[PATCH] Gracefully (and correctly) handle init of multiple union members

Matthew Curtis mcurtis at codeaurora.org
Tue Sep 24 08:04:49 PDT 2013


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

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

-------------- next part --------------
>From f419dc61e0c467bd2f8b8408b548969bacb6bc05 Mon Sep 17 00:00:00 2001
From: Matthew Curtis <mcurtis at codeaurora.org>
Date: Fri, 13 Sep 2013 11:09:37 -0500
Subject: [PATCH] Gracefully (and correctly) handle init of multiple union
 members

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
---
 include/clang/AST/Expr.h            |    3 ++
 lib/Sema/SemaInit.cpp               |   23 +++++++++++++-
 test/Sema/designated-initializers.c |   56 ++++++++++++++++++++++++++++++++++-
 3 files changed, 80 insertions(+), 2 deletions(-)

diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index 8a884c0..a0ac2b5 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -3824,6 +3824,9 @@ public:
     return const_cast<InitListExpr *>(this)->getInitializedFieldInUnion();
   }
   void setInitializedFieldInUnion(FieldDecl *FD) {
+    FieldDecl *CFD = ArrayFillerOrUnionFieldInit.dyn_cast<FieldDecl *>();
+    assert((FD == 0 || CFD == 0 || CFD == FD)
+           && "Only one field of a union may be initiazed at a time!");
     ArrayFillerOrUnionFieldInit = FD;
   }
 
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index afd9393..e407253 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/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/test/Sema/designated-initializers.c b/test/Sema/designated-initializers.c
index 36fa559..be365a0 100644
--- a/test/Sema/designated-initializers.c
+++ b/test/Sema/designated-initializers.c
@@ -1,5 +1,8 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-unknown-unknown %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -DCHECK_CODEGEN=1 \
+// RUN:   -S -emit-llvm -o - 2>&1 | FileCheck %s
 
+#if !CHECK_CODEGEN
 int complete_array_from_init[] = { 1, 2, [10] = 5, 1, 2, [5] = 2, 6 };
 
 int complete_array_from_init_check[((sizeof(complete_array_from_init) / sizeof(int)) == 13)? 1 : -1];
@@ -136,10 +139,12 @@ void test() {
     [0].b = 8
   };
 }
+#endif // !CHECK_CODEGEN
 
-// FIXME: How do we test that this initializes the long properly?
 union { char c; long l; } u1 = { .l = 0xFFFF };
+// CHECK: @u1 = {{.*}} { i64 65535 }
 
+#if !CHECK_CODEGEN
 extern float global_float;
 
 struct XX { int a, *b; };
@@ -223,6 +228,54 @@ struct Enigma enigma = {
 };
 
 
+#endif // !CHECK_CODEGEN
+
+/// 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}}
+};
+// CHECK: @union_16644_instance_0 = {{.*}} { i32 0, i32 0, i32 0, i32 3 } }
+
+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}}
+};
+// CHECK: @union_16644_instance_1 = {{.*}} [i32 10, i32 0, i32 0, i32 0]
+
+union_16644_t union_16644_instance_2 =
+{
+  .a.one   = 21, //                               expected-note{{previous}}
+  .b[1]    = 20, // expected-warning{{overrides}}
+};
+// CHECK: @union_16644_instance_2 = {{.*}} [i32 0, i32 20, i32 0, i32 0]
+
+union_16644_t union_16644_instance_3 =
+{
+  .b[1]    = 30, //                               expected-note{{previous}}
+  .a = {         // expected-warning{{overrides}}
+    .one = 31
+  }
+};
+// CHECK: @union_16644_instance_3 = {{.*}} { i32 0, i32 31, i32 0, i32 0 }
+
+#if !CHECK_CODEGEN
 /// PR4073
 /// Should use evaluate to fold aggressively and emit a warning if not an ice.
 extern int crazy_x;
@@ -293,3 +346,4 @@ struct overwrite_string_struct2 {
     { { "foo" }, 1 },
     [0].L[4] = 'x' // no-warning
   };
+#endif // !CHECK_CODEGEN
-- 
1.7.8.3



More information about the cfe-commits mailing list