summaryrefslogtreecommitdiffstats
path: root/clang/lib/CodeGen/CodeGenModule.cpp
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2013-06-12 22:31:48 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2013-06-12 22:31:48 +0000
commitcc1b96d356a0bd85c033309b8cfa965f36ae8aa6 (patch)
tree0494bcbc5d7f1e890c1c814a70b4ee0dd0a8352e /clang/lib/CodeGen/CodeGenModule.cpp
parent6a0c9ae4f93fd29b7bae48513674ab18dda73f9e (diff)
downloadbcm5719-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/CodeGenModule.cpp')
-rw-r--r--clang/lib/CodeGen/CodeGenModule.cpp131
1 files changed, 2 insertions, 129 deletions
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index d49fc0b0315..f6218cddfb5 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -1628,125 +1628,6 @@ CharUnits CodeGenModule::GetTargetTypeStoreSize(llvm::Type *Ty) const {
TheDataLayout.getTypeStoreSizeInBits(Ty));
}
-llvm::Constant *
-CodeGenModule::MaybeEmitGlobalStdInitializerListInitializer(const VarDecl *D,
- const Expr *rawInit) {
- ArrayRef<ExprWithCleanups::CleanupObject> cleanups;
- if (const ExprWithCleanups *withCleanups =
- dyn_cast<ExprWithCleanups>(rawInit)) {
- cleanups = withCleanups->getObjects();
- rawInit = withCleanups->getSubExpr();
- }
-
- const InitListExpr *init = dyn_cast<InitListExpr>(rawInit);
- if (!init || !init->initializesStdInitializerList() ||
- init->getNumInits() == 0)
- return 0;
-
- ASTContext &ctx = getContext();
- unsigned numInits = init->getNumInits();
- // FIXME: This check is here because we would otherwise silently miscompile
- // nested global std::initializer_lists. Better would be to have a real
- // implementation.
- for (unsigned i = 0; i < numInits; ++i) {
- const InitListExpr *inner = dyn_cast<InitListExpr>(init->getInit(i));
- if (inner && inner->initializesStdInitializerList()) {
- ErrorUnsupported(inner, "nested global std::initializer_list");
- return 0;
- }
- }
-
- // Synthesize a fake VarDecl for the array and initialize that.
- QualType elementType = init->getInit(0)->getType();
- llvm::APInt numElements(ctx.getTypeSize(ctx.getSizeType()), numInits);
- QualType arrayType = ctx.getConstantArrayType(elementType, numElements,
- ArrayType::Normal, 0);
-
- IdentifierInfo *name = &ctx.Idents.get(D->getNameAsString() + "__initlist");
- TypeSourceInfo *sourceInfo = ctx.getTrivialTypeSourceInfo(
- arrayType, D->getLocation());
- VarDecl *backingArray = VarDecl::Create(ctx, const_cast<DeclContext*>(
- D->getDeclContext()),
- D->getLocStart(), D->getLocation(),
- name, arrayType, sourceInfo,
- SC_Static);
- backingArray->setTSCSpec(D->getTSCSpec());
-
- // Now clone the InitListExpr to initialize the array instead.
- // Incredible hack: we want to use the existing InitListExpr here, so we need
- // to tell it that it no longer initializes a std::initializer_list.
- ArrayRef<Expr*> Inits(const_cast<InitListExpr*>(init)->getInits(),
- init->getNumInits());
- Expr *arrayInit = new (ctx) InitListExpr(ctx, init->getLBraceLoc(), Inits,
- init->getRBraceLoc());
- arrayInit->setType(arrayType);
-
- if (!cleanups.empty())
- arrayInit = ExprWithCleanups::Create(ctx, arrayInit, cleanups);
-
- backingArray->setInit(arrayInit);
-
- // Emit the definition of the array.
- EmitGlobalVarDefinition(backingArray);
-
- // Inspect the initializer list to validate it and determine its type.
- // FIXME: doing this every time is probably inefficient; caching would be nice
- RecordDecl *record = init->getType()->castAs<RecordType>()->getDecl();
- RecordDecl::field_iterator field = record->field_begin();
- if (field == record->field_end()) {
- ErrorUnsupported(D, "weird std::initializer_list");
- return 0;
- }
- QualType elementPtr = ctx.getPointerType(elementType.withConst());
- // Start pointer.
- if (!ctx.hasSameType(field->getType(), elementPtr)) {
- ErrorUnsupported(D, "weird std::initializer_list");
- return 0;
- }
- ++field;
- if (field == record->field_end()) {
- ErrorUnsupported(D, "weird std::initializer_list");
- return 0;
- }
- bool isStartEnd = false;
- if (ctx.hasSameType(field->getType(), elementPtr)) {
- // End pointer.
- isStartEnd = true;
- } else if(!ctx.hasSameType(field->getType(), ctx.getSizeType())) {
- ErrorUnsupported(D, "weird std::initializer_list");
- return 0;
- }
-
- // Now build an APValue representing the std::initializer_list.
- APValue initListValue(APValue::UninitStruct(), 0, 2);
- APValue &startField = initListValue.getStructField(0);
- APValue::LValuePathEntry startOffsetPathEntry;
- startOffsetPathEntry.ArrayIndex = 0;
- startField = APValue(APValue::LValueBase(backingArray),
- CharUnits::fromQuantity(0),
- llvm::makeArrayRef(startOffsetPathEntry),
- /*IsOnePastTheEnd=*/false, 0);
-
- if (isStartEnd) {
- APValue &endField = initListValue.getStructField(1);
- APValue::LValuePathEntry endOffsetPathEntry;
- endOffsetPathEntry.ArrayIndex = numInits;
- endField = APValue(APValue::LValueBase(backingArray),
- ctx.getTypeSizeInChars(elementType) * numInits,
- llvm::makeArrayRef(endOffsetPathEntry),
- /*IsOnePastTheEnd=*/true, 0);
- } else {
- APValue &sizeField = initListValue.getStructField(1);
- sizeField = APValue(llvm::APSInt(numElements));
- }
-
- // Emit the constant for the initializer_list.
- llvm::Constant *llvmInit =
- EmitConstantValueForMemory(initListValue, D->getType());
- assert(llvmInit && "failed to initialize as constant");
- return llvmInit;
-}
-
unsigned CodeGenModule::GetGlobalVarAddressSpace(const VarDecl *D,
unsigned AddrSpace) {
if (LangOpts.CUDA && CodeGenOpts.CUDAIsDevice) {
@@ -1817,18 +1698,10 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
assert(!ASTTy->isIncompleteType() && "Unexpected incomplete type");
Init = EmitNullConstant(D->getType());
} else {
- // If this is a std::initializer_list, emit the special initializer.
- Init = MaybeEmitGlobalStdInitializerListInitializer(D, InitExpr);
- // An empty init list will perform zero-initialization, which happens
- // to be exactly what we want.
- // FIXME: It does so in a global constructor, which is *not* what we
- // want.
+ initializedGlobalDecl = GlobalDecl(D);
+ Init = EmitConstantInit(*InitDecl);
if (!Init) {
- initializedGlobalDecl = GlobalDecl(D);
- Init = EmitConstantInit(*InitDecl);
- }
- if (!Init) {
QualType T = InitExpr->getType();
if (D->getType()->isReferenceType())
T = D->getType();
OpenPOWER on IntegriCloud