diff options
Diffstat (limited to 'clang/lib')
23 files changed, 291 insertions, 470 deletions
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index db4269bf163..ecd147aebe3 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -1789,7 +1789,6 @@ InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc, LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), AltForm(0, true) { sawArrayRangeDesignator(false); - setInitializesStdInitializerList(false); for (unsigned I = 0; I != initExprs.size(); ++I) { if (initExprs[I]->isTypeDependent()) ExprBits.TypeDependent = true; @@ -2836,6 +2835,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const { case DesignatedInitExprClass: case ParenListExprClass: case CXXPseudoDestructorExprClass: + case CXXStdInitializerListExprClass: case SubstNonTypeTemplateParmExprClass: case MaterializeTemporaryExprClass: case ShuffleVectorExprClass: diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp index bcb6d4e809b..12510d68830 100644 --- a/clang/lib/AST/ExprClassification.cpp +++ b/clang/lib/AST/ExprClassification.cpp @@ -353,6 +353,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::CXXConstructExprClass: case Expr::CXXTemporaryObjectExprClass: case Expr::LambdaExprClass: + case Expr::CXXStdInitializerListExprClass: return Cl::CL_ClassTemporary; case Expr::VAArgExprClass: diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index d94efc13413..21fb4599664 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -4576,6 +4576,7 @@ namespace { bool VisitCastExpr(const CastExpr *E); bool VisitInitListExpr(const InitListExpr *E); bool VisitCXXConstructExpr(const CXXConstructExpr *E); + bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E); }; } @@ -4691,10 +4692,6 @@ bool RecordExprEvaluator::VisitCastExpr(const CastExpr *E) { } bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { - // Cannot constant-evaluate std::initializer_list inits. - if (E->initializesStdInitializerList()) - return false; - const RecordDecl *RD = E->getType()->castAs<RecordType>()->getDecl(); if (RD->isInvalidDecl()) return false; const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD); @@ -4810,6 +4807,58 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) { Result); } +bool RecordExprEvaluator::VisitCXXStdInitializerListExpr( + const CXXStdInitializerListExpr *E) { + const ConstantArrayType *ArrayType = + Info.Ctx.getAsConstantArrayType(E->getSubExpr()->getType()); + + LValue Array; + if (!EvaluateLValue(E->getSubExpr(), Array, Info)) + return false; + + // Get a pointer to the first element of the array. + Array.addArray(Info, E, ArrayType); + + // 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()) + return Error(E); + + // Start pointer. + if (!Field->getType()->isPointerType() || + !Info.Ctx.hasSameType(Field->getType()->getPointeeType(), + ArrayType->getElementType())) + return Error(E); + + // FIXME: What if the initializer_list type has base classes, etc? + Result = APValue(APValue::UninitStruct(), 0, 2); + Array.moveInto(Result.getStructField(0)); + + if (++Field == Record->field_end()) + return Error(E); + + if (Field->getType()->isPointerType() && + Info.Ctx.hasSameType(Field->getType()->getPointeeType(), + ArrayType->getElementType())) { + // End pointer. + if (!HandleLValueArrayAdjustment(Info, E, Array, + ArrayType->getElementType(), + ArrayType->getSize().getZExtValue())) + return false; + Array.moveInto(Result.getStructField(1)); + } else if (Info.Ctx.hasSameType(Field->getType(), Info.Ctx.getSizeType())) + // Length. + Result.getStructField(1) = APValue(APSInt(ArrayType->getSize())); + else + return Error(E); + + if (++Field != Record->field_end()) + return Error(E); + + return true; +} + static bool EvaluateRecord(const Expr *E, const LValue &This, APValue &Result, EvalInfo &Info) { assert(E->isRValue() && E->getType()->isRecordType() && @@ -7762,6 +7811,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::UnresolvedLookupExprClass: case Expr::DependentScopeDeclRefExprClass: case Expr::CXXConstructExprClass: + case Expr::CXXStdInitializerListExprClass: case Expr::CXXBindTemporaryExprClass: case Expr::ExprWithCleanupsClass: case Expr::CXXTemporaryObjectExprClass: diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 3137f3c8fdc..20f699fafb4 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -2481,6 +2481,10 @@ recurse: mangleExpression(cast<CXXDefaultInitExpr>(E)->getExpr(), Arity); break; + case Expr::CXXStdInitializerListExprClass: + mangleExpression(cast<CXXStdInitializerListExpr>(E)->getSubExpr(), Arity); + break; + case Expr::SubstNonTypeTemplateParmExprClass: mangleExpression(cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement(), Arity); diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 467413bfb20..d6358023907 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -1534,6 +1534,10 @@ void StmtPrinter::VisitCXXConstructExpr(CXXConstructExpr *E) { OS << " }"; } +void StmtPrinter::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) { + PrintExpr(E->getSubExpr()); +} + void StmtPrinter::VisitExprWithCleanups(ExprWithCleanups *E) { // Just forward to the sub expression. PrintExpr(E->getSubExpr()); diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index 4a3448c1e5f..391c1e60abe 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -758,6 +758,11 @@ void StmtProfiler::VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *S) { VisitExpr(S); } +void StmtProfiler::VisitCXXStdInitializerListExpr( + const CXXStdInitializerListExpr *S) { + VisitExpr(S); +} + void StmtProfiler::VisitCXXTypeidExpr(const CXXTypeidExpr *S) { VisitExpr(S); if (S->isTypeOperand()) diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp index b3a14772ad0..9d08d1c7f7a 100644 --- a/clang/lib/CodeGen/CGClass.cpp +++ b/clang/lib/CodeGen/CGClass.cpp @@ -433,52 +433,45 @@ static void EmitAggMemberInitializer(CodeGenFunction &CGF, unsigned Index) { if (Index == ArrayIndexes.size()) { LValue LV = LHS; - { // Scope for Cleanups. - CodeGenFunction::RunCleanupsScope Cleanups(CGF); - - if (ArrayIndexVar) { - // If we have an array index variable, load it and use it as an offset. - // Then, increment the value. - llvm::Value *Dest = LHS.getAddress(); - llvm::Value *ArrayIndex = CGF.Builder.CreateLoad(ArrayIndexVar); - Dest = CGF.Builder.CreateInBoundsGEP(Dest, ArrayIndex, "destaddress"); - llvm::Value *Next = llvm::ConstantInt::get(ArrayIndex->getType(), 1); - Next = CGF.Builder.CreateAdd(ArrayIndex, Next, "inc"); - CGF.Builder.CreateStore(Next, ArrayIndexVar); - - // Update the LValue. - LV.setAddress(Dest); - CharUnits Align = CGF.getContext().getTypeAlignInChars(T); - LV.setAlignment(std::min(Align, LV.getAlignment())); - } - switch (CGF.getEvaluationKind(T)) { - case TEK_Scalar: - CGF.EmitScalarInit(Init, /*decl*/ 0, LV, false); - break; - case TEK_Complex: - CGF.EmitComplexExprIntoLValue(Init, LV, /*isInit*/ true); - break; - case TEK_Aggregate: { - AggValueSlot Slot = - AggValueSlot::forLValue(LV, - AggValueSlot::IsDestructed, - AggValueSlot::DoesNotNeedGCBarriers, - AggValueSlot::IsNotAliased); - - CGF.EmitAggExpr(Init, Slot); - break; - } - } + if (ArrayIndexVar) { + // If we have an array index variable, load it and use it as an offset. + // Then, increment the value. + llvm::Value *Dest = LHS.getAddress(); + llvm::Value *ArrayIndex = CGF.Builder.CreateLoad(ArrayIndexVar); + Dest = CGF.Builder.CreateInBoundsGEP(Dest, ArrayIndex, "destaddress"); + llvm::Value *Next = llvm::ConstantInt::get(ArrayIndex->getType(), 1); + Next = CGF.Builder.CreateAdd(ArrayIndex, Next, "inc"); + CGF.Builder.CreateStore(Next, ArrayIndexVar); + + // Update the LValue. + LV.setAddress(Dest); + CharUnits Align = CGF.getContext().getTypeAlignInChars(T); + LV.setAlignment(std::min(Align, LV.getAlignment())); } - // Now, outside of the initializer cleanup scope, destroy the backing array - // for a std::initializer_list member. - CGF.MaybeEmitStdInitializerListCleanup(LV.getAddress(), Init); + switch (CGF.getEvaluationKind(T)) { + case TEK_Scalar: + CGF.EmitScalarInit(Init, /*decl*/ 0, LV, false); + break; + case TEK_Complex: + CGF.EmitComplexExprIntoLValue(Init, LV, /*isInit*/ true); + break; + case TEK_Aggregate: { + AggValueSlot Slot = + AggValueSlot::forLValue(LV, + AggValueSlot::IsDestructed, + AggValueSlot::DoesNotNeedGCBarriers, + AggValueSlot::IsNotAliased); + + CGF.EmitAggExpr(Init, Slot); + break; + } + } return; } - + const ConstantArrayType *Array = CGF.getContext().getAsConstantArrayType(T); assert(Array && "Array initialization without the array type?"); llvm::Value *IndexVar @@ -512,16 +505,12 @@ static void EmitAggMemberInitializer(CodeGenFunction &CGF, CGF.EmitBlock(ForBody); llvm::BasicBlock *ContinueBlock = CGF.createBasicBlock("for.inc"); - - { - CodeGenFunction::RunCleanupsScope Cleanups(CGF); - - // Inside the loop body recurse to emit the inner loop or, eventually, the - // constructor call. - EmitAggMemberInitializer(CGF, LHS, Init, ArrayIndexVar, - Array->getElementType(), ArrayIndexes, Index + 1); - } - + + // Inside the loop body recurse to emit the inner loop or, eventually, the + // constructor call. + EmitAggMemberInitializer(CGF, LHS, Init, ArrayIndexVar, + Array->getElementType(), ArrayIndexes, Index + 1); + CGF.EmitBlock(ContinueBlock); // Emit the increment of the loop counter. @@ -726,7 +715,7 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) { if (IsTryBody) EnterCXXTryStmt(*cast<CXXTryStmt>(Body), true); - EHScopeStack::stable_iterator CleanupDepth = EHStack.stable_begin(); + RunCleanupsScope RunCleanups(*this); // TODO: in restricted cases, we can emit the vbase initializers of // a complete ctor and then delegate to the base ctor. @@ -745,7 +734,7 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) { // initializers, which includes (along the exceptional path) the // destructors for those members and bases that were fully // constructed. - PopCleanupBlocks(CleanupDepth); + RunCleanups.ForceCleanup(); if (IsTryBody) ExitCXXTryStmt(*cast<CXXTryStmt>(Body), true); diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 7fc79e08f0f..4d14014f9c9 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -1187,7 +1187,6 @@ void CodeGenFunction::EmitExprAsInit(const Expr *init, AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsNotAliased)); } - MaybeEmitStdInitializerListCleanup(lvalue.getAddress(), init); return; } llvm_unreachable("bad evaluation kind"); diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index d534ff440cf..f88da33fbf5 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -240,15 +240,6 @@ pushTemporaryCleanup(CodeGenFunction &CGF, const MaterializeTemporaryExpr *M, } } - if (const InitListExpr *ILE = dyn_cast<InitListExpr>(E)) { - if (ILE->initializesStdInitializerList()) { - // FIXME: This is wrong if the temporary has static or thread storage - // duration. - CGF.EmitStdInitializerListCleanup(ReferenceTemporary, ILE); - return; - } - } - CXXDestructorDecl *ReferenceTemporaryDtor = 0; if (const RecordType *RT = E->getType()->getBaseElementTypeUnsafe()->getAs<RecordType>()) { 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); -} diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp index 83c8ace98cd..60a70f8e07f 100644 --- a/clang/lib/CodeGen/CGExprCXX.cpp +++ b/clang/lib/CodeGen/CGExprCXX.cpp @@ -838,8 +838,6 @@ static void StoreAnyExprIntoOneUnit(CodeGenFunction &CGF, const Expr *Init, AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsNotAliased); CGF.EmitAggExpr(Init, Slot); - - CGF.MaybeEmitStdInitializerListCleanup(NewPtr, Init); return; } } diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index ca331cc92be..3e13e972801 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -368,11 +368,6 @@ void ConstStructBuilder::ConvertStructToPacked() { } bool ConstStructBuilder::Build(InitListExpr *ILE) { - if (ILE->initializesStdInitializerList()) { - //CGM.ErrorUnsupported(ILE, "global std::initializer_list"); - return false; - } - RecordDecl *RD = ILE->getType()->getAs<RecordType>()->getDecl(); const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 7bbf788eb52..4619322e1e1 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -1631,10 +1631,6 @@ public: llvm::Value *EmitDynamicCast(llvm::Value *V, const CXXDynamicCastExpr *DCE); llvm::Value* EmitCXXUuidofExpr(const CXXUuidofExpr *E); - void MaybeEmitStdInitializerListCleanup(llvm::Value *loc, const Expr *init); - void EmitStdInitializerListCleanup(llvm::Value *loc, - const InitListExpr *init); - /// \brief Situations in which we might emit a check for the suitability of a /// pointer or glvalue. enum TypeCheckKind { 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(); diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index b2ff60deff2..ffb1243726e 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -1020,8 +1020,6 @@ private: void EmitGlobalFunctionDefinition(GlobalDecl GD); void EmitGlobalVarDefinition(const VarDecl *D); - llvm::Constant *MaybeEmitGlobalStdInitializerListInitializer(const VarDecl *D, - const Expr *init); void EmitAliasDefinition(GlobalDecl GD); void EmitObjCPropertyImplementations(const ObjCImplementationDecl *D); void EmitObjCIvarInitializations(ObjCImplementationDecl *D); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 5d6eab0f173..be198ad3782 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -2153,10 +2153,6 @@ Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation InitLoc, ExprResult Init = InitExpr; if (!FD->getType()->isDependentType() && !InitExpr->isTypeDependent()) { - if (isa<InitListExpr>(InitExpr) && isStdInitializerList(FD->getType(), 0)) { - Diag(FD->getLocation(), diag::warn_dangling_std_initializer_list) - << /*at end of ctor*/1 << InitExpr->getSourceRange(); - } InitializedEntity Entity = InitializedEntity::InitializeMember(FD); InitializationKind Kind = FD->getInClassInitStyle() == ICIS_ListInit ? InitializationKind::CreateDirectList(InitExpr->getLocStart()) @@ -2550,11 +2546,6 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init, if (isa<InitListExpr>(Init)) { InitList = true; Args = Init; - - if (isStdInitializerList(Member->getType(), 0)) { - Diag(IdLoc, diag::warn_dangling_std_initializer_list) - << /*at end of ctor*/1 << InitRange; - } } // Initialize the member. diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index a121a75fa48..7ed32b89e3d 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -1006,6 +1006,7 @@ CanThrowResult Sema::canThrow(const Expr *E) { case Expr::CompoundLiteralExprClass: case Expr::CXXConstCastExprClass: case Expr::CXXReinterpretCastExprClass: + case Expr::CXXStdInitializerListExprClass: case Expr::DesignatedInitExprClass: case Expr::ExprWithCleanupsClass: case Expr::ExtVectorElementExprClass: diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index a4bccacb2da..18b3d8225e0 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -2937,6 +2937,12 @@ static void MaybeProduceObjCObject(Sema &S, } } +static void TryListInitialization(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + InitListExpr *InitList, + InitializationSequence &Sequence); + /// \brief When initializing from init list via constructor, handle /// initialization of an object of type std::initializer_list<T>. /// @@ -2950,25 +2956,23 @@ static bool TryInitializerListConstruction(Sema &S, if (!S.isStdInitializerList(DestType, &E)) return false; - // Check that each individual element can be copy-constructed. But since we - // have no place to store further information, we'll recalculate everything - // later. - InitializedEntity HiddenArray = InitializedEntity::InitializeTemporary( - S.Context.getConstantArrayType(E, - llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()), - List->getNumInits()), - ArrayType::Normal, 0)); - InitializedEntity Element = InitializedEntity::InitializeElement(S.Context, - 0, HiddenArray); - for (unsigned i = 0, n = List->getNumInits(); i < n; ++i) { - Element.setElementIndex(i); - if (!S.CanPerformCopyInitialization(Element, List->getInit(i))) { - Sequence.SetFailed( - InitializationSequence::FK_InitListElementCopyFailure); - return true; - } + if (S.RequireCompleteType(List->getExprLoc(), E, 0)) { + Sequence.setIncompleteTypeFailure(E); + return true; } - Sequence.AddStdInitializerListConstructionStep(DestType); + + // Try initializing a temporary array from the init list. + QualType ArrayType = S.Context.getConstantArrayType( + E.withConst(), llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()), + List->getNumInits()), + clang::ArrayType::Normal, 0); + InitializedEntity HiddenArray = + InitializedEntity::InitializeTemporary(ArrayType); + InitializationKind Kind = + InitializationKind::CreateDirectList(List->getExprLoc()); + TryListInitialization(S, HiddenArray, Kind, List, Sequence); + if (Sequence) + Sequence.AddStdInitializerListConstructionStep(DestType); return true; } @@ -3198,12 +3202,6 @@ static void TryValueInitialization(Sema &S, InitializationSequence &Sequence, InitListExpr *InitList = 0); -static void TryListInitialization(Sema &S, - const InitializedEntity &Entity, - const InitializationKind &Kind, - InitListExpr *InitList, - InitializationSequence &Sequence); - /// \brief Attempt list initialization of a reference. static void TryReferenceListInitialization(Sema &S, const InitializedEntity &Entity, @@ -5135,7 +5133,7 @@ PerformConstructorInitialization(Sema &S, return ExprError(); if (shouldBindAsTemporary(Entity)) - CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>()); + CurInit = S.MaybeBindToTemporary(CurInit.take()); return CurInit; } @@ -5277,19 +5275,18 @@ static void performLifetimeExtension(Expr *Init, const ValueDecl *ExtendingD) { if (CXXBindTemporaryExpr *BTE = dyn_cast<CXXBindTemporaryExpr>(Init)) Init = BTE->getSubExpr(); + if (CXXStdInitializerListExpr *ILE = + dyn_cast<CXXStdInitializerListExpr>(Init)) + return performReferenceExtension(ILE->getSubExpr(), ExtendingD); + if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) { - if (ILE->initializesStdInitializerList() || ILE->getType()->isArrayType()) { - // FIXME: If this is an InitListExpr which creates a std::initializer_list - // object, we also need to lifetime-extend the underlying array - // itself. Fix the representation to explicitly materialize an - // array temporary so we can model this properly. + if (ILE->getType()->isArrayType()) { for (unsigned I = 0, N = ILE->getNumInits(); I != N; ++I) performLifetimeExtension(ILE->getInit(I), ExtendingD); return; } - CXXRecordDecl *RD = ILE->getType()->getAsCXXRecordDecl(); - if (RD) { + if (CXXRecordDecl *RD = ILE->getType()->getAsCXXRecordDecl()) { assert(RD->isAggregate() && "aggregate init on non-aggregate"); // If we lifetime-extend a braced initializer which is initializing an @@ -5319,6 +5316,39 @@ static void performLifetimeExtension(Expr *Init, const ValueDecl *ExtendingD) { } } +static void warnOnLifetimeExtension(Sema &S, const InitializedEntity &Entity, + const Expr *Init, bool IsInitializerList, + const ValueDecl *ExtendingDecl) { + // Warn if a field lifetime-extends a temporary. + if (isa<FieldDecl>(ExtendingDecl)) { + if (IsInitializerList) { + S.Diag(Init->getExprLoc(), diag::warn_dangling_std_initializer_list) + << /*at end of constructor*/true; + return; + } + + bool IsSubobjectMember = false; + for (const InitializedEntity *Ent = Entity.getParent(); Ent; + Ent = Ent->getParent()) { + if (Ent->getKind() != InitializedEntity::EK_Base) { + IsSubobjectMember = true; + break; + } + } + S.Diag(Init->getExprLoc(), + diag::warn_bind_ref_member_to_temporary) + << ExtendingDecl << Init->getSourceRange() + << IsSubobjectMember << IsInitializerList; + if (IsSubobjectMember) + S.Diag(ExtendingDecl->getLocation(), + diag::note_ref_subobject_of_member_declared_here); + else + S.Diag(ExtendingDecl->getLocation(), + diag::note_ref_or_ptr_member_declared_here) + << /*is pointer*/false; + } +} + ExprResult InitializationSequence::Perform(Sema &S, const InitializedEntity &Entity, @@ -5570,29 +5600,7 @@ InitializationSequence::Perform(Sema &S, getDeclForTemporaryLifetimeExtension(Entity); if (ExtendingDecl) { performLifetimeExtension(CurInit.get(), ExtendingDecl); - - // Warn if a field lifetime-extends a temporary. - if (isa<FieldDecl>(ExtendingDecl)) { - bool IsSubobjectMember = false; - for (const InitializedEntity *Ent = Entity.getParent(); Ent; - Ent = Ent->getParent()) { - if (Ent->getKind() != InitializedEntity::EK_Base) { - IsSubobjectMember = true; - break; - } - } - S.Diag(CurInit.get()->getExprLoc(), - diag::warn_bind_ref_member_to_temporary) - << ExtendingDecl << CurInit.get()->getSourceRange() - << IsSubobjectMember; - if (IsSubobjectMember) - S.Diag(ExtendingDecl->getLocation(), - diag::note_ref_subobject_of_member_declared_here); - else - S.Diag(ExtendingDecl->getLocation(), - diag::note_ref_or_ptr_member_declared_here) - << /*IsPointer*/false; - } + warnOnLifetimeExtension(S, Entity, CurInit.get(), false, ExtendingDecl); } // Materialize the temporary into memory. @@ -5763,16 +5771,10 @@ InitializationSequence::Perform(Sema &S, case SK_ListInitialization: { InitListExpr *InitList = cast<InitListExpr>(CurInit.get()); - // Hack: We must pass *ResultType if available in order to set the type - // of arrays, e.g. in 'int ar[] = {1, 2, 3};'. - // But in 'const X &x = {1, 2, 3};' we're supposed to initialize a - // temporary, not a reference, so we should pass Ty. - // Worst case: 'const int (&arref)[] = {1, 2, 3};'. - // Since this step is never used for a reference directly, we explicitly - // unwrap references here and rewrap them afterwards. - // We also need to create a InitializeTemporary entity for this. - QualType Ty = ResultType ? ResultType->getNonReferenceType() : Step->Type; - bool IsTemporary = Entity.getType()->isReferenceType(); + // If we're not initializing the top-level entity, we need to create an + // InitializeTemporary entity for our target type. + QualType Ty = Step->Type; + bool IsTemporary = !S.Context.hasSameType(Entity.getType(), Ty); InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(Ty); InitializedEntity InitEntity = IsTemporary ? TempEntity : Entity; InitListChecker PerformInitList(S, InitEntity, @@ -5780,7 +5782,11 @@ InitializationSequence::Perform(Sema &S, if (PerformInitList.HadError()) return ExprError(); - if (ResultType) { + // Hack: We must update *ResultType if available in order to set the + // bounds of arrays, e.g. in 'int ar[] = {1, 2, 3};'. + // Worst case: 'const int (&arref)[] = {1, 2, 3};'. + if (ResultType && + ResultType->getNonReferenceType()->isIncompleteArrayType()) { if ((*ResultType)->isRValueReferenceType()) Ty = S.Context.getRValueReferenceType(Ty); else if ((*ResultType)->isLValueReferenceType()) @@ -5973,56 +5979,35 @@ InitializationSequence::Perform(Sema &S, break; case SK_StdInitializerList: { - QualType Dest = Step->Type; - QualType E; - bool Success = S.isStdInitializerList(Dest.getNonReferenceType(), &E); - (void)Success; - assert(Success && "Destination type changed?"); - - // If the element type has a destructor, check it. - if (CXXRecordDecl *RD = E->getAsCXXRecordDecl()) { - if (!RD->hasIrrelevantDestructor()) { - if (CXXDestructorDecl *Destructor = S.LookupDestructor(RD)) { - S.MarkFunctionReferenced(Kind.getLocation(), Destructor); - S.CheckDestructorAccess(Kind.getLocation(), Destructor, - S.PDiag(diag::err_access_dtor_temp) << E); - if (S.DiagnoseUseOfDecl(Destructor, Kind.getLocation())) - return ExprError(); - } - } - } + S.Diag(CurInit.get()->getExprLoc(), + diag::warn_cxx98_compat_initializer_list_init) + << CurInit.get()->getSourceRange(); - InitListExpr *ILE = cast<InitListExpr>(CurInit.take()); - S.Diag(ILE->getExprLoc(), diag::warn_cxx98_compat_initializer_list_init) - << ILE->getSourceRange(); - unsigned NumInits = ILE->getNumInits(); - SmallVector<Expr*, 16> Converted(NumInits); - InitializedEntity HiddenArray = InitializedEntity::InitializeTemporary( - S.Context.getConstantArrayType(E, - llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()), - NumInits), - ArrayType::Normal, 0)); - InitializedEntity Element =InitializedEntity::InitializeElement(S.Context, - 0, HiddenArray); - for (unsigned i = 0; i < NumInits; ++i) { - Element.setElementIndex(i); - ExprResult Init = S.Owned(ILE->getInit(i)); - ExprResult Res = S.PerformCopyInitialization( - Element, Init.get()->getExprLoc(), Init, - /*TopLevelOfInitList=*/ true); - if (Res.isInvalid()) - return ExprError(); - Converted[i] = Res.take(); + // Maybe lifetime-extend the array temporary's subobjects to match the + // entity's lifetime. + const ValueDecl *ExtendingDecl = + getDeclForTemporaryLifetimeExtension(Entity); + if (ExtendingDecl) { + performLifetimeExtension(CurInit.get(), ExtendingDecl); + warnOnLifetimeExtension(S, Entity, CurInit.get(), true, ExtendingDecl); } - InitListExpr *Semantic = new (S.Context) - InitListExpr(S.Context, ILE->getLBraceLoc(), - Converted, ILE->getRBraceLoc()); - Semantic->setSyntacticForm(ILE); - Semantic->setType(Dest); - Semantic->setInitializesStdInitializerList(); - CurInit = S.Owned(Semantic); + + // Materialize the temporary into memory. + MaterializeTemporaryExpr *MTE = new (S.Context) + MaterializeTemporaryExpr(CurInit.get()->getType(), CurInit.get(), + /*lvalue reference*/ false, ExtendingDecl); + + // Wrap it in a construction of a std::initializer_list<T>. + CurInit = S.Owned( + new (S.Context) CXXStdInitializerListExpr(Step->Type, MTE)); + + // Bind the result, in case the library has given initializer_list a + // non-trivial destructor. + if (shouldBindAsTemporary(Entity)) + CurInit = S.MaybeBindToTemporary(CurInit.take()); break; } + case SK_OCLSamplerInit: { assert(Step->Type->isSamplerT() && "Sampler initialization on non sampler type."); diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index fe49153d991..da1e41c2afb 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -2639,6 +2639,10 @@ ExprResult TreeTransform<Derived>::TransformInitializer(Expr *Init, if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Init)) Init = ICE->getSubExprAsWritten(); + if (CXXStdInitializerListExpr *ILE = + dyn_cast<CXXStdInitializerListExpr>(Init)) + return TransformInitializer(ILE->getSubExpr(), CXXDirectInit); + // If this is not a direct-initializer, we only need to reconstruct // InitListExprs. Other forms of copy-initialization will be a no-op if // the initializer is already the right type. @@ -8549,6 +8553,13 @@ TreeTransform<Derived>::TransformMaterializeTemporaryExpr( template<typename Derived> ExprResult +TreeTransform<Derived>::TransformCXXStdInitializerListExpr( + CXXStdInitializerListExpr *E) { + return getDerived().TransformExpr(E->getSubExpr()); +} + +template<typename Derived> +ExprResult TreeTransform<Derived>::TransformObjCStringLiteral(ObjCStringLiteral *E) { return SemaRef.MaybeBindToTemporary(E); } diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index 9e0157d7afb..2f5dee8282d 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -723,7 +723,6 @@ void ASTStmtReader::VisitInitListExpr(InitListExpr *E) { } else E->ArrayFillerOrUnionFieldInit = ReadDeclAs<FieldDecl>(Record, Idx); E->sawArrayRangeDesignator(Record[Idx++]); - E->setInitializesStdInitializerList(Record[Idx++]); unsigned NumInits = Record[Idx++]; E->reserveInits(Reader.getContext(), NumInits); if (isArrayFiller) { @@ -1227,6 +1226,12 @@ void ASTStmtReader::VisitLambdaExpr(LambdaExpr *E) { } } +void +ASTStmtReader::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) { + VisitExpr(E); + E->SubExpr = Reader.ReadSubExpr(); +} + void ASTStmtReader::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) { VisitExplicitCastExpr(E); SourceRange R = ReadSourceRange(Record, Idx); @@ -2161,6 +2166,10 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { S = new (Context) UserDefinedLiteral(Context, Empty); break; + case EXPR_CXX_STD_INITIALIZER_LIST: + S = new (Context) CXXStdInitializerListExpr(Empty); + break; + case EXPR_CXX_BOOL_LITERAL: S = new (Context) CXXBoolLiteralExpr(Empty); break; diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index ba6243a51af..ece297f3e53 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -735,6 +735,7 @@ static void AddStmtsExprs(llvm::BitstreamWriter &Stream, RECORD(EXPR_CXX_CONST_CAST); RECORD(EXPR_CXX_FUNCTIONAL_CAST); RECORD(EXPR_USER_DEFINED_LITERAL); + RECORD(EXPR_CXX_STD_INITIALIZER_LIST); RECORD(EXPR_CXX_BOOL_LITERAL); RECORD(EXPR_CXX_NULL_PTR_LITERAL); RECORD(EXPR_CXX_TYPEID_EXPR); diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index 5a8baa9d88a..4b01a218f56 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -683,7 +683,6 @@ void ASTStmtWriter::VisitInitListExpr(InitListExpr *E) { else Writer.AddDeclRef(E->getInitializedFieldInUnion(), Record); Record.push_back(E->hadArrayRangeDesignator()); - Record.push_back(E->initializesStdInitializerList()); Record.push_back(E->getNumInits()); if (isArrayFiller) { // ArrayFiller may have filled "holes" due to designated initializer. @@ -1187,6 +1186,12 @@ void ASTStmtWriter::VisitLambdaExpr(LambdaExpr *E) { Code = serialization::EXPR_LAMBDA; } +void ASTStmtWriter::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) { + VisitExpr(E); + Writer.AddStmt(E->getSubExpr()); + Code = serialization::EXPR_CXX_STD_INITIALIZER_LIST; +} + void ASTStmtWriter::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) { VisitExplicitCastExpr(E); Writer.AddSourceRange(SourceRange(E->getOperatorLoc(), E->getRParenLoc()), diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index a07b72e36f2..db32003e7bf 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -607,6 +607,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::CXXDefaultInitExprClass: case Stmt::CXXDependentScopeMemberExprClass: case Stmt::CXXPseudoDestructorExprClass: + case Stmt::CXXStdInitializerListExprClass: case Stmt::CXXTryStmtClass: case Stmt::CXXTypeidExprClass: case Stmt::CXXUuidofExprClass: |