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);
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);
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) {
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);
- }
- }
-}
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
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);
void EmitCXXThrowExpr(const CXXThrowExpr *E, bool KeepInsertionPoint = true);
- void EmitLambdaExpr(const LambdaExpr *E, AggValueSlot Dest);
-
RValue EmitAtomicExpr(AtomicExpr *E);
//===--------------------------------------------------------------------===//
--- /dev/null
+// 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: }
+}