sepavloff created this revision.
sepavloff added a reviewer: rsmith.
sepavloff added subscribers: cfe-commits, silvas.

Instantiation of static class members may be a source of user misunderstanding,
especially in the case of using modules, PR24425 describes one of such examples.
This patch implements warning if compiler tried to make implicit instantiation
but could not find template definition. The implementation follows discussion
of http://reviews.llvm.org/D12326.

http://reviews.llvm.org/D16396

Files:
  include/clang/Basic/DiagnosticGroups.td
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/Sema.h
  lib/Sema/SemaTemplateInstantiateDecl.cpp
  test/CXX/temp/temp.decls/temp.mem/p1.cpp
  test/OpenMP/parallel_ast_print.cpp
  test/OpenMP/parallel_sections_ast_print.cpp
  test/OpenMP/task_ast_print.cpp
  test/OpenMP/teams_ast_print.cpp
  test/OpenMP/threadprivate_ast_print.cpp
  test/SemaCXX/PR10177.cpp
  test/SemaCXX/undefined-internal.cpp
  test/SemaTemplate/unavailable-var-template.cpp

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 <class T> struct Foo {
+  static char s_bar;
+  static char s_bar2;
+};
+
+extern template char Foo<int>::s_bar2;
+
+char baz(char x) {
+  if (x == '.')
+    return Foo<int>::s_bar2;
+  return Foo<int>::s_bar; // expected-warning{{instantiation of 'Foo<int>::s_bar' required here, but corresponding template is not found}}
+                          // expected-note@-1{{add an explicit instantiation declaration to suppress this warning if 'Foo<int>::s_bar' is explicitly instantiated in another translation unit}}
+}
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<test5::(anonymous namespace)::A>::var' has internal linkage but is not defined}}
     static void foo(); // expected-warning {{function 'test5::B<test5::(anonymous namespace)::A>::foo' has internal linkage but is not defined}}
   };
+  extern template int B<A>::var;
 
   void test() {
     B<A>::var = 0; // expected-note {{used here}}
Index: test/SemaCXX/PR10177.cpp
===================================================================
--- test/SemaCXX/PR10177.cpp
+++ test/SemaCXX/PR10177.cpp
@@ -54,6 +54,7 @@
 
 namespace { template<typename> extern int n; }
 template<typename T> int g() { return n<int>; }
+namespace { extern template int n<int>; }
 
 #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<int>());
 }
 
+extern template int ST<int>::m;
 #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<int, 5>(b, &b) + tmain<long, 1>(x, &x);
 }
 
+extern template int S<int>::TS;
+extern template long S<long>::TS;
 #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<int, 5>(b, &b) + tmain<long, 1>(x, &x);
 }
 
+extern template int S<int>::TS;
+extern template long S<long>::TS;
+
 #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<int, 5>(b, &b) + tmain<long, 1>(x, &x);
 }
 
+template<typename T>
+T S<T>::TS = 0;
+
 #endif
Index: test/OpenMP/parallel_ast_print.cpp
===================================================================
--- test/OpenMP/parallel_ast_print.cpp
+++ test/OpenMP/parallel_ast_print.cpp
@@ -171,4 +171,7 @@
   }
 }
 
+template<typename T>
+T S<T>::TS = 0;
+
 #endif
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<bool>::cond;
 
 int foo() {
   A<bool>::cond = true;
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: 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: 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<UnavailableTemplate>;
+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/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">;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to