Diagnose explicit instantiations of function templates and member
functions/static data members of class template specializations that
do not have definitions. This is the latter part of [temp.explicit]p4;
the former part still needs more testing.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@84182 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index c9803da..5ea8a6a 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1112,9 +1112,12 @@
   "qualifier in explicit instantiation of '%0%1' requires a template-id">;
 def err_explicit_instantiation_unqualified_wrong_namespace : Error<
   "explicit instantiation of %q0 must occur in %1">;
-def err_explicit_instantiation_undefined_member_class : Error<
-  "explicit instantiation of undefined member class %0 of class template %1">;
-
+def err_explicit_instantiation_undefined_member : Error<
+  "explicit instantiation of undefined %select{member class|member function|"
+  "static data member}0 %1 of class template %2">;
+def err_explicit_instantiation_undefined_func_template : Error<
+  "explicit instantiation of undefined function template %0">;
+  
 // C++ typename-specifiers
 def err_typename_nested_not_found : Error<"no type named %0 in %1">;
 def err_typename_nested_not_type : Error<
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 80f3663..9b46f77 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -3197,11 +3197,13 @@
 
   void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
                                      FunctionDecl *Function,
-                                     bool Recursive = false);
+                                     bool Recursive = false,
+                                     bool DefinitionRequired = false);
   void InstantiateStaticDataMemberDefinition(
                                      SourceLocation PointOfInstantiation,
                                      VarDecl *Var,
-                                     bool Recursive = false);
+                                     bool Recursive = false,
+                                     bool DefinitionRequired = false);
 
   void InstantiateMemInitializers(CXXConstructorDecl *New,
                                   const CXXConstructorDecl *Tmpl,
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 04580b7..aa0c034 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -3657,8 +3657,8 @@
     CXXRecordDecl *Def 
       = cast_or_null<CXXRecordDecl>(Pattern->getDefinition(Context));
     if (!Def) {
-      Diag(TemplateLoc, diag::err_explicit_instantiation_undefined_member_class)
-        << Record->getDeclName() << Record->getDeclContext();
+      Diag(TemplateLoc, diag::err_explicit_instantiation_undefined_member)
+        << 0 << Record->getDeclName() << Record->getDeclContext();
       Diag(Pattern->getLocation(), diag::note_forward_declaration)
         << Pattern;
       return true;
@@ -3787,7 +3787,8 @@
     // FIXME: Check for prior specializations and such.
     Prev->setTemplateSpecializationKind(TSK);
     if (TSK == TSK_ExplicitInstantiationDefinition)
-      InstantiateStaticDataMemberDefinition(D.getIdentifierLoc(), Prev, false);
+      InstantiateStaticDataMemberDefinition(D.getIdentifierLoc(), Prev, false,
+                                            /*DefinitionRequired=*/true);
     
     // FIXME: Create an ExplicitInstantiation node?
     return DeclPtrTy();
@@ -3887,7 +3888,7 @@
     // definition.
     if (TSK == TSK_ExplicitInstantiationDefinition)
       InstantiateFunctionDefinition(D.getIdentifierLoc(), Specialization, 
-                                    false);
+                                    false, /*DefinitionRequired=*/true);
       
     Specialization->setTemplateSpecializationKind(TSK);
     break;
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 060cc55..ca05d59 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1044,9 +1044,14 @@
 ///
 /// \param Recursive if true, recursively instantiates any functions that
 /// are required by this instantiation.
+///
+/// \param DefinitionRequired if true, then we are performing an explicit
+/// instantiation where the body of the function is required. Complain if
+/// there is no such body.
 void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
                                          FunctionDecl *Function,
-                                         bool Recursive) {
+                                         bool Recursive,
+                                         bool DefinitionRequired) {
   if (Function->isInvalidDecl())
     return;
 
@@ -1075,8 +1080,24 @@
   if (PatternDecl)
     Pattern = PatternDecl->getBody(PatternDecl);
 
-  if (!Pattern)
+  if (!Pattern) {
+    if (DefinitionRequired) {
+      if (Function->getPrimaryTemplate())
+        Diag(PointOfInstantiation, 
+             diag::err_explicit_instantiation_undefined_func_template)
+          << Function->getPrimaryTemplate();
+      else
+        Diag(PointOfInstantiation, 
+             diag::err_explicit_instantiation_undefined_member)
+          << 1 << Function->getDeclName() << Function->getDeclContext();
+      
+      if (PatternDecl)
+        Diag(PatternDecl->getLocation(), 
+             diag::note_explicit_instantiation_here);
+    }
+      
     return;
+  }
 
   // C++0x [temp.explicit]p9:
   //   Except for inline functions, other explicit instantiation declarations
@@ -1161,10 +1182,15 @@
 ///
 /// \param Recursive if true, recursively instantiates any functions that
 /// are required by this instantiation.
+///
+/// \param DefinitionRequired if true, then we are performing an explicit
+/// instantiation where an out-of-line definition of the member variable
+/// is required. Complain if there is no such definition.
 void Sema::InstantiateStaticDataMemberDefinition(
                                           SourceLocation PointOfInstantiation,
                                                  VarDecl *Var,
-                                                 bool Recursive) {
+                                                 bool Recursive,
+                                                 bool DefinitionRequired) {
   if (Var->isInvalidDecl())
     return;
 
@@ -1187,6 +1213,13 @@
     // so we won't perform any instantiation. Rather, we rely on the user to
     // instantiate this definition (or provide a specialization for it) in
     // another translation unit.
+    if (DefinitionRequired) {
+      Diag(PointOfInstantiation, 
+           diag::err_explicit_instantiation_undefined_member)
+        << 2 << Var->getDeclName() << Var->getDeclContext();
+      Diag(Def->getLocation(), diag::note_explicit_instantiation_here);
+    }    
+    
     return;
   }
 
diff --git a/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp b/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp
index becdd6b..d7731f1 100644
--- a/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp
+++ b/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp
@@ -2,7 +2,7 @@
 
 template<typename T>
 struct X {
-  void f();
+  void f() {}
 };
 
 template inline void X<int>::f(); // expected-error{{'inline'}}
diff --git a/test/CXX/temp/temp.spec/temp.explicit/p2.cpp b/test/CXX/temp/temp.spec/temp.explicit/p2.cpp
index aee0e5d..f3d2c95 100644
--- a/test/CXX/temp/temp.spec/temp.explicit/p2.cpp
+++ b/test/CXX/temp/temp.spec/temp.explicit/p2.cpp
@@ -35,7 +35,7 @@
   };
   
   template<typename T>
-  void f1(T); // expected-note{{explicit instantiation refers here}}
+  void f1(T) {}; // expected-note{{explicit instantiation refers here}}
 }
 using namespace N;
 
diff --git a/test/CXX/temp/temp.spec/temp.explicit/p4.cpp b/test/CXX/temp/temp.spec/temp.explicit/p4.cpp
new file mode 100644
index 0000000..c45df56
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.explicit/p4.cpp
@@ -0,0 +1,16 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T> void f0(T); // expected-note{{here}}
+template void f0(int); // expected-error{{explicit instantiation of undefined function template}}
+
+template<typename T>
+struct X0 {
+  void f1(); // expected-note{{here}}
+  
+  static T value; // expected-note{{here}}
+};
+
+template void X0<int>::f1(); // expected-error{{explicit instantiation of undefined member function}}
+
+template int X0<int>::value; // expected-error{{explicit instantiation of undefined static data member}}
+