blob: 38e0f314ee52f481316e4e598383a708803557c5 [file]
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll
// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM
struct Struk {
~Struk();
bool check();
};
// Test that a for-loop body containing a local variable with a destructor
// followed by 'continue' and 'return' produces a properly terminated
// cir.scope. This exercises the interaction between LexicalScope cleanup,
// CleanupScopeOp popping, and empty-block erasure.
int test_cleanup_return_in_loop(int n) {
for (int i = 0; i < n; i++) {
Struk s;
if (s.check())
continue;
return i;
}
return -1;
}
// CIR: cir.func {{.*}} @_Z27test_cleanup_return_in_loopi
// CIR: cir.scope {
// CIR: cir.for : cond {
// CIR: } body {
// CIR: cir.scope {
// CIR: cir.cleanup.scope {
// CIR: cir.continue
// CIR: cir.return
// CIR: } cleanup normal {
// CIR: cir.call @_ZN5StrukD1Ev
// CIR: cir.yield
// CIR: cir.yield
// CIR: } step {
// CIR: cir.return
// LLVM: define dso_local noundef i32 @_Z27test_cleanup_return_in_loopi(i32 noundef %{{.*}})
// LLVM: [[LOOP_COND:.*]]:
// LLVM: %[[ICMP:.*]] = icmp slt i32
// LLVM-NEXT: br i1 %[[ICMP]]
// LLVM: [[LOOP_BODY:.*]]:
// LLVM: %[[CALL:.*]] = call noundef {{.*}} @_ZN5Struk5checkEv(
// LLVM-NEXT: br i1 %[[CALL]]
// LLVM: [[CLEANUP:.*]]:
// LLVM: call void @_ZN5StrukD1Ev(
// LLVM: switch i32 %{{.*}}, label %{{.*}} [
// LLVM: ]
// LLVM: [[LOOP_STEP:.*]]:
// LLVM: add nsw i32 %{{.*}}, 1
// LLVM: [[POST_LOOP:.*]]:
// LLVM: store i32 -1, ptr %{{.*}}, align 4
// LLVM: ret i32