In an array declaration with omitted bound, is the type considered incomplete until the closing brace?

73 views
Skip to first unread message

Brian Bi

unread,
Sep 16, 2014, 12:54:06 AM9/16/14
to std-dis...@isocpp.org
Consider

size_t a[] = { sizeof(a) };

By my reading of the standard this is valid although possibly annoying to compile: there's one initializer, so this declares "a" to be of type size_t[1], and then initializes it with sizeof(size_t[1]).

However both g++ and clang++ complain, "invalid application of sizeof to incomplete type size_t[]".

The standard doesn't say that in the declaration of an array of unknown bound, the type is considered incomplete until the closing brace of the braced-init-list.

* Is it supposed to be implicitly understood that this kind of declaration is ill-formed?
* Or, is it unclear that it was intended to be ill-formed (maybe there's a DR already?)
* Or, is it supposed to be well-formed (bug in gcc and clang)?
--
Brian Bi

Richard Smith

unread,
Sep 16, 2014, 3:02:25 PM9/16/14
to std-dis...@isocpp.org, Mike Miller
EDG and MSVC reject this too. I think this is a defect in the standard, and I can't find it in the issues list.

The standard seems clear that the above code should work; [dcl.array]p1 says:

"Except as noted below, if the constant expression is omitted, the type of the identifier of D is “derived-declarator-type-list array of unknown bound of T”, an incomplete object type."

[dcl.array]p3 says:

"An array bound may also be omitted when the declarator is followed by an initializer (8.5). In this case the bound is calculated from the number of initial elements (say, N) supplied (8.5.1), and the type of the identifier of D is “array of N T.”"

So in this case it's clear that 'a' *never* has type "array of unknown bound of size_t"; it's instead immediately declared with type "array of 1 size_t".

I think the type should be incomplete within the initializer in this case, because it is not possible in general to compute the sizeof before we have parsed the initializer:

  template<int> struct T{};
  template<> struct T<1> { static const int U = 0; };
  template<> struct T<2> { template<int,int> static int U(int); };

  size_t a[] = { T<sizeof(a)>::U<0, 1>(2) };

Gabriel Dos Reis

unread,
Sep 16, 2014, 3:15:22 PM9/16/14
to std-dis...@isocpp.org, Mike Miller
Correct.

| I think the type should be incomplete within the initializer in this
| case, because it is not possible in general to compute the sizeof
| before we have parsed the initializer:

That would be too blunt a hammer. It would break the following:

int main() {
int a[] = { 0, 1, 2, 3, a[3] + 1 };
return a[4];
}

which is accepted by gcc, g++, clang, clang++ because an
lvalue-to-rvalue conversion from an object of incomplete type would be
required to initialize the last element of a. It would also break
compat with C99/C11.

-- Gaby

Richard Smith

unread,
Sep 16, 2014, 3:48:50 PM9/16/14
to std-dis...@isocpp.org, Mike Miller
'a' having incomplete type doesn't imply that a[3] has incomplete type. In this case, the type of 'a' would be the incomplete type 'array of unknown bound of int', and array indexing on that type produces the complete type 'int'.

David Krauss

unread,
Sep 16, 2014, 10:03:20 PM9/16/14
to std-dis...@isocpp.org
On 2014–09–17, at 3:02 AM, Richard Smith <ric...@metafoo.co.uk> wrote:

I think the type should be incomplete within the initializer in this case, because it is not possible in general to compute the sizeof before we have parsed the initializer:

To be sure, there’s no possible circular dependency between the initializer and the type (unless there’s a comma in a template argument list, and the angle brackets can be parsed as inequality operators). As long as the compiler has an AST before trying to evaluate that expression, it can fix the array type before it would see a problem.

The standard is free to require some number of passes in the interpreter, and if all implementations happen to agree, that might as well be required. But, it’s always unfortunate to restrict usage which is unambiguous and force anybody to reduce their QOI.

Gabriel Dos Reis

unread,
Sep 19, 2014, 7:50:07 AM9/19/14
to std-dis...@isocpp.org, Mike Miller
Right -- that is clever wording but I am still uncomfortable with that
double-vision treatement. The real culprit here is brace-elision.

-- Gaby

Reply all
Reply to author
Forward
0 new messages