forked from OSchip/llvm-project
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. llvm-svn: 150803
This commit is contained in:
parent
8e7bfceb98
commit
c83ed8248e
|
@ -3483,10 +3483,6 @@ class InitListExpr : public Expr {
|
|||
/// field within the union will be initialized.
|
||||
llvm::PointerUnion<Expr *, FieldDecl *> 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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1093,6 +1093,7 @@ void CodeGenFunction::EmitExprAsInit(const Expr *init,
|
|||
AggValueSlot::IsDestructed,
|
||||
AggValueSlot::DoesNotNeedGCBarriers,
|
||||
AggValueSlot::IsNotAliased));
|
||||
MaybeEmitStdInitializerListCleanup(lvalue, init);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<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(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");
|
||||
}
|
||||
|
||||
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<CXXConstructExpr>(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<llvm::PointerType>(DestPtr->getType());
|
||||
llvm::ArrayType *AType =
|
||||
cast<llvm::ArrayType>(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<ArrayType>(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<CXXConstructExpr>(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<llvm::PointerType>(DestPtr->getType());
|
||||
llvm::ArrayType *AType =
|
||||
cast<llvm::ArrayType>(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<ExprWithCleanups>(init);
|
||||
if (!cleanups)
|
||||
return; // Nothing interesting here.
|
||||
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(lvalue, cast<InitListExpr>(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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 _E>
|
||||
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<int> intlist{1, 2, i};
|
||||
}
|
||||
|
||||
struct destroyme1 {
|
||||
~destroyme1();
|
||||
};
|
||||
struct destroyme2 {
|
||||
~destroyme2();
|
||||
};
|
||||
|
||||
|
||||
void fn2() {
|
||||
// CHECK: define void @_Z3fn2v
|
||||
void target(std::initializer_list<destroyme1>);
|
||||
// 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
|
||||
}
|
Loading…
Reference in New Issue