Commit fad95741db

Andrew Kelley <andrew@ziglang.org>
2022-07-14 00:59:46
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
1 parent 1fee9ea
Changed files (5)
lib
src
test
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) {
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;
         }
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;
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;
+    }
+}
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;
+    }
+}