]> granicus.if.org Git - clang/commitdiff
Gracefully (and correctly) handle init of multiple union members
authorMatthew Curtis <mcurtis@codeaurora.org>
Thu, 3 Oct 2013 12:14:24 +0000 (12:14 +0000)
committerMatthew Curtis <mcurtis@codeaurora.org>
Thu, 3 Oct 2013 12:14:24 +0000 (12:14 +0000)
We now emit warnings when doing so and code generation is consistent
with GCC. Note that the C99 spec is unclear as to the precise
behavior.

See also ...
Bug:
  http://llvm.org/bugs/show_bug.cgi?id=16644 and

cfe-dev discussion:
  http://lists.cs.uiuc.edu/pipermail/cfe-dev/2013-September/031918.html

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@191890 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Expr.h
lib/Sema/SemaInit.cpp
test/CodeGen/designated-initializers.c
test/Sema/designated-initializers.c

index 8a884c0b2e5a504f05fa0bb195b4d7004baf0107..a53b88d61393c0f6afe63f0647fca5c4dbd6a467 100644 (file)
@@ -3824,6 +3824,10 @@ public:
     return const_cast<InitListExpr *>(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;
   }
 
index afd9393123e96b5cdc007065bd370b1c22c41003..e407253df7ca4eca2ce7975670d74a1efa4d1fee 100644 (file)
@@ -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.
index b41898600b208f824ac7948ae5a707427009480f..b11c67a454213518339d290e3991b0e8348f1db8 100644 (file)
@@ -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)
 {
index 36fa559f6f3704d93cbfaac7d57dd8fb5a5413f6..6630da67c5bd7e5c2e2fd6c26e42c4b35e5f9ffd 100644 (file)
@@ -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;