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 @@ -2207,7 +2207,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<"final", Bool> { + let Read = [{ parm->getFinal() }]; + } def : Creator<[{ - return ctx.getSubstTemplateTemplateParmPack(argumentPack, associatedDecl, index); + return ctx.getSubstTemplateTemplateParmPack(argumentPack, associatedDecl, index, final); }]>; } 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; } + // When true the substitution will be 'Final' (subst node won't be placed). + 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 @@ -5158,10 +5158,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: @@ -5170,7 +5170,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; @@ -5179,6 +5179,9 @@ /// This should match the result of `getReplacedParameter()->getIndex()`. unsigned getIndex() const { return SubstTemplateTypeParmPackTypeBits.Index; } + // When true the substitution will be 'Final' (subst node won't be placed). + bool getFinal() const; + unsigned getNumArgs() const { return SubstTemplateTypeParmPackTypeBits.NumArgs; } @@ -5190,7 +5193,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 @@ -9074,10 +9074,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 @@ -10171,16 +10173,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 AssociatedDeclAndFinal; 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,11 @@ /// 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 { + std::pair getAssociatedDecl(unsigned Depth) const { assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels()); - return TemplateArgumentLists[getNumLevels() - Depth - 1].AssociatedDecl; + auto AD = TemplateArgumentLists[getNumLevels() - Depth - 1] + .AssociatedDeclAndFinal; + return {AD.getPointer(), AD.getInt()}; } /// Determine whether there is a non-NULL template argument at the @@ -202,21 +204,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 @@ -3045,6 +3045,18 @@ return getObjCLayout(D->getClassInterface(), D); } +static auto getCanonicalTemplateArguments(const ASTContext &C, + ArrayRef Args, + bool &AnyNonCanonArgs) { + SmallVector CanonArgs(Args); + for (auto &Arg : CanonArgs) { + TemplateArgument OrigArg = Arg; + Arg = C.getCanonicalTemplateArgument(Arg); + AnyNonCanonArgs |= !Arg.structurallyEquals(OrigArg); + } + return CanonArgs; +} + //===----------------------------------------------------------------------===// // Type creation/memoization methods //===----------------------------------------------------------------------===// @@ -4852,31 +4864,38 @@ } /// 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); + { + TemplateArgument CanonArgPack = getCanonicalTemplateArgument(ArgPack); + if (!AssociatedDecl->isCanonicalDecl() || + !CanonArgPack.structurallyEquals(ArgPack)) { + 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, ArgPack); + auto *SubstParm = new (*this, TypeAlignment) SubstTemplateTypeParmPackType( + Canon, AssociatedDecl, Index, Final, ArgPack); Types.push_back(SubstParm); SubstTemplateTypeParmPackTypes.InsertNode(SubstParm, InsertPos); return QualType(SubstParm, 0); @@ -5001,23 +5020,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() && @@ -5029,8 +5031,9 @@ // Build the canonical template specialization type. TemplateName CanonTemplate = getCanonicalTemplateName(Template); - SmallVector CanonArgs; - ::getCanonicalTemplateArguments(*this, Args, CanonArgs); + bool AnyNonCanonArgs = false; + auto CanonArgs = + ::getCanonicalTemplateArguments(*this, Args, AnyNonCanonArgs); // Determine whether this canonical template specialization type already // exists. @@ -5184,9 +5187,9 @@ ElaboratedTypeKeyword CanonKeyword = Keyword; if (Keyword == ETK_None) CanonKeyword = ETK_Typename; - SmallVector CanonArgs; - bool AnyNonCanonArgs = - ::getCanonicalTemplateArguments(*this, Args, CanonArgs); + bool AnyNonCanonArgs = false; + auto CanonArgs = + ::getCanonicalTemplateArguments(*this, Args, AnyNonCanonArgs); QualType Canon; if (AnyNonCanonArgs || CanonNNS != NNS || CanonKeyword != Keyword) { @@ -6285,7 +6288,7 @@ getCanonicalTemplateArgument(subst->getArgumentPack()); return getSubstTemplateTemplateParmPack( canonArgPack, subst->getAssociatedDecl()->getCanonicalDecl(), - subst->getIndex()); + subst->getFinal(), subst->getIndex()); } } @@ -6793,17 +6796,13 @@ return TemplateArgument(getCanonicalType(Arg.getAsType())); case TemplateArgument::Pack: { - if (Arg.pack_size() == 0) + bool AnyNonCanonArgs = false; + auto CanonArgs = ::getCanonicalTemplateArguments( + *this, Arg.pack_elements(), AnyNonCanonArgs); + if (!AnyNonCanonArgs) return Arg; - - auto *CanonArgs = new (*this) TemplateArgument[Arg.pack_size()]; - unsigned Idx = 0; - for (TemplateArgument::pack_iterator A = Arg.pack_begin(), - AEnd = Arg.pack_end(); - A != AEnd; (void)++A, ++Idx) - CanonArgs[Idx] = getCanonicalTemplateArgument(*A); - - return TemplateArgument(llvm::makeArrayRef(CanonArgs, Arg.pack_size())); + return TemplateArgument::CreatePackCopy(const_cast(*this), + CanonArgs); } } @@ -9311,11 +9310,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 @@ -9323,7 +9322,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 @@ -1542,7 +1542,7 @@ return ToArgumentPack.takeError(); return Importer.getToContext().getSubstTemplateTypeParmPackType( - *ReplacedOrErr, T->getIndex(), *ToArgumentPack); + *ReplacedOrErr, T->getIndex(), T->getFinal(), *ToArgumentPack); } ExpectedType ASTNodeImporter::VisitTemplateSpecializationType( @@ -9439,7 +9439,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 @@ -454,7 +454,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; @@ -507,10 +508,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; @@ -587,7 +589,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(); @@ -600,8 +602,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; @@ -1072,11 +1076,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) { @@ -3849,13 +3852,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()); @@ -3981,9 +3981,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); } @@ -4866,7 +4866,8 @@ bool AreArgsDependent = TemplateSpecializationType::anyDependentTemplateArguments( *TemplateArgs, CanonicalConverted); - MultiLevelTemplateArgumentList MLTAL(NamedConcept, CanonicalConverted); + MultiLevelTemplateArgumentList MLTAL(NamedConcept, CanonicalConverted, + /*Final=*/false); LocalInstantiationScope Scope(*this); EnterExpressionEvaluationContext EECtx{ @@ -5278,11 +5279,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); @@ -5334,11 +5333,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); @@ -5387,11 +5384,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); @@ -5572,10 +5567,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, @@ -5737,9 +5730,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; } @@ -6138,7 +6132,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); } } @@ -236,7 +241,8 @@ MultiLevelTemplateArgumentList &Result) { Result.addOuterTemplateArguments( const_cast(CSD), - CSD->getTemplateArguments()); + CSD->getTemplateArguments(), + /*Final=*/false); return Response::UseNextDecl(CSD); } @@ -271,7 +277,7 @@ /// arguments on an enclosing class template. MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs( - const NamedDecl *ND, const TemplateArgumentList *Innermost, + const NamedDecl *ND, bool Final, const TemplateArgumentList *Innermost, bool RelativeToPrimary, const FunctionDecl *Pattern, bool ForConstraintInstantiation) { assert(ND && "Can't find arguments for a decl if one isn't provided"); @@ -280,7 +286,7 @@ if (Innermost) Result.addOuterTemplateArguments(const_cast(ND), - Innermost->asArray()); + Innermost->asArray(), Final); const Decl *CurDecl = ND; @@ -1120,6 +1126,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, @@ -1288,16 +1301,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 Final, + 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); @@ -1580,7 +1603,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 && @@ -1591,11 +1615,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(); @@ -1603,9 +1627,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; } } @@ -1614,9 +1639,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, @@ -1660,7 +1690,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 && @@ -1679,15 +1709,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); } @@ -1779,6 +1809,7 @@ return ExprError(); Expr *resultExpr = result.get(); + // FIXME: Don't put subst node on final replacement. return new (SemaRef.Context) SubstNonTypeTemplateParmExpr( resultExpr->getType(), resultExpr->getValueKind(), loc, resultExpr, AssociatedDecl, parm->getIndex(), PackIndex, refParam); @@ -1787,17 +1818,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 final replacement. return transformNonTypeTemplateParmRef( E->getAssociatedDecl(), E->getParameterPack(), - E->getParameterPackLocation(), Arg, PackIndex); + E->getParameterPackLocation(), Arg, getPackIndex(Pack)); } ExprResult @@ -1840,7 +1871,7 @@ return true; return transformNonTypeTemplateParmRef(E->getAssociatedDecl(), E->getParameter(), E->getExprLoc(), - CanonicalConverted, E->getPackIndex()); + SugaredConverted, E->getPackIndex()); } ExprResult TemplateInstantiator::RebuildVarDeclRefExpr(VarDecl *PD, @@ -1971,9 +2002,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 @@ -2010,8 +2071,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 && @@ -2022,7 +2083,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()); @@ -2030,22 +2091,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., @@ -2065,7 +2120,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()); @@ -2075,7 +2131,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()); @@ -2084,14 +2140,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 @@ -4552,8 +4552,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; @@ -4591,8 +4591,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, @@ -4766,7 +4766,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)); } @@ -5032,8 +5033,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. @@ -5125,13 +5126,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 + // final 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, @@ -1285,9 +1293,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. @@ -4152,9 +4161,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()) { @@ -4211,14 +4224,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; @@ -4228,7 +4244,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(); } @@ -4391,9 +4407,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. @@ -4807,7 +4823,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(); @@ -4870,17 +4899,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(); @@ -6422,6 +6441,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); } @@ -6457,6 +6484,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); } @@ -7240,7 +7274,8 @@ TypeLocBuilder TypeArgBuilder; TypeArgBuilder.reserve(TypeArgLoc.getFullDataSize()); - QualType NewTypeArg = getDerived().TransformType(TypeArgBuilder, TypeArgLoc); + QualType NewTypeArg = + getDerived().TransformType(TypeArgBuilder, TypeArgLoc); if (NewTypeArg.isNull()) return QualType(); @@ -14530,11 +14565,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