-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[clang] fix TemplateName Subst* nodes transform #155342
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
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
@llvm/pr-subscribers-clang Author: Matheus Izvekov (mizvekov) ChangesThis 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:
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]
|
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