authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-07-13 15:59:46-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-07-13 16:10:41-07:00
logfad95741db7529bbad873fb330c25d64ac765340
tree22ca663d66d22bccc6ffe9ac0d2c676ed8bb0636
parent1fee9eac8bb5d2e3e78c098b9cebe2cda332e7cf

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

5 files changed, 35 insertions(+), 4 deletions(-)

lib/std/net/test.zig-1
...@@ -104,7 +104,6 @@ test "parse and render UNIX addresses" {...@@ -104,7 +104,6 @@ test "parse and render UNIX addresses" {
104}104}
105105
106test "resolve DNS" {106test "resolve DNS" {
107 if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest;
108 if (builtin.os.tag == .wasi) return error.SkipZigTest;107 if (builtin.os.tag == .wasi) return error.SkipZigTest;
109108
110 if (builtin.os.tag == .windows) {109 if (builtin.os.tag == .windows) {
lib/std/os.zig+3-3
...@@ -6476,7 +6476,7 @@ pub fn dn_expand(...@@ -6476,7 +6476,7 @@ pub fn dn_expand(
6476 p = msg.ptr + j;6476 p = msg.ptr + j;
6477 } else if (p[0] != 0) {6477 } else if (p[0] != 0) {
6478 if (dest != exp_dn.ptr) {6478 if (dest != exp_dn.ptr) {
6479 dest.* = '.';6479 dest[0] = '.';
6480 dest += 1;6480 dest += 1;
6481 }6481 }
6482 var j = p[0];6482 var j = p[0];
...@@ -6486,12 +6486,12 @@ pub fn dn_expand(...@@ -6486,12 +6486,12 @@ pub fn dn_expand(
6486 }6486 }
6487 while (j != 0) {6487 while (j != 0) {
6488 j -= 1;6488 j -= 1;
6489 dest.* = p[0];6489 dest[0] = p[0];
6490 dest += 1;6490 dest += 1;
6491 p += 1;6491 p += 1;
6492 }6492 }
6493 } else {6493 } else {
6494 dest.* = 0;6494 dest[0] = 0;
6495 if (len == std.math.maxInt(usize)) len = @ptrToInt(p) + 1 - @ptrToInt(comp_dn.ptr);6495 if (len == std.math.maxInt(usize)) len = @ptrToInt(p) + 1 - @ptrToInt(comp_dn.ptr);
6496 return len;6496 return len;
6497 }6497 }
src/AstGen.zig+8
...@@ -5795,6 +5795,10 @@ fn whileExpr(...@@ -5795,6 +5795,10 @@ fn whileExpr(
5795 break :s &else_scope.base;5795 break :s &else_scope.base;
5796 }5796 }
5797 };5797 };
5798 // Remove the continue block and break block so that `continue` and `break`
5799 // control flow apply to outer loops; not this one.
5800 loop_scope.continue_block = 0;
5801 loop_scope.break_block = 0;
5798 const e = try expr(&else_scope, sub_scope, loop_scope.break_result_loc, else_node);5802 const e = try expr(&else_scope, sub_scope, loop_scope.break_result_loc, else_node);
5799 if (!else_scope.endsWithNoReturn()) {5803 if (!else_scope.endsWithNoReturn()) {
5800 loop_scope.break_count += 1;5804 loop_scope.break_count += 1;
...@@ -5994,6 +5998,10 @@ fn forExpr(...@@ -5994,6 +5998,10 @@ fn forExpr(
5994 result: Zir.Inst.Ref,5998 result: Zir.Inst.Ref,
5995 } = if (else_node != 0) blk: {5999 } = if (else_node != 0) blk: {
5996 const sub_scope = &else_scope.base;6000 const sub_scope = &else_scope.base;
6001 // Remove the continue block and break block so that `continue` and `break`
6002 // control flow apply to outer loops; not this one.
6003 loop_scope.continue_block = 0;
6004 loop_scope.break_block = 0;
5997 const else_result = try expr(&else_scope, sub_scope, loop_scope.break_result_loc, else_node);6005 const else_result = try expr(&else_scope, sub_scope, loop_scope.break_result_loc, else_node);
5998 if (!else_scope.endsWithNoReturn()) {6006 if (!else_scope.endsWithNoReturn()) {
5999 loop_scope.break_count += 1;6007 loop_scope.break_count += 1;
test/behavior/for.zig+14
...@@ -210,3 +210,17 @@ test "for on slice with allowzero ptr" {...@@ -210,3 +210,17 @@ test "for on slice with allowzero ptr" {
210 try S.doTheTest(&[_]u8{ 1, 2, 3, 4 });210 try S.doTheTest(&[_]u8{ 1, 2, 3, 4 });
211 comptime try S.doTheTest(&[_]u8{ 1, 2, 3, 4 });211 comptime try S.doTheTest(&[_]u8{ 1, 2, 3, 4 });
212}212}
213
214test "else continue outer for" {
215 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
216 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
217
218 var i: usize = 6;
219 var buf: [5]u8 = undefined;
220 while (true) {
221 i -= 1;
222 for (buf[i..5]) |_| {
223 return;
224 } else continue;
225 }
226}
test/behavior/while.zig+10
...@@ -334,3 +334,13 @@ test "continue inline while loop" {...@@ -334,3 +334,13 @@ test "continue inline while loop" {
334 }334 }
335 comptime assert(i == 5);335 comptime assert(i == 5);
336}336}
337
338test "else continue outer while" {
339 var i: usize = 0;
340 while (true) {
341 i += 1;
342 while (i > 5) {
343 return;
344 } else continue;
345 }
346}