Author: Matheus Izvekov
Date: 2026-05-14T15:05:03-03:00
New Revision: 28749538069bb018f1f327b2fe757e216ac80cf1

URL: 
https://github.com/llvm/llvm-project/commit/28749538069bb018f1f327b2fe757e216ac80cf1
DIFF: 
https://github.com/llvm/llvm-project/commit/28749538069bb018f1f327b2fe757e216ac80cf1.diff

LOG: [clang] NFC: add new test cases involving bugs in 
getTemplateInstantiationArgs (#197755)

The new test files come from 2bb3d3a3f32ffaef3d9b6a27db7f1941f0cb1136,
which was reverted a long time ago. These have a couple I had to #ifdef
out because they expose crashes.

The other test cases are preparatory for a future PR.

Also some changes are pure whitespace cleanup.

Added: 
    clang/test/CXX/temp/temp.constr/temp.constr.decl/p4.cpp
    clang/test/CXX/temp/temp.spec/temp.expl.spec/p7.cpp

Modified: 
    clang/test/AST/ast-dump-linkage-internal.cpp
    clang/test/AST/ast-dump-linkage.cpp
    clang/test/SemaCXX/friend.cpp
    clang/test/SemaTemplate/concepts-out-of-line-def.cpp
    clang/test/SemaTemplate/friend.cpp

Removed: 
    


################################################################################
diff  --git a/clang/test/AST/ast-dump-linkage-internal.cpp 
b/clang/test/AST/ast-dump-linkage-internal.cpp
index 49f5b3124450b..6b961301c4abb 100644
--- a/clang/test/AST/ast-dump-linkage-internal.cpp
+++ b/clang/test/AST/ast-dump-linkage-internal.cpp
@@ -91,7 +91,7 @@ int TemplatedVarSpec = TemplatedVar<int>;
 
 void FuncDef() {
 // CHECK: | |-FunctionDecl {{.*}} FuncDef 'void ()' internal-linkage
-  
+
   extern int Int;
 // CHECK: | |   | `-VarDecl {{.*}} Int 'int' extern internal-linkage
   extern const int ConstInt;
@@ -176,7 +176,7 @@ struct Struct {
 
   friend struct Known::FriendStruct;
 // CHECK: | |   |-FriendDecl {{.*}} 'struct Known::FriendStruct'
-  
+
   template <typename>
   friend struct Known::FriendStructTemplate;
 // CHECK: | |   |-FriendDecl {{.*}} col:{{[0-9]*$}}
@@ -215,7 +215,7 @@ struct Struct {
   friend void Known::FuncDecl();
 // CHECK: | |   |-FriendDecl {{.*}} col:{{[0-9]*$}}
 // CHECK: | |   | `-FunctionDecl {{.*}} friend FuncDecl 'void ()' 
internal-linkage
-  
+
   template <typename>
   friend void Known::TemplatedFuncDecl();
 // CHECK: | |   |-FriendDecl {{.*}} col:{{[0-9]*$}}
@@ -333,7 +333,7 @@ struct StructTemplate {
 
   friend struct Known::FriendStruct;
 // CHECK: | |   |-FriendDecl {{.*}} 'struct Known::FriendStruct'
-  
+
   template <typename>
   friend struct Known::FriendStructTemplate;
 // CHECK: | |   |-FriendDecl {{.*}} col:{{[0-9]*$}}
@@ -376,7 +376,7 @@ struct StructTemplate {
 // CHECK: | |   | `-FunctionDecl {{.*}} friend_undeclared FuncDecl 'void ()' 
internal-linkage
 // FIXME: friend_undeclared is the wrong answer; friends with qualified-id
 //        have to correspond to one or more declarations found by name lookup.
-  
+
   template <typename>
   friend void Known::TemplatedFuncDecl();
 // CHECK: | |   |-FriendDecl {{.*}} col:{{[0-9]*$}}

diff  --git a/clang/test/AST/ast-dump-linkage.cpp 
b/clang/test/AST/ast-dump-linkage.cpp
index 98ff532be0f03..18228eb4e8c21 100644
--- a/clang/test/AST/ast-dump-linkage.cpp
+++ b/clang/test/AST/ast-dump-linkage.cpp
@@ -88,7 +88,7 @@ int TemplatedVarSpec = TemplatedVar<int>;
 
 void FuncDef() {
 // CHECK: |-FunctionDecl {{.*}} FuncDef 'void ()' external-linkage
-  
+
   extern int Int;
 // CHECK: |   | `-VarDecl {{.*}} Int 'int' extern external-linkage
   extern const int ConstInt;
@@ -170,11 +170,11 @@ struct Struct {
 // CHECK: |   | `-ClassTemplateDecl {{.*}} friend_undeclared 
UnknownFriendStructTemplate external-linkage
 // CHECK: |   |   `-CXXRecordDecl {{.*}} struct UnknownFriendStructTemplate
 // FIXME: Friend declarations do not bind names, so they cannot have linkage.
-  
+
   friend struct Known::FriendStruct;
 // CHECK: |   |-FriendDecl {{.*}} 'struct Known::FriendStruct'
 // FIXME: Where is CXXRecordDecl?
-  
+
   template <typename>
   friend struct Known::FriendStructTemplate;
 // CHECK: |   |-FriendDecl {{.*}} col:{{[0-9]*$}}
@@ -336,10 +336,10 @@ struct StructTemplate {
 // CHECK: |   | `-ClassTemplateDecl {{.*}} friend_undeclared 
UnknownFriendStructTemplate external-linkage
 // CHECK: |   |   `-CXXRecordDecl {{.*}} struct UnknownFriendStructTemplate
 // FIXME: Friend declarations do not bind names, so they cannot have linkage.
-  
+
   friend struct Known::FriendStruct;
 // CHECK: |   |-FriendDecl {{.*}} 'struct Known::FriendStruct'
-  
+
   template <typename>
   friend struct Known::FriendStructTemplate;
 // CHECK: |   |-FriendDecl {{.*}} col:{{[0-9]*$}}

diff  --git a/clang/test/CXX/temp/temp.constr/temp.constr.decl/p4.cpp 
b/clang/test/CXX/temp/temp.constr/temp.constr.decl/p4.cpp
new file mode 100644
index 0000000000000..fefe86a448b18
--- /dev/null
+++ b/clang/test/CXX/temp/temp.constr/temp.constr.decl/p4.cpp
@@ -0,0 +1,188 @@
+// RUN: %clang_cc1 -std=c++20 -verify %s
+
+template<typename T>
+concept D = true;
+
+template<typename T>
+struct A { // expected-note {{defined here}}
+  template<typename U, bool V>
+  void f() requires V;
+
+  template<>
+  void f<short, true>();
+
+  template<D U>
+  void g();
+
+  template<typename U, bool V> requires V
+  struct B;
+  // expected-note@-2 {{previous template declaration is here}}
+
+  template<typename U, bool V> requires V
+  struct B<U*, V>;
+
+  template<>
+  struct B<short, true>;
+
+  template<D U>
+  struct C;
+  // expected-note@-2 {{previous template declaration is here}}
+
+  template<D U>
+  struct C<U*>;
+
+  template<typename U, bool V> requires V
+  static int x;
+  // expected-note@-2 {{previous template declaration is here}}
+
+  template<typename U, bool V> requires V
+  static int x<U*, V>;
+
+  template<>
+  int x<short, true>;
+
+  template<D U>
+  static int y;
+  // expected-note@-2 {{previous template declaration is here}}
+
+  template<D U>
+  static int y<U*>;
+};
+
+template<typename T>
+template<typename U, bool V>
+void A<T>::f() requires V { }
+
+template<typename T>
+template<D U>
+void A<T>::g() { }
+
+template<typename T>
+template<typename U, bool V> requires V
+struct A<T>::B { };
+
+template<typename T>
+template<typename U, bool V> requires V
+struct A<T>::B<U*, V> { };
+
+template<typename T>
+template<typename U, bool V> requires V
+struct A<T>::B<U&, V> { };
+
+template<typename T>
+template<D U>
+struct A<T>::C { };
+
+template<typename T>
+template<D U>
+struct A<T>::C<U*> { };
+
+template<typename T>
+template<typename U, bool V> requires V
+int A<T>::x = 0;
+
+template<typename T>
+template<typename U, bool V> requires V
+int A<T>::x<U*, V> = 0;
+
+template<typename T>
+template<typename U, bool V> requires V
+int A<T>::x<U&, V> = 0;
+
+template<typename T>
+template<D U>
+int A<T>::y = 0;
+
+template<typename T>
+template<D U>
+int A<T>::y<U*> = 0;
+
+// FIXME: This should be accepted.
+template<>
+template<typename U, bool V>
+void A<short>::f() requires V;
+// expected-error@-1 {{out-of-line declaration of 'f' does not match any 
declaration in 'A<short>'}}
+
+template<>
+template<>
+void A<short>::f<int, true>();
+
+template<>
+template<>
+void A<void>::f<int, true>();
+
+template<>
+template<D U>
+void A<short>::g();
+
+// FIXME: This should be accepted.
+template<>
+template<typename U, bool V> requires V
+struct A<int>::B;
+// expected-error@-2 {{requires clause 
diff ers in template redeclaration}}
+
+template<>
+template<>
+struct A<int>::B<int, true>;
+
+template<>
+template<>
+struct A<void>::B<int, true>;
+
+template<>
+template<typename U, bool V> requires V
+struct A<int>::B<U*, V>;
+
+template<>
+template<typename U, bool V> requires V
+struct A<int>::B<U&, V>;
+
+// FIXME: This should be accepted.
+template<>
+template<D U>
+struct A<int>::C;
+// expected-error@-2 {{type constraint 
diff ers in template redeclaration}}
+
+template<>
+template<D U>
+struct A<int>::C<U*>;
+
+template<>
+template<D U>
+struct A<int>::C<U&>;
+
+// FIXME: This should be accepted.
+template<>
+template<typename U, bool V> requires V
+int A<long>::x;
+// expected-error@-2 {{requires clause 
diff ers in template redeclaration}}
+
+template<>
+template<>
+int A<long>::x<int, true>;
+
+template<>
+template<>
+int A<void>::x<int, true>;
+
+template<>
+template<typename U, bool V> requires V
+int A<long>::x<U*, V>;
+
+template<>
+template<typename U, bool V> requires V
+int A<long>::x<U&, V>;
+
+// FIXME: This should be accepted.
+template<>
+template<D U>
+int A<long>::y;
+// expected-error@-2 {{type constraint 
diff ers in template redeclaration}}
+
+template<>
+template<D U>
+int A<long>::y<U*>;
+
+template<>
+template<D U>
+int A<long>::y<U&>;

diff  --git a/clang/test/CXX/temp/temp.spec/temp.expl.spec/p7.cpp 
b/clang/test/CXX/temp/temp.spec/temp.expl.spec/p7.cpp
new file mode 100644
index 0000000000000..5bb5de88a6fc2
--- /dev/null
+++ b/clang/test/CXX/temp/temp.spec/temp.expl.spec/p7.cpp
@@ -0,0 +1,234 @@
+// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
+
+namespace Undefined {
+  template<typename T>
+  struct A {
+    template<typename U>
+    static constexpr int f(); // expected-note {{declared here}}
+
+    template<typename U>
+    static const int x; // expected-note {{declared here}}
+
+    template<typename U>
+    static const int x<U*>; // expected-note {{declared here}}
+
+    template<typename U>
+    struct B; // expected-note {{template is declared here}}
+
+    template<typename U>
+    struct B<U*>; // expected-note {{template is declared here}}
+  };
+
+  template<>
+  template<typename U>
+  constexpr int A<short>::f() {
+    return A<long>::f<U>();
+  }
+
+  template<>
+  template<typename U>
+  constexpr int A<short>::x = A<long>::x<U>;
+
+  template<>
+  template<typename U>
+  constexpr int A<short>::x<U*> = A<long>::x<U*>;
+
+  template<>
+  template<typename U>
+  struct A<short>::B<U*> {
+    static constexpr int y = A<long>::B<U*>::y;
+  };
+
+  template<>
+  template<typename U>
+  struct A<short>::B {
+    static constexpr int y = A<long>::B<U>::y;
+  };
+
+  template<>
+  template<typename U>
+  constexpr int A<long>::f() {
+    return 1;
+  }
+
+  template<>
+  template<typename U>
+  constexpr int A<long>::x = 1;
+
+  template<>
+  template<typename U>
+  constexpr int A<long>::x<U*> = 2;
+
+  template<>
+  template<typename U>
+  struct A<long>::B {
+    static constexpr int y = 1;
+  };
+
+  template<>
+  template<typename U>
+  struct A<long>::B<U*> {
+    static constexpr int y = 2;
+  };
+
+  static_assert(A<int>::f<int>() == 0); // expected-error {{static assertion 
expression is not an integral constant expression}}
+                                        // expected-note@-1 {{undefined 
function 'f<int>' cannot be used in a constant expression}}
+  static_assert(A<int>::x<int> == 0); // expected-error {{static assertion 
expression is not an integral constant expression}}
+                                      // expected-note@-1 {{initializer of 
'x<int>' is unknown}}
+  static_assert(A<int>::x<int*> == 0); // expected-error {{static assertion 
expression is not an integral constant expression}}
+                                       // expected-note@-1 {{initializer of 
'x<int *>' is unknown}}
+  static_assert(A<int>::B<int>::y == 0); // expected-error {{implicit 
instantiation of undefined template 'Undefined::A<int>::B<int>'}}
+  static_assert(A<int>::B<int*>::y == 0); // expected-error {{implicit 
instantiation of undefined template 'Undefined::A<int>::B<int *>'}}
+
+  static_assert(A<short>::f<int>() == 1);
+  static_assert(A<short>::x<int> == 1);
+  static_assert(A<short>::x<int*> == 2);
+#if 0
+  // FIXME: crashes
+  static_assert(A<short>::B<int>::y == 1);
+  static_assert(A<short>::B<int*>::y == 2);
+#endif
+} // namespace Undefined
+
+namespace Defined {
+  template<typename T>
+  struct A {
+    template<typename U>
+    static constexpr int f() {
+      return 0;
+    };
+
+    template<typename U>
+    static const int x = 0;
+
+    template<typename U>
+    static const int x<U*> = 0;
+
+    template<typename U>
+    struct B {
+      static constexpr int y = 0;
+    };
+
+    template<typename U>
+    struct B<U*> {
+      static constexpr int y = 0;
+    };
+  };
+
+  template<>
+  template<typename U>
+  constexpr int A<short>::f() {
+    return A<long>::f<U>();
+  }
+
+  template<>
+  template<typename U>
+  constexpr int A<short>::x = A<long>::x<U>;
+
+  template<>
+  template<typename U>
+  constexpr int A<short>::x<U*> = A<long>::x<U*>;
+
+  template<>
+  template<typename U>
+  struct A<short>::B<U*> {
+    static constexpr int y = A<long>::B<U*>::y;
+  };
+
+  template<>
+  template<typename U>
+  struct A<short>::B {
+    static constexpr int y = A<long>::B<U>::y;
+  };
+
+  template<>
+  template<typename U>
+  constexpr int A<long>::f() {
+    return 1;
+  }
+
+  template<>
+  template<typename U>
+  constexpr int A<long>::x = 1;
+
+  template<>
+  template<typename U>
+  constexpr int A<long>::x<U*> = 2;
+
+  template<>
+  template<typename U>
+  struct A<long>::B {
+    static constexpr int y = 1;
+  };
+
+  template<>
+  template<typename U>
+  struct A<long>::B<U*> {
+    static constexpr int y = 2;
+  };
+
+  static_assert(A<int>::f<int>() == 0);
+  static_assert(A<int>::x<int> == 0);
+  static_assert(A<int>::x<int*> == 0);
+  static_assert(A<int>::B<int>::y == 0);
+  static_assert(A<int>::B<int*>::y == 0);
+
+  static_assert(A<short>::f<int>() == 1);
+  static_assert(A<short>::x<int> == 1);
+  static_assert(A<short>::x<int*> == 2);
+  static_assert(A<short>::B<int>::y == 1);
+  static_assert(A<short>::B<int*>::y == 2);
+} // namespace Defined
+
+namespace Dependent {
+  template<int I>
+  struct A {
+    template<int J>
+    static constexpr int f();
+
+    template<int J>
+    static const int x;
+
+    template<int J>
+    struct B;
+  };
+
+  template<>
+  template<int J>
+  constexpr int A<0>::f() {
+    return A<1>::f<J>();
+  }
+
+  template<>
+  template<int J>
+  constexpr int A<1>::f() {
+    return J;
+  }
+
+  template<>
+  template<int J>
+  constexpr int A<0>::x = A<1>::x<J>;
+
+  template<>
+  template<int J>
+  constexpr int A<1>::x = J;
+
+  template<>
+  template<int J>
+  struct A<0>::B {
+    static constexpr int y = A<1>::B<J>::y;
+  };
+
+  template<>
+  template<int J>
+  struct A<1>::B {
+    static constexpr int y = J;
+  };
+
+  static_assert(A<0>::f<2>() == 2);
+  static_assert(A<0>::x<2> == 2);
+#if 0
+  // FIXME: crashes
+  static_assert(A<0>::B<2>::y == 2);
+#endif
+} // namespace Dependent

diff  --git a/clang/test/SemaCXX/friend.cpp b/clang/test/SemaCXX/friend.cpp
index 53e6bbfcf42a8..e644cab67b2b2 100644
--- a/clang/test/SemaCXX/friend.cpp
+++ b/clang/test/SemaCXX/friend.cpp
@@ -130,6 +130,20 @@ namespace test6_3 {
     v.f();
   }
 }
+namespace test6_4 {
+  template<class T> struct vector {
+    constexpr vector(int i) {}
+    constexpr int f(const T& t = T()) const { return T().v; }
+  };
+  class A {
+    friend constexpr int vector<A>::f(const A&) const;
+    static constexpr int v = 2;
+  };
+  void f() {
+    constexpr vector<A> v(1);
+    static_assert(v.f() == 2, "");
+  }
+} // namespace test6_4
 
 namespace test7 {
   extern "C" {

diff  --git a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp 
b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
index 9cc53237461f3..6c41853cf3b4f 100644
--- a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
+++ b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
@@ -836,11 +836,11 @@ auto TplClass<int>::buggy() -> void {}
 
 }
 
-namespace PackIndexExpr {
+namespace PackIndexExpr1 {
 template <int... T>
 concept C = true;
 
-template <typename...> struct TplClass { // #TplClassDef
+template <typename...> struct TplClass { // #PackIndexExpr1-TplClassDef
   template <int... Ts>
   requires C<Ts...[0]>
   static auto buggy() -> void;
@@ -852,9 +852,84 @@ requires C<Ts...[0]>
 auto TplClass<int>::buggy() -> void {}
 // FIXME: These shouldn't diagnose, but are a result of a revert: #193558
 // expected-error@-2{{does not match any declaration in}}
-// expected-note@#TplClassDef{{TplClass defined here}}
-//
-}
+// expected-note@#PackIndexExpr1-TplClassDef{{TplClass defined here}}
+} // namespace PackIndexExpr1
+
+namespace PackIndexExpr2 {
+  template <int... T> concept C = true;
+
+  namespace t1 {
+    template <int...> struct TplClass { // expected-note {{defined here}}
+      template <int... Ts, int... Us>
+      requires C<Ts...[0]>
+      static auto buggy() -> void;
+    };
+
+    template <>
+    template <int... Ts, int... Us>
+    requires C<Us...[0]>
+    auto TplClass<0>::buggy() -> void {}
+    // expected-error@-1 {{out-of-line definition of 'buggy' does not match 
any declaration}}
+  } // namespace t1
+  namespace t2 {
+    template <int...> struct TplClass { // expected-note {{defined here}}
+      template <int... Ts>
+      requires C<Ts...[0]>
+      static auto buggy() -> void;
+    };
+
+    template <>
+    template <int... Ts>
+    requires C<Ts...[1]>
+    auto TplClass<0>::buggy() -> void {}
+    // expected-error@-1 {{out-of-line definition of 'buggy' does not match 
any declaration}}
+  } // namespace t2
+  namespace t3 {
+    template <int... Us> struct TplClass { // expected-note {{defined here}}
+      template <int... Ts>
+      requires C<Us...[0]>
+      static auto buggy() -> void;
+    };
+
+    template <>
+    template <int... Ts>
+    requires C<Ts...[0]>
+    auto TplClass<0>::buggy() -> void {}
+    // expected-error@-1 {{out-of-line definition of 'buggy' does not match 
any declaration}}
+  } // namespace t3
+} // namespace PackIndexExpr2
+
+namespace FuncTemplateInClass {
+  template <int T> concept C = true;
+
+  namespace t1 {
+    template <int> struct TplClass { // expected-note {{defined here}}
+      template <int Ts>
+      requires C<Ts>
+      static auto buggy() -> void;
+    };
+
+    // FIXME: This should be accepted.
+    template <>
+    template <int Ts>
+    requires C<Ts>
+    auto TplClass<0>::buggy() -> void {}
+    // expected-error@-1 {{out-of-line definition of 'buggy' does not match 
any declaration}}
+  } //namespace t1
+  namespace t2 {
+    template <int> struct TplClass { // expected-note {{defined here}}
+      template <int Ts, int Us>
+      requires C<Ts>
+      static auto buggy() -> void;
+    };
+
+    template <>
+    template <int Ts, int Us>
+    requires C<Us>
+    auto TplClass<0>::buggy() -> void {}
+    // expected-error@-1 {{out-of-line definition of 'buggy' does not match 
any declaration}}
+  } //namespace t2
+} // namespace FuncTemplateInClass
 
 namespace GH139476 {
 
@@ -905,3 +980,13 @@ namespace NoDiagnosticsInNormalization {
   template<class>
   void S<int>::f() requires (sizeof(int) > 1) {}
 } // namespace NoDiagnosticsInNormalization
+
+namespace GH193558 {
+  template<class T> class A;
+  template<class T> struct A<T*> {
+    template<class> requires (T()) void f();
+  };
+  template<class T> template<class>
+    requires (T())
+    void A<T*>::f() {}
+} // namespace GH193558

diff  --git a/clang/test/SemaTemplate/friend.cpp 
b/clang/test/SemaTemplate/friend.cpp
index 9a1ed46812ca9..aef2faced6a96 100644
--- a/clang/test/SemaTemplate/friend.cpp
+++ b/clang/test/SemaTemplate/friend.cpp
@@ -1,7 +1,7 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
 template<typename T> struct A {
   struct B { };
-  
+
   friend struct B;
 };
 
@@ -19,7 +19,7 @@ namespace PR6770 {
   }
   using namespace N;
 
-  namespace M { 
+  namespace M {
     float f1(float);
   }
   using M::f1;
@@ -166,3 +166,17 @@ void foobar() {
   A::Bar<int> b;
 }
 }
+
+namespace InstQualifier1 {
+  template <class> struct A {
+    template <class T> void f(T);
+  };
+  void g() {
+    A<int>().f(0);
+  }
+  template <class T> template <class U> void A<T>::f(U) {
+    struct B {
+      B() {}
+    };
+  }
+} // namespace InstQualifier1


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

Reply via email to