From af130fd78267ee9e2395b758a7d827b07ce317a0 Mon Sep 17 00:00:00 2001 From: Sebastian Redl Date: Sun, 19 Feb 2012 12:28:02 +0000 Subject: [PATCH] Get recursive initializer lists to work and add a test. Codegen of std::initializer_list is now complete. Onward to array new. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150926 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGExprAgg.cpp | 53 ++++++++++++++----- lib/CodeGen/CodeGenFunction.h | 3 +- .../cxx0x-initializer-stdinitializerlist.cpp | 28 ++++++++++ 3 files changed, 71 insertions(+), 13 deletions(-) diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 1cd08b7e87..13f5bc47d5 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -80,7 +80,7 @@ public: void EmitMoveFromReturnSlot(const Expr *E, RValue Src); - void EmitStdInitializerList(InitListExpr *InitList); + void EmitStdInitializerList(llvm::Value *DestPtr, InitListExpr *InitList); void EmitArrayInit(llvm::Value *DestPtr, llvm::ArrayType *AType, QualType elementType, InitListExpr *E); @@ -303,7 +303,8 @@ static void EmitStdInitializerListCleanup(CodeGenFunction &CGF, /// \brief Emit the initializer for a std::initializer_list initialized with a /// real initializer list. -void AggExprEmitter::EmitStdInitializerList(InitListExpr *initList) { +void AggExprEmitter::EmitStdInitializerList(llvm::Value *destPtr, + InitListExpr *initList) { // We emit an array containing the elements, then have the init list point // at the array. ASTContext &ctx = CGF.getContext(); @@ -326,7 +327,6 @@ void AggExprEmitter::EmitStdInitializerList(InitListExpr *initList) { } QualType elementPtr = ctx.getPointerType(element.withConst()); - llvm::Value *destPtr = Dest.getAddr(); // Start pointer. if (!ctx.hasSameType(field->getType(), elementPtr)) { @@ -416,8 +416,15 @@ void AggExprEmitter::EmitArrayInit(llvm::Value *DestPtr, llvm::ArrayType *AType, if (endOfInit) Builder.CreateStore(element, endOfInit); } - LValue elementLV = CGF.MakeAddrLValue(element, elementType); - EmitInitializationToLValue(E->getInit(i), elementLV); + // If these are nested std::initializer_list inits, do them directly, + // because they are conceptually the same "location". + InitListExpr *initList = dyn_cast(E->getInit(i)); + if (initList && initList->initializesStdInitializerList()) { + EmitStdInitializerList(element, initList); + } else { + LValue elementLV = CGF.MakeAddrLValue(element, elementType); + EmitInitializationToLValue(E->getInit(i), elementLV); + } } // Check whether there's a non-trivial array-fill expression. @@ -875,7 +882,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { CGF.ErrorUnsupported(E, "GNU array range designator extension"); if (E->initializesStdInitializerList()) { - EmitStdInitializerList(E); + EmitStdInitializerList(Dest.getAddr(), E); return; } @@ -1267,11 +1274,31 @@ void CodeGenFunction::MaybeEmitStdInitializerListCleanup(LValue lvalue, cast(init)->initializesStdInitializerList()) { // We initialized this std::initializer_list with an initializer list. // A backing array was created. Push a cleanup for it. - EmitStdInitializerListCleanup(lvalue, cast(init)); + EmitStdInitializerListCleanup(lvalue.getAddress(), + cast(init)); + } +} + +static void EmitRecursiveStdInitializerListCleanup(CodeGenFunction &CGF, + llvm::Value *arrayStart, + const InitListExpr *init) { + // Check if there are any recursive cleanups to do, i.e. if we have + // std::initializer_list> list = {{obj()}}; + // then we need to destroy the inner array as well. + for (unsigned i = 0, e = init->getNumInits(); i != e; ++i) { + const InitListExpr *subInit = dyn_cast(init->getInit(i)); + if (!subInit || !subInit->initializesStdInitializerList()) + continue; + + // This one needs to be destroyed. Get the address of the std::init_list. + llvm::Value *offset = llvm::ConstantInt::get(CGF.SizeTy, i); + llvm::Value *loc = CGF.Builder.CreateInBoundsGEP(arrayStart, offset, + "std.initlist"); + CGF.EmitStdInitializerListCleanup(loc, subInit); } } -void CodeGenFunction::EmitStdInitializerListCleanup(LValue lvalue, +void CodeGenFunction::EmitStdInitializerListCleanup(llvm::Value *loc, const InitListExpr *init) { ASTContext &ctx = getContext(); QualType element = GetStdInitializerListElementType(init->getType()); @@ -1283,10 +1310,12 @@ void CodeGenFunction::EmitStdInitializerListCleanup(LValue lvalue, // lvalue is the location of a std::initializer_list, which as its first // element has a pointer to the array we want to destroy. - llvm::Value *startPointer = Builder.CreateStructGEP(lvalue.getAddress(), 0, - "startPointer"); - llvm::Value *arrayAddress = - Builder.CreateBitCast(startPointer, arrayPtrType, "arrayAddress"); + llvm::Value *startPointer = Builder.CreateStructGEP(loc, 0, "startPointer"); + llvm::Value *startAddress = Builder.CreateLoad(startPointer, "startAddress"); + ::EmitRecursiveStdInitializerListCleanup(*this, startAddress, init); + + llvm::Value *arrayAddress = + Builder.CreateBitCast(startAddress, arrayPtrType, "arrayAddress"); ::EmitStdInitializerListCleanup(*this, array, arrayAddress, init); } diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 82f6f9af5f..95420e5344 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -1812,7 +1812,8 @@ public: llvm::Value *EmitDynamicCast(llvm::Value *V, const CXXDynamicCastExpr *DCE); void MaybeEmitStdInitializerListCleanup(LValue lvalue, const Expr *init); - void EmitStdInitializerListCleanup(LValue lvalue, const InitListExpr *init); + void EmitStdInitializerListCleanup(llvm::Value *loc, + const InitListExpr *init); void EmitCheck(llvm::Value *, unsigned Size); diff --git a/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp index 79d2073759..7dc5503c96 100644 --- a/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp +++ b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp @@ -136,3 +136,31 @@ void fn7() { // CHECK: call void @_ZN10destroyme2D1Ev // CHECK: call void @_ZN10wantslist1D1Ev } + +void fn8() { + // CHECK: define void @_Z3fn8v + void target(std::initializer_list>); + // objects should be destroyed before dm2, after call returns + // CHECK: call void @_Z6targetSt16initializer_listIS_I10destroyme1EE + std::initializer_list inner; + target({ inner, { destroyme1() } }); + // CHECK: call void @_ZN10destroyme1D1Ev + // Only one destroy loop, since only one inner init list is directly inited. + // CHECK-NOT: call void @_ZN10destroyme1D1Ev + destroyme2 dm2; + // CHECK: call void @_ZN10destroyme2D1Ev +} + +void fn9() { + // CHECK: define void @_Z3fn9v + // objects should be destroyed after dm2 + std::initializer_list inner; + std::initializer_list> list = + { inner, { destroyme1() } }; + destroyme2 dm2; + // CHECK: call void @_ZN10destroyme2D1Ev + // CHECK: call void @_ZN10destroyme1D1Ev + // Only one destroy loop, since only one inner init list is directly inited. + // CHECK-NOT: call void @_ZN10destroyme1D1Ev + // CHECK: ret void +} -- 2.40.0