authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-09-09 16:44:23-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-09-09 16:44:23-04:00
log852679c3695af19f218fdc9eab22c6fdf8d09622
tree3a77eec40dec41edb707536e630de6e62e2948d7
parenta3993465feefae6e64f16ce7e7a70251a739cb22
signaturelock-open Commit is signed but in an unrecognized format.

fix a var decl in scope preventing for loop spills


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) {
57015701// (await y) + x
57025702static void mark_suspension_point(Scope *scope) {
57035703 ScopeExpr *child_expr_scope = (scope->id == ScopeIdExpr) ? reinterpret_cast<ScopeExpr *>(scope) : nullptr;
5704 bool looking_for_exprs = true;
57045705 for (;;) {
57055706 scope = scope->parent;
57065707 switch (scope->id) {
5707 case ScopeIdDefer:
57085708 case ScopeIdDeferExpr:
57095709 case ScopeIdDecls:
57105710 case ScopeIdFnDef:
57115711 case ScopeIdCompTime:
5712 case ScopeIdVarDecl:
57135712 case ScopeIdCImport:
57145713 case ScopeIdSuspend:
57155714 case ScopeIdTypeOf:
57165715 return;
5716 case ScopeIdVarDecl:
5717 case ScopeIdDefer:
5718 looking_for_exprs = false;
5719 continue;
57175720 case ScopeIdLoop:
57185721 case ScopeIdRuntime:
57195722 continue;
57205723 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 }
57215728 ScopeExpr *parent_expr_scope = reinterpret_cast<ScopeExpr *>(scope);
57225729 if (child_expr_scope != nullptr) {
57235730 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" {
12331233 resume S.global_frame;
12341234}
12351235
1236test "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}