]> granicus.if.org Git - clang/commitdiff
If we see an explicit instantiation declaration or definition of a function
authorRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 24 Apr 2014 22:45:46 +0000 (22:45 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 24 Apr 2014 22:45:46 +0000 (22:45 +0000)
after we've already instantiated a definition for the function, pass it to the
ASTConsumer again so that it knows the specialization kind has changed and can
update the function's linkage.

This only matters if we instantiate the definition of the function before we
reach the end of the TU; this can happen in at least three different ways:
C++11 constexpr functions, C++14 deduced return types, and functions
instantiated within modules.

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

lib/Sema/SemaTemplate.cpp
lib/Sema/SemaTemplateInstantiate.cpp
test/CodeGenCXX/explicit-instantiation.cpp
test/Modules/Inputs/templates-left.h
test/Modules/Inputs/templates-top.h
test/Modules/templates.mm

index 64c3263805135b1498a2821fec2d94030196b90c..fb35f9084f7f2146201be8deb7fa197aaae4df20 100644 (file)
@@ -7188,6 +7188,7 @@ Sema::ActOnExplicitInstantiation(Scope *S,
     // TSK_ExplicitInstantiationDefinition
     if (Old_TSK == TSK_ExplicitInstantiationDeclaration &&
         TSK == TSK_ExplicitInstantiationDefinition)
+      // FIXME: Need to notify the ASTMutationListener that we did this.
       Def->setTemplateSpecializationKind(TSK);
 
     InstantiateClassTemplateSpecializationMembers(TemplateNameLoc, Def, TSK);
@@ -7624,7 +7625,11 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
   if (Attr)
     ProcessDeclAttributeList(S, Specialization, Attr);
 
-  if (TSK == TSK_ExplicitInstantiationDefinition)
+  if (Specialization->isDefined()) {
+    // Let the ASTConsumer know that this function has been explicitly
+    // instantiated now, and its linkage might have changed.
+    Consumer.HandleTopLevelDecl(DeclGroupRef(Specialization));
+  } else if (TSK == TSK_ExplicitInstantiationDefinition)
     InstantiateFunctionDefinition(D.getIdentifierLoc(), Specialization);
 
   // C++0x [temp.explicit]p2:
index 1ee3e4b23a836e9dd0a1e5992cbbf4029ec4d2b1..657ea6488a9e2c666951753b25110400157298a7 100644 (file)
@@ -2369,6 +2369,9 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
                               CXXRecordDecl *Instantiation,
                         const MultiLevelTemplateArgumentList &TemplateArgs,
                               TemplateSpecializationKind TSK) {
+  // FIXME: We need to notify the ASTMutationListener that we did all of these
+  // things, in case we have an explicit instantiation definition in a PCM, a
+  // module, or preamble, and the declaration is in an imported AST.
   assert(
       (TSK == TSK_ExplicitInstantiationDefinition ||
        TSK == TSK_ExplicitInstantiationDeclaration ||
@@ -2393,28 +2396,27 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
                                                    SuppressNew) ||
             SuppressNew)
           continue;
-        
-        if (Function->isDefined())
+
+        // C++11 [temp.explicit]p8:
+        //   An explicit instantiation definition that names a class template
+        //   specialization explicitly instantiates the class template
+        //   specialization and is only an explicit instantiation definition
+        //   of members whose definition is visible at the point of
+        //   instantiation.
+        if (TSK == TSK_ExplicitInstantiationDefinition && !Pattern->isDefined())
           continue;
 
-        if (TSK == TSK_ExplicitInstantiationDefinition) {
-          // C++0x [temp.explicit]p8:
-          //   An explicit instantiation definition that names a class template
-          //   specialization explicitly instantiates the class template 
-          //   specialization and is only an explicit instantiation definition 
-          //   of members whose definition is visible at the point of 
-          //   instantiation.
-          if (!Pattern->isDefined())
-            continue;
-        
-          Function->setTemplateSpecializationKind(TSK, PointOfInstantiation);
-                      
+        Function->setTemplateSpecializationKind(TSK, PointOfInstantiation);
+
+        if (Function->isDefined()) {
+          // Let the ASTConsumer know that this function has been explicitly
+          // instantiated now, and its linkage might have changed.
+          Consumer.HandleTopLevelDecl(DeclGroupRef(Function));
+        } else if (TSK == TSK_ExplicitInstantiationDefinition) {
           InstantiateFunctionDefinition(PointOfInstantiation, Function);
-        } else {
-          Function->setTemplateSpecializationKind(TSK, PointOfInstantiation);
-          if (TSK == TSK_ImplicitInstantiation)
-            PendingLocalImplicitInstantiations.push_back(
-                std::make_pair(Function, PointOfInstantiation));
+        } else if (TSK == TSK_ImplicitInstantiation) {
+          PendingLocalImplicitInstantiations.push_back(
+              std::make_pair(Function, PointOfInstantiation));
         }
       }
     } else if (auto *Var = dyn_cast<VarDecl>(D)) {
index 6a4fd822122fc968b0c175ec1125f85b5d4c2d07..5bd06784cfabb13046f25ec7341a6ba3eba550c7 100644 (file)
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -emit-llvm -triple i686-pc-linux-gnu -o - %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -triple i686-pc-linux-gnu -std=c++1y -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-OPT
+// RUN: %clang_cc1 -emit-llvm -triple i686-pc-linux-gnu -std=c++1y -O3 -disable-llvm-optzns -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-OPT
 
 // This check logically is attached to 'template int S<int>::i;' below.
 // CHECK: @_ZN1SIiE1iE = weak_odr global i32
@@ -16,6 +17,79 @@ Result plus<T, U, Result>::operator()(const T& t, const U& u) const {
 // CHECK-LABEL: define weak_odr i32 @_ZNK4plusIillEclERKiRKl
 template struct plus<int, long, long>;
 
+namespace EarlyInstantiation {
+  // Check that we emit definitions if we instantiate a function definition before
+  // it gets explicitly instantiatied.
+  template<typename T> struct S {
+    constexpr int constexpr_function() { return 0; }
+    auto deduced_return_type() { return 0; }
+  };
+
+  // From an implicit instantiation.
+  constexpr int a = S<char>().constexpr_function();
+  int b = S<char>().deduced_return_type();
+
+  // From an explicit instantiation declaration.
+  extern template struct S<int>;
+  constexpr int c = S<int>().constexpr_function();
+  int d = S<int>().deduced_return_type();
+
+  // CHECK: define weak_odr i32 @_ZN18EarlyInstantiation1SIcE18constexpr_functionEv(
+  // CHECK: define weak_odr i32 @_ZN18EarlyInstantiation1SIcE19deduced_return_typeEv(
+  // CHECK: define weak_odr i32 @_ZN18EarlyInstantiation1SIiE18constexpr_functionEv(
+  // CHECK: define weak_odr i32 @_ZN18EarlyInstantiation1SIiE19deduced_return_typeEv(
+  template struct S<char>;
+  template struct S<int>;
+
+  template<typename T> constexpr int constexpr_function() { return 0; }
+  template<typename T> auto deduced_return_type() { return 0; }
+
+  // From an implicit instantiation.
+  constexpr int e = constexpr_function<char>();
+  int f = deduced_return_type<char>();
+
+  // From an explicit instantiation declaration.
+  extern template int constexpr_function<int>();
+  extern template auto deduced_return_type<int>();
+  constexpr int g = constexpr_function<int>();
+  int h = deduced_return_type<int>();
+
+  // The FIXMEs below are for PR19551.
+  // CHECK: define weak_odr i32 @_ZN18EarlyInstantiation18constexpr_functionIcEEiv(
+  // FIXME: define weak_odr i32 @_ZN18EarlyInstantiation19deduced_return_typeIcEEiv(
+  // CHECK: define weak_odr i32 @_ZN18EarlyInstantiation18constexpr_functionIiEEiv(
+  // FIXME: define weak_odr i32 @_ZN18EarlyInstantiation19deduced_return_typeIiEEiv(
+  template int constexpr_function<char>();
+  // FIXME template auto deduced_return_type<char>();
+  template int constexpr_function<int>();
+  // FIXME template auto deduced_return_type<int>();
+}
+
+namespace LateInstantiation {
+  // Check that we downgrade the linkage to available_externally if we see an
+  // explicit instantiation declaration after the function template is
+  // instantiated.
+  template<typename T> struct S { constexpr int f() { return 0; } };
+  template<typename T> constexpr int f() { return 0; }
+
+  // Trigger eager instantiation of the function definitions.
+  int a, b = S<char>().f() + f<char>() + a;
+  int c, d = S<int>().f() + f<int>() + a;
+
+  // Don't allow some of those definitions to be emitted.
+  extern template struct S<int>;
+  extern template int f<int>();
+
+  // Check that we declare, define, or provide an available-externally
+  // definition as appropriate.
+  // CHECK: define linkonce_odr i32 @_ZN17LateInstantiation1SIcE1fEv(
+  // CHECK: define linkonce_odr i32 @_ZN17LateInstantiation1fIcEEiv(
+  // CHECK-NO-OPT: declare i32 @_ZN17LateInstantiation1SIiE1fEv(
+  // CHECK-NO-OPT: declare i32 @_ZN17LateInstantiation1fIiEEiv(
+  // CHECK-OPT: define available_externally i32 @_ZN17LateInstantiation1SIiE1fEv(
+  // CHECK-OPT: define available_externally i32 @_ZN17LateInstantiation1fIiEEiv(
+}
+
 // Check that we emit definitions from explicit instantiations even when they
 // occur prior to the definition itself.
 template <typename T> struct S {
index c61775b14fafe75a35f1bb13ebd68020d8bf1268..076a1f43c2d30d20d4e6774f169657e3c4e07845 100644 (file)
@@ -41,3 +41,13 @@ int defineListDoubleLeft() {
 }
 
 template<typename T> struct MergePatternDecl;
+
+extern template struct ExplicitInstantiation<false, false>;
+extern template struct ExplicitInstantiation<false, true>;
+extern template struct ExplicitInstantiation<true, false>;
+extern template struct ExplicitInstantiation<true, true>;
+
+void useExplicitInstantiation() {
+  ExplicitInstantiation<true, false>().f();
+  ExplicitInstantiation<true, true>().f();
+}
index 0b13359c23756e45f5bd977705885eb8bbb26c72..144bfcd0efd8f9c1796ce7b25f743c4ca7ececcf 100644 (file)
@@ -25,3 +25,7 @@ public:
 template<typename T> struct Outer {
   struct Inner {};
 };
+
+template<bool, bool> struct ExplicitInstantiation {
+  void f() {}
+};
index fb4303f6a21e8a85301da404f54f45211675417b..feeae85cc12a71545ec63e357534dafd7336dc3f 100644 (file)
@@ -39,6 +39,11 @@ void testRedeclDefinition() {
   redeclDefinitionEmit();
 }
 
+// CHECK-NOT: @_ZN21ExplicitInstantiationILb0ELb0EE1fEv(
+// CHECK: declare {{.*}}@_ZN21ExplicitInstantiationILb1ELb0EE1fEv(
+// CHECK: define {{.*}}@_ZN21ExplicitInstantiationILb1ELb1EE1fEv(
+// CHECK-NOT: @_ZN21ExplicitInstantiationILb0ELb0EE1fEv(
+
 // These three are all the same type.
 typedef OuterIntInner_left OuterIntInner;
 typedef OuterIntInner_right OuterIntInner;
@@ -76,3 +81,6 @@ template<typename T> struct MergePatternDecl {
   void f(Type);
 };
 template<typename T> void MergePatternDecl<T>::f(Type type) {}
+// CHECK: define {{.*}}@_ZN21ExplicitInstantiationILb0ELb1EE1fEv(
+template struct ExplicitInstantiation<false, true>;
+template struct ExplicitInstantiation<true, true>;