clang rejects nested struct-member-access-typeof

== Compiler info (clang -v) ==

[openSUSE 12.1 RC]
SUSE Linux clang version 3.0 (trunk 140782) (based on LLVM 3.0)
Target: x86_64-unknown-linux-gnu
Thread model: posix

== Source ==

int main(void)
{
  void *p = 0;
  typeof((struct { typeof((struct { void *m; }){p}.m) n; }){0}.n) q = 0;
  return 0;
}

== Description ==

I was giving clang a spin on libHX [http://libhx.sf.net/] when it errored out
on libHX's "type-checking casts" macros. The above source snippet is the
distilled minimal test case.

../../src/format.c:34:29: error: initializer element is not a compile-time
      constant
        return const_cast1(void *, static_cast(const void *, t));
               ~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[...]

== Observed output ==

$ clang test.c
t.c:4:47: error: initializer element is not a compile-time constant
        typeof((struct { typeof((struct { void *m; }){p}.m) n; }){0}.n) q = 0;
                                                     ^~~
t.c:4:63: error: member reference base type 'void' is not a structure or union
        typeof((struct { typeof((struct { void *m; }){p}.m) n; }){0}.n) q = 0;
                                                                 ~~~ ^
2 errors generated.

== Expected output ==

That no errors be output. GCC 4.5/4.6/4.x compiles the very same file
fine, because it sees that we are really only doing type inspection.

This code is relying on GCC extensions to treat a compound literal as a constant expression, which C99 forbids. Feel free to file a bug; this might be the kind of thing that we can support for GNU compatibility, if it falls out of the constexpr and other C++11 work in this area.

  - Doug

Hi,

== Compiler info (clang -v) ==

[openSUSE 12.1 RC]
SUSE Linux clang version 3.0 (trunk 140782) (based on LLVM 3.0)
Target: x86_64-unknown-linux-gnu
Thread model: posix

== Source ==

int main(void)
{
void *p = 0;
typeof((struct { typeof((struct { void *m; }){p}.m) n; }){0}.n) q = 0;
return 0;
}

== Description ==

I was giving clang a spin on libHX [http://libhx.sf.net/] when it errored out
on libHX's "type-checking casts" macros. The above source snippet is the
distilled minimal test case.

../../src/format.c:34:29: error: initializer element is not a compile-time
constant
return const_cast1(void *, static_cast(const void *, t));
~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[...]

== Observed output ==

$ clang test.c
t.c:4:47: error: initializer element is not a compile-time constant
typeof((struct { typeof((struct { void *m; }){p}.m) n; }){0}.n) q = 0;
^~~
t.c:4:63: error: member reference base type 'void' is not a structure or union
typeof((struct { typeof((struct { void *m; }){p}.m) n; }){0}.n) q = 0;
~~~ ^
2 errors generated.

== Expected output ==

That no errors be output. GCC 4.5/4.6/4.x compiles the very same file
fine, because it sees that we are really only doing type inspection.

Comeau C++ didn't accept it either:

Comeau C/C++ 4.3.10.1 (Oct 6 2008 11:28:09) for ONLINE_EVALUATION_BETA2
Copyright 1988-2008 Comeau Computing. All rights reserved.
MODE:strict errors C++ C++0x_extensions

"ComeauTest.c", line 4: error: expected a type specifier
         typeof((struct { typeof((struct { void *m; }){p}.m) n; }){0}.n) q = 0;
                                 ^

"ComeauTest.c", line 4: error: expected a ")"
         typeof((struct { typeof((struct { void *m; }){p}.m) n; }){0}.n) q = 0;
                                                      ^

"ComeauTest.c", line 4: error: explicit type is missing ("int" assumed)
         typeof((struct { typeof((struct { void *m; }){p}.m) n; }){0}.n) q = 0;
                          ^

"ComeauTest.c", line 4: error: expected a declaration
  Wild guess: Should this be in a function block?
         typeof((struct { typeof((struct { void *m; }){p}.m) n; }){0}.n) q = 0;
                                                         ^

"ComeauTest.c", line 4: error: reference to local variable of
enclosing function is
          not allowed
         typeof((struct { typeof((struct { void *m; }){p}.m) n; }){0}.n) q = 0;
                                                       ^

"ComeauTest.c", line 4: error: expected a ";" (perhaps on the previous
statement)
         typeof((struct { typeof((struct { void *m; }){p}.m) n; }){0}.n) q = 0;
                                                        ^

"ComeauTest.c", line 4: warning: missing return statement at end of non-void
          function "<unnamed>::typeof"
         typeof((struct { typeof((struct { void *m; }){p}.m) n; }){0}.n) q = 0;
                                                        ^

"ComeauTest.c", line 4: error: type definition is not allowed
         typeof((struct { typeof((struct { void *m; }){p}.m) n; }){0}.n) q = 0;
                 ^

"ComeauTest.c", line 4: error: expected an expression
         typeof((struct { typeof((struct { void *m; }){p}.m) n; }){0}.n) q = 0;
                                                                  ^

"ComeauTest.c", line 4: error: identifier "typeof" is undefined
         typeof((struct { typeof((struct { void *m; }){p}.m) n; }){0}.n) q = 0;
         ^

"ComeauTest.c", line 4: error: expected a ";" (perhaps on the previous
statement)
         typeof((struct { typeof((struct { void *m; }){p}.m) n; }){0}.n) q = 0;
                                                                         ^

10 errors detected in the compilation of "ComeauTest.c".

  void *p = 0;
  typeof((struct { typeof((struct { void *m; }){p}.m) n; }){0}.n) q = 0;

This code is relying on GCC extensions to treat a compound literal
as a constant expression, which C99 forbids.

I do not think this should have anything to do with constexprs, also
because typeof does not really evaluate its argument, but just looks
at the type system. Clang accepts a handful of - what looks to me
like non-constant expressions - to typeof:

  typeof((struct { void *m; }){p}.m) q = 0;

  typeof(argc) argc2 = argc;

Feel free to file a bug; this might be the kind of thing that we can
support for GNU compatibility, if it falls out of the constexpr and
other C++11 work in this area.

I guess I did by writing to this list.

Hello Jan,

To file a bug you need to visit: http://llvm.org/bugs/

On top of your description of the problem you are expected to provide a minimal example that reproduces the issue. If you cannot produce this minimal example, a preprocessed file can suffice (use -E to get the preprocessor output) however it might make investigation harder (and thus delay the correction).

–Matthieu

According to http://clang.llvm.org/get_involved.html , cfe-dev is (also)
for bugs.
Minimal test case has already been provided.

Entered into the bug database (http://llvm.org/bugs/show_bug.cgi?id=11299).

-Eli