]> granicus.if.org Git - clang/commitdiff
Fix PR7402: We were creating implicit member initializers for every field in an
authorChandler Carruth <chandlerc@gmail.com>
Wed, 30 Jun 2010 00:54:29 +0000 (00:54 +0000)
committerChandler Carruth <chandlerc@gmail.com>
Wed, 30 Jun 2010 00:54:29 +0000 (00:54 +0000)
anonymous union under the presumption that they didn't do anything. While this
is true, our checks for redundant initialization of an anonymous union still
fire when these overlap with explicit user initialization. A cleaner approach
is to avoid initializing multiple members of a union altogether, but this still
is in a rather fuzzy are especially when C++0x allows non-POD types into
unions.

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

lib/Sema/SemaDeclCXX.cpp
test/SemaCXX/constructor-initializer.cpp

index 29455087aee6501ccf3b2bbf21d42b670fe31b13..1757c845517380d1f2d95938f6383e4e40e860d8 100644 (file)
@@ -1753,38 +1753,64 @@ struct BaseAndFieldInfo {
 };
 }
 
+static void RecordFieldInitializer(BaseAndFieldInfo &Info,
+                                   FieldDecl *Top, FieldDecl *Field,
+                                   CXXBaseOrMemberInitializer *Init) {
+  // If the member doesn't need to be initialized, Init will still be null.
+  if (!Init)
+    return;
+
+  Info.AllToInit.push_back(Init);
+  if (Field != Top) {
+    Init->setMember(Top);
+    Init->setAnonUnionMember(Field);
+  }
+}
+
 static bool CollectFieldInitializer(BaseAndFieldInfo &Info,
                                     FieldDecl *Top, FieldDecl *Field) {
 
-  // Overwhelmingly common case:  we have a direct initializer for this field.
+  // Overwhelmingly common case: we have a direct initializer for this field.
   if (CXXBaseOrMemberInitializer *Init = Info.AllBaseFields.lookup(Field)) {
-    Info.AllToInit.push_back(Init);
-
-    if (Field != Top) {
-      Init->setMember(Top);
-      Init->setAnonUnionMember(Field);
-    }
+    RecordFieldInitializer(Info, Top, Field, Init);
     return false;
   }
 
   if (Info.IIK == IIK_Default && Field->isAnonymousStructOrUnion()) {
     const RecordType *FieldClassType = Field->getType()->getAs<RecordType>();
     assert(FieldClassType && "anonymous struct/union without record type");
-
-    // Walk through the members, tying in any initializers for fields
-    // we find.  The earlier semantic checks should prevent redundant
-    // initialization of union members, given the requirement that
-    // union members never have non-trivial default constructors.
-
-    // TODO: in C++0x, it might be legal to have union members with
-    // non-trivial default constructors in unions.  Revise this
-    // implementation then with the appropriate semantics.
     CXXRecordDecl *FieldClassDecl
       = cast<CXXRecordDecl>(FieldClassType->getDecl());
-    for (RecordDecl::field_iterator FA = FieldClassDecl->field_begin(),
-           EA = FieldClassDecl->field_end(); FA != EA; FA++)
-      if (CollectFieldInitializer(Info, Top, *FA))
-        return true;
+
+    // Even though union members never have non-trivial default
+    // constructions in C++03, we still build member initializers for aggregate
+    // record types which can be union members, and C++0x allows non-trivial
+    // default constructors for union members, so we ensure that only one
+    // member is initialized for these.
+    if (FieldClassDecl->isUnion()) {
+      // First check for an explicit initializer for one field.
+      for (RecordDecl::field_iterator FA = FieldClassDecl->field_begin(),
+           EA = FieldClassDecl->field_end(); FA != EA; FA++) {
+        if (CXXBaseOrMemberInitializer *Init = Info.AllBaseFields.lookup(*FA)) {
+          RecordFieldInitializer(Info, Top, *FA, Init);
+          break;
+        }
+      }
+
+      // Fallthrough and construct a default initializer for the union as
+      // a whole, which can call its default constructor if such a thing exists
+      // (C++0x perhaps). FIXME: It's not clear that this is the correct
+      // behavior going forward with C++0x, when anonymous unions there are
+      // finalized, we should revisit this.
+    } else {
+      // For structs, we simply descend through to initialize all members where
+      // necessary.
+      for (RecordDecl::field_iterator FA = FieldClassDecl->field_begin(),
+           EA = FieldClassDecl->field_end(); FA != EA; FA++) {
+        if (CollectFieldInitializer(Info, Top, *FA))
+          return true;
+      }
+    }
   }
 
   // Don't try to build an implicit initializer if there were semantic
@@ -1796,15 +1822,8 @@ static bool CollectFieldInitializer(BaseAndFieldInfo &Info,
   CXXBaseOrMemberInitializer *Init = 0;
   if (BuildImplicitMemberInitializer(Info.S, Info.Ctor, Info.IIK, Field, Init))
     return true;
-    
-  // If the member doesn't need to be initialized, Init will still be null.
-  if (!Init) return false;
 
-  Info.AllToInit.push_back(Init);
-  if (Top != Field) {
-    Init->setMember(Top);
-    Init->setAnonUnionMember(Field);
-  }
+  RecordFieldInitializer(Info, Top, Field, Init);
   return false;
 }
                                
index 8e9e133d94cbdad8ad3ff49c2d19a11e4b12c8e2..bf4b289a9086774775affb94140279d295d22e8a 100644 (file)
@@ -204,3 +204,20 @@ C f(C c) {
 }
 
 }
+
+// Don't build implicit initializers for anonymous union fields when we already
+// have an explicit initializer for another field in the union.
+namespace PR7402 {
+  struct S {
+    union {
+      void* ptr_;
+      struct { int i_; };
+    };
+
+    template <typename T> S(T) : ptr_(0) { }
+  };
+
+  void f() {
+    MyStruct s(3);
+  }
+}