llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Matheus Izvekov (mizvekov)

<details>
<summary>Changes</summary>

This makes sure NestedNameSpecifierLocs don't apply to the replacement 
TemplateName of SubstTemplate* nodes.

Also removes improper name qualification over these Subst Nodes, causing some 
canonical TemplateNames to not be fully qualified when printed.

Since this is a regression introduced in #<!-- -->147835, which was never 
released, there are no release notes.

Fixes #<!-- -->155281

---

Patch is 37.88 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/155342.diff


12 Files Affected:

- (modified) clang/include/clang/AST/TemplateName.h (+7-7) 
- (modified) clang/include/clang/AST/TypeLoc.h (+8-13) 
- (modified) clang/lib/AST/ASTContext.cpp (+6) 
- (modified) clang/lib/AST/TemplateName.cpp (+17-21) 
- (modified) clang/lib/AST/Type.cpp (+4-6) 
- (modified) clang/lib/AST/TypeLoc.cpp (+5-7) 
- (modified) clang/lib/Sema/SemaLookup.cpp (+1-1) 
- (modified) clang/lib/Sema/SemaTemplateInstantiate.cpp (+5-10) 
- (modified) clang/lib/Sema/TreeTransform.h (+35-36) 
- (modified) clang/test/SemaCXX/cxx20-ctad-type-alias.cpp (+19-19) 
- (modified) clang/test/SemaTemplate/deduction-guide.cpp (+21-21) 
- (modified) clang/test/SemaTemplate/nested-name-spec-template.cpp (+24) 


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

``````````

</details>


https://github.com/llvm/llvm-project/pull/155342
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to