https://github.com/mizvekov created https://github.com/llvm/llvm-project/pull/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 >From 3b3e1b30d55f4f4ff67b631652982ed2d9cd8887 Mon Sep 17 00:00:00 2001 From: Matheus Izvekov <mizve...@gmail.com> Date: Mon, 25 Aug 2025 22:18:31 -0300 Subject: [PATCH] [clang] fix TemplateName Subst* nodes transform 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 --- clang/include/clang/AST/TemplateName.h | 14 ++-- clang/include/clang/AST/TypeLoc.h | 21 +++--- clang/lib/AST/ASTContext.cpp | 6 ++ clang/lib/AST/TemplateName.cpp | 38 +++++----- clang/lib/AST/Type.cpp | 10 ++- clang/lib/AST/TypeLoc.cpp | 12 ++-- clang/lib/Sema/SemaLookup.cpp | 2 +- clang/lib/Sema/SemaTemplateInstantiate.cpp | 15 ++-- clang/lib/Sema/TreeTransform.h | 71 +++++++++---------- clang/test/SemaCXX/cxx20-ctad-type-alias.cpp | 38 +++++----- clang/test/SemaTemplate/deduction-guide.cpp | 42 +++++------ .../nested-name-spec-template.cpp | 24 +++++++ 12 files changed, 152 insertions(+), 141 deletions(-) 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::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@-1 {{candidate template ignored: could not match}} expected-note@-1 {{candidate template ignored: constraints not satisfied}} -// expected-note@-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@-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@-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@-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@-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@-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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits