From: Sebastian Redl Date: Fri, 17 Feb 2012 08:42:25 +0000 (+0000) Subject: Basic code generation support for std::initializer_list. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=32cf1f27ae8620e7b79bb4e81a067187c0aab7ae;p=clang Basic code generation support for std::initializer_list. We now generate temporary arrays to back std::initializer_list objects initialized with braces. The initializer_list is then made to point at the array. We support both ptr+size and start+end forms, although the latter is untested. Array lifetime is correct for temporary std::initializer_lists (e.g. call arguments) and local variables. It is untested for new expressions and member initializers. Things left to do: Massively increase the amount of testing. I need to write tests for start+end init lists, temporary objects created as a side effect of initializing init list objects, new expressions, member initialization, creation of temporary objects (e.g. std::vector) for initializer lists, and probably more. Get lifetime "right" for member initializers and new expressions. Not that either are very useful. Implement list-initialization of array new expressions. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150803 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 0f325bdcc9..d66ad8fbca 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -3483,10 +3483,6 @@ class InitListExpr : public Expr { /// field within the union will be initialized. llvm::PointerUnion ArrayFillerOrUnionFieldInit; - /// Whether this initializer list originally had a GNU array-range - /// designator in it. This is a temporary marker used by CodeGen. - bool HadArrayRangeDesignator; - public: InitListExpr(ASTContext &C, SourceLocation lbraceloc, Expr **initexprs, unsigned numinits, @@ -3585,9 +3581,18 @@ public: InitListExpr *getSyntacticForm() const { return SyntacticForm; } void setSyntacticForm(InitListExpr *Init) { SyntacticForm = Init; } - bool hadArrayRangeDesignator() const { return HadArrayRangeDesignator; } + bool hadArrayRangeDesignator() const { + return InitListExprBits.HadArrayRangeDesignator != 0; + } void sawArrayRangeDesignator(bool ARD = true) { - HadArrayRangeDesignator = ARD; + InitListExprBits.HadArrayRangeDesignator = ARD; + } + + bool initializesStdInitializerList() const { + return InitListExprBits.InitializesStdInitializerList != 0; + } + void setInitializesStdInitializerList(bool ISIL = true) { + InitListExprBits.InitializesStdInitializerList = ISIL; } SourceRange getSourceRange() const; diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h index 3a300d1b10..e9fce27796 100644 --- a/include/clang/AST/Stmt.h +++ b/include/clang/AST/Stmt.h @@ -213,6 +213,20 @@ protected: unsigned ShouldCopy : 1; }; + class InitListExprBitfields { + friend class InitListExpr; + + unsigned : NumExprBits; + + /// Whether this initializer list originally had a GNU array-range + /// designator in it. This is a temporary marker used by CodeGen. + unsigned HadArrayRangeDesignator : 1; + + /// Whether this initializer list initializes a std::initializer_list + /// object. + unsigned InitializesStdInitializerList : 1; + }; + union { // FIXME: this is wasteful on 64-bit platforms. void *Aligner; @@ -226,6 +240,7 @@ protected: ExprWithCleanupsBitfields ExprWithCleanupsBits; PseudoObjectExprBitfields PseudoObjectExprBits; ObjCIndirectCopyRestoreExprBitfields ObjCIndirectCopyRestoreExprBits; + InitListExprBitfields InitListExprBits; }; friend class ASTStmtReader; diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index d5eab77816..b3077cbaa4 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -1433,9 +1433,10 @@ InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc, : Expr(InitListExprClass, QualType(), VK_RValue, OK_Ordinary, false, false, false, false), InitExprs(C, numInits), - LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0), - HadArrayRangeDesignator(false) -{ + LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0) +{ + sawArrayRangeDesignator(false); + setInitializesStdInitializerList(false); for (unsigned I = 0; I != numInits; ++I) { if (initExprs[I]->isTypeDependent()) ExprBits.TypeDependent = true; diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 2467d991d9..57425668ff 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -1093,6 +1093,7 @@ void CodeGenFunction::EmitExprAsInit(const Expr *init, AggValueSlot::IsDestructed, AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsNotAliased)); + MaybeEmitStdInitializerListCleanup(lvalue, init); } } diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 91f9db0bfe..1cd08b7e87 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -16,6 +16,7 @@ #include "CGObjCRuntime.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/StmtVisitor.h" #include "llvm/Constants.h" #include "llvm/Function.h" @@ -79,6 +80,10 @@ public: void EmitMoveFromReturnSlot(const Expr *E, RValue Src); + void EmitStdInitializerList(InitListExpr *InitList); + void EmitArrayInit(llvm::Value *DestPtr, llvm::ArrayType *AType, + QualType elementType, InitListExpr *E); + AggValueSlot::NeedsGCBarriers_t needsGC(QualType T) { if (CGF.getLangOptions().getGC() && TypeRequiresGCollection(T)) return AggValueSlot::NeedsGCBarriers; @@ -271,6 +276,218 @@ void AggExprEmitter::EmitFinalDestCopy(const Expr *E, LValue Src, bool Ignore) { EmitFinalDestCopy(E, Src.asAggregateRValue(), Ignore, Alignment.getQuantity()); } +static QualType GetStdInitializerListElementType(QualType T) { + // Just assume that this is really std::initializer_list. + ClassTemplateSpecializationDecl *specialization = + cast(T->castAs()->getDecl()); + return specialization->getTemplateArgs()[0].getAsType(); +} + +/// \brief Prepare cleanup for the temporary array. +static void EmitStdInitializerListCleanup(CodeGenFunction &CGF, + QualType arrayType, + llvm::Value *addr, + const InitListExpr *initList) { + QualType::DestructionKind dtorKind = arrayType.isDestructedType(); + if (!dtorKind) + return; // Type doesn't need destroying. + if (dtorKind != QualType::DK_cxx_destructor) { + CGF.ErrorUnsupported(initList, "ObjC ARC type in initializer_list"); + return; + } + + CodeGenFunction::Destroyer *destroyer = CGF.getDestroyer(dtorKind); + CGF.pushDestroy(NormalAndEHCleanup, addr, arrayType, destroyer, + /*EHCleanup=*/true); +} + +/// \brief Emit the initializer for a std::initializer_list initialized with a +/// real initializer list. +void AggExprEmitter::EmitStdInitializerList(InitListExpr *initList) { + // We emit an array containing the elements, then have the init list point + // at the array. + ASTContext &ctx = CGF.getContext(); + unsigned numInits = initList->getNumInits(); + QualType element = GetStdInitializerListElementType(initList->getType()); + llvm::APInt size(ctx.getTypeSize(ctx.getSizeType()), numInits); + QualType array = ctx.getConstantArrayType(element, size, ArrayType::Normal,0); + llvm::Type *LTy = CGF.ConvertTypeForMem(array); + llvm::AllocaInst *alloc = CGF.CreateTempAlloca(LTy); + alloc->setAlignment(ctx.getTypeAlignInChars(array).getQuantity()); + alloc->setName(".initlist."); + + EmitArrayInit(alloc, cast(LTy), element, initList); + + // FIXME: The diagnostics are somewhat out of place here. + RecordDecl *record = initList->getType()->castAs()->getDecl(); + RecordDecl::field_iterator field = record->field_begin(); + if (field == record->field_end()) { + CGF.ErrorUnsupported(initList, "weird std::initializer_list"); + } + + QualType elementPtr = ctx.getPointerType(element.withConst()); + llvm::Value *destPtr = Dest.getAddr(); + + // Start pointer. + if (!ctx.hasSameType(field->getType(), elementPtr)) { + CGF.ErrorUnsupported(initList, "weird std::initializer_list"); + } + LValue start = CGF.EmitLValueForFieldInitialization(destPtr, *field, 0); + llvm::Value *arrayStart = Builder.CreateStructGEP(alloc, 0, "arraystart"); + CGF.EmitStoreThroughLValue(RValue::get(arrayStart), start); + ++field; + + if (field == record->field_end()) { + CGF.ErrorUnsupported(initList, "weird std::initializer_list"); + } + LValue endOrLength = CGF.EmitLValueForFieldInitialization(destPtr, *field, 0); + if (ctx.hasSameType(field->getType(), elementPtr)) { + // End pointer. + llvm::Value *arrayEnd = Builder.CreateStructGEP(alloc,numInits, "arrayend"); + CGF.EmitStoreThroughLValue(RValue::get(arrayEnd), endOrLength); + } else if(ctx.hasSameType(field->getType(), ctx.getSizeType())) { + // Length. + CGF.EmitStoreThroughLValue(RValue::get(Builder.getInt(size)), endOrLength); + } else { + CGF.ErrorUnsupported(initList, "weird std::initializer_list"); + } + + if (!Dest.isExternallyDestructed()) + EmitStdInitializerListCleanup(CGF, array, alloc, initList); +} + +/// \brief Emit initialization of an array from an initializer list. +void AggExprEmitter::EmitArrayInit(llvm::Value *DestPtr, llvm::ArrayType *AType, + QualType elementType, InitListExpr *E) { + uint64_t NumInitElements = E->getNumInits(); + + uint64_t NumArrayElements = AType->getNumElements(); + assert(NumInitElements <= NumArrayElements); + + // DestPtr is an array*. Construct an elementType* by drilling + // down a level. + llvm::Value *zero = llvm::ConstantInt::get(CGF.SizeTy, 0); + llvm::Value *indices[] = { zero, zero }; + llvm::Value *begin = + Builder.CreateInBoundsGEP(DestPtr, indices, "arrayinit.begin"); + + // Exception safety requires us to destroy all the + // already-constructed members if an initializer throws. + // For that, we'll need an EH cleanup. + QualType::DestructionKind dtorKind = elementType.isDestructedType(); + llvm::AllocaInst *endOfInit = 0; + EHScopeStack::stable_iterator cleanup; + llvm::Instruction *cleanupDominator = 0; + if (CGF.needsEHCleanup(dtorKind)) { + // In principle we could tell the cleanup where we are more + // directly, but the control flow can get so varied here that it + // would actually be quite complex. Therefore we go through an + // alloca. + endOfInit = CGF.CreateTempAlloca(begin->getType(), + "arrayinit.endOfInit"); + cleanupDominator = Builder.CreateStore(begin, endOfInit); + CGF.pushIrregularPartialArrayCleanup(begin, endOfInit, elementType, + CGF.getDestroyer(dtorKind)); + cleanup = CGF.EHStack.stable_begin(); + + // Otherwise, remember that we didn't need a cleanup. + } else { + dtorKind = QualType::DK_none; + } + + llvm::Value *one = llvm::ConstantInt::get(CGF.SizeTy, 1); + + // The 'current element to initialize'. The invariants on this + // variable are complicated. Essentially, after each iteration of + // the loop, it points to the last initialized element, except + // that it points to the beginning of the array before any + // elements have been initialized. + llvm::Value *element = begin; + + // Emit the explicit initializers. + for (uint64_t i = 0; i != NumInitElements; ++i) { + // Advance to the next element. + if (i > 0) { + element = Builder.CreateInBoundsGEP(element, one, "arrayinit.element"); + + // Tell the cleanup that it needs to destroy up to this + // element. TODO: some of these stores can be trivially + // observed to be unnecessary. + if (endOfInit) Builder.CreateStore(element, endOfInit); + } + + LValue elementLV = CGF.MakeAddrLValue(element, elementType); + EmitInitializationToLValue(E->getInit(i), elementLV); + } + + // Check whether there's a non-trivial array-fill expression. + // Note that this will be a CXXConstructExpr even if the element + // type is an array (or array of array, etc.) of class type. + Expr *filler = E->getArrayFiller(); + bool hasTrivialFiller = true; + if (CXXConstructExpr *cons = dyn_cast_or_null(filler)) { + assert(cons->getConstructor()->isDefaultConstructor()); + hasTrivialFiller = cons->getConstructor()->isTrivial(); + } + + // Any remaining elements need to be zero-initialized, possibly + // using the filler expression. We can skip this if the we're + // emitting to zeroed memory. + if (NumInitElements != NumArrayElements && + !(Dest.isZeroed() && hasTrivialFiller && + CGF.getTypes().isZeroInitializable(elementType))) { + + // Use an actual loop. This is basically + // do { *array++ = filler; } while (array != end); + + // Advance to the start of the rest of the array. + if (NumInitElements) { + element = Builder.CreateInBoundsGEP(element, one, "arrayinit.start"); + if (endOfInit) Builder.CreateStore(element, endOfInit); + } + + // Compute the end of the array. + llvm::Value *end = Builder.CreateInBoundsGEP(begin, + llvm::ConstantInt::get(CGF.SizeTy, NumArrayElements), + "arrayinit.end"); + + llvm::BasicBlock *entryBB = Builder.GetInsertBlock(); + llvm::BasicBlock *bodyBB = CGF.createBasicBlock("arrayinit.body"); + + // Jump into the body. + CGF.EmitBlock(bodyBB); + llvm::PHINode *currentElement = + Builder.CreatePHI(element->getType(), 2, "arrayinit.cur"); + currentElement->addIncoming(element, entryBB); + + // Emit the actual filler expression. + LValue elementLV = CGF.MakeAddrLValue(currentElement, elementType); + if (filler) + EmitInitializationToLValue(filler, elementLV); + else + EmitNullInitializationToLValue(elementLV); + + // Move on to the next element. + llvm::Value *nextElement = + Builder.CreateInBoundsGEP(currentElement, one, "arrayinit.next"); + + // Tell the EH cleanup that we finished with the last element. + if (endOfInit) Builder.CreateStore(nextElement, endOfInit); + + // Leave the loop if we're done. + llvm::Value *done = Builder.CreateICmpEQ(nextElement, end, + "arrayinit.done"); + llvm::BasicBlock *endBB = CGF.createBasicBlock("arrayinit.end"); + Builder.CreateCondBr(done, endBB, bodyBB); + currentElement->addIncoming(nextElement, Builder.GetInsertBlock()); + + CGF.EmitBlock(endBB); + } + + // Leave the partial-array cleanup if we entered one. + if (dtorKind) CGF.DeactivateCleanupBlock(cleanup, cleanupDominator); +} + //===----------------------------------------------------------------------===// // Visitor Methods //===----------------------------------------------------------------------===// @@ -657,17 +874,15 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { if (E->hadArrayRangeDesignator()) CGF.ErrorUnsupported(E, "GNU array range designator extension"); + if (E->initializesStdInitializerList()) { + EmitStdInitializerList(E); + return; + } + llvm::Value *DestPtr = Dest.getAddr(); // Handle initialization of an array. if (E->getType()->isArrayType()) { - llvm::PointerType *APType = - cast(DestPtr->getType()); - llvm::ArrayType *AType = - cast(APType->getElementType()); - - uint64_t NumInitElements = E->getNumInits(); - if (E->getNumInits() > 0) { QualType T1 = E->getType(); QualType T2 = E->getInit(0)->getType(); @@ -677,137 +892,17 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { } } - uint64_t NumArrayElements = AType->getNumElements(); - assert(NumInitElements <= NumArrayElements); - QualType elementType = E->getType().getCanonicalType(); elementType = CGF.getContext().getQualifiedType( cast(elementType)->getElementType(), elementType.getQualifiers() + Dest.getQualifiers()); - // DestPtr is an array*. Construct an elementType* by drilling - // down a level. - llvm::Value *zero = llvm::ConstantInt::get(CGF.SizeTy, 0); - llvm::Value *indices[] = { zero, zero }; - llvm::Value *begin = - Builder.CreateInBoundsGEP(DestPtr, indices, "arrayinit.begin"); - - // Exception safety requires us to destroy all the - // already-constructed members if an initializer throws. - // For that, we'll need an EH cleanup. - QualType::DestructionKind dtorKind = elementType.isDestructedType(); - llvm::AllocaInst *endOfInit = 0; - EHScopeStack::stable_iterator cleanup; - llvm::Instruction *cleanupDominator = 0; - if (CGF.needsEHCleanup(dtorKind)) { - // In principle we could tell the cleanup where we are more - // directly, but the control flow can get so varied here that it - // would actually be quite complex. Therefore we go through an - // alloca. - endOfInit = CGF.CreateTempAlloca(begin->getType(), - "arrayinit.endOfInit"); - cleanupDominator = Builder.CreateStore(begin, endOfInit); - CGF.pushIrregularPartialArrayCleanup(begin, endOfInit, elementType, - CGF.getDestroyer(dtorKind)); - cleanup = CGF.EHStack.stable_begin(); - - // Otherwise, remember that we didn't need a cleanup. - } else { - dtorKind = QualType::DK_none; - } - - llvm::Value *one = llvm::ConstantInt::get(CGF.SizeTy, 1); - - // The 'current element to initialize'. The invariants on this - // variable are complicated. Essentially, after each iteration of - // the loop, it points to the last initialized element, except - // that it points to the beginning of the array before any - // elements have been initialized. - llvm::Value *element = begin; - - // Emit the explicit initializers. - for (uint64_t i = 0; i != NumInitElements; ++i) { - // Advance to the next element. - if (i > 0) { - element = Builder.CreateInBoundsGEP(element, one, "arrayinit.element"); - - // Tell the cleanup that it needs to destroy up to this - // element. TODO: some of these stores can be trivially - // observed to be unnecessary. - if (endOfInit) Builder.CreateStore(element, endOfInit); - } - - LValue elementLV = CGF.MakeAddrLValue(element, elementType); - EmitInitializationToLValue(E->getInit(i), elementLV); - } - - // Check whether there's a non-trivial array-fill expression. - // Note that this will be a CXXConstructExpr even if the element - // type is an array (or array of array, etc.) of class type. - Expr *filler = E->getArrayFiller(); - bool hasTrivialFiller = true; - if (CXXConstructExpr *cons = dyn_cast_or_null(filler)) { - assert(cons->getConstructor()->isDefaultConstructor()); - hasTrivialFiller = cons->getConstructor()->isTrivial(); - } - - // Any remaining elements need to be zero-initialized, possibly - // using the filler expression. We can skip this if the we're - // emitting to zeroed memory. - if (NumInitElements != NumArrayElements && - !(Dest.isZeroed() && hasTrivialFiller && - CGF.getTypes().isZeroInitializable(elementType))) { - - // Use an actual loop. This is basically - // do { *array++ = filler; } while (array != end); - - // Advance to the start of the rest of the array. - if (NumInitElements) { - element = Builder.CreateInBoundsGEP(element, one, "arrayinit.start"); - if (endOfInit) Builder.CreateStore(element, endOfInit); - } - - // Compute the end of the array. - llvm::Value *end = Builder.CreateInBoundsGEP(begin, - llvm::ConstantInt::get(CGF.SizeTy, NumArrayElements), - "arrayinit.end"); - - llvm::BasicBlock *entryBB = Builder.GetInsertBlock(); - llvm::BasicBlock *bodyBB = CGF.createBasicBlock("arrayinit.body"); - - // Jump into the body. - CGF.EmitBlock(bodyBB); - llvm::PHINode *currentElement = - Builder.CreatePHI(element->getType(), 2, "arrayinit.cur"); - currentElement->addIncoming(element, entryBB); - - // Emit the actual filler expression. - LValue elementLV = CGF.MakeAddrLValue(currentElement, elementType); - if (filler) - EmitInitializationToLValue(filler, elementLV); - else - EmitNullInitializationToLValue(elementLV); - - // Move on to the next element. - llvm::Value *nextElement = - Builder.CreateInBoundsGEP(currentElement, one, "arrayinit.next"); - - // Tell the EH cleanup that we finished with the last element. - if (endOfInit) Builder.CreateStore(nextElement, endOfInit); - - // Leave the loop if we're done. - llvm::Value *done = Builder.CreateICmpEQ(nextElement, end, - "arrayinit.done"); - llvm::BasicBlock *endBB = CGF.createBasicBlock("arrayinit.end"); - Builder.CreateCondBr(done, endBB, bodyBB); - currentElement->addIncoming(nextElement, Builder.GetInsertBlock()); - - CGF.EmitBlock(endBB); - } - - // Leave the partial-array cleanup if we entered one. - if (dtorKind) CGF.DeactivateCleanupBlock(cleanup, cleanupDominator); + llvm::PointerType *APType = + cast(DestPtr->getType()); + llvm::ArrayType *AType = + cast(APType->getElementType()); + EmitArrayInit(DestPtr, AType, elementType, E); return; } @@ -1160,3 +1255,38 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr, TypeInfo.first.getQuantity()), Alignment, isVolatile); } + +void CodeGenFunction::MaybeEmitStdInitializerListCleanup(LValue lvalue, + const Expr *init) { + const ExprWithCleanups *cleanups = dyn_cast(init); + if (!cleanups) + return; // Nothing interesting here. + init = cleanups->getSubExpr(); + + if (isa(init) && + 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)); + } +} + +void CodeGenFunction::EmitStdInitializerListCleanup(LValue lvalue, + const InitListExpr *init) { + ASTContext &ctx = getContext(); + QualType element = GetStdInitializerListElementType(init->getType()); + unsigned numInits = init->getNumInits(); + llvm::APInt size(ctx.getTypeSize(ctx.getSizeType()), numInits); + QualType array =ctx.getConstantArrayType(element, size, ArrayType::Normal, 0); + QualType arrayPtr = ctx.getPointerType(array); + llvm::Type *arrayPtrType = ConvertType(arrayPtr); + + // 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"); + + ::EmitStdInitializerListCleanup(*this, array, arrayAddress, init); +} diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 427ee08e69..82f6f9af5f 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -1811,6 +1811,9 @@ public: llvm::Value* EmitCXXTypeidExpr(const CXXTypeidExpr *E); llvm::Value *EmitDynamicCast(llvm::Value *V, const CXXDynamicCastExpr *DCE); + void MaybeEmitStdInitializerListCleanup(LValue lvalue, const Expr *init); + void EmitStdInitializerListCleanup(LValue lvalue, const InitListExpr *init); + void EmitCheck(llvm::Value *, unsigned Size); llvm::Value *EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index b6d55aae80..fb97b00ace 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -5282,6 +5282,7 @@ InitializationSequence::Perform(Sema &S, Converted.data(), NumInits, ILE->getRBraceLoc()); Semantic->setSyntacticForm(ILE); Semantic->setType(Dest); + Semantic->setInitializesStdInitializerList(); CurInit = S.Owned(Semantic); break; } diff --git a/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp new file mode 100644 index 0000000000..ef7af88297 --- /dev/null +++ b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp @@ -0,0 +1,80 @@ +// RUN: %clang_cc1 -std=c++11 -S -emit-llvm -o - %s | FileCheck %s + +namespace std { + typedef decltype(sizeof(int)) size_t; + + // libc++'s implementation + template + class initializer_list + { + const _E* __begin_; + size_t __size_; + + initializer_list(const _E* __b, size_t __s) + : __begin_(__b), + __size_(__s) + {} + + public: + typedef _E value_type; + typedef const _E& reference; + typedef const _E& const_reference; + typedef size_t size_type; + + typedef const _E* iterator; + typedef const _E* const_iterator; + + initializer_list() : __begin_(nullptr), __size_(0) {} + + size_t size() const {return __size_;} + const _E* begin() const {return __begin_;} + const _E* end() const {return __begin_ + __size_;} + }; +} + +void fn1(int i) { + // CHECK: define void @_Z3fn1i + // temporary array + // CHECK: [[array:%[^ ]+]] = alloca [3 x i32] + // CHECK: getelementptr inbounds [3 x i32]* [[array]], i{{32|64}} 0 + // CHECK-NEXT: store i32 1, i32* + // CHECK-NEXT: getelementptr + // CHECK-NEXT: store + // CHECK-NEXT: getelementptr + // CHECK-NEXT: load + // CHECK-NEXT: store + // init the list + // CHECK-NEXT: getelementptr + // CHECK-NEXT: getelementptr inbounds [3 x i32]* + // CHECK-NEXT: store i32* + // CHECK-NEXT: getelementptr + // CHECK-NEXT: store i{{32|64}} 3 + std::initializer_list intlist{1, 2, i}; +} + +struct destroyme1 { + ~destroyme1(); +}; +struct destroyme2 { + ~destroyme2(); +}; + + +void fn2() { + // CHECK: define void @_Z3fn2v + void target(std::initializer_list); + // objects should be destroyed before dm2, after call returns + target({ destroyme1(), destroyme1() }); + // CHECK: call void @_ZN10destroyme1D1Ev + destroyme2 dm2; + // CHECK: call void @_ZN10destroyme2D1Ev +} + +void fn3() { + // CHECK: define void @_Z3fn3v + // objects should be destroyed after dm2 + auto list = { destroyme1(), destroyme1() }; + destroyme2 dm2; + // CHECK: call void @_ZN10destroyme2D1Ev + // CHECK: call void @_ZN10destroyme1D1Ev +}