From e9c9d15ef9429257136564c5bab76dbe286e37c7 Mon Sep 17 00:00:00 2001 From: Chandler Carruth Date: Wed, 30 Jun 2010 00:54:29 +0000 Subject: [PATCH] Fix PR7402: We were creating implicit member initializers for every field in an 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 | 75 +++++++++++++++--------- 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(); 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(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 S(T) : ptr_(0) { } + }; + + void f() { + MyStruct s(3); + } +} -- 2.40.0