Why do conforming implementations behave differently w.r.t. incomplete array types with internal linkage?

Viewed 154

Sample code (t0.c):

static int arr[ ];

int main( void )
{
        return arr[ 0 ];
}

static int arr[ ] = { 0 };

Invocations:

$ gcc t0.c -std=c11 -Wall -Wextra
<nothing>

$ clang t0.c -std=c11 -Wall -Wextra
<nothing>

$ cl t0.c /std:c11 /Za
t0.c(1): error C2133: 'arr': unknown size

$ gcc t0.c -std=c11 -Wall -Wextra -pedantic
t0.c:1:12: error: array size missing in ‘arr’

$ clang t0.c -std=c11 -Wall -Wextra -pedantic
<nothing>

C11, 6.2.5 Types, 22:

An array type of unknown size is an incomplete type. It is completed, for an identifier of that type, by specifying the size in a later declaration (with internal or external linkage).

C11, 6.9.2 External object definitions, 3:

If the declaration of an identifier for an object is a tentative definition and has internal linkage, the declared type shall not be an incomplete type.

C11, J.2 Undefined behavior, 1:

An identifier for an object with internal linkage and an incomplete type is declared with a tentative definition (6.9.2).

Question: Why do conforming implementations show different behavior? Which one behaves correctly?

UPD1. Created https://bugs.llvm.org/show_bug.cgi?id=51319.

1 Answers

Based on the quoted passages, particularly 6.9.2p3 and the non-normative J.2p1, it seems clear that the code violates these clauses and therefore may not appear in a strictly conforming program defined in section 4p5 of the C standard:

A strictly conforming program shall use only those features of the language and library specified in this International Standard. It shall not produce output dependent on any unspecified, undefined, or implementation-defined behavior, and shall not exceed any minimum implementation limit

Implementations are however free to define extensions that would not be allowed in a strictly conforming program. A program using such extensions is a conforming program as defined in section 4p6:

The two forms of conforming implementation are hosted and freestanding. A conforming hosted implementation shall accept any strictly conforming program. [ ... details of freestanding omitted ... ] A conforming implementation may have extensions (including additional library functions), provided they do not alter the behavior of any strictly conforming program

Based on the compiler output, it appears that MSVC does not support such an extension but gcc and clang do.

Additionally, gcc correctly disables this feature when the -pedantic flag is passed, forcing strict compliance. That clang does not generate a diagnostic with -pedantic appears to be a bug.

Related