// RUN: %clang_cc1 -std=c++23 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir // RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s // RUN: %clang_cc1 -std=c++23 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll // RUN: FileCheck --check-prefix=LLVM,LLVMCIR --input-file=%t-cir.ll %s // RUN: %clang_cc1 -std=c++23 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll // RUN: FileCheck --check-prefix=LLVM,OGCG --input-file=%t.ll %s struct SmallVector { ~SmallVector(); }; struct BitVector { SmallVector Bits; }; // The switch body is a single DeclStmt (no compound statement / explicit scope). void simple_stmt_body(int x) { switch (x) BitVector bv; } // CIR-LABEL: cir.func{{.*}} @_Z16simple_stmt_bodyi // CIR: cir.scope { // CIR: cir.alloca !rec_BitVector, !cir.ptr, ["bv"] // CIR: cir.switch(%{{.*}} : !s32i) { // CIR: cir.cleanup.scope { // CIR: cir.yield // CIR: } cleanup normal { // CIR: cir.call @_ZN9BitVectorD1Ev // CIR: cir.yield // CIR: } // CIR: cir.yield // CIR: } // CIR: } // CIR: cir.return // LLVM-LABEL: define{{.*}} void @_Z16simple_stmt_bodyi // LLVM: alloca %struct.BitVector // LLVM: switch i32 %{{.*}}, label %[[EPILOG:.*]] [ // LLVM: ] // The CIR pipeline emits the (dead) destructor cleanup; OGCG drops it entirely. // This is inside an unreachable block in LLVMCIR. // LLVMCIR: call void @_ZN9BitVectorD1Ev // OGCG: [[EPILOG]]: // LLVM: ret void // The switch body is a CompoundStmt, so it introduces an explicit scope and the // declaration is emitted through the unassociated-statement path. void compound_stmt_body(int x) { switch (x) { BitVector bv; } } // CIR-LABEL: cir.func{{.*}} @_Z18compound_stmt_bodyi // CIR: cir.scope { // CIR: cir.alloca !rec_BitVector, !cir.ptr, ["bv"] // CIR: cir.switch(%{{.*}} : !s32i) { // CIR: cir.cleanup.scope { // CIR: cir.yield // CIR: } cleanup normal { // CIR: cir.call @_ZN9BitVectorD1Ev // CIR: cir.yield // CIR: } // CIR: cir.yield // CIR: } // CIR: } // CIR: cir.return // LLVM-LABEL: define{{.*}} void @_Z18compound_stmt_bodyi // LLVM: alloca %struct.BitVector // LLVM: switch i32 %{{.*}}, label %[[EPILOG:.*]] [ // LLVM: ] // The CIR pipeline emits the (dead) destructor cleanup; OGCG drops it entirely. // This is inside an unreachable block in LLVMCIR. // LLVMCIR: call void @_ZN9BitVectorD1Ev // OGCG: [[EPILOG]]: // LLVM: ret void void cleanup_in_case(int x) { switch (x) { default: break; case 0: BitVector bv; break; } } // CIR-LABEL: cir.func{{.*}} @_Z15cleanup_in_casei // CIR: cir.scope { // CIR: cir.alloca !rec_BitVector, !cir.ptr, ["bv"] // CIR: cir.switch(%{{.*}} : !s32i) { // CIR: cir.case(default, []) { // CIR: cir.break // CIR: } // CIR: cir.case(equal, [#cir.int<0> : !s32i]) { // CIR: cir.cleanup.scope { // CIR: cir.break // CIR: ^bb[[DEAD_BLOCK:.*]]: // CIR: cir.yield // CIR: } cleanup normal { // CIR: cir.call @_ZN9BitVectorD1Ev // CIR: cir.yield // CIR: } // CIR: cir.yield // CIR: } // CIR: cir.yield // CIR: } // CIR: } // CIR: cir.return // LLVM-LABEL: define{{.*}} void @_Z15cleanup_in_casei // LLVMCIR: %[[CLEANUP_FLAG:.*]] = alloca i32 // LLVM: alloca %struct.BitVector // LLVM: switch i32 %{{.*}}, label %[[DEFAULT:.*]] [ // LLVM: i32 0, label %[[CASE_ZERO:.*]] // LLVM: ] // LLVM: [[DEFAULT]]: // LLVM: br label %[[EPILOG:.*]] // LLVM: [[CASE_ZERO]]: // LLVMCIR: store i32 1, ptr %[[CLEANUP_FLAG]] // LLVMCIR: br label %[[CASE_ZERO_CLEANUP:.*]] // LLVMCIR: [[DEAD_BLOCK:.*]]: // LLVMCIR: store i32 0, ptr %[[CLEANUP_FLAG]] // LLVMCIR: br label %[[CASE_ZERO_CLEANUP]] // LLVMCIR: [[CASE_ZERO_CLEANUP]]: // LLVM: call void @_ZN9BitVectorD1Ev // LLVMCIR: br label %[[CLEANUP_CONTINUE:.*]] // LLVM: br label %[[EPILOG]] // LLVM: [[EPILOG]]: // LLVM: ret void void cleanup_in_while_in_switch(int x) { switch (x) while (x) { default: break; case 0: BitVector bv; continue; } } // CIR-LABEL: cir.func{{.*}} @_Z26cleanup_in_while_in_switchi // CIR: cir.scope { // CIR: cir.switch(%{{.*}} : !s32i) { // CIR: cir.scope { // CIR: cir.while { // CIR: cir.condition // CIR: } do { // CIR: cir.scope { // CIR: cir.alloca !rec_BitVector, !cir.ptr, ["bv"] // CIR: cir.case(default, []) { // CIR: cir.break // CIR: } // CIR: cir.case(equal, [#cir.int<0> : !s32i]) { // CIR: cir.cleanup.scope { // CIR: cir.yield // CIR: } cleanup normal { // CIR: cir.call @_ZN9BitVectorD1Ev // CIR: cir.yield // CIR: } // CIR: cir.yield // CIR: } // CIR: cir.continue // CIR: } // CIR: cir.yield // CIR: } // CIR: } // CIR: cir.yield // CIR: } // CIR: } // CIR: cir.return // LLVM-LABEL: define{{.*}} void @_Z26cleanup_in_while_in_switchi // LLVM: alloca %struct.BitVector // LLVM: switch i32 %{{.*}}, label %[[DEFAULT:.*]] [ // LLVM: i32 0, label %[[CASE_ZERO:.*]] // LLVM: ] // LLVM: [[DEAD_BLOCK:.*]]: // LLVMCIR: br label %[[SWITCH_BODY:.*]] // OGCG: br label %[[WHILE_COND:.*]] // LLVMCIR: [[SWITCH_BODY]]: // LLVMCIR: br label %[[WHILE_COND:.*]] // LLVM: [[WHILE_COND]]: // LLVM: icmp // LLVM: br i1 %{{.*}}, label %[[WHILE_BODY:.*]], label %[[WHILE_END:.*]] // LLVM: [[WHILE_BODY]]: // LLVM: br label %[[DEFAULT]] // LLVM: [[DEFAULT]]: // LLVM: br label %[[WHILE_END]] // LLVM: [[CASE_ZERO]]: // LLVM: call void @_ZN9BitVectorD1Ev // LLVM: br label %[[WHILE_COND]] // LLVM: [[WHILE_END]]: // LLVM: br label %[[EPILOG:.*]] // LLVM: [[EPILOG]]: // LLVM: ret void