[clang] 89ce871 - [clang] fix TemplateName Subst* nodes transform (#155342)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Aug 25 20:08:45 PDT 2025
Author: Matheus Izvekov
Date: 2025-08-26T00:08:41-03:00
New Revision: 89ce8718be80ead58ef5942d2d5052a528e79fee
URL: https://github.com/llvm/llvm-project/commit/89ce8718be80ead58ef5942d2d5052a528e79fee
DIFF: https://github.com/llvm/llvm-project/commit/89ce8718be80ead58ef5942d2d5052a528e79fee.diff
LOG: [clang] fix TemplateName Subst* nodes transform (#155342)
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
Added:
Modified:
clang/include/clang/AST/TemplateName.h
clang/include/clang/AST/TypeLoc.h
clang/lib/AST/ASTContext.cpp
clang/lib/AST/TemplateName.cpp
clang/lib/AST/Type.cpp
clang/lib/AST/TypeLoc.cpp
clang/lib/Sema/SemaLookup.cpp
clang/lib/Sema/SemaTemplateInstantiate.cpp
clang/lib/Sema/TreeTransform.h
clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
clang/test/SemaTemplate/deduction-guide.cpp
clang/test/SemaTemplate/nested-name-spec-template.cpp
Removed:
################################################################################
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
diff erent 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::Foo<int, 4UL>'}}
Bar s = {{1}}; // expected-error {{no viable constructor or deduction guide }}
@@ -138,13 +138,13 @@ namespace test11 {
struct A {};
template<class T> struct Foo { T c; };
template<class X, class Y=A>
-using AFoo = Foo<Y>; // expected-note {{candidate template ignored: could not match 'Foo<Y>' against 'int'}} \
- // expected-note {{implicit deduction guide declared as 'template <class Y = A> requires __is_deducible(test11::AFoo, Foo<Y>) AFoo(Foo<Y>) -> Foo<Y>'}} \
+using AFoo = Foo<Y>; // expected-note {{candidate template ignored: could not match 'test11::Foo<Y>' against 'int'}} \
+ // expected-note {{implicit deduction guide declared as 'template <class Y = A> requires __is_deducible(test11::AFoo, test11::Foo<Y>) AFoo(test11::Foo<Y>) -> test11::Foo<Y>'}} \
// expected-note {{candidate template ignored: constraints not satisfied [with Y = int]}} \
- // expected-note {{cannot deduce template arguments for 'AFoo' from 'Foo<int>'}} \
- // expected-note {{implicit deduction guide declared as 'template <class Y = A> requires __is_deducible(test11::AFoo, Foo<Y>) AFoo(Y) -> Foo<Y>'}} \
+ // expected-note {{cannot deduce template arguments for 'test11::AFoo' from 'test11::Foo<int>'}} \
+ // expected-note {{implicit deduction guide declared as 'template <class Y = A> requires __is_deducible(test11::AFoo, test11::Foo<Y>) AFoo(Y) -> test11::Foo<Y>'}} \
// expected-note {{candidate function template not viable: requires 0 arguments, but 1 was provided}} \
- // expected-note {{implicit deduction guide declared as 'template <class Y = A> requires __is_deducible(test11::AFoo, Foo<Y>) AFoo() -> Foo<Y>'}}
+ // expected-note {{implicit deduction guide declared as 'template <class Y = A> requires __is_deducible(test11::AFoo, test11::Foo<Y>) AFoo() -> test11::Foo<Y>'}}
AFoo s = {1}; // expected-error {{no viable constructor or deduction guide for deduction of template arguments of 'AFoo'}}
} // namespace test11
@@ -197,8 +197,8 @@ struct Foo {
template <int K>
using Bar = Foo<double, K>; // expected-note {{constraints not satisfied for class template 'Foo'}}
// expected-note at -1 {{candidate template ignored: could not match}} expected-note at -1 {{candidate template ignored: constraints not satisfied}}
-// expected-note at -2 {{implicit deduction guide declared as 'template <int K> requires __is_deducible(test14::Bar, Foo<double, K>) Bar(Foo<double, K>) -> Foo<double, K>'}}
-// expected-note at -3 {{implicit deduction guide declared as 'template <int K> requires __is_deducible(test14::Bar, Foo<double, K>) Bar(const double (&)[K]) -> Foo<double, K>'}}
+// expected-note at -2 {{implicit deduction guide declared as 'template <int K> requires __is_deducible(test14::Bar, test14::Foo<double, K>) Bar(test14::Foo<double, K>) -> test14::Foo<double, K>'}}
+// expected-note at -3 {{implicit deduction guide declared as 'template <int K> requires __is_deducible(test14::Bar, test14::Foo<double, K>) Bar(const double (&)[K]) -> test14::Foo<double, K>'}}
double abc[3];
Bar s2 = {abc}; // expected-error {{no viable constructor or deduction guide for deduction }}
} // namespace test14
@@ -212,9 +212,9 @@ template<False W>
using BFoo = AFoo<W>; // expected-note {{candidate template ignored: constraints not satisfied [with W = int]}} \
// expected-note at -1 {{because 'int' does not satisfy 'False'}} \
// expected-note@#test15_False {{because 'false' evaluated to false}} \
- // expected-note {{implicit deduction guide declared as 'template <False<> W> requires __is_deducible(AFoo, Foo<W *>) && __is_deducible(test15::BFoo, Foo<W *>) BFoo(W *) -> Foo<W *>}} \
- // expected-note {{candidate template ignored: could not match 'Foo<W *>' against 'int *'}} \
- // expected-note {{template <False<> W> requires __is_deducible(AFoo, Foo<W *>) && __is_deducible(test15::BFoo, Foo<W *>) BFoo(Foo<W *>) -> Foo<W *>}}
+ // expected-note {{implicit deduction guide declared as 'template <False<> W> requires __is_deducible(test15::AFoo, test15::Foo<W *>) && __is_deducible(test15::BFoo, test15::Foo<W *>) BFoo(W *) -> test15::Foo<W *>}} \
+ // expected-note {{candidate template ignored: could not match 'test15::Foo<W *>' against 'int *'}} \
+ // expected-note {{template <False<> W> requires __is_deducible(test15::AFoo, test15::Foo<W *>) && __is_deducible(test15::BFoo, test15::Foo<W *>) BFoo(test15::Foo<W *>) -> test15::Foo<W *>}}
int i = 0;
AFoo a1(&i); // OK, deduce Foo<int *>
@@ -276,12 +276,12 @@ template<typename T> requires False<T> // expected-note {{because 'int' does not
Foo(T) -> Foo<int>;
template <typename U>
-using Bar = Foo<U>; // expected-note {{could not match 'Foo<U>' against 'int'}} \
- // expected-note {{implicit deduction guide declared as 'template <typename U> requires __is_deducible(test18::Bar, Foo<U>) Bar(Foo<U>) -> Foo<U>'}} \
+using Bar = Foo<U>; // expected-note {{could not match 'test18::Foo<U>' against 'int'}} \
+ // expected-note {{implicit deduction guide declared as 'template <typename U> requires __is_deducible(test18::Bar, test18::Foo<U>) Bar(test18::Foo<U>) -> test18::Foo<U>'}} \
// expected-note {{candidate template ignored: constraints not satisfied}} \
// expected-note {{implicit deduction guide declared as 'template <typename T> requires False<T> && __is_deducible(test18::Bar, Foo<int>) Bar(T) -> Foo<int>'}} \
// expected-note {{candidate function template not viable}} \
- // expected-note {{implicit deduction guide declared as 'template <typename U> requires __is_deducible(test18::Bar, Foo<U>) Bar() -> Foo<U>'}}
+ // expected-note {{implicit deduction guide declared as 'template <typename U> requires __is_deducible(test18::Bar, test18::Foo<U>) Bar() -> test18::Foo<U>'}}
Bar s = {1}; // expected-error {{no viable constructor or deduction guide for deduction of template arguments}}
} // namespace test18
@@ -309,8 +309,8 @@ class Foo {};
// Verify that template template type parameter TTP is referenced/used in the
// template arguments of the RHS.
template <template<typename> typename TTP>
-using Bar = Foo<K<TTP>>; // expected-note {{candidate template ignored: could not match 'Foo<K<TTP>>' against 'int'}} \
- // expected-note {{implicit deduction guide declared as 'template <template <typename> typename TTP> requires __is_deducible(test20::Bar, Foo<K<TTP>>) Bar(Foo<K<TTP>>) -> Foo<K<TTP>>'}}
+using Bar = Foo<K<TTP>>; // expected-note {{candidate template ignored: could not match 'test20::Foo<K<TTP>>' against 'int'}} \
+ // expected-note {{implicit deduction guide declared as 'template <template <typename> typename TTP> requires __is_deducible(test20::Bar, test20::Foo<K<TTP>>) Bar(test20::Foo<K<TTP>>) -> test20::Foo<K<TTP>>'}}
template <class T>
class Container {};
@@ -463,7 +463,7 @@ static_assert(__is_same(decltype(a), A<int>));
BB b{0, 1};
// expected-error at -1 {{no viable}}
// expected-note@#test25_BB 2{{not viable}}
-// expected-note@#test25_BB {{template <typename ...US, typename V> requires __is_same(V, int) && __is_deducible(AA, A<int, US...>) && __is_deducible(test25::BB, A<int, US...>) BB(V) -> A<int, US...>}}
+// expected-note@#test25_BB {{template <typename ...US, typename V> requires __is_same(V, int) && __is_deducible(test25::AA, test25::A<int, US...>) && __is_deducible(test25::BB, test25::A<int, US...>) BB(V) -> test25::A<int, US...>}}
// expected-note@#test25_BB {{implicit deduction guide}}
}
diff --git a/clang/test/SemaTemplate/deduction-guide.cpp b/clang/test/SemaTemplate/deduction-guide.cpp
index ef9b91ca0b18e..e41ba7b3eeb2e 100644
--- a/clang/test/SemaTemplate/deduction-guide.cpp
+++ b/clang/test/SemaTemplate/deduction-guide.cpp
@@ -331,7 +331,7 @@ namespace TTP {
// CHECK-NEXT: |-InjectedClassNameType {{.+}} 'TTP::B<T>' dependent{{$}}
// CHECK-NEXT: | `-CXXRecord {{.+}} 'B'{{$}}
// CHECK-NEXT: `-TemplateSpecializationType {{.+}} 'TT<T>' dependent{{$}}
-// CHECK-NEXT: |-name: 'TT':'template-parameter-0-1' qualified
+// CHECK-NEXT: |-name: 'TT':'template-parameter-0-1'
// CHECK-NEXT: | `-TemplateTemplateParmDecl {{.+}} depth 0 index 1
// CHECK-NEXT: `-TemplateArgument type 'T':'type-parameter-0-0'{{$}}
// CHECK-NEXT: `-TemplateTypeParmType {{.+}} 'T' dependent depth 0 index 0{{$}}
@@ -673,8 +673,8 @@ Test test(42);
// CHECK-NEXT: | |-DeducedTemplateSpecializationType {{.*}} 'GH122134::Test' dependent
// CHECK-NEXT: | | `-name: 'GH122134::Test'
// CHECK-NEXT: | | `-TypeAliasTemplateDecl {{.*}} Test
-// CHECK-NEXT: | `-TemplateSpecializationType {{.*}} 'Struct<int, N>' dependent
-// CHECK-NEXT: | |-name: 'Struct':'GH122134::Struct' qualified
+// CHECK-NEXT: | `-TemplateSpecializationType {{.*}} 'GH122134::Struct<int, N>' dependent
+// CHECK-NEXT: | |-name: 'GH122134::Struct'
// CHECK-NEXT: | | `-ClassTemplateDecl {{.*}} Struct
// CHECK-NEXT: | |-TemplateArgument type 'int'
// CHECK-NEXT: | | `-SubstTemplateTypeParmType {{.*}} 'int' sugar class depth 0 index 0 T
@@ -684,7 +684,7 @@ Test test(42);
// CHECK-NEXT: | `-SubstNonTypeTemplateParmExpr {{.*}} 'int'
// CHECK-NEXT: | |-NonTypeTemplateParmDecl {{.*}} 'int' depth 0 index 1
// CHECK-NEXT: | `-DeclRefExpr {{.*}} 'int' NonTypeTemplateParm {{.*}} 'N' 'int'
-// CHECK-NEXT: |-CXXDeductionGuideDecl {{.*}} implicit <deduction guide for Test> 'auto (auto:1) -> Struct<int, N>'
+// CHECK-NEXT: |-CXXDeductionGuideDecl {{.*}} implicit <deduction guide for Test> 'auto (auto:1) -> GH122134::Struct<int, N>'
// CHECK-NEXT: | `-ParmVarDecl {{.*}} 'auto:1'
} // namespace GH122134
@@ -792,16 +792,16 @@ AA a{};
// CHECK-NEXT: | |-DeducedTemplateSpecializationType {{.+}} 'GH133132::AA' dependent
// CHECK-NEXT: | | `-name: 'GH133132::AA'
// CHECK-NEXT: | | `-TypeAliasTemplateDecl {{.+}} AA
-// CHECK-NEXT: | `-TemplateSpecializationType {{.+}} 'A<U>' dependent
-// CHECK-NEXT: | |-name: 'A':'GH133132::A' qualified
+// CHECK-NEXT: | `-TemplateSpecializationType {{.+}} 'GH133132::A<U>' dependent
+// CHECK-NEXT: | |-name: 'GH133132::A'
// CHECK-NEXT: | | `-ClassTemplateDecl {{.+}} A
// CHECK-NEXT: | `-TemplateArgument type 'U':'type-parameter-0-1'
// CHECK-NEXT: | `-SubstTemplateTypeParmType {{.+}} 'U' sugar dependent class depth 0 index 0 _Ty
// CHECK-NEXT: | |-FunctionTemplate {{.+}} '<deduction guide for A>'
// CHECK-NEXT: | `-TemplateTypeParmType {{.+}} 'U' dependent depth 0 index 1
// CHECK-NEXT: | `-TemplateTypeParm {{.+}} 'U'
-// CHECK-NEXT: |-CXXDeductionGuideDecl {{.+}} implicit <deduction guide for AA> 'auto () -> A<U>'
-// CHECK-NEXT: `-CXXDeductionGuideDecl {{.+}} implicit used <deduction guide for AA> 'auto () -> A<int>' implicit_instantiation
+// CHECK-NEXT: |-CXXDeductionGuideDecl {{.+}} implicit <deduction guide for AA> 'auto () -> GH133132::A<U>'
+// CHECK-NEXT: `-CXXDeductionGuideDecl {{.+}} implicit used <deduction guide for AA> 'auto () -> GH133132::A<int>' implicit_instantiation
// CHECK-NEXT: |-TemplateArgument type 'int'
// CHECK-NEXT: | `-BuiltinType {{.+}} 'int'
// CHECK-NEXT: `-TemplateArgument type 'int'
@@ -823,22 +823,22 @@ BB b{};
// CHECK-NEXT: | `-ClassTemplateDecl {{.+}} A
// CHECK-NEXT: |-TemplateTemplateParmDecl {{.+}} depth 0 index 1 _Y
// CHECK-NEXT: | |-TemplateTypeParmDecl {{.+}} class depth 0 index 0
-// CHECK-NEXT: | `-TemplateArgument {{.+}} template '_X':'template-parameter-0-0' qualified
+// CHECK-NEXT: | `-TemplateArgument {{.+}} template '_X':'template-parameter-0-0'
// CHECK-NEXT: | `-TemplateTemplateParmDecl {{.+}} depth 0 index 0 _X
// CHECK-NEXT: |-TypeTraitExpr {{.+}} 'bool' __is_deducible
// CHECK-NEXT: | |-DeducedTemplateSpecializationType {{.+}} 'GH133132::BB' dependent
// CHECK-NEXT: | | `-name: 'GH133132::BB'
// CHECK-NEXT: | | `-TypeAliasTemplateDecl {{.+}} BB
-// CHECK-NEXT: | `-TemplateSpecializationType {{.+}} 'B<_Y>' dependent
-// CHECK-NEXT: | |-name: 'B':'GH133132::B' qualified
+// CHECK-NEXT: | `-TemplateSpecializationType {{.+}} 'GH133132::B<_Y>' dependent
+// CHECK-NEXT: | |-name: 'GH133132::B'
// CHECK-NEXT: | | `-ClassTemplateDecl {{.+}} B
// CHECK-NEXT: | `-TemplateArgument template '_Y':'template-parameter-0-1' subst index 0
// CHECK-NEXT: | |-parameter: TemplateTemplateParmDecl {{.+}} depth 0 index 0 _X
// CHECK-NEXT: | |-associated FunctionTemplate {{.+}} '<deduction guide for B>'
-// CHECK-NEXT: | `-replacement: '_Y':'template-parameter-0-1' qualified
+// CHECK-NEXT: | `-replacement: '_Y':'template-parameter-0-1'
// CHECK-NEXT: | `-TemplateTemplateParmDecl {{.+}} depth 0 index 1 _Y
-// CHECK-NEXT: |-CXXDeductionGuideDecl {{.+}} implicit <deduction guide for BB> 'auto () -> B<_Y>'
-// CHECK-NEXT: `-CXXDeductionGuideDecl {{.+}} implicit used <deduction guide for BB> 'auto () -> B<GH133132::A>' implicit_instantiation
+// CHECK-NEXT: |-CXXDeductionGuideDecl {{.+}} implicit <deduction guide for BB> 'auto () -> GH133132::B<_Y>'
+// CHECK-NEXT: `-CXXDeductionGuideDecl {{.+}} implicit used <deduction guide for BB> 'auto () -> GH133132::B<GH133132::A>' implicit_instantiation
// CHECK-NEXT: |-TemplateArgument template 'GH133132::A'
// CHECK-NEXT: | `-ClassTemplateDecl {{.+}} A
// CHECK-NEXT: `-TemplateArgument template 'GH133132::A'
@@ -866,16 +866,16 @@ CC c{};
// CHECK-NEXT: | |-DeducedTemplateSpecializationType {{.+}} 'GH133132::CC' dependent
// CHECK-NEXT: | | `-name: 'GH133132::CC'
// CHECK-NEXT: | | `-TypeAliasTemplateDecl {{.+}} CC
-// CHECK-NEXT: | `-TemplateSpecializationType {{.+}} 'A<U>' dependent
-// CHECK-NEXT: | |-name: 'A':'GH133132::A' qualified
+// CHECK-NEXT: | `-TemplateSpecializationType {{.+}} 'GH133132::A<U>' dependent
+// CHECK-NEXT: | |-name: 'GH133132::A'
// CHECK-NEXT: | | `-ClassTemplateDecl {{.+}} A
// CHECK-NEXT: | `-TemplateArgument type 'U':'type-parameter-0-1'
// CHECK-NEXT: | `-SubstTemplateTypeParmType {{.+}} 'U' sugar dependent class depth 0 index 0 _Ty
// CHECK-NEXT: | |-FunctionTemplate {{.+}} '<deduction guide for A>'
// CHECK-NEXT: | `-TemplateTypeParmType {{.+}} 'U' dependent depth 0 index 1
// CHECK-NEXT: | `-TemplateTypeParm {{.+}} 'U'
-// CHECK-NEXT: |-CXXDeductionGuideDecl {{.+}} implicit <deduction guide for CC> 'auto () -> A<U>'
-// CHECK-NEXT: `-CXXDeductionGuideDecl {{.+}} implicit used <deduction guide for CC> 'auto () -> A<GH133132::A<int>>' implicit_instantiation
+// CHECK-NEXT: |-CXXDeductionGuideDecl {{.+}} implicit <deduction guide for CC> 'auto () -> GH133132::A<U>'
+// CHECK-NEXT: `-CXXDeductionGuideDecl {{.+}} implicit used <deduction guide for CC> 'auto () -> GH133132::A<GH133132::A<int>>' implicit_instantiation
// CHECK-NEXT: |-TemplateArgument integral '42'
// CHECK-NEXT: `-TemplateArgument type 'GH133132::A<int>'
// CHECK-NEXT: `-RecordType {{.+}} 'GH133132::A<int>'
@@ -949,8 +949,8 @@ Expand<Type, Invocable<>> _{};
// CHECK-NEXT: | |-DeducedTemplateSpecializationType {{.+}} 'GH141425::Alias' dependent
// CHECK-NEXT: | | `-name: 'GH141425::Alias'
// CHECK-NEXT: | | `-TypeAliasTemplateDecl {{.+}} Alias
-// CHECK-NEXT: | `-TemplateSpecializationType {{.+}} 'Container<T...>' dependent
-// CHECK-NEXT: | |-name: 'Container':'GH141425::Container' qualified
+// CHECK-NEXT: | `-TemplateSpecializationType {{.+}} 'GH141425::Container<T...>' dependent
+// CHECK-NEXT: | |-name: 'GH141425::Container'
// CHECK-NEXT: | | `-ClassTemplateDecl {{.+}} Container
// CHECK-NEXT: | `-TemplateArgument type 'T...':'type-parameter-0-0...'
// CHECK-NEXT: | `-PackExpansionType {{.+}} 'T...' dependent
@@ -958,7 +958,7 @@ Expand<Type, Invocable<>> _{};
// CHECK-NEXT: | |-FunctionTemplate {{.+}} '<deduction guide for Container>'
// CHECK-NEXT: | `-TemplateTypeParmType {{.+}} 'T' dependent contains_unexpanded_pack depth 0 index 0 pack
// CHECK-NEXT: | `-TemplateTypeParm {{.+}} 'T'
-// CHECK-NEXT: |-CXXDeductionGuideDecl {{.+}} implicit <deduction guide for Alias> 'auto (T...) -> Container<T...>'
+// CHECK-NEXT: |-CXXDeductionGuideDecl {{.+}} implicit <deduction guide for Alias> 'auto (T...) -> GH141425::Container<T...>'
// CHECK-NEXT: | `-ParmVarDecl {{.+}} 'T...' pack
}
diff --git a/clang/test/SemaTemplate/nested-name-spec-template.cpp b/clang/test/SemaTemplate/nested-name-spec-template.cpp
index 0f51a14af9e52..f99fa4b464859 100644
--- a/clang/test/SemaTemplate/nested-name-spec-template.cpp
+++ b/clang/test/SemaTemplate/nested-name-spec-template.cpp
@@ -186,3 +186,27 @@ namespace DependentSizedArray {
template <class, class> struct A;
template <class T> struct A<T, typename Z<T(0)>::X>;
} // namespace DependentUnaryTransform
+
+namespace GH155281 {
+ template <bool> struct enable_if;
+ template <class _Tp, _Tp> struct integral_constant;
+ template <typename> struct conjunction;
+ template <typename T> using value_type_t = T;
+ template <class Check> using require_t = typename enable_if<Check::value>::type;
+ template <template <class> class, template <class> class,
+ template <class> class, class... Check>
+ using container_type_check_base =
+ integral_constant<bool, conjunction<Check...>::value>;
+ template <typename> struct is_std_vector;
+ template <template <class> class TypeCheck, class... Check>
+ using require_std_vector_vt =
+ require_t<container_type_check_base<is_std_vector, value_type_t, TypeCheck,
+ Check...> >;
+ template <typename, typename> class vector_seq_view;
+ namespace internal {
+ template <typename> using is_matrix_or_std_vector = int;
+ }
+ template <typename T>
+ class vector_seq_view<
+ T, require_std_vector_vt<internal::is_matrix_or_std_vector, T> >;
+} // namespace GH155281
More information about the cfe-commits
mailing list