aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/CodeGen/CGCXX.cpp82
-rw-r--r--lib/CodeGen/CGDecl.cpp2
-rw-r--r--lib/CodeGen/CodeGenFunction.h15
-rw-r--r--lib/Sema/SemaDecl.cpp2
-rw-r--r--test/CodeGenCXX/static-init.cpp13
5 files changed, 97 insertions, 17 deletions
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp
index a1ea6bf76a..bed6785ef1 100644
--- a/lib/CodeGen/CGCXX.cpp
+++ b/lib/CodeGen/CGCXX.cpp
@@ -26,8 +26,74 @@ using namespace clang;
using namespace CodeGen;
void
-CodeGenFunction::GenerateStaticCXXBlockVarDeclInit(const VarDecl &D,
- llvm::GlobalVariable *GV) {
+CodeGenFunction::EmitCXXGlobalDtorRegistration(const CXXDestructorDecl *Dtor,
+ llvm::Constant *DeclPtr) {
+ // FIXME: This is ABI dependent and we use the Itanium ABI.
+
+ const llvm::Type *Int8PtrTy =
+ llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+
+ std::vector<const llvm::Type *> Params;
+ Params.push_back(Int8PtrTy);
+
+ // Get the destructor function type
+ const llvm::Type *DtorFnTy =
+ llvm::FunctionType::get(llvm::Type::VoidTy, Params, false);
+ DtorFnTy = llvm::PointerType::getUnqual(DtorFnTy);
+
+ Params.clear();
+ Params.push_back(DtorFnTy);
+ Params.push_back(Int8PtrTy);
+ Params.push_back(Int8PtrTy);
+
+ // Get the __cxa_atexit function type
+ // extern "C" int __cxa_atexit ( void (*f)(void *), void *p, void *d );
+ const llvm::FunctionType *AtExitFnTy =
+ llvm::FunctionType::get(ConvertType(getContext().IntTy), Params, false);
+
+ llvm::Constant *AtExitFn = CGM.CreateRuntimeFunction(AtExitFnTy,
+ "__cxa_atexit");
+
+ llvm::Constant *Handle = CGM.CreateRuntimeVariable(Int8PtrTy,
+ "__dso_handle");
+
+ llvm::Constant *DtorFn = CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete);
+
+ llvm::Value *Args[3] = { llvm::ConstantExpr::getBitCast(DtorFn, DtorFnTy),
+ llvm::ConstantExpr::getBitCast(DeclPtr, Int8PtrTy),
+ llvm::ConstantExpr::getBitCast(Handle, Int8PtrTy) };
+ Builder.CreateCall(AtExitFn, &Args[0], llvm::array_endof(Args));
+}
+
+void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D,
+ llvm::Constant *DeclPtr) {
+ assert(D.hasGlobalStorage() &&
+ "VarDecl must have global storage!");
+
+ const Expr *Init = D.getInit();
+ QualType T = D.getType();
+
+ if (T->isReferenceType()) {
+ ErrorUnsupported(Init, "Global variable that binds to a reference");
+ } else if (!hasAggregateLLVMType(T)) {
+ llvm::Value *V = EmitScalarExpr(Init);
+ EmitStoreOfScalar(V, DeclPtr, T.isVolatileQualified(), T);
+ } else if (T->isAnyComplexType()) {
+ EmitComplexExprIntoAddr(Init, DeclPtr, T.isVolatileQualified());
+ } else {
+ EmitAggExpr(Init, DeclPtr, T.isVolatileQualified());
+
+ if (const RecordType *RT = T->getAs<RecordType>()) {
+ CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+ if (!RD->hasTrivialDestructor())
+ EmitCXXGlobalDtorRegistration(RD->getDestructor(getContext()), DeclPtr);
+ }
+ }
+}
+
+void
+CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D,
+ llvm::GlobalVariable *GV) {
// FIXME: This should use __cxa_guard_{acquire,release}?
assert(!getContext().getLangOptions().ThreadsafeStatics &&
@@ -61,16 +127,8 @@ CodeGenFunction::GenerateStaticCXXBlockVarDeclInit(const VarDecl &D,
EmitBlock(InitBlock);
- const Expr *Init = D.getInit();
- if (!hasAggregateLLVMType(Init->getType())) {
- llvm::Value *V = EmitScalarExpr(Init);
- Builder.CreateStore(V, GV, D.getType().isVolatileQualified());
- } else if (Init->getType()->isAnyComplexType()) {
- EmitComplexExprIntoAddr(Init, GV, D.getType().isVolatileQualified());
- } else {
- EmitAggExpr(Init, GV, D.getType().isVolatileQualified());
- }
-
+ EmitCXXGlobalVarDeclInit(D, GV);
+
Builder.CreateStore(llvm::ConstantInt::get(llvm::Type::Int8Ty, 1),
Builder.CreateBitCast(GuardV, PtrTy));
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 477cf52aad..d3b7db089b 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -140,7 +140,7 @@ void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D) {
if (!getContext().getLangOptions().CPlusPlus)
CGM.ErrorUnsupported(D.getInit(), "constant l-value expression");
else
- GenerateStaticCXXBlockVarDeclInit(D, GV);
+ EmitStaticCXXBlockVarDeclInit(D, GV);
} else {
// The initializer may differ in type from the global. Rewrite
// the global to match the initializer. (We have to do this
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index 6e4d9ec891..da88b53352 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -887,11 +887,20 @@ public:
llvm::GlobalValue::LinkageTypes
Linkage);
- /// GenerateStaticCXXBlockVarDecl - Create the initializer for a C++
+ /// EmitStaticCXXBlockVarDeclInit - Create the initializer for a C++
/// runtime initialized static block var decl.
- void GenerateStaticCXXBlockVarDeclInit(const VarDecl &D,
- llvm::GlobalVariable *GV);
+ void EmitStaticCXXBlockVarDeclInit(const VarDecl &D,
+ llvm::GlobalVariable *GV);
+ /// EmitCXXGlobalVarDeclInit - Create the initializer for a C++
+ /// variable with global storage.
+ void EmitCXXGlobalVarDeclInit(const VarDecl &D, llvm::Constant *DeclPtr);
+
+ /// EmitCXXGlobalDtorRegistration - Emits a call to register the global ptr
+ /// with the C++ runtime so that its destructor will be called at exit.
+ void EmitCXXGlobalDtorRegistration(const CXXDestructorDecl *Dtor,
+ llvm::Constant *DeclPtr);
+
void EmitCXXConstructExpr(llvm::Value *Dest, const CXXConstructExpr *E);
RValue EmitCXXExprWithTemporaries(const CXXExprWithTemporaries *E,
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 44e8b44d7a..aac79e9fc7 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -3227,7 +3227,7 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl,
if (!Constructor)
Var->setInvalidDecl();
else {
- if (!RD->hasTrivialConstructor())
+ if (!RD->hasTrivialConstructor() || !RD->hasTrivialDestructor())
InitializeVarWithConstructor(Var, Constructor, InitType, 0, 0);
FinalizeVarWithDestructor(Var, InitType);
}
diff --git a/test/CodeGenCXX/static-init.cpp b/test/CodeGenCXX/static-init.cpp
new file mode 100644
index 0000000000..2d0b4b0c77
--- /dev/null
+++ b/test/CodeGenCXX/static-init.cpp
@@ -0,0 +1,13 @@
+// RUN: clang-cc -triple=x86_64-apple-darwin9 -emit-llvm %s -o %t &&
+// RUN: grep "call void @_ZN1AC1Ev" %t | count 1 &&
+// RUN: grep "call i32 @__cxa_atexit(void (i8\*)\* bitcast (void (%.truct.A\*)\* @_ZN1AD1Ev to void (i8\*)\*), i8\* getelementptr (%.truct.A\* @_ZZ1fvE1a, i32 0, i32 0), i8\* bitcast (i8\*\* @__dso_handle to i8\*))" %t | count 1
+
+struct A {
+ A();
+ ~A();
+};
+
+void f() {
+ static A a;
+}
+