From: Anders Carlsson Date: Fri, 2 Apr 2010 06:26:44 +0000 (+0000) Subject: If a constructor is a dependent context, just set the base and member initializers... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=bcc12fdaa7b3276b46c8e1349d5c99fd42d6a0a1;p=clang If a constructor is a dependent context, just set the base and member initializers as they are written. Fixes a bug where we wouldn't show initialization order warnings when instantiating. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@100180 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index c77ff97f66..47df43516c 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1430,6 +1430,21 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, CXXBaseOrMemberInitializer **Initializers, unsigned NumInitializers, bool AnyErrors) { + if (Constructor->isDependentContext()) { + // Just store the initializers as written, they will be checked during + // instantiation. + if (NumInitializers > 0) { + Constructor->setNumBaseOrMemberInitializers(NumInitializers); + CXXBaseOrMemberInitializer **baseOrMemberInitializers = + new (Context) CXXBaseOrMemberInitializer*[NumInitializers]; + memcpy(baseOrMemberInitializers, Initializers, + NumInitializers * sizeof(CXXBaseOrMemberInitializer*)); + Constructor->setBaseOrMemberInitializers(baseOrMemberInitializers); + } + + return false; + } + // We need to build the initializer AST according to order of construction // and not what user specified in the Initializers list. CXXRecordDecl *ClassDecl = Constructor->getParent()->getDefinition(); @@ -1438,127 +1453,82 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, llvm::SmallVector AllToInit; llvm::DenseMap AllBaseFields; - bool HasDependentBaseInit = false; bool HadError = false; for (unsigned i = 0; i < NumInitializers; i++) { CXXBaseOrMemberInitializer *Member = Initializers[i]; - if (Member->isBaseInitializer()) { - if (Member->getBaseClass()->isDependentType()) - HasDependentBaseInit = true; + + if (Member->isBaseInitializer()) AllBaseFields[Member->getBaseClass()->getAs()] = Member; - } else { + else AllBaseFields[Member->getMember()] = Member; - } } - if (HasDependentBaseInit) { - // FIXME. This does not preserve the ordering of the initializers. - // Try (with -Wreorder) - // template struct A {}; - // template struct B : A { - // B() : x1(10), A() {} - // int x1; - // }; - // B x; - // On seeing one dependent type, we should essentially exit this routine - // while preserving user-declared initializer list. When this routine is - // called during instantiatiation process, this routine will rebuild the - // ordered initializer list correctly. - - // If we have a dependent base initialization, we can't determine the - // association between initializers and bases; just dump the known - // initializers into the list, and don't try to deal with other bases. - for (unsigned i = 0; i < NumInitializers; i++) { - CXXBaseOrMemberInitializer *Member = Initializers[i]; - if (Member->isBaseInitializer()) - AllToInit.push_back(Member); - } - } else { - llvm::SmallVector BasesToDefaultInit; - - // Push virtual bases before others. - for (CXXRecordDecl::base_class_iterator VBase = - ClassDecl->vbases_begin(), - E = ClassDecl->vbases_end(); VBase != E; ++VBase) { - if (VBase->getType()->isDependentType()) - continue; - if (CXXBaseOrMemberInitializer *Value - = AllBaseFields.lookup(VBase->getType()->getAs())) { - AllToInit.push_back(Value); - } else if (!AnyErrors) { - InitializedEntity InitEntity - = InitializedEntity::InitializeBase(Context, VBase); - InitializationKind InitKind - = InitializationKind::CreateDefault(Constructor->getLocation()); - InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0); - OwningExprResult BaseInit = InitSeq.Perform(*this, InitEntity, InitKind, - MultiExprArg(*this, 0, 0)); - BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit)); - if (BaseInit.isInvalid()) { - HadError = true; - continue; - } + llvm::SmallVector BasesToDefaultInit; - // Don't attach synthesized base initializers in a dependent - // context; they'll be checked again at template instantiation - // time. - if (CurContext->isDependentContext()) - continue; - - CXXBaseOrMemberInitializer *CXXBaseInit = - new (Context) CXXBaseOrMemberInitializer(Context, - Context.getTrivialTypeSourceInfo(VBase->getType(), - SourceLocation()), - SourceLocation(), - BaseInit.takeAs(), - SourceLocation()); - AllToInit.push_back(CXXBaseInit); - } - } + // Push virtual bases before others. + for (CXXRecordDecl::base_class_iterator VBase = ClassDecl->vbases_begin(), + E = ClassDecl->vbases_end(); VBase != E; ++VBase) { - for (CXXRecordDecl::base_class_iterator Base = - ClassDecl->bases_begin(), - E = ClassDecl->bases_end(); Base != E; ++Base) { - // Virtuals are in the virtual base list and already constructed. - if (Base->isVirtual()) - continue; - // Skip dependent types. - if (Base->getType()->isDependentType()) + if (CXXBaseOrMemberInitializer *Value + = AllBaseFields.lookup(VBase->getType()->getAs())) { + AllToInit.push_back(Value); + } else if (!AnyErrors) { + InitializedEntity InitEntity + = InitializedEntity::InitializeBase(Context, VBase); + InitializationKind InitKind + = InitializationKind::CreateDefault(Constructor->getLocation()); + InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0); + OwningExprResult BaseInit = InitSeq.Perform(*this, InitEntity, InitKind, + MultiExprArg(*this, 0, 0)); + BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit)); + if (BaseInit.isInvalid()) { + HadError = true; continue; - if (CXXBaseOrMemberInitializer *Value - = AllBaseFields.lookup(Base->getType()->getAs())) { - AllToInit.push_back(Value); } - else if (!AnyErrors) { - InitializedEntity InitEntity - = InitializedEntity::InitializeBase(Context, Base); - InitializationKind InitKind - = InitializationKind::CreateDefault(Constructor->getLocation()); - InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0); - OwningExprResult BaseInit = InitSeq.Perform(*this, InitEntity, InitKind, - MultiExprArg(*this, 0, 0)); - BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit)); - if (BaseInit.isInvalid()) { - HadError = true; - continue; - } - // Don't attach synthesized base initializers in a dependent - // context; they'll be regenerated at template instantiation - // time. - if (CurContext->isDependentContext()) - continue; - - CXXBaseOrMemberInitializer *CXXBaseInit = - new (Context) CXXBaseOrMemberInitializer(Context, - Context.getTrivialTypeSourceInfo(Base->getType(), - SourceLocation()), - SourceLocation(), - BaseInit.takeAs(), - SourceLocation()); - AllToInit.push_back(CXXBaseInit); + CXXBaseOrMemberInitializer *CXXBaseInit = + new (Context) CXXBaseOrMemberInitializer(Context, + Context.getTrivialTypeSourceInfo(VBase->getType(), + SourceLocation()), + SourceLocation(), + BaseInit.takeAs(), + SourceLocation()); + AllToInit.push_back(CXXBaseInit); + } + } + + for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), + E = ClassDecl->bases_end(); Base != E; ++Base) { + // Virtuals are in the virtual base list and already constructed. + if (Base->isVirtual()) + continue; + + if (CXXBaseOrMemberInitializer *Value + = AllBaseFields.lookup(Base->getType()->getAs())) { + AllToInit.push_back(Value); + } else if (!AnyErrors) { + InitializedEntity InitEntity + = InitializedEntity::InitializeBase(Context, Base); + InitializationKind InitKind + = InitializationKind::CreateDefault(Constructor->getLocation()); + InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0); + OwningExprResult BaseInit = InitSeq.Perform(*this, InitEntity, InitKind, + MultiExprArg(*this, 0, 0)); + BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit)); + if (BaseInit.isInvalid()) { + HadError = true; + continue; } + + CXXBaseOrMemberInitializer *CXXBaseInit = + new (Context) CXXBaseOrMemberInitializer(Context, + Context.getTrivialTypeSourceInfo(Base->getType(), + SourceLocation()), + SourceLocation(), + BaseInit.takeAs(), + SourceLocation()); + AllToInit.push_back(CXXBaseInit); } } diff --git a/test/SemaTemplate/instantiate-member-initializers.cpp b/test/SemaTemplate/instantiate-member-initializers.cpp index eecb445ea9..e0594347f2 100644 --- a/test/SemaTemplate/instantiate-member-initializers.cpp +++ b/test/SemaTemplate/instantiate-member-initializers.cpp @@ -10,14 +10,14 @@ A a0; A a1; // expected-note{{in instantiation of member function 'A::A' requested here}} template struct B { - // FIXME: This should warn about initialization order - B() : b(1), a(2) { } + B() : b(1), // expected-warning {{member 'b' will be initialized after}} + a(2) { } // expected-note {{field a}} int a; int b; }; -B b0; +B b0; // expected-note {{in instantiation of member function 'B::B' requested here}} template struct AA { AA(int); }; template class BB : public AA {