r207152 - If we see an explicit instantiation declaration or definition of a function

Richard Smith richard-llvm at metafoo.co.uk
Thu Apr 24 15:45:46 PDT 2014


Author: rsmith
Date: Thu Apr 24 17:45:46 2014
New Revision: 207152

URL: http://llvm.org/viewvc/llvm-project?rev=207152&view=rev
Log:
If we see an explicit instantiation declaration or definition of a function
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.

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

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=207152&r1=207151&r2=207152&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu Apr 24 17:45:46 2014
@@ -7188,6 +7188,7 @@ Sema::ActOnExplicitInstantiation(Scope *
     // 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::ActOnExplicitInstantiat
   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:

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=207152&r1=207151&r2=207152&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Thu Apr 24 17:45:46 2014
@@ -2369,6 +2369,9 @@ Sema::InstantiateClassMembers(SourceLoca
                               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(SourceLoca
                                                    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)) {

Modified: cfe/trunk/test/CodeGenCXX/explicit-instantiation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/explicit-instantiation.cpp?rev=207152&r1=207151&r2=207152&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/explicit-instantiation.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/explicit-instantiation.cpp Thu Apr 24 17:45:46 2014
@@ -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()(co
 // 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 {

Modified: cfe/trunk/test/Modules/Inputs/templates-left.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/templates-left.h?rev=207152&r1=207151&r2=207152&view=diff
==============================================================================
--- cfe/trunk/test/Modules/Inputs/templates-left.h (original)
+++ cfe/trunk/test/Modules/Inputs/templates-left.h Thu Apr 24 17:45:46 2014
@@ -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();
+}

Modified: cfe/trunk/test/Modules/Inputs/templates-top.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/templates-top.h?rev=207152&r1=207151&r2=207152&view=diff
==============================================================================
--- cfe/trunk/test/Modules/Inputs/templates-top.h (original)
+++ cfe/trunk/test/Modules/Inputs/templates-top.h Thu Apr 24 17:45:46 2014
@@ -25,3 +25,7 @@ public:
 template<typename T> struct Outer {
   struct Inner {};
 };
+
+template<bool, bool> struct ExplicitInstantiation {
+  void f() {}
+};

Modified: cfe/trunk/test/Modules/templates.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/templates.mm?rev=207152&r1=207151&r2=207152&view=diff
==============================================================================
--- cfe/trunk/test/Modules/templates.mm (original)
+++ cfe/trunk/test/Modules/templates.mm Thu Apr 24 17:45:46 2014
@@ -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 MergePattern
   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>;





More information about the cfe-commits mailing list