diff options
Diffstat (limited to 'lib/CodeGen')
-rw-r--r-- | lib/CodeGen/CGCXXABI.cpp | 3 | ||||
-rw-r--r-- | lib/CodeGen/CGCXXABI.h | 4 | ||||
-rw-r--r-- | lib/CodeGen/CGDecl.cpp | 20 | ||||
-rw-r--r-- | lib/CodeGen/CGDeclCXX.cpp | 27 | ||||
-rw-r--r-- | lib/CodeGen/CGExprConstant.cpp | 9 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.h | 9 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenModule.cpp | 18 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenModule.h | 5 | ||||
-rw-r--r-- | lib/CodeGen/ItaniumCXXABI.cpp | 7 |
9 files changed, 75 insertions, 27 deletions
diff --git a/lib/CodeGen/CGCXXABI.cpp b/lib/CodeGen/CGCXXABI.cpp index c1b20af799..e5d3f2da6b 100644 --- a/lib/CodeGen/CGCXXABI.cpp +++ b/lib/CodeGen/CGCXXABI.cpp @@ -168,6 +168,7 @@ void CGCXXABI::ReadArrayCookie(CodeGenFunction &CGF, llvm::Value *Ptr, void CGCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D, - llvm::GlobalVariable *GV) { + llvm::GlobalVariable *GV, + bool PerformInit) { ErrorUnsupportedABI(CGF, "static local variable initialization"); } diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h index 5e21bb0c9f..4bacd01403 100644 --- a/lib/CodeGen/CGCXXABI.h +++ b/lib/CodeGen/CGCXXABI.h @@ -226,12 +226,14 @@ public: /// Emits the guarded initializer and destructor setup for the given /// variable, given that it couldn't be emitted as a constant. + /// If \p PerformInit is false, the initialization has been folded to a + /// constant and should not be performed. /// /// The variable may be: /// - a static local variable /// - a static data member of a class template instantiation virtual void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D, - llvm::GlobalVariable *DeclPtr); + llvm::GlobalVariable *DeclPtr, bool PerformInit); }; diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 3d32091a4b..2de19840e5 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -196,6 +196,14 @@ CodeGenFunction::CreateStaticVarDecl(const VarDecl &D, return GV; } +/// hasNontrivialDestruction - Determine whether a type's destruction is +/// non-trivial. If so, and the variable uses static initialization, we must +/// register its destructor to run on exit. +static bool hasNontrivialDestruction(QualType T) { + CXXRecordDecl *RD = T->getBaseElementTypeUnsafe()->getAsCXXRecordDecl(); + return RD && !RD->hasTrivialDestructor(); +} + /// AddInitializerToStaticVarDecl - Add the initializer for 'D' to the /// global variable that has already been created for it. If the initializer /// has a different type than GV does, this may free GV and return a different @@ -215,7 +223,7 @@ CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D, // be constant. GV->setConstant(false); - EmitCXXGuardedInit(D, GV); + EmitCXXGuardedInit(D, GV, /*PerformInit*/true); } return GV; } @@ -248,6 +256,16 @@ CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D, } GV->setInitializer(Init); + + if (hasNontrivialDestruction(D.getType())) { + // We have a constant initializer, but a nontrivial destructor. We still + // need to perform a guarded "initialization" in order to register the + // destructor. Since we're running a destructor on this variable, it can't + // be a constant even if it's const. + GV->setConstant(false); + EmitCXXGuardedInit(D, GV, /*PerformInit*/false); + } + return GV; } diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp index 8406002e5a..44acf62aa6 100644 --- a/lib/CodeGen/CGDeclCXX.cpp +++ b/lib/CodeGen/CGDeclCXX.cpp @@ -102,17 +102,21 @@ static void EmitDeclDestroy(CodeGenFunction &CGF, const VarDecl &D, } void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D, - llvm::Constant *DeclPtr) { + llvm::Constant *DeclPtr, + bool PerformInit) { const Expr *Init = D.getInit(); QualType T = D.getType(); if (!T->isReferenceType()) { - EmitDeclInit(*this, D, DeclPtr); + if (PerformInit) + EmitDeclInit(*this, D, DeclPtr); EmitDeclDestroy(*this, D, DeclPtr); return; } + assert(PerformInit && "cannot have constant initializer which needs " + "destruction for reference"); unsigned Alignment = getContext().getDeclAlign(&D).getQuantity(); RValue RV = EmitReferenceBindingToExpr(Init, &D); EmitStoreOfScalar(RV.getScalarVal(), DeclPtr, false, Alignment, T); @@ -152,7 +156,8 @@ CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn, } void CodeGenFunction::EmitCXXGuardedInit(const VarDecl &D, - llvm::GlobalVariable *DeclPtr) { + llvm::GlobalVariable *DeclPtr, + bool PerformInit) { // If we've been asked to forbid guard variables, emit an error now. // This diagnostic is hard-coded for Darwin's use case; we can find // better phrasing if someone else needs it. @@ -161,7 +166,7 @@ void CodeGenFunction::EmitCXXGuardedInit(const VarDecl &D, "this initialization requires a guard variable, which " "the kernel does not support"); - CGM.getCXXABI().EmitGuardedInit(*this, D, DeclPtr); + CGM.getCXXABI().EmitGuardedInit(*this, D, DeclPtr, PerformInit); } static llvm::Function * @@ -186,14 +191,16 @@ CreateGlobalInitOrDestructFunction(CodeGenModule &CGM, void CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D, - llvm::GlobalVariable *Addr) { + llvm::GlobalVariable *Addr, + bool PerformInit) { llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false); // Create a variable initialization function. llvm::Function *Fn = CreateGlobalInitOrDestructFunction(*this, FTy, "__cxx_global_var_init"); - CodeGenFunction(*this).GenerateCXXGlobalVarDeclInitFunc(Fn, D, Addr); + CodeGenFunction(*this).GenerateCXXGlobalVarDeclInitFunc(Fn, D, Addr, + PerformInit); if (D->hasAttr<InitPriorityAttr>()) { unsigned int order = D->getAttr<InitPriorityAttr>()->getPriority(); @@ -267,7 +274,8 @@ void CodeGenModule::EmitCXXGlobalDtorFunc() { /// Emit the code necessary to initialize the given global variable. void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn, const VarDecl *D, - llvm::GlobalVariable *Addr) { + llvm::GlobalVariable *Addr, + bool PerformInit) { StartFunction(GlobalDecl(), getContext().VoidTy, Fn, getTypes().getNullaryFunctionInfo(), FunctionArgList(), SourceLocation()); @@ -277,9 +285,9 @@ void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn, // definitions explicitly marked weak. if (Addr->getLinkage() == llvm::GlobalValue::WeakODRLinkage || Addr->getLinkage() == llvm::GlobalValue::WeakAnyLinkage) { - EmitCXXGuardedInit(*D, Addr); + EmitCXXGuardedInit(*D, Addr, PerformInit); } else { - EmitCXXGlobalVarDeclInit(*D, Addr); + EmitCXXGlobalVarDeclInit(*D, Addr, PerformInit); } FinishFunction(); @@ -357,4 +365,3 @@ CodeGenFunction::generateDestroyHelper(llvm::Constant *addr, return fn; } - diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index ccb4b930e6..0b3ac9cbe5 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -939,6 +939,15 @@ llvm::Constant *CodeGenModule::EmitConstantInit(const VarDecl &D, if (const APValue *Value = D.evaluateValue()) return EmitConstantValue(*Value, D.getType(), CGF); + // FIXME: Implement C++11 [basic.start.init]p2: if the initializer of a + // reference is a constant expression, and the reference binds to a temporary, + // then constant initialization is performed. ConstExprEmitter will + // incorrectly emit a prvalue constant in this case, and the calling code + // interprets that as the (pointer) value of the reference, rather than the + // desired value of the referee. + if (D.getType()->isReferenceType()) + return 0; + const Expr *E = D.getInit(); assert(E && "No initializer to emit"); diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 277640b8ce..ca5b88363e 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -2361,7 +2361,8 @@ public: /// EmitCXXGlobalVarDeclInit - Create the initializer for a C++ /// variable with global storage. - void EmitCXXGlobalVarDeclInit(const VarDecl &D, llvm::Constant *DeclPtr); + void EmitCXXGlobalVarDeclInit(const VarDecl &D, llvm::Constant *DeclPtr, + bool PerformInit); /// EmitCXXGlobalDtorRegistration - Emits a call to register the global ptr /// with the C++ runtime so that its destructor will be called at exit. @@ -2373,7 +2374,8 @@ public: /// possible to prove that an initialization will be done exactly /// once, e.g. with a static local variable or a static data member /// of a class template. - void EmitCXXGuardedInit(const VarDecl &D, llvm::GlobalVariable *DeclPtr); + void EmitCXXGuardedInit(const VarDecl &D, llvm::GlobalVariable *DeclPtr, + bool PerformInit); /// GenerateCXXGlobalInitFunc - Generates code for initializing global /// variables. @@ -2389,7 +2391,8 @@ public: void GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn, const VarDecl *D, - llvm::GlobalVariable *Addr); + llvm::GlobalVariable *Addr, + bool PerformInit); void EmitCXXConstructExpr(const CXXConstructExpr *E, AggValueSlot Dest); diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index fde217efec..2ebea59264 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -1359,7 +1359,9 @@ CharUnits CodeGenModule::GetTargetTypeStoreSize(llvm::Type *Ty) const { void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { llvm::Constant *Init = 0; QualType ASTTy = D->getType(); - bool NonConstInit = false; + CXXRecordDecl *RD = ASTTy->getBaseElementTypeUnsafe()->getAsCXXRecordDecl(); + bool NeedsGlobalCtor = false; + bool NeedsGlobalDtor = RD && !RD->hasTrivialDestructor(); const VarDecl *InitDecl; const Expr *InitExpr = D->getAnyInitializer(InitDecl); @@ -1385,15 +1387,16 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { if (getLangOptions().CPlusPlus) { Init = EmitNullConstant(T); - NonConstInit = true; + NeedsGlobalCtor = true; } else { ErrorUnsupported(D, "static initializer"); Init = llvm::UndefValue::get(getTypes().ConvertType(T)); } } else { // We don't need an initializer, so remove the entry for the delayed - // initializer position (just in case this entry was delayed). - if (getLangOptions().CPlusPlus) + // initializer position (just in case this entry was delayed) if we + // also don't need to register a destructor. + if (getLangOptions().CPlusPlus && !NeedsGlobalDtor) DelayedCXXInitPosition.erase(D); } } @@ -1448,7 +1451,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { // If it is safe to mark the global 'constant', do so now. GV->setConstant(false); - if (!NonConstInit && DeclIsConstantGlobal(Context, D, true)) + if (!NeedsGlobalCtor && !NeedsGlobalDtor && + DeclIsConstantGlobal(Context, D, true)) GV->setConstant(true); GV->setAlignment(getContext().getDeclAlign(D).getQuantity()); @@ -1464,8 +1468,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { SetCommonAttributes(D, GV); // Emit the initializer function if necessary. - if (NonConstInit) - EmitCXXGlobalVarDeclInitFunc(D, GV); + if (NeedsGlobalCtor || NeedsGlobalDtor) + EmitCXXGlobalVarDeclInitFunc(D, GV, NeedsGlobalCtor); // Emit global variable debug information. if (CGDebugInfo *DI = getModuleDebugInfo()) diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 08e1ed7fb1..6813edd5f1 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -900,8 +900,11 @@ private: /// EmitCXXGlobalDtorFunc - Emit the function that destroys C++ globals. void EmitCXXGlobalDtorFunc(); + /// EmitCXXGlobalVarDeclInitFunc - Emit the function that initializes the + /// specified global (if PerformInit is true) and registers its destructor. void EmitCXXGlobalVarDeclInitFunc(const VarDecl *D, - llvm::GlobalVariable *Addr); + llvm::GlobalVariable *Addr, + bool PerformInit); // FIXME: Hardcoding priority here is gross. void AddGlobalCtor(llvm::Function *Ctor, int Priority=65535); diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index 044b7f0532..8dee17a38c 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -121,7 +121,7 @@ public: llvm::Value *&AllocPtr, CharUnits &CookieSize); void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D, - llvm::GlobalVariable *DeclPtr); + llvm::GlobalVariable *DeclPtr, bool PerformInit); }; class ARMCXXABI : public ItaniumCXXABI { @@ -1016,7 +1016,8 @@ namespace { /// just special-case it at particular places. void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D, - llvm::GlobalVariable *GV) { + llvm::GlobalVariable *GV, + bool PerformInit) { CGBuilderTy &Builder = CGF.Builder; // We only need to use thread-safe statics for local variables; @@ -1129,7 +1130,7 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, } // Emit the initializer and add a global destructor if appropriate. - CGF.EmitCXXGlobalVarDeclInit(D, GV); + CGF.EmitCXXGlobalVarDeclInit(D, GV, PerformInit); if (threadsafe) { // Pop the guard-abort cleanup if we pushed one. |