]> granicus.if.org Git - clang/commitdiff
Support explicit instantiation of function templates and members of class
authorChandler Carruth <chandlerc@gmail.com>
Wed, 25 Aug 2010 08:27:02 +0000 (08:27 +0000)
committerChandler Carruth <chandlerc@gmail.com>
Wed, 25 Aug 2010 08:27:02 +0000 (08:27 +0000)
templates when only the declaration is in scope. This requires deferring the
instantiation to be lazy, and ensuring the definition is required for that
translation unit. We re-use the existing pending instantiation queue,
previously only used to track implicit instantiations which were required to be
lazy. Fixes PR7979.

A subsequent change will rename *PendingImplicitInstantiations to
*PendingInstatiations for clarity given its broader role.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@112037 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaTemplate.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
test/CXX/temp/temp.spec/temp.explicit/p3.cpp
test/CodeGenCXX/explicit-instantiation.cpp

index 8826b7f370fad9d409acf3185e0aab8c10a37910..e7c506810d6671602ff5ea7d72ec7d7b65661041 100644 (file)
@@ -5071,8 +5071,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
     // Instantiate static data member.
     Prev->setTemplateSpecializationKind(TSK, D.getIdentifierLoc());
     if (TSK == TSK_ExplicitInstantiationDefinition)
-      InstantiateStaticDataMemberDefinition(D.getIdentifierLoc(), Prev, false,
-                                            /*DefinitionRequired=*/true);
+      InstantiateStaticDataMemberDefinition(D.getIdentifierLoc(), Prev);
     
     // FIXME: Create an ExplicitInstantiation node?
     return (Decl*) 0;
@@ -5179,8 +5178,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
   Specialization->setTemplateSpecializationKind(TSK, D.getIdentifierLoc());
   
   if (TSK == TSK_ExplicitInstantiationDefinition)
-    InstantiateFunctionDefinition(D.getIdentifierLoc(), Specialization, 
-                                  false, /*DefinitionRequired=*/true);
+    InstantiateFunctionDefinition(D.getIdentifierLoc(), Specialization);
  
   // C++0x [temp.explicit]p2:
   //   If the explicit instantiation is for a member function, a member class 
index 39d7f234099f2feacf3b56b3052673e50d40064d..dd82114f2b034287e0cc789418148e7ab6a52644 100644 (file)
@@ -2040,8 +2040,12 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
         Diag(PatternDecl->getLocation(), 
              diag::note_explicit_instantiation_here);
       Function->setInvalidDecl();
+    } else if (Function->getTemplateSpecializationKind()
+                 == TSK_ExplicitInstantiationDefinition) {
+      PendingImplicitInstantiations.push_back(
+        std::make_pair(Function, PointOfInstantiation));
     }
-      
+
     return;
   }
 
@@ -2176,8 +2180,12 @@ void Sema::InstantiateStaticDataMemberDefinition(
            diag::err_explicit_instantiation_undefined_member)
         << 2 << Var->getDeclName() << Var->getDeclContext();
       Diag(Def->getLocation(), diag::note_explicit_instantiation_here);
-    }    
-    
+    } else if (Var->getTemplateSpecializationKind()
+                 == TSK_ExplicitInstantiationDefinition) {
+      PendingImplicitInstantiations.push_back(
+        std::make_pair(Var, PointOfInstantiation));
+    }
+
     return;
   }
 
@@ -2714,8 +2722,10 @@ void Sema::PerformPendingImplicitInstantiations(bool LocalOnly) {
                                             Function->getLocation(), *this,
                                             Context.getSourceManager(),
                                            "instantiating function definition");
-
-      InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true);
+      bool DefinitionRequired = Function->getTemplateSpecializationKind() ==
+                                TSK_ExplicitInstantiationDefinition;
+      InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true,
+                                    DefinitionRequired);
       continue;
     }
 
@@ -2734,9 +2744,12 @@ void Sema::PerformPendingImplicitInstantiations(bool LocalOnly) {
     case TSK_Undeclared:
       assert(false && "Cannot instantitiate an undeclared specialization.");
     case TSK_ExplicitInstantiationDeclaration:
-    case TSK_ExplicitInstantiationDefinition:
     case TSK_ExplicitSpecialization:
-      continue;  // No longer need implicit instantiation.
+      continue;  // No longer need to instantiate this type.
+    case TSK_ExplicitInstantiationDefinition:
+      // We only need an instantiation if the pending instantiation *is* the
+      // explicit instantiation.
+      if (Var != Var->getMostRecentDeclaration()) continue;
     case TSK_ImplicitInstantiation:
       break;
     }
@@ -2746,7 +2759,10 @@ void Sema::PerformPendingImplicitInstantiations(bool LocalOnly) {
                                           "instantiating static data member "
                                           "definition");
 
-    InstantiateStaticDataMemberDefinition(/*FIXME:*/Inst.second, Var, true);
+    bool DefinitionRequired = Var->getTemplateSpecializationKind() ==
+                              TSK_ExplicitInstantiationDefinition;
+    InstantiateStaticDataMemberDefinition(/*FIXME:*/Inst.second, Var, true,
+                                          DefinitionRequired);
   }
 }
 
index e9758bcdec2c9899ac8b6f10ae74e0fcd7232c1b..48c42c399a4688ca1df756f29ec9481f8da91821 100644 (file)
@@ -2,8 +2,9 @@
 
 // A declaration of a function template shall be in scope at the point of the 
 // explicit instantiation of the function template.
-template<typename T> void f0(T) { }
+template<typename T> void f0(T);
 template void f0(int); // okay
+template<typename T> void f0(T) { }
 
 // A definition of the class or class template containing a member function 
 // template shall be in scope at the point of the explicit instantiation of 
@@ -47,3 +48,27 @@ template X2<int>::X2(); // expected-error{{not an instantiation}}
 template X2<int>::X2(const X2&); // expected-error{{not an instantiation}}
 template X2<int>::~X2(); // expected-error{{not an instantiation}}
 template X2<int> &X2<int>::operator=(const X2<int>&); // expected-error{{not an instantiation}}
+
+
+// A definition of a class template is sufficient to explicitly
+// instantiate a member of the class template which itself is not yet defined.
+namespace PR7979 {
+  template <typename T> struct S {
+    void f();
+    static void g();
+    static int i;
+    struct S2 {
+      void h();
+    };
+  };
+
+  template void S<int>::f();
+  template void S<int>::g();
+  template int S<int>::i;
+  template void S<int>::S2::h();
+
+  template <typename T> void S<T>::f() {}
+  template <typename T> void S<T>::g() {}
+  template <typename T> int S<T>::i;
+  template <typename T> void S<T>::S2::h() {}
+}
index 24d1a67392290b89382dd0729150793c44de7e7f..b82958568a8ac648023f41b6b4c5813aaceb3d75 100644 (file)
@@ -1,5 +1,8 @@
 // RUN: %clang_cc1 -emit-llvm -triple i686-pc-linux-gnu -o - %s | FileCheck %s
 
+// This check logically is attached to 'template int S<int>::i;' below.
+// CHECK: @_ZN1SIiE1iE = weak global i32
+
 template<typename T, typename U, typename Result>
 struct plus {
   Result operator()(const T& t, const U& u) const;
@@ -12,3 +15,31 @@ Result plus<T, U, Result>::operator()(const T& t, const U& u) const {
 
 // CHECK: define weak_odr i32 @_ZNK4plusIillEclERKiRKl
 template struct plus<int, long, long>;
+
+// Check that we emit definitions from explicit instantiations even when they
+// occur prior to the definition itself.
+template <typename T> struct S {
+  void f();
+  static void g();
+  static int i;
+  struct S2 {
+    void h();
+  };
+};
+
+// CHECK: define weak_odr void @_ZN1SIiE1fEv
+template void S<int>::f();
+
+// CHECK: define weak_odr void @_ZN1SIiE1gEv
+template void S<int>::g();
+
+// See the check line at the top of the file.
+template int S<int>::i;
+
+// CHECK: define weak_odr void @_ZN1SIiE2S21hEv
+template void S<int>::S2::h();
+
+template <typename T> void S<T>::f() {}
+template <typename T> void S<T>::g() {}
+template <typename T> int S<T>::i;
+template <typename T> void S<T>::S2::h() {}