diff options
-rw-r--r-- | clang/lib/CodeGen/CGExpr.cpp | 9 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGExprAgg.cpp | 47 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGExprCXX.cpp | 18 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenFunction.h | 6 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/cxx1y-init-captures-eh.cpp | 104 |
5 files changed, 153 insertions, 31 deletions
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 34a921e2dc0..f986bc4c4cf 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -1287,8 +1287,6 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { return EmitCXXBindTemporaryLValue(cast<CXXBindTemporaryExpr>(E)); case Expr::CXXUuidofExprClass: return EmitCXXUuidofLValue(cast<CXXUuidofExpr>(E)); - case Expr::LambdaExprClass: - return EmitLambdaLValue(cast<LambdaExpr>(E)); case Expr::ExprWithCleanupsClass: { const auto *cleanups = cast<ExprWithCleanups>(E); @@ -4548,13 +4546,6 @@ CodeGenFunction::EmitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *E) { return MakeAddrLValue(Slot.getAddress(), E->getType(), AlignmentSource::Decl); } -LValue -CodeGenFunction::EmitLambdaLValue(const LambdaExpr *E) { - AggValueSlot Slot = CreateAggTemp(E->getType(), "temp.lvalue"); - EmitLambdaExpr(E, Slot); - return MakeAddrLValue(Slot.getAddress(), E->getType(), AlignmentSource::Decl); -} - LValue CodeGenFunction::EmitObjCMessageExprLValue(const ObjCMessageExpr *E) { RValue RV = EmitObjCMessageExpr(E); diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index db49b3f28a5..be6e938c308 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -1264,7 +1264,52 @@ void AggExprEmitter::VisitCXXInheritedCtorInitExpr( void AggExprEmitter::VisitLambdaExpr(LambdaExpr *E) { AggValueSlot Slot = EnsureSlot(E->getType()); - CGF.EmitLambdaExpr(E, Slot); + LValue SlotLV = CGF.MakeAddrLValue(Slot.getAddress(), E->getType()); + + // We'll need to enter cleanup scopes in case any of the element + // initializers throws an exception. + SmallVector<EHScopeStack::stable_iterator, 16> Cleanups; + llvm::Instruction *CleanupDominator = nullptr; + + CXXRecordDecl::field_iterator CurField = E->getLambdaClass()->field_begin(); + for (LambdaExpr::const_capture_init_iterator i = E->capture_init_begin(), + e = E->capture_init_end(); + i != e; ++i, ++CurField) { + // Emit initialization + LValue LV = CGF.EmitLValueForFieldInitialization(SlotLV, *CurField); + if (CurField->hasCapturedVLAType()) { + CGF.EmitLambdaVLACapture(CurField->getCapturedVLAType(), LV); + continue; + } + + EmitInitializationToLValue(*i, LV); + + // Push a destructor if necessary. + if (QualType::DestructionKind DtorKind = + CurField->getType().isDestructedType()) { + assert(LV.isSimple()); + if (CGF.needsEHCleanup(DtorKind)) { + if (!CleanupDominator) + CleanupDominator = CGF.Builder.CreateAlignedLoad( + CGF.Int8Ty, + llvm::Constant::getNullValue(CGF.Int8PtrTy), + CharUnits::One()); // placeholder + + CGF.pushDestroy(EHCleanup, LV.getAddress(), CurField->getType(), + CGF.getDestroyer(DtorKind), false); + Cleanups.push_back(CGF.EHStack.stable_begin()); + } + } + } + + // Deactivate all the partial cleanups in reverse order, which + // generally means popping them. + for (unsigned i = Cleanups.size(); i != 0; --i) + CGF.DeactivateCleanupBlock(Cleanups[i-1], CleanupDominator); + + // Destroy the placeholder if we made one. + if (CleanupDominator) + CleanupDominator->eraseFromParent(); } void AggExprEmitter::VisitExprWithCleanups(ExprWithCleanups *E) { diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp index 884ce96859c..98ef25bb192 100644 --- a/clang/lib/CodeGen/CGExprCXX.cpp +++ b/clang/lib/CodeGen/CGExprCXX.cpp @@ -2253,21 +2253,3 @@ llvm::Value *CodeGenFunction::EmitDynamicCast(Address ThisAddr, return Value; } - -void CodeGenFunction::EmitLambdaExpr(const LambdaExpr *E, AggValueSlot Slot) { - LValue SlotLV = MakeAddrLValue(Slot.getAddress(), E->getType()); - - CXXRecordDecl::field_iterator CurField = E->getLambdaClass()->field_begin(); - for (LambdaExpr::const_capture_init_iterator i = E->capture_init_begin(), - e = E->capture_init_end(); - i != e; ++i, ++CurField) { - // Emit initialization - LValue LV = EmitLValueForFieldInitialization(SlotLV, *CurField); - if (CurField->hasCapturedVLAType()) { - auto VAT = CurField->getCapturedVLAType(); - EmitStoreThroughLValue(RValue::get(VLASizeMap[VAT->getSizeExpr()]), LV); - } else { - EmitInitializerForField(*CurField, LV, *i); - } - } -} diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 89cb850ab1b..005337a56b9 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -1836,6 +1836,9 @@ public: void EmitLambdaBlockInvokeBody(); void EmitLambdaDelegatingInvokeBody(const CXXMethodDecl *MD); void EmitLambdaStaticInvokeBody(const CXXMethodDecl *MD); + void EmitLambdaVLACapture(const VariableArrayType *VAT, LValue LV) { + EmitStoreThroughLValue(RValue::get(VLASizeMap[VAT->getSizeExpr()]), LV); + } void EmitAsanPrologueOrEpilogue(bool Prologue); /// Emit the unified return block, trying to avoid its emission when @@ -3560,7 +3563,6 @@ public: LValue EmitCXXConstructLValue(const CXXConstructExpr *E); LValue EmitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *E); - LValue EmitLambdaLValue(const LambdaExpr *E); LValue EmitCXXTypeidLValue(const CXXTypeidExpr *E); LValue EmitCXXUuidofLValue(const CXXUuidofExpr *E); @@ -3982,8 +3984,6 @@ public: void EmitCXXThrowExpr(const CXXThrowExpr *E, bool KeepInsertionPoint = true); - void EmitLambdaExpr(const LambdaExpr *E, AggValueSlot Dest); - RValue EmitAtomicExpr(AtomicExpr *E); //===--------------------------------------------------------------------===// diff --git a/clang/test/CodeGenCXX/cxx1y-init-captures-eh.cpp b/clang/test/CodeGenCXX/cxx1y-init-captures-eh.cpp new file mode 100644 index 00000000000..70103dccb15 --- /dev/null +++ b/clang/test/CodeGenCXX/cxx1y-init-captures-eh.cpp @@ -0,0 +1,104 @@ +// RUN: %clang_cc1 -std=c++1y -triple x86_64-linux-gnu -fexceptions -fcxx-exceptions -emit-llvm %s -o - | FileCheck %s + +struct S { + S(); + ~S(); +}; + +struct T { + T() noexcept; + ~T(); + int n; +}; + +// CHECK-LABEL: define void @_Z1fv( +void f() { + // CHECK: call void @_ZN1SC1Ev( + // CHECK: invoke void @__cxa_throw + // + // Ensure we call the lambda destructor here, and do not call the destructor + // for the capture. + // CHECK: landingpad + // CHECK-NOT: _ZN1SD + // CHECK: call void @"_ZZ1fvEN3$_0D1Ev"( + // CHECK-NOT: _ZN1SD + // CHECK: resume + [s = S()] {}, throw 0; + + // CHECK: } +} + +// CHECK-LABEL: define void @_Z1gv( +void g() { + // CHECK: call void @_ZN1SC1Ev( + // CHECK: invoke void @__cxa_throw + // + // Ensure we call the lambda destructor here, and do not call the destructor + // for the capture. + // CHECK: landingpad + // CHECK-NOT: @"_ZZ1gvEN3$_0D1Ev"( + // CHECK: call void @_ZN1SD1Ev( + // CHECK-NOT: @"_ZZ1gvEN3$_0D1Ev"( + // CHECK: resume + [s = S(), t = (throw 0, 1)] {}; + + // CHECK: } +} + +void x() noexcept; +void y() noexcept; + +// CHECK-LABEL: define void @_Z1hbb( +void h(bool b1, bool b2) { + // CHECK: {{.*}} = alloca i1, + // CHECK: %[[S_ISACTIVE:.*]] = alloca i1, + // CHECK: {{.*}} = alloca i1, + + // lambda init: s and t, branch on b1 + // CHECK: call void @_ZN1SC1Ev( + // CHECK: store i1 true, i1* %[[S_ISACTIVE]], align 1 + // CHECK: call void @_ZN1TC1Ev( + // CHECK: br i1 + + // throw 1 + // CHECK: invoke void @__cxa_throw + + // completion of lambda init, branch on b2 + // CHECK: store i32 42, + // CHECK: store i1 false, i1* %[[S_ISACTIVE]], align 1 + // CHECK: br i1 + + // throw 2 + // CHECK: invoke void @__cxa_throw + + // end of full-expression + // CHECK: call void @_Z1xv( + // CHECK: call void @"_ZZ1hbbEN3$_2D1Ev"( + // CHECK: call void @_ZN1TD1Ev( + // CHECK: call void @_Z1yv( + // CHECK: ret void + + // cleanups for throw 1 + // CHECK: landingpad + // CHECK-NOT: @"_ZZ1hbbEN3$_2D1Ev"( + // CHECK: br + + // cleanups for throw 2 + // CHECK: landingpad + // CHECK: call void @"_ZZ1hbbEN3$_2D1Ev"( + // CHECK: br + + // common cleanup code + // CHECK: call void @_ZN1TD1Ev( + // CHECK: load i1, i1* %[[S_ISACTIVE]], + // CHECK: br i1 + + // CHECK: call void @_ZN1SD1Ev( + // CHECK: br + + // CHECK: resume + [s = S(), t = T().n, u = (b1 ? throw 1 : 42)] {}, (b2 ? throw 2 : 0), x(); + y(); + + // CHECK: } +} |