Index: include/clang/Basic/DiagnosticGroups.td =================================================================== --- include/clang/Basic/DiagnosticGroups.td +++ include/clang/Basic/DiagnosticGroups.td @@ -75,6 +75,7 @@ def GNUDesignator : DiagGroup<"gnu-designator">; def GNUStringLiteralOperatorTemplate : DiagGroup<"gnu-string-literal-operator-template">; +def UnavailableTemplate : DiagGroup<"unavailable-template">; def DeleteIncomplete : DiagGroup<"delete-incomplete">; def DeleteNonVirtualDtor : DiagGroup<"delete-non-virtual-dtor">; Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -3821,7 +3821,12 @@ "in instantiation of template type alias %0 requested here">; def note_template_exception_spec_instantiation_here : Note< "in instantiation of exception specification for %0 requested here">; - + +def warn_var_template_missing : Warning<"instantiation of %q0 required here, " + "but corresponding template is not found">, InGroup; +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_default_arg_instantiation_here : Note< "in instantiation of default argument for '%0' required here">; def note_default_function_arg_instantiation_here : Note< Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -7128,7 +7128,8 @@ const MultiLevelTemplateArgumentList &TemplateArgs); void InstantiateVariableDefinition(SourceLocation PointOfInstantiation, VarDecl *Var, bool Recursive = false, - bool DefinitionRequired = false); + bool DefinitionRequired = false, + bool AtEndOfTU = false); void InstantiateStaticDataMemberDefinition( SourceLocation PointOfInstantiation, VarDecl *Var, Index: lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiateDecl.cpp +++ lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -3768,7 +3768,7 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, VarDecl *Var, bool Recursive, - bool DefinitionRequired) { + bool DefinitionRequired, bool AtEndOfTU) { if (Var->isInvalidDecl()) return; @@ -3900,6 +3900,14 @@ == TSK_ExplicitInstantiationDefinition) { PendingInstantiations.push_back( std::make_pair(Var, PointOfInstantiation)); + } else if (Var->getTemplateSpecializationKind() + == TSK_ImplicitInstantiation) { + // Warn about missing definition at the end of translation unit. + if (AtEndOfTU && !getDiagnostics().hasErrorOccurred()) { + Diag(PointOfInstantiation, diag::warn_var_template_missing) + << Var; + Diag(PointOfInstantiation, diag::note_inst_declaration_hint) << Var; + } } return; @@ -4710,7 +4718,7 @@ // Instantiate static data member definitions or variable template // specializations. InstantiateVariableDefinition(/*FIXME:*/ Inst.second, Var, true, - DefinitionRequired); + DefinitionRequired, true); } } Index: test/CXX/temp/temp.decls/temp.mem/p1.cpp =================================================================== --- test/CXX/temp/temp.decls/temp.mem/p1.cpp +++ test/CXX/temp/temp.decls/temp.mem/p1.cpp @@ -10,6 +10,7 @@ } }; }; +extern template bool A::cond; int foo() { A::cond = true; Index: test/OpenMP/parallel_ast_print.cpp =================================================================== --- test/OpenMP/parallel_ast_print.cpp +++ test/OpenMP/parallel_ast_print.cpp @@ -171,4 +171,7 @@ } } +template +T S::TS = 0; + #endif Index: test/OpenMP/parallel_sections_ast_print.cpp =================================================================== --- test/OpenMP/parallel_sections_ast_print.cpp +++ test/OpenMP/parallel_sections_ast_print.cpp @@ -141,4 +141,7 @@ return tmain(b, &b) + tmain(x, &x); } +template +T S::TS = 0; + #endif Index: test/OpenMP/task_ast_print.cpp =================================================================== --- test/OpenMP/task_ast_print.cpp +++ test/OpenMP/task_ast_print.cpp @@ -149,4 +149,7 @@ return tmain(b, &b) + tmain(x, &x); } +extern template int S::TS; +extern template long S::TS; + #endif Index: test/OpenMP/teams_ast_print.cpp =================================================================== --- test/OpenMP/teams_ast_print.cpp +++ test/OpenMP/teams_ast_print.cpp @@ -109,4 +109,6 @@ return tmain(b, &b) + tmain(x, &x); } +extern template int S::TS; +extern template long S::TS; #endif Index: test/OpenMP/threadprivate_ast_print.cpp =================================================================== --- test/OpenMP/threadprivate_ast_print.cpp +++ test/OpenMP/threadprivate_ast_print.cpp @@ -69,4 +69,5 @@ return (foo()); } +extern template int ST::m; #endif Index: test/SemaCXX/PR10177.cpp =================================================================== --- test/SemaCXX/PR10177.cpp +++ test/SemaCXX/PR10177.cpp @@ -54,6 +54,7 @@ namespace { template extern int n; } template int g() { return n; } +namespace { extern template int n; } #endif Index: test/SemaCXX/undefined-internal.cpp =================================================================== --- test/SemaCXX/undefined-internal.cpp +++ test/SemaCXX/undefined-internal.cpp @@ -82,6 +82,7 @@ static int var; // expected-warning {{variable 'test5::B::var' has internal linkage but is not defined}} static void foo(); // expected-warning {{function 'test5::B::foo' has internal linkage but is not defined}} }; + extern template int B::var; void test() { B::var = 0; // expected-note {{used here}} Index: test/SemaTemplate/unavailable-var-template.cpp =================================================================== --- /dev/null +++ test/SemaTemplate/unavailable-var-template.cpp @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +template struct Foo { + static char s_bar; + static char s_bar2; +}; + +extern template char Foo::s_bar2; + +char baz(char x) { + if (x == '.') + return Foo::s_bar2; + return Foo::s_bar; // expected-warning{{instantiation of 'Foo::s_bar' required here, but corresponding template is not found}} + // expected-note@-1{{add an explicit instantiation declaration to suppress this warning if 'Foo::s_bar' is explicitly instantiated in another translation unit}} +}