llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Matthias Görgens (matthiasgoergens)

<details>
<summary>Changes</summary>

`TemplateDiff` stores template-template arguments as `TemplateDecl *`, but a 
dependent template name such as `PartialApply&lt;B, F&gt;::template R` has no 
declaration: `GetTemplateDecl` returned null for both sides, and 
`PrintTemplateTemplate` hit `assert((FromTD || ToTD))` as soon as a diagnostic 
printed a template tree containing such arguments — a crash on valid code.

Carry `TemplateName` through the diff tree instead. Equality uses 
`ASTContext::hasSameTemplateName`, which matches the previous 
canonical-declaration comparison for resolved names and additionally identifies 
equal dependent names; printing uses `TemplateName::print` when no declaration 
exists and is unchanged otherwise. The test pins the printed tree for two 
differing dependent names rather than merely the absence of the crash.

Fixes #<!-- -->213068.

## Tool use

Per the [LLVM AI Tool Use Policy](https://llvm.org/docs/AIToolPolicy.html): AI
tools were involved throughout the preparation of this change. I am the author
and accountable for the contribution.

Assisted-by: OpenAI Codex
Assisted-by: Claude Code
Assisted-by: Kimi
Assisted-by: DeepSeek


---
Full diff: https://github.com/llvm/llvm-project/pull/214989.diff


2 Files Affected:

- (modified) clang/lib/AST/ASTDiagnostic.cpp (+52-29) 
- (added) clang/test/SemaTemplate/gh213068.cpp (+23) 


``````````diff
diff --git a/clang/lib/AST/ASTDiagnostic.cpp b/clang/lib/AST/ASTDiagnostic.cpp
index f7888f58985db..0a76457cf4bb2 100644
--- a/clang/lib/AST/ASTDiagnostic.cpp
+++ b/clang/lib/AST/ASTDiagnostic.cpp
@@ -616,6 +616,7 @@ class TemplateDiff {
       bool IsValidInt = false;
       Expr *ArgExpr = nullptr;
       TemplateDecl *TD = nullptr;
+      TemplateName TN;
       ValueDecl *VD = nullptr;
       bool NeedAddressOf = false;
       bool IsNullPtr = false;
@@ -694,12 +695,12 @@ class TemplateDiff {
       SetDefault(FromDefault, ToDefault);
     }
 
-    void SetTemplateTemplateDiff(TemplateDecl *FromTD, TemplateDecl *ToTD,
+    void SetTemplateTemplateDiff(TemplateName FromTN, TemplateName ToTN,
                                  bool FromDefault, bool ToDefault) {
       assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty.");
       FlatTree[CurrentNode].Kind = TemplateTemplate;
-      FlatTree[CurrentNode].FromArgInfo.TD = FromTD;
-      FlatTree[CurrentNode].ToArgInfo.TD = ToTD;
+      FlatTree[CurrentNode].FromArgInfo.TN = FromTN;
+      FlatTree[CurrentNode].ToArgInfo.TN = ToTN;
       SetDefault(FromDefault, ToDefault);
     }
 
@@ -853,10 +854,10 @@ class TemplateDiff {
       ToExpr = FlatTree[ReadNode].ToArgInfo.ArgExpr;
     }
 
-    void GetTemplateTemplateDiff(TemplateDecl *&FromTD, TemplateDecl *&ToTD) {
+    void GetTemplateTemplateDiff(TemplateName &FromTN, TemplateName &ToTN) {
       assert(FlatTree[ReadNode].Kind == TemplateTemplate && "Unexpected 
kind.");
-      FromTD = FlatTree[ReadNode].FromArgInfo.TD;
-      ToTD = FlatTree[ReadNode].ToArgInfo.TD;
+      FromTN = FlatTree[ReadNode].FromArgInfo.TN;
+      ToTN = FlatTree[ReadNode].ToArgInfo.TN;
     }
 
     void GetIntegerDiff(llvm::APSInt &FromInt, llvm::APSInt &ToInt,
@@ -1218,12 +1219,13 @@ class TemplateDiff {
   /// template template difference.
   void DiffTemplateTemplates(const TSTiterator &FromIter,
                              const TSTiterator &ToIter) {
-    TemplateDecl *FromDecl = GetTemplateDecl(FromIter);
-    TemplateDecl *ToDecl = GetTemplateDecl(ToIter);
-    Tree.SetTemplateTemplateDiff(FromDecl, ToDecl, FromIter.isEnd() && 
FromDecl,
-                                 ToIter.isEnd() && ToDecl);
-    Tree.SetSame(FromDecl && ToDecl &&
-                 FromDecl->getCanonicalDecl() == ToDecl->getCanonicalDecl());
+    TemplateName FromName = GetTemplateName(FromIter);
+    TemplateName ToName = GetTemplateName(ToIter);
+    Tree.SetTemplateTemplateDiff(FromName, ToName,
+                                 FromIter.isEnd() && !FromName.isNull(),
+                                 ToIter.isEnd() && !ToName.isNull());
+    Tree.SetSame(!FromName.isNull() && !ToName.isNull() &&
+                 Context.hasSameTemplateName(FromName, ToName));
   }
 
   /// InitializeNonTypeDiffVariables - Helper function for DiffNonTypes
@@ -1513,14 +1515,14 @@ class TemplateDiff {
     return QualType();
   }
 
-  /// GetTemplateDecl - Retrieves the template template arguments, including
+  /// GetTemplateName - Retrieves the template template arguments, including
   /// default arguments.
-  static TemplateDecl *GetTemplateDecl(const TSTiterator &Iter) {
+  static TemplateName GetTemplateName(const TSTiterator &Iter) {
     if (!Iter.isEnd())
-      return Iter->getAsTemplate().getAsTemplateDecl();
+      return Iter->getAsTemplateOrTemplatePattern();
     if (Iter.hasDesugaredTA())
-      return Iter.getDesugaredTA().getAsTemplate().getAsTemplateDecl();
-    return nullptr;
+      return Iter.getDesugaredTA().getAsTemplateOrTemplatePattern();
+    return {};
   }
 
   /// IsEqualExpr - Returns true if the expressions are the same in regards to
@@ -1571,9 +1573,9 @@ class TemplateDiff {
         return;
       }
       case DiffTree::TemplateTemplate: {
-        TemplateDecl *FromTD, *ToTD;
-        Tree.GetTemplateTemplateDiff(FromTD, ToTD);
-        PrintTemplateTemplate(FromTD, ToTD, Tree.FromDefault(),
+        TemplateName FromTN, ToTN;
+        Tree.GetTemplateTemplateDiff(FromTN, ToTN);
+        PrintTemplateTemplate(FromTN, ToTN, Tree.FromDefault(),
                               Tree.ToDefault(), Tree.NodeIsSame());
         return;
       }
@@ -1801,20 +1803,41 @@ class TemplateDiff {
 
   /// PrintTemplateTemplate - Handles printing of template template arguments,
   /// highlighting argument differences.
-  void PrintTemplateTemplate(TemplateDecl *FromTD, TemplateDecl *ToTD,
+  void PrintTemplateTemplate(TemplateName FromTN, TemplateName ToTN,
                              bool FromDefault, bool ToDefault, bool Same) {
-    assert((FromTD || ToTD) && "Only one template argument may be missing.");
+    assert((!FromTN.isNull() || !ToTN.isNull()) &&
+           "Only one template argument may be missing.");
 
-    std::string FromName =
-        std::string(FromTD ? FromTD->getName() : "(no argument)");
-    std::string ToName = std::string(ToTD ? ToTD->getName() : "(no argument)");
-    if (FromTD && ToTD && FromName == ToName) {
-      FromName = FromTD->getQualifiedNameAsString();
-      ToName = ToTD->getQualifiedNameAsString();
+    auto GetName = [this](TemplateName TN, TemplateName::Qualified Qual) {
+      if (TN.isNull())
+        return std::string("(no argument)");
+      std::string Name;
+      llvm::raw_string_ostream Out(Name);
+      TN.print(Out, Policy, Qual);
+      return Name;
+    };
+    TemplateDecl *FromTD = FromTN.getAsTemplateDecl();
+    TemplateDecl *ToTD = ToTN.getAsTemplateDecl();
+    std::string FromName;
+    std::string ToName;
+    if (FromTD && ToTD) {
+      FromName = std::string(FromTD->getName());
+      ToName = std::string(ToTD->getName());
+      if (FromName == ToName) {
+        FromName = FromTD->getQualifiedNameAsString();
+        ToName = ToTD->getQualifiedNameAsString();
+      }
+    } else {
+      FromName = GetName(FromTN, TemplateName::Qualified::AsWritten);
+      ToName = GetName(ToTN, TemplateName::Qualified::AsWritten);
     }
 
     if (Same) {
-      OS << "template " << FromTD->getDeclName();
+      OS << "template ";
+      if (FromTD)
+        OS << FromTD->getDeclName();
+      else
+        FromTN.print(OS, Policy);
     } else if (!PrintTree) {
       OS << (FromDefault ? "(default) template " : "template ");
       Bold();
diff --git a/clang/test/SemaTemplate/gh213068.cpp 
b/clang/test/SemaTemplate/gh213068.cpp
new file mode 100644
index 0000000000000..8d6c89cbde850
--- /dev/null
+++ b/clang/test/SemaTemplate/gh213068.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s
+// RUN: not %clang_cc1 -std=c++17 -fsyntax-only 
-fdiagnostics-show-template-tree %s 2>&1 | FileCheck %s
+
+template <template <template <typename> class, typename> class T,
+          template <typename> class V>
+struct PartialApply {
+  template <template <template <typename> class, typename> class A,
+            template <template <typename> class, typename> class B,
+            template <typename> class F, typename X>
+  using Mul = A<PartialApply<B, F>::template R, X>; // expected-note 
{{previous definition is here}}
+  template <template <template <typename> class, typename> class T_ffl,
+            template <typename> class V_ffl>
+  struct PartialApply_ffl {};
+  template <template <template <typename> class, typename> class A_ffl,
+            template <template <typename> class, typename> class B_ffl,
+            template <typename> class F_ffl, typename X>
+  using Mul = // expected-error {{type alias template redefinition with 
different types}}
+      A_ffl<PartialApply_ffl<B_ffl, F_ffl>::template R, X>;
+};
+
+// CHECK:      error: type alias template redefinition with different types
+// CHECK:      [template PartialApply_ffl<B_ffl, F_ffl>::template R != 
template PartialApply<B, F>::template R],
+// CHECK-NEXT: [...]

``````````

</details>


https://github.com/llvm/llvm-project/pull/214989
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to