// RUN: %clang_cc1 -fnamed-loops -triple x86_64-unknown-linux -std=c++20 -emit-llvm -o - %s | FileCheck %s static int a[10]{}; struct NonTrivialDestructor { ~NonTrivialDestructor(); }; bool g(int); bool h(); // CHECK-LABEL: define {{.*}} void @_Z2f1v() // CHECK: entry: // CHECK: %__range1 = alloca ptr, align 8 // CHECK: %__begin1 = alloca ptr, align 8 // CHECK: %__end1 = alloca ptr, align 8 // CHECK: %i = alloca i32, align 4 // CHECK: br label %x // CHECK: x: // CHECK: store ptr @_ZL1a, ptr %__range1, align 8 // CHECK: store ptr @_ZL1a, ptr %__begin1, align 8 // CHECK: store ptr getelementptr inbounds (i32, ptr @_ZL1a, i64 10), ptr %__end1, align 8 // CHECK: br label %for.cond // CHECK: for.cond: // CHECK: %0 = load ptr, ptr %__begin1, align 8 // CHECK: %1 = load ptr, ptr %__end1, align 8 // CHECK: %cmp = icmp ne ptr %0, %1 // CHECK: br i1 %cmp, label %for.body, label %for.end // CHECK: for.body: // CHECK: %2 = load ptr, ptr %__begin1, align 8 // CHECK: %3 = load i32, ptr %2, align 4 // CHECK: store i32 %3, ptr %i, align 4 // CHECK: %4 = load i32, ptr %i, align 4 // CHECK: %call = call {{.*}} i1 @_Z1gi(i32 {{.*}} %4) // CHECK: br i1 %call, label %if.then, label %if.end // CHECK: if.then: // CHECK: br label %for.end // CHECK: if.end: // CHECK: %5 = load i32, ptr %i, align 4 // CHECK: %call1 = call {{.*}} i1 @_Z1gi(i32 {{.*}} %5) // CHECK: br i1 %call1, label %if.then2, label %if.end3 // CHECK: if.then2: // CHECK: br label %for.inc // CHECK: if.end3: // CHECK: br label %for.inc // CHECK: for.inc: // CHECK: %6 = load ptr, ptr %__begin1, align 8 // CHECK: %incdec.ptr = getelementptr inbounds nuw i32, ptr %6, i32 1 // CHECK: store ptr %incdec.ptr, ptr %__begin1, align 8 // CHECK: br label %for.cond // CHECK: for.end: // CHECK: ret void void f1() { x: for (int i : a) { if (g(i)) break x; if (g(i)) continue x; } } // CHECK-LABEL: define {{.*}} void @_Z2f2v() // CHECK: entry: // CHECK: %n1 = alloca %struct.NonTrivialDestructor, align 1 // CHECK: %__range2 = alloca ptr, align 8 // CHECK: %__begin2 = alloca ptr, align 8 // CHECK: %__end2 = alloca ptr, align 8 // CHECK: %i = alloca i32, align 4 // CHECK: %n2 = alloca %struct.NonTrivialDestructor, align 1 // CHECK: %cleanup.dest.slot = alloca i32, align 4 // CHECK: %n3 = alloca %struct.NonTrivialDestructor, align 1 // CHECK: %n4 = alloca %struct.NonTrivialDestructor, align 1 // CHECK: br label %l1 // CHECK: l1: // CHECK: br label %while.cond // CHECK: while.cond: // CHECK: %call = call {{.*}} i1 @_Z1gi(i32 {{.*}} 0) // CHECK: br i1 %call, label %while.body, label %while.end // CHECK: while.body: // CHECK: br label %l2 // CHECK: l2: // CHECK: store ptr @_ZL1a, ptr %__range2, align 8 // CHECK: store ptr @_ZL1a, ptr %__begin2, align 8 // CHECK: store ptr getelementptr inbounds (i32, ptr @_ZL1a, i64 10), ptr %__end2, align 8 // CHECK: br label %for.cond // CHECK: for.cond: // CHECK: %0 = load ptr, ptr %__begin2, align 8 // CHECK: %1 = load ptr, ptr %__end2, align 8 // CHECK: %cmp = icmp ne ptr %0, %1 // CHECK: br i1 %cmp, label %for.body, label %for.end // CHECK: for.body: // CHECK: %2 = load ptr, ptr %__begin2, align 8 // CHECK: %3 = load i32, ptr %2, align 4 // CHECK: store i32 %3, ptr %i, align 4 // CHECK: %4 = load i32, ptr %i, align 4 // CHECK: %call1 = call {{.*}} i1 @_Z1gi(i32 {{.*}} %4) // CHECK: br i1 %call1, label %if.then, label %if.end // CHECK: if.then: // CHECK: store i32 4, ptr %cleanup.dest.slot, align 4 // CHECK: br label %cleanup // CHECK: if.end: // CHECK: %5 = load i32, ptr %i, align 4 // CHECK: %call2 = call {{.*}} i1 @_Z1gi(i32 {{.*}} %5) // CHECK: br i1 %call2, label %if.then3, label %if.end4 // CHECK: if.then3: // CHECK: store i32 3, ptr %cleanup.dest.slot, align 4 // CHECK: br label %cleanup // CHECK: if.end4: // CHECK: %6 = load i32, ptr %i, align 4 // CHECK: %call5 = call {{.*}} i1 @_Z1gi(i32 {{.*}} %6) // CHECK: br i1 %call5, label %if.then6, label %if.end7 // CHECK: if.then6: // CHECK: store i32 6, ptr %cleanup.dest.slot, align 4 // CHECK: br label %cleanup // CHECK: if.end7: // CHECK: %7 = load i32, ptr %i, align 4 // CHECK: %call8 = call {{.*}} i1 @_Z1gi(i32 {{.*}} %7) // CHECK: br i1 %call8, label %if.then9, label %if.end10 // CHECK: if.then9: // CHECK: store i32 7, ptr %cleanup.dest.slot, align 4 // CHECK: br label %cleanup // CHECK: if.end10: // CHECK: call void @_ZN20NonTrivialDestructorD1Ev(ptr {{.*}} %n3) // CHECK: store i32 0, ptr %cleanup.dest.slot, align 4 // CHECK: br label %cleanup // CHECK: cleanup: // CHECK: call void @_ZN20NonTrivialDestructorD1Ev(ptr {{.*}} %n2) // CHECK: %cleanup.dest = load i32, ptr %cleanup.dest.slot, align 4 // CHECK: switch i32 %cleanup.dest, label %cleanup11 [ // CHECK: i32 0, label %cleanup.cont // CHECK: i32 6, label %for.end // CHECK: i32 7, label %for.inc // CHECK: ] // CHECK: cleanup.cont: // CHECK: br label %for.inc // CHECK: for.inc: // CHECK: %8 = load ptr, ptr %__begin2, align 8 // CHECK: %incdec.ptr = getelementptr inbounds nuw i32, ptr %8, i32 1 // CHECK: store ptr %incdec.ptr, ptr %__begin2, align 8 // CHECK: br label %for.cond // CHECK: for.end: // CHECK: call void @_ZN20NonTrivialDestructorD1Ev(ptr {{.*}} %n4) // CHECK: store i32 0, ptr %cleanup.dest.slot, align 4 // CHECK: br label %cleanup11 // CHECK: cleanup11: // CHECK: call void @_ZN20NonTrivialDestructorD1Ev(ptr {{.*}} %n1) // CHECK: %cleanup.dest12 = load i32, ptr %cleanup.dest.slot, align 4 // CHECK: switch i32 %cleanup.dest12, label %unreachable [ // CHECK: i32 0, label %cleanup.cont13 // CHECK: i32 4, label %while.end // CHECK: i32 3, label %while.cond // CHECK: ] // CHECK: cleanup.cont13: // CHECK: br label %while.cond // CHECK: while.end: // CHECK: ret void // CHECK: unreachable: // CHECK: unreachable void f2() { l1: while (g(0)) { NonTrivialDestructor n1; l2: for (int i : a) { NonTrivialDestructor n2; if (g(i)) break l1; if (g(i)) continue l1; if (g(i)) break l2; if (g(i)) continue l2; NonTrivialDestructor n3; } NonTrivialDestructor n4; } } template void f3() { l1: while (g(1)) { for (;g(2);) { if constexpr (Continue) continue l1; else break l1; } } } // CHECK-LABEL: define {{.*}} void @_Z2f3ILb1EEvv() // CHECK: entry: // CHECK: br label %l1 // CHECK: l1: // CHECK: br label %while.cond // CHECK: while.cond: // CHECK: %call = call {{.*}} i1 @_Z1gi(i32 {{.*}} 1) // CHECK: br i1 %call, label %while.body, label %while.end // CHECK: while.body: // CHECK: br label %for.cond // CHECK: for.cond: // CHECK: %call1 = call {{.*}} i1 @_Z1gi(i32 {{.*}} 2) // CHECK: br i1 %call1, label %for.body, label %for.end // CHECK: for.body: // CHECK: br label %while.cond // CHECK: for.end: // CHECK: br label %while.cond // CHECK: while.end: // CHECK: ret void template void f3(); // CHECK-LABEL: define {{.*}} void @_Z2f3ILb0EEvv() // CHECK: entry: // CHECK: br label %l1 // CHECK: l1: // CHECK: br label %while.cond // CHECK: while.cond: // CHECK: %call = call {{.*}} i1 @_Z1gi(i32 {{.*}} 1) // CHECK: br i1 %call, label %while.body, label %while.end // CHECK: while.body: // CHECK: br label %for.cond // CHECK: for.cond: // CHECK: %call1 = call {{.*}} i1 @_Z1gi(i32 {{.*}} 2) // CHECK: br i1 %call1, label %for.body, label %for.end // CHECK: for.body: // CHECK: br label %while.end // CHECK: for.end: // CHECK: br label %while.cond // CHECK: while.end: // CHECK: ret void template void f3();