<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Apr 19, 2016 at 7:28 AM, Nico Weber via cfe-commits <span dir="ltr"><<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">(sorry, accidentally sent this mid-mail)<div><br></div><div><div>../../v8/src/crankshaft/lithium.h:322:45: error: instantiation of variable 'v8::internal::LSubKindOperand<v8::internal::LOperand::Kind::DOUBLE_STACK_SLOT, 128>::cache' required here, but no definition is available [-Werror,-Wundefined-var-template]</div><span class=""><div>    if (index < kNumCachedOperands) return &cache[index];</div></span><div>                                            ^</div><div>../../v8/src/crankshaft/x64/lithium-x64.cc:334:30: note: in instantiation of member function 'v8::internal::LSubKindOperand<v8::internal::LOperand::Kind::DOUBLE_STACK_SLOT, 128>::Create' requested here</div><div>    return LDoubleStackSlot::Create(index, zone());</div><div>                             ^</div><div>../../v8/src/crankshaft/lithium.h:335:27: note: forward declaration of template entity is here</div><div>  static LSubKindOperand* cache;</div><div>                          ^</div><div>../../v8/src/crankshaft/lithium.h:322:45: note: add an explicit instantiation declaration to suppress this warning if 'v8::internal::LSubKindOperand<v8::internal::LOperand::Kind::DOUBLE_STACK_SLOT, 128>::cache' is explicitly instantiated in another translation unit</div><span class=""><div>    if (index < kNumCachedOperands) return &cache[index];</div></span><div>                                            ^</div></div><div><br></div><div>I don't understand what this warning wants to tell me, or what it wants me to do. What is this warning good for? Neither warning text nor commit message explain that.</div></div></blockquote><div><br></div><div><br></div><div>+1</div><div><br></div><div>I'm seeing a similar error in an internal codebase for a Singleton<T> class.</div><div><br></div><div>Something like:</div><div><br></div><div>template <typename T></div><div>struct Singleton {</div><div>... other stuff ...</div><div>  T *getInstance();</div><div>private:</div><div>  static T *instance;<br>};</div><div><br></div><div>And `instance` is defined in a .cpp file somewhere.</div><div><br></div><div>This seems to be deliberate.</div><div><br></div><div>-- Sean Silva</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5"><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Apr 19, 2016 at 10:27 AM, Nico Weber <span dir="ltr"><<a href="mailto:thakis@chromium.org" target="_blank">thakis@chromium.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">Hi Serge,<div><br></div><div>this complains on this snippet from v8:</div><div><br></div><div><div>template <LOperand::Kind kOperandKind, int kNumCachedOperands></div><div>class LSubKindOperand final : public LOperand {</div><div> public:</div><div>  static LSubKindOperand* Create(int index, Zone* zone) {</div><div>    if (index < kNumCachedOperands) return &cache[index];</div><div>    return new(zone) LSubKindOperand(index);</div><div>  }</div><div> private:</div><div>  static LSubKindOperand* cache;</div><div>  explicit LSubKindOperand(int index);</div><div>};</div></div><div><br></div><div><br></div></div><div><div><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Apr 19, 2016 at 2:19 AM, Serge Pavlov via cfe-commits <span dir="ltr"><<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: sepavloff<br>
Date: Tue Apr 19 01:19:52 2016<br>
New Revision: 266719<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=266719&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=266719&view=rev</a><br>
Log:<br>
Warn if function or variable cannot be implicitly instantiated<br>
<br>
With this patch compiler emits warning if it tries to make implicit instantiation<br>
of a template but cannot find the template definition. The warning can be suppressed<br>
by explicit instantiation declaration or by command line options<br>
-Wundefined-var-template and -Wundefined-func-template. The implementation follows<br>
the discussion of <a href="http://reviews.llvm.org/D12326" rel="noreferrer" target="_blank">http://reviews.llvm.org/D12326</a>.<br>
<br>
Differential Revision: <a href="http://reviews.llvm.org/D16396" rel="noreferrer" target="_blank">http://reviews.llvm.org/D16396</a><br>
<br>
Added:<br>
    cfe/trunk/test/SemaTemplate/undefined-template.cpp<br>
Modified:<br>
    cfe/trunk/include/clang/AST/DeclBase.h<br>
    cfe/trunk/include/clang/Basic/DiagnosticGroups.td<br>
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td<br>
    cfe/trunk/include/clang/Sema/Sema.h<br>
    cfe/trunk/lib/AST/DeclBase.cpp<br>
    cfe/trunk/lib/Sema/SemaOverload.cpp<br>
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp<br>
    cfe/trunk/test/CXX/temp/temp.decls/temp.mem/p1.cpp<br>
    cfe/trunk/test/OpenMP/parallel_ast_print.cpp<br>
    cfe/trunk/test/OpenMP/parallel_sections_ast_print.cpp<br>
    cfe/trunk/test/OpenMP/target_parallel_ast_print.cpp<br>
    cfe/trunk/test/OpenMP/task_ast_print.cpp<br>
    cfe/trunk/test/OpenMP/teams_ast_print.cpp<br>
    cfe/trunk/test/OpenMP/threadprivate_ast_print.cpp<br>
    cfe/trunk/test/SemaCXX/PR10177.cpp<br>
    cfe/trunk/test/SemaCXX/undefined-internal.cpp<br>
<br>
Modified: cfe/trunk/include/clang/AST/DeclBase.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclBase.h?rev=266719&r1=266718&r2=266719&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclBase.h?rev=266719&r1=266718&r2=266719&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/AST/DeclBase.h (original)<br>
+++ cfe/trunk/include/clang/AST/DeclBase.h Tue Apr 19 01:19:52 2016<br>
@@ -52,6 +52,7 @@ struct PrintingPolicy;<br>
 class RecordDecl;<br>
 class Stmt;<br>
 class StoredDeclsMap;<br>
+class TemplateDecl;<br>
 class TranslationUnitDecl;<br>
 class UsingDirectiveDecl;<br>
 }<br>
@@ -905,6 +906,10 @@ public:<br>
            DeclKind == FunctionTemplate;<br>
   }<br>
<br>
+  /// \brief If this is a declaration that describes some template, this<br>
+  /// method returns that template declaration.<br>
+  TemplateDecl *getDescribedTemplate() const;<br>
+<br>
   /// \brief Returns the function itself, or the templated function if this is a<br>
   /// function template.<br>
   FunctionDecl *getAsFunction() LLVM_READONLY;<br>
<br>
Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=266719&r1=266718&r2=266719&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=266719&r1=266718&r2=266719&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original)<br>
+++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Tue Apr 19 01:19:52 2016<br>
@@ -75,6 +75,8 @@ def : DiagGroup<"ctor-dtor-privacy">;<br>
 def GNUDesignator : DiagGroup<"gnu-designator">;<br>
 def GNUStringLiteralOperatorTemplate :<br>
   DiagGroup<"gnu-string-literal-operator-template">;<br>
+def UndefinedVarTemplate : DiagGroup<"undefined-var-template">;<br>
+def UndefinedFuncTemplate : DiagGroup<"undefined-func-template">;<br>
<br>
 def DeleteIncomplete : DiagGroup<"delete-incomplete">;<br>
 def DeleteNonVirtualDtor : DiagGroup<"delete-non-virtual-dtor">;<br>
<br>
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=266719&r1=266718&r2=266719&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=266719&r1=266718&r2=266719&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)<br>
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Apr 19 01:19:52 2016<br>
@@ -3883,7 +3883,18 @@ def note_template_type_alias_instantiati<br>
   "in instantiation of template type alias %0 requested here">;<br>
 def note_template_exception_spec_instantiation_here : Note<<br>
   "in instantiation of exception specification for %0 requested here">;<br>
-<br>
+def warn_var_template_missing : Warning<"instantiation of variable %q0 "<br>
+  "required here, but no definition is available">,<br>
+  InGroup<UndefinedVarTemplate>;<br>
+def warn_func_template_missing : Warning<"instantiation of function %q0 "<br>
+  "required here, but no definition is available">,<br>
+  InGroup<UndefinedFuncTemplate>, DefaultIgnore;<br>
+def note_forward_template_decl : Note<<br>
+  "forward declaration of template entity is here">;<br>
+def note_inst_declaration_hint : Note<"add an explicit instantiation "<br>
+  "declaration to suppress this warning if %q0 is explicitly instantiated in "<br>
+  "another translation unit">;<br>
+<br>
 def note_default_arg_instantiation_here : Note<<br>
   "in instantiation of default argument for '%0' required here">;<br>
 def note_default_function_arg_instantiation_here : Note<<br>
<br>
Modified: cfe/trunk/include/clang/Sema/Sema.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=266719&r1=266718&r2=266719&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=266719&r1=266718&r2=266719&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Sema/Sema.h (original)<br>
+++ cfe/trunk/include/clang/Sema/Sema.h Tue Apr 19 01:19:52 2016<br>
@@ -7171,7 +7171,8 @@ public:<br>
   void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,<br>
                                      FunctionDecl *Function,<br>
                                      bool Recursive = false,<br>
-                                     bool DefinitionRequired = false);<br>
+                                     bool DefinitionRequired = false,<br>
+                                     bool AtEndOfTU = false);<br>
   VarTemplateSpecializationDecl *BuildVarTemplateInstantiation(<br>
       VarTemplateDecl *VarTemplate, VarDecl *FromVar,<br>
       const TemplateArgumentList &TemplateArgList,<br>
@@ -7195,7 +7196,8 @@ public:<br>
       const MultiLevelTemplateArgumentList &TemplateArgs);<br>
   void InstantiateVariableDefinition(SourceLocation PointOfInstantiation,<br>
                                      VarDecl *Var, bool Recursive = false,<br>
-                                     bool DefinitionRequired = false);<br>
+                                     bool DefinitionRequired = false,<br>
+                                     bool AtEndOfTU = false);<br>
   void InstantiateStaticDataMemberDefinition(<br>
                                      SourceLocation PointOfInstantiation,<br>
                                      VarDecl *Var,<br>
<br>
Modified: cfe/trunk/lib/AST/DeclBase.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclBase.cpp?rev=266719&r1=266718&r2=266719&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclBase.cpp?rev=266719&r1=266718&r2=266719&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/AST/DeclBase.cpp (original)<br>
+++ cfe/trunk/lib/AST/DeclBase.cpp Tue Apr 19 01:19:52 2016<br>
@@ -196,6 +196,17 @@ bool Decl::isTemplateDecl() const {<br>
   return isa<TemplateDecl>(this);<br>
 }<br>
<br>
+TemplateDecl *Decl::getDescribedTemplate() const {<br>
+  if (auto *FD = dyn_cast<FunctionDecl>(this))<br>
+    return FD->getDescribedFunctionTemplate();<br>
+  else if (auto *RD = dyn_cast<CXXRecordDecl>(this))<br>
+    return RD->getDescribedClassTemplate();<br>
+  else if (auto *VD = dyn_cast<VarDecl>(this))<br>
+    return VD->getDescribedVarTemplate();<br>
+<br>
+  return nullptr;<br>
+}<br>
+<br>
 const DeclContext *Decl::getParentFunctionOrMethod() const {<br>
   for (const DeclContext *DC = getDeclContext();<br>
        DC && !DC->isTranslationUnit() && !DC->isNamespace();<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=266719&r1=266718&r2=266719&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=266719&r1=266718&r2=266719&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Tue Apr 19 01:19:52 2016<br>
@@ -9324,11 +9324,8 @@ static void DiagnoseArityMismatch(Sema &<br>
 }<br>
<br>
 static TemplateDecl *getDescribedTemplate(Decl *Templated) {<br>
-  if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Templated))<br>
-    return FD->getDescribedFunctionTemplate();<br>
-  else if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Templated))<br>
-    return RD->getDescribedClassTemplate();<br>
-<br>
+  if (TemplateDecl *TD = Templated->getDescribedTemplate())<br>
+    return TD;<br>
   llvm_unreachable("Unsupported: Getting the described template declaration"<br>
                    " for bad deduction diagnosis");<br>
 }<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=266719&r1=266718&r2=266719&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=266719&r1=266718&r2=266719&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Tue Apr 19 01:19:52 2016<br>
@@ -3530,7 +3530,8 @@ TemplateDeclInstantiator::InitMethodInst<br>
 void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,<br>
                                          FunctionDecl *Function,<br>
                                          bool Recursive,<br>
-                                         bool DefinitionRequired) {<br>
+                                         bool DefinitionRequired,<br>
+                                         bool AtEndOfTU) {<br>
   if (Function->isInvalidDecl() || Function->isDefined())<br>
     return;<br>
<br>
@@ -3604,6 +3605,16 @@ void Sema::InstantiateFunctionDefinition<br>
       assert(!Recursive);<br>
       PendingInstantiations.push_back(<br>
         std::make_pair(Function, PointOfInstantiation));<br>
+    } else if (Function->getTemplateSpecializationKind()<br>
+                 == TSK_ImplicitInstantiation) {<br>
+      if (AtEndOfTU && !getDiagnostics().hasErrorOccurred()) {<br>
+        Diag(PointOfInstantiation, diag::warn_func_template_missing)<br>
+          << Function;<br>
+        Diag(PatternDecl->getLocation(), diag::note_forward_template_decl);<br>
+        if (getLangOpts().CPlusPlus11)<br>
+          Diag(PointOfInstantiation, diag::note_inst_declaration_hint)<br>
+            << Function;<br>
+      }<br>
     }<br>
<br>
     return;<br>
@@ -3951,7 +3962,7 @@ void Sema::InstantiateStaticDataMemberDe<br>
<br>
 void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,<br>
                                          VarDecl *Var, bool Recursive,<br>
-                                         bool DefinitionRequired) {<br>
+                                      bool DefinitionRequired, bool AtEndOfTU) {<br>
   if (Var->isInvalidDecl())<br>
     return;<br>
<br>
@@ -4083,6 +4094,16 @@ void Sema::InstantiateVariableDefinition<br>
                  == TSK_ExplicitInstantiationDefinition) {<br>
       PendingInstantiations.push_back(<br>
         std::make_pair(Var, PointOfInstantiation));<br>
+    } else if (Var->getTemplateSpecializationKind()<br>
+                 == TSK_ImplicitInstantiation) {<br>
+      // Warn about missing definition at the end of translation unit.<br>
+      if (AtEndOfTU && !getDiagnostics().hasErrorOccurred()) {<br>
+        Diag(PointOfInstantiation, diag::warn_var_template_missing)<br>
+          << Var;<br>
+        Diag(PatternDecl->getLocation(), diag::note_forward_template_decl);<br>
+        if (getLangOpts().CPlusPlus11)<br>
+          Diag(PointOfInstantiation, diag::note_inst_declaration_hint) << Var;<br>
+      }<br>
     }<br>
<br>
     return;<br>
@@ -4852,7 +4873,7 @@ void Sema::PerformPendingInstantiations(<br>
       bool DefinitionRequired = Function->getTemplateSpecializationKind() ==<br>
                                 TSK_ExplicitInstantiationDefinition;<br>
       InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true,<br>
-                                    DefinitionRequired);<br>
+                                    DefinitionRequired, true);<br>
       continue;<br>
     }<br>
<br>
@@ -4893,7 +4914,7 @@ void Sema::PerformPendingInstantiations(<br>
     // Instantiate static data member definitions or variable template<br>
     // specializations.<br>
     InstantiateVariableDefinition(/*FIXME:*/ Inst.second, Var, true,<br>
-                                  DefinitionRequired);<br>
+                                  DefinitionRequired, true);<br>
   }<br>
 }<br>
<br>
<br>
Modified: cfe/trunk/test/CXX/temp/temp.decls/temp.mem/p1.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.mem/p1.cpp?rev=266719&r1=266718&r2=266719&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.mem/p1.cpp?rev=266719&r1=266718&r2=266719&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/CXX/temp/temp.decls/temp.mem/p1.cpp (original)<br>
+++ cfe/trunk/test/CXX/temp/temp.decls/temp.mem/p1.cpp Tue Apr 19 01:19:52 2016<br>
@@ -10,6 +10,7 @@ template <class T> struct A {<br>
     }<br>
   };<br>
 };<br>
+extern template bool A<bool>::cond;<br>
<br>
 int foo() {<br>
   A<bool>::cond = true;<br>
<br>
Modified: cfe/trunk/test/OpenMP/parallel_ast_print.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/parallel_ast_print.cpp?rev=266719&r1=266718&r2=266719&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/parallel_ast_print.cpp?rev=266719&r1=266718&r2=266719&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/OpenMP/parallel_ast_print.cpp (original)<br>
+++ cfe/trunk/test/OpenMP/parallel_ast_print.cpp Tue Apr 19 01:19:52 2016<br>
@@ -227,4 +227,7 @@ void foo(const Foo<int> &arg) {<br>
   }<br>
 }<br>
<br>
+template<typename T><br>
+T S<T>::TS = 0;<br>
+<br>
 #endif<br>
<br>
Modified: cfe/trunk/test/OpenMP/parallel_sections_ast_print.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/parallel_sections_ast_print.cpp?rev=266719&r1=266718&r2=266719&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/parallel_sections_ast_print.cpp?rev=266719&r1=266718&r2=266719&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/OpenMP/parallel_sections_ast_print.cpp (original)<br>
+++ cfe/trunk/test/OpenMP/parallel_sections_ast_print.cpp Tue Apr 19 01:19:52 2016<br>
@@ -141,4 +141,7 @@ int main(int argc, char **argv) {<br>
   return tmain<int, 5>(b, &b) + tmain<long, 1>(x, &x);<br>
 }<br>
<br>
+template<typename T><br>
+T S<T>::TS = 0;<br>
+<br>
 #endif<br>
<br>
Modified: cfe/trunk/test/OpenMP/target_parallel_ast_print.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/target_parallel_ast_print.cpp?rev=266719&r1=266718&r2=266719&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/target_parallel_ast_print.cpp?rev=266719&r1=266718&r2=266719&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/OpenMP/target_parallel_ast_print.cpp (original)<br>
+++ cfe/trunk/test/OpenMP/target_parallel_ast_print.cpp Tue Apr 19 01:19:52 2016<br>
@@ -227,4 +227,7 @@ int main (int argc, char **argv) {<br>
   return tmain<int, 5>(argc, &argc) + tmain<char, 1>(argv[0][0], argv[0]);<br>
 }<br>
<br>
+extern template int S<int>::TS;<br>
+extern template char S<char>::TS;<br>
+<br>
 #endif<br>
<br>
Modified: cfe/trunk/test/OpenMP/task_ast_print.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/task_ast_print.cpp?rev=266719&r1=266718&r2=266719&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/task_ast_print.cpp?rev=266719&r1=266718&r2=266719&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/OpenMP/task_ast_print.cpp (original)<br>
+++ cfe/trunk/test/OpenMP/task_ast_print.cpp Tue Apr 19 01:19:52 2016<br>
@@ -149,4 +149,7 @@ int main(int argc, char **argv) {<br>
   return tmain<int, 5>(b, &b) + tmain<long, 1>(x, &x);<br>
 }<br>
<br>
+extern template int S<int>::TS;<br>
+extern template long S<long>::TS;<br>
+<br>
 #endif<br>
<br>
Modified: cfe/trunk/test/OpenMP/teams_ast_print.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/teams_ast_print.cpp?rev=266719&r1=266718&r2=266719&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/teams_ast_print.cpp?rev=266719&r1=266718&r2=266719&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/OpenMP/teams_ast_print.cpp (original)<br>
+++ cfe/trunk/test/OpenMP/teams_ast_print.cpp Tue Apr 19 01:19:52 2016<br>
@@ -109,4 +109,6 @@ int main (int argc, char **argv) {<br>
   return tmain<int, 5>(b, &b) + tmain<long, 1>(x, &x);<br>
 }<br>
<br>
+extern template int S<int>::TS;<br>
+extern template long S<long>::TS;<br>
 #endif<br>
<br>
Modified: cfe/trunk/test/OpenMP/threadprivate_ast_print.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/threadprivate_ast_print.cpp?rev=266719&r1=266718&r2=266719&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/threadprivate_ast_print.cpp?rev=266719&r1=266718&r2=266719&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/OpenMP/threadprivate_ast_print.cpp (original)<br>
+++ cfe/trunk/test/OpenMP/threadprivate_ast_print.cpp Tue Apr 19 01:19:52 2016<br>
@@ -69,4 +69,5 @@ int main () {<br>
   return (foo<int>());<br>
 }<br>
<br>
+extern template int ST<int>::m;<br>
 #endif<br>
<br>
Modified: cfe/trunk/test/SemaCXX/PR10177.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/PR10177.cpp?rev=266719&r1=266718&r2=266719&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/PR10177.cpp?rev=266719&r1=266718&r2=266719&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/SemaCXX/PR10177.cpp (original)<br>
+++ cfe/trunk/test/SemaCXX/PR10177.cpp Tue Apr 19 01:19:52 2016<br>
@@ -54,6 +54,7 @@ namespace N {<br>
<br>
 namespace { template<typename> extern int n; }<br>
 template<typename T> int g() { return n<int>; }<br>
+namespace { extern template int n<int>; }<br>
<br>
 #endif<br>
<br>
<br>
Modified: cfe/trunk/test/SemaCXX/undefined-internal.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/undefined-internal.cpp?rev=266719&r1=266718&r2=266719&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/undefined-internal.cpp?rev=266719&r1=266718&r2=266719&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/SemaCXX/undefined-internal.cpp (original)<br>
+++ cfe/trunk/test/SemaCXX/undefined-internal.cpp Tue Apr 19 01:19:52 2016<br>
@@ -82,6 +82,7 @@ namespace test5 {<br>
     static int var; // expected-warning {{variable 'test5::B<test5::(anonymous namespace)::A>::var' has internal linkage but is not defined}}<br>
     static void foo(); // expected-warning {{function 'test5::B<test5::(anonymous namespace)::A>::foo' has internal linkage but is not defined}}<br>
   };<br>
+  extern template int B<A>::var;<br>
<br>
   void test() {<br>
     B<A>::var = 0; // expected-note {{used here}}<br>
<br>
Added: cfe/trunk/test/SemaTemplate/undefined-template.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/undefined-template.cpp?rev=266719&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/undefined-template.cpp?rev=266719&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/test/SemaTemplate/undefined-template.cpp (added)<br>
+++ cfe/trunk/test/SemaTemplate/undefined-template.cpp Tue Apr 19 01:19:52 2016<br>
@@ -0,0 +1,139 @@<br>
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++14 -Wundefined-func-template %s<br>
+<br>
+template <class T> struct C1 {<br>
+  static char s_var_1;       // expected-note{{forward declaration of template entity is here}}<br>
+  static char s_var_2;       // expected-note{{forward declaration of template entity is here}}<br>
+  static void s_func_1();    // expected-note{{forward declaration of template entity is here}}<br>
+  static void s_func_2();    // expected-note{{forward declaration of template entity is here}}<br>
+  void meth_1();             // expected-note2{{forward declaration of template entity is here}}<br>
+  void meth_2();<br>
+  template <class T1> static char s_tvar_2;      // expected-note{{forward declaration of template entity is here}}<br>
+  template <class T1> static void s_tfunc_2();   // expected-note{{forward declaration of template entity is here}}<br>
+  template<typename T1> struct C2 {<br>
+    static char s_var_2;     // expected-note{{forward declaration of template entity is here}}<br>
+    static void s_func_2();  // expected-note{{forward declaration of template entity is here}}<br>
+    void meth_2();           // expected-note{{forward declaration of template entity is here}}<br>
+    template <class T2> static char s_tvar_2;    // expected-note{{forward declaration of template entity is here}}<br>
+    template <class T2> void tmeth_2();          // expected-note{{forward declaration of template entity is here}}<br>
+  };<br>
+};<br>
+<br>
+extern template char C1<int>::s_var_2;<br>
+extern template void C1<int>::s_func_2();<br>
+extern template void C1<int>::meth_2();<br>
+extern template char C1<int>::s_tvar_2<char>;<br>
+extern template void C1<int>::s_tfunc_2<char>();<br>
+extern template void C1<int>::C2<long>::s_var_2;<br>
+extern template void C1<int>::C2<long>::s_func_2();<br>
+extern template void C1<int>::C2<long>::meth_2();<br>
+extern template char C1<int>::C2<long>::s_tvar_2<char>;<br>
+extern template void C1<int>::C2<long>::tmeth_2<char>();<br>
+<br>
+char func_01() {<br>
+  return C1<int>::s_var_2;<br>
+}<br>
+<br>
+char func_02() {<br>
+  return C1<int>::s_var_1; // expected-warning{{instantiation of variable 'C1<int>::s_var_1' required here, but no definition is available}}<br>
+                           // 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}}<br>
+}<br>
+<br>
+char func_03() {<br>
+  return C1<char>::s_var_2; // expected-warning{{instantiation of variable 'C1<char>::s_var_2' required here, but no definition is available}}<br>
+                            // 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}}<br>
+}<br>
+<br>
+void func_04() {<br>
+  C1<int>::s_func_1(); // expected-warning{{instantiation of function 'C1<int>::s_func_1' required here, but no definition is available}}<br>
+                       // 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}}<br>
+}<br>
+<br>
+void func_05() {<br>
+  C1<int>::s_func_2();<br>
+}<br>
+<br>
+void func_06() {<br>
+  C1<char>::s_func_2(); // expected-warning{{instantiation of function 'C1<char>::s_func_2' required here, but no definition is available}}<br>
+                        // 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}}<br>
+}<br>
+<br>
+void func_07(C1<int> *x) {<br>
+  x->meth_1();  // expected-warning{{instantiation of function 'C1<int>::meth_1' required here, but no definition is available}}<br>
+                // expected-note@-1{{add an explicit instantiation declaration to suppress this warning if 'C1<int>::meth_1' is explicitly instantiated in another translation unit}}<br>
+}<br>
+<br>
+void func_08(C1<int> *x) {<br>
+  x->meth_2();<br>
+}<br>
+<br>
+void func_09(C1<char> *x) {<br>
+  x->meth_1();  // expected-warning{{instantiation of function 'C1<char>::meth_1' required here, but no definition is available}}<br>
+                // expected-note@-1{{add an explicit instantiation declaration to suppress this warning if 'C1<char>::meth_1' is explicitly instantiated in another translation unit}}<br>
+}<br>
+<br>
+char func_10() {<br>
+  return C1<int>::s_tvar_2<char>;<br>
+}<br>
+<br>
+char func_11() {<br>
+  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}}<br>
+                                  // 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}}<br>
+}<br>
+<br>
+void func_12() {<br>
+  C1<int>::s_tfunc_2<char>();<br>
+}<br>
+<br>
+void func_13() {<br>
+  C1<int>::s_tfunc_2<long>(); // expected-warning{{instantiation of function 'C1<int>::s_tfunc_2<long>' required here, but no definition is available}}<br>
+                              // 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}}<br>
+}<br>
+<br>
+char func_14() {<br>
+  return C1<int>::C2<long>::s_var_2;<br>
+}<br>
+<br>
+char func_15() {<br>
+  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}}<br>
+                                      // 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}}<br>
+}<br>
+<br>
+void func_16() {<br>
+  C1<int>::C2<long>::s_func_2();<br>
+}<br>
+<br>
+void func_17() {<br>
+  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}}<br>
+                        // 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}}<br>
+}<br>
+<br>
+void func_18(C1<int>::C2<long> *x) {<br>
+  x->meth_2();<br>
+}<br>
+<br>
+void func_19(C1<int>::C2<char> *x) {<br>
+  x->meth_2();   // expected-warning{{instantiation of function 'C1<int>::C2<char>::meth_2' required here, but no definition is available}}<br>
+                        // 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}}<br>
+}<br>
+<br>
+char func_20() {<br>
+  return C1<int>::C2<long>::s_tvar_2<char>;<br>
+}<br>
+<br>
+char func_21() {<br>
+  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}}<br>
+                                  // 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}}<br>
+}<br>
+<br>
+void func_22(C1<int>::C2<long> *x) {<br>
+  x->tmeth_2<char>();<br>
+}<br>
+<br>
+void func_23(C1<int>::C2<long> *x) {<br>
+  x->tmeth_2<int>();    // expected-warning{{instantiation of function 'C1<int>::C2<long>::tmeth_2<int>' required here, but no definition is available}}<br>
+                        // 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}}<br>
+}<br>
+<br>
+int main() {<br>
+  return 0;<br>
+}<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div>
</div></div></blockquote></div><br></div>
</div></div><br>_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org">cfe-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits</a><br>
<br></blockquote></div><br></div></div>