[cfe-commits] r150803 - in /cfe/trunk: include/clang/AST/Expr.h include/clang/AST/Stmt.h lib/AST/Expr.cpp lib/CodeGen/CGDecl.cpp lib/CodeGen/CGExprAgg.cpp lib/CodeGen/CodeGenFunction.h lib/Sema/SemaInit.cpp test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp

Sebastian Redl sebastian.redl at getdesigned.at
Fri Feb 17 00:42:25 PST 2012


Author: cornedbee
Date: Fri Feb 17 02:42:25 2012
New Revision: 150803

URL: http://llvm.org/viewvc/llvm-project?rev=150803&view=rev
Log:
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.

Added:
    cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
Modified:
    cfe/trunk/include/clang/AST/Expr.h
    cfe/trunk/include/clang/AST/Stmt.h
    cfe/trunk/lib/AST/Expr.cpp
    cfe/trunk/lib/CodeGen/CGDecl.cpp
    cfe/trunk/lib/CodeGen/CGExprAgg.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.h
    cfe/trunk/lib/Sema/SemaInit.cpp

Modified: cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=150803&r1=150802&r2=150803&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Fri Feb 17 02:42:25 2012
@@ -3483,10 +3483,6 @@
   ///  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 @@
   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;

Modified: cfe/trunk/include/clang/AST/Stmt.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Stmt.h?rev=150803&r1=150802&r2=150803&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Stmt.h (original)
+++ cfe/trunk/include/clang/AST/Stmt.h Fri Feb 17 02:42:25 2012
@@ -213,6 +213,20 @@
     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 @@
     ExprWithCleanupsBitfields ExprWithCleanupsBits;
     PseudoObjectExprBitfields PseudoObjectExprBits;
     ObjCIndirectCopyRestoreExprBitfields ObjCIndirectCopyRestoreExprBits;
+    InitListExprBitfields InitListExprBits;
   };
 
   friend class ASTStmtReader;

Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=150803&r1=150802&r2=150803&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Fri Feb 17 02:42:25 2012
@@ -1433,9 +1433,10 @@
   : 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;

Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=150803&r1=150802&r2=150803&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGDecl.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGDecl.cpp Fri Feb 17 02:42:25 2012
@@ -1093,6 +1093,7 @@
                                               AggValueSlot::IsDestructed,
                                          AggValueSlot::DoesNotNeedGCBarriers,
                                               AggValueSlot::IsNotAliased));
+    MaybeEmitStdInitializerListCleanup(lvalue, init);
   }
 }
 

Modified: cfe/trunk/lib/CodeGen/CGExprAgg.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprAgg.cpp?rev=150803&r1=150802&r2=150803&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprAgg.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprAgg.cpp Fri Feb 17 02:42:25 2012
@@ -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 @@
 
   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 @@
   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 @@
   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 @@
       }
     }
 
-    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 @@
                                               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);
+}

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=150803&r1=150802&r2=150803&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Fri Feb 17 02:42:25 2012
@@ -1811,6 +1811,9 @@
   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,

Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=150803&r1=150802&r2=150803&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Fri Feb 17 02:42:25 2012
@@ -5282,6 +5282,7 @@
                        Converted.data(), NumInits, ILE->getRBraceLoc());
       Semantic->setSyntacticForm(ILE);
       Semantic->setType(Dest);
+      Semantic->setInitializesStdInitializerList();
       CurInit = S.Owned(Semantic);
       break;
     }

Added: cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp?rev=150803&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp Fri Feb 17 02:42:25 2012
@@ -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
+}





More information about the cfe-commits mailing list