]> granicus.if.org Git - clang/commitdiff
Diagnose explicit instantiations of function templates and member
authorDouglas Gregor <dgregor@apple.com>
Thu, 15 Oct 2009 14:05:49 +0000 (14:05 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 15 Oct 2009 14:05:49 +0000 (14:05 +0000)
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

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/Sema.h
lib/Sema/SemaTemplate.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp
test/CXX/temp/temp.spec/temp.explicit/p2.cpp
test/CXX/temp/temp.spec/temp.explicit/p4.cpp [new file with mode: 0644]

index c9803da719c33e87b5a1308310fcd96975c0df7b..5ea8a6a288344768eee2492746a274fa527fe7d5 100644 (file)
@@ -1112,9 +1112,12 @@ def err_explicit_instantiation_without_qualified_id_quals : Error<
   "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<
index 80f366302171bc769a407d73c96ed19e4aa95725..9b46f77c13ef6516227c5c80b9b7439a988f0ada 100644 (file)
@@ -3197,11 +3197,13 @@ public:
 
   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,
index 04580b70b8839dd02226fb6e0dbd962848f6e6cf..aa0c034a55c063ba55f0afeb7ba57cc958e1e45d 100644 (file)
@@ -3657,8 +3657,8 @@ Sema::ActOnExplicitInstantiation(Scope *S,
     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 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
     // 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 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
     // definition.
     if (TSK == TSK_ExplicitInstantiationDefinition)
       InstantiateFunctionDefinition(D.getIdentifierLoc(), Specialization, 
-                                    false);
+                                    false, /*DefinitionRequired=*/true);
       
     Specialization->setTemplateSpecializationKind(TSK);
     break;
index 060cc559833fd2dc83acf35f2ca8055087d580c0..ca05d59abab9435ebfbcae91c2e04fe92900659d 100644 (file)
@@ -1044,9 +1044,14 @@ TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New,
 ///
 /// \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 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
   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 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
 ///
 /// \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 @@ void Sema::InstantiateStaticDataMemberDefinition(
     // 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;
   }
 
index becdd6b606bbcf334ac7cc216b777443c1470767..d7731f17637c9cf915f151a5069116ee4eef7ca8 100644 (file)
@@ -2,7 +2,7 @@
 
 template<typename T>
 struct X {
-  void f();
+  void f() {}
 };
 
 template inline void X<int>::f(); // expected-error{{'inline'}}
index aee0e5d19d5086b039be0f807e55fa215d0e6976..f3d2c955cb5bdb90b2220cef6dd13f9f7cda9904 100644 (file)
@@ -35,7 +35,7 @@ namespace N {
   };
   
   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 (file)
index 0000000..c45df56
--- /dev/null
@@ -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}}
+