zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit fad95741db7529bbad873fb330c25d64ac765340 (tree)
parent 1fee9eac8bb5d2e3e78c098b9cebe2cda332e7cf
Author: Andrew Kelley <andrew@ziglang.org>
Date:   Wed, 13 Jul 2022 15:59:46 -0700

AstGen: fix loop control flow applying to wrong loop

In the case of 'continue' or 'break' inside the 'else' block of a
'while' or 'for' loop.

Closes #12109

Diffstat:
Mlib/std/net/test.zig | 1-
Mlib/std/os.zig | 6+++---
Msrc/AstGen.zig | 8++++++++
Mtest/behavior/for.zig | 14++++++++++++++
Mtest/behavior/while.zig | 10++++++++++
5 files changed, 35 insertions(+), 4 deletions(-)

diff --git a/lib/std/net/test.zig b/lib/std/net/test.zig @@ -104,7 +104,6 @@ test "parse and render UNIX addresses" { } test "resolve DNS" { - if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; if (builtin.os.tag == .wasi) return error.SkipZigTest; if (builtin.os.tag == .windows) { diff --git a/lib/std/os.zig b/lib/std/os.zig @@ -6476,7 +6476,7 @@ pub fn dn_expand( p = msg.ptr + j; } else if (p[0] != 0) { if (dest != exp_dn.ptr) { - dest.* = '.'; + dest[0] = '.'; dest += 1; } var j = p[0]; @@ -6486,12 +6486,12 @@ pub fn dn_expand( } while (j != 0) { j -= 1; - dest.* = p[0]; + dest[0] = p[0]; dest += 1; p += 1; } } else { - dest.* = 0; + dest[0] = 0; if (len == std.math.maxInt(usize)) len = @ptrToInt(p) + 1 - @ptrToInt(comp_dn.ptr); return len; } diff --git a/src/AstGen.zig b/src/AstGen.zig @@ -5795,6 +5795,10 @@ fn whileExpr( break :s &else_scope.base; } }; + // Remove the continue block and break block so that `continue` and `break` + // control flow apply to outer loops; not this one. + loop_scope.continue_block = 0; + loop_scope.break_block = 0; const e = try expr(&else_scope, sub_scope, loop_scope.break_result_loc, else_node); if (!else_scope.endsWithNoReturn()) { loop_scope.break_count += 1; @@ -5994,6 +5998,10 @@ fn forExpr( result: Zir.Inst.Ref, } = if (else_node != 0) blk: { const sub_scope = &else_scope.base; + // Remove the continue block and break block so that `continue` and `break` + // control flow apply to outer loops; not this one. + loop_scope.continue_block = 0; + loop_scope.break_block = 0; const else_result = try expr(&else_scope, sub_scope, loop_scope.break_result_loc, else_node); if (!else_scope.endsWithNoReturn()) { loop_scope.break_count += 1; diff --git a/test/behavior/for.zig b/test/behavior/for.zig @@ -210,3 +210,17 @@ test "for on slice with allowzero ptr" { try S.doTheTest(&[_]u8{ 1, 2, 3, 4 }); comptime try S.doTheTest(&[_]u8{ 1, 2, 3, 4 }); } + +test "else continue outer for" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + + var i: usize = 6; + var buf: [5]u8 = undefined; + while (true) { + i -= 1; + for (buf[i..5]) |_| { + return; + } else continue; + } +} diff --git a/test/behavior/while.zig b/test/behavior/while.zig @@ -334,3 +334,13 @@ test "continue inline while loop" { } comptime assert(i == 5); } + +test "else continue outer while" { + var i: usize = 0; + while (true) { + i += 1; + while (i > 5) { + return; + } else continue; + } +}