diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index ddc077456b23..5666c0a8d33e 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -4244,9 +4244,8 @@ updateExceptionSpec(Sema &S, FunctionDecl *FD, const FunctionProtoType *FPT, const Sema::ImplicitExceptionSpecification &ExceptSpec) { FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); ExceptSpec.getEPI(EPI); - const FunctionProtoType *NewFPT = cast( - S.Context.getFunctionType(FPT->getResultType(), FPT->getArgTypes(), EPI)); - FD->setType(QualType(NewFPT, 0)); + FD->setType(S.Context.getFunctionType(FPT->getResultType(), + FPT->getArgTypes(), EPI)); } void Sema::EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD) { @@ -7655,208 +7654,305 @@ void Sema::ActOnFinishDelayedMemberInitializers(Decl *D) { CheckDelayedExplicitlyDefaultedMemberExceptionSpecs(); } -void Sema::DeclareInheritingConstructors(CXXRecordDecl *ClassDecl) { - // We start with an initial pass over the base classes to collect those that - // inherit constructors from. If there are none, we can forgo all further - // processing. - typedef SmallVector BasesVector; - BasesVector BasesToInheritFrom; - for (CXXRecordDecl::base_class_iterator BaseIt = ClassDecl->bases_begin(), - BaseE = ClassDecl->bases_end(); - BaseIt != BaseE; ++BaseIt) { - if (BaseIt->getInheritConstructors()) { - QualType Base = BaseIt->getType(); - if (Base->isDependentType()) { - // If we inherit constructors from anything that is dependent, just - // abort processing altogether. We'll get another chance for the - // instantiations. - // FIXME: We need to ensure that any call to a constructor of this class - // is considered instantiation-dependent in this case. - return; +namespace { +/// Information on inheriting constructors to declare. +class InheritingConstructorInfo { +public: + InheritingConstructorInfo(Sema &SemaRef, CXXRecordDecl *Derived) + : SemaRef(SemaRef), Derived(Derived) { + // Mark the constructors that we already have in the derived class. + // + // C++11 [class.inhctor]p3: [...] a constructor is implicitly declared [...] + // unless there is a user-declared constructor with the same signature in + // the class where the using-declaration appears. + visitAll(Derived, &InheritingConstructorInfo::noteDeclaredInDerived); + } + + void inheritAll(CXXRecordDecl *RD) { + visitAll(RD, &InheritingConstructorInfo::inherit); + } + +private: + /// Information about an inheriting constructor. + struct InheritingConstructor { + InheritingConstructor() + : DeclaredInDerived(false), BaseCtor(0), DerivedCtor(0) {} + + /// If \c true, a constructor with this signature is already declared + /// in the derived class. + bool DeclaredInDerived; + + /// The constructor which is inherited. + const CXXConstructorDecl *BaseCtor; + + /// The derived constructor we declared. + CXXConstructorDecl *DerivedCtor; + }; + + /// Inheriting constructors with a given canonical type. There can be at + /// most one such non-template constructor, and any number of templated + /// constructors. + struct InheritingConstructorsForType { + InheritingConstructor NonTemplate; + llvm::SmallVector< + std::pair, 4> Templates; + + InheritingConstructor &getEntry(Sema &S, const CXXConstructorDecl *Ctor) { + if (FunctionTemplateDecl *FTD = Ctor->getDescribedFunctionTemplate()) { + TemplateParameterList *ParamList = FTD->getTemplateParameters(); + for (unsigned I = 0, N = Templates.size(); I != N; ++I) + if (S.TemplateParameterListsAreEqual(ParamList, Templates[I].first, + false, S.TPL_TemplateMatch)) + return Templates[I].second; + Templates.push_back(std::make_pair(ParamList, InheritingConstructor())); + return Templates.back().second; } - BasesToInheritFrom.push_back(Base->castAs()); + + return NonTemplate; + } + }; + + /// Get or create the inheriting constructor record for a constructor. + InheritingConstructor &getEntry(const CXXConstructorDecl *Ctor, + QualType CtorType) { + return Map[CtorType.getCanonicalType()->castAs()] + .getEntry(SemaRef, Ctor); + } + + typedef void (InheritingConstructorInfo::*VisitFn)(const CXXConstructorDecl*); + + /// Process all constructors for a class. + void visitAll(const CXXRecordDecl *RD, VisitFn Callback) { + for (CXXRecordDecl::ctor_iterator CtorIt = RD->ctor_begin(), + CtorE = RD->ctor_end(); + CtorIt != CtorE; ++CtorIt) + (this->*Callback)(*CtorIt); + for (CXXRecordDecl::specific_decl_iterator + I(RD->decls_begin()), E(RD->decls_end()); + I != E; ++I) { + const FunctionDecl *FD = (*I)->getTemplatedDecl(); + if (const CXXConstructorDecl *CD = dyn_cast(FD)) + (this->*Callback)(CD); } } - if (BasesToInheritFrom.empty()) + + /// Note that a constructor (or constructor template) was declared in Derived. + void noteDeclaredInDerived(const CXXConstructorDecl *Ctor) { + getEntry(Ctor, Ctor->getType()).DeclaredInDerived = true; + } + + /// Inherit a single constructor. + void inherit(const CXXConstructorDecl *Ctor) { + const FunctionProtoType *CtorType = + Ctor->getType()->castAs(); + ArrayRef ArgTypes(CtorType->getArgTypes()); + FunctionProtoType::ExtProtoInfo EPI = CtorType->getExtProtoInfo(); + + SourceLocation UsingLoc = getUsingLoc(Ctor->getParent()); + + // Core issue (no number yet): the ellipsis is always discarded. + if (EPI.Variadic) { + SemaRef.Diag(UsingLoc, diag::warn_using_decl_constructor_ellipsis); + SemaRef.Diag(Ctor->getLocation(), + diag::note_using_decl_constructor_ellipsis); + EPI.Variadic = false; + } + + // Declare a constructor for each number of parameters. + // + // C++11 [class.inhctor]p1: + // The candidate set of inherited constructors from the class X named in + // the using-declaration consists of [... modulo defects ...] for each + // constructor or constructor template of X, the set of constructors or + // constructor templates that results from omitting any ellipsis parameter + // specification and successively omitting parameters with a default + // argument from the end of the parameter-type-list + for (unsigned Params = std::max(minParamsToInherit(Ctor), + Ctor->getMinRequiredArguments()), + MaxParams = Ctor->getNumParams(); + Params <= MaxParams; ++Params) + declareCtor(UsingLoc, Ctor, + SemaRef.Context.getFunctionType( + Ctor->getResultType(), ArgTypes.slice(0, Params), EPI)); + } + + /// Find the using-declaration which specified that we should inherit the + /// constructors of \p Base. + SourceLocation getUsingLoc(const CXXRecordDecl *Base) { + // No fancy lookup required; just look for the base constructor name + // directly within the derived class. + ASTContext &Context = SemaRef.Context; + DeclarationName Name = Context.DeclarationNames.getCXXConstructorName( + Context.getCanonicalType(Context.getRecordType(Base))); + DeclContext::lookup_const_result Decls = Derived->lookup(Name); + return Decls.empty() ? Derived->getLocation() : Decls[0]->getLocation(); + } + + unsigned minParamsToInherit(const CXXConstructorDecl *Ctor) { + // C++11 [class.inhctor]p3: + // [F]or each constructor template in the candidate set of inherited + // constructors, a constructor template is implicitly declared + if (Ctor->getDescribedFunctionTemplate()) + return 0; + + // For each non-template constructor in the candidate set of inherited + // constructors other than a constructor having no parameters or a + // copy/move constructor having a single parameter, a constructor is + // implicitly declared [...] + if (Ctor->getNumParams() == 0) + return 1; + if (Ctor->isCopyOrMoveConstructor()) + return 2; + + // Per discussion on core reflector, never inherit a constructor which + // would become a default, copy, or move constructor of Derived either. + const ParmVarDecl *PD = Ctor->getParamDecl(0); + const ReferenceType *RT = PD->getType()->getAs(); + return (RT && RT->getPointeeCXXRecordDecl() == Derived) ? 2 : 1; + } + + /// Declare a single inheriting constructor, inheriting the specified + /// constructor, with the given type. + void declareCtor(SourceLocation UsingLoc, const CXXConstructorDecl *BaseCtor, + QualType DerivedType) { + InheritingConstructor &Entry = getEntry(BaseCtor, DerivedType); + + // C++11 [class.inhctor]p3: + // ... a constructor is implicitly declared with the same constructor + // characteristics unless there is a user-declared constructor with + // the same signature in the class where the using-declaration appears + if (Entry.DeclaredInDerived) + return; + + // C++11 [class.inhctor]p7: + // If two using-declarations declare inheriting constructors with the + // same signature, the program is ill-formed + if (Entry.DerivedCtor) { + if (BaseCtor->getParent() != Entry.BaseCtor->getParent()) { + // Only diagnose this once per constructor. + if (Entry.DerivedCtor->isInvalidDecl()) + return; + Entry.DerivedCtor->setInvalidDecl(); + + SemaRef.Diag(UsingLoc, diag::err_using_decl_constructor_conflict); + SemaRef.Diag(BaseCtor->getLocation(), + diag::note_using_decl_constructor_conflict_current_ctor); + SemaRef.Diag(Entry.BaseCtor->getLocation(), + diag::note_using_decl_constructor_conflict_previous_ctor); + SemaRef.Diag(Entry.DerivedCtor->getLocation(), + diag::note_using_decl_constructor_conflict_previous_using); + } else { + // Core issue (no number): if the same inheriting constructor is + // produced by multiple base class constructors from the same base + // class, the inheriting constructor is defined as deleted. + SemaRef.SetDeclDeleted(Entry.DerivedCtor, UsingLoc); + } + + return; + } + + ASTContext &Context = SemaRef.Context; + DeclarationName Name = Context.DeclarationNames.getCXXConstructorName( + Context.getCanonicalType(Context.getRecordType(Derived))); + DeclarationNameInfo NameInfo(Name, UsingLoc); + + TemplateParameterList *TemplateParams = 0; + if (const FunctionTemplateDecl *FTD = + BaseCtor->getDescribedFunctionTemplate()) { + TemplateParams = FTD->getTemplateParameters(); + // We're reusing template parameters from a different DeclContext. This + // is questionable at best, but works out because the template depth in + // both places is guaranteed to be 0. + // FIXME: Rebuild the template parameters in the new context, and + // transform the function type to refer to them. + } + + // Build type source info pointing at the using-declaration. This is + // required by template instantiation. + TypeSourceInfo *TInfo = + Context.getTrivialTypeSourceInfo(DerivedType, UsingLoc); + FunctionProtoTypeLoc ProtoLoc = + TInfo->getTypeLoc().IgnoreParens().castAs(); + + CXXConstructorDecl *DerivedCtor = CXXConstructorDecl::Create( + Context, Derived, UsingLoc, NameInfo, DerivedType, + TInfo, BaseCtor->isExplicit(), /*Inline=*/true, + /*ImplicitlyDeclared=*/true, /*Constexpr=*/BaseCtor->isConstexpr()); + + // Build an unevaluated exception specification for this constructor. + const FunctionProtoType *FPT = DerivedType->castAs(); + FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); + EPI.ExceptionSpecType = EST_Unevaluated; + EPI.ExceptionSpecDecl = DerivedCtor; + DerivedCtor->setType(Context.getFunctionType(FPT->getResultType(), + FPT->getArgTypes(), EPI)); + + // Build the parameter declarations. + SmallVector ParamDecls; + for (unsigned I = 0, N = FPT->getNumArgs(); I != N; ++I) { + TypeSourceInfo *TInfo = + Context.getTrivialTypeSourceInfo(FPT->getArgType(I), UsingLoc); + ParmVarDecl *PD = ParmVarDecl::Create( + Context, DerivedCtor, UsingLoc, UsingLoc, /*IdentifierInfo=*/0, + FPT->getArgType(I), TInfo, SC_None, /*DefaultArg=*/0); + PD->setScopeInfo(0, I); + PD->setImplicit(); + ParamDecls.push_back(PD); + ProtoLoc.setArg(I, PD); + } + + // Set up the new constructor. + DerivedCtor->setAccess(BaseCtor->getAccess()); + DerivedCtor->setParams(ParamDecls); + DerivedCtor->setInheritedConstructor(BaseCtor); + if (BaseCtor->isDeleted()) + SemaRef.SetDeclDeleted(DerivedCtor, UsingLoc); + + // If this is a constructor template, build the template declaration. + if (TemplateParams) { + FunctionTemplateDecl *DerivedTemplate = + FunctionTemplateDecl::Create(SemaRef.Context, Derived, UsingLoc, Name, + TemplateParams, DerivedCtor); + DerivedTemplate->setAccess(BaseCtor->getAccess()); + DerivedCtor->setDescribedFunctionTemplate(DerivedTemplate); + Derived->addDecl(DerivedTemplate); + } else { + Derived->addDecl(DerivedCtor); + } + + Entry.BaseCtor = BaseCtor; + Entry.DerivedCtor = DerivedCtor; + } + + Sema &SemaRef; + CXXRecordDecl *Derived; + typedef llvm::DenseMap MapType; + MapType Map; +}; +} + +void Sema::DeclareInheritingConstructors(CXXRecordDecl *ClassDecl) { + // Defer declaring the inheriting constructors until the class is + // instantiated. + if (ClassDecl->isDependentContext()) return; - // FIXME: Constructor templates. + // Find base classes from which we might inherit constructors. + SmallVector InheritedBases; + for (CXXRecordDecl::base_class_iterator BaseIt = ClassDecl->bases_begin(), + BaseE = ClassDecl->bases_end(); + BaseIt != BaseE; ++BaseIt) + if (BaseIt->getInheritConstructors()) + InheritedBases.push_back(BaseIt->getType()->getAsCXXRecordDecl()); - // Now collect the constructors that we already have in the current class. - // Those take precedence over inherited constructors. - // C++11 [class.inhctor]p3: [...] a constructor is implicitly declared [...] - // unless there is a user-declared constructor with the same signature in - // the class where the using-declaration appears. - llvm::SmallSet ExistingConstructors; - for (CXXRecordDecl::ctor_iterator CtorIt = ClassDecl->ctor_begin(), - CtorE = ClassDecl->ctor_end(); - CtorIt != CtorE; ++CtorIt) - ExistingConstructors.insert( - Context.getCanonicalType(CtorIt->getType()).getTypePtr()); + // Go no further if we're not inheriting any constructors. + if (InheritedBases.empty()) + return; - DeclarationName CreatedCtorName = - Context.DeclarationNames.getCXXConstructorName( - ClassDecl->getTypeForDecl()->getCanonicalTypeUnqualified()); - - // Now comes the true work. - // First, we keep a map from constructor types to the base that introduced - // them. Needed for finding conflicting constructors. We also keep the - // actually inserted declarations in there, for pretty diagnostics. - typedef std::pair ConstructorInfo; - typedef llvm::DenseMap ConstructorToSourceMap; - ConstructorToSourceMap InheritedConstructors; - for (BasesVector::iterator BaseIt = BasesToInheritFrom.begin(), - BaseE = BasesToInheritFrom.end(); - BaseIt != BaseE; ++BaseIt) { - const RecordType *Base = *BaseIt; - CanQualType CanonicalBase = Base->getCanonicalTypeUnqualified(); - CXXRecordDecl *BaseDecl = cast(Base->getDecl()); - for (CXXRecordDecl::ctor_iterator CtorIt = BaseDecl->ctor_begin(), - CtorE = BaseDecl->ctor_end(); - CtorIt != CtorE; ++CtorIt) { - // Find the using declaration for inheriting this base's constructors. - // FIXME: Don't perform name lookup just to obtain a source location! - DeclarationName Name = - Context.DeclarationNames.getCXXConstructorName(CanonicalBase); - LookupResult Result(*this, Name, SourceLocation(), LookupUsingDeclName); - LookupQualifiedName(Result, CurContext); - UsingDecl *UD = Result.getAsSingle(); - SourceLocation UsingLoc = UD ? UD->getLocation() : - ClassDecl->getLocation(); - - // C++11 [class.inhctor]p1: - // The candidate set of inherited constructors from the class X named in - // the using-declaration consists of actual constructors and notional - // constructors that result from the transformation of defaulted - // parameters as follows: - // - all non-template constructors of X, and - // - for each non-template constructor of X that has at least one - // parameter with a default argument, the set of constructors that - // results from omitting any ellipsis parameter specification and - // successively omitting parameters with a default argument from the - // end of the parameter-type-list, and - // FIXME: ...also constructor templates. - CXXConstructorDecl *BaseCtor = *CtorIt; - bool CanBeCopyOrMove = BaseCtor->isCopyOrMoveConstructor(); - const FunctionProtoType *BaseCtorType = - BaseCtor->getType()->getAs(); - - // Determine whether this would be a copy or move constructor for the - // derived class. - if (BaseCtorType->getNumArgs() >= 1 && - BaseCtorType->getArgType(0)->isReferenceType() && - Context.hasSameUnqualifiedType( - BaseCtorType->getArgType(0)->getPointeeType(), - Context.getTagDeclType(ClassDecl))) - CanBeCopyOrMove = true; - - ArrayRef ArgTypes(BaseCtorType->getArgTypes()); - FunctionProtoType::ExtProtoInfo EPI = BaseCtorType->getExtProtoInfo(); - // Core issue (no number yet): the ellipsis is always discarded. - if (EPI.Variadic) { - Diag(UsingLoc, diag::warn_using_decl_constructor_ellipsis); - Diag(BaseCtor->getLocation(), - diag::note_using_decl_constructor_ellipsis); - EPI.Variadic = false; - } - - for (unsigned Params = BaseCtor->getMinRequiredArguments(), - MaxParams = BaseCtor->getNumParams(); - Params <= MaxParams; ++Params) { - // Skip default constructors. They're never inherited. - if (Params == 0) - continue; - - // Skip copy and move constructors for both base and derived class - // for the same reason. - if (CanBeCopyOrMove && Params == 1) - continue; - - // Build up a function type for this particular constructor. - QualType NewCtorType = - Context.getFunctionType(Context.VoidTy, ArgTypes.slice(0, Params), - EPI); - const Type *CanonicalNewCtorType = - Context.getCanonicalType(NewCtorType).getTypePtr(); - - // C++11 [class.inhctor]p3: - // ... a constructor is implicitly declared with the same constructor - // characteristics unless there is a user-declared constructor with - // the same signature in the class where the using-declaration appears - if (ExistingConstructors.count(CanonicalNewCtorType)) - continue; - - // C++11 [class.inhctor]p7: - // If two using-declarations declare inheriting constructors with the - // same signature, the program is ill-formed - std::pair result = - InheritedConstructors.insert(std::make_pair( - CanonicalNewCtorType, - std::make_pair(CanonicalBase, (CXXConstructorDecl*)0))); - if (!result.second) { - // Already in the map. If it came from a different class, that's an - // error. Not if it's from the same. - CanQualType PreviousBase = result.first->second.first; - if (CanonicalBase != PreviousBase) { - const CXXConstructorDecl *PrevCtor = result.first->second.second; - const CXXConstructorDecl *PrevBaseCtor = - PrevCtor->getInheritedConstructor(); - assert(PrevBaseCtor && "Conflicting constructor was not inherited"); - - Diag(UsingLoc, diag::err_using_decl_constructor_conflict); - Diag(BaseCtor->getLocation(), - diag::note_using_decl_constructor_conflict_current_ctor); - Diag(PrevBaseCtor->getLocation(), - diag::note_using_decl_constructor_conflict_previous_ctor); - Diag(PrevCtor->getLocation(), - diag::note_using_decl_constructor_conflict_previous_using); - } else { - // Core issue (no number): if the same inheriting constructor is - // produced by multiple base class constructors from the same base - // class, the inheriting constructor is defined as deleted. - SetDeclDeleted(result.first->second.second, UsingLoc); - } - continue; - } - - // OK, we're there, now add the constructor. - DeclarationNameInfo DNI(CreatedCtorName, UsingLoc); - CXXConstructorDecl *NewCtor = CXXConstructorDecl::Create( - Context, ClassDecl, UsingLoc, DNI, NewCtorType, - /*TInfo=*/0, BaseCtor->isExplicit(), /*Inline=*/true, - /*ImplicitlyDeclared=*/true, /*Constexpr=*/BaseCtor->isConstexpr()); - NewCtor->setAccess(BaseCtor->getAccess()); - - // Build an unevaluated exception specification for this constructor. - EPI.ExceptionSpecType = EST_Unevaluated; - EPI.ExceptionSpecDecl = NewCtor; - NewCtor->setType(Context.getFunctionType(Context.VoidTy, - ArgTypes.slice(0, Params), - EPI)); - - // Build up the parameter decls and add them. - SmallVector ParamDecls; - for (unsigned i = 0; i < Params; ++i) { - ParmVarDecl *PD = ParmVarDecl::Create(Context, NewCtor, - UsingLoc, UsingLoc, - /*IdentifierInfo=*/0, - BaseCtorType->getArgType(i), - /*TInfo=*/0, SC_None, - /*DefaultArg=*/0); - PD->setScopeInfo(0, i); - PD->setImplicit(); - ParamDecls.push_back(PD); - } - NewCtor->setParams(ParamDecls); - NewCtor->setInheritedConstructor(BaseCtor); - if (BaseCtor->isDeleted()) - SetDeclDeleted(NewCtor, UsingLoc); - - ClassDecl->addDecl(NewCtor); - result.first->second.second = NewCtor; - } - } - } + // Declare the inherited constructors. + InheritingConstructorInfo ICI(*this, ClassDecl); + for (unsigned I = 0, N = InheritedBases.size(); I != N; ++I) + ICI.inheritAll(InheritedBases[I]); } void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation, diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 33e83d07d634..17e3218bffc1 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1513,6 +1513,10 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Constructor->isExplicit(), Constructor->isInlineSpecified(), false, Constructor->isConstexpr()); + // Claim that the instantiation of a constructor or constructor template + // inherits the same constructor that the template does. + if (const CXXConstructorDecl *Inh = Constructor->getInheritedConstructor()) + cast(Method)->setInheritedConstructor(Inh); } else if (CXXDestructorDecl *Destructor = dyn_cast(D)) { Method = CXXDestructorDecl::Create(SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, @@ -2688,15 +2692,16 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, FunctionDecl *ExceptionSpecTemplate = Tmpl; if (EPI.ExceptionSpecType == EST_Uninstantiated) ExceptionSpecTemplate = EPI.ExceptionSpecTemplate; - assert(EPI.ExceptionSpecType != EST_Unevaluated && - "instantiating implicitly-declared special member"); + ExceptionSpecificationType NewEST = EST_Uninstantiated; + if (EPI.ExceptionSpecType == EST_Unevaluated) + NewEST = EST_Unevaluated; // Mark the function has having an uninstantiated exception specification. const FunctionProtoType *NewProto = New->getType()->getAs(); assert(NewProto && "Template instantiation without function prototype?"); EPI = NewProto->getExtProtoInfo(); - EPI.ExceptionSpecType = EST_Uninstantiated; + EPI.ExceptionSpecType = NewEST; EPI.ExceptionSpecDecl = New; EPI.ExceptionSpecTemplate = ExceptionSpecTemplate; New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(), @@ -2733,7 +2738,6 @@ TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New, if (Tmpl->isVirtualAsWritten()) New->setVirtualAsWritten(true); - // FIXME: attributes // FIXME: New needs a pointer to Tmpl return false; } diff --git a/clang/test/CXX/special/class.inhctor/elsewhere.cpp b/clang/test/CXX/special/class.inhctor/elsewhere.cpp index 184e90298b0a..b986f6582495 100644 --- a/clang/test/CXX/special/class.inhctor/elsewhere.cpp +++ b/clang/test/CXX/special/class.inhctor/elsewhere.cpp @@ -55,3 +55,10 @@ template struct F : D { using A::A; // expected-error {{'A' is not a direct base of 'F'}} }; F fb; // expected-note {{here}} + +template +struct G : T { + using T::T; + G(int &) : G(0) {} +}; +G g(123); diff --git a/clang/test/CXX/special/class.inhctor/p1.cpp b/clang/test/CXX/special/class.inhctor/p1.cpp index 57e91504d684..7300495c0c07 100644 --- a/clang/test/CXX/special/class.inhctor/p1.cpp +++ b/clang/test/CXX/special/class.inhctor/p1.cpp @@ -2,17 +2,24 @@ // Per a core issue (no number yet), an ellipsis is always dropped. struct A { A(...); // expected-note {{here}} - A(int = 0, int = 0, int = 0, int = 0, ...); // expected-note 5{{here}} + A(int = 0, int = 0, int = 0, int = 0, ...); // expected-note 9{{here}} A(int = 0, int = 0, ...); // expected-note {{here}} + + template A(T, int = 0, ...); // expected-note 5{{here}} + + template A(const T (&)[N]); // expected-note 2{{here}} + template A(const T (&)[N], int = 0); // expected-note 2{{here}} }; -struct B : A { // expected-note 3{{candidate}} - using A::A; // expected-warning 3{{inheriting constructor does not inherit ellipsis}} expected-note 4{{candidate}} expected-note 2{{deleted}} +struct B : A { // expected-note 6{{candidate}} + using A::A; // expected-warning 4{{inheriting constructor does not inherit ellipsis}} expected-note 16{{candidate}} expected-note 3{{deleted}} }; +struct C {} c; + B b0{}; // expected-error@-1 {{call to implicitly-deleted default constructor}} -// expected-note@9 {{default constructor of 'B' is implicitly deleted because base class 'A' has multiple default constructors}} +// expected-note@-8 {{default constructor of 'B' is implicitly deleted because base class 'A' has multiple default constructors}} B b1{1}; // FIXME: explain why the inheriting constructor was deleted @@ -29,3 +36,16 @@ B b4{1,2,3,4}; B b5{1,2,3,4,5}; // expected-error@-1 {{no matching constructor for initialization of 'B'}} + +B b6{c}; +// ok + +B b7{c,0}; +// ok + +B b8{c,0,1}; +// expected-error@-1 {{no matching constructor}} + +B b9{"foo"}; +// FIXME: explain why the inheriting constructor was deleted +// expected-error@-2 {{call to deleted constructor of 'B'}} diff --git a/clang/test/CXX/special/class.inhctor/p2.cpp b/clang/test/CXX/special/class.inhctor/p2.cpp index e4267385ced8..e6abd6840e46 100644 --- a/clang/test/CXX/special/class.inhctor/p2.cpp +++ b/clang/test/CXX/special/class.inhctor/p2.cpp @@ -3,7 +3,7 @@ template struct X {}; // Constructor characteristics are: -// - the template parameter list [FIXME] +// - the template parameter list // - the parameter-type-list // - absence or presence of explicit // - absence or presence of constexpr @@ -85,3 +85,37 @@ struct ConstexprEval3 : ConstexprEval, ConstexprEval2 { constexpr ConstexprEval3 ce{4, "foobar"}; static_assert(ce.k == 'a', ""); static_assert(ce.k2 == 'x', ""); + + +struct TemplateCtors { + constexpr TemplateCtors() {} + template class T> TemplateCtors(X<0>, T<0>); + template TemplateCtors(X<1>, X); + template TemplateCtors(X<2>, T); + + template TemplateCtors(int, int = 0, int = 0); // expected-note {{inherited from here}} +}; + +struct UsingTemplateCtors : TemplateCtors { + using TemplateCtors::TemplateCtors; // expected-note 4{{here}} expected-note {{candidate}} + + constexpr UsingTemplateCtors(X<0>, X<0>) {} + constexpr UsingTemplateCtors(X<1>, X<1>) {} + constexpr UsingTemplateCtors(X<2>, X<2>) {} + + template constexpr UsingTemplateCtors(int) {} // expected-note {{candidate}} + template constexpr UsingTemplateCtors(int, int) {} + template constexpr UsingTemplateCtors(int, int, int) {} +}; + +template struct Y {}; +constexpr UsingTemplateCtors uct1{ X<0>{}, X<0>{} }; +constexpr UsingTemplateCtors uct2{ X<0>{}, Y<0>{} }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}} +constexpr UsingTemplateCtors uct3{ X<1>{}, X<0>{} }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}} +constexpr UsingTemplateCtors uct4{ X<1>{}, X<1>{} }; +constexpr UsingTemplateCtors uct5{ X<2>{}, 0 }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}} +constexpr UsingTemplateCtors uct6{ X<2>{}, X<2>{} }; + +constexpr UsingTemplateCtors utc7{ 0 }; // expected-error {{ambiguous}} +constexpr UsingTemplateCtors utc8{ 0, 0 }; // ok +constexpr UsingTemplateCtors utc9{ 0, 0, 0 }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}} diff --git a/clang/test/CXX/special/class.inhctor/p3.cpp b/clang/test/CXX/special/class.inhctor/p3.cpp index f71ab16c0f17..7aaaa7a6f0b8 100644 --- a/clang/test/CXX/special/class.inhctor/p3.cpp +++ b/clang/test/CXX/special/class.inhctor/p3.cpp @@ -46,3 +46,13 @@ struct U { friend T3::T3(int); friend T3::T3(int, int); }; + +struct B4 { + template explicit B4(T, int = 0); +}; +template struct T4 : B4 { + using B4::B4; // expected-note {{here}} + template T4(U); +}; +T4 t4a = {0}; +T4 t4b = {0, 0}; // expected-error {{chosen constructor is explicit}} diff --git a/clang/test/CXX/special/class.inhctor/p4.cpp b/clang/test/CXX/special/class.inhctor/p4.cpp index eea3bf297317..512705e4dd94 100644 --- a/clang/test/CXX/special/class.inhctor/p4.cpp +++ b/clang/test/CXX/special/class.inhctor/p4.cpp @@ -44,11 +44,13 @@ FA fa2{X<2>{}}; // expected-error {{calling a private constructor}} // It is deleted if the corresponding constructor [...] is deleted. struct G { G(int) = delete; + template G(T*) = delete; }; struct H : G { - using G::G; // expected-note {{marked deleted here}} + using G::G; // expected-note 2{{marked deleted here}} }; -H h(5); // expected-error {{call to implicitly-deleted function of 'H'}} +H h1(5); // expected-error {{call to implicitly-deleted function of 'H'}} +H h2("foo"); // expected-error {{call to deleted constructor of 'H'}} // Core defect: It is also deleted if multiple base constructors generate the diff --git a/clang/test/CXX/special/class.inhctor/p7.cpp b/clang/test/CXX/special/class.inhctor/p7.cpp index 9ae160f0547a..a57e8558f5cb 100644 --- a/clang/test/CXX/special/class.inhctor/p7.cpp +++ b/clang/test/CXX/special/class.inhctor/p7.cpp @@ -27,3 +27,21 @@ template struct B4 : B3, B1 { }; B4 b4c; B4 b4i; // expected-note {{here}} + +struct B5 { + template B5(T); // expected-note {{previous constructor}} +}; +struct B6 { + template B6(T); // expected-note {{conflicting constructor}} +}; +struct B7 { + template B7(T); +}; +struct D56 : B5, B6, B7 { + using B5::B5; // expected-note {{inherited here}} + using B6::B6; // expected-error {{already inherited}} +}; +struct D57 : B5, B6, B7 { + using B5::B5; + using B7::B7; // ok, not the same signature +}; diff --git a/clang/test/CXX/special/class.inhctor/p8.cpp b/clang/test/CXX/special/class.inhctor/p8.cpp index e2b07dfae81d..0c857382e38c 100644 --- a/clang/test/CXX/special/class.inhctor/p8.cpp +++ b/clang/test/CXX/special/class.inhctor/p8.cpp @@ -19,3 +19,12 @@ constexpr B b0{0}; constexpr B b1{k}; static_assert(a0.rval && !a1.rval && b0.rval && !b1.rval, ""); + +struct C { + template constexpr C(T t) : v(t) {} + int v; +}; +struct D : C { + using C::C; +}; +static_assert(D(123).v == 123, ""); diff --git a/clang/test/CodeGenCXX/inheriting-constructor.cpp b/clang/test/CodeGenCXX/inheriting-constructor.cpp index adb9f6dc1a7b..0f3978492976 100644 --- a/clang/test/CodeGenCXX/inheriting-constructor.cpp +++ b/clang/test/CodeGenCXX/inheriting-constructor.cpp @@ -7,6 +7,10 @@ B::~B() {} B b(123); +struct C { template C(T); }; +struct D : C { using C::C; }; +D d(123); + // CHECK: define void @_ZN1BD0Ev // CHECK: define void @_ZN1BD1Ev // CHECK: define void @_ZN1BD2Ev @@ -14,5 +18,11 @@ B b(123); // CHECK: define linkonce_odr void @_ZN1BC1Ei( // CHECK: call void @_ZN1BC2Ei( +// CHECK: define linkonce_odr void @_ZN1DC1IiEET_( +// CHECK: call void @_ZN1DC2IiEET_( + +// CHECK: define linkonce_odr void @_ZN1DC2IiEET_( +// CHECK: call void @_ZN1CC2IiEET_( + // CHECK: define linkonce_odr void @_ZN1BC2Ei( // CHECK: call void @_ZN1AC2Ei(