| author | |
| committer | |
| log | 852679c3695af19f218fdc9eab22c6fdf8d09622 |
| tree | 3a77eec40dec41edb707536e630de6e62e2948d7 |
| parent | a3993465feefae6e64f16ce7e7a70251a739cb22 |
| signature |
2 files changed, 44 insertions(+), 2 deletions(-)
src/analyze.cpp+9-2| ... | ... | @@ -5701,23 +5701,30 @@ static ZigType *get_async_fn_type(CodeGen *g, ZigType *orig_fn_type) { |
| 5701 | 5701 | // (await y) + x |
| 5702 | 5702 | static void mark_suspension_point(Scope *scope) { |
| 5703 | 5703 | ScopeExpr *child_expr_scope = (scope->id == ScopeIdExpr) ? reinterpret_cast<ScopeExpr *>(scope) : nullptr; |
| 5704 | bool looking_for_exprs = true; | |
| 5704 | 5705 | for (;;) { |
| 5705 | 5706 | scope = scope->parent; |
| 5706 | 5707 | switch (scope->id) { |
| 5707 | case ScopeIdDefer: | |
| 5708 | 5708 | case ScopeIdDeferExpr: |
| 5709 | 5709 | case ScopeIdDecls: |
| 5710 | 5710 | case ScopeIdFnDef: |
| 5711 | 5711 | case ScopeIdCompTime: |
| 5712 | case ScopeIdVarDecl: | |
| 5713 | 5712 | case ScopeIdCImport: |
| 5714 | 5713 | case ScopeIdSuspend: |
| 5715 | 5714 | case ScopeIdTypeOf: |
| 5716 | 5715 | return; |
| 5716 | case ScopeIdVarDecl: | |
| 5717 | case ScopeIdDefer: | |
| 5718 | looking_for_exprs = false; | |
| 5719 | continue; | |
| 5717 | 5720 | case ScopeIdLoop: |
| 5718 | 5721 | case ScopeIdRuntime: |
| 5719 | 5722 | continue; |
| 5720 | 5723 | case ScopeIdExpr: { |
| 5724 | if (!looking_for_exprs) { | |
| 5725 | // Now we're only looking for a block, to see if it's in a loop (see the case ScopeIdBlock) | |
| 5726 | continue; | |
| 5727 | } | |
| 5721 | 5728 | ScopeExpr *parent_expr_scope = reinterpret_cast<ScopeExpr *>(scope); |
| 5722 | 5729 | if (child_expr_scope != nullptr) { |
| 5723 | 5730 | for (size_t i = 0; parent_expr_scope->children_ptr[i] != child_expr_scope; i += 1) { |
test/stage1/behavior/async_fn.zig+35| ... | ... | @@ -1233,3 +1233,38 @@ test "spill target expr in a for loop" { |
| 1233 | 1233 | resume S.global_frame; |
| 1234 | 1234 | } |
| 1235 | 1235 | |
| 1236 | test "spill target expr in a for loop, with a var decl in the loop body" { | |
| 1237 | const S = struct { | |
| 1238 | var global_frame: anyframe = undefined; | |
| 1239 | ||
| 1240 | fn doTheTest() void { | |
| 1241 | var foo = Foo{ | |
| 1242 | .slice = [_]i32{1, 2}, | |
| 1243 | }; | |
| 1244 | expect(atest(&foo) == 3); | |
| 1245 | } | |
| 1246 | ||
| 1247 | const Foo = struct { | |
| 1248 | slice: []i32, | |
| 1249 | }; | |
| 1250 | ||
| 1251 | fn atest(foo: *Foo) i32 { | |
| 1252 | var sum: i32 = 0; | |
| 1253 | for (foo.slice) |x| { | |
| 1254 | // Previously this var decl would prevent spills. This test makes sure | |
| 1255 | // the for loop spills still happen even though there is a VarDecl in scope | |
| 1256 | // before the suspend. | |
| 1257 | var anything = true; | |
| 1258 | _ = anything; | |
| 1259 | suspend { | |
| 1260 | global_frame = @frame(); | |
| 1261 | } | |
| 1262 | sum += x; | |
| 1263 | } | |
| 1264 | return sum; | |
| 1265 | } | |
| 1266 | }; | |
| 1267 | _ = async S.doTheTest(); | |
| 1268 | resume S.global_frame; | |
| 1269 | resume S.global_frame; | |
| 1270 | } |