From: Anders Carlsson Date: Tue, 24 Nov 2009 18:43:52 +0000 (+0000) Subject: Handle cases where we're constructing an array of objects and the constructor has... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5d4d946ec2d88696fd8422aeb64dc29688e6a2c1;p=clang Handle cases where we're constructing an array of objects and the constructor has default arguments. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@89783 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index b7670dfb45..19cc04bace 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -463,20 +463,25 @@ llvm::Value *CodeGenFunction::LoadCXXThis() { /// It is assumed that all relevant checks have been made by the caller. void CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D, - const ConstantArrayType *ArrayTy, - llvm::Value *ArrayPtr) { + const ConstantArrayType *ArrayTy, + llvm::Value *ArrayPtr, + CallExpr::const_arg_iterator ArgBeg, + CallExpr::const_arg_iterator ArgEnd) { + const llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); llvm::Value * NumElements = llvm::ConstantInt::get(SizeTy, getContext().getConstantArrayElementCount(ArrayTy)); - EmitCXXAggrConstructorCall(D, NumElements, ArrayPtr); + EmitCXXAggrConstructorCall(D, NumElements, ArrayPtr, ArgBeg, ArgEnd); } void CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D, - llvm::Value *NumElements, - llvm::Value *ArrayPtr) { + llvm::Value *NumElements, + llvm::Value *ArrayPtr, + CallExpr::const_arg_iterator ArgBeg, + CallExpr::const_arg_iterator ArgEnd) { const llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); // Create a temporary for the loop index and initialize it with 0. @@ -506,8 +511,24 @@ CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D, Counter = Builder.CreateLoad(IndexPtr); llvm::Value *Address = Builder.CreateInBoundsGEP(ArrayPtr, Counter, "arrayidx"); - EmitCXXConstructorCall(D, Ctor_Complete, Address, 0, 0); + // C++ [class.temporary]p4: + // There are two contexts in which temporaries are destroyed at a different + // point than the end of the full- expression. The first context is when a + // default constructor is called to initialize an element of an array. + // If the constructor has one or more default arguments, the destruction of + // every temporary created in a default argument expression is sequenced + // before the construction of the next array element, if any. + + // Keep track of the current number of live temporaries. + unsigned OldNumLiveTemporaries = LiveTemporaries.size(); + + EmitCXXConstructorCall(D, Ctor_Complete, Address, ArgBeg, ArgEnd); + + // Pop temporaries. + while (LiveTemporaries.size() > OldNumLiveTemporaries) + PopCXXTemporary(); + EmitBlock(ContinueBlock); // Emit the increment of the loop counter. @@ -714,7 +735,8 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest, BasePtr = llvm::PointerType::getUnqual(BasePtr); llvm::Value *BaseAddrPtr = Builder.CreateBitCast(Dest, BasePtr); - EmitCXXAggrConstructorCall(CD, Array, BaseAddrPtr); + EmitCXXAggrConstructorCall(CD, Array, BaseAddrPtr, + E->arg_begin(), E->arg_end()); } else // Call the constructor. @@ -1559,7 +1581,9 @@ static void EmitMemberInitializer(CodeGenFunction &CGF, llvm::Value *BaseAddrPtr = CGF.Builder.CreateBitCast(LHS.getAddress(), BasePtr); CGF.EmitCXXAggrConstructorCall(MemberInit->getConstructor(), - Array, BaseAddrPtr); + Array, BaseAddrPtr, + MemberInit->const_arg_begin(), + MemberInit->const_arg_end()); } else CGF.EmitCXXConstructorCall(MemberInit->getConstructor(), diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index 048e9de499..b982c15683 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -83,39 +83,41 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF, static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E, llvm::Value *NewPtr, llvm::Value *NumElements) { + if (E->isArray()) { + if (CXXConstructorDecl *Ctor = E->getConstructor()) + CGF.EmitCXXAggrConstructorCall(Ctor, NumElements, NewPtr, + E->constructor_arg_begin(), + E->constructor_arg_end()); + return; + } + QualType AllocType = E->getAllocatedType(); - if (!E->isArray()) { - if (CXXConstructorDecl *Ctor = E->getConstructor()) { - CGF.EmitCXXConstructorCall(Ctor, Ctor_Complete, NewPtr, - E->constructor_arg_begin(), - E->constructor_arg_end()); + if (CXXConstructorDecl *Ctor = E->getConstructor()) { + CGF.EmitCXXConstructorCall(Ctor, Ctor_Complete, NewPtr, + E->constructor_arg_begin(), + E->constructor_arg_end()); - return; - } + return; + } - // We have a POD type. - if (E->getNumConstructorArgs() == 0) - return; + // We have a POD type. + if (E->getNumConstructorArgs() == 0) + return; - assert(E->getNumConstructorArgs() == 1 && - "Can only have one argument to initializer of POD type."); + assert(E->getNumConstructorArgs() == 1 && + "Can only have one argument to initializer of POD type."); - const Expr *Init = E->getConstructorArg(0); + const Expr *Init = E->getConstructorArg(0); - if (!CGF.hasAggregateLLVMType(AllocType)) - CGF.EmitStoreOfScalar(CGF.EmitScalarExpr(Init), NewPtr, - AllocType.isVolatileQualified(), AllocType); - else if (AllocType->isAnyComplexType()) - CGF.EmitComplexExprIntoAddr(Init, NewPtr, - AllocType.isVolatileQualified()); - else - CGF.EmitAggExpr(Init, NewPtr, AllocType.isVolatileQualified()); - return; - } - - if (CXXConstructorDecl *Ctor = E->getConstructor()) - CGF.EmitCXXAggrConstructorCall(Ctor, NumElements, NewPtr); + if (!CGF.hasAggregateLLVMType(AllocType)) + CGF.EmitStoreOfScalar(CGF.EmitScalarExpr(Init), NewPtr, + AllocType.isVolatileQualified(), AllocType); + else if (AllocType->isAnyComplexType()) + CGF.EmitComplexExprIntoAddr(Init, NewPtr, + AllocType.isVolatileQualified()); + else + CGF.EmitAggExpr(Init, NewPtr, AllocType.isVolatileQualified()); } llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index be1a15ed66..a0dd7c08bf 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -671,10 +671,15 @@ public: void EmitCXXAggrConstructorCall(const CXXConstructorDecl *D, const ConstantArrayType *ArrayTy, - llvm::Value *ArrayPtr); + llvm::Value *ArrayPtr, + CallExpr::const_arg_iterator ArgBeg, + CallExpr::const_arg_iterator ArgEnd); + void EmitCXXAggrConstructorCall(const CXXConstructorDecl *D, llvm::Value *NumElements, - llvm::Value *ArrayPtr); + llvm::Value *ArrayPtr, + CallExpr::const_arg_iterator ArgBeg, + CallExpr::const_arg_iterator ArgEnd); void EmitCXXAggrDestructorCall(const CXXDestructorDecl *D, const ArrayType *Array, diff --git a/test/CodeGenCXX/default-arguments.cpp b/test/CodeGenCXX/default-arguments.cpp index 5028ce99c7..71d4baa475 100644 --- a/test/CodeGenCXX/default-arguments.cpp +++ b/test/CodeGenCXX/default-arguments.cpp @@ -1,4 +1,4 @@ -// RUN: clang-cc -emit-llvm %s -o - -triple=x86_64-apple-darwin10 +// RUN: clang-cc %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s // PR5484 namespace PR5484 { @@ -11,3 +11,59 @@ void g() { f(); } } + +struct A1 { + A1(); + ~A1(); +}; + +struct A2 { + A2(); + ~A2(); +}; + +struct B { + B(const A1& = A1(), const A2& = A2()); +}; + +// CHECK: define void @_Z2f1v() +void f1() { + + // CHECK: call void @_ZN2A1C1Ev( + // CHECK: call void @_ZN2A2C1Ev( + // CHECK: call void @_ZN1BC1ERK2A1RK2A2( + // CHECK: call void @_ZN2A2D1Ev + // CHECK: call void @_ZN2A1D1Ev + B bs[2]; +} + +struct C { + B bs[2]; + C(); +}; + +// CHECK: define void @_ZN1CC1Ev( +// CHECK: call void @_ZN2A1C1Ev( +// CHECK: call void @_ZN2A2C1Ev( +// CHECK: call void @_ZN1BC1ERK2A1RK2A2( +// CHECK: call void @_ZN2A2D1Ev +// CHECK: call void @_ZN2A1D1Ev + +// CHECK: define void @_ZN1CC2Ev( +// CHECK: call void @_ZN2A1C1Ev( +// CHECK: call void @_ZN2A2C1Ev( +// CHECK: call void @_ZN1BC1ERK2A1RK2A2( +// CHECK: call void @_ZN2A2D1Ev +// CHECK: call void @_ZN2A1D1Ev +C::C() { } + +// CHECK: define void @_Z2f3v() +void f3() { + // CHECK: call void @_ZN2A1C1Ev( + // CHECK: call void @_ZN2A2C1Ev( + // CHECK: call void @_ZN1BC1ERK2A1RK2A2( + // CHECK: call void @_ZN2A2D1Ev + // CHECK: call void @_ZN2A1D1Ev + B *bs = new B[2]; + delete bs; +}