diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2013-06-12 22:31:48 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2013-06-12 22:31:48 +0000 |
commit | cc1b96d356a0bd85c033309b8cfa965f36ae8aa6 (patch) | |
tree | 0494bcbc5d7f1e890c1c814a70b4ee0dd0a8352e /clang/lib/CodeGen/CGExprAgg.cpp | |
parent | 6a0c9ae4f93fd29b7bae48513674ab18dda73f9e (diff) | |
download | bcm5719-llvm-cc1b96d356a0bd85c033309b8cfa965f36ae8aa6.tar.gz bcm5719-llvm-cc1b96d356a0bd85c033309b8cfa965f36ae8aa6.zip |
PR12086, PR15117
Introduce CXXStdInitializerListExpr node, representing the implicit
construction of a std::initializer_list<T> object from its underlying array.
The AST representation of such an expression goes from an InitListExpr with a
flag set, to a CXXStdInitializerListExpr containing a MaterializeTemporaryExpr
containing an InitListExpr (possibly wrapped in a CXXBindTemporaryExpr).
This more detailed representation has several advantages, the most important of
which is that the new MaterializeTemporaryExpr allows us to directly model
lifetime extension of the underlying temporary array. Using that, this patch
*drastically* simplifies the IR generation of this construct, provides IR
generation support for nested global initializer_list objects, fixes several
bugs where the destructors for the underlying array would accidentally not get
invoked, and provides constant expression evaluation support for
std::initializer_list objects.
llvm-svn: 183872
Diffstat (limited to 'clang/lib/CodeGen/CGExprAgg.cpp')
-rw-r--r-- | clang/lib/CodeGen/CGExprAgg.cpp | 190 |
1 files changed, 52 insertions, 138 deletions
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index f8b19d686b2..f3eb34567bd 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -91,7 +91,6 @@ public: void EmitMoveFromReturnSlot(const Expr *E, RValue Src); - void EmitStdInitializerList(llvm::Value *DestPtr, InitListExpr *InitList); void EmitArrayInit(llvm::Value *DestPtr, llvm::ArrayType *AType, QualType elementType, InitListExpr *E); @@ -177,6 +176,7 @@ public: void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E); void VisitCXXConstructExpr(const CXXConstructExpr *E); void VisitLambdaExpr(LambdaExpr *E); + void VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E); void VisitExprWithCleanups(ExprWithCleanups *E); void VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E); void VisitCXXTypeidExpr(CXXTypeidExpr *E) { EmitAggLoadOfLValue(E); } @@ -345,89 +345,70 @@ void AggExprEmitter::EmitCopy(QualType type, const AggValueSlot &dest, std::min(dest.getAlignment(), src.getAlignment())); } -static QualType GetStdInitializerListElementType(QualType T) { - // Just assume that this is really std::initializer_list. - ClassTemplateSpecializationDecl *specialization = - cast<ClassTemplateSpecializationDecl>(T->castAs<RecordType>()->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(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(); - 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<llvm::ArrayType>(LTy), element, initList); - - // FIXME: The diagnostics are somewhat out of place here. - RecordDecl *record = initList->getType()->castAs<RecordType>()->getDecl(); - RecordDecl::field_iterator field = record->field_begin(); - if (field == record->field_end()) { - CGF.ErrorUnsupported(initList, "weird std::initializer_list"); +void +AggExprEmitter::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) { + // Emit an array containing the elements. The array is externally destructed + // if the std::initializer_list object is. + ASTContext &Ctx = CGF.getContext(); + LValue Array = CGF.EmitLValue(E->getSubExpr()); + assert(Array.isSimple() && "initializer_list array not a simple lvalue"); + llvm::Value *ArrayPtr = Array.getAddress(); + + const ConstantArrayType *ArrayType = + Ctx.getAsConstantArrayType(E->getSubExpr()->getType()); + assert(ArrayType && "std::initializer_list constructed from non-array"); + + // FIXME: Perform the checks on the field types in SemaInit. + RecordDecl *Record = E->getType()->castAs<RecordType>()->getDecl(); + RecordDecl::field_iterator Field = Record->field_begin(); + if (Field == Record->field_end()) { + CGF.ErrorUnsupported(E, "weird std::initializer_list"); return; } - QualType elementPtr = ctx.getPointerType(element.withConst()); - // Start pointer. - if (!ctx.hasSameType(field->getType(), elementPtr)) { - CGF.ErrorUnsupported(initList, "weird std::initializer_list"); + if (!Field->getType()->isPointerType() || + !Ctx.hasSameType(Field->getType()->getPointeeType(), + ArrayType->getElementType())) { + CGF.ErrorUnsupported(E, "weird std::initializer_list"); return; } - LValue DestLV = CGF.MakeNaturalAlignAddrLValue(destPtr, initList->getType()); - LValue start = CGF.EmitLValueForFieldInitialization(DestLV, *field); - 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"); + + AggValueSlot Dest = EnsureSlot(E->getType()); + LValue DestLV = CGF.MakeAddrLValue(Dest.getAddr(), E->getType(), + Dest.getAlignment()); + LValue Start = CGF.EmitLValueForFieldInitialization(DestLV, *Field); + llvm::Value *Zero = llvm::ConstantInt::get(CGF.PtrDiffTy, 0); + llvm::Value *IdxStart[] = { Zero, Zero }; + llvm::Value *ArrayStart = + Builder.CreateInBoundsGEP(ArrayPtr, IdxStart, "arraystart"); + CGF.EmitStoreThroughLValue(RValue::get(ArrayStart), Start); + ++Field; + + if (Field == Record->field_end()) { + CGF.ErrorUnsupported(E, "weird std::initializer_list"); return; } - LValue endOrLength = CGF.EmitLValueForFieldInitialization(DestLV, *field); - if (ctx.hasSameType(field->getType(), elementPtr)) { + + llvm::Value *Size = Builder.getInt(ArrayType->getSize()); + LValue EndOrLength = CGF.EmitLValueForFieldInitialization(DestLV, *Field); + if (Field->getType()->isPointerType() && + Ctx.hasSameType(Field->getType()->getPointeeType(), + ArrayType->getElementType())) { // End pointer. - llvm::Value *arrayEnd = Builder.CreateStructGEP(alloc,numInits, "arrayend"); - CGF.EmitStoreThroughLValue(RValue::get(arrayEnd), endOrLength); - } else if(ctx.hasSameType(field->getType(), ctx.getSizeType())) { + llvm::Value *IdxEnd[] = { Zero, Size }; + llvm::Value *ArrayEnd = + Builder.CreateInBoundsGEP(ArrayPtr, IdxEnd, "arrayend"); + CGF.EmitStoreThroughLValue(RValue::get(ArrayEnd), EndOrLength); + } else if (Ctx.hasSameType(Field->getType(), Ctx.getSizeType())) { // Length. - CGF.EmitStoreThroughLValue(RValue::get(Builder.getInt(size)), endOrLength); + CGF.EmitStoreThroughLValue(RValue::get(Size), EndOrLength); } else { - CGF.ErrorUnsupported(initList, "weird std::initializer_list"); + CGF.ErrorUnsupported(E, "weird std::initializer_list"); return; } - - if (!Dest.isExternallyDestructed()) - EmitStdInitializerListCleanup(CGF, array, alloc, initList); } /// \brief Emit initialization of an array from an initializer list. @@ -490,15 +471,8 @@ void AggExprEmitter::EmitArrayInit(llvm::Value *DestPtr, llvm::ArrayType *AType, if (endOfInit) Builder.CreateStore(element, endOfInit); } - // If these are nested std::initializer_list inits, do them directly, - // because they are conceptually the same "location". - InitListExpr *initList = dyn_cast<InitListExpr>(E->getInit(i)); - if (initList && initList->initializesStdInitializerList()) { - EmitStdInitializerList(element, initList); - } else { - LValue elementLV = CGF.MakeAddrLValue(element, elementType); - EmitInitializationToLValue(E->getInit(i), elementLV); - } + LValue elementLV = CGF.MakeAddrLValue(element, elementType); + EmitInitializationToLValue(E->getInit(i), elementLV); } // Check whether there's a non-trivial array-fill expression. @@ -1161,11 +1135,6 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { AggValueSlot Dest = EnsureSlot(E->getType()); - if (E->initializesStdInitializerList()) { - EmitStdInitializerList(Dest.getAddr(), E); - return; - } - LValue DestLV = CGF.MakeAddrLValue(Dest.getAddr(), E->getType(), Dest.getAlignment()); @@ -1546,58 +1515,3 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr, alignment.getQuantity(), isVolatile, /*TBAATag=*/0, TBAAStructTag); } - -void CodeGenFunction::MaybeEmitStdInitializerListCleanup(llvm::Value *loc, - const Expr *init) { - const ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(init); - if (cleanups) - init = cleanups->getSubExpr(); - - if (isa<InitListExpr>(init) && - cast<InitListExpr>(init)->initializesStdInitializerList()) { - // We initialized this std::initializer_list with an initializer list. - // A backing array was created. Push a cleanup for it. - EmitStdInitializerListCleanup(loc, cast<InitListExpr>(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<std::initializer_list<obj>> 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<InitListExpr>(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(llvm::Value *loc, - 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(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); -} |