diff options
-rw-r--r-- | lib/CodeGen/CGCXX.cpp | 70 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.h | 6 | ||||
-rw-r--r-- | test/CodeGenCXX/global-array-destruction.cpp | 33 |
3 files changed, 101 insertions, 8 deletions
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index 56b38e57e3..bb8041f567 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -27,7 +27,7 @@ using namespace clang; using namespace CodeGen; void -CodeGenFunction::EmitCXXGlobalDtorRegistration(const CXXDestructorDecl *Dtor, +CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn, llvm::Constant *DeclPtr) { const llvm::Type *Int8PtrTy = llvm::Type::getInt8Ty(VMContext)->getPointerTo(); @@ -55,9 +55,6 @@ CodeGenFunction::EmitCXXGlobalDtorRegistration(const CXXDestructorDecl *Dtor, 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) }; @@ -82,11 +79,26 @@ void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D, EmitComplexExprIntoAddr(Init, DeclPtr, isVolatile); } else { EmitAggExpr(Init, DeclPtr, isVolatile); - + const ConstantArrayType *Array = getContext().getAsConstantArrayType(T); + if (Array) + T = getContext().getBaseElementType(Array); + if (const RecordType *RT = T->getAs<RecordType>()) { CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); - if (!RD->hasTrivialDestructor()) - EmitCXXGlobalDtorRegistration(RD->getDestructor(getContext()), DeclPtr); + if (!RD->hasTrivialDestructor()) { + llvm::Constant *DtorFn; + if (Array) { + DtorFn = CodeGenFunction(CGM).GenerateCXXAggrDestructorHelper( + RD->getDestructor(getContext()), + Array, DeclPtr); + DeclPtr = + llvm::Constant::getNullValue(llvm::Type::getInt8PtrTy(VMContext)); + } + else + DtorFn = CGM.GetAddrOfCXXDestructor(RD->getDestructor(getContext()), + Dtor_Complete); + EmitCXXGlobalDtorRegistration(DtorFn, DeclPtr); + } } } } @@ -559,6 +571,50 @@ CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D, EmitBlock(AfterFor, true); } +/// EmitCXXAggrDestructorCall - Generates a helper function which when invoked, +/// calls the default destructor on array elements in reverse order of +/// construction. +llvm::Constant * +CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D, + const ArrayType *Array, + llvm::Value *This) { + static int UniqueCount; + FunctionArgList Args; + ImplicitParamDecl *Dst = + ImplicitParamDecl::Create(getContext(), 0, + SourceLocation(), 0, + getContext().getPointerType(getContext().VoidTy)); + Args.push_back(std::make_pair(Dst, Dst->getType())); + + llvm::SmallString<16> Name; + llvm::raw_svector_ostream(Name) << "__tcf_" << (++UniqueCount); + QualType R = getContext().VoidTy; + const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(R, Args); + const llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI, false); + llvm::Function *Fn = + llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage, + Name.c_str(), + &CGM.getModule()); + IdentifierInfo *II + = &CGM.getContext().Idents.get(Name.c_str()); + FunctionDecl *FD = FunctionDecl::Create(getContext(), + getContext().getTranslationUnitDecl(), + SourceLocation(), II, R, 0, + FunctionDecl::Static, + false, true); + StartFunction(FD, R, Fn, Args, SourceLocation()); + QualType BaseElementTy = getContext().getBaseElementType(Array); + const llvm::Type *BasePtr = ConvertType(BaseElementTy); + BasePtr = llvm::PointerType::getUnqual(BasePtr); + llvm::Value *BaseAddrPtr = Builder.CreateBitCast(This, BasePtr); + EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr); + FinishFunction(); + llvm::Type *Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), + 0); + llvm::Constant *m = llvm::ConstantExpr::getBitCast(Fn, Ptr8Ty); + return m; +} + void CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, CXXCtorType Type, diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 593840213a..f42376b623 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -646,6 +646,10 @@ public: const ArrayType *Array, llvm::Value *This); + llvm::Constant * GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D, + const ArrayType *Array, + llvm::Value *This); + void EmitCXXDestructorCall(const CXXDestructorDecl *D, CXXDtorType Type, llvm::Value *This); @@ -994,7 +998,7 @@ public: /// 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, + void EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn, llvm::Constant *DeclPtr); /// GenerateCXXGlobalInitFunc - Generates code for initializing global diff --git a/test/CodeGenCXX/global-array-destruction.cpp b/test/CodeGenCXX/global-array-destruction.cpp new file mode 100644 index 0000000000..ebea9c156e --- /dev/null +++ b/test/CodeGenCXX/global-array-destruction.cpp @@ -0,0 +1,33 @@ +// RUN: clang-cc -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s +// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s + +extern "C" int printf(...); + +int count; + +struct S { + S() : iS(++count) { printf("S::S(%d)\n", iS); } + ~S() { printf("S::~S(%d)\n", iS); } + int iS; +}; + + +S arr[2][1]; +S s1; +S arr1[3]; +static S sarr[4]; + +int main () {} +S arr2[2]; +static S sarr1[4]; +S s2; +S arr3[3]; + +// CHECK-LP64: call ___cxa_atexit +// CHECK-LP64: call ___cxa_atexit +// CHECK-LP64: call ___cxa_atexit +// CHECK-LP64: call ___cxa_atexit +// CHECK-LP64: call ___cxa_atexit +// CHECK-LP64: call ___cxa_atexit +// CHECK-LP64: call ___cxa_atexit +// CHECK-LP64: call ___cxa_atexit |