]> granicus.if.org Git - clang/commitdiff
Move the logic to avoid double global emission from Sema to CodeGen
authorReid Kleckner <reid@kleckner.net>
Wed, 15 Apr 2015 01:08:06 +0000 (01:08 +0000)
committerReid Kleckner <reid@kleckner.net>
Wed, 15 Apr 2015 01:08:06 +0000 (01:08 +0000)
Reverts the code changes from r234675 but keeps the test case.

We were already maintaining a DenseMap of globals with dynamic
initializers anyway.

Fixes the test case from PR23234.

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

lib/CodeGen/CGDeclCXX.cpp
lib/CodeGen/CodeGenModule.h
lib/Sema/SemaTemplateInstantiateDecl.cpp
test/CodeGenCXX/auto-variable-template.cpp [new file with mode: 0644]

index 236337b4034d82d7d8ca0ea04cc83339e8a01d91..eb4ddc704d13a5d8463c3bcecdd7db1f9728b3fd 100644 (file)
@@ -298,6 +298,11 @@ void
 CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
                                             llvm::GlobalVariable *Addr,
                                             bool PerformInit) {
+  // Check if we've already initialized this decl.
+  auto I = DelayedCXXInitPosition.find(D);
+  if (I != DelayedCXXInitPosition.end() && I->second == ~0U)
+    return;
+
   llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
   SmallString<256> FnName;
   {
@@ -327,11 +332,9 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
     CXXThreadLocalInitVars.push_back(Addr);
   } else if (PerformInit && ISA) {
     EmitPointerToInitFunc(D, Addr, Fn, ISA);
-    DelayedCXXInitPosition.erase(D);
   } else if (auto *IPA = D->getAttr<InitPriorityAttr>()) {
     OrderGlobalInits Key(IPA->getPriority(), PrioritizedCXXGlobalInits.size());
     PrioritizedCXXGlobalInits.push_back(std::make_pair(Key, Fn));
-    DelayedCXXInitPosition.erase(D);
   } else if (isTemplateInstantiation(D->getTemplateSpecializationKind())) {
     // C++ [basic.start.init]p2:
     //   Definitions of explicitly specialized class template static data
@@ -346,24 +349,24 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
     // minor startup time optimization.  In the MS C++ ABI, there are no guard
     // variables, so this COMDAT key is required for correctness.
     AddGlobalCtor(Fn, 65535, COMDATKey);
-    DelayedCXXInitPosition.erase(D);
   } else if (D->hasAttr<SelectAnyAttr>()) {
     // SelectAny globals will be comdat-folded. Put the initializer into a
     // COMDAT group associated with the global, so the initializers get folded
     // too.
     AddGlobalCtor(Fn, 65535, COMDATKey);
-    DelayedCXXInitPosition.erase(D);
   } else {
-    llvm::DenseMap<const Decl *, unsigned>::iterator I =
-      DelayedCXXInitPosition.find(D);
+    I = DelayedCXXInitPosition.find(D); // Re-do lookup in case of re-hash.
     if (I == DelayedCXXInitPosition.end()) {
       CXXGlobalInits.push_back(Fn);
-    } else {
-      assert(CXXGlobalInits[I->second] == nullptr);
+    } else if (I->second != ~0U) {
+      assert(I->second < CXXGlobalInits.size() &&
+             CXXGlobalInits[I->second] == nullptr);
       CXXGlobalInits[I->second] = Fn;
-      DelayedCXXInitPosition.erase(I);
     }
   }
+
+  // Remember that we already emitted the initializer for this global.
+  DelayedCXXInitPosition[D] = ~0U;
 }
 
 void CodeGenModule::EmitCXXThreadLocalInitFunc() {
index e5e52b5e7baf221f684282b430b322c49deee699..feef6c2583ec38cd5c1bafc5985dc951d9ce855f 100644 (file)
@@ -400,7 +400,8 @@ private:
   /// When a C++ decl with an initializer is deferred, null is
   /// appended to CXXGlobalInits, and the index of that null is placed
   /// here so that the initializer will be performed in the correct
-  /// order.
+  /// order. Once the decl is emitted, the index is replaced with ~0U to ensure
+  /// that we don't re-emit the initializer.
   llvm::DenseMap<const Decl*, unsigned> DelayedCXXInitPosition;
   
   typedef std::pair<OrderGlobalInits, llvm::Function*> GlobalInitData;
index 014400822c3b32ea50a402758b2705fe5489c310..6936539f1caaa5a19712933e84d39c932706c067 100644 (file)
@@ -3865,17 +3865,6 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
   if (TSK == TSK_ExplicitInstantiationDeclaration)
     return;
 
-  // We may be explicitly instantiating something we've already implicitly
-  // instantiated.
-  VarDecl *InstantiatedDef = Var->getDefinition();
-  if (InstantiatedDef)
-    InstantiatedDef->setTemplateSpecializationKind(TSK, PointOfInstantiation);
-
-  // If we've already instantiated the definition and we're not
-  // re-instantiating it explicitly, we don't need to do anything.
-  if (InstantiatedDef && TSK != TSK_ExplicitInstantiationDefinition)
-    return;
-
   // Make sure to pass the instantiated variable to the consumer at the end.
   struct PassToConsumerRAII {
     ASTConsumer &Consumer;
@@ -3889,10 +3878,14 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
     }
   } PassToConsumerRAII(Consumer, Var);
 
-  // If we already implicitly instantiated this, just let the consumer know that
-  // it needs to handle an explicit instantiation now.
-  if (InstantiatedDef && TSK == TSK_ExplicitInstantiationDefinition)
+  // If we already have a definition, we're done.
+  if (VarDecl *Def = Var->getDefinition()) {
+    // We may be explicitly instantiating something we've already implicitly
+    // instantiated.
+    Def->setTemplateSpecializationKind(Var->getTemplateSpecializationKind(),
+                                       PointOfInstantiation);
     return;
+  }
 
   InstantiatingTemplate Inst(*this, PointOfInstantiation, Var);
   if (Inst.isInvalid())
diff --git a/test/CodeGenCXX/auto-variable-template.cpp b/test/CodeGenCXX/auto-variable-template.cpp
new file mode 100644 (file)
index 0000000..265d81d
--- /dev/null
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -std=c++14 %s -triple=x86_64-linux -emit-llvm -o - | FileCheck %s
+
+struct f {
+  void operator()() const {}
+};
+
+template <typename T> auto vtemplate = f{};
+
+int main() { vtemplate<int>(); }
+
+// CHECK: @_Z9vtemplateIiE = linkonce_odr global %struct.f undef, comdat
+
+// CHECK: define i32 @main()
+// CHECK: call void @_ZNK1fclEv(%struct.f* @_Z9vtemplateIiE)