https://github.com/diohabara updated 
https://github.com/llvm/llvm-project/pull/187896

From 3349dabfc52cd6f440c3bc64ed5e453476d4dd47 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=8D=8Ddiohabara=E5=8D=8D?=
 <[email protected]>
Date: Sat, 21 Mar 2026 18:52:57 +0900
Subject: [PATCH 1/7] [clang][diagnostics] suggest extern template syntax for
 -Wundefined-var-template and -Wundefined-func-template

---
 .../clang/Basic/DiagnosticSemaKinds.td        |  2 +
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  | 68 ++++++++++++++++++-
 ...antiation.diagnose_on_undefined_entity.cpp |  4 ++
 clang/test/SemaCXX/cxx1z-ast-print.cpp        |  4 +-
 .../instantiate-pure-virtual-function.cpp     |  6 +-
 .../test/SemaTemplate/undefined-template.cpp  | 13 ++++
 6 files changed, 93 insertions(+), 4 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index d4d09a8ecef36..d8647f6d426c9 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5954,6 +5954,8 @@ def note_unreachable_template_decl
 def note_inst_declaration_hint : Note<"add an explicit instantiation "
   "declaration to suppress this warning if %q0 is explicitly instantiated in "
   "another translation unit">;
+def note_inst_declaration_example : Note<
+  "e.g., '%0'">;
 def note_evaluating_exception_spec_here : Note<
   "in evaluation of exception specification for %q0 needed here">;
 
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp 
b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index cc24e03e77c07..f221b180e2bdd 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -5636,9 +5636,58 @@ void Sema::InstantiateFunctionDefinition(SourceLocation 
PointOfInstantiation,
                diag::note_unreachable_template_decl);
         } else {
           Diag(PatternDecl->getLocation(), diag::note_forward_template_decl);
-          if (getLangOpts().CPlusPlus11)
+          if (getLangOpts().CPlusPlus11) {
             Diag(PointOfInstantiation, diag::note_inst_declaration_hint)
                 << Function;
+            // Suggest the exact extern template declaration syntax.
+            // Note: for functions with complex declarator return types
+            // (e.g., function pointers), the suggestion may not be
+            // perfectly formatted, but these cases are rare in practice.
+            std::string Suggestion;
+            {
+              llvm::raw_string_ostream OS(Suggestion);
+              OS << "extern template ";
+              // Constructors, destructors, and conversion operators have no
+              // separate return type in the declaration syntax.
+              if (!isa<CXXConstructorDecl>(Function) &&
+                  !isa<CXXDestructorDecl>(Function) &&
+                  !isa<CXXConversionDecl>(Function)) {
+                Function->getReturnType().print(OS, getPrintingPolicy());
+                OS << " ";
+              }
+              Function->getNameForDiagnostic(OS, getPrintingPolicy(),
+                                              /*Qualified=*/true);
+              OS << "(";
+              for (unsigned I = 0, N = Function->getNumParams(); I != N; ++I) {
+                if (I > 0)
+                  OS << ", ";
+                Function->getParamDecl(I)->getType().print(
+                    OS, getPrintingPolicy());
+              }
+              if (Function->isVariadic()) {
+                if (Function->getNumParams() > 0)
+                  OS << ", ";
+                OS << "...";
+              }
+              OS << ")";
+              if (const auto *MD = dyn_cast<CXXMethodDecl>(Function)) {
+                if (MD->getMethodQualifiers().hasConst())
+                  OS << " const";
+                if (MD->getMethodQualifiers().hasVolatile())
+                  OS << " volatile";
+                if (MD->getRefQualifier() == RQ_LValue)
+                  OS << " &";
+                else if (MD->getRefQualifier() == RQ_RValue)
+                  OS << " &&";
+              }
+              if (auto EST = Function->getExceptionSpecType();
+                  EST == EST_BasicNoexcept)
+                OS << " noexcept";
+              OS << ";";
+            }
+            Diag(PointOfInstantiation, diag::note_inst_declaration_example)
+                << Suggestion;
+          }
         }
       }
     }
@@ -6379,8 +6428,23 @@ void Sema::InstantiateVariableDefinition(SourceLocation 
PointOfInstantiation,
         Diag(PointOfInstantiation, diag::warn_var_template_missing)
           << Var;
         Diag(PatternDecl->getLocation(), diag::note_forward_template_decl);
-        if (getLangOpts().CPlusPlus11)
+        if (getLangOpts().CPlusPlus11) {
           Diag(PointOfInstantiation, diag::note_inst_declaration_hint) << Var;
+          // Suggest the exact extern template declaration syntax.
+          std::string Suggestion;
+          {
+            llvm::raw_string_ostream OS(Suggestion);
+            OS << "extern template ";
+            std::string QualName;
+            llvm::raw_string_ostream NameOS(QualName);
+            Var->getNameForDiagnostic(NameOS, getPrintingPolicy(),
+                                      /*Qualified=*/true);
+            Var->getType().print(OS, getPrintingPolicy(), QualName);
+            OS << ";";
+          }
+          Diag(PointOfInstantiation, diag::note_inst_declaration_example)
+              << Suggestion;
+        }
       }
       return;
     }
diff --git 
a/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.diagnose_on_undefined_entity.cpp
 
b/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.diagnose_on_undefined_entity.cpp
index 24e24221939fa..b79e5983fe6be 100644
--- 
a/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.diagnose_on_undefined_entity.cpp
+++ 
b/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.diagnose_on_undefined_entity.cpp
@@ -24,13 +24,17 @@ void use() {
 
   foo.non_static_member_function(); // expected-warning{{instantiation of 
function 'Foo<int>::non_static_member_function' required here, but no 
definition is available}}
   // expected-note@-1 {{add an explicit instantiation}}
+  // expected-note@-2 {{e.g., 'extern template}}
 
   Foo<int>::static_member_function(); // expected-warning{{instantiation of 
function 'Foo<int>::static_member_function' required here, but no definition is 
available}}
   // expected-note@-1 {{add an explicit instantiation}}
+  // expected-note@-2 {{e.g., 'extern template}}
 
   (void)Foo<int>::static_data_member; // expected-warning{{instantiation of 
variable 'Foo<int>::static_data_member' required here, but no definition is 
available}}
   // expected-note@-1 {{add an explicit instantiation}}
+  // expected-note@-2 {{e.g., 'extern template}}
 
   Foo<int>::nested::static_member_function(); // 
expected-warning{{instantiation of function 
'Foo<int>::nested::static_member_function' required here, but no definition is 
available}}
   // expected-note@-1 {{add an explicit instantiation}}
+  // expected-note@-2 {{e.g., 'extern template}}
 }
diff --git a/clang/test/SemaCXX/cxx1z-ast-print.cpp 
b/clang/test/SemaCXX/cxx1z-ast-print.cpp
index a6ba149e974ef..642b7ceff935e 100644
--- a/clang/test/SemaCXX/cxx1z-ast-print.cpp
+++ b/clang/test/SemaCXX/cxx1z-ast-print.cpp
@@ -7,5 +7,7 @@ struct TypeSuffix {
 // CHECK: int k = TypeSuffix().x<0L> + TypeSuffix().y<0L>;
 int k = TypeSuffix().x<0L> + TypeSuffix().y<0L>; // expected-warning 
{{instantiation of variable 'TypeSuffix::x<0>' required here, but no definition 
is available}} \
                                                  // expected-note {{add an 
explicit instantiation declaration to suppress this warning if 
'TypeSuffix::x<0>' is explicitly instantiated in another translation unit}} \
+                                                 // expected-note {{e.g., 
'extern template}} \
                                                  // expected-warning 
{{instantiation of variable 'TypeSuffix::y<0L>' required here, but no 
definition is available}} \
-                                                 // expected-note {{add an 
explicit instantiation declaration to suppress this warning if 
'TypeSuffix::y<0L>' is explicitly instantiated in another translation unit}}
+                                                 // expected-note {{add an 
explicit instantiation declaration to suppress this warning if 
'TypeSuffix::y<0L>' is explicitly instantiated in another translation unit}} \
+                                                 // expected-note {{e.g., 
'extern template}}
diff --git a/clang/test/SemaTemplate/instantiate-pure-virtual-function.cpp 
b/clang/test/SemaTemplate/instantiate-pure-virtual-function.cpp
index caec42b6b77f9..548f7662b0af5 100644
--- a/clang/test/SemaTemplate/instantiate-pure-virtual-function.cpp
+++ b/clang/test/SemaTemplate/instantiate-pure-virtual-function.cpp
@@ -23,6 +23,7 @@ namespace call_pure_virtual_function_from_virtual {
   public:
     const void foo(const T &) { B::bar(1); } // expected-warning 
{{instantiation of function 
'call_pure_virtual_function_from_virtual::B<int>::bar' required here, but no 
definition is available}}
     // expected-note@-1 {{add an explicit instantiation declaration to 
suppress this warning if 'call_pure_virtual_function_from_virtual::B<int>::bar' 
is explicitly instantiated in another translation unit}}
+    // expected-note@-2 {{e.g., 'extern template}}
     virtual const void bar(unsigned int) = 0; // expected-note {{forward 
declaration of template entity is here}}
   };
 
@@ -54,7 +55,10 @@ namespace non_pure_virtual_function {
 // expected-note@-3 {{add an explicit instantiation declaration to suppress 
this warning if 'non_pure_virtual_function::B<int>::bar' is explicitly 
instantiated in another translation unit}}
 // expected-note@-4 {{add an explicit instantiation declaration to suppress 
this warning if 'non_pure_virtual_function::B<int>::bar' is explicitly 
instantiated in another translation unit}}
 // expected-note@-5 {{add an explicit instantiation declaration to suppress 
this warning if 'non_pure_virtual_function::B<int>::bar' is explicitly 
instantiated in another translation unit}}
-// expected-note@-6 {{used here}}
+// expected-note@-6 {{e.g., 'extern template}}
+// expected-note@-7 {{e.g., 'extern template}}
+// expected-note@-8 {{e.g., 'extern template}}
+// expected-note@-9 {{used here}}
 
   public:
     constexpr void bar(unsigned int) override { }
diff --git a/clang/test/SemaTemplate/undefined-template.cpp 
b/clang/test/SemaTemplate/undefined-template.cpp
index 52530e2e3909a..c26ab6c8ff03a 100644
--- a/clang/test/SemaTemplate/undefined-template.cpp
+++ b/clang/test/SemaTemplate/undefined-template.cpp
@@ -37,16 +37,19 @@ char func_01() {
 char func_02() {
   return C1<int>::s_var_1; // expected-warning{{instantiation of variable 
'C1<int>::s_var_1' required here, but no definition is available}}
                            // expected-note@-1{{add an explicit instantiation 
declaration to suppress this warning if 'C1<int>::s_var_1' is explicitly 
instantiated in another translation unit}}
+                           // expected-note@-2{{e.g., 'extern template char 
C1<int>::s_var_1;'}}
 }
 
 char func_03() {
   return C1<char>::s_var_2; // expected-warning{{instantiation of variable 
'C1<char>::s_var_2' required here, but no definition is available}}
                             // expected-note@-1{{add an explicit instantiation 
declaration to suppress this warning if 'C1<char>::s_var_2' is explicitly 
instantiated in another translation unit}}
+                            // expected-note@-2{{e.g., 'extern template char 
C1<char>::s_var_2;'}}
 }
 
 void func_04() {
   C1<int>::s_func_1(); // expected-warning{{instantiation of function 
'C1<int>::s_func_1' required here, but no definition is available}}
                        // expected-note@-1{{add an explicit instantiation 
declaration to suppress this warning if 'C1<int>::s_func_1' is explicitly 
instantiated in another translation unit}}
+                       // expected-note@-2{{e.g., 'extern template void 
C1<int>::s_func_1();'}}
 }
 
 void func_05() {
@@ -56,11 +59,13 @@ void func_05() {
 void func_06() {
   C1<char>::s_func_2(); // expected-warning{{instantiation of function 
'C1<char>::s_func_2' required here, but no definition is available}}
                         // expected-note@-1{{add an explicit instantiation 
declaration to suppress this warning if 'C1<char>::s_func_2' is explicitly 
instantiated in another translation unit}}
+                        // expected-note@-2{{e.g., 'extern template void 
C1<char>::s_func_2();'}}
 }
 
 void func_07(C1<int> *x) {
   x->meth_1();  // expected-warning{{instantiation of function 
'C1<int>::meth_1' required here, but no definition is available}}
                 // expected-note@-1{{add an explicit instantiation declaration 
to suppress this warning if 'C1<int>::meth_1' is explicitly instantiated in 
another translation unit}}
+                // expected-note@-2{{e.g., 'extern template void 
C1<int>::meth_1();'}}
 }
 
 void func_08(C1<int> *x) {
@@ -70,6 +75,7 @@ void func_08(C1<int> *x) {
 void func_09(C1<char> *x) {
   x->meth_1();  // expected-warning{{instantiation of function 
'C1<char>::meth_1' required here, but no definition is available}}
                 // expected-note@-1{{add an explicit instantiation declaration 
to suppress this warning if 'C1<char>::meth_1' is explicitly instantiated in 
another translation unit}}
+                // expected-note@-2{{e.g., 'extern template void 
C1<char>::meth_1();'}}
 }
 
 char func_10() {
@@ -79,6 +85,7 @@ char func_10() {
 char func_11() {
   return C1<int>::s_tvar_2<long>; // expected-warning{{instantiation of 
variable 'C1<int>::s_tvar_2<long>' required here, but no definition is 
available}}
                                   // expected-note@-1{{add an explicit 
instantiation declaration to suppress this warning if 'C1<int>::s_tvar_2<long>' 
is explicitly instantiated in another translation unit}}
+                                  // expected-note@-2{{e.g., 'extern template 
char C1<int>::s_tvar_2<long>;'}}
 }
 
 void func_12() {
@@ -88,6 +95,7 @@ void func_12() {
 void func_13() {
   C1<int>::s_tfunc_2<long>(); // expected-warning{{instantiation of function 
'C1<int>::s_tfunc_2<long>' required here, but no definition is available}}
                               // expected-note@-1{{add an explicit 
instantiation declaration to suppress this warning if 
'C1<int>::s_tfunc_2<long>' is explicitly instantiated in another translation 
unit}}
+                              // expected-note@-2{{e.g., 'extern template void 
C1<int>::s_tfunc_2<long>();'}}
 }
 
 char func_14() {
@@ -97,6 +105,7 @@ char func_14() {
 char func_15() {
   return C1<int>::C2<char>::s_var_2;  //expected-warning {{instantiation of 
variable 'C1<int>::C2<char>::s_var_2' required here, but no definition is 
available}}
                                       // expected-note@-1{{add an explicit 
instantiation declaration to suppress this warning if 
'C1<int>::C2<char>::s_var_2' is explicitly instantiated in another translation 
unit}}
+                                      // expected-note@-2{{e.g., 'extern 
template char C1<int>::C2<char>::s_var_2;'}}
 }
 
 void func_16() {
@@ -106,6 +115,7 @@ void func_16() {
 void func_17() {
   C1<int>::C2<char>::s_func_2(); // expected-warning{{instantiation of 
function 'C1<int>::C2<char>::s_func_2' required here, but no definition is 
available}}
                         // expected-note@-1{{add an explicit instantiation 
declaration to suppress this warning if 'C1<int>::C2<char>::s_func_2' is 
explicitly instantiated in another translation unit}}
+                        // expected-note@-2{{e.g., 'extern template void 
C1<int>::C2<char>::s_func_2();'}}
 }
 
 void func_18(C1<int>::C2<long> *x) {
@@ -115,6 +125,7 @@ void func_18(C1<int>::C2<long> *x) {
 void func_19(C1<int>::C2<char> *x) {
   x->meth_2();   // expected-warning{{instantiation of function 
'C1<int>::C2<char>::meth_2' required here, but no definition is available}}
                         // expected-note@-1{{add an explicit instantiation 
declaration to suppress this warning if 'C1<int>::C2<char>::meth_2' is 
explicitly instantiated in another translation unit}}
+                        // expected-note@-2{{e.g., 'extern template void 
C1<int>::C2<char>::meth_2();'}}
 }
 
 char func_20() {
@@ -124,6 +135,7 @@ char func_20() {
 char func_21() {
   return C1<int>::C2<long>::s_tvar_2<long>; // expected-warning{{instantiation 
of variable 'C1<int>::C2<long>::s_tvar_2<long>' required here, but no 
definition is available}}
                                   // expected-note@-1{{add an explicit 
instantiation declaration to suppress this warning if 
'C1<int>::C2<long>::s_tvar_2<long>' is explicitly instantiated in another 
translation unit}}
+                                  // expected-note@-2{{e.g., 'extern template 
char C1<int>::C2<long>::s_tvar_2<long>;'}}
 }
 
 void func_22(C1<int>::C2<long> *x) {
@@ -133,6 +145,7 @@ void func_22(C1<int>::C2<long> *x) {
 void func_23(C1<int>::C2<long> *x) {
   x->tmeth_2<int>();    // expected-warning{{instantiation of function 
'C1<int>::C2<long>::tmeth_2<int>' required here, but no definition is 
available}}
                         // expected-note@-1{{add an explicit instantiation 
declaration to suppress this warning if 'C1<int>::C2<long>::tmeth_2<int>' is 
explicitly instantiated in another translation unit}}
+                        // expected-note@-2{{e.g., 'extern template void 
C1<int>::C2<long>::tmeth_2<int>();'}}
 }
 
 namespace test_24 {

From 7465dfc4dbbdb05cf463d7f26a65825bb4941718 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=8D=8Ddiohabara=E5=8D=8D?=
 <[email protected]>
Date: Sun, 22 Mar 2026 11:13:34 +0900
Subject: [PATCH 2/7] chore: remove func warning suggestion

---
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  | 51 +------------------
 ...antiation.diagnose_on_undefined_entity.cpp |  3 --
 .../instantiate-pure-virtual-function.cpp     |  6 +--
 .../test/SemaTemplate/undefined-template.cpp  |  8 ---
 4 files changed, 2 insertions(+), 66 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp 
b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index f221b180e2bdd..5590433d05818 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -5636,58 +5636,9 @@ void Sema::InstantiateFunctionDefinition(SourceLocation 
PointOfInstantiation,
                diag::note_unreachable_template_decl);
         } else {
           Diag(PatternDecl->getLocation(), diag::note_forward_template_decl);
-          if (getLangOpts().CPlusPlus11) {
+          if (getLangOpts().CPlusPlus11)
             Diag(PointOfInstantiation, diag::note_inst_declaration_hint)
                 << Function;
-            // Suggest the exact extern template declaration syntax.
-            // Note: for functions with complex declarator return types
-            // (e.g., function pointers), the suggestion may not be
-            // perfectly formatted, but these cases are rare in practice.
-            std::string Suggestion;
-            {
-              llvm::raw_string_ostream OS(Suggestion);
-              OS << "extern template ";
-              // Constructors, destructors, and conversion operators have no
-              // separate return type in the declaration syntax.
-              if (!isa<CXXConstructorDecl>(Function) &&
-                  !isa<CXXDestructorDecl>(Function) &&
-                  !isa<CXXConversionDecl>(Function)) {
-                Function->getReturnType().print(OS, getPrintingPolicy());
-                OS << " ";
-              }
-              Function->getNameForDiagnostic(OS, getPrintingPolicy(),
-                                              /*Qualified=*/true);
-              OS << "(";
-              for (unsigned I = 0, N = Function->getNumParams(); I != N; ++I) {
-                if (I > 0)
-                  OS << ", ";
-                Function->getParamDecl(I)->getType().print(
-                    OS, getPrintingPolicy());
-              }
-              if (Function->isVariadic()) {
-                if (Function->getNumParams() > 0)
-                  OS << ", ";
-                OS << "...";
-              }
-              OS << ")";
-              if (const auto *MD = dyn_cast<CXXMethodDecl>(Function)) {
-                if (MD->getMethodQualifiers().hasConst())
-                  OS << " const";
-                if (MD->getMethodQualifiers().hasVolatile())
-                  OS << " volatile";
-                if (MD->getRefQualifier() == RQ_LValue)
-                  OS << " &";
-                else if (MD->getRefQualifier() == RQ_RValue)
-                  OS << " &&";
-              }
-              if (auto EST = Function->getExceptionSpecType();
-                  EST == EST_BasicNoexcept)
-                OS << " noexcept";
-              OS << ";";
-            }
-            Diag(PointOfInstantiation, diag::note_inst_declaration_example)
-                << Suggestion;
-          }
         }
       }
     }
diff --git 
a/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.diagnose_on_undefined_entity.cpp
 
b/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.diagnose_on_undefined_entity.cpp
index b79e5983fe6be..24f6852171f44 100644
--- 
a/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.diagnose_on_undefined_entity.cpp
+++ 
b/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.diagnose_on_undefined_entity.cpp
@@ -24,11 +24,9 @@ void use() {
 
   foo.non_static_member_function(); // expected-warning{{instantiation of 
function 'Foo<int>::non_static_member_function' required here, but no 
definition is available}}
   // expected-note@-1 {{add an explicit instantiation}}
-  // expected-note@-2 {{e.g., 'extern template}}
 
   Foo<int>::static_member_function(); // expected-warning{{instantiation of 
function 'Foo<int>::static_member_function' required here, but no definition is 
available}}
   // expected-note@-1 {{add an explicit instantiation}}
-  // expected-note@-2 {{e.g., 'extern template}}
 
   (void)Foo<int>::static_data_member; // expected-warning{{instantiation of 
variable 'Foo<int>::static_data_member' required here, but no definition is 
available}}
   // expected-note@-1 {{add an explicit instantiation}}
@@ -36,5 +34,4 @@ void use() {
 
   Foo<int>::nested::static_member_function(); // 
expected-warning{{instantiation of function 
'Foo<int>::nested::static_member_function' required here, but no definition is 
available}}
   // expected-note@-1 {{add an explicit instantiation}}
-  // expected-note@-2 {{e.g., 'extern template}}
 }
diff --git a/clang/test/SemaTemplate/instantiate-pure-virtual-function.cpp 
b/clang/test/SemaTemplate/instantiate-pure-virtual-function.cpp
index 548f7662b0af5..caec42b6b77f9 100644
--- a/clang/test/SemaTemplate/instantiate-pure-virtual-function.cpp
+++ b/clang/test/SemaTemplate/instantiate-pure-virtual-function.cpp
@@ -23,7 +23,6 @@ namespace call_pure_virtual_function_from_virtual {
   public:
     const void foo(const T &) { B::bar(1); } // expected-warning 
{{instantiation of function 
'call_pure_virtual_function_from_virtual::B<int>::bar' required here, but no 
definition is available}}
     // expected-note@-1 {{add an explicit instantiation declaration to 
suppress this warning if 'call_pure_virtual_function_from_virtual::B<int>::bar' 
is explicitly instantiated in another translation unit}}
-    // expected-note@-2 {{e.g., 'extern template}}
     virtual const void bar(unsigned int) = 0; // expected-note {{forward 
declaration of template entity is here}}
   };
 
@@ -55,10 +54,7 @@ namespace non_pure_virtual_function {
 // expected-note@-3 {{add an explicit instantiation declaration to suppress 
this warning if 'non_pure_virtual_function::B<int>::bar' is explicitly 
instantiated in another translation unit}}
 // expected-note@-4 {{add an explicit instantiation declaration to suppress 
this warning if 'non_pure_virtual_function::B<int>::bar' is explicitly 
instantiated in another translation unit}}
 // expected-note@-5 {{add an explicit instantiation declaration to suppress 
this warning if 'non_pure_virtual_function::B<int>::bar' is explicitly 
instantiated in another translation unit}}
-// expected-note@-6 {{e.g., 'extern template}}
-// expected-note@-7 {{e.g., 'extern template}}
-// expected-note@-8 {{e.g., 'extern template}}
-// expected-note@-9 {{used here}}
+// expected-note@-6 {{used here}}
 
   public:
     constexpr void bar(unsigned int) override { }
diff --git a/clang/test/SemaTemplate/undefined-template.cpp 
b/clang/test/SemaTemplate/undefined-template.cpp
index c26ab6c8ff03a..f1331c3437b93 100644
--- a/clang/test/SemaTemplate/undefined-template.cpp
+++ b/clang/test/SemaTemplate/undefined-template.cpp
@@ -49,7 +49,6 @@ char func_03() {
 void func_04() {
   C1<int>::s_func_1(); // expected-warning{{instantiation of function 
'C1<int>::s_func_1' required here, but no definition is available}}
                        // expected-note@-1{{add an explicit instantiation 
declaration to suppress this warning if 'C1<int>::s_func_1' is explicitly 
instantiated in another translation unit}}
-                       // expected-note@-2{{e.g., 'extern template void 
C1<int>::s_func_1();'}}
 }
 
 void func_05() {
@@ -59,13 +58,11 @@ void func_05() {
 void func_06() {
   C1<char>::s_func_2(); // expected-warning{{instantiation of function 
'C1<char>::s_func_2' required here, but no definition is available}}
                         // expected-note@-1{{add an explicit instantiation 
declaration to suppress this warning if 'C1<char>::s_func_2' is explicitly 
instantiated in another translation unit}}
-                        // expected-note@-2{{e.g., 'extern template void 
C1<char>::s_func_2();'}}
 }
 
 void func_07(C1<int> *x) {
   x->meth_1();  // expected-warning{{instantiation of function 
'C1<int>::meth_1' required here, but no definition is available}}
                 // expected-note@-1{{add an explicit instantiation declaration 
to suppress this warning if 'C1<int>::meth_1' is explicitly instantiated in 
another translation unit}}
-                // expected-note@-2{{e.g., 'extern template void 
C1<int>::meth_1();'}}
 }
 
 void func_08(C1<int> *x) {
@@ -75,7 +72,6 @@ void func_08(C1<int> *x) {
 void func_09(C1<char> *x) {
   x->meth_1();  // expected-warning{{instantiation of function 
'C1<char>::meth_1' required here, but no definition is available}}
                 // expected-note@-1{{add an explicit instantiation declaration 
to suppress this warning if 'C1<char>::meth_1' is explicitly instantiated in 
another translation unit}}
-                // expected-note@-2{{e.g., 'extern template void 
C1<char>::meth_1();'}}
 }
 
 char func_10() {
@@ -95,7 +91,6 @@ void func_12() {
 void func_13() {
   C1<int>::s_tfunc_2<long>(); // expected-warning{{instantiation of function 
'C1<int>::s_tfunc_2<long>' required here, but no definition is available}}
                               // expected-note@-1{{add an explicit 
instantiation declaration to suppress this warning if 
'C1<int>::s_tfunc_2<long>' is explicitly instantiated in another translation 
unit}}
-                              // expected-note@-2{{e.g., 'extern template void 
C1<int>::s_tfunc_2<long>();'}}
 }
 
 char func_14() {
@@ -115,7 +110,6 @@ void func_16() {
 void func_17() {
   C1<int>::C2<char>::s_func_2(); // expected-warning{{instantiation of 
function 'C1<int>::C2<char>::s_func_2' required here, but no definition is 
available}}
                         // expected-note@-1{{add an explicit instantiation 
declaration to suppress this warning if 'C1<int>::C2<char>::s_func_2' is 
explicitly instantiated in another translation unit}}
-                        // expected-note@-2{{e.g., 'extern template void 
C1<int>::C2<char>::s_func_2();'}}
 }
 
 void func_18(C1<int>::C2<long> *x) {
@@ -125,7 +119,6 @@ void func_18(C1<int>::C2<long> *x) {
 void func_19(C1<int>::C2<char> *x) {
   x->meth_2();   // expected-warning{{instantiation of function 
'C1<int>::C2<char>::meth_2' required here, but no definition is available}}
                         // expected-note@-1{{add an explicit instantiation 
declaration to suppress this warning if 'C1<int>::C2<char>::meth_2' is 
explicitly instantiated in another translation unit}}
-                        // expected-note@-2{{e.g., 'extern template void 
C1<int>::C2<char>::meth_2();'}}
 }
 
 char func_20() {
@@ -145,7 +138,6 @@ void func_22(C1<int>::C2<long> *x) {
 void func_23(C1<int>::C2<long> *x) {
   x->tmeth_2<int>();    // expected-warning{{instantiation of function 
'C1<int>::C2<long>::tmeth_2<int>' required here, but no definition is 
available}}
                         // expected-note@-1{{add an explicit instantiation 
declaration to suppress this warning if 'C1<int>::C2<long>::tmeth_2<int>' is 
explicitly instantiated in another translation unit}}
-                        // expected-note@-2{{e.g., 'extern template void 
C1<int>::C2<long>::tmeth_2<int>();'}}
 }
 
 namespace test_24 {

From cb800faade6532139b27423b921ee496afb8072b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=8D=8Ddiohabara=E5=8D=8D?=
 <[email protected]>
Date: Sun, 22 Mar 2026 12:25:07 +0900
Subject: [PATCH 3/7] chore: emit more informative warnings

---
 clang/include/clang/Basic/DiagnosticSemaKinds.td       |  4 ++--
 clang/lib/Sema/SemaTemplateInstantiateDecl.cpp         |  3 ++-
 ...icit_instantiation.diagnose_on_undefined_entity.cpp |  2 +-
 clang/test/SemaCXX/cxx1z-ast-print.cpp                 |  4 ++--
 clang/test/SemaTemplate/undefined-template.cpp         | 10 +++++-----
 5 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index d8647f6d426c9..d42cb042b3df1 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5954,8 +5954,8 @@ def note_unreachable_template_decl
 def note_inst_declaration_hint : Note<"add an explicit instantiation "
   "declaration to suppress this warning if %q0 is explicitly instantiated in "
   "another translation unit">;
-def note_inst_declaration_example : Note<
-  "e.g., '%0'">;
+def note_inst_declaration_extern_suggestion : Note<
+  "use '%0' to declare the definition is in another translation unit">;
 def note_evaluating_exception_spec_here : Note<
   "in evaluation of exception specification for %q0 needed here">;
 
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp 
b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 5590433d05818..bcefbffb12a90 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -6393,7 +6393,8 @@ void Sema::InstantiateVariableDefinition(SourceLocation 
PointOfInstantiation,
             Var->getType().print(OS, getPrintingPolicy(), QualName);
             OS << ";";
           }
-          Diag(PointOfInstantiation, diag::note_inst_declaration_example)
+          Diag(PointOfInstantiation,
+               diag::note_inst_declaration_extern_suggestion)
               << Suggestion;
         }
       }
diff --git 
a/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.diagnose_on_undefined_entity.cpp
 
b/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.diagnose_on_undefined_entity.cpp
index 24f6852171f44..885197e5157da 100644
--- 
a/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.diagnose_on_undefined_entity.cpp
+++ 
b/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.diagnose_on_undefined_entity.cpp
@@ -30,7 +30,7 @@ void use() {
 
   (void)Foo<int>::static_data_member; // expected-warning{{instantiation of 
variable 'Foo<int>::static_data_member' required here, but no definition is 
available}}
   // expected-note@-1 {{add an explicit instantiation}}
-  // expected-note@-2 {{e.g., 'extern template}}
+  // expected-note@-2 {{use 'extern template}}
 
   Foo<int>::nested::static_member_function(); // 
expected-warning{{instantiation of function 
'Foo<int>::nested::static_member_function' required here, but no definition is 
available}}
   // expected-note@-1 {{add an explicit instantiation}}
diff --git a/clang/test/SemaCXX/cxx1z-ast-print.cpp 
b/clang/test/SemaCXX/cxx1z-ast-print.cpp
index 642b7ceff935e..d1c856ff0dfa8 100644
--- a/clang/test/SemaCXX/cxx1z-ast-print.cpp
+++ b/clang/test/SemaCXX/cxx1z-ast-print.cpp
@@ -7,7 +7,7 @@ struct TypeSuffix {
 // CHECK: int k = TypeSuffix().x<0L> + TypeSuffix().y<0L>;
 int k = TypeSuffix().x<0L> + TypeSuffix().y<0L>; // expected-warning 
{{instantiation of variable 'TypeSuffix::x<0>' required here, but no definition 
is available}} \
                                                  // expected-note {{add an 
explicit instantiation declaration to suppress this warning if 
'TypeSuffix::x<0>' is explicitly instantiated in another translation unit}} \
-                                                 // expected-note {{e.g., 
'extern template}} \
+                                                 // expected-note {{use 
'extern template}} \
                                                  // expected-warning 
{{instantiation of variable 'TypeSuffix::y<0L>' required here, but no 
definition is available}} \
                                                  // expected-note {{add an 
explicit instantiation declaration to suppress this warning if 
'TypeSuffix::y<0L>' is explicitly instantiated in another translation unit}} \
-                                                 // expected-note {{e.g., 
'extern template}}
+                                                 // expected-note {{use 
'extern template}}
diff --git a/clang/test/SemaTemplate/undefined-template.cpp 
b/clang/test/SemaTemplate/undefined-template.cpp
index f1331c3437b93..12530d44dd5fb 100644
--- a/clang/test/SemaTemplate/undefined-template.cpp
+++ b/clang/test/SemaTemplate/undefined-template.cpp
@@ -37,13 +37,13 @@ char func_01() {
 char func_02() {
   return C1<int>::s_var_1; // expected-warning{{instantiation of variable 
'C1<int>::s_var_1' required here, but no definition is available}}
                            // expected-note@-1{{add an explicit instantiation 
declaration to suppress this warning if 'C1<int>::s_var_1' is explicitly 
instantiated in another translation unit}}
-                           // expected-note@-2{{e.g., 'extern template char 
C1<int>::s_var_1;'}}
+                           // expected-note@-2{{use 'extern template char 
C1<int>::s_var_1;'}}
 }
 
 char func_03() {
   return C1<char>::s_var_2; // expected-warning{{instantiation of variable 
'C1<char>::s_var_2' required here, but no definition is available}}
                             // expected-note@-1{{add an explicit instantiation 
declaration to suppress this warning if 'C1<char>::s_var_2' is explicitly 
instantiated in another translation unit}}
-                            // expected-note@-2{{e.g., 'extern template char 
C1<char>::s_var_2;'}}
+                            // expected-note@-2{{use 'extern template char 
C1<char>::s_var_2;'}}
 }
 
 void func_04() {
@@ -81,7 +81,7 @@ char func_10() {
 char func_11() {
   return C1<int>::s_tvar_2<long>; // expected-warning{{instantiation of 
variable 'C1<int>::s_tvar_2<long>' required here, but no definition is 
available}}
                                   // expected-note@-1{{add an explicit 
instantiation declaration to suppress this warning if 'C1<int>::s_tvar_2<long>' 
is explicitly instantiated in another translation unit}}
-                                  // expected-note@-2{{e.g., 'extern template 
char C1<int>::s_tvar_2<long>;'}}
+                                  // expected-note@-2{{use 'extern template 
char C1<int>::s_tvar_2<long>;'}}
 }
 
 void func_12() {
@@ -100,7 +100,7 @@ char func_14() {
 char func_15() {
   return C1<int>::C2<char>::s_var_2;  //expected-warning {{instantiation of 
variable 'C1<int>::C2<char>::s_var_2' required here, but no definition is 
available}}
                                       // expected-note@-1{{add an explicit 
instantiation declaration to suppress this warning if 
'C1<int>::C2<char>::s_var_2' is explicitly instantiated in another translation 
unit}}
-                                      // expected-note@-2{{e.g., 'extern 
template char C1<int>::C2<char>::s_var_2;'}}
+                                      // expected-note@-2{{use 'extern 
template char C1<int>::C2<char>::s_var_2;'}}
 }
 
 void func_16() {
@@ -128,7 +128,7 @@ char func_20() {
 char func_21() {
   return C1<int>::C2<long>::s_tvar_2<long>; // expected-warning{{instantiation 
of variable 'C1<int>::C2<long>::s_tvar_2<long>' required here, but no 
definition is available}}
                                   // expected-note@-1{{add an explicit 
instantiation declaration to suppress this warning if 
'C1<int>::C2<long>::s_tvar_2<long>' is explicitly instantiated in another 
translation unit}}
-                                  // expected-note@-2{{e.g., 'extern template 
char C1<int>::C2<long>::s_tvar_2<long>;'}}
+                                  // expected-note@-2{{use 'extern template 
char C1<int>::C2<long>::s_tvar_2<long>;'}}
 }
 
 void func_22(C1<int>::C2<long> *x) {

From 8392c045f5229cdf77603c168fc938969773f968 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=8D=8Ddiohabara=E5=8D=8D?=
 <[email protected]>
Date: Sun, 22 Mar 2026 13:14:21 +0900
Subject: [PATCH 4/7] feat: add explicit specialization

---
 clang/include/clang/Basic/DiagnosticSemaKinds.td  |  2 ++
 clang/lib/Sema/SemaTemplateInstantiateDecl.cpp    | 15 +++++++++++++++
 ...instantiation.diagnose_on_undefined_entity.cpp |  1 +
 clang/test/SemaCXX/cxx1z-ast-print.cpp            |  4 +++-
 clang/test/SemaTemplate/undefined-template.cpp    |  5 +++++
 5 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index d42cb042b3df1..a8d9c571eee9b 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5956,6 +5956,8 @@ def note_inst_declaration_hint : Note<"add an explicit 
instantiation "
   "another translation unit">;
 def note_inst_declaration_extern_suggestion : Note<
   "use '%0' to declare the definition is in another translation unit">;
+def note_inst_declaration_specialization_suggestion : Note<
+  "use '%0' to provide a definition for this type">;
 def note_evaluating_exception_spec_here : Note<
   "in evaluation of exception specification for %q0 needed here">;
 
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp 
b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index bcefbffb12a90..db56de0570132 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -6396,6 +6396,21 @@ void Sema::InstantiateVariableDefinition(SourceLocation 
PointOfInstantiation,
           Diag(PointOfInstantiation,
                diag::note_inst_declaration_extern_suggestion)
               << Suggestion;
+          // Suggest explicit specialization syntax.
+          std::string SpecSuggestion;
+          {
+            llvm::raw_string_ostream OS(SpecSuggestion);
+            OS << "template <> ";
+            std::string QualName;
+            llvm::raw_string_ostream NameOS(QualName);
+            Var->getNameForDiagnostic(NameOS, getPrintingPolicy(),
+                                      /*Qualified=*/true);
+            Var->getType().print(OS, getPrintingPolicy(), QualName);
+            OS << ";";
+          }
+          Diag(PointOfInstantiation,
+               diag::note_inst_declaration_specialization_suggestion)
+              << SpecSuggestion;
         }
       }
       return;
diff --git 
a/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.diagnose_on_undefined_entity.cpp
 
b/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.diagnose_on_undefined_entity.cpp
index 885197e5157da..8a6103e0f2996 100644
--- 
a/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.diagnose_on_undefined_entity.cpp
+++ 
b/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.diagnose_on_undefined_entity.cpp
@@ -31,6 +31,7 @@ void use() {
   (void)Foo<int>::static_data_member; // expected-warning{{instantiation of 
variable 'Foo<int>::static_data_member' required here, but no definition is 
available}}
   // expected-note@-1 {{add an explicit instantiation}}
   // expected-note@-2 {{use 'extern template}}
+  // expected-note@-3 {{use 'template <>}}
 
   Foo<int>::nested::static_member_function(); // 
expected-warning{{instantiation of function 
'Foo<int>::nested::static_member_function' required here, but no definition is 
available}}
   // expected-note@-1 {{add an explicit instantiation}}
diff --git a/clang/test/SemaCXX/cxx1z-ast-print.cpp 
b/clang/test/SemaCXX/cxx1z-ast-print.cpp
index d1c856ff0dfa8..6326cf138d965 100644
--- a/clang/test/SemaCXX/cxx1z-ast-print.cpp
+++ b/clang/test/SemaCXX/cxx1z-ast-print.cpp
@@ -8,6 +8,8 @@ struct TypeSuffix {
 int k = TypeSuffix().x<0L> + TypeSuffix().y<0L>; // expected-warning 
{{instantiation of variable 'TypeSuffix::x<0>' required here, but no definition 
is available}} \
                                                  // expected-note {{add an 
explicit instantiation declaration to suppress this warning if 
'TypeSuffix::x<0>' is explicitly instantiated in another translation unit}} \
                                                  // expected-note {{use 
'extern template}} \
+                                                 // expected-note {{use 
'template <>}} \
                                                  // expected-warning 
{{instantiation of variable 'TypeSuffix::y<0L>' required here, but no 
definition is available}} \
                                                  // expected-note {{add an 
explicit instantiation declaration to suppress this warning if 
'TypeSuffix::y<0L>' is explicitly instantiated in another translation unit}} \
-                                                 // expected-note {{use 
'extern template}}
+                                                 // expected-note {{use 
'extern template}} \
+                                                 // expected-note {{use 
'template <>}}
diff --git a/clang/test/SemaTemplate/undefined-template.cpp 
b/clang/test/SemaTemplate/undefined-template.cpp
index 12530d44dd5fb..bf98b2f577331 100644
--- a/clang/test/SemaTemplate/undefined-template.cpp
+++ b/clang/test/SemaTemplate/undefined-template.cpp
@@ -38,12 +38,14 @@ char func_02() {
   return C1<int>::s_var_1; // expected-warning{{instantiation of variable 
'C1<int>::s_var_1' required here, but no definition is available}}
                            // expected-note@-1{{add an explicit instantiation 
declaration to suppress this warning if 'C1<int>::s_var_1' is explicitly 
instantiated in another translation unit}}
                            // expected-note@-2{{use 'extern template char 
C1<int>::s_var_1;'}}
+                           // expected-note@-3{{use 'template <> char 
C1<int>::s_var_1;'}}
 }
 
 char func_03() {
   return C1<char>::s_var_2; // expected-warning{{instantiation of variable 
'C1<char>::s_var_2' required here, but no definition is available}}
                             // expected-note@-1{{add an explicit instantiation 
declaration to suppress this warning if 'C1<char>::s_var_2' is explicitly 
instantiated in another translation unit}}
                             // expected-note@-2{{use 'extern template char 
C1<char>::s_var_2;'}}
+                            // expected-note@-3{{use 'template <> char 
C1<char>::s_var_2;'}}
 }
 
 void func_04() {
@@ -82,6 +84,7 @@ char func_11() {
   return C1<int>::s_tvar_2<long>; // expected-warning{{instantiation of 
variable 'C1<int>::s_tvar_2<long>' required here, but no definition is 
available}}
                                   // expected-note@-1{{add an explicit 
instantiation declaration to suppress this warning if 'C1<int>::s_tvar_2<long>' 
is explicitly instantiated in another translation unit}}
                                   // expected-note@-2{{use 'extern template 
char C1<int>::s_tvar_2<long>;'}}
+                                  // expected-note@-3{{use 'template <> char 
C1<int>::s_tvar_2<long>;'}}
 }
 
 void func_12() {
@@ -101,6 +104,7 @@ char func_15() {
   return C1<int>::C2<char>::s_var_2;  //expected-warning {{instantiation of 
variable 'C1<int>::C2<char>::s_var_2' required here, but no definition is 
available}}
                                       // expected-note@-1{{add an explicit 
instantiation declaration to suppress this warning if 
'C1<int>::C2<char>::s_var_2' is explicitly instantiated in another translation 
unit}}
                                       // expected-note@-2{{use 'extern 
template char C1<int>::C2<char>::s_var_2;'}}
+                                      // expected-note@-3{{use 'template <> 
char C1<int>::C2<char>::s_var_2;'}}
 }
 
 void func_16() {
@@ -129,6 +133,7 @@ char func_21() {
   return C1<int>::C2<long>::s_tvar_2<long>; // expected-warning{{instantiation 
of variable 'C1<int>::C2<long>::s_tvar_2<long>' required here, but no 
definition is available}}
                                   // expected-note@-1{{add an explicit 
instantiation declaration to suppress this warning if 
'C1<int>::C2<long>::s_tvar_2<long>' is explicitly instantiated in another 
translation unit}}
                                   // expected-note@-2{{use 'extern template 
char C1<int>::C2<long>::s_tvar_2<long>;'}}
+                                  // expected-note@-3{{use 'template <> char 
C1<int>::C2<long>::s_tvar_2<long>;'}}
 }
 
 void func_22(C1<int>::C2<long> *x) {

From 73eb46c322f6d0ae9bafac992a9d114a5071236e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=8D=8Ddiohabara=E5=8D=8D?=
 <[email protected]>
Date: Sun, 22 Mar 2026 14:30:57 +0900
Subject: [PATCH 5/7] feat: support generic definition

---
 .../clang/Basic/DiagnosticSemaKinds.td        |  6 ++-
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  | 54 ++++++++++++++++++-
 ...antiation.diagnose_on_undefined_entity.cpp |  6 ++-
 clang/test/SemaCXX/cxx1z-ast-print.cpp        |  6 ++-
 .../test/SemaTemplate/undefined-template.cpp  | 27 ++++++----
 5 files changed, 83 insertions(+), 16 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index a8d9c571eee9b..252de54acba0e 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5954,10 +5954,14 @@ def note_unreachable_template_decl
 def note_inst_declaration_hint : Note<"add an explicit instantiation "
   "declaration to suppress this warning if %q0 is explicitly instantiated in "
   "another translation unit">;
+def note_inst_declaration_num_ways : Note<
+  "there %plural{1:is 1 way|:are %0 ways}0 to fix this:">;
 def note_inst_declaration_extern_suggestion : Note<
   "use '%0' to declare the definition is in another translation unit">;
 def note_inst_declaration_specialization_suggestion : Note<
-  "use '%0' to provide a definition for this type">;
+  "or use '%0' to provide a definition for this type">;
+def note_inst_declaration_definition_suggestion : Note<
+  "or use '%0' to provide a definition for all types">;
 def note_evaluating_exception_spec_here : Note<
   "in evaluation of exception specification for %q0 needed here">;
 
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp 
b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index db56de0570132..2e064645146f2 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -6381,7 +6381,32 @@ void Sema::InstantiateVariableDefinition(SourceLocation 
PointOfInstantiation,
         Diag(PatternDecl->getLocation(), diag::note_forward_template_decl);
         if (getLangOpts().CPlusPlus11) {
           Diag(PointOfInstantiation, diag::note_inst_declaration_hint) << Var;
-          // Suggest the exact extern template declaration syntax.
+
+          // Determine if we can suggest a generic out-of-class definition.
+          // FIXME: Support nested class templates (e.g.,
+          // C1<T>::C2<T1>::value) and member variable templates (e.g.,
+          // C1<T>::s_tvar_2<T1>) which require multiple template
+          // parameter lists.
+          bool CanSuggestDefinition = false;
+          const CXXRecordDecl *PatternRD = nullptr;
+          const ClassTemplateDecl *PatternCTD = nullptr;
+          if (!PatternDecl->getDescribedVarTemplate() &&
+              !isa<VarTemplateSpecializationDecl>(PatternDecl)) {
+            PatternRD = dyn_cast<CXXRecordDecl>(PatternDecl->getDeclContext());
+            if (PatternRD) {
+              PatternCTD = PatternRD->getDescribedClassTemplate();
+              if (PatternCTD &&
+                  (PatternRD->getDeclContext()->isFileContext() ||
+                   isa<NamespaceDecl>(PatternRD->getDeclContext())))
+                CanSuggestDefinition = true;
+            }
+          }
+
+          unsigned NumWays = CanSuggestDefinition ? 3 : 2;
+          Diag(PointOfInstantiation, diag::note_inst_declaration_num_ways)
+              << NumWays;
+
+          // Suggest extern template declaration syntax.
           std::string Suggestion;
           {
             llvm::raw_string_ostream OS(Suggestion);
@@ -6396,6 +6421,7 @@ void Sema::InstantiateVariableDefinition(SourceLocation 
PointOfInstantiation,
           Diag(PointOfInstantiation,
                diag::note_inst_declaration_extern_suggestion)
               << Suggestion;
+
           // Suggest explicit specialization syntax.
           std::string SpecSuggestion;
           {
@@ -6411,6 +6437,32 @@ void Sema::InstantiateVariableDefinition(SourceLocation 
PointOfInstantiation,
           Diag(PointOfInstantiation,
                diag::note_inst_declaration_specialization_suggestion)
               << SpecSuggestion;
+
+          // Suggest generic out-of-class definition syntax.
+          if (CanSuggestDefinition) {
+            std::string DefSuggestion;
+            {
+              llvm::raw_string_ostream OS(DefSuggestion);
+              // print() already appends a trailing space.
+              PatternCTD->getTemplateParameters()->print(OS, getASTContext(),
+                                                         getPrintingPolicy());
+              std::string QualName;
+              llvm::raw_string_ostream NameOS(QualName);
+              NameOS << PatternRD->getName() << "<";
+              const auto *TPL = PatternCTD->getTemplateParameters();
+              for (unsigned I = 0, N = TPL->size(); I != N; ++I) {
+                if (I > 0)
+                  NameOS << ", ";
+                NameOS << TPL->getParam(I)->getName();
+              }
+              NameOS << ">::" << PatternDecl->getName();
+              PatternDecl->getType().print(OS, getPrintingPolicy(), QualName);
+              OS << ";";
+            }
+            Diag(PointOfInstantiation,
+                 diag::note_inst_declaration_definition_suggestion)
+                << DefSuggestion;
+          }
         }
       }
       return;
diff --git 
a/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.diagnose_on_undefined_entity.cpp
 
b/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.diagnose_on_undefined_entity.cpp
index 8a6103e0f2996..269bb7b8e5cd3 100644
--- 
a/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.diagnose_on_undefined_entity.cpp
+++ 
b/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.diagnose_on_undefined_entity.cpp
@@ -30,8 +30,10 @@ void use() {
 
   (void)Foo<int>::static_data_member; // expected-warning{{instantiation of 
variable 'Foo<int>::static_data_member' required here, but no definition is 
available}}
   // expected-note@-1 {{add an explicit instantiation}}
-  // expected-note@-2 {{use 'extern template}}
-  // expected-note@-3 {{use 'template <>}}
+  // expected-note@-2 {{there are 3 ways to fix this:}}
+  // expected-note@-3 {{use 'extern template}}
+  // expected-note@-4 {{or use 'template <>}}
+  // expected-note@-5 {{or use 'template <class T>}}
 
   Foo<int>::nested::static_member_function(); // 
expected-warning{{instantiation of function 
'Foo<int>::nested::static_member_function' required here, but no definition is 
available}}
   // expected-note@-1 {{add an explicit instantiation}}
diff --git a/clang/test/SemaCXX/cxx1z-ast-print.cpp 
b/clang/test/SemaCXX/cxx1z-ast-print.cpp
index 6326cf138d965..dabe073135cfe 100644
--- a/clang/test/SemaCXX/cxx1z-ast-print.cpp
+++ b/clang/test/SemaCXX/cxx1z-ast-print.cpp
@@ -7,9 +7,11 @@ struct TypeSuffix {
 // CHECK: int k = TypeSuffix().x<0L> + TypeSuffix().y<0L>;
 int k = TypeSuffix().x<0L> + TypeSuffix().y<0L>; // expected-warning 
{{instantiation of variable 'TypeSuffix::x<0>' required here, but no definition 
is available}} \
                                                  // expected-note {{add an 
explicit instantiation declaration to suppress this warning if 
'TypeSuffix::x<0>' is explicitly instantiated in another translation unit}} \
+                                                 // expected-note {{there are 
2 ways to fix this:}} \
                                                  // expected-note {{use 
'extern template}} \
-                                                 // expected-note {{use 
'template <>}} \
+                                                 // expected-note {{or use 
'template <>}} \
                                                  // expected-warning 
{{instantiation of variable 'TypeSuffix::y<0L>' required here, but no 
definition is available}} \
                                                  // expected-note {{add an 
explicit instantiation declaration to suppress this warning if 
'TypeSuffix::y<0L>' is explicitly instantiated in another translation unit}} \
+                                                 // expected-note {{there are 
2 ways to fix this:}} \
                                                  // expected-note {{use 
'extern template}} \
-                                                 // expected-note {{use 
'template <>}}
+                                                 // expected-note {{or use 
'template <>}}
diff --git a/clang/test/SemaTemplate/undefined-template.cpp 
b/clang/test/SemaTemplate/undefined-template.cpp
index bf98b2f577331..ca6bca0413039 100644
--- a/clang/test/SemaTemplate/undefined-template.cpp
+++ b/clang/test/SemaTemplate/undefined-template.cpp
@@ -37,15 +37,19 @@ char func_01() {
 char func_02() {
   return C1<int>::s_var_1; // expected-warning{{instantiation of variable 
'C1<int>::s_var_1' required here, but no definition is available}}
                            // expected-note@-1{{add an explicit instantiation 
declaration to suppress this warning if 'C1<int>::s_var_1' is explicitly 
instantiated in another translation unit}}
-                           // expected-note@-2{{use 'extern template char 
C1<int>::s_var_1;'}}
-                           // expected-note@-3{{use 'template <> char 
C1<int>::s_var_1;'}}
+                           // expected-note@-2{{there are 3 ways to fix this:}}
+                           // expected-note@-3{{use 'extern template char 
C1<int>::s_var_1;'}}
+                           // expected-note@-4{{or use 'template <> char 
C1<int>::s_var_1;'}}
+                           // expected-note@-5{{or use 'template <class T> 
char C1<T>::s_var_1;' to provide a definition for all types}}
 }
 
 char func_03() {
   return C1<char>::s_var_2; // expected-warning{{instantiation of variable 
'C1<char>::s_var_2' required here, but no definition is available}}
                             // expected-note@-1{{add an explicit instantiation 
declaration to suppress this warning if 'C1<char>::s_var_2' is explicitly 
instantiated in another translation unit}}
-                            // expected-note@-2{{use 'extern template char 
C1<char>::s_var_2;'}}
-                            // expected-note@-3{{use 'template <> char 
C1<char>::s_var_2;'}}
+                            // expected-note@-2{{there are 3 ways to fix 
this:}}
+                            // expected-note@-3{{use 'extern template char 
C1<char>::s_var_2;'}}
+                            // expected-note@-4{{or use 'template <> char 
C1<char>::s_var_2;'}}
+                            // expected-note@-5{{or use 'template <class T> 
char C1<T>::s_var_2;' to provide a definition for all types}}
 }
 
 void func_04() {
@@ -83,8 +87,9 @@ char func_10() {
 char func_11() {
   return C1<int>::s_tvar_2<long>; // expected-warning{{instantiation of 
variable 'C1<int>::s_tvar_2<long>' required here, but no definition is 
available}}
                                   // expected-note@-1{{add an explicit 
instantiation declaration to suppress this warning if 'C1<int>::s_tvar_2<long>' 
is explicitly instantiated in another translation unit}}
-                                  // expected-note@-2{{use 'extern template 
char C1<int>::s_tvar_2<long>;'}}
-                                  // expected-note@-3{{use 'template <> char 
C1<int>::s_tvar_2<long>;'}}
+                                  // expected-note@-2{{there are 2 ways to fix 
this:}}
+                                  // expected-note@-3{{use 'extern template 
char C1<int>::s_tvar_2<long>;'}}
+                                  // expected-note@-4{{or use 'template <> 
char C1<int>::s_tvar_2<long>;'}}
 }
 
 void func_12() {
@@ -103,8 +108,9 @@ char func_14() {
 char func_15() {
   return C1<int>::C2<char>::s_var_2;  //expected-warning {{instantiation of 
variable 'C1<int>::C2<char>::s_var_2' required here, but no definition is 
available}}
                                       // expected-note@-1{{add an explicit 
instantiation declaration to suppress this warning if 
'C1<int>::C2<char>::s_var_2' is explicitly instantiated in another translation 
unit}}
-                                      // expected-note@-2{{use 'extern 
template char C1<int>::C2<char>::s_var_2;'}}
-                                      // expected-note@-3{{use 'template <> 
char C1<int>::C2<char>::s_var_2;'}}
+                                      // expected-note@-2{{there are 2 ways to 
fix this:}}
+                                      // expected-note@-3{{use 'extern 
template char C1<int>::C2<char>::s_var_2;'}}
+                                      // expected-note@-4{{or use 'template <> 
char C1<int>::C2<char>::s_var_2;'}}
 }
 
 void func_16() {
@@ -132,8 +138,9 @@ char func_20() {
 char func_21() {
   return C1<int>::C2<long>::s_tvar_2<long>; // expected-warning{{instantiation 
of variable 'C1<int>::C2<long>::s_tvar_2<long>' required here, but no 
definition is available}}
                                   // expected-note@-1{{add an explicit 
instantiation declaration to suppress this warning if 
'C1<int>::C2<long>::s_tvar_2<long>' is explicitly instantiated in another 
translation unit}}
-                                  // expected-note@-2{{use 'extern template 
char C1<int>::C2<long>::s_tvar_2<long>;'}}
-                                  // expected-note@-3{{use 'template <> char 
C1<int>::C2<long>::s_tvar_2<long>;'}}
+                                  // expected-note@-2{{there are 2 ways to fix 
this:}}
+                                  // expected-note@-3{{use 'extern template 
char C1<int>::C2<long>::s_tvar_2<long>;'}}
+                                  // expected-note@-4{{or use 'template <> 
char C1<int>::C2<long>::s_tvar_2<long>;'}}
 }
 
 void func_22(C1<int>::C2<long> *x) {

From b62e85c10fa24305789531de5f86de738a5b2575 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=8D=8Ddiohabara=E5=8D=8D?=
 <[email protected]>
Date: Sun, 22 Mar 2026 15:37:54 +0900
Subject: [PATCH 6/7] feat: support generic definition for nested/var templates

---
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  | 71 ++++++++++++-------
 .../test/SemaTemplate/undefined-template.cpp  |  9 ++-
 2 files changed, 50 insertions(+), 30 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp 
b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 2e064645146f2..7a6a18afb430b 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -6382,24 +6382,26 @@ void Sema::InstantiateVariableDefinition(SourceLocation 
PointOfInstantiation,
         if (getLangOpts().CPlusPlus11) {
           Diag(PointOfInstantiation, diag::note_inst_declaration_hint) << Var;
 
-          // Determine if we can suggest a generic out-of-class definition.
-          // FIXME: Support nested class templates (e.g.,
-          // C1<T>::C2<T1>::value) and member variable templates (e.g.,
-          // C1<T>::s_tvar_2<T1>) which require multiple template
-          // parameter lists.
+          // Determine if we can suggest a generic out-of-class definition
+          // by collecting all enclosing class template declarations.
           bool CanSuggestDefinition = false;
-          const CXXRecordDecl *PatternRD = nullptr;
-          const ClassTemplateDecl *PatternCTD = nullptr;
-          if (!PatternDecl->getDescribedVarTemplate() &&
-              !isa<VarTemplateSpecializationDecl>(PatternDecl)) {
-            PatternRD = dyn_cast<CXXRecordDecl>(PatternDecl->getDeclContext());
-            if (PatternRD) {
-              PatternCTD = PatternRD->getDescribedClassTemplate();
-              if (PatternCTD &&
-                  (PatternRD->getDeclContext()->isFileContext() ||
-                   isa<NamespaceDecl>(PatternRD->getDeclContext())))
-                CanSuggestDefinition = true;
+          SmallVector<const ClassTemplateDecl *, 4> EnclosingCTDs;
+          const VarTemplateDecl *PatternVTD =
+              PatternDecl->getDescribedVarTemplate();
+          {
+            const DeclContext *DC = PatternDecl->getDeclContext();
+            bool Valid = true;
+            while (DC && !DC->isFileContext() &&
+                   !isa<NamespaceDecl>(DC)) {
+              const auto *RD = dyn_cast<CXXRecordDecl>(DC);
+              if (!RD) { Valid = false; break; }
+              const auto *CTD = RD->getDescribedClassTemplate();
+              if (!CTD) { Valid = false; break; }
+              EnclosingCTDs.push_back(CTD);
+              DC = DC->getParent();
             }
+            if (Valid && !EnclosingCTDs.empty())
+              CanSuggestDefinition = true;
           }
 
           unsigned NumWays = CanSuggestDefinition ? 3 : 2;
@@ -6443,20 +6445,35 @@ void Sema::InstantiateVariableDefinition(SourceLocation 
PointOfInstantiation,
             std::string DefSuggestion;
             {
               llvm::raw_string_ostream OS(DefSuggestion);
-              // print() already appends a trailing space.
-              PatternCTD->getTemplateParameters()->print(OS, getASTContext(),
-                                                         getPrintingPolicy());
+              // Print class template parameter lists (outermost to
+              // innermost). Each print() appends a trailing space.
+              for (auto It = EnclosingCTDs.rbegin(),
+                        End = EnclosingCTDs.rend();
+                   It != End; ++It)
+                (*It)->getTemplateParameters()->print(
+                    OS, getASTContext(), getPrintingPolicy());
+              // Print variable template parameter list if present.
+              if (PatternVTD)
+                PatternVTD->getTemplateParameters()->print(
+                    OS, getASTContext(), getPrintingPolicy());
+              // Build qualified name: C1<T>::C2<T1>::varName
               std::string QualName;
               llvm::raw_string_ostream NameOS(QualName);
-              NameOS << PatternRD->getName() << "<";
-              const auto *TPL = PatternCTD->getTemplateParameters();
-              for (unsigned I = 0, N = TPL->size(); I != N; ++I) {
-                if (I > 0)
-                  NameOS << ", ";
-                NameOS << TPL->getParam(I)->getName();
+              for (auto It = EnclosingCTDs.rbegin(),
+                        End = EnclosingCTDs.rend();
+                   It != End; ++It) {
+                const auto *TPL = (*It)->getTemplateParameters();
+                NameOS << (*It)->getName() << "<";
+                for (unsigned I = 0, N = TPL->size(); I != N; ++I) {
+                  if (I > 0)
+                    NameOS << ", ";
+                  NameOS << TPL->getParam(I)->getName();
+                }
+                NameOS << ">::";
               }
-              NameOS << ">::" << PatternDecl->getName();
-              PatternDecl->getType().print(OS, getPrintingPolicy(), QualName);
+              NameOS << PatternDecl->getName();
+              PatternDecl->getType().print(OS, getPrintingPolicy(),
+                                           QualName);
               OS << ";";
             }
             Diag(PointOfInstantiation,
diff --git a/clang/test/SemaTemplate/undefined-template.cpp 
b/clang/test/SemaTemplate/undefined-template.cpp
index ca6bca0413039..1b19d58e14b7a 100644
--- a/clang/test/SemaTemplate/undefined-template.cpp
+++ b/clang/test/SemaTemplate/undefined-template.cpp
@@ -87,9 +87,10 @@ char func_10() {
 char func_11() {
   return C1<int>::s_tvar_2<long>; // expected-warning{{instantiation of 
variable 'C1<int>::s_tvar_2<long>' required here, but no definition is 
available}}
                                   // expected-note@-1{{add an explicit 
instantiation declaration to suppress this warning if 'C1<int>::s_tvar_2<long>' 
is explicitly instantiated in another translation unit}}
-                                  // expected-note@-2{{there are 2 ways to fix 
this:}}
+                                  // expected-note@-2{{there are 3 ways to fix 
this:}}
                                   // expected-note@-3{{use 'extern template 
char C1<int>::s_tvar_2<long>;'}}
                                   // expected-note@-4{{or use 'template <> 
char C1<int>::s_tvar_2<long>;'}}
+                                  // expected-note@-5{{or use 'template <class 
T> template <class T1> char C1<T>::s_tvar_2;' to provide a definition for all 
types}}
 }
 
 void func_12() {
@@ -108,9 +109,10 @@ char func_14() {
 char func_15() {
   return C1<int>::C2<char>::s_var_2;  //expected-warning {{instantiation of 
variable 'C1<int>::C2<char>::s_var_2' required here, but no definition is 
available}}
                                       // expected-note@-1{{add an explicit 
instantiation declaration to suppress this warning if 
'C1<int>::C2<char>::s_var_2' is explicitly instantiated in another translation 
unit}}
-                                      // expected-note@-2{{there are 2 ways to 
fix this:}}
+                                      // expected-note@-2{{there are 3 ways to 
fix this:}}
                                       // expected-note@-3{{use 'extern 
template char C1<int>::C2<char>::s_var_2;'}}
                                       // expected-note@-4{{or use 'template <> 
char C1<int>::C2<char>::s_var_2;'}}
+                                      // expected-note@-5{{or use 'template 
<class T> template <typename T1> char C1<T>::C2<T1>::s_var_2;' to provide a 
definition for all types}}
 }
 
 void func_16() {
@@ -138,9 +140,10 @@ char func_20() {
 char func_21() {
   return C1<int>::C2<long>::s_tvar_2<long>; // expected-warning{{instantiation 
of variable 'C1<int>::C2<long>::s_tvar_2<long>' required here, but no 
definition is available}}
                                   // expected-note@-1{{add an explicit 
instantiation declaration to suppress this warning if 
'C1<int>::C2<long>::s_tvar_2<long>' is explicitly instantiated in another 
translation unit}}
-                                  // expected-note@-2{{there are 2 ways to fix 
this:}}
+                                  // expected-note@-2{{there are 3 ways to fix 
this:}}
                                   // expected-note@-3{{use 'extern template 
char C1<int>::C2<long>::s_tvar_2<long>;'}}
                                   // expected-note@-4{{or use 'template <> 
char C1<int>::C2<long>::s_tvar_2<long>;'}}
+                                  // expected-note@-5{{or use 'template <class 
T> template <typename T1> template <class T2> char C1<T>::C2<T1>::s_tvar_2;' to 
provide a definition for all types}}
 }
 
 void func_22(C1<int>::C2<long> *x) {

From f0b8baf64b2395d94c18943d8218b580aba81ad9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=8D=8Ddiohabara=E5=8D=8D?=
 <[email protected]>
Date: Sun, 22 Mar 2026 15:38:23 +0900
Subject: [PATCH 7/7] chore: format

---
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  | 30 ++++++++++---------
 1 file changed, 16 insertions(+), 14 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp 
b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 7a6a18afb430b..e6a7f253032cd 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -6391,12 +6391,17 @@ void Sema::InstantiateVariableDefinition(SourceLocation 
PointOfInstantiation,
           {
             const DeclContext *DC = PatternDecl->getDeclContext();
             bool Valid = true;
-            while (DC && !DC->isFileContext() &&
-                   !isa<NamespaceDecl>(DC)) {
+            while (DC && !DC->isFileContext() && !isa<NamespaceDecl>(DC)) {
               const auto *RD = dyn_cast<CXXRecordDecl>(DC);
-              if (!RD) { Valid = false; break; }
+              if (!RD) {
+                Valid = false;
+                break;
+              }
               const auto *CTD = RD->getDescribedClassTemplate();
-              if (!CTD) { Valid = false; break; }
+              if (!CTD) {
+                Valid = false;
+                break;
+              }
               EnclosingCTDs.push_back(CTD);
               DC = DC->getParent();
             }
@@ -6447,20 +6452,18 @@ void Sema::InstantiateVariableDefinition(SourceLocation 
PointOfInstantiation,
               llvm::raw_string_ostream OS(DefSuggestion);
               // Print class template parameter lists (outermost to
               // innermost). Each print() appends a trailing space.
-              for (auto It = EnclosingCTDs.rbegin(),
-                        End = EnclosingCTDs.rend();
+              for (auto It = EnclosingCTDs.rbegin(), End = 
EnclosingCTDs.rend();
                    It != End; ++It)
-                (*It)->getTemplateParameters()->print(
-                    OS, getASTContext(), getPrintingPolicy());
+                (*It)->getTemplateParameters()->print(OS, getASTContext(),
+                                                      getPrintingPolicy());
               // Print variable template parameter list if present.
               if (PatternVTD)
-                PatternVTD->getTemplateParameters()->print(
-                    OS, getASTContext(), getPrintingPolicy());
+                PatternVTD->getTemplateParameters()->print(OS, getASTContext(),
+                                                           
getPrintingPolicy());
               // Build qualified name: C1<T>::C2<T1>::varName
               std::string QualName;
               llvm::raw_string_ostream NameOS(QualName);
-              for (auto It = EnclosingCTDs.rbegin(),
-                        End = EnclosingCTDs.rend();
+              for (auto It = EnclosingCTDs.rbegin(), End = 
EnclosingCTDs.rend();
                    It != End; ++It) {
                 const auto *TPL = (*It)->getTemplateParameters();
                 NameOS << (*It)->getName() << "<";
@@ -6472,8 +6475,7 @@ void Sema::InstantiateVariableDefinition(SourceLocation 
PointOfInstantiation,
                 NameOS << ">::";
               }
               NameOS << PatternDecl->getName();
-              PatternDecl->getType().print(OS, getPrintingPolicy(),
-                                           QualName);
+              PatternDecl->getType().print(OS, getPrintingPolicy(), QualName);
               OS << ";";
             }
             Diag(PointOfInstantiation,

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

Reply via email to