diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -1495,6 +1495,13 @@ // initializers throws an exception. SmallVector cleanups; llvm::Instruction *cleanupDominator = nullptr; + auto addCleanup = [&](const EHScopeStack::stable_iterator &cleanup) { + cleanups.push_back(cleanup); + if (!cleanupDominator) // create placeholder once needed + cleanupDominator = CGF.Builder.CreateAlignedLoad( + CGF.Int8Ty, llvm::Constant::getNullValue(CGF.Int8PtrTy), + CharUnits::One()); + }; unsigned curInitIndex = 0; @@ -1519,7 +1526,7 @@ if (QualType::DestructionKind dtorKind = Base.getType().isDestructedType()) { CGF.pushDestroy(dtorKind, V, Base.getType()); - cleanups.push_back(CGF.EHStack.stable_begin()); + addCleanup(CGF.EHStack.stable_begin()); } } } @@ -1596,15 +1603,9 @@ = field->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(), field->getType(), CGF.getDestroyer(dtorKind), false); - cleanups.push_back(CGF.EHStack.stable_begin()); + addCleanup(CGF.EHStack.stable_begin()); pushedCleanup = true; } } @@ -1620,6 +1621,8 @@ // Deactivate all the partial cleanups in reverse order, which // generally means popping them. + assert((cleanupDominator || cleanups.empty()) && + "Missing cleanupDominator before deactivating cleanup blocks"); for (unsigned i = cleanups.size(); i != 0; --i) CGF.DeactivateCleanupBlock(cleanups[i-1], cleanupDominator); diff --git a/clang/test/CodeGenCXX/pr40771-ctad-with-lambda-copy-capture.cpp b/clang/test/CodeGenCXX/pr40771-ctad-with-lambda-copy-capture.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/pr40771-ctad-with-lambda-copy-capture.cpp @@ -0,0 +1,51 @@ +// RUN: %clang_cc1 -emit-llvm --std=c++17 -fcxx-exceptions -fexceptions \ +// RUN: %s -o - | FileCheck %s + +struct Q { Q(); }; +struct R { R(Q); ~R(); }; +struct S { S(Q); ~S(); }; +struct T : R, S {}; + +Q q; +T t { R{q}, S{q} }; + +// CHECK-LABEL: define internal void @__cxx_global_var_init.1() {{.*}} { +// CHECK-LABEL: entry: +// CHECK: %cleanup.isactive = alloca i1, align 1 +// CHECK: call void @_ZN1RC1E1Q(%struct.R* %ref.tmp) +// CHECK: store i1 true, i1* %cleanup.isactive, align 1 +// CHECK: invoke void @_ZN1SC1E1Q(%struct.S* %ref.tmp1) +// CHECK: to label %invoke.cont unwind label %lpad + +// CHECK-LABEL: invoke.cont: +// CHECK: store i1 false, i1* %cleanup.isactive, align 1 +// CHECK: call void @_ZN1SD1Ev(%struct.S* +// CHECK: call void @_ZN1RD1Ev(%struct.R* +// CHECK: %0 = call i32 @__cxa_atexit( +// CHECK: ret void + +// CHECK-LABEL: lpad: +// CHECK: %1 = landingpad { i8*, i32 } +// CHECK: cleanup +// CHECK: %2 = extractvalue { i8*, i32 } %1, 0 +// CHECK: store i8* %2, i8** %exn.slot, align 8 +// CHECK: %3 = extractvalue { i8*, i32 } %1, 1 +// CHECK: store i32 %3, i32* %ehselector.slot, align 4 +// CHECK: %cleanup.is_active = load i1, i1* %cleanup.isactive, align 1 +// CHECK: br i1 %cleanup.is_active, label %cleanup.action, label %cleanup.done + +// CHECK-LABEL: cleanup.action: +// CHECK: call void @_ZN1RD1Ev(%struct.R* +// CHECK: br label %cleanup.done + +// CHECK-LABEL: cleanup.done: +// CHECK: call void @_ZN1RD1Ev(%struct.R* %ref.tmp) +// CHECK: br label %eh.resume + +// CHECK-LABEL: eh.resume: +// CHECK: %exn = load i8*, i8** %exn.slot, align 8 +// CHECK: %sel = load i32, i32* %ehselector.slot, align 4 +// CHECK: %lpad.val = insertvalue { i8*, i32 } undef, i8* %exn, 0 +// CHECK: %lpad.val3 = insertvalue { i8*, i32 } %lpad.val, i32 %sel, 1 +// CHECK: resume { i8*, i32 } %lpad.val3 +// CHECK: }