llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Matheus Izvekov (mizvekov) <details> <summary>Changes</summary> This makes sure NestedNameSpecifierLocs don't apply to the replacement TemplateName of SubstTemplate* nodes. Also removes improper name qualification over these Subst Nodes, causing some canonical TemplateNames to not be fully qualified when printed. Since this is a regression introduced in #<!-- -->147835, which was never released, there are no release notes. Fixes #<!-- -->155281 --- Patch is 37.88 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/155342.diff 12 Files Affected: - (modified) clang/include/clang/AST/TemplateName.h (+7-7) - (modified) clang/include/clang/AST/TypeLoc.h (+8-13) - (modified) clang/lib/AST/ASTContext.cpp (+6) - (modified) clang/lib/AST/TemplateName.cpp (+17-21) - (modified) clang/lib/AST/Type.cpp (+4-6) - (modified) clang/lib/AST/TypeLoc.cpp (+5-7) - (modified) clang/lib/Sema/SemaLookup.cpp (+1-1) - (modified) clang/lib/Sema/SemaTemplateInstantiate.cpp (+5-10) - (modified) clang/lib/Sema/TreeTransform.h (+35-36) - (modified) clang/test/SemaCXX/cxx20-ctad-type-alias.cpp (+19-19) - (modified) clang/test/SemaTemplate/deduction-guide.cpp (+21-21) - (modified) clang/test/SemaTemplate/nested-name-spec-template.cpp (+24) ``````````diff diff --git a/clang/include/clang/AST/TemplateName.h b/clang/include/clang/AST/TemplateName.h index 37ea401a0045a..abb0669bff378 100644 --- a/clang/include/clang/AST/TemplateName.h +++ b/clang/include/clang/AST/TemplateName.h @@ -335,17 +335,17 @@ class TemplateName { /// structure, if any. QualifiedTemplateName *getAsQualifiedTemplateName() const; - /// Retrieve the underlying qualified template name, - /// looking through underlying nodes. - QualifiedTemplateName *getAsAdjustedQualifiedTemplateName() const; - /// Retrieve the underlying dependent template name /// structure, if any. DependentTemplateName *getAsDependentTemplateName() const; - // Retrieve the qualifier stored in either a underlying DependentTemplateName - // or QualifiedTemplateName. - NestedNameSpecifier getQualifier() const; + // Retrieve the qualifier and template keyword stored in either a underlying + // DependentTemplateName or QualifiedTemplateName. + std::tuple<NestedNameSpecifier, bool> getQualifierAndTemplateKeyword() const; + + NestedNameSpecifier getQualifier() const { + return std::get<0>(getQualifierAndTemplateKeyword()); + } /// Retrieve the using shadow declaration through which the underlying /// template declaration is introduced, if any. diff --git a/clang/include/clang/AST/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h index 00835f1490eda..9df7844e4b90b 100644 --- a/clang/include/clang/AST/TypeLoc.h +++ b/clang/include/clang/AST/TypeLoc.h @@ -1872,11 +1872,10 @@ class TemplateSpecializationTypeLoc : if (!getLocalData()->QualifierData) return NestedNameSpecifierLoc(); - auto *QTN = - getTypePtr()->getTemplateName().getAsAdjustedQualifiedTemplateName(); - assert(QTN && "missing qualification"); - return NestedNameSpecifierLoc(QTN->getQualifier(), - getLocalData()->QualifierData); + NestedNameSpecifier Qualifier = + getTypePtr()->getTemplateName().getQualifier(); + assert(Qualifier && "missing qualification"); + return NestedNameSpecifierLoc(Qualifier, getLocalData()->QualifierData); } SourceLocation getTemplateKeywordLoc() const { @@ -2503,10 +2502,9 @@ class DeducedTemplateSpecializationTypeLoc void *Data = getLocalData()->QualifierData; if (!Data) return NestedNameSpecifierLoc(); - NestedNameSpecifier Qualifier = getTypePtr() - ->getTemplateName() - .getAsAdjustedQualifiedTemplateName() - ->getQualifier(); + NestedNameSpecifier Qualifier = + getTypePtr()->getTemplateName().getQualifier(); + assert(Qualifier && "missing qualification"); return NestedNameSpecifierLoc(Qualifier, Data); } @@ -2521,10 +2519,7 @@ class DeducedTemplateSpecializationTypeLoc } assert(QualifierLoc.getNestedNameSpecifier() == - getTypePtr() - ->getTemplateName() - .getAsAdjustedQualifiedTemplateName() - ->getQualifier() && + getTypePtr()->getTemplateName().getQualifier() && "Inconsistent nested-name-specifier pointer"); getLocalData()->QualifierData = QualifierLoc.getOpaqueData(); } diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 036df53063568..621973bd19aad 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -10447,6 +10447,12 @@ TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier Qualifier, assert(Template.getKind() == TemplateName::Template || Template.getKind() == TemplateName::UsingTemplate); + if (Template.getAsTemplateDecl()->getKind() == Decl::TemplateTemplateParm) { + assert(!Qualifier && "unexpected qualified template template parameter"); + assert(TemplateKeyword == false); + return Template; + } + // FIXME: Canonicalization? llvm::FoldingSetNodeID ID; QualifiedTemplateName::Profile(ID, Qualifier, TemplateKeyword, Template); diff --git a/clang/lib/AST/TemplateName.cpp b/clang/lib/AST/TemplateName.cpp index c171516c38c10..f2cb15dbc43dd 100644 --- a/clang/lib/AST/TemplateName.cpp +++ b/clang/lib/AST/TemplateName.cpp @@ -289,28 +289,23 @@ QualifiedTemplateName *TemplateName::getAsQualifiedTemplateName() const { return dyn_cast_if_present<QualifiedTemplateName *>(Storage); } -QualifiedTemplateName * -TemplateName::getAsAdjustedQualifiedTemplateName() const { - for (std::optional<TemplateName> Cur = *this; Cur; - Cur = Cur->desugar(/*IgnoreDeduced=*/true)) - if (QualifiedTemplateName *N = Cur->getAsQualifiedTemplateName()) - return N; - return nullptr; -} - DependentTemplateName *TemplateName::getAsDependentTemplateName() const { return Storage.dyn_cast<DependentTemplateName *>(); } -NestedNameSpecifier TemplateName::getQualifier() const { +std::tuple<NestedNameSpecifier, bool> +TemplateName::getQualifierAndTemplateKeyword() const { for (std::optional<TemplateName> Cur = *this; Cur; Cur = Cur->desugar(/*IgnoreDeduced=*/true)) { if (DependentTemplateName *N = Cur->getAsDependentTemplateName()) - return N->getQualifier(); + return {N->getQualifier(), N->hasTemplateKeyword()}; if (QualifiedTemplateName *N = Cur->getAsQualifiedTemplateName()) - return N->getQualifier(); + return {N->getQualifier(), N->hasTemplateKeyword()}; + if (Cur->getAsSubstTemplateTemplateParm() || + Cur->getAsSubstTemplateTemplateParmPack()) + break; } - return std::nullopt; + return {std::nullopt, false}; } UsingShadowDecl *TemplateName::getAsUsingShadowDecl() const { @@ -448,8 +443,14 @@ void TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy, Template = cast<TemplateDecl>(Template->getCanonicalDecl()); if (handleAnonymousTTP(Template, OS)) return; - if (Qual == Qualified::None || Policy.SuppressScope) { - OS << *Template; + if (Qual == Qualified::None || isa<TemplateTemplateParmDecl>(Template) || + Policy.SuppressScope) { + if (IdentifierInfo *II = Template->getIdentifier(); + Policy.CleanUglifiedParameters && II && + isa<TemplateTemplateParmDecl>(Template)) + OS << II->deuglifiedName(); + else + OS << *Template; } else { PrintingPolicy NestedNamePolicy = Policy; NestedNamePolicy.SuppressUnwrittenScope = true; @@ -474,12 +475,7 @@ void TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy, if (handleAnonymousTTP(UTD, OS)) return; - if (IdentifierInfo *II = UTD->getIdentifier(); - Policy.CleanUglifiedParameters && II && - isa<TemplateTemplateParmDecl>(UTD)) - OS << II->deuglifiedName(); - else - OS << *UTD; + OS << *UTD; } else if (DependentTemplateName *DTN = getAsDependentTemplateName()) { DTN->print(OS, Policy); } else if (SubstTemplateTemplateParmStorage *subst = diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 9df01b8b361c1..63d808f631591 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -1961,12 +1961,10 @@ NestedNameSpecifier Type::getPrefix() const { switch (getTypeClass()) { case Type::DependentName: return cast<DependentNameType>(this)->getQualifier(); - case Type::TemplateSpecialization: { - QualifiedTemplateName *S = cast<TemplateSpecializationType>(this) - ->getTemplateName() - .getAsAdjustedQualifiedTemplateName(); - return S ? S->getQualifier() : std::nullopt; - } + case Type::TemplateSpecialization: + return cast<TemplateSpecializationType>(this) + ->getTemplateName() + .getQualifier(); case Type::DependentTemplateSpecialization: return cast<DependentTemplateSpecializationType>(this) ->getDependentTemplateName() diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp index fbe8772924465..3e9597fc4d471 100644 --- a/clang/lib/AST/TypeLoc.cpp +++ b/clang/lib/AST/TypeLoc.cpp @@ -750,8 +750,9 @@ void TemplateSpecializationTypeLoc::set(SourceLocation ElaboratedKeywordLoc, void TemplateSpecializationTypeLoc::initializeLocal(ASTContext &Context, SourceLocation Loc) { - QualifiedTemplateName *Name = - getTypePtr()->getTemplateName().getAsAdjustedQualifiedTemplateName(); + + auto [Qualifier, HasTemplateKeyword] = + getTypePtr()->getTemplateName().getQualifierAndTemplateKeyword(); SourceLocation ElaboratedKeywordLoc = getTypePtr()->getKeyword() != ElaboratedTypeKeyword::None @@ -759,8 +760,7 @@ void TemplateSpecializationTypeLoc::initializeLocal(ASTContext &Context, : SourceLocation(); NestedNameSpecifierLoc QualifierLoc; - if (NestedNameSpecifier Qualifier = - Name ? Name->getQualifier() : std::nullopt) { + if (Qualifier) { NestedNameSpecifierLocBuilder Builder; Builder.MakeTrivial(Context, Qualifier, Loc); QualifierLoc = Builder.getWithLocInContext(Context); @@ -768,9 +768,7 @@ void TemplateSpecializationTypeLoc::initializeLocal(ASTContext &Context, TemplateArgumentListInfo TAL(Loc, Loc); set(ElaboratedKeywordLoc, QualifierLoc, - /*TemplateKeywordLoc=*/Name && Name->hasTemplateKeyword() - ? Loc - : SourceLocation(), + /*TemplateKeywordLoc=*/HasTemplateKeyword ? Loc : SourceLocation(), /*NameLoc=*/Loc, /*LAngleLoc=*/Loc, /*RAngleLoc=*/Loc); initializeArgLocs(Context, getTypePtr()->template_arguments(), getArgInfos(), Loc); diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 68f7af139af46..42519a52b57ac 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -4578,7 +4578,7 @@ static void getNestedNameSpecifierIdentifiers( TemplateName Name = cast<TemplateSpecializationType>(T)->getTemplateName(); if (const QualifiedTemplateName *QTN = - Name.getAsAdjustedQualifiedTemplateName()) { + Name.getAsQualifiedTemplateName()) { getNestedNameSpecifierIdentifiers(QTN->getQualifier(), Identifiers); Name = QTN->getUnderlyingTemplate(); } diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index fe1c5faba9e40..a72c95d6d77cf 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -2124,9 +2124,11 @@ TemplateName TemplateInstantiator::TransformTemplateName( NestedNameSpecifierLoc &QualifierLoc, SourceLocation TemplateKWLoc, TemplateName Name, SourceLocation NameLoc, QualType ObjectType, NamedDecl *FirstQualifierInScope, bool AllowInjectedClassName) { - if (TemplateTemplateParmDecl *TTP - = dyn_cast_or_null<TemplateTemplateParmDecl>(Name.getAsTemplateDecl())) { - if (TTP->getDepth() < TemplateArgs.getNumLevels()) { + if (Name.getKind() == TemplateName::Template) { + assert(!QualifierLoc && "Unexpected qualifier"); + if (auto *TTP = + dyn_cast<TemplateTemplateParmDecl>(Name.getAsTemplateDecl()); + TTP && TTP->getDepth() < TemplateArgs.getNumLevels()) { // If the corresponding template argument is NULL or non-existent, it's // because we are performing instantiation from explicitly-specified // template arguments in a function template, but there were some @@ -2169,13 +2171,6 @@ TemplateName TemplateInstantiator::TransformTemplateName( TemplateName Template = Arg.getAsTemplate(); assert(!Template.isNull() && "Null template template argument"); - - if (NestedNameSpecifier Qualifier = Template.getQualifier()) { - NestedNameSpecifierLocBuilder Builder; - Builder.MakeTrivial(SemaRef.Context, Qualifier, NameLoc); - QualifierLoc = Builder.getWithLocInContext(SemaRef.Context); - } - return getSema().Context.getSubstTemplateTemplateParm( Template, AssociatedDecl, TTP->getIndex(), PackIndex, Final); } diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index b9404c60f3bd1..79aca11839802 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -744,11 +744,6 @@ class TreeTransform { StmtResult TransformSEHHandler(Stmt *Handler); - QualType TransformTemplateSpecializationType(TypeLocBuilder &TLB, - TemplateSpecializationTypeLoc TL, - TemplateName Template, - CXXScopeSpec &SS); - QualType TransformDependentTemplateSpecializationType( TypeLocBuilder &TLB, DependentTemplateSpecializationTypeLoc TL, QualType ObjectType, NamedDecl *UnqualLookup, @@ -1315,9 +1310,8 @@ class TreeTransform { /// /// By default, builds the new template name directly. Subclasses may override /// this routine to provide different behavior. - TemplateName RebuildTemplateName(CXXScopeSpec &SS, - bool TemplateKW, - TemplateDecl *Template); + TemplateName RebuildTemplateName(CXXScopeSpec &SS, bool TemplateKW, + TemplateName Name); /// Build a new template name given a nested name specifier and the /// name that is referred to as a template. @@ -4822,9 +4816,7 @@ TemplateName TreeTransform<Derived>::TransformTemplateName( TemplateName Name, SourceLocation NameLoc, QualType ObjectType, NamedDecl *FirstQualifierInScope, bool AllowInjectedClassName) { if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) { - // FIXME: Preserve UsingTemplateName. - TemplateDecl *Template = QTN->getUnderlyingTemplate().getAsTemplateDecl(); - assert(Template && "qualified template name must refer to a template"); + TemplateName UnderlyingName = QTN->getUnderlyingTemplate(); if (QualifierLoc) { QualifierLoc = getDerived().TransformNestedNameSpecifierLoc( @@ -4833,20 +4825,22 @@ TemplateName TreeTransform<Derived>::TransformTemplateName( return TemplateName(); } - TemplateDecl *TransTemplate - = cast_or_null<TemplateDecl>(getDerived().TransformDecl(NameLoc, - Template)); - if (!TransTemplate) + NestedNameSpecifierLoc UnderlyingQualifier; + TemplateName NewUnderlyingName = getDerived().TransformTemplateName( + UnderlyingQualifier, TemplateKWLoc, UnderlyingName, NameLoc, ObjectType, + FirstQualifierInScope, AllowInjectedClassName); + if (NewUnderlyingName.isNull()) return TemplateName(); + assert(!UnderlyingQualifier && "unexpected qualifier"); if (!getDerived().AlwaysRebuild() && QualifierLoc.getNestedNameSpecifier() == QTN->getQualifier() && - TransTemplate == Template) + NewUnderlyingName == UnderlyingName) return Name; CXXScopeSpec SS; SS.Adopt(QualifierLoc); return getDerived().RebuildTemplateName(SS, QTN->hasTemplateKeyword(), - TransTemplate); + NewUnderlyingName); } if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) { @@ -4874,9 +4868,19 @@ TemplateName TreeTransform<Derived>::TransformTemplateName( if (SubstTemplateTemplateParmStorage *S = Name.getAsSubstTemplateTemplateParm()) { + assert(!QualifierLoc && "Unexpected qualified SubstTemplateTemplateParm"); + + NestedNameSpecifierLoc ReplacementQualifierLoc; + TemplateName ReplacementName = S->getReplacement(); + if (NestedNameSpecifier Qualifier = ReplacementName.getQualifier()) { + NestedNameSpecifierLocBuilder Builder; + Builder.MakeTrivial(SemaRef.Context, Qualifier, NameLoc); + ReplacementQualifierLoc = Builder.getWithLocInContext(SemaRef.Context); + } + TemplateName NewName = getDerived().TransformTemplateName( - QualifierLoc, TemplateKWLoc, S->getReplacement(), NameLoc, ObjectType, - FirstQualifierInScope, AllowInjectedClassName); + ReplacementQualifierLoc, TemplateKWLoc, ReplacementName, NameLoc, + ObjectType, FirstQualifierInScope, AllowInjectedClassName); if (NewName.isNull()) return TemplateName(); Decl *AssociatedDecl = @@ -4892,21 +4896,17 @@ TemplateName TreeTransform<Derived>::TransformTemplateName( assert(!Name.getAsDeducedTemplateName() && "DeducedTemplateName should not escape partial ordering"); - if (TemplateDecl *Template = Name.getAsTemplateDecl()) { - assert(!QualifierLoc && "missed a Qualified Template"); - TemplateDecl *TransTemplate - = cast_or_null<TemplateDecl>(getDerived().TransformDecl(NameLoc, - Template)); - if (!TransTemplate) - return TemplateName(); - - CXXScopeSpec SS; - return getDerived().RebuildTemplateName(SS, /*TemplateKeyword=*/false, - TransTemplate); + // FIXME: Preserve UsingTemplateName. + if (auto *Template = Name.getAsTemplateDecl()) { + assert(!QualifierLoc && "Unexpected qualifier"); + return TemplateName(cast_or_null<TemplateDecl>( + getDerived().TransformDecl(NameLoc, Template))); } if (SubstTemplateTemplateParmPackStorage *SubstPack = Name.getAsSubstTemplateTemplateParmPack()) { + assert(!QualifierLoc && + "Unexpected qualified SubstTemplateTemplateParmPack"); return getDerived().RebuildTemplateName( SubstPack->getArgumentPack(), SubstPack->getAssociatedDecl(), SubstPack->getIndex(), SubstPack->getFinal()); @@ -17497,13 +17497,12 @@ QualType TreeTransform<Derived>::RebuildDependentBitIntType( return SemaRef.BuildBitIntType(IsUnsigned, NumBitsExpr, Loc); } -template<typename Derived> -TemplateName -TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS, - bool TemplateKW, - TemplateDecl *Template) { +template <typename Derived> +TemplateName TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS, + bool TemplateKW, + TemplateName Name) { return SemaRef.Context.getQualifiedTemplateName(SS.getScopeRep(), TemplateKW, - TemplateName(Template)); + Name); } template <typename Derived> diff --git a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp index ae70cd9eeac43..1f4d44218ad1f 100644 --- a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp +++ b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp @@ -110,10 +110,10 @@ struct Foo { template <typename X, int Y> using Bar = Foo<X, sizeof(X)>; // expected-note {{candidate template ignored: couldn't infer template argument 'X'}} \ - // expected-note {{implicit deduction guide declared as 'template <typename X> requires __is_deducible(test9::Bar, Foo<X, sizeof(X)>) Bar(Foo<X, sizeof(X)>) -> Foo<X, sizeof(X)>'}} \ - // expected-note {{implicit deduction guide declared as 'template <typename X> requires __is_deducible(test9::Bar, Foo<X, sizeof(X)>) Bar(const X (&)[sizeof(X)]) -> Foo<X, sizeof(X)>'}} \ + // expected-note {{implicit deduction guide declared as 'template <typename X> requires __is_deducible(test9::Bar, test9::Foo<X, sizeof(X)>) Bar(test9::Foo<X, sizeof(X)>) -> test9::Foo<X, sizeof(X)>'}} \ + // expected-note {{implicit deduction guide declared as 'template <typename X> requires __is_deducible(test9::Bar, test9::Foo<X, sizeof(X)>) Bar(const X (&)[sizeof(X)]) -> test9::Foo<X, sizeof(X)>'}} \ // expected-note {{candidate template ignored: constraints not satisfied [with X = int]}} \ - // expected-note {{cannot deduce template arguments for 'Bar' from 'Foo<int, 4UL>'}} + // expected-note {{cannot deduce template arguments for 'test9::Bar' from 'test9... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/155342 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits