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/4] [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/4] 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/4] 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/4] 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) { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
