[clang] [clang] fix TemplateName Subst* nodes transform (PR #155342)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Aug 25 19:00:32 PDT 2025
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
More information about the cfe-commits
mailing list