Index: lib/Sema/SemaDeclCXX.cpp =================================================================== --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -3823,6 +3823,10 @@ if (Info.AnyErrorsInInits) return false; + // Don't try to implicitly initialize any fields with dependent types. + if (Field->getType()->isDependentType()) + return false; + CXXCtorInitializer *Init = nullptr; if (BuildImplicitMemberInitializer(Info.S, Info.Ctor, Info.IIK, Field, Indirect, Init)) @@ -3856,27 +3860,20 @@ return false; } +static bool +hasDependentBasesOrInitializers(const CXXRecordDecl *RD, + ArrayRef Inits) { + for (const CXXBaseSpecifier &Base : RD->bases()) + if (Base.getType()->isDependentType()) + return true; + for (CXXCtorInitializer *Init : Inits) + if (Init->isBaseInitializer() && Init->getBaseClass()->isDependentType()) + return true; + return false; +} + bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors, ArrayRef Initializers) { - if (Constructor->isDependentContext()) { - // Just store the initializers as written, they will be checked during - // instantiation. - if (!Initializers.empty()) { - Constructor->setNumCtorInitializers(Initializers.size()); - CXXCtorInitializer **baseOrMemberInitializers = - new (Context) CXXCtorInitializer*[Initializers.size()]; - memcpy(baseOrMemberInitializers, Initializers.data(), - Initializers.size() * sizeof(CXXCtorInitializer*)); - Constructor->setCtorInitializers(baseOrMemberInitializers); - } - - // Let template instantiation know whether we had errors. - if (AnyErrors) - Constructor->setInvalidDecl(); - - return false; - } - BaseAndFieldInfo Info(*this, Constructor, AnyErrors); // We need to build the initializer AST according to order of construction @@ -3884,15 +3881,21 @@ CXXRecordDecl *ClassDecl = Constructor->getParent()->getDefinition(); if (!ClassDecl) return true; - - bool HadError = false; - for (unsigned i = 0; i < Initializers.size(); i++) { - CXXCtorInitializer *Member = Initializers[i]; + // If there are any dependent bases or dependent initializers, we won't be + // able to establish the correct ordering until after instantiation. For now, + // we move bases to the front of the list, and leave them in source order. + bool HasDependentBasesOrInits = + hasDependentBasesOrInitializers(ClassDecl, Initializers); + bool HadError = false; - if (Member->isBaseInitializer()) - Info.AllBaseFields[Member->getBaseClass()->getAs()] = Member; - else { + for (CXXCtorInitializer *Member : Initializers) { + if (Member->isBaseInitializer()) { + if (!HasDependentBasesOrInits) { + Info.AllBaseFields[Member->getBaseClass()->castAs()] = + Member; + } + } else { Info.AllBaseFields[Member->getAnyMember()->getCanonicalDecl()] = Member; if (IndirectFieldDecl *F = Member->getIndirectMember()) { @@ -3910,67 +3913,69 @@ } } - // Keep track of the direct virtual bases. - llvm::SmallPtrSet DirectVBases; - for (auto &I : ClassDecl->bases()) { - if (I.isVirtual()) - DirectVBases.insert(&I); - } - - // Push virtual bases before others. - for (auto &VBase : ClassDecl->vbases()) { - if (CXXCtorInitializer *Value - = Info.AllBaseFields.lookup(VBase.getType()->getAs())) { - // [class.base.init]p7, per DR257: - // A mem-initializer where the mem-initializer-id names a virtual base - // class is ignored during execution of a constructor of any class that - // is not the most derived class. - if (ClassDecl->isAbstract()) { - // FIXME: Provide a fixit to remove the base specifier. This requires - // tracking the location of the associated comma for a base specifier. - Diag(Value->getSourceLocation(), diag::warn_abstract_vbase_init_ignored) - << VBase.getType() << ClassDecl; - DiagnoseAbstractType(ClassDecl); - } + if (!HasDependentBasesOrInits) { + // Keep track of the direct virtual bases. + llvm::SmallPtrSet DirectVBases; + for (auto &I : ClassDecl->bases()) { + if (I.isVirtual()) + DirectVBases.insert(&I); + } + + // Push virtual bases before others. + for (auto &VBase : ClassDecl->vbases()) { + if (CXXCtorInitializer *Value = + Info.AllBaseFields.lookup(VBase.getType()->getAs())) { + // [class.base.init]p7, per DR257: + // A mem-initializer where the mem-initializer-id names a virtual base + // class is ignored during execution of a constructor of any class + // that is not the most derived class. + if (ClassDecl->isAbstract()) { + // FIXME: Provide a fixit to remove the base specifier. This requires + // tracking the location of the associated comma for a base specifier. + Diag(Value->getSourceLocation(), + diag::warn_abstract_vbase_init_ignored) + << VBase.getType() << ClassDecl; + DiagnoseAbstractType(ClassDecl); + } - Info.AllToInit.push_back(Value); - } else if (!AnyErrors && !ClassDecl->isAbstract()) { - // [class.base.init]p8, per DR257: - // If a given [...] base class is not named by a mem-initializer-id - // [...] and the entity is not a virtual base class of an abstract - // class, then [...] the entity is default-initialized. - bool IsInheritedVirtualBase = !DirectVBases.count(&VBase); - CXXCtorInitializer *CXXBaseInit; - if (BuildImplicitBaseInitializer(*this, Constructor, Info.IIK, - &VBase, IsInheritedVirtualBase, - CXXBaseInit)) { - HadError = true; - continue; - } + Info.AllToInit.push_back(Value); + } else if (!AnyErrors && !ClassDecl->isAbstract()) { + // [class.base.init]p8, per DR257: + // If a given [...] base class is not named by a mem-initializer-id + // [...] and the entity is not a virtual base class of an abstract + // class, then [...] the entity is default-initialized. + bool IsInheritedVirtualBase = !DirectVBases.count(&VBase); + CXXCtorInitializer *CXXBaseInit; + if (BuildImplicitBaseInitializer(*this, Constructor, Info.IIK, &VBase, + IsInheritedVirtualBase, CXXBaseInit)) { + HadError = true; + continue; + } - Info.AllToInit.push_back(CXXBaseInit); + Info.AllToInit.push_back(CXXBaseInit); + } } - } - // Non-virtual bases. - for (auto &Base : ClassDecl->bases()) { - // Virtuals are in the virtual base list and already constructed. - if (Base.isVirtual()) - continue; - - if (CXXCtorInitializer *Value - = Info.AllBaseFields.lookup(Base.getType()->getAs())) { - Info.AllToInit.push_back(Value); - } else if (!AnyErrors) { - CXXCtorInitializer *CXXBaseInit; - if (BuildImplicitBaseInitializer(*this, Constructor, Info.IIK, - &Base, /*IsInheritedVirtualBase=*/false, - CXXBaseInit)) { - HadError = true; + // Non-virtual bases. + for (auto &Base : ClassDecl->bases()) { + // Virtuals are in the virtual base list and already constructed. + if (Base.isVirtual()) continue; - } - Info.AllToInit.push_back(CXXBaseInit); + if (CXXCtorInitializer *Value = + Info.AllBaseFields.lookup(Base.getType()->getAs())) { + Info.AllToInit.push_back(Value); + } else if (!AnyErrors) { + CXXCtorInitializer *CXXBaseInit; + if (BuildImplicitBaseInitializer(*this, Constructor, Info.IIK, &Base, + /*IsInheritedVirtualBase=*/false, + CXXBaseInit)) { + HadError = true; + continue; + } + + Info.AllToInit.push_back(CXXBaseInit); + } } } @@ -4014,13 +4019,30 @@ } } - unsigned NumInitializers = Info.AllToInit.size(); + // Leave all the initializers that didn't correspond to bases or fields in + // source order in the AST at the front. They must all be base initializers + // that are somehow dependent on template parameters. + llvm::SmallPtrSet UsedInits(Info.AllToInit.begin(), + Info.AllToInit.end()); + SmallVector MissingInits; + for (CXXCtorInitializer *Init : Initializers) { + if (!UsedInits.count(Init)) { + assert(Init->isBaseInitializer() && "lost field initializer"); + MissingInits.push_back(Init); + } + } + + unsigned NumInitializers = MissingInits.size() + Info.AllToInit.size(); + assert(NumInitializers >= Initializers.size() && "lost initializers"); if (NumInitializers > 0) { Constructor->setNumCtorInitializers(NumInitializers); CXXCtorInitializer **baseOrMemberInitializers = new (Context) CXXCtorInitializer*[NumInitializers]; - memcpy(baseOrMemberInitializers, Info.AllToInit.data(), - NumInitializers * sizeof(CXXCtorInitializer*)); + memcpy(baseOrMemberInitializers, MissingInits.data(), + MissingInits.size() * sizeof(CXXCtorInitializer *)); + memcpy(baseOrMemberInitializers + MissingInits.size(), + Info.AllToInit.data(), + Info.AllToInit.size() * sizeof(CXXCtorInitializer *)); Constructor->setCtorInitializers(baseOrMemberInitializers); // Constructors implicitly reference the base and member @@ -4059,9 +4081,6 @@ static void DiagnoseBaseOrMemInitializerOrder( Sema &SemaRef, const CXXConstructorDecl *Constructor, ArrayRef Inits) { - if (Constructor->getDeclContext()->isDependentContext()) - return; - // Don't check initializers order unless the warning is enabled at the // location of at least one initializer. bool ShouldCheckOrder = false; @@ -4106,8 +4125,27 @@ unsigned IdealIndex = 0; CXXCtorInitializer *PrevInit = nullptr; - for (unsigned InitIndex = 0; InitIndex != Inits.size(); ++InitIndex) { - CXXCtorInitializer *Init = Inits[InitIndex]; + + // If we have dependent bases or base initializers, we can't reason about + // their relative ordering. We will reorder all base initializers to the + // front, but we won't reorder them relative to each other. + bool HasDependentBasesOrInits = + hasDependentBasesOrInitializers(ClassDecl, Inits); + + for (CXXCtorInitializer *Init : Inits) { + // Don't try to reason about the relative order of dependent type base + // initializers. We'll try to catch them during instantiation. We can still + // warn if this is a base initializer after a field initializer. + if (HasDependentBasesOrInits && Init->isBaseInitializer()) { + if (PrevInit && PrevInit->isAnyMemberInitializer()) { + SemaRef.Diag(PrevInit->getSourceLocation(), + diag::warn_initializer_out_of_order) + << /*field*/ 0 << PrevInit->getAnyMember()->getDeclName() + << /*base*/ 1 << Init->getTypeSourceInfo()->getType(); + } + continue; + } + const void *InitKey = GetKeyForMember(SemaRef.Context, Init); // Scan forward to try to find this initializer in the idealized Index: test/SemaTemplate/class-template-ctor-initializer.cpp =================================================================== --- test/SemaTemplate/class-template-ctor-initializer.cpp +++ test/SemaTemplate/class-template-ctor-initializer.cpp @@ -57,6 +57,7 @@ } namespace NonDependentError { + // expected-note@+1 2 {{declared here}} struct Base { Base(int); }; // expected-note {{candidate constructor not viable}} // expected-note@-1 {{candidate constructor (the implicit copy constructor) not viable}} #if __cplusplus >= 201103L // C++11 or later @@ -65,14 +66,44 @@ template struct Derived1 : Base { + // expected-error@+1 {{must explicitly initialize the base class}} Derived1() : Base(1, 2) {} // expected-error {{no matching constructor}} }; template struct Derived2 : Base { + // expected-error@+1 {{must explicitly initialize the base class}} Derived2() : BaseClass(1) {} // expected-error {{does not name a non-static data member or base}} }; - Derived1 d1; - Derived2 d2; + Derived1 d1; // expected-note {{requested here}} + Derived2 d2; // expected-note {{requested here}} +} + +namespace pr24658 { +// expected-error@+2 {{cannot be defined in a type specifier}} +// expected-error@+1 {{non-type template parameter cannot}} +template void f(); + +#if __cplusplus >= 201402L +// expected-error@+1 {{cannot be defined in a type specifier}} +template int x = sizeof(struct B : T{B(){}}); +#endif + +// expected-note@+1 {{'pr24658::C' declared here}} +struct C { C(int); }; + +template struct D { + // expected-note@+1 {{member is declared here}} + C c; + // expected-error@+1 {{must explicitly initialize the member 'c'}} + D() {} +}; + +struct X { }; + +template struct E : X, C { + E() : X(), T(0) {} +}; +E y; } Index: test/SemaTemplate/default-expr-arguments.cpp =================================================================== --- test/SemaTemplate/default-expr-arguments.cpp +++ test/SemaTemplate/default-expr-arguments.cpp @@ -158,13 +158,18 @@ // PR5810 namespace PR5810 { - template - struct allocator { - allocator() { int a[sizeof(T) ? -1 : -1]; } // expected-error2 {{array with a negative size}} - }; +template +struct allocator { + // expected-note@-1 {{candidate constructor (the implicit copy constructor) not viable: requires 1 argument, but 0 were provided}} +#if __cplusplus >= 201103L + // expected-note@-3 {{candidate constructor (the implicit move constructor) not viable: requires 1 argument, but 0 were provided}} +#endif + allocator() { int a[sizeof(T) ? -1 : -1]; } // expected-error2 {{array with a negative size}} +}; template struct vector { + // expected-error@+1 {{no matching constructor for initialization of 'allocator'}} vector(const allocator& = allocator()) {} // expected-note2 {{instantiation of}} }; @@ -183,6 +188,7 @@ template struct X { vector bs; + // expected-note@+1 {{in instantiation of default function argument expression for 'vector' required here}} X() { } }; Index: test/SemaTemplate/instantiate-member-initializers.cpp =================================================================== --- test/SemaTemplate/instantiate-member-initializers.cpp +++ test/SemaTemplate/instantiate-member-initializers.cpp @@ -17,7 +17,42 @@ int b; }; -B b0; // expected-note {{in instantiation of member function 'B::B' requested here}} +B b0; + +namespace test2 { +struct A {}; +struct B {}; +template +struct C : A, B { + int f1; + int f2; + C() : A() + , f1(0) // expected-warning {{field 'f1' will be initialized after base 'T'}} + , T() + , f2(0) + {} +}; +C c; + +template +struct D : A, B { + int f1; + int f2; + D() : A() + , T() + , f2(0) // expected-warning {{field 'f2' will be initialized after field 'f1'}} + , f1(0) + {} +}; +D d; + +template +struct E : A, B { + // expected-warning@+1 {{base class 'test2::B' will be initialized after base 'test2::A'}} + E() : T(), A() {} +}; +E e; // expected-note-re {{in instantiation {{.*}} requested here}} +} template struct AA { AA(int); }; template class BB : public AA {