llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Andy Kaylor (andykaylor) <details> <summary>Changes</summary> This adds EH cleanup handling for C++ initializer list expressions containing destructed types. The necessary support for deferred deactivation cleanups was already in place, so this just needed to push the deferred destroy cleanup when the init list element is constructed. --- Full diff: https://github.com/llvm/llvm-project/pull/192172.diff 3 Files Affected: - (modified) clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp (+9-5) - (added) clang/test/CIR/CodeGen/paren-init-list-eh.cpp (+115) - (modified) clang/test/CIR/CodeGen/paren-init-list.cpp (+54) ``````````diff diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp index ec8ebf75ccbee..ae243f2ec3905 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp @@ -1088,7 +1088,7 @@ void AggExprEmitter::visitCXXParenListOrInitListExpr( // We'll need to enter cleanup scopes in case any of the element // initializers throws an exception. - assert(!cir::MissingFeatures::requiresCleanups()); + CIRGenFunction::CleanupDeactivationScope deactivateCleanups(cgf); unsigned curInitIndex = 0; @@ -1189,10 +1189,14 @@ void AggExprEmitter::visitCXXParenListOrInitListExpr( // Push a destructor if necessary. // FIXME: if we have an array of structures, all explicitly // initialized, we can end up pushing a linear number of cleanups. - if (field->getType().isDestructedType()) { - cgf.cgm.errorNYI(e->getSourceRange(), - "visitCXXParenListOrInitListExpr destructor"); - return; + if (QualType::DestructionKind dtorKind = + field->getType().isDestructedType()) { + assert(lv.isSimple()); + if (dtorKind) { + cgf.pushDestroyAndDeferDeactivation(NormalAndEHCleanup, lv.getAddress(), + field->getType(), + cgf.getDestroyer(dtorKind), false); + } } // From classic codegen, maybe not useful for CIR: diff --git a/clang/test/CIR/CodeGen/paren-init-list-eh.cpp b/clang/test/CIR/CodeGen/paren-init-list-eh.cpp new file mode 100644 index 0000000000000..89e400b70700d --- /dev/null +++ b/clang/test/CIR/CodeGen/paren-init-list-eh.cpp @@ -0,0 +1,115 @@ +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fexceptions -fcxx-exceptions -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fexceptions -fcxx-exceptions -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fexceptions -fcxx-exceptions -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s + +struct Struk { + int val; + Struk(int); + ~Struk(); +}; + +struct Outer { + Struk s1; + Struk s2; + int x; +}; + +void test_init_list_with_dtor() { + Outer o = {Struk{1}, Struk{2}, 3}; +} + +// CIR: cir.func {{.*}} @_Z24test_init_list_with_dtorv +// CIR: %[[O:.*]] = cir.alloca !rec_Outer, !cir.ptr<!rec_Outer>, ["o", init] +// CIR: cir.scope { +// CIR: %[[S1:.*]] = cir.get_member %[[O]][0] {name = "s1"} : !cir.ptr<!rec_Outer> -> !cir.ptr<!rec_Struk> +// CIR: %[[ONE:.*]] = cir.const #cir.int<1> +// CIR: cir.call @_ZN5StrukC1Ei(%[[S1]], %[[ONE]]) +// CIR: cir.cleanup.scope { +// CIR: %[[S2:.*]] = cir.get_member %[[O]][1] {name = "s2"} : !cir.ptr<!rec_Outer> -> !cir.ptr<!rec_Struk> +// CIR: %[[TWO:.*]] = cir.const #cir.int<2> +// CIR: cir.call @_ZN5StrukC1Ei(%[[S2]], %[[TWO]]) +// CIR: cir.cleanup.scope { +// CIR: %[[X:.*]] = cir.get_member %[[O]][2] {name = "x"} +// CIR: %[[THREE:.*]] = cir.const #cir.int<3> : !s32i +// CIR: cir.store align(4) %[[THREE]], %[[X]] +// CIR: cir.yield +// CIR: } cleanup eh { +// CIR: cir.call @_ZN5StrukD1Ev(%[[S2]]) +// CIR: cir.yield +// CIR: } +// CIR: cir.yield +// CIR: } cleanup eh { +// CIR: cir.call @_ZN5StrukD1Ev(%[[S1]]) +// CIR: cir.yield +// CIR: } +// CIR: } +// CIR: cir.cleanup.scope { +// CIR: cir.yield +// CIR: } cleanup all { +// CIR: cir.call @_ZN5OuterD1Ev(%[[O]]) +// CIR: cir.yield +// CIR: } +// CIR: cir.return +// CIR: } + +// LLVM: define {{.*}} void @_Z24test_init_list_with_dtorv +// LLVM: %[[O:.*]] = alloca %struct.Outer +// LLVM: %[[S1_ADDR:.*]] = getelementptr %struct.Outer, ptr %[[O]], i32 0, i32 0 +// LLVM: call void @_ZN5StrukC1Ei(ptr {{.*}} %[[S1_ADDR]], i32 {{.*}} 1) +// LLVM: %[[S2_ADDR:.*]] = getelementptr %struct.Outer, ptr %[[O]], i32 0, i32 1 +// LLVM: invoke void @_ZN5StrukC1Ei(ptr {{.*}} %[[S2_ADDR]], i32 {{.*}} 2) +// LLVM: to label %[[CONT:.*]] unwind label %[[LPAD:.*]] +// LLVM: [[CONT]]: +// LLVM: %[[X_ADDR:.*]] = getelementptr %struct.Outer, ptr %[[O]], i32 0, i32 2 +// LLVM: store i32 3, ptr %[[X_ADDR]] +// LLVM: br label %[[EXIT_CLEANUP_SCOPE:.*]] +// LLVM: [[EXIT_CLEANUP_SCOPE]]: +// LLVM: br label %[[DONE:.*]] +// LLVM: [[LPAD]]: +// LLVM: %[[EXN:.*]] = landingpad { ptr, i32 } +// LLVM: cleanup +// LLVM: %[[EXN_ADDR:.*]] = extractvalue { ptr, i32 } %[[EXN]], 0 +// LLVM: %[[EXN_SELECTOR:.*]] = extractvalue { ptr, i32 } %[[EXN]], 1 +// LLVM: br label %[[EH_CLEANUP:.*]] +// LLVM: [[EH_CLEANUP]]: +// LLVM: %[[EXN_ADDR_PHI:.*]] = phi ptr [ %[[EXN_ADDR]], %[[LPAD]] ] +// LLVM: %[[EXN_SELECTOR_PHI:.*]] = phi i32 [ %[[EXN_SELECTOR]], %[[LPAD]] ] +// LLVM: call void @_ZN5StrukD1Ev(ptr {{.*}} %[[S1_ADDR]]) +// LLVM: %[[EXN_INS:.*]] = insertvalue { ptr, i32 } poison, ptr %[[EXN_ADDR_PHI]], 0 +// LLVM: %[[EXN_INS2:.*]] = insertvalue { ptr, i32 } %[[EXN_INS]], i32 %[[EXN_SELECTOR_PHI]], 1 +// LLVM: resume { ptr, i32 } %[[EXN_INS2]] +// LLVM: [[DONE]]: +// LLVM: ret void + +// OGCG: define {{.*}} void @_Z24test_init_list_with_dtorv +// OGCG: %[[O:.*]] = alloca %struct.Outer +// OGCG: %[[EXN_SLOT:.*]] = alloca ptr +// OGCG: %[[EHSELECTOR_SLOT:.*]] = alloca i32 +// OGCG: %[[S1_ADDR:.*]] = getelementptr inbounds nuw %struct.Outer, ptr %[[O]], i32 0, i32 0 +// OGCG: call void @_ZN5StrukC1Ei(ptr {{.*}} %[[S1_ADDR]], i32 {{.*}} 1) +// OGCG: %[[S2_ADDR:.*]] = getelementptr inbounds nuw %struct.Outer, ptr %[[O]], i32 0, i32 1 +// OGCG: invoke void @_ZN5StrukC1Ei(ptr {{.*}} %[[S2_ADDR]], i32 {{.*}} 2) +// OGCG: to label %[[CONT:.*]] unwind label %[[LPAD:.*]] +// OGCG: [[CONT]]: +// OGCG: %[[X_ADDR:.*]] = getelementptr inbounds nuw %struct.Outer, ptr %[[O]], i32 0, i32 2 +// OGCG: store i32 3, ptr %[[X_ADDR]] +// OGCG: call void @_ZN5OuterD1Ev(ptr{{.*}} %[[O]]) +// OGCG: ret void +// OGCG: [[LPAD]]: +// OGCG: %[[EXN:.*]] = landingpad { ptr, i32 } +// OGCG: cleanup +// OGCG: %[[EXN_ADDR:.*]] = extractvalue { ptr, i32 } %[[EXN]], 0 +// OGCG: store ptr %[[EXN_ADDR]], ptr %[[EXN_SLOT]] +// OGCG: %[[EXN_SELECTOR:.*]] = extractvalue { ptr, i32 } %[[EXN]], 1 +// OGCG: store i32 %[[EXN_SELECTOR]], ptr %[[EHSELECTOR_SLOT]] +// OGCG: call void @_ZN5StrukD1Ev(ptr {{.*}} %[[S1_ADDR]]) +// OGCG: br label %[[EH_RESUME:.*]] +// OGCG: [[EH_RESUME]]: +// OGCG: %[[EXN_SLOT_LOAD:.*]] = load ptr, ptr %[[EXN_SLOT]] +// OGCG: %[[EHSELECTOR_SLOT_LOAD:.*]] = load i32, ptr %[[EHSELECTOR_SLOT]] +// OGCG: %[[EXN_INSERT:.*]] = insertvalue { ptr, i32 } poison, ptr %[[EXN_SLOT_LOAD]], 0 +// OGCG: %[[EXN_INSERT_2:.*]] = insertvalue { ptr, i32 } %[[EXN_INSERT]], i32 %[[EHSELECTOR_SLOT_LOAD]], 1 +// OGCG: resume { ptr, i32 } %[[EXN_INSERT_2]] diff --git a/clang/test/CIR/CodeGen/paren-init-list.cpp b/clang/test/CIR/CodeGen/paren-init-list.cpp index aba8b05374b1b..0b658acf18dda 100644 --- a/clang/test/CIR/CodeGen/paren-init-list.cpp +++ b/clang/test/CIR/CodeGen/paren-init-list.cpp @@ -24,3 +24,57 @@ void cxx_paren_list_init_expr() { CompleteS a(1, 'a'); } // OGCG: %[[A_ADDR:.*]] = alloca %struct.CompleteS, align 4 // OGCG: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[A_ADDR]], ptr align 4 @__const._Z24cxx_paren_list_init_exprv.a, i64 8, i1 false) + +struct HasDtor { + int val; + ~HasDtor(); +}; + +struct Outer { + HasDtor h; + int x; +}; + +void test_init_list_with_dtor() { + Outer o = {HasDtor{1}, 2}; +} + +// CIR: cir.func {{.*}} @_Z24test_init_list_with_dtorv +// CIR: %[[O:.*]] = cir.alloca !rec_Outer, !cir.ptr<!rec_Outer>, ["o", init] +// CIR: cir.scope { +// CIR: %[[H:.*]] = cir.get_member %[[O]][0] {name = "h"} : !cir.ptr<!rec_Outer> -> !cir.ptr<!rec_HasDtor> +// CIR: %[[VAL:.*]] = cir.get_member %[[H]][0] {name = "val"} : !cir.ptr<!rec_HasDtor> -> !cir.ptr<!s32i> +// CIR: %[[CONST:.*]] = cir.const #cir.int<1> +// CIR: cir.store{{.*}} %[[CONST]], %[[VAL]] +// CIR: %[[X:.*]] = cir.get_member %[[O]][1] {name = "x"} : !cir.ptr<!rec_Outer> -> !cir.ptr<!s32i> +// CIR: %[[CONST:.*]] = cir.const #cir.int<2> +// CIR: cir.store{{.*}} %[[CONST]], %[[X]] +// CIR: } +// CIR: cir.cleanup.scope { +// CIR: cir.yield +// CIR: } cleanup normal { +// CIR: cir.call @_ZN5OuterD1Ev(%[[O]]) nothrow : (!cir.ptr<!rec_Outer> {llvm.align = 4 : i64, llvm.dereferenceable = 8 : i64, llvm.nonnull, llvm.noundef}) -> () +// CIR: cir.yield +// CIR: } +// CIR: cir.return +// CIR: } + +// LLVM: define {{.*}} void @_Z24test_init_list_with_dtorv +// LLVM: %[[O:.*]] = alloca %struct.Outer +// LLVM: %[[O_ADDR:.*]] = getelementptr %struct.Outer, ptr %[[O]], i32 0, i32 0 +// LLVM: %[[H_ADDR:.*]] = getelementptr %struct.HasDtor, ptr %[[O_ADDR]], i32 0, i32 0 +// LLVM: store i32 1, ptr %[[H_ADDR]] +// LLVM: %[[X_ADDR:.*]] = getelementptr %struct.Outer, ptr %[[O]], i32 0, i32 1 +// LLVM: store i32 2, ptr %[[X_ADDR]] +// LLVM: call void @_ZN5OuterD1Ev(ptr{{.*}} %[[O]]) +// LLVM: ret void + +// OGCG: define {{.*}} void @_Z24test_init_list_with_dtorv +// OGCG: %[[O:.*]] = alloca %struct.Outer +// OGCG: %[[O_ADDR:.*]] = getelementptr inbounds nuw %struct.Outer, ptr %[[O]], i32 0, i32 0 +// OGCG: %[[H_ADDR:.*]] = getelementptr inbounds nuw %struct.HasDtor, ptr %[[O_ADDR]], i32 0, i32 0 +// OGCG: store i32 1, ptr %[[H_ADDR]] +// OGCG: %[[X_ADDR:.*]] = getelementptr inbounds nuw %struct.Outer, ptr %[[O]], i32 0, i32 1 +// OGCG: store i32 2, ptr %[[X_ADDR]] +// OGCG: call void @_ZN5OuterD1Ev(ptr{{.*}} %[[O]]) +// OGCG: ret void `````````` </details> https://github.com/llvm/llvm-project/pull/192172 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
