// 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 {{.*}}) void test_cleanup() { Struk s; } // CHECK: cir.func{{.*}} @_Z12test_cleanupv() // CHECK: %[[S_ADDR:.*]] = cir.alloca !rec_Struk, !cir.ptr, ["s"] // CHECK: cir.call @_ZN5StrukD1Ev(%[[S_ADDR]]) nothrow : (!cir.ptr {{.*}}) -> () // 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 // CHECK: cir.if %[[B]] { // CHECK: %[[S:.*]] = cir.alloca !rec_Struk, !cir.ptr, ["s"] // CHECK: cir.call @_ZN5StrukD1Ev(%[[S]]) nothrow : (!cir.ptr {{.*}}) -> () // CHECK: } else { // CHECK: %[[S_TOO:.*]] = cir.alloca !rec_Struk, !cir.ptr, ["s"] // CHECK: cir.call @_ZN5StrukD1Ev(%[[S_TOO]]) nothrow : (!cir.ptr {{.*}}) -> () // 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 !rec_Struk, !cir.ptr, ["s"] // CHECK: cir.call @_ZN5StrukD1Ev(%[[S]]) nothrow : (!cir.ptr {{.*}}) -> () // 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 !rec_Struk, !cir.ptr, ["outer"] // CHECK: cir.scope { // CHECK: %[[MIDDLE:.*]] = cir.alloca !rec_Struk, !cir.ptr, ["middle"] // CHECK: cir.scope { // CHECK: %[[INNER:.*]] = cir.alloca !rec_Struk, !cir.ptr, ["inner"] // CHECK: cir.call @_ZN5StrukD1Ev(%[[INNER]]) nothrow : (!cir.ptr {{.*}}) -> () // CHECK: } // CHECK: cir.call @_ZN5StrukD1Ev(%[[MIDDLE]]) nothrow : (!cir.ptr {{.*}}) -> () // CHECK: } // CHECK: cir.call @_ZN5StrukD1Ev(%[[OUTER]]) nothrow : (!cir.ptr {{.*}}) -> () // 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 !rec_Struk, !cir.ptr // CHECK: cir.call @_Z7use_refRK5Struk(%[[S]]) // CHECK: cir.call @_ZN5StrukD1Ev(%[[S]]) nothrow : (!cir.ptr {{.*}}) -> () // 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 !cir.complex, !cir.ptr>, ["result", init] // CHECK: %[[CONTAINER_ADDR:.*]] = cir.alloca !rec_ComplexContainer, !cir.ptr, ["ref.tmp0"] // CHECK: %[[ARG_ADDR:.*]] = cir.alloca !cir.complex, !cir.ptr>, ["coerce"] // 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 // CHECK: cir.store {{.*}} %[[ARG_COMPLEX]], %[[ARG_ADDR]] : !cir.complex, !cir.ptr> // CHECK: %[[TMP_ARG:.*]] = cir.load {{.*}} %[[ARG_ADDR]] : !cir.ptr>, !cir.complex // CHECK: cir.call @_ZN16ComplexContainerC1ECi(%[[CONTAINER_ADDR]], %[[TMP_ARG]]) : (!cir.ptr {{.*}}, !cir.complex {{.*}}) -> () // CHECK: %[[ELEM_0:.*]] = cir.get_member %[[CONTAINER_ADDR]][0] {name = "value"} : !cir.ptr -> !cir.ptr> // CHECK: %[[TMP_ELEM_0:.*]] = cir.load {{.*}} %[[ELEM_0]] : !cir.ptr>, !cir.complex // CHECK: cir.store {{.*}} %[[TMP_ELEM_0]], %[[RESULT]] : !cir.complex, !cir.ptr> 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 !cir.complex, !cir.ptr>, ["result", init] // CHECK: %[[CONTAINER_ADDR:.*]] = cir.alloca !rec_ComplexContainerWithDtor, !cir.ptr, ["ref.tmp0"] // CHECK: %[[ARG_ADDR:.*]] = cir.alloca !cir.complex, !cir.ptr>, ["coerce"] // CHECK: %[[TEMP_ADDR:.*]] = cir.alloca !cir.complex, !cir.ptr>, ["tmp.exprcleanup"] // 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 // CHECK: cir.store {{.*}} %[[ARG_COMPLEX]], %[[ARG_ADDR]] : !cir.complex, !cir.ptr> // CHECK: %[[TMP_ARG:.*]] = cir.load {{.*}} %[[ARG_ADDR]] : !cir.ptr>, !cir.complex // CHECK: cir.call @_ZN24ComplexContainerWithDtorC1ECi(%[[CONTAINER_ADDR]], %[[TMP_ARG]]) : (!cir.ptr {{.*}}, !cir.complex {{.*}}) -> () // CHECK: cir.cleanup.scope { // CHECK: %[[ELEM_0:.*]] = cir.get_member %[[CONTAINER_ADDR]][0] {name = "value"} : !cir.ptr -> !cir.ptr> // CHECK: %[[TMP_ELEM_0:.*]] = cir.load {{.*}} %[[ELEM_0]] : !cir.ptr>, !cir.complex // CHECK: cir.store{{.*}} %[[TMP_ELEM_0]], %[[TEMP_ADDR]] : !cir.complex, !cir.ptr> // CHECK: cir.yield // CHECK: } cleanup normal { // CHECK: cir.call @_ZN24ComplexContainerWithDtorD1Ev(%[[CONTAINER_ADDR]]) nothrow : (!cir.ptr {{.*}}) -> () // CHECK: cir.yield // CHECK: } // CHECK: %[[RELOAD:.*]] = cir.load {{.*}} %[[TEMP_ADDR]] : !cir.ptr>, !cir.complex // CHECK: cir.store {{.*}} %[[RELOAD]], %[[RESULT]] : !cir.complex, !cir.ptr> 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 !rec_Struk, !cir.ptr, ["ref.tmp0"] // CHECK: %[[REF:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["ref", init, const] // 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: }