diff options
author | Anders Carlsson <andersca@mac.com> | 2010-04-02 06:26:44 +0000 |
---|---|---|
committer | Anders Carlsson <andersca@mac.com> | 2010-04-02 06:26:44 +0000 |
commit | bcc12fdaa7b3276b46c8e1349d5c99fd42d6a0a1 (patch) | |
tree | 51ef4de44a7a8d2cb74a2710c4de3d9274c18564 | |
parent | ea356fb65cc844abeab1176f6333a86b69644735 (diff) |
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
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 184 | ||||
-rw-r--r-- | test/SemaTemplate/instantiate-member-initializers.cpp | 6 |
2 files changed, 80 insertions, 110 deletions
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<CXXBaseOrMemberInitializer*, 32> AllToInit; llvm::DenseMap<const void *, CXXBaseOrMemberInitializer*> 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<RecordType>()] = Member; - } else { + else AllBaseFields[Member->getMember()] = Member; - } } - if (HasDependentBaseInit) { - // FIXME. This does not preserve the ordering of the initializers. - // Try (with -Wreorder) - // template<class X> struct A {}; - // template<class X> struct B : A<X> { - // B() : x1(10), A<X>() {} - // int x1; - // }; - // B<int> 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<CXXBaseSpecifier *, 4> 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<RecordType>())) { - 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<CXXBaseSpecifier *, 4> 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<Expr>(), - 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<RecordType>())) { + 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<RecordType>())) { - 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<Expr>(), - SourceLocation()); - AllToInit.push_back(CXXBaseInit); + CXXBaseOrMemberInitializer *CXXBaseInit = + new (Context) CXXBaseOrMemberInitializer(Context, + Context.getTrivialTypeSourceInfo(VBase->getType(), + SourceLocation()), + SourceLocation(), + BaseInit.takeAs<Expr>(), + 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<RecordType>())) { + 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<Expr>(), + 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<int> a0; A<void*> a1; // expected-note{{in instantiation of member function 'A<void *>::A' requested here}} template<typename T> 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<int> b0; +B<int> b0; // expected-note {{in instantiation of member function 'B<int>::B' requested here}} template <class T> struct AA { AA(int); }; template <class T> class BB : public AA<T> { |