diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 8a884c0b2e5a..a53b88d61393 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -3824,6 +3824,10 @@ public: return const_cast(this)->getInitializedFieldInUnion(); } void setInitializedFieldInUnion(FieldDecl *FD) { + assert((FD == 0 + || getInitializedFieldInUnion() == 0 + || getInitializedFieldInUnion() == FD) + && "Only one field of a union may be initialized at a time!"); ArrayFillerOrUnionFieldInit = FD; } diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index afd9393123e9..e407253df7ca 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -1868,8 +1868,29 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, // the initializer list. if (RT->getDecl()->isUnion()) { FieldIndex = 0; - if (!VerifyOnly) + if (!VerifyOnly) { + FieldDecl *CurrentField = StructuredList->getInitializedFieldInUnion(); + if (CurrentField && CurrentField != *Field) { + assert(StructuredList->getNumInits() == 1 + && "A union should never have more than one initializer!"); + + // we're about to throw away an initializer, emit warning + SemaRef.Diag(D->getFieldLoc(), + diag::warn_initializer_overrides) + << D->getSourceRange(); + Expr *ExistingInit = StructuredList->getInit(0); + SemaRef.Diag(ExistingInit->getLocStart(), + diag::note_previous_initializer) + << /*FIXME:has side effects=*/0 + << ExistingInit->getSourceRange(); + + // remove existing initializer + StructuredList->resizeInits(SemaRef.Context, 0); + StructuredList->setInitializedFieldInUnion(0); + } + StructuredList->setInitializedFieldInUnion(*Field); + } } // Make sure we can use this declaration. diff --git a/clang/test/CodeGen/designated-initializers.c b/clang/test/CodeGen/designated-initializers.c index b41898600b20..b11c67a45421 100644 --- a/clang/test/CodeGen/designated-initializers.c +++ b/clang/test/CodeGen/designated-initializers.c @@ -81,6 +81,63 @@ struct overwrite_string_struct5 { // CHECK: [6 x i8] c"foo\00y\00", i32 1 +// CHECK: @u1 = {{.*}} { i32 65535 } +union u_FFFF { char c; long l; } u1 = { .l = 0xFFFF }; + + +/// PR16644 +typedef union u_16644 { + struct s_16644 { + int zero; + int one; + int two; + int three; + } a; + int b[4]; +} union_16644_t; + +// CHECK: @union_16644_instance_0 = {{.*}} { i32 0, i32 0, i32 0, i32 3 } } +union_16644_t union_16644_instance_0 = +{ + .b[0] = 0, + .a.one = 1, + .b[2] = 2, + .a.three = 3, +}; + +// CHECK: @union_16644_instance_1 = {{.*}} [i32 10, i32 0, i32 0, i32 0] +union_16644_t union_16644_instance_1 = +{ + .a.three = 13, + .b[2] = 12, + .a.one = 11, + .b[0] = 10, +}; + +// CHECK: @union_16644_instance_2 = {{.*}} [i32 0, i32 20, i32 0, i32 0] +union_16644_t union_16644_instance_2 = +{ + .a.one = 21, + .b[1] = 20, +}; + +// CHECK: @union_16644_instance_3 = {{.*}} { i32 0, i32 31, i32 0, i32 0 } +union_16644_t union_16644_instance_3 = +{ + .b[1] = 30, + .a = { + .one = 31 + } +}; + +// CHECK: @union_16644_instance_4 = {{.*}} { i32 5, i32 2, i32 0, i32 0 } {{.*}} [i32 0, i32 4, i32 0, i32 0] +union_16644_t union_16644_instance_4[2] = +{ + [0].a.one = 2, + [1].a.zero = 3, + [0].a.zero = 5, + [1].b[1] = 4 +}; void test1(int argc, char **argv) { diff --git a/clang/test/Sema/designated-initializers.c b/clang/test/Sema/designated-initializers.c index 36fa559f6f37..6630da67c5bd 100644 --- a/clang/test/Sema/designated-initializers.c +++ b/clang/test/Sema/designated-initializers.c @@ -137,7 +137,6 @@ void test() { }; } -// FIXME: How do we test that this initializes the long properly? union { char c; long l; } u1 = { .l = 0xFFFF }; extern float global_float; @@ -223,6 +222,55 @@ struct Enigma enigma = { }; +/// PR16644 +typedef union { + struct { + int zero; + int one; + int two; + int three; + } a; + int b[4]; +} union_16644_t; + +union_16644_t union_16644_instance_0 = +{ + .b[0] = 0, // expected-note{{previous}} + .a.one = 1, // expected-warning{{overrides}} expected-note{{previous}} + .b[2] = 2, // expected-warning{{overrides}} expected-note{{previous}} + .a.three = 3, // expected-warning{{overrides}} +}; + +union_16644_t union_16644_instance_1 = +{ + .a.three = 13, // expected-note{{previous}} + .b[2] = 12, // expected-warning{{overrides}} expected-note{{previous}} + .a.one = 11, // expected-warning{{overrides}} expected-note{{previous}} + .b[0] = 10, // expected-warning{{overrides}} +}; + +union_16644_t union_16644_instance_2 = +{ + .a.one = 21, // expected-note{{previous}} + .b[1] = 20, // expected-warning{{overrides}} +}; + +union_16644_t union_16644_instance_3 = +{ + .b[1] = 30, // expected-note{{previous}} + .a = { // expected-warning{{overrides}} + .one = 31 + } +}; + +union_16644_t union_16644_instance_4[2] = +{ + [0].a.one = 2, + [1].a.zero = 3,// expected-note{{previous}} + [0].a.zero = 5, + [1].b[1] = 4 // expected-warning{{overrides}} +}; + /// PR4073 /// Should use evaluate to fold aggressively and emit a warning if not an ice. extern int crazy_x;