Open llvmbot opened 3 years ago
Hmm, this works in C++ but not in C. In C++ we build this structured initializer:
-VarDecl 0x11503010 <line:12:1, line:17:1> line:12:13 nd 'struct node':'node' cinit
-InitListExpr 0x11503340 <col:18, line:17:1> 'struct node':'node'
-InitListExpr 0x115033e8 <line:13:15, line:15:5> 'struct capab':'capab' |-InitListExpr 0x115035c8 <col:5> 'struct wss':'wss' | |-ImplicitCastExpr 0x11532a60 <line:16:26> 'unsigned int' <IntegralCast> | |
-IntegerLiteral 0x115031a8 -ImplicitValueInitExpr 0x11503628 <<invalid sloc>> 'unsigned char'
-ImplicitCastExpr 0x11503438
But in C we end up with a DesignatedInitUpdateExpr, which CheckForConstantInitializer rejects (even though CodeGen can typically emit IR for it these days):
-VarDecl 0x108e1470 <line:12:1, line:17:1> line:12:13 nd 'struct node':'struct node' cinit
-InitListExpr 0x108e17a0 <col:18, line:17:1> 'struct node':'struct node'
-InitListExpr 0x108e1848 <line:13:15, line:15:5> 'struct capab':'struct capab' |-DesignatedInitUpdateExpr 0x108e18c0 <<invalid sloc>> 'struct wss':'struct wss' | |-ImplicitValueInitExpr 0x108e18b0 <<invalid sloc>> 'struct wss':'struct wss' |
-InitListExpr 0x108e18e0 <line:16:17, col:26> 'struct wss':'struct wss'
| |-ImplicitCastExpr 0x108e1928 -IntegerLiteral 0x108e1608 <col:26> 'int' 1 |
-NoInitExpr 0x108e1950 <-ImplicitCastExpr 0x108e1898 <line:14:21> 'unsigned char' <IntegralCast>
-IntegerLiteral 0x108e1520
Presumably we should convert the ImplicitValueInitExpr for 'struct wss' into an InitListExpr when attempting a designated update, instead of creating a DesignatedInitUpdateExpr. (In modern C++, uninitialized elements are list-initialized instead of being value-initialized, which is why this works there.)
We might also want to consider allowing DesignatedInitUpdateExprs through CheckForConstantInitializer, given that we can now (in reasonable cases) generate IR constants for them.
Extended Description
For the following code: struct wss { unsigned int count; unsigned char _have_ct : 1 ; }; struct capab { struct wss _wss; unsigned char _have_type; }; struct node { struct capab _capab; }; struct node nd = { ._capab = { ._have_type = 1, }, ._capab._wss.count = 1, // ERROR! };
Clang gives error: clang -emit-llvm test.c -c error: initializer element is not a compile-time constant 1 error generated.
Code appears to be valid according to struct initialization rules, and gcc gives no error: gcc -c test.c