]> granicus.if.org Git - clang/commitdiff
This patch fixes multiple issues in clang's designated init builder and
authorDouglas Gregor <dgregor@apple.com>
Fri, 8 Oct 2010 20:44:28 +0000 (20:44 +0000)
committerDouglas Gregor <dgregor@apple.com>
Fri, 8 Oct 2010 20:44:28 +0000 (20:44 +0000)
completes support for C1X anonymous struct/union init features:

 * Indexed anonymous member initializers should not be expanded. Doing so makes
little sense and would cause unresolvable semantic ambiguity in valid code
(regression introduced by r69153).

 * Subobject initialization of (possibly nested) anonymous members are now
referred to with paths relative to the naming record context, eliminating the
synthesis of incorrect implicit InitListExprs that caused CodeGen to assert.

 * Field lookup was missing a null check in IdentifierInfo comparison which
caused lookup for a known (already resolved) field to match the first unnamed
data member it encountered leading to silent miscompilation.

 * Subobject paths are no longer built using the general purpose
Sema::BuildAnonymousStructUnionMemberPath(). If any corner cases crop up, we
will now assert earlier in Sema instead of passing invalid InitListExprs
through to CodeGen.

Fixes PR6955, from Alp Toker!

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

lib/Sema/SemaInit.cpp
test/CodeGen/designated-initializers.c
test/Sema/designated-initializers.c

index 6fd1d68dcd06cd64853cd0d1cb6904e74803da4b..bac9f8fa7556a249af8ad582f1da25a7b2237928 100644 (file)
@@ -1167,6 +1167,22 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity,
                           StructuredList, StructuredIndex);
 }
 
+/// \brief Similar to Sema::BuildAnonymousStructUnionMemberPath() but builds a
+/// relative path and has strict checks.
+static void BuildRelativeAnonymousStructUnionMemberPath(FieldDecl *Field,
+                                    llvm::SmallVectorImpl<FieldDecl *> &Path,
+                                    DeclContext *BaseDC) {
+  Path.push_back(Field);
+  for (DeclContext *Ctx = Field->getDeclContext();
+       !Ctx->Equals(BaseDC);
+       Ctx = Ctx->getParent()) {
+    ValueDecl *AnonObject =
+      cast<RecordDecl>(Ctx)->getAnonymousStructOrUnionObject();
+    FieldDecl *AnonField = cast<FieldDecl>(AnonObject);
+    Path.push_back(AnonField);
+  }
+}
+
 /// \brief Expand a field designator that refers to a member of an
 /// anonymous struct or union into a series of field designators that
 /// refers to the field within the appropriate subobject.
@@ -1178,13 +1194,14 @@ static void ExpandAnonymousFieldDesignator(Sema &SemaRef,
                                            unsigned DesigIdx,
                                            FieldDecl *Field,
                                         RecordDecl::field_iterator &FieldIter,
-                                           unsigned &FieldIndex) {
+                                           unsigned &FieldIndex,
+                                           DeclContext *BaseDC) {
   typedef DesignatedInitExpr::Designator Designator;
 
   // Build the path from the current object to the member of the
   // anonymous struct/union (backwards).
   llvm::SmallVector<FieldDecl *, 4> Path;
-  SemaRef.BuildAnonymousStructUnionMemberPath(Field, Path);
+  BuildRelativeAnonymousStructUnionMemberPath(Field, Path, BaseDC);
 
   // Build the replacement designators.
   llvm::SmallVector<Designator, 4> Replacements;
@@ -1343,7 +1360,9 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
       if (Field->isUnnamedBitfield())
         continue;
 
-      if (KnownField == *Field || Field->getIdentifier() == FieldName)
+      if (KnownField && KnownField == *Field)
+        break;
+      if (FieldName && FieldName == Field->getIdentifier())
         break;
 
       ++FieldIndex;
@@ -1400,10 +1419,10 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
           cast<RecordDecl>((ReplacementField)->getDeclContext())
                                                  ->isAnonymousStructOrUnion()) {
         // Handle an field designator that refers to a member of an
-        // anonymous struct or union.
+        // anonymous struct or union. This is a C1X feature.
         ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx,
                                        ReplacementField,
-                                       Field, FieldIndex);
+                                       Field, FieldIndex, RT->getDecl());
         D = DIE->getDesignator(DesigIdx);
       } else if (!KnownField) {
         // The replacement field comes from typo correction; find it
@@ -1421,12 +1440,6 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
           ++FieldIndex;
         }
       }
-    } else if (!KnownField &&
-               cast<RecordDecl>((*Field)->getDeclContext())
-                 ->isAnonymousStructOrUnion()) {
-      ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx, *Field,
-                                     Field, FieldIndex);
-      D = DIE->getDesignator(DesigIdx);
     }
 
     // All of the fields of a union are located at the same place in
index 312d78565294e6beb24a3131bf61414132311a04..d928296ef23015809b8fb5f868b4169b251d58c7 100644 (file)
@@ -19,6 +19,39 @@ int b[2] = {
   [1] = 22
 };
 
+// PR6955
+
+struct ds {
+  struct {
+    struct {
+      short a;
+    };
+    short b;
+    struct {
+      short c;
+    };
+  };
+};
+
+// Traditional C anonymous member init
+struct ds ds0 = { { { .a = 0 } } };
+// C1X lookup-based anonymous member init cases
+struct ds ds1 = { { .a = 1 } };
+struct ds ds2 = { { .b = 1 } };
+struct ds ds3 = { .a = 0 };
+// CHECK: @ds4 = global %3 { %4 { %struct.anon zeroinitializer, i16 0, %struct.anon { i16 1 } } }
+struct ds ds4 = { .c = 1 };
+struct ds ds5 = { { { .a = 0 } }, .b = 1 };
+struct ds ds6 = { { .a = 0, .b = 1 } };
+// CHECK: @ds7 = global %3 { %4 { %struct.anon { i16 2 }, i16 3, %struct.anon zeroinitializer } }
+struct ds ds7 = {
+  { {
+      .a = 1
+    } },
+  .a = 2,
+  .b = 3
+};
+
 void test1(int argc, char **argv)
 {
   // CHECK: internal global %struct.foo { i8* null, i32 1024 }
index 7e4ed6892aee94607c9dd594fbb8882fcec52059..c9a8482e85dba82dacb01cf57e6084354caa193d 100644 (file)
@@ -249,3 +249,31 @@ struct expr expr0 = {
     }
   }
 };
+
+// PR6955
+
+struct ds {
+  struct {
+    struct {
+      unsigned int a;
+    };
+    unsigned int b;
+    struct {
+      unsigned int c;
+    };
+  };
+};
+
+// C1X lookup-based anonymous member init cases
+struct ds ds0 = {
+  { {
+      .a = 1 // expected-note{{previous initialization is here}}
+    } },
+  .a = 2, // expected-warning{{initializer overrides prior initialization of this subobject}}
+  .b = 3
+};
+struct ds ds1 = { .c = 0 };
+struct ds ds2 = { { {
+    .a = 0,
+    .b = 1 // expected-error{{field designator 'b' does not refer to any field}}
+} } };