Commit 852679c369
Changed files (2)
src
test
stage1
behavior
src/analyze.cpp
@@ -5701,23 +5701,30 @@ static ZigType *get_async_fn_type(CodeGen *g, ZigType *orig_fn_type) {
// (await y) + x
static void mark_suspension_point(Scope *scope) {
ScopeExpr *child_expr_scope = (scope->id == ScopeIdExpr) ? reinterpret_cast<ScopeExpr *>(scope) : nullptr;
+ bool looking_for_exprs = true;
for (;;) {
scope = scope->parent;
switch (scope->id) {
- case ScopeIdDefer:
case ScopeIdDeferExpr:
case ScopeIdDecls:
case ScopeIdFnDef:
case ScopeIdCompTime:
- case ScopeIdVarDecl:
case ScopeIdCImport:
case ScopeIdSuspend:
case ScopeIdTypeOf:
return;
+ case ScopeIdVarDecl:
+ case ScopeIdDefer:
+ looking_for_exprs = false;
+ continue;
case ScopeIdLoop:
case ScopeIdRuntime:
continue;
case ScopeIdExpr: {
+ if (!looking_for_exprs) {
+ // Now we're only looking for a block, to see if it's in a loop (see the case ScopeIdBlock)
+ continue;
+ }
ScopeExpr *parent_expr_scope = reinterpret_cast<ScopeExpr *>(scope);
if (child_expr_scope != nullptr) {
for (size_t i = 0; parent_expr_scope->children_ptr[i] != child_expr_scope; i += 1) {
test/stage1/behavior/async_fn.zig
@@ -1233,3 +1233,38 @@ test "spill target expr in a for loop" {
resume S.global_frame;
}
+test "spill target expr in a for loop, with a var decl in the loop body" {
+ const S = struct {
+ var global_frame: anyframe = undefined;
+
+ fn doTheTest() void {
+ var foo = Foo{
+ .slice = [_]i32{1, 2},
+ };
+ expect(atest(&foo) == 3);
+ }
+
+ const Foo = struct {
+ slice: []i32,
+ };
+
+ fn atest(foo: *Foo) i32 {
+ var sum: i32 = 0;
+ for (foo.slice) |x| {
+ // Previously this var decl would prevent spills. This test makes sure
+ // the for loop spills still happen even though there is a VarDecl in scope
+ // before the suspend.
+ var anything = true;
+ _ = anything;
+ suspend {
+ global_frame = @frame();
+ }
+ sum += x;
+ }
+ return sum;
+ }
+ };
+ _ = async S.doTheTest();
+ resume S.global_frame;
+ resume S.global_frame;
+}