diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -1621,7 +1621,7 @@ Decl *AssociatedDecl, unsigned Index, Optional PackIndex) const; QualType getSubstTemplateTypeParmPackType(Decl *AssociatedDecl, - unsigned Index, + unsigned Index, bool Final, const TemplateArgument &ArgPack); QualType @@ -2208,7 +2208,8 @@ Optional PackIndex) const; TemplateName getSubstTemplateTemplateParmPack(const TemplateArgument &ArgPack, Decl *AssociatedDecl, - unsigned Index) const; + unsigned Index, + bool Final) const; enum GetBuiltinTypeError { /// No error diff --git a/clang/include/clang/AST/PropertiesBase.td b/clang/include/clang/AST/PropertiesBase.td --- a/clang/include/clang/AST/PropertiesBase.td +++ b/clang/include/clang/AST/PropertiesBase.td @@ -730,8 +730,11 @@ def : Property<"index", UInt32> { let Read = [{ parm->getIndex() }]; } + def : Property<"sugared", Bool> { + let Read = [{ parm->getFinal() }]; + } def : Creator<[{ - return ctx.getSubstTemplateTemplateParmPack(argumentPack, associatedDecl, index); + return ctx.getSubstTemplateTemplateParmPack(argumentPack, associatedDecl, index, sugared); }]>; } diff --git a/clang/include/clang/AST/TemplateName.h b/clang/include/clang/AST/TemplateName.h --- a/clang/include/clang/AST/TemplateName.h +++ b/clang/include/clang/AST/TemplateName.h @@ -139,25 +139,24 @@ class SubstTemplateTemplateParmPackStorage : public UncommonTemplateNameStorage, public llvm::FoldingSetNode { const TemplateArgument *Arguments; - Decl *AssociatedDecl; + llvm::PointerIntPair AssociatedDeclAndFinal; public: SubstTemplateTemplateParmPackStorage(ArrayRef ArgPack, - Decl *AssociatedDecl, unsigned Index) - : UncommonTemplateNameStorage(SubstTemplateTemplateParmPack, Index, - ArgPack.size()), - Arguments(ArgPack.data()), AssociatedDecl(AssociatedDecl) { - assert(AssociatedDecl != nullptr); - } + Decl *AssociatedDecl, unsigned Index, + bool Final); /// A template-like entity which owns the whole pattern being substituted. /// This will own a set of template parameters. - Decl *getAssociatedDecl() const { return AssociatedDecl; } + Decl *getAssociatedDecl() const; /// Returns the index of the replaced parameter in the associated declaration. /// This should match the result of `getParameterPack()->getIndex()`. unsigned getIndex() const { return Bits.Index; } + // Represents a sugared substitution (not replacing with Subst sugar). + bool getFinal() const; + /// Retrieve the template template parameter pack being substituted. TemplateTemplateParmDecl *getParameterPack() const; @@ -169,7 +168,7 @@ static void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context, const TemplateArgument &ArgPack, Decl *AssociatedDecl, - unsigned Index); + unsigned Index, bool Final); }; /// Represents a C++ template name within the type system. diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -5156,10 +5156,10 @@ /// parameter pack is instantiated with. const TemplateArgument *Arguments; - Decl *AssociatedDecl; + llvm::PointerIntPair AssociatedDeclAndFinal; SubstTemplateTypeParmPackType(QualType Canon, Decl *AssociatedDecl, - unsigned Index, + unsigned Index, bool Final, const TemplateArgument &ArgPack); public: @@ -5168,7 +5168,7 @@ /// A template-like entity which owns the whole pattern being substituted. /// This will usually own a set of template parameters, or in some /// cases might even be a template parameter itself. - Decl *getAssociatedDecl() const { return AssociatedDecl; } + Decl *getAssociatedDecl() const; /// Gets the template parameter declaration that was substituted for. const TemplateTypeParmDecl *getReplacedParameter() const; @@ -5177,6 +5177,9 @@ /// This should match the result of `getReplacedParameter()->getIndex()`. unsigned getIndex() const { return SubstTemplateTypeParmPackTypeBits.Index; } + // Represents a sugared substitution (not replacing with Subst sugar). + bool getFinal() const; + unsigned getNumArgs() const { return SubstTemplateTypeParmPackTypeBits.NumArgs; } @@ -5188,7 +5191,8 @@ void Profile(llvm::FoldingSetNodeID &ID); static void Profile(llvm::FoldingSetNodeID &ID, const Decl *AssociatedDecl, - unsigned Index, const TemplateArgument &ArgPack); + unsigned Index, bool Final, + const TemplateArgument &ArgPack); static bool classof(const Type *T) { return T->getTypeClass() == SubstTemplateTypeParmPack; diff --git a/clang/include/clang/AST/TypeProperties.td b/clang/include/clang/AST/TypeProperties.td --- a/clang/include/clang/AST/TypeProperties.td +++ b/clang/include/clang/AST/TypeProperties.td @@ -773,13 +773,16 @@ def : Property<"Index", UInt32> { let Read = [{ node->getIndex() }]; } + def : Property<"Final", Bool> { + let Read = [{ node->getFinal() }]; + } def : Property<"replacementPack", TemplateArgument> { let Read = [{ node->getArgumentPack() }]; } def : Creator<[{ return ctx.getSubstTemplateTypeParmPackType( - associatedDecl, Index, replacementPack); + associatedDecl, Index, Final, replacementPack); }]>; } diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -9078,10 +9078,12 @@ // C++ Template Instantiation // - MultiLevelTemplateArgumentList getTemplateInstantiationArgs( - const NamedDecl *D, const TemplateArgumentList *Innermost = nullptr, - bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr, - bool ForConstraintInstantiation = false); + MultiLevelTemplateArgumentList + getTemplateInstantiationArgs(const NamedDecl *D, bool Final = false, + const TemplateArgumentList *Innermost = nullptr, + bool RelativeToPrimary = false, + const FunctionDecl *Pattern = nullptr, + bool ForConstraintInstantiation = false); /// A context in which code is being synthesized (where a source location /// alone is not sufficient to identify the context). This covers template @@ -10175,16 +10177,12 @@ bool FailOnError = false); /// Build an Objective-C object pointer type. - QualType BuildObjCObjectType(QualType BaseType, - SourceLocation Loc, - SourceLocation TypeArgsLAngleLoc, - ArrayRef TypeArgs, - SourceLocation TypeArgsRAngleLoc, - SourceLocation ProtocolLAngleLoc, - ArrayRef Protocols, - ArrayRef ProtocolLocs, - SourceLocation ProtocolRAngleLoc, - bool FailOnError = false); + QualType BuildObjCObjectType( + QualType BaseType, SourceLocation Loc, SourceLocation TypeArgsLAngleLoc, + ArrayRef TypeArgs, SourceLocation TypeArgsRAngleLoc, + SourceLocation ProtocolLAngleLoc, ArrayRef Protocols, + ArrayRef ProtocolLocs, SourceLocation ProtocolRAngleLoc, + bool FailOnError, bool Rebuilding); /// Ensure attributes are consistent with type. /// \param [in, out] Attributes The attributes to check; they will diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h --- a/clang/include/clang/Sema/Template.h +++ b/clang/include/clang/Sema/Template.h @@ -77,7 +77,7 @@ using ArgList = ArrayRef; struct ArgumentListLevel { - Decl *AssociatedDecl; + llvm::PointerIntPair AssociatedDeclAsFinal; ArgList Args; }; using ContainerType = SmallVector; @@ -101,8 +101,8 @@ MultiLevelTemplateArgumentList() = default; /// Construct a single-level template argument list. - MultiLevelTemplateArgumentList(Decl *D, ArgList Args) { - addOuterTemplateArguments(D, Args); + MultiLevelTemplateArgumentList(Decl *D, ArgList Args, bool Final) { + addOuterTemplateArguments(D, Args, Final); } void setKind(TemplateSubstitutionKind K) { Kind = K; } @@ -160,9 +160,12 @@ /// A template-like entity which owns the whole pattern being substituted. /// This will usually own a set of template parameters, or in some /// cases might even be a template parameter itself. - Decl *getAssociatedDecl(unsigned Depth) const { + /// Returns nullptr for fully-sugared substitutions. + std::pair getAssociatedDecl(unsigned Depth) const { assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels()); - return TemplateArgumentLists[getNumLevels() - Depth - 1].AssociatedDecl; + auto AD = TemplateArgumentLists[getNumLevels() - Depth - 1] + .AssociatedDeclAsFinal; + return {AD.getPointer(), AD.getInt()}; } /// Determine whether there is a non-NULL template argument at the @@ -202,21 +205,22 @@ /// Add a new outmost level to the multi-level template argument /// list. - void addOuterTemplateArguments(Decl *AssociatedDecl, ArgList Args) { + /// A 'Final' substitution means that Subst* nodes won't be built + /// for the replacements. + void addOuterTemplateArguments(Decl *AssociatedDecl, ArgList Args, + bool Final) { assert(!NumRetainedOuterLevels && "substituted args outside retained args?"); assert(getKind() == TemplateSubstitutionKind::Specialization); - assert(AssociatedDecl != nullptr || Args.size() == 0); TemplateArgumentLists.push_back( - {AssociatedDecl ? AssociatedDecl->getCanonicalDecl() : nullptr, - Args}); + {{AssociatedDecl->getCanonicalDecl(), Final}, Args}); } void addOuterTemplateArguments(ArgList Args) { assert(!NumRetainedOuterLevels && "substituted args outside retained args?"); assert(getKind() == TemplateSubstitutionKind::Rewrite); - TemplateArgumentLists.push_back({nullptr, Args}); + TemplateArgumentLists.push_back({{}, Args}); } void addOuterTemplateArguments(llvm::NoneType) { diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -3041,6 +3041,23 @@ return getObjCLayout(D->getClassInterface(), D); } +static bool +getCanonicalTemplateArguments(const ASTContext &C, + ArrayRef OrigArgs, + SmallVectorImpl &CanonArgs) { + bool AnyNonCanonArgs = false; + unsigned NumArgs = OrigArgs.size(); + CanonArgs.resize(NumArgs); + for (unsigned I = 0; I != NumArgs; ++I) { + const TemplateArgument &OrigArg = OrigArgs[I]; + TemplateArgument &CanonArg = CanonArgs[I]; + CanonArg = C.getCanonicalTemplateArgument(OrigArg); + if (!CanonArg.structurallyEquals(OrigArg)) + AnyNonCanonArgs = true; + } + return AnyNonCanonArgs; +} + //===----------------------------------------------------------------------===// // Type creation/memoization methods //===----------------------------------------------------------------------===// @@ -4848,31 +4865,42 @@ } /// Retrieve a -QualType ASTContext::getSubstTemplateTypeParmPackType( - Decl *AssociatedDecl, unsigned Index, const TemplateArgument &ArgPack) { +QualType +ASTContext::getSubstTemplateTypeParmPackType(Decl *AssociatedDecl, + unsigned Index, bool Final, + const TemplateArgument &ArgPack) { #ifndef NDEBUG - for (const auto &P : ArgPack.pack_elements()) { + for (const auto &P : ArgPack.pack_elements()) assert(P.getKind() == TemplateArgument::Type && "Pack contains a non-type"); - assert(P.getAsType().isCanonical() && "Pack contains non-canonical type"); - } #endif llvm::FoldingSetNodeID ID; - SubstTemplateTypeParmPackType::Profile(ID, AssociatedDecl, Index, ArgPack); + SubstTemplateTypeParmPackType::Profile(ID, AssociatedDecl, Index, Final, + ArgPack); void *InsertPos = nullptr; if (SubstTemplateTypeParmPackType *SubstParm = SubstTemplateTypeParmPackTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(SubstParm, 0); QualType Canon; - if (!AssociatedDecl->isCanonicalDecl()) { - Canon = getSubstTemplateTypeParmPackType(AssociatedDecl->getCanonicalDecl(), - Index, ArgPack); - SubstTemplateTypeParmPackTypes.FindNodeOrInsertPos(ID, InsertPos); - } - - auto *SubstParm = new (*this, TypeAlignment) - SubstTemplateTypeParmPackType(Canon, AssociatedDecl, Index, ArgPack); + { + SmallVector Args(ArgPack.pack_size()); + TemplateArgument CanonArgPack = ArgPack; + bool AnyNonCanonArgs = + getCanonicalTemplateArguments(*this, ArgPack.pack_elements(), Args); + if (AnyNonCanonArgs) + CanonArgPack = TemplateArgument::CreatePackCopy(*this, Args); + if (!AssociatedDecl->isCanonicalDecl() || AnyNonCanonArgs) { + Canon = getSubstTemplateTypeParmPackType( + AssociatedDecl->getCanonicalDecl(), Index, Final, CanonArgPack); + [[maybe_unused]] const auto *Nothing = + SubstTemplateTypeParmPackTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(!Nothing); + } + } + + auto *SubstParm = new (*this, TypeAlignment) SubstTemplateTypeParmPackType( + Canon, AssociatedDecl, Index, Final, ArgPack); Types.push_back(SubstParm); SubstTemplateTypeParmPackTypes.InsertNode(SubstParm, InsertPos); return QualType(SubstParm, 0); @@ -4997,23 +5025,6 @@ return QualType(Spec, 0); } -static bool -getCanonicalTemplateArguments(const ASTContext &C, - ArrayRef OrigArgs, - SmallVectorImpl &CanonArgs) { - bool AnyNonCanonArgs = false; - unsigned NumArgs = OrigArgs.size(); - CanonArgs.resize(NumArgs); - for (unsigned I = 0; I != NumArgs; ++I) { - const TemplateArgument &OrigArg = OrigArgs[I]; - TemplateArgument &CanonArg = CanonArgs[I]; - CanonArg = C.getCanonicalTemplateArgument(OrigArg); - if (!CanonArg.structurallyEquals(OrigArg)) - AnyNonCanonArgs = true; - } - return AnyNonCanonArgs; -} - QualType ASTContext::getCanonicalTemplateSpecializationType( TemplateName Template, ArrayRef Args) const { assert(!Template.getAsDependentTemplateName() && @@ -6284,7 +6295,7 @@ getCanonicalTemplateArgument(subst->getArgumentPack()); return getSubstTemplateTemplateParmPack( canonArgPack, subst->getAssociatedDecl()->getCanonicalDecl(), - subst->getIndex()); + subst->getFinal(), subst->getIndex()); } } @@ -9310,11 +9321,11 @@ TemplateName ASTContext::getSubstTemplateTemplateParmPack(const TemplateArgument &ArgPack, Decl *AssociatedDecl, - unsigned Index) const { + unsigned Index, bool Final) const { auto &Self = const_cast(*this); llvm::FoldingSetNodeID ID; SubstTemplateTemplateParmPackStorage::Profile(ID, Self, ArgPack, - AssociatedDecl, Index); + AssociatedDecl, Index, Final); void *InsertPos = nullptr; SubstTemplateTemplateParmPackStorage *Subst @@ -9322,7 +9333,7 @@ if (!Subst) { Subst = new (*this) SubstTemplateTemplateParmPackStorage( - ArgPack.pack_elements(), AssociatedDecl, Index); + ArgPack.pack_elements(), AssociatedDecl, Index, Final); SubstTemplateTemplateParmPacks.InsertNode(Subst, InsertPos); } diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -1547,7 +1547,7 @@ return ToArgumentPack.takeError(); return Importer.getToContext().getSubstTemplateTypeParmPackType( - *ReplacedOrErr, T->getIndex(), *ToArgumentPack); + *ReplacedOrErr, T->getIndex(), T->getFinal(), *ToArgumentPack); } ExpectedType ASTNodeImporter::VisitTemplateSpecializationType( @@ -9447,7 +9447,8 @@ return AssociatedDeclOrErr.takeError(); return ToContext.getSubstTemplateTemplateParmPack( - *ArgPackOrErr, *AssociatedDeclOrErr, SubstPack->getIndex()); + *ArgPackOrErr, *AssociatedDeclOrErr, SubstPack->getIndex(), + SubstPack->getFinal()); } case TemplateName::UsingTemplate: { auto UsingOrError = Import(From.getAsUsingShadowDecl()); diff --git a/clang/lib/AST/TemplateName.cpp b/clang/lib/AST/TemplateName.cpp --- a/clang/lib/AST/TemplateName.cpp +++ b/clang/lib/AST/TemplateName.cpp @@ -67,17 +67,37 @@ ID.AddInteger(PackIndex ? *PackIndex + 1 : 0); } +SubstTemplateTemplateParmPackStorage::SubstTemplateTemplateParmPackStorage( + ArrayRef ArgPack, Decl *AssociatedDecl, unsigned Index, + bool Final) + : UncommonTemplateNameStorage(SubstTemplateTemplateParmPack, Index, + ArgPack.size()), + Arguments(ArgPack.data()), AssociatedDeclAndFinal(AssociatedDecl, Final) { + assert(AssociatedDecl != nullptr); +} + void SubstTemplateTemplateParmPackStorage::Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context) { - Profile(ID, Context, getArgumentPack(), getAssociatedDecl(), getIndex()); + Profile(ID, Context, getArgumentPack(), getAssociatedDecl(), getIndex(), + getFinal()); +} + +Decl *SubstTemplateTemplateParmPackStorage::getAssociatedDecl() const { + return AssociatedDeclAndFinal.getPointer(); +} + +bool SubstTemplateTemplateParmPackStorage::getFinal() const { + return AssociatedDeclAndFinal.getInt(); } void SubstTemplateTemplateParmPackStorage::Profile( llvm::FoldingSetNodeID &ID, ASTContext &Context, - const TemplateArgument &ArgPack, Decl *AssociatedDecl, unsigned Index) { + const TemplateArgument &ArgPack, Decl *AssociatedDecl, unsigned Index, + bool Final) { ArgPack.Profile(ID, Context); ID.AddPointer(AssociatedDecl); ID.AddInteger(Index); + ID.AddBoolean(Final); } TemplateName::TemplateName(void *Ptr) { diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -3666,17 +3666,26 @@ } SubstTemplateTypeParmPackType::SubstTemplateTypeParmPackType( - QualType Canon, Decl *AssociatedDecl, unsigned Index, + QualType Canon, Decl *AssociatedDecl, unsigned Index, bool Final, const TemplateArgument &ArgPack) : Type(SubstTemplateTypeParmPack, Canon, TypeDependence::DependentInstantiation | TypeDependence::UnexpandedPack), - Arguments(ArgPack.pack_begin()), AssociatedDecl(AssociatedDecl) { + Arguments(ArgPack.pack_begin()), + AssociatedDeclAndFinal(AssociatedDecl, Final) { SubstTemplateTypeParmPackTypeBits.Index = Index; SubstTemplateTypeParmPackTypeBits.NumArgs = ArgPack.pack_size(); assert(AssociatedDecl != nullptr); } +Decl *SubstTemplateTypeParmPackType::getAssociatedDecl() const { + return AssociatedDeclAndFinal.getPointer(); +} + +bool SubstTemplateTypeParmPackType::getFinal() const { + return AssociatedDeclAndFinal.getInt(); +} + const TemplateTypeParmDecl * SubstTemplateTypeParmPackType::getReplacedParameter() const { return ::getReplacedParameter(getAssociatedDecl(), getIndex()); @@ -3691,15 +3700,16 @@ } void SubstTemplateTypeParmPackType::Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getAssociatedDecl(), getIndex(), getArgumentPack()); + Profile(ID, getAssociatedDecl(), getIndex(), getFinal(), getArgumentPack()); } void SubstTemplateTypeParmPackType::Profile(llvm::FoldingSetNodeID &ID, const Decl *AssociatedDecl, - unsigned Index, + unsigned Index, bool Final, const TemplateArgument &ArgPack) { ID.AddPointer(AssociatedDecl); ID.AddInteger(Index); + ID.AddBoolean(Final); ID.AddInteger(ArgPack.pack_size()); for (const auto &P : ArgPack.pack_elements()) ID.AddPointer(P.getAsType().getAsOpaquePtr()); diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -453,7 +453,8 @@ // the list of current template arguments to the list so that they also can // be picked out of the map. if (auto *SpecArgs = FD->getTemplateSpecializationArgs()) { - MultiLevelTemplateArgumentList JustTemplArgs(FD, SpecArgs->asArray()); + MultiLevelTemplateArgumentList JustTemplArgs(FD, SpecArgs->asArray(), + /*Final=*/false); if (addInstantiatedParametersToScope( FD, PrimaryTemplate->getTemplatedDecl(), Scope, JustTemplArgs)) return true; @@ -506,10 +507,11 @@ // Collect the list of template arguments relative to the 'primary' template. // We need the entire list, since the constraint is completely uninstantiated // at this point. - MLTAL = getTemplateInstantiationArgs(FD, /*Innermost=*/nullptr, - /*RelativeToPrimary=*/true, - /*Pattern=*/nullptr, - /*ForConstraintInstantiation=*/true); + MLTAL = + getTemplateInstantiationArgs(FD, /*Final=*/false, /*Innermost=*/nullptr, + /*RelativeToPrimary=*/true, + /*Pattern=*/nullptr, + /*ForConstraintInstantiation=*/true); if (SetupConstraintScope(FD, TemplateArgs, MLTAL, Scope)) return llvm::None; @@ -586,7 +588,7 @@ static unsigned CalculateTemplateDepthForConstraints(Sema &S, const NamedDecl *ND) { MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs( - ND, /*Innermost=*/nullptr, /*RelativeToPrimary=*/true, + ND, /*Final=*/false, /*Innermost=*/nullptr, /*RelativeToPrimary=*/true, /*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true); return MLTAL.getNumSubstitutedLevels(); @@ -599,8 +601,10 @@ using inherited = TreeTransform; AdjustConstraintDepth(Sema &SemaRef, unsigned TemplateDepth) : inherited(SemaRef), TemplateDepth(TemplateDepth) {} + + using inherited::TransformTemplateTypeParmType; QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB, - TemplateTypeParmTypeLoc TL) { + TemplateTypeParmTypeLoc TL, bool) { const TemplateTypeParmType *T = TL.getTypePtr(); TemplateTypeParmDecl *NewTTPDecl = nullptr; @@ -1071,11 +1075,11 @@ const ConceptSpecializationExpr *CSE) { TemplateArgumentList TAL{TemplateArgumentList::OnStack, CSE->getTemplateArguments()}; - MultiLevelTemplateArgumentList MLTAL = - S.getTemplateInstantiationArgs(CSE->getNamedConcept(), &TAL, - /*RelativeToPrimary=*/true, - /*Pattern=*/nullptr, - /*ForConstraintInstantiation=*/true); + MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs( + CSE->getNamedConcept(), /*Final=*/false, &TAL, + /*RelativeToPrimary=*/true, + /*Pattern=*/nullptr, + /*ForConstraintInstantiation=*/true); return substituteParameterMappings(S, N, CSE->getNamedConcept(), MLTAL, CSE->getTemplateArgsAsWritten()); diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -8964,7 +8964,8 @@ auto *Param = cast(TPL->getParam(0)); TemplateArgumentList TAL(TemplateArgumentList::OnStack, Args); - MultiLevelTemplateArgumentList MLTAL(Param, TAL.asArray()); + MultiLevelTemplateArgumentList MLTAL(Param, TAL.asArray(), + /*Final=*/false); MLTAL.addOuterRetainedLevels(TPL->getDepth()); Expr *IDC = Param->getTypeConstraint()->getImmediatelyDeclaredConstraint(); ExprResult Constraint = SubstExpr(IDC, MLTAL); diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1720,14 +1720,17 @@ // SubstTempalteTypeParmPack, SubstNonTypeTemplateParmPack, and // FunctionParmPackExpr are all partially substituted, which cannot happen // with concepts at this point in translation. + using inherited::TransformTemplateTypeParmType; QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB, - TemplateTypeParmTypeLoc TL) { + TemplateTypeParmTypeLoc TL, bool) { assert(TL.getDecl()->getDepth() <= TemplateDepth && "Nothing should reference a value below the actual template depth, " "depth is likely wrong"); if (TL.getDecl()->getDepth() != TemplateDepth) Result = true; - return inherited::TransformTemplateTypeParmType(TLB, TL); + return inherited::TransformTemplateTypeParmType( + TLB, TL, + /*SuppressObjCLifetime=*/false); } Decl *TransformDecl(SourceLocation Loc, Decl *D) { @@ -3850,13 +3853,10 @@ if (Pattern->isInvalidDecl()) return QualType(); - TemplateArgumentList StackTemplateArgs(TemplateArgumentList::OnStack, - CanonicalConverted); - // Only substitute for the innermost template argument list. MultiLevelTemplateArgumentList TemplateArgLists; - TemplateArgLists.addOuterTemplateArguments(Template, - StackTemplateArgs.asArray()); + TemplateArgLists.addOuterTemplateArguments(Template, CanonicalConverted, + /*Final=*/false); TemplateArgLists.addOuterRetainedLevels( AliasTemplate->getTemplateParameters()->getDepth()); @@ -3982,9 +3982,9 @@ ClassTemplate->getTemplatedDecl()->hasAttrs()) { InstantiatingTemplate Inst(*this, TemplateLoc, Decl); if (!Inst.isInvalid()) { - MultiLevelTemplateArgumentList TemplateArgLists; - TemplateArgLists.addOuterTemplateArguments(Template, - CanonicalConverted); + MultiLevelTemplateArgumentList TemplateArgLists(Template, + CanonicalConverted, + /*Final=*/false); InstantiateAttrsForDecl(TemplateArgLists, ClassTemplate->getTemplatedDecl(), Decl); } @@ -4865,7 +4865,8 @@ bool AreArgsDependent = TemplateSpecializationType::anyDependentTemplateArguments( *TemplateArgs, CanonicalConverted); - MultiLevelTemplateArgumentList MLTAL(NamedConcept, CanonicalConverted); + MultiLevelTemplateArgumentList MLTAL(NamedConcept, CanonicalConverted, + /*Final=*/false); LocalInstantiationScope Scope(*this); if (!AreArgsDependent && CheckConstraintSatisfaction( @@ -5273,11 +5274,9 @@ if (Inst.isInvalid()) return nullptr; - TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted); - // Only substitute for the innermost template argument list. - MultiLevelTemplateArgumentList TemplateArgLists(Template, - TemplateArgs.asArray()); + MultiLevelTemplateArgumentList TemplateArgLists(Template, Converted, + /*Final=*/false); for (unsigned i = 0, e = Param->getDepth(); i != e; ++i) TemplateArgLists.addOuterTemplateArguments(None); @@ -5329,11 +5328,9 @@ if (Inst.isInvalid()) return ExprError(); - TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted); - // Only substitute for the innermost template argument list. - MultiLevelTemplateArgumentList TemplateArgLists(Template, - TemplateArgs.asArray()); + MultiLevelTemplateArgumentList TemplateArgLists(Template, Converted, + /*Final=*/false); for (unsigned i = 0, e = Param->getDepth(); i != e; ++i) TemplateArgLists.addOuterTemplateArguments(None); @@ -5382,11 +5379,9 @@ if (Inst.isInvalid()) return TemplateName(); - TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted); - // Only substitute for the innermost template argument list. - MultiLevelTemplateArgumentList TemplateArgLists(Template, - TemplateArgs.asArray()); + MultiLevelTemplateArgumentList TemplateArgLists(Template, Converted, + /*Final=*/false); for (unsigned i = 0, e = Param->getDepth(); i != e; ++i) TemplateArgLists.addOuterTemplateArguments(None); @@ -5567,10 +5562,8 @@ if (Inst.isInvalid()) return true; - TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, - CanonicalConverted); - - MultiLevelTemplateArgumentList MLTAL(Template, TemplateArgs.asArray()); + MultiLevelTemplateArgumentList MLTAL(Template, CanonicalConverted, + /*Final=*/false); // If the parameter is a pack expansion, expand this slice of the pack. if (auto *PET = NTTPType->getAs()) { Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(*this, @@ -5732,9 +5725,10 @@ if (Inst.isInvalid()) return true; - Params = SubstTemplateParams( - Params, CurContext, - MultiLevelTemplateArgumentList(Template, CanonicalConverted)); + Params = + SubstTemplateParams(Params, CurContext, + MultiLevelTemplateArgumentList( + Template, CanonicalConverted, /*Final=*/false)); if (!Params) return true; } @@ -6133,7 +6127,8 @@ CXXThisScopeRAII(*this, RD, ThisQuals, RD != nullptr); MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs( - Template, &StackTemplateArgs, /*RelativeToPrimary=*/true, + Template, /*Final=*/false, &StackTemplateArgs, + /*RelativeToPrimary=*/true, /*Pattern=*/nullptr, /*ForConceptInstantiation=*/true); if (EnsureTemplateArgumentListConstraints( diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -2687,9 +2687,8 @@ // itself, in case that substitution fails. if (SugaredPackedArgsBuilder.empty()) { LocalInstantiationScope Scope(S); - TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, - CanonicalOutput); - MultiLevelTemplateArgumentList Args(Template, TemplateArgs.asArray()); + MultiLevelTemplateArgumentList Args(Template, CanonicalOutput, + /*Final=*/false); if (auto *NTTP = dyn_cast(Param)) { Sema::InstantiatingTemplate Inst(S, Template->getLocation(), Template, @@ -2890,7 +2889,8 @@ CanonicalDeducedArgs}; MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs( - Template, /*InnerMost=*/NeedsReplacement ? nullptr : &DeducedTAL, + Template, /*Final=*/false, + /*InnerMost=*/NeedsReplacement ? nullptr : &DeducedTAL, /*RelativeToPrimary=*/true, /*Pattern=*/ nullptr, /*ForConstraintInstantiation=*/true); @@ -2959,11 +2959,12 @@ TemplateArgumentListInfo InstArgs(PartialTemplArgInfo->LAngleLoc, PartialTemplArgInfo->RAngleLoc); - if (S.SubstTemplateArguments( - PartialTemplArgInfo->arguments(), - MultiLevelTemplateArgumentList( - Partial, CanonicalDeducedArgumentList->asArray()), - InstArgs)) { + if (S.SubstTemplateArguments(PartialTemplArgInfo->arguments(), + MultiLevelTemplateArgumentList( + Partial, + CanonicalDeducedArgumentList->asArray(), + /*Final=*/false), + InstArgs)) { unsigned ArgIdx = InstArgs.size(), ParamIdx = ArgIdx; if (ParamIdx >= Partial->getTemplateParameters()->size()) ParamIdx = Partial->getTemplateParameters()->size() - 1; @@ -3301,17 +3302,18 @@ ExtParameterInfoBuilder ExtParamInfos; + MultiLevelTemplateArgumentList MLTAL(FunctionTemplate, + CanonicalExplicitArgumentList->asArray(), + /*Final=*/false); + // Instantiate the types of each of the function parameters given the // explicitly-specified template arguments. If the function has a trailing // return type, substitute it after the arguments to ensure we substitute // in lexical order. if (Proto->hasTrailingReturn()) { - if (SubstParmTypes( - Function->getLocation(), Function->parameters(), - Proto->getExtParameterInfosOrNull(), - MultiLevelTemplateArgumentList( - FunctionTemplate, CanonicalExplicitArgumentList->asArray()), - ParamTypes, /*params=*/nullptr, ExtParamInfos)) + if (SubstParmTypes(Function->getLocation(), Function->parameters(), + Proto->getExtParameterInfosOrNull(), MLTAL, ParamTypes, + /*params=*/nullptr, ExtParamInfos)) return TDK_SubstitutionFailure; } @@ -3334,11 +3336,9 @@ CXXThisScopeRAII ThisScope(*this, ThisContext, ThisTypeQuals, getLangOpts().CPlusPlus11); - ResultType = SubstType( - Proto->getReturnType(), - MultiLevelTemplateArgumentList( - FunctionTemplate, CanonicalExplicitArgumentList->asArray()), - Function->getTypeSpecStartLoc(), Function->getDeclName()); + ResultType = + SubstType(Proto->getReturnType(), MLTAL, + Function->getTypeSpecStartLoc(), Function->getDeclName()); if (ResultType.isNull() || Trap.hasErrorOccurred()) return TDK_SubstitutionFailure; // CUDA: Kernel function must have 'void' return type. @@ -3353,12 +3353,9 @@ // Instantiate the types of each of the function parameters given the // explicitly-specified template arguments if we didn't do so earlier. if (!Proto->hasTrailingReturn() && - SubstParmTypes( - Function->getLocation(), Function->parameters(), - Proto->getExtParameterInfosOrNull(), - MultiLevelTemplateArgumentList( - FunctionTemplate, CanonicalExplicitArgumentList->asArray()), - ParamTypes, /*params*/ nullptr, ExtParamInfos)) + SubstParmTypes(Function->getLocation(), Function->parameters(), + Proto->getExtParameterInfosOrNull(), MLTAL, ParamTypes, + /*params*/ nullptr, ExtParamInfos)) return TDK_SubstitutionFailure; if (FunctionType) { @@ -3370,10 +3367,8 @@ // specification. SmallVector ExceptionStorage; if (getLangOpts().CPlusPlus17 && - SubstExceptionSpec( - Function->getLocation(), EPI.ExceptionSpec, ExceptionStorage, - MultiLevelTemplateArgumentList( - FunctionTemplate, CanonicalExplicitArgumentList->asArray()))) + SubstExceptionSpec(Function->getLocation(), EPI.ExceptionSpec, + ExceptionStorage, MLTAL)) return TDK_SubstitutionFailure; *FunctionType = BuildFunctionType(ResultType, ParamTypes, @@ -3616,7 +3611,8 @@ if (FunctionTemplate->getFriendObjectKind()) Owner = FunctionTemplate->getLexicalDeclContext(); MultiLevelTemplateArgumentList SubstArgs( - FunctionTemplate, CanonicalDeducedArgumentList->asArray()); + FunctionTemplate, CanonicalDeducedArgumentList->asArray(), + /*Final=*/false); Specialization = cast_or_null( SubstDecl(FunctionTemplate->getTemplatedDecl(), Owner, SubstArgs)); if (!Specialization || Specialization->isInvalidDecl()) @@ -4677,7 +4673,8 @@ /*PartialTemplateArgs=*/false, SugaredConverted, CanonicalConverted)) return true; - MultiLevelTemplateArgumentList MLTAL(Concept, CanonicalConverted); + MultiLevelTemplateArgumentList MLTAL(Concept, CanonicalConverted, + /*Final=*/false); if (S.CheckConstraintSatisfaction(Concept, {Concept->getConstraintExpr()}, MLTAL, TypeLoc.getLocalSourceRange(), Satisfaction)) diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -94,13 +94,15 @@ if (VarTemplatePartialSpecializationDecl *Partial = Specialized.dyn_cast()) { Result.addOuterTemplateArguments( - Partial, VarTemplSpec->getTemplateInstantiationArgs().asArray()); + Partial, VarTemplSpec->getTemplateInstantiationArgs().asArray(), + /*Final=*/false); if (Partial->isMemberSpecialization()) return Response::Done(); } else { VarTemplateDecl *Tmpl = Specialized.get(); Result.addOuterTemplateArguments( - Tmpl, VarTemplSpec->getTemplateInstantiationArgs().asArray()); + Tmpl, VarTemplSpec->getTemplateInstantiationArgs().asArray(), + /*Final=*/false); if (Tmpl->isMemberSpecialization()) return Response::Done(); } @@ -133,7 +135,8 @@ Result.addOuterTemplateArguments( const_cast(ClassTemplSpec), - ClassTemplSpec->getTemplateInstantiationArgs().asArray()); + ClassTemplSpec->getTemplateInstantiationArgs().asArray(), + /*Final=*/false); // If this class template specialization was instantiated from a // specialized member that is a class template, we're done. @@ -164,7 +167,8 @@ Function->getTemplateSpecializationArgs()) { // Add the template arguments for this specialization. Result.addOuterTemplateArguments(const_cast(Function), - TemplateArgs->asArray()); + TemplateArgs->asArray(), + /*Final=*/false); // If this function was instantiated from a specialized member that is // a function template, we're done. @@ -210,7 +214,8 @@ ->getInjectedSpecializationType(); const auto *InjectedType = cast(Injected); Result.addOuterTemplateArguments(const_cast(Rec), - InjectedType->template_arguments()); + InjectedType->template_arguments(), + /*Final=*/false); } } @@ -262,7 +267,7 @@ /// arguments on an enclosing class template. MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs( - const NamedDecl *ND, const TemplateArgumentList *Innermost, + const NamedDecl *ND, bool Sugared, const TemplateArgumentList *Innermost, bool RelativeToPrimary, const FunctionDecl *Pattern, bool ForConstraintInstantiation) { assert(ND && "Can't find arguments for a decl if one isn't provided"); @@ -271,7 +276,7 @@ if (Innermost) Result.addOuterTemplateArguments(const_cast(ND), - Innermost->asArray()); + Innermost->asArray(), Sugared); const Decl *CurDecl = ND; @@ -1108,6 +1113,13 @@ return TemplateArgs.getNewDepth(Depth); } + Optional getPackIndex(TemplateArgument Pack) { + int Index = getSema().ArgumentPackSubstitutionIndex; + if (Index == -1) + return None; + return Pack.pack_size() - 1 - Index; + } + bool TryExpandParameterPacks(SourceLocation EllipsisLoc, SourceRange PatternRange, ArrayRef Unexpanded, @@ -1276,16 +1288,26 @@ Optional NumExpansions, bool ExpectParameterPack); + using inherited::TransformTemplateTypeParmType; /// Transforms a template type parameter type by performing /// substitution of the corresponding template type argument. QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB, - TemplateTypeParmTypeLoc TL); + TemplateTypeParmTypeLoc TL, + bool SuppressObjCLifetime); + + QualType BuildSubstTemplateTypeParmType( + TypeLocBuilder &TLB, bool SuppressObjCLifetime, bool Sugared, + Decl *AssociatedDecl, unsigned Index, Optional PackIndex, + TemplateArgument Arg, SourceLocation NameLoc); /// Transforms an already-substituted template type parameter pack /// into either itself (if we aren't substituting into its pack expansion) /// or the appropriate substituted argument. - QualType TransformSubstTemplateTypeParmPackType(TypeLocBuilder &TLB, - SubstTemplateTypeParmPackTypeLoc TL); + using inherited::TransformSubstTemplateTypeParmPackType; + QualType + TransformSubstTemplateTypeParmPackType(TypeLocBuilder &TLB, + SubstTemplateTypeParmPackTypeLoc TL, + bool SuppressObjCLifetime); ExprResult TransformLambdaExpr(LambdaExpr *E) { LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true); @@ -1568,7 +1590,8 @@ return Arg.getAsTemplate(); } - Decl *AssociatedDecl = TemplateArgs.getAssociatedDecl(TTP->getDepth()); + auto [AssociatedDecl, Final] = + TemplateArgs.getAssociatedDecl(TTP->getDepth()); Optional PackIndex; if (TTP->isParameterPack()) { assert(Arg.getKind() == TemplateArgument::Pack && @@ -1579,11 +1602,11 @@ // actually expanding the enclosing pack expansion yet. So, just // keep the entire argument pack. return getSema().Context.getSubstTemplateTemplateParmPack( - Arg, AssociatedDecl, TTP->getIndex()); + Arg, AssociatedDecl, TTP->getIndex(), Final); } + PackIndex = getPackIndex(Arg); Arg = getPackSubstitutedTemplateArgument(getSema(), Arg); - PackIndex = getSema().ArgumentPackSubstitutionIndex; } TemplateName Template = Arg.getAsTemplate().getNameToSubstitute(); @@ -1591,9 +1614,10 @@ assert(!Template.getAsQualifiedTemplateName() && "template decl to substitute is qualified?"); - Template = getSema().Context.getSubstTemplateTemplateParm( + if (Final) + return Template; + return getSema().Context.getSubstTemplateTemplateParm( Template, AssociatedDecl, TTP->getIndex(), PackIndex); - return Template; } } @@ -1602,9 +1626,14 @@ if (getSema().ArgumentPackSubstitutionIndex == -1) return Name; - TemplateArgument Arg = SubstPack->getArgumentPack(); - Arg = getPackSubstitutedTemplateArgument(getSema(), Arg); - return Arg.getAsTemplate().getNameToSubstitute(); + TemplateArgument Pack = SubstPack->getArgumentPack(); + TemplateName Template = + getPackSubstitutedTemplateArgument(getSema(), Pack).getAsTemplate(); + if (SubstPack->getFinal()) + return Template; + return getSema().Context.getSubstTemplateTemplateParm( + Template.getNameToSubstitute(), SubstPack->getAssociatedDecl(), + SubstPack->getIndex(), getPackIndex(Pack)); } return inherited::TransformTemplateName(SS, Name, NameLoc, ObjectType, @@ -1648,7 +1677,7 @@ return Arg.getAsExpr(); } - Decl *AssociatedDecl = TemplateArgs.getAssociatedDecl(NTTP->getDepth()); + auto [AssociatedDecl, _] = TemplateArgs.getAssociatedDecl(NTTP->getDepth()); Optional PackIndex; if (NTTP->isParameterPack()) { assert(Arg.getKind() == TemplateArgument::Pack && @@ -1667,15 +1696,15 @@ QualType ExprType = TargetType.getNonLValueExprType(SemaRef.Context); if (TargetType->isRecordType()) ExprType.addConst(); - + // FIXME: Pass in Final. return new (SemaRef.Context) SubstNonTypeTemplateParmPackExpr( ExprType, TargetType->isReferenceType() ? VK_LValue : VK_PRValue, E->getLocation(), Arg, AssociatedDecl, NTTP->getPosition()); } - PackIndex = getSema().ArgumentPackSubstitutionIndex; + PackIndex = getPackIndex(Arg); Arg = getPackSubstitutedTemplateArgument(getSema(), Arg); } - + // FIXME: Don't put subst node on Final replacement. return transformNonTypeTemplateParmRef(AssociatedDecl, NTTP, E->getLocation(), Arg, PackIndex); } @@ -1767,6 +1796,7 @@ return ExprError(); Expr *resultExpr = result.get(); + // FIXME: Don't put subst node on sugared replacement. return new (SemaRef.Context) SubstNonTypeTemplateParmExpr( resultExpr->getType(), resultExpr->getValueKind(), loc, resultExpr, AssociatedDecl, parm->getIndex(), PackIndex, refParam); @@ -1775,17 +1805,17 @@ ExprResult TemplateInstantiator::TransformSubstNonTypeTemplateParmPackExpr( SubstNonTypeTemplateParmPackExpr *E) { - int PackIndex = getSema().ArgumentPackSubstitutionIndex; - if (PackIndex == -1) { + if (getSema().ArgumentPackSubstitutionIndex == -1) { // We aren't expanding the parameter pack, so just return ourselves. return E; } - TemplateArgument Arg = E->getArgumentPack(); - Arg = getPackSubstitutedTemplateArgument(getSema(), Arg); + TemplateArgument Pack = E->getArgumentPack(); + TemplateArgument Arg = getPackSubstitutedTemplateArgument(getSema(), Pack); + // FIXME: Don't put subst node on sugared replacement. return transformNonTypeTemplateParmRef( E->getAssociatedDecl(), E->getParameterPack(), - E->getParameterPackLocation(), Arg, PackIndex); + E->getParameterPackLocation(), Arg, getPackIndex(Pack)); } ExprResult @@ -1828,7 +1858,7 @@ return true; return transformNonTypeTemplateParmRef(E->getAssociatedDecl(), E->getParameter(), E->getExprLoc(), - CanonicalConverted, E->getPackIndex()); + SugaredConverted, E->getPackIndex()); } ExprResult TemplateInstantiator::RebuildVarDeclRefExpr(VarDecl *PD, @@ -1959,9 +1989,39 @@ return NewParm; } +QualType TemplateInstantiator::BuildSubstTemplateTypeParmType( + TypeLocBuilder &TLB, bool SuppressObjCLifetime, bool Final, + Decl *AssociatedDecl, unsigned Index, Optional PackIndex, + TemplateArgument Arg, SourceLocation NameLoc) { + QualType Replacement = Arg.getAsType(); + + // If the template parameter had ObjC lifetime qualifiers, + // then any such qualifiers on the replacement type are ignored. + if (SuppressObjCLifetime) { + Qualifiers RQs; + RQs = Replacement.getQualifiers(); + RQs.removeObjCLifetime(); + Replacement = + SemaRef.Context.getQualifiedType(Replacement.getUnqualifiedType(), RQs); + } + + if (Final) { + TLB.pushTrivial(SemaRef.Context, Replacement, NameLoc); + return Replacement; + } + // TODO: only do this uniquing once, at the start of instantiation. + QualType Result = getSema().Context.getSubstTemplateTypeParmType( + Replacement, AssociatedDecl, Index, PackIndex); + SubstTemplateTypeParmTypeLoc NewTL = + TLB.push(Result); + NewTL.setNameLoc(NameLoc); + return Result; +} + QualType TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB, - TemplateTypeParmTypeLoc TL) { + TemplateTypeParmTypeLoc TL, + bool SuppressObjCLifetime) { const TemplateTypeParmType *T = TL.getTypePtr(); if (T->getDepth() < TemplateArgs.getNumLevels()) { // Replace the template type parameter with its corresponding @@ -1998,8 +2058,8 @@ return NewT; } - Decl *AssociatedDecl = - const_cast(TemplateArgs.getAssociatedDecl(T->getDepth())); + auto [AssociatedDecl, Final] = + TemplateArgs.getAssociatedDecl(T->getDepth()); Optional PackIndex; if (T->isParameterPack()) { assert(Arg.getKind() == TemplateArgument::Pack && @@ -2010,7 +2070,7 @@ // enclosing pack expansion yet. Just save the template argument // pack for later substitution. QualType Result = getSema().Context.getSubstTemplateTypeParmPackType( - AssociatedDecl, T->getIndex(), Arg); + AssociatedDecl, T->getIndex(), Final, Arg); SubstTemplateTypeParmPackTypeLoc NewTL = TLB.push(Result); NewTL.setNameLoc(TL.getNameLoc()); @@ -2018,22 +2078,16 @@ } // PackIndex starts from last element. - PackIndex = Arg.pack_size() - 1 - getSema().ArgumentPackSubstitutionIndex; + PackIndex = getPackIndex(Arg); Arg = getPackSubstitutedTemplateArgument(getSema(), Arg); } assert(Arg.getKind() == TemplateArgument::Type && "Template argument kind mismatch"); - QualType Replacement = Arg.getAsType(); - - // TODO: only do this uniquing once, at the start of instantiation. - QualType Result = getSema().Context.getSubstTemplateTypeParmType( - Replacement, AssociatedDecl, T->getIndex(), PackIndex); - SubstTemplateTypeParmTypeLoc NewTL - = TLB.push(Result); - NewTL.setNameLoc(TL.getNameLoc()); - return Result; + return BuildSubstTemplateTypeParmType(TLB, SuppressObjCLifetime, Final, + AssociatedDecl, T->getIndex(), + PackIndex, Arg, TL.getNameLoc()); } // The template type parameter comes from an inner template (e.g., @@ -2053,7 +2107,8 @@ } QualType TemplateInstantiator::TransformSubstTemplateTypeParmPackType( - TypeLocBuilder &TLB, SubstTemplateTypeParmPackTypeLoc TL) { + TypeLocBuilder &TLB, SubstTemplateTypeParmPackTypeLoc TL, + bool SuppressObjCLifetime) { const SubstTemplateTypeParmPackType *T = TL.getTypePtr(); Decl *NewReplaced = TransformDecl(TL.getNameLoc(), T->getAssociatedDecl()); @@ -2063,7 +2118,7 @@ QualType Result = TL.getType(); if (NewReplaced != T->getAssociatedDecl()) Result = getSema().Context.getSubstTemplateTypeParmPackType( - NewReplaced, T->getIndex(), T->getArgumentPack()); + NewReplaced, T->getIndex(), T->getFinal(), T->getArgumentPack()); SubstTemplateTypeParmPackTypeLoc NewTL = TLB.push(Result); NewTL.setNameLoc(TL.getNameLoc()); @@ -2072,14 +2127,9 @@ TemplateArgument Pack = T->getArgumentPack(); TemplateArgument Arg = getPackSubstitutedTemplateArgument(getSema(), Pack); - // PackIndex starts from last element. - QualType Result = getSema().Context.getSubstTemplateTypeParmType( - Arg.getAsType(), NewReplaced, T->getIndex(), - Pack.pack_size() - 1 - getSema().ArgumentPackSubstitutionIndex); - SubstTemplateTypeParmTypeLoc NewTL = - TLB.push(Result); - NewTL.setNameLoc(TL.getNameLoc()); - return Result; + return BuildSubstTemplateTypeParmType( + TLB, SuppressObjCLifetime, T->getFinal(), NewReplaced, T->getIndex(), + getPackIndex(Pack), Arg, TL.getNameLoc()); } template diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -4547,8 +4547,8 @@ // // template // A Foo(int a = A::FooImpl()); - MultiLevelTemplateArgumentList TemplateArgs - = getTemplateInstantiationArgs(FD, nullptr, /*RelativeToPrimary=*/true); + MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs( + FD, /*Final=*/false, nullptr, /*RelativeToPrimary=*/true); if (SubstDefaultArgument(CallLoc, Param, TemplateArgs, /*ForCallExpr*/ true)) return true; @@ -4586,8 +4586,8 @@ Sema::ContextRAII savedContext(*this, Decl); LocalInstantiationScope Scope(*this); - MultiLevelTemplateArgumentList TemplateArgs = - getTemplateInstantiationArgs(Decl, nullptr, /*RelativeToPrimary*/true); + MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs( + Decl, /*Final=*/false, nullptr, /*RelativeToPrimary*/ true); // FIXME: We can't use getTemplateInstantiationPattern(false) in general // here, because for a non-defining friend declaration in a class template, @@ -4761,7 +4761,8 @@ return nullptr; ContextRAII SavedContext(*this, FD); - MultiLevelTemplateArgumentList MArgs(FTD, Args->asArray()); + MultiLevelTemplateArgumentList MArgs(FTD, Args->asArray(), + /*Final=*/false); return cast_or_null(SubstDecl(FD, FD->getParent(), MArgs)); } @@ -5027,8 +5028,8 @@ RebuildTypeSourceInfoForDefaultSpecialMembers(); SetDeclDefaulted(Function, PatternDecl->getLocation()); } else { - MultiLevelTemplateArgumentList TemplateArgs = - getTemplateInstantiationArgs(Function, nullptr, false, PatternDecl); + MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs( + Function, /*Final=*/false, nullptr, false, PatternDecl); // Substitute into the qualifier; we can get a substitution failure here // through evil use of alias templates. @@ -5120,13 +5121,13 @@ if (auto *PartialSpec = dyn_cast(FromVar)) { IsMemberSpec = PartialSpec->isMemberSpecialization(); - MultiLevelList.addOuterTemplateArguments(PartialSpec, - TemplateArgList.asArray()); + MultiLevelList.addOuterTemplateArguments( + PartialSpec, TemplateArgList.asArray(), /*Final=*/false); } else { assert(VarTemplate == FromVar->getDescribedVarTemplate()); IsMemberSpec = VarTemplate->isMemberSpecialization(); - MultiLevelList.addOuterTemplateArguments(VarTemplate, - TemplateArgList.asArray()); + MultiLevelList.addOuterTemplateArguments( + VarTemplate, TemplateArgList.asArray(), /*Final=*/false); } if (!IsMemberSpec) FromVar = FromVar->getFirstDecl(); diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -829,8 +829,8 @@ /// Apply Objective-C type arguments to the given type. static QualType applyObjCTypeArgs(Sema &S, SourceLocation loc, QualType type, ArrayRef typeArgs, - SourceRange typeArgsRange, - bool failOnError = false) { + SourceRange typeArgsRange, bool failOnError, + bool rebuilding) { // We can only apply type arguments to an Objective-C class type. const auto *objcObjectType = type->getAs(); if (!objcObjectType || !objcObjectType->getInterface()) { @@ -894,7 +894,9 @@ } } - if (!diagnosed) { + // When rebuilding, qualifiers might have gotten here through a + // sugared substitution. + if (!rebuilding && !diagnosed) { S.Diag(qual.getBeginLoc(), diag::err_objc_type_arg_qualified) << typeArg << typeArg.getQualifiers().getAsString() << FixItHint::CreateRemoval(rangeToRemove); @@ -1056,22 +1058,18 @@ return Result; } -QualType Sema::BuildObjCObjectType(QualType BaseType, - SourceLocation Loc, - SourceLocation TypeArgsLAngleLoc, - ArrayRef TypeArgs, - SourceLocation TypeArgsRAngleLoc, - SourceLocation ProtocolLAngleLoc, - ArrayRef Protocols, - ArrayRef ProtocolLocs, - SourceLocation ProtocolRAngleLoc, - bool FailOnError) { +QualType Sema::BuildObjCObjectType( + QualType BaseType, SourceLocation Loc, SourceLocation TypeArgsLAngleLoc, + ArrayRef TypeArgs, SourceLocation TypeArgsRAngleLoc, + SourceLocation ProtocolLAngleLoc, ArrayRef Protocols, + ArrayRef ProtocolLocs, SourceLocation ProtocolRAngleLoc, + bool FailOnError, bool Rebuilding) { QualType Result = BaseType; if (!TypeArgs.empty()) { - Result = applyObjCTypeArgs(*this, Loc, Result, TypeArgs, - SourceRange(TypeArgsLAngleLoc, - TypeArgsRAngleLoc), - FailOnError); + Result = + applyObjCTypeArgs(*this, Loc, Result, TypeArgs, + SourceRange(TypeArgsLAngleLoc, TypeArgsRAngleLoc), + FailOnError, Rebuilding); if (FailOnError && Result.isNull()) return QualType(); } @@ -1170,10 +1168,11 @@ T, BaseTypeInfo->getTypeLoc().getSourceRange().getBegin(), TypeArgsLAngleLoc, ActualTypeArgInfos, TypeArgsRAngleLoc, ProtocolLAngleLoc, - llvm::makeArrayRef((ObjCProtocolDecl * const *)Protocols.data(), + llvm::makeArrayRef((ObjCProtocolDecl *const *)Protocols.data(), Protocols.size()), ProtocolLocs, ProtocolRAngleLoc, - /*FailOnError=*/false); + /*FailOnError=*/false, + /*Rebuilding=*/false); if (Result == T) return BaseType; diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -636,6 +636,14 @@ QualType Transform##CLASS##Type(TypeLocBuilder &TLB, CLASS##TypeLoc T); #include "clang/AST/TypeLocNodes.def" + QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB, + TemplateTypeParmTypeLoc TL, + bool SuppressObjCLifetime); + QualType + TransformSubstTemplateTypeParmPackType(TypeLocBuilder &TLB, + SubstTemplateTypeParmPackTypeLoc TL, + bool SuppressObjCLifetime); + template QualType TransformFunctionProtoType(TypeLocBuilder &TLB, FunctionProtoTypeLoc TL, @@ -1286,9 +1294,10 @@ /// template name. Subclasses may override this routine to provide different /// behavior. TemplateName RebuildTemplateName(const TemplateArgument &ArgPack, - Decl *AssociatedDecl, unsigned Index) { + Decl *AssociatedDecl, unsigned Index, + bool Final) { return getSema().Context.getSubstTemplateTemplateParmPack( - ArgPack, AssociatedDecl, Index); + ArgPack, AssociatedDecl, Index, Final); } /// Build a new compound statement. @@ -4153,9 +4162,13 @@ NestedNameSpecifierLoc NNS, QualType ObjectType, NamedDecl *FirstQualifierInScope) { SmallVector Qualifiers; - for (NestedNameSpecifierLoc Qualifier = NNS; Qualifier; - Qualifier = Qualifier.getPrefix()) - Qualifiers.push_back(Qualifier); + + auto insertNNS = [&Qualifiers](NestedNameSpecifierLoc NNS) { + for (NestedNameSpecifierLoc Qualifier = NNS; Qualifier; + Qualifier = Qualifier.getPrefix()) + Qualifiers.push_back(Qualifier); + }; + insertNNS(NNS); CXXScopeSpec SS; while (!Qualifiers.empty()) { @@ -4212,14 +4225,17 @@ if (!TL) return NestedNameSpecifierLoc(); - if (TL.getType()->isDependentType() || TL.getType()->isRecordType() || - (SemaRef.getLangOpts().CPlusPlus11 && - TL.getType()->isEnumeralType())) { - assert(!TL.getType().hasLocalQualifiers() && - "Can't get cv-qualifiers here"); - if (TL.getType()->isEnumeralType()) + QualType T = TL.getType(); + if (T->isDependentType() || T->isRecordType() || + (SemaRef.getLangOpts().CPlusPlus11 && T->isEnumeralType())) { + if (T->isEnumeralType()) SemaRef.Diag(TL.getBeginLoc(), diag::warn_cxx98_compat_enum_nested_name_spec); + + if (const auto ETL = TL.getAs()) { + SS.Adopt(ETL.getQualifierLoc()); + TL = ETL.getNamedTypeLoc(); + } SS.Extend(SemaRef.Context, /*FIXME:*/ SourceLocation(), TL, Q.getLocalEndLoc()); break; @@ -4229,7 +4245,7 @@ TypedefTypeLoc TTL = TL.getAsAdjusted(); if (!TTL || !TTL.getTypedefNameDecl()->isInvalidDecl()) { SemaRef.Diag(TL.getBeginLoc(), diag::err_nested_name_spec_non_tag) - << TL.getType() << SS.getRange(); + << T << SS.getRange(); } return NestedNameSpecifierLoc(); } @@ -4392,9 +4408,9 @@ if (SubstTemplateTemplateParmPackStorage *SubstPack = Name.getAsSubstTemplateTemplateParmPack()) { - return getDerived().RebuildTemplateName(SubstPack->getArgumentPack(), - SubstPack->getAssociatedDecl(), - SubstPack->getIndex()); + return getDerived().RebuildTemplateName( + SubstPack->getArgumentPack(), SubstPack->getAssociatedDecl(), + SubstPack->getIndex(), SubstPack->getFinal()); } // These should be getting filtered out before they reach the AST. @@ -4808,7 +4824,20 @@ QualType TreeTransform::TransformQualifiedType(TypeLocBuilder &TLB, QualifiedTypeLoc T) { - QualType Result = getDerived().TransformType(TLB, T.getUnqualifiedLoc()); + QualType Result; + TypeLoc UnqualTL = T.getUnqualifiedLoc(); + auto SuppressObjCLifetime = + T.getType().getLocalQualifiers().hasObjCLifetime(); + if (auto TTP = UnqualTL.getAs()) { + Result = getDerived().TransformTemplateTypeParmType(TLB, TTP, + SuppressObjCLifetime); + } else if (auto STTP = UnqualTL.getAs()) { + Result = getDerived().TransformSubstTemplateTypeParmPackType( + TLB, STTP, SuppressObjCLifetime); + } else { + Result = getDerived().TransformType(TLB, UnqualTL); + } + if (Result.isNull()) return QualType(); @@ -4871,17 +4900,7 @@ // A lifetime qualifier applied to a substituted template parameter // overrides the lifetime qualifier from the template argument. const AutoType *AutoTy; - if (const SubstTemplateTypeParmType *SubstTypeParam - = dyn_cast(T)) { - QualType Replacement = SubstTypeParam->getReplacementType(); - Qualifiers Qs = Replacement.getQualifiers(); - Qs.removeObjCLifetime(); - Replacement = SemaRef.Context.getQualifiedType( - Replacement.getUnqualifiedType(), Qs); - T = SemaRef.Context.getSubstTemplateTypeParmType( - Replacement, SubstTypeParam->getAssociatedDecl(), - SubstTypeParam->getIndex(), SubstTypeParam->getPackIndex()); - } else if ((AutoTy = dyn_cast(T)) && AutoTy->isDeduced()) { + if ((AutoTy = dyn_cast(T)) && AutoTy->isDeduced()) { // 'auto' types behave the same way as template parameters. QualType Deduced = AutoTy->getDeducedType(); Qualifiers Qs = Deduced.getQualifiers(); @@ -6423,6 +6442,14 @@ QualType TreeTransform::TransformTemplateTypeParmType( TypeLocBuilder &TLB, TemplateTypeParmTypeLoc TL) { + return getDerived().TransformTemplateTypeParmType( + TLB, TL, + /*SuppressObjCLifetime=*/false); +} + +template +QualType TreeTransform::TransformTemplateTypeParmType( + TypeLocBuilder &TLB, TemplateTypeParmTypeLoc TL, bool) { return TransformTypeSpecType(TLB, TL); } @@ -6458,6 +6485,13 @@ QualType TreeTransform::TransformSubstTemplateTypeParmPackType( TypeLocBuilder &TLB, SubstTemplateTypeParmPackTypeLoc TL) { + return getDerived().TransformSubstTemplateTypeParmPackType( + TLB, TL, /*SuppressObjCLifetime=*/false); +} + +template +QualType TreeTransform::TransformSubstTemplateTypeParmPackType( + TypeLocBuilder &TLB, SubstTemplateTypeParmPackTypeLoc TL, bool) { return TransformTypeSpecType(TLB, TL); } @@ -7244,7 +7278,8 @@ TypeLocBuilder TypeArgBuilder; TypeArgBuilder.reserve(TypeArgLoc.getFullDataSize()); - QualType NewTypeArg = getDerived().TransformType(TypeArgBuilder, TypeArgLoc); + QualType NewTypeArg = + getDerived().TransformType(TypeArgBuilder, TypeArgLoc); if (NewTypeArg.isNull()) return QualType(); @@ -14533,11 +14568,11 @@ ArrayRef Protocols, ArrayRef ProtocolLocs, SourceLocation ProtocolRAngleLoc) { - return SemaRef.BuildObjCObjectType(BaseType, Loc, TypeArgsLAngleLoc, - TypeArgs, TypeArgsRAngleLoc, - ProtocolLAngleLoc, Protocols, ProtocolLocs, - ProtocolRAngleLoc, - /*FailOnError=*/true); + return SemaRef.BuildObjCObjectType(BaseType, Loc, TypeArgsLAngleLoc, TypeArgs, + TypeArgsRAngleLoc, ProtocolLAngleLoc, + Protocols, ProtocolLocs, ProtocolRAngleLoc, + /*FailOnError=*/true, + /*Rebuilding=*/true); } template diff --git a/clang/lib/Sema/TypeLocBuilder.h b/clang/lib/Sema/TypeLocBuilder.h --- a/clang/lib/Sema/TypeLocBuilder.h +++ b/clang/lib/Sema/TypeLocBuilder.h @@ -64,6 +64,10 @@ /// must be empty for this to work. void pushFullCopy(TypeLoc L); + /// Pushes 'T' with all locations pointing to 'Loc'. + /// The builder must be empty for this to work. + void pushTrivial(ASTContext &Context, QualType T, SourceLocation Loc); + /// Pushes space for a typespec TypeLoc. Invalidates any TypeLocs /// previously retrieved from this builder. TypeSpecTypeLoc pushTypeSpec(QualType T) { diff --git a/clang/lib/Sema/TypeLocBuilder.cpp b/clang/lib/Sema/TypeLocBuilder.cpp --- a/clang/lib/Sema/TypeLocBuilder.cpp +++ b/clang/lib/Sema/TypeLocBuilder.cpp @@ -41,6 +41,29 @@ } } +void TypeLocBuilder::pushTrivial(ASTContext &Context, QualType T, + SourceLocation Loc) { + auto L = TypeLoc(T, nullptr); + reserve(L.getFullDataSize()); + + SmallVector TypeLocs; + for (auto CurTL = L; CurTL; CurTL = CurTL.getNextTypeLoc()) + TypeLocs.push_back(CurTL); + + for (const auto &CurTL : llvm::reverse(TypeLocs)) { + switch (CurTL.getTypeLocClass()) { +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + case TypeLoc::CLASS: { \ + auto NewTL = push(CurTL.getType()); \ + NewTL.initializeLocal(Context, Loc); \ + break; \ + } +#include "clang/AST/TypeLocNodes.def" + } + } +} + void TypeLocBuilder::grow(size_t NewCapacity) { assert(NewCapacity > Capacity); diff --git a/clang/test/SemaTemplate/nested-name-spec-template.cpp b/clang/test/SemaTemplate/nested-name-spec-template.cpp --- a/clang/test/SemaTemplate/nested-name-spec-template.cpp +++ b/clang/test/SemaTemplate/nested-name-spec-template.cpp @@ -147,3 +147,10 @@ template void f(); // expected-note{{in instantiation of}} } + +namespace sugared_template_instantiation { + // Test that we ignore local qualifiers. + template struct A {}; + struct B { typedef int type1; }; + typedef A type2; +} // namespace sugated_template_instantiation diff --git a/libcxx/DELETE.ME b/libcxx/DELETE.ME new file mode 100644 --- /dev/null +++ b/libcxx/DELETE.ME @@ -0,0 +1 @@ +D134604