From cf8c20978186287d33420274b3c061c16f3fdd1e Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 10 Nov 2025 11:17:10 -0500 Subject: [PATCH] SILGen: Fix break/continue inside 'for ... in ... repeat' loop We were creating the JumpDests too early, so lowering a 'break' or 'continue' statement would perform cleanups that were recorded while evaluating the pack expansion expression, which would cause SIL verifier errors and runtime crashes. - Fixes https://github.com/swiftlang/swift/issues/78598 - Fixes rdar://131847933 (cherry picked from commit 522a6b7c8034da35e48d4fc24f3eda9d09692e85) --- lib/SILGen/ResultPlan.cpp | 3 + lib/SILGen/SILGenApply.cpp | 1 + lib/SILGen/SILGenConstructor.cpp | 1 + lib/SILGen/SILGenDecl.cpp | 1 + lib/SILGen/SILGenDestructor.cpp | 3 +- lib/SILGen/SILGenExpr.cpp | 2 + lib/SILGen/SILGenFunction.h | 9 +-- lib/SILGen/SILGenPack.cpp | 21 ++++-- lib/SILGen/SILGenPoly.cpp | 3 + lib/SILGen/SILGenProlog.cpp | 8 ++- lib/SILGen/SILGenStmt.cpp | 20 +++--- test/Interpreter/issue-78598.swift | 43 ++++++++++++ test/Interpreter/pack_iteration.swift | 47 +++++++++++++ test/SILGen/pack_iteration.swift | 98 +++++++++++++++++++++++++-- 14 files changed, 231 insertions(+), 29 deletions(-) create mode 100644 test/Interpreter/issue-78598.swift create mode 100644 test/Interpreter/pack_iteration.swift diff --git a/lib/SILGen/ResultPlan.cpp b/lib/SILGen/ResultPlan.cpp index c89ec23faca76..4b0ccc26b1873 100644 --- a/lib/SILGen/ResultPlan.cpp +++ b/lib/SILGen/ResultPlan.cpp @@ -524,6 +524,7 @@ class PackTransformResultPlan final : public ResultPlan { // Loop over the pack, initializing each value with the appropriate // element. SGF.emitDynamicPackLoop(loc, FormalPackType, ComponentIndex, openedEnv, + []() -> SILBasicBlock * { return nullptr; }, [&](SILValue indexWithinComponent, SILValue expansionIndex, SILValue packIndex) { @@ -1313,6 +1314,7 @@ ResultPlanBuilder::buildPackExpansionIntoPack(SILValue packAddr, // we can emit a dynamic loop to do that now. if (init->canPerformInPlacePackInitialization(openedEnv, eltTy)) { SGF.emitDynamicPackLoop(loc, formalPackType, componentIndex, openedEnv, + []() -> SILBasicBlock * { return nullptr; }, [&](SILValue indexWithinComponent, SILValue expansionPackIndex, SILValue packIndex) { @@ -1334,6 +1336,7 @@ ResultPlanBuilder::buildPackExpansionIntoPack(SILValue packAddr, SILType::getPrimitiveObjectType(tupleTy)); SGF.emitDynamicPackLoop(loc, formalPackType, componentIndex, openedEnv, + []() -> SILBasicBlock * { return nullptr; }, [&](SILValue indexWithinComponent, SILValue expansionPackIndex, SILValue packIndex) { diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp index de56c7d9771a8..d9b05a36875ef 100644 --- a/lib/SILGen/SILGenApply.cpp +++ b/lib/SILGen/SILGenApply.cpp @@ -4430,6 +4430,7 @@ class ArgEmitter { auto openedElementEnv = expansionExpr->getGenericEnvironment(); SGF.emitDynamicPackLoop(expansionExpr, formalPackType, packComponentIndex, openedElementEnv, + []() -> SILBasicBlock * { return nullptr; }, [&](SILValue indexWithinComponent, SILValue packExpansionIndex, SILValue packIndex) { diff --git a/lib/SILGen/SILGenConstructor.cpp b/lib/SILGen/SILGenConstructor.cpp index 9461515b94106..12a6751908c78 100644 --- a/lib/SILGen/SILGenConstructor.cpp +++ b/lib/SILGen/SILGenConstructor.cpp @@ -212,6 +212,7 @@ static RValue emitImplicitValueConstructorArg(SILGenFunction &SGF, auto formalPackType = CanPackType::get(SGF.getASTContext(), {type}); SGF.emitDynamicPackLoop(loc, formalPackType, /*component*/0, openedEnv, + []() -> SILBasicBlock * { return nullptr; }, [&](SILValue indexWithinComponent, SILValue packExpansionIndex, SILValue packIndex) { diff --git a/lib/SILGen/SILGenDecl.cpp b/lib/SILGen/SILGenDecl.cpp index 0cd8ef002ca68..1a91e00a1e351 100644 --- a/lib/SILGen/SILGenDecl.cpp +++ b/lib/SILGen/SILGenDecl.cpp @@ -75,6 +75,7 @@ static void copyOrInitPackExpansionInto(SILGenFunction &SGF, SGF.Cleanups.forwardCleanup(componentCleanup); SGF.emitDynamicPackLoop(loc, formalPackType, componentIndex, openedEnv, + []() -> SILBasicBlock * { return nullptr; }, [&](SILValue indexWithinComponent, SILValue packExpansionIndex, SILValue packIndex) { diff --git a/lib/SILGen/SILGenDestructor.cpp b/lib/SILGen/SILGenDestructor.cpp index 0ae90b2db278c..ee96edb950f13 100644 --- a/lib/SILGen/SILGenDestructor.cpp +++ b/lib/SILGen/SILGenDestructor.cpp @@ -433,7 +433,8 @@ void SILGenFunction::emitIsolatingDestructor(DestructorDecl *dd) { B.createIntegerLiteral(loc, wordTy, 0); // Schedule isolated execution - B.createApply(loc, swiftDeinitOnExecutorFunc, {}, + B.createApply(loc, swiftDeinitOnExecutorFunc, + getForwardingSubstitutionMap(), {castedSelf, castedDeallocator, executor, flagsInst}); }); } diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index a64f32f4770c5..3021db178b693 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -1660,6 +1660,7 @@ RValueEmitter::visitPackExpansionExpr(PackExpansionExpr *E, SGF.emitDynamicPackLoop(E, formalPackType, /*component index*/ 0, E->getGenericEnvironment(), + []() -> SILBasicBlock * { return nullptr; }, [&](SILValue indexWithinComponent, SILValue packExpansionIndex, SILValue packIndex) { @@ -7417,6 +7418,7 @@ static void emitIgnoredPackExpansion(SILGenFunction &SGF, auto openedElementEnv = E->getGenericEnvironment(); SGF.emitDynamicPackLoop(E, formalPackType, /*component index*/ 0, openedElementEnv, + []() -> SILBasicBlock * { return nullptr; }, [&](SILValue indexWithinComponent, SILValue packExpansionIndex, SILValue packIndex) { diff --git a/lib/SILGen/SILGenFunction.h b/lib/SILGen/SILGenFunction.h index 464a56c29a781..d873b1122e876 100644 --- a/lib/SILGen/SILGenFunction.h +++ b/lib/SILGen/SILGenFunction.h @@ -3155,6 +3155,7 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction /// within the loop; can be null to bind no elements /// \param reverse - if true, iterate the elements in reverse order, /// starting at index limitWithinComponent - 1 + /// \param emitLoopLatch - emit the entry block. /// \param emitBody - a function that will be called to emit the body of /// the loop. It's okay if this has paths that exit the body of the loop, /// but it should leave the insertion point set at the end. @@ -3172,20 +3173,20 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction SILLocation loc, CanPackType formalPackType, unsigned componentIndex, SILValue startingAfterIndexWithinComponent, SILValue limitWithinComponent, GenericEnvironment *openedElementEnv, bool reverse, + llvm::function_ref emitLoopLatch, llvm::function_ref - emitBody, - SILBasicBlock *loopLatch = nullptr); + emitBody); /// A convenience version of dynamic pack loop that visits an entire /// pack expansion component in forward order. void emitDynamicPackLoop( SILLocation loc, CanPackType formalPackType, unsigned componentIndex, GenericEnvironment *openedElementEnv, + llvm::function_ref emitLoopLatch, llvm::function_ref - emitBody, - SILBasicBlock *loopLatch = nullptr); + emitBody); /// Emit a transform on each element of a pack-expansion component /// of a pack, write the result into a pack-expansion component of diff --git a/lib/SILGen/SILGenPack.cpp b/lib/SILGen/SILGenPack.cpp index 2def23e9abf3b..ae10ea7be6a5b 100644 --- a/lib/SILGen/SILGenPack.cpp +++ b/lib/SILGen/SILGenPack.cpp @@ -527,6 +527,7 @@ void SILGenFunction::emitPartialDestroyPack(SILLocation loc, SILValue packAddr, emitDynamicPackLoop(loc, formalPackType, componentIndex, /*startAfter*/ SILValue(), limitWithinComponent, elementEnv, /*reverse*/ true, + []() -> SILBasicBlock * { return nullptr; }, [&](SILValue indexWithinComponent, SILValue packExpansionIndex, SILValue packIndex) { @@ -548,6 +549,7 @@ void SILGenFunction::emitPartialDestroyRemainingPack(SILLocation loc, emitDynamicPackLoop(loc, formalPackType, componentIndex, /*startAfter*/ currentIndexWithinComponent, /*limit*/ SILValue(), elementEnv, /*reverse*/ false, + []() -> SILBasicBlock * { return nullptr; }, [&](SILValue indexWithinComponent, SILValue packExpansionIndex, SILValue packIndex) { @@ -570,6 +572,7 @@ void SILGenFunction::emitPartialDestroyTuple(SILLocation loc, emitDynamicPackLoop(loc, inducedPackType, componentIndex, /*startAfter*/ SILValue(), limitWithinComponent, elementEnv, /*reverse*/ true, + []() -> SILBasicBlock * { return nullptr; }, [&](SILValue indexWithinComponent, SILValue packExpansionIndex, SILValue packIndex) { @@ -592,6 +595,7 @@ void SILGenFunction::emitPartialDestroyRemainingTuple(SILLocation loc, emitDynamicPackLoop(loc, inducedPackType, componentIndex, /*startAfter*/ currentIndexWithinComponent, /*limit*/ SILValue(), elementEnv, /*reverse*/ false, + []() -> SILBasicBlock * { return nullptr; }, [&](SILValue indexWithinComponent, SILValue packExpansionIndex, SILValue packIndex) { @@ -650,6 +654,7 @@ void SILGenFunction::copyPackElementsToTuple(SILLocation loc, emitDynamicPackLoop( loc, formalPackType, /*componentIndex=*/0, elementEnv, + []() -> SILBasicBlock * { return nullptr; }, [&](SILValue indexWithinComponent, SILValue packExpansionIndex, SILValue packIndex) { @@ -673,6 +678,7 @@ void SILGenFunction::projectTupleElementsToPack(SILLocation loc, emitDynamicPackLoop( loc, formalPackType, /*componentIndex=*/0, elementEnv, + []() -> SILBasicBlock * { return nullptr; }, [&](SILValue indexWithinComponent, SILValue packExpansionIndex, SILValue packIndex) { @@ -685,24 +691,24 @@ void SILGenFunction::projectTupleElementsToPack(SILLocation loc, void SILGenFunction::emitDynamicPackLoop( SILLocation loc, CanPackType formalPackType, unsigned componentIndex, GenericEnvironment *openedElementEnv, + llvm::function_ref emitLoopLatch, llvm::function_ref - emitBody, - SILBasicBlock *loopLatch) { + emitBody) { return emitDynamicPackLoop(loc, formalPackType, componentIndex, /*startAfter*/ SILValue(), /*limit*/ SILValue(), - openedElementEnv, /*reverse*/ false, emitBody, - loopLatch); + openedElementEnv, /*reverse*/ false, + emitLoopLatch, emitBody); } void SILGenFunction::emitDynamicPackLoop( SILLocation loc, CanPackType formalPackType, unsigned componentIndex, SILValue startingAfterIndexInComponent, SILValue limitWithinComponent, GenericEnvironment *openedElementEnv, bool reverse, + llvm::function_ref emitLoopLatch, llvm::function_ref - emitBody, - SILBasicBlock *loopLatch) { + emitBody) { assert(isa(formalPackType.getElementType(componentIndex))); assert((!startingAfterIndexInComponent || !reverse) && "cannot reverse with a starting index"); @@ -719,6 +725,8 @@ void SILGenFunction::emitDynamicPackLoop( if (auto *expansion = loc.getAsASTNode()) prepareToEmitPackExpansionExpr(expansion); + auto *loopLatch = emitLoopLatch(); + auto wordTy = SILType::getBuiltinWordType(ctx); auto boolTy = SILType::getBuiltinIntegerType(1, ctx); @@ -1073,6 +1081,7 @@ SILGenFunction::emitPackTransform(SILLocation loc, } emitDynamicPackLoop(loc, inputFormalPackType, inputComponentIndex, openedEnv, + []() -> SILBasicBlock * { return nullptr; }, [&](SILValue indexWithinComponent, SILValue packExpansionIndex, SILValue inputPackIndex) { diff --git a/lib/SILGen/SILGenPoly.cpp b/lib/SILGen/SILGenPoly.cpp index 3145d7841ac59..7a8759d0adc9a 100644 --- a/lib/SILGen/SILGenPoly.cpp +++ b/lib/SILGen/SILGenPoly.cpp @@ -4020,6 +4020,7 @@ ManagedValue ResultPlanner::expandPackExpansion( // expansion in the inner pack. SGF.emitDynamicPackLoop(Loc, innerFormalPackType, innerComponentIndex, openedEnv, + []() -> SILBasicBlock * { return nullptr; }, [&](SILValue indexWithinComponent, SILValue packExpansionIndex, SILValue innerPackIndex) { @@ -4165,6 +4166,7 @@ ManagedValue TranslateArguments::expandPackExpansion( // index. SGF.emitDynamicPackLoop(Loc, innerFormalPackType, innerComponentIndex, openedEnv, + []() -> SILBasicBlock * { return nullptr; }, [&](SILValue indexWithinComponent, SILValue packExpansionIndex, SILValue innerPackIndex) { @@ -4301,6 +4303,7 @@ void ResultPlanner::Operation::emitReabstractTupleIntoPackExpansion( SGF.emitDynamicPackLoop(loc, innerFormalPackType, innerComponentIndex, openedEnv, + []() -> SILBasicBlock * { return nullptr; }, [&](SILValue indexWithinComponent, SILValue packExpansionIndex, SILValue innerPackIndex) { diff --git a/lib/SILGen/SILGenProlog.cpp b/lib/SILGen/SILGenProlog.cpp index 759720cfd9aad..e2be99833c73f 100644 --- a/lib/SILGen/SILGenProlog.cpp +++ b/lib/SILGen/SILGenProlog.cpp @@ -597,9 +597,11 @@ class EmitBBArguments : public CanTypeVisitor SILBasicBlock * { return nullptr; }, + [&](SILValue indexWithinComponent, + SILValue expansionPackIndex, + SILValue packIndex) { componentInit->performPackExpansionInitialization(SGF, loc, indexWithinComponent, [&](Initialization *eltInit) { diff --git a/lib/SILGen/SILGenStmt.cpp b/lib/SILGen/SILGenStmt.cpp index 88db501de104a..34b3944a4ee1b 100644 --- a/lib/SILGen/SILGenStmt.cpp +++ b/lib/SILGen/SILGenStmt.cpp @@ -1245,30 +1245,32 @@ void StmtEmitter::visitForEachStmt(ForEachStmt *S) { PackType::get(SGF.getASTContext(), expansion->getType()) ->getCanonicalType()); - JumpDest continueDest = createJumpDest(S->getBody()); - JumpDest breakDest = createJumpDest(S->getBody()); + std::optional continueDest; + std::optional breakDest; SGF.emitDynamicPackLoop( SILLocation(expansion), formalPackType, 0, expansion->getGenericEnvironment(), + [&]() -> SILBasicBlock * { + breakDest = createJumpDest(S->getBody()); + continueDest = createJumpDest(S->getBody()); + return continueDest->getBlock(); + }, [&](SILValue indexWithinComponent, SILValue packExpansionIndex, SILValue packIndex) { Scope innerForScope(SGF.Cleanups, CleanupLocation(S->getBody())); auto letValueInit = - SGF.emitPatternBindingInitialization(S->getPattern(), continueDest); + SGF.emitPatternBindingInitialization(S->getPattern(), *continueDest); SGF.emitExprInto(expansion->getPatternExpr(), letValueInit.get()); // Set the destinations for 'break' and 'continue'. - SGF.BreakContinueDestStack.push_back({S, breakDest, continueDest}); + SGF.BreakContinueDestStack.push_back({S, *breakDest, *continueDest}); visit(S->getBody()); SGF.BreakContinueDestStack.pop_back(); + }); - return; - }, - continueDest.getBlock()); - - emitOrDeleteBlock(SGF, breakDest, S); + emitOrDeleteBlock(SGF, *breakDest, S); return; } diff --git a/test/Interpreter/issue-78598.swift b/test/Interpreter/issue-78598.swift new file mode 100644 index 0000000000000..00c4f0e74a318 --- /dev/null +++ b/test/Interpreter/issue-78598.swift @@ -0,0 +1,43 @@ +// RUN: %target-run-simple-swift(-target %target-swift-5.9-abi-triple) | %FileCheck %s + +// https://github.com/swiftlang/swift/issues/78598 + +var counter = 0 + +final class Entry { + var isEmpty: Bool { true } + init() { + counter += 1 + } + deinit { + counter -= 1 + } +} + +struct Foo { + private let entry: (repeat Entry) + + init(_ entry: (repeat Entry)) { + self.entry = entry + for entry in repeat each entry { + if entry.isEmpty { + break + } + } + } + + var hmmm: Void { + for entry in repeat each entry { + if !entry.isEmpty { + break + } + } + } +} + +_ = Foo(( + Entry() +)).hmmm + +// CHECK: Counter: 0 +print("Counter: \(counter)") diff --git a/test/Interpreter/pack_iteration.swift b/test/Interpreter/pack_iteration.swift new file mode 100644 index 0000000000000..c608691329d7e --- /dev/null +++ b/test/Interpreter/pack_iteration.swift @@ -0,0 +1,47 @@ +// RUN: %target-run-simple-swift + +// REQUIRES: executable_test + +import StdlibUnittest + +var packIter = TestSuite("PackIteration") + +packIter.test("break") { + func breakTest(_ ts: (repeat (each T)?)) -> [AnyHashable] { + var result: [AnyHashable] = [] + + for t in repeat each ts { + if let t { + result.append(t) + } else { + break + } + } + + return result + } + + let results = breakTest((0, "hello", nil as Bool?, 3.14)) + expectEqual(results, [0, "hello"] as [AnyHashable]) +} + +packIter.test("break") { + func continueTest(_ ts: (repeat (each T)?)) -> [AnyHashable] { + var result: [AnyHashable] = [] + + for t in repeat each ts { + if let t { + result.append(t) + } else { + continue + } + } + + return result + } + + let results = continueTest((0, "hello", nil as Bool?, 3.14)) + expectEqual(results, [0, "hello", 3.14] as [AnyHashable]) +} + +runAllTests() \ No newline at end of file diff --git a/test/SILGen/pack_iteration.swift b/test/SILGen/pack_iteration.swift index 57d1e83e3cbbf..0db70bebd68fd 100644 --- a/test/SILGen/pack_iteration.swift +++ b/test/SILGen/pack_iteration.swift @@ -1,5 +1,4 @@ - -// RUN: %target-swift-emit-silgen -Xllvm -sil-print-types -module-name pack_iteration %s | %FileCheck %s +// RUN: %target-swift-emit-silgen -Xllvm -sil-print-types -module-name pack_iteration %s -target %target-swift-5.9-abi-triple | %FileCheck %s ////////////////// // Declarations // @@ -239,13 +238,14 @@ func iterateTrivialBreak(over element: repeat each Element) { // CHECK: [[NONE_BB]]: // CHECK: br [[FUNC_END_BB:bb[0-9]+]] // -// CHECK: [[FUNC_END_BB]] -// CHECK: [[FUNC_END_FUNC:%.*]] = function_ref @funcEnd : $@convention(thin) () -> () -// CHECK: apply [[FUNC_END_FUNC]]() : $@convention(thin) () -> () -// // CHECK: [[LATCH]]: // CHECK: [[ADD_WORD:%.*]] = builtin "add_Word"([[IDX3]] : $Builtin.Word, [[IDX2]] : $Builtin.Word) : $Builtin.Word // CHECK: br [[LOOP_DEST]]([[ADD_WORD]] : $Builtin.Word) +// +// CHECK: [[FUNC_END_BB]] +// CHECK: [[FUNC_END_FUNC:%.*]] = function_ref @funcEnd : $@convention(thin) () -> () +// CHECK: apply [[FUNC_END_FUNC]]() : $@convention(thin) () -> () +// CHECK: return // CHECK: } // end sil function '$s14pack_iteration20iterateContinueBreak4overyxxQp_tRvzlF' func iterateContinueBreak(over element: repeat each Element) { for el in repeat each element { @@ -323,3 +323,89 @@ func iterateClosure(over element: repeat each Element) { } } } + +struct G { + var t: (repeat each T) +} + +// Make sure the 'break' jump destination uses the correct +// cleanup height. + +// CHECK-LABEL: sil hidden [ossa] @$s14pack_iteration0B12BreakCleanupyyAA1GVyxxQp_QPGRvzlF : $@convention(thin) (@in_guaranteed G) -> () { +// CHECK: bb0(%0 : $*G): +// CHECK: [[STACK:%.*]] = alloc_stack $(repeat each T) +// CHECK-NEXT: [[PROJ:%.*]] = struct_element_addr %0 : $*G, #G.t +// CHECK-NEXT: copy_addr [[PROJ]] to [init] [[STACK]] : $*(repeat each T) +// CHECK-NEXT: [[ZERO:%.*]] = integer_literal $Builtin.Word, 0 +// CHECK-NEXT: [[ONE:%.*]] = integer_literal $Builtin.Word, 1 +// CHECK-NEXT: [[LEN:%.*]] = pack_length $Pack{repeat each T} +// CHECK-NEXT: br bb1([[ZERO]] : $Builtin.Word) +// +// CHECK: bb1([[IDX:%.*]] : $Builtin.Word): +// CHECK-NEXT: [[CMP:%.*]] = builtin "cmp_eq_Word"([[IDX:%.*]] : $Builtin.Word, [[LEN]] : $Builtin.Word) : $Builtin.Int1 +// CHECK-NEXT: cond_br [[CMP]], bb3, bb2 +// +// CHECK: bb2: +// CHECK-NEXT: [[PACK_IDX:%.*]] = dynamic_pack_index [[IDX]] of $Pack{repeat each T} +// CHECK-NEXT: [[ELT:%.*]] = open_pack_element [[PACK_IDX]] of at , shape $each T +// CHECK-NEXT: [[ELT_STACK:%.*]] = alloc_stack [lexical] [var_decl] $@pack_element({{.*}}) each T +// CHECK-NEXT: [[ELT_TUPLE:%.*]] = tuple_pack_element_addr [[PACK_IDX]] of [[STACK]] : $*(repeat each T) as $*@pack_element({{.*}}) each T +// CHECK-NEXT: copy_addr [[ELT_TUPLE]] to [init] [[ELT_STACK]] : $*@pack_element({{.*}}) each T +// CHECK-NEXT: destroy_addr [[ELT_STACK]] : $*@pack_element({{.*}}) each T +// CHECK-NEXT: dealloc_stack [[ELT_STACK]] : $*@pack_element({{.*}}) each T + +// CHECK: br bb5 +// +// CHECK: bb3: +// CHECK-NEXT: bb5 +// +// CHECK: bb4: +// CHECK-NEXT: [[NEXT:%.*]] = builtin "add_Word"([[IDX]] : $Builtin.Word, [[ONE]] : $Builtin.Word) : $Builtin.Word +// CHECK: br bb1([[NEXT]] : $Builtin.Word) +// +// CHECK: bb5: +// CHECK: destroy_addr [[STACK]] : $*(repeat each T) +// CHECK: dealloc_stack [[STACK]] : $*(repeat each T) +// CHECK: [[RESULT:%.*]] = tuple () +// CHECK: return [[RESULT]] : $() +func iterationBreakCleanup(_ xs: G) { + for x in repeat each xs.t { + break + } +} + +// CHECK-LABEL: sil hidden [ossa] @$s14pack_iteration0B15ContinueCleanupyyAA1GVyxxQp_QPGRvzlF : $@convention(thin) (@in_guaranteed G) -> () { +// CHECK: bb0(%0 : $*G): +// CHECK: [[STACK:%.*]] = alloc_stack $(repeat each T) +// CHECK-NEXT: [[PROJ:%.*]] = struct_element_addr %0 : $*G, #G.t +// CHECK-NEXT: copy_addr [[PROJ]] to [init] [[STACK]] : $*(repeat each T) +// CHECK-NEXT: [[ZERO:%.*]] = integer_literal $Builtin.Word, 0 +// CHECK-NEXT: [[ONE:%.*]] = integer_literal $Builtin.Word, 1 +// CHECK-NEXT: [[LEN:%.*]] = pack_length $Pack{repeat each T} +// CHECK-NEXT: br bb1([[ZERO]] : $Builtin.Word) +// +// CHECK: bb1([[IDX:%.*]] : $Builtin.Word): +// CHECK-NEXT: [[CMP:%.*]] = builtin "cmp_eq_Word"([[IDX:%.*]] : $Builtin.Word, [[LEN]] : $Builtin.Word) : $Builtin.Int1 +// CHECK-NEXT: cond_br [[CMP]], bb2, bb3 +// +// CHECK: bb2: +// CHECK: destroy_addr [[STACK]] : $*(repeat each T) +// CHECK: dealloc_stack [[STACK]] : $*(repeat each T) +// CHECK: [[RESULT:%.*]] = tuple () +// CHECK: return [[RESULT]] : $() +// +// CHECK: bb3: +// CHECK-NEXT: [[PACK_IDX:%.*]] = dynamic_pack_index [[IDX]] of $Pack{repeat each T} +// CHECK-NEXT: [[ELT:%.*]] = open_pack_element [[PACK_IDX]] of at , shape $each T +// CHECK-NEXT: [[ELT_STACK:%.*]] = alloc_stack [lexical] [var_decl] $@pack_element({{.*}}) each T +// CHECK-NEXT: [[ELT_TUPLE:%.*]] = tuple_pack_element_addr [[PACK_IDX]] of [[STACK]] : $*(repeat each T) as $*@pack_element({{.*}}) each T +// CHECK-NEXT: copy_addr [[ELT_TUPLE]] to [init] [[ELT_STACK]] : $*@pack_element({{.*}}) each T +// CHECK-NEXT: destroy_addr [[ELT_STACK]] : $*@pack_element({{.*}}) each T +// CHECK-NEXT: dealloc_stack [[ELT_STACK]] : $*@pack_element({{.*}}) each T +// CHECK-NEXT: [[NEXT:%.*]] = builtin "add_Word"([[IDX]] : $Builtin.Word, [[ONE]] : $Builtin.Word) : $Builtin.Word +// CHECK: br bb1([[NEXT]] : $Builtin.Word) +func iterationContinueCleanup(_ xs: G) { + for x in repeat each xs.t { + continue + } +} \ No newline at end of file