| // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir |
| // RUN: FileCheck --input-file=%t.cir %s |
| |
| struct Struk { |
| ~Struk(); |
| }; |
| |
| // CHECK: !rec_Struk = !cir.struct<"Struk" padded {!u8i}> |
| |
| // CHECK: cir.func{{.*}} @_ZN5StrukD1Ev(!cir.ptr<!rec_Struk> {{.*}}) |
| |
| void test_cleanup() { |
| Struk s; |
| } |
| |
| // CHECK: cir.func{{.*}} @_Z12test_cleanupv() |
| // CHECK: %[[S_ADDR:.*]] = cir.alloca "s" {{.*}} : !cir.ptr<!rec_Struk> |
| // CHECK: cir.call @_ZN5StrukD1Ev(%[[S_ADDR]]) nothrow : (!cir.ptr<!rec_Struk> {{.*}}) -> () |
| // CHECK: cir.return |
| |
| void test_cleanup_ifelse(bool b) { |
| if (b) { |
| Struk s; |
| } else { |
| Struk s; |
| } |
| } |
| |
| // CHECK: cir.func{{.*}} @_Z19test_cleanup_ifelseb(%arg0: !cir.bool |
| // CHECK: cir.scope { |
| // CHECK: %[[B:.*]] = cir.load{{.*}} %0 : !cir.ptr<!cir.bool> |
| // CHECK: cir.if %[[B]] { |
| // CHECK: %[[S:.*]] = cir.alloca "s" {{.*}} : !cir.ptr<!rec_Struk> |
| // CHECK: cir.call @_ZN5StrukD1Ev(%[[S]]) nothrow : (!cir.ptr<!rec_Struk> {{.*}}) -> () |
| // CHECK: } else { |
| // CHECK: %[[S_TOO:.*]] = cir.alloca "s" {{.*}} : !cir.ptr<!rec_Struk> |
| // CHECK: cir.call @_ZN5StrukD1Ev(%[[S_TOO]]) nothrow : (!cir.ptr<!rec_Struk> {{.*}}) -> () |
| // CHECK: } |
| // CHECK: } |
| // CHECK: cir.return |
| |
| void test_cleanup_for() { |
| for (int i = 0; i < 10; i++) { |
| Struk s; |
| } |
| } |
| |
| // CHECK: cir.func{{.*}} @_Z16test_cleanup_forv() |
| // CHECK: cir.scope { |
| // CHECK: cir.for : cond { |
| // CHECK: } body { |
| // CHECK: cir.scope { |
| // CHECK: %[[S:.*]] = cir.alloca "s" {{.*}} : !cir.ptr<!rec_Struk> |
| // CHECK: cir.call @_ZN5StrukD1Ev(%[[S]]) nothrow : (!cir.ptr<!rec_Struk> {{.*}}) -> () |
| // CHECK: } |
| // CHECK: cir.yield |
| // CHECK: } step { |
| // CHECK: } |
| // CHECK: } |
| // CHECK: cir.return |
| |
| void test_cleanup_nested() { |
| Struk outer; |
| { |
| Struk middle; |
| { |
| Struk inner; |
| } |
| } |
| } |
| |
| // CHECK: cir.func{{.*}} @_Z19test_cleanup_nestedv() |
| // CHECK: %[[OUTER:.*]] = cir.alloca "outer" {{.*}} : !cir.ptr<!rec_Struk> |
| // CHECK: cir.scope { |
| // CHECK: %[[MIDDLE:.*]] = cir.alloca "middle" {{.*}} : !cir.ptr<!rec_Struk> |
| // CHECK: cir.scope { |
| // CHECK: %[[INNER:.*]] = cir.alloca "inner" {{.*}} : !cir.ptr<!rec_Struk> |
| // CHECK: cir.call @_ZN5StrukD1Ev(%[[INNER]]) nothrow : (!cir.ptr<!rec_Struk> {{.*}}) -> () |
| // CHECK: } |
| // CHECK: cir.call @_ZN5StrukD1Ev(%[[MIDDLE]]) nothrow : (!cir.ptr<!rec_Struk> {{.*}}) -> () |
| // CHECK: } |
| // CHECK: cir.call @_ZN5StrukD1Ev(%[[OUTER]]) nothrow : (!cir.ptr<!rec_Struk> {{.*}}) -> () |
| // CHECK: cir.return |
| |
| void use_ref(const Struk &); |
| |
| void test_expr_with_cleanup() { |
| use_ref(Struk{}); |
| } |
| |
| // CHECK: cir.func{{.*}} @_Z22test_expr_with_cleanupv() |
| // CHECK: %[[S:.*]] = cir.alloca {{.*}} : !cir.ptr<!rec_Struk> |
| // CHECK: cir.call @_Z7use_refRK5Struk(%[[S]]) |
| // CHECK: cir.call @_ZN5StrukD1Ev(%[[S]]) nothrow : (!cir.ptr<!rec_Struk> {{.*}}) -> () |
| // CHECK: cir.return |
| |
| struct ComplexContainer { |
| int _Complex value; |
| ComplexContainer(int _Complex v) : value(v) {} |
| }; |
| |
| void complex_expr_with_cleanup() { |
| int _Complex result = ComplexContainer(10).value; |
| } |
| |
| // CHECK: cir.func{{.*}} @_Z25complex_expr_with_cleanupv() |
| // CHECK: %[[RESULT:.*]] = cir.alloca "result" {{.*}} init : !cir.ptr<!cir.complex<!s32i>> |
| // CHECK: %[[CONTAINER_ADDR:.*]] = cir.alloca "ref.tmp0" {{.*}} : !cir.ptr<!rec_ComplexContainer> |
| // CHECK: %[[ARG_ADDR:.*]] = cir.alloca "coerce" {{.*}} : !cir.ptr<!cir.complex<!s32i>> |
| // CHECK: %[[CONST_10:.*]] = cir.const #cir.int<10> : !s32i |
| // CHECK: %[[CONST_0:.*]] = cir.const #cir.int<0> : !s32i |
| // CHECK: %[[ARG_COMPLEX:.*]] = cir.complex.create %[[CONST_10]], %[[CONST_0]] : !s32i -> !cir.complex<!s32i> |
| // CHECK: cir.store {{.*}} %[[ARG_COMPLEX]], %[[ARG_ADDR]] : !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>> |
| // CHECK: %[[TMP_ARG:.*]] = cir.load {{.*}} %[[ARG_ADDR]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i> |
| // CHECK: cir.call @_ZN16ComplexContainerC1ECi(%[[CONTAINER_ADDR]], %[[TMP_ARG]]) : (!cir.ptr<!rec_ComplexContainer> {{.*}}, !cir.complex<!s32i> {{.*}}) -> () |
| // CHECK: %[[ELEM_0:.*]] = cir.get_member %[[CONTAINER_ADDR]][0] {name = "value"} : !cir.ptr<!rec_ComplexContainer> -> !cir.ptr<!cir.complex<!s32i>> |
| // CHECK: %[[TMP_ELEM_0:.*]] = cir.load {{.*}} %[[ELEM_0]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i> |
| // CHECK: cir.store {{.*}} %[[TMP_ELEM_0]], %[[RESULT]] : !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>> |
| |
| struct ComplexContainerWithDtor { |
| int _Complex value; |
| ComplexContainerWithDtor(int _Complex v) : value(v) {} |
| ~ComplexContainerWithDtor() {} |
| }; |
| |
| void complex_expr_with_cleanup_inside_cleanupscope() { |
| int _Complex result = ComplexContainerWithDtor(10).value; |
| } |
| |
| // CHECK: cir.func{{.*}} @_Z45complex_expr_with_cleanup_inside_cleanupscopev() |
| // CHECK: %[[RESULT:.*]] = cir.alloca "result" {{.*}} init : !cir.ptr<!cir.complex<!s32i>> |
| // CHECK: %[[CONTAINER_ADDR:.*]] = cir.alloca "ref.tmp0" {{.*}} : !cir.ptr<!rec_ComplexContainerWithDtor> |
| // CHECK: %[[ARG_ADDR:.*]] = cir.alloca "coerce" {{.*}} : !cir.ptr<!cir.complex<!s32i>> |
| // CHECK: %[[TEMP_ADDR:.*]] = cir.alloca "tmp.exprcleanup" {{.*}} : !cir.ptr<!cir.complex<!s32i>> |
| // CHECK: %[[CONST_10:.*]] = cir.const #cir.int<10> : !s32i |
| // CHECK: %[[CONST_0:.*]] = cir.const #cir.int<0> : !s32i |
| // CHECK: %[[ARG_COMPLEX:.*]] = cir.complex.create %[[CONST_10]], %[[CONST_0]] : !s32i -> !cir.complex<!s32i> |
| // CHECK: cir.store {{.*}} %[[ARG_COMPLEX]], %[[ARG_ADDR]] : !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>> |
| // CHECK: %[[TMP_ARG:.*]] = cir.load {{.*}} %[[ARG_ADDR]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i> |
| // CHECK: cir.call @_ZN24ComplexContainerWithDtorC1ECi(%[[CONTAINER_ADDR]], %[[TMP_ARG]]) : (!cir.ptr<!rec_ComplexContainerWithDtor> {{.*}}, !cir.complex<!s32i> {{.*}}) -> () |
| // CHECK: cir.cleanup.scope { |
| // CHECK: %[[ELEM_0:.*]] = cir.get_member %[[CONTAINER_ADDR]][0] {name = "value"} : !cir.ptr<!rec_ComplexContainerWithDtor> -> !cir.ptr<!cir.complex<!s32i>> |
| // CHECK: %[[TMP_ELEM_0:.*]] = cir.load {{.*}} %[[ELEM_0]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i> |
| // CHECK: cir.store{{.*}} %[[TMP_ELEM_0]], %[[TEMP_ADDR]] : !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>> |
| // CHECK: cir.yield |
| // CHECK: } cleanup normal { |
| // CHECK: cir.call @_ZN24ComplexContainerWithDtorD1Ev(%[[CONTAINER_ADDR]]) nothrow : (!cir.ptr<!rec_ComplexContainerWithDtor> {{.*}}) -> () |
| // CHECK: cir.yield |
| // CHECK: } |
| // CHECK: %[[RELOAD:.*]] = cir.load {{.*}} %[[TEMP_ADDR]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i> |
| // CHECK: cir.store {{.*}} %[[RELOAD]], %[[RESULT]] : !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>> |
| |
| void test_cleanup_with_automatic_storage_duration() { |
| const Struk &ref = Struk{}; |
| } |
| |
| // CHECK: cir.func{{.*}} @_Z44test_cleanup_with_automatic_storage_durationv() |
| // CHECK: %[[REF_TMP:.*]] = cir.alloca "ref.tmp0" {{.*}} : !cir.ptr<!rec_Struk> |
| // CHECK: %[[REF:.*]] = cir.alloca "ref" {{.*}} init const : !cir.ptr<!cir.ptr<!rec_Struk>> |
| // CHECK: cir.cleanup.scope { |
| // CHECK: cir.store{{.*}} %[[REF_TMP]], %[[REF]] |
| // CHECK: cir.yield |
| // CHECK: } cleanup normal { |
| // CHECK: cir.call @_ZN5StrukD1Ev(%[[REF_TMP]]) nothrow |
| // CHECK: cir.yield |
| // CHECK: } |