diff options
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 75 | ||||
-rw-r--r-- | test/SemaCXX/constructor-initializer.cpp | 17 |
2 files changed, 64 insertions, 28 deletions
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 29455087ae..1757c84551 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -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; } diff --git a/test/SemaCXX/constructor-initializer.cpp b/test/SemaCXX/constructor-initializer.cpp index 8e9e133d94..bf4b289a90 100644 --- a/test/SemaCXX/constructor-initializer.cpp +++ b/test/SemaCXX/constructor-initializer.cpp @@ -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); + } +} |