From d65179533012c1ab7323c6353c0a14bf424df6af Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Wed, 15 Apr 2015 01:08:06 +0000 Subject: [PATCH] Move the logic to avoid double global emission from Sema to CodeGen 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 | 21 ++++++++++++--------- lib/CodeGen/CodeGenModule.h | 3 ++- lib/Sema/SemaTemplateInstantiateDecl.cpp | 21 +++++++-------------- test/CodeGenCXX/auto-variable-template.cpp | 14 ++++++++++++++ 4 files changed, 35 insertions(+), 24 deletions(-) create mode 100644 test/CodeGenCXX/auto-variable-template.cpp diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp index 236337b403..eb4ddc704d 100644 --- a/lib/CodeGen/CGDeclCXX.cpp +++ b/lib/CodeGen/CGDeclCXX.cpp @@ -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()) { 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()) { // 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::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() { diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index e5e52b5e7b..feef6c2583 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -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 DelayedCXXInitPosition; typedef std::pair GlobalInitData; diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 014400822c..6936539f1c 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -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 index 0000000000..265d81dd35 --- /dev/null +++ b/test/CodeGenCXX/auto-variable-template.cpp @@ -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 auto vtemplate = f{}; + +int main() { vtemplate(); } + +// CHECK: @_Z9vtemplateIiE = linkonce_odr global %struct.f undef, comdat + +// CHECK: define i32 @main() +// CHECK: call void @_ZNK1fclEv(%struct.f* @_Z9vtemplateIiE) -- 2.40.0