Commit 9e0a930ce3

Veikka Tuominen <git@vexu.eu>
2022-07-26 15:20:38
stage2: add error for comptime control flow in runtime block
1 parent b586119
src/AstGen.zig
@@ -1940,6 +1940,9 @@ fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index)
                     .break_inline
                 else
                     .@"break";
+                if (break_tag == .break_inline) {
+                    _ = try parent_gz.addNode(.check_comptime_control_flow, node);
+                }
                 _ = try parent_gz.addBreak(break_tag, continue_block, .void_value);
                 return Zir.Inst.Ref.unreachable_value;
             },
@@ -2473,6 +2476,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
             .repeat_inline,
             .panic,
             .panic_comptime,
+            .check_comptime_control_flow,
             => {
                 noreturn_src_node = statement;
                 break :b true;
src/Module.zig
@@ -2283,6 +2283,8 @@ pub const SrcLoc = struct {
                     .@"while" => tree.whileFull(node).ast.cond_expr,
                     .for_simple => tree.forSimple(node).ast.cond_expr,
                     .@"for" => tree.forFull(node).ast.cond_expr,
+                    .@"orelse" => node,
+                    .@"catch" => node,
                     else => unreachable,
                 };
                 return nodeToSpan(tree, src_node);
src/print_zir.zig
@@ -409,6 +409,7 @@ const Writer = struct {
             .alloc_inferred_comptime_mut,
             .ret_ptr,
             .ret_type,
+            .check_comptime_control_flow,
             => try self.writeNode(stream, inst),
 
             .error_value,
src/Sema.zig
@@ -1146,6 +1146,24 @@ fn analyzeBodyInner(
                 i += 1;
                 continue;
             },
+            .check_comptime_control_flow => {
+                if (!block.is_comptime) {
+                    if (block.runtime_cond orelse block.runtime_loop) |runtime_src| {
+                        const inst_data = sema.code.instructions.items(.data)[inst].node;
+                        const src = LazySrcLoc.nodeOffset(inst_data);
+                        const msg = msg: {
+                            const msg = try sema.errMsg(block, src, "comptime control flow inside runtime block", .{});
+                            errdefer msg.destroy(sema.gpa);
+
+                            try sema.errNote(block, runtime_src, msg, "runtime control flow here", .{});
+                            break :msg msg;
+                        };
+                        return sema.failWithOwnedErrorMsg(block, msg);
+                    }
+                }
+                i += 1;
+                continue;
+            },
 
             // Special case instructions to handle comptime control flow.
             .@"break" => {
src/Zir.zig
@@ -280,6 +280,9 @@ pub const Inst = struct {
         /// break instruction in a block, and the target block is the parent.
         /// Uses the `break` union field.
         break_inline,
+        /// Checks that comptime control flow does not happen inside a runtime block.
+        /// Uses the `node` union field.
+        check_comptime_control_flow,
         /// Function call.
         /// Uses the `pl_node` union field with payload `Call`.
         /// AST node is the function call.
@@ -1266,6 +1269,7 @@ pub const Inst = struct {
                 .repeat_inline,
                 .panic,
                 .panic_comptime,
+                .check_comptime_control_flow,
                 => true,
             };
         }
@@ -1315,6 +1319,7 @@ pub const Inst = struct {
                 .set_runtime_safety,
                 .memcpy,
                 .memset,
+                .check_comptime_control_flow,
                 => true,
 
                 .param,
@@ -1595,6 +1600,7 @@ pub const Inst = struct {
                 .bool_br_or = .bool_br,
                 .@"break" = .@"break",
                 .break_inline = .@"break",
+                .check_comptime_control_flow = .node,
                 .call = .pl_node,
                 .cmp_lt = .pl_node,
                 .cmp_lte = .pl_node,
test/cases/compile_errors/stage1/obj/comptime_continue_inside_runtime_catch.zig → test/cases/compile_errors/comptime_continue_inside_runtime_catch.zig
@@ -9,8 +9,8 @@ fn bad() !void {
 }
 
 // error
-// backend=stage1
+// backend=stage2
 // target=native
 //
-// tmp.zig:4:21: error: comptime control flow inside runtime block
-// tmp.zig:4:15: note: runtime block created here
+// :4:21: error: comptime control flow inside runtime block
+// :4:15: note: runtime control flow here
test/cases/compile_errors/stage1/obj/comptime_continue_inside_runtime_if_bool.zig → test/cases/compile_errors/comptime_continue_inside_runtime_if_bool.zig
@@ -8,8 +8,8 @@ export fn entry() void {
 }
 
 // error
-// backend=stage1
+// backend=stage2
 // target=native
 //
-// tmp.zig:5:22: error: comptime control flow inside runtime block
-// tmp.zig:5:9: note: runtime block created here
+// :5:22: error: comptime control flow inside runtime block
+// :5:15: note: runtime control flow here
test/cases/compile_errors/stage1/obj/comptime_continue_inside_runtime_if_error.zig → test/cases/compile_errors/comptime_continue_inside_runtime_if_error.zig
@@ -8,8 +8,8 @@ export fn entry() void {
 }
 
 // error
-// backend=stage1
+// backend=stage2
 // target=native
 //
-// tmp.zig:5:20: error: comptime control flow inside runtime block
-// tmp.zig:5:9: note: runtime block created here
+// :5:20: error: comptime control flow inside runtime block
+// :5:13: note: runtime control flow here
test/cases/compile_errors/stage1/obj/comptime_continue_inside_runtime_if_optional.zig → test/cases/compile_errors/comptime_continue_inside_runtime_if_optional.zig
@@ -8,8 +8,8 @@ export fn entry() void {
 }
 
 // error
-// backend=stage1
+// backend=stage2
 // target=native
 //
-// tmp.zig:5:20: error: comptime control flow inside runtime block
-// tmp.zig:5:9: note: runtime block created here
+// :5:20: error: comptime control flow inside runtime block
+// :5:13: note: runtime control flow here
test/cases/compile_errors/comptime_continue_inside_runtime_orelse.zig
@@ -0,0 +1,16 @@
+export fn entry() void {
+    const ints = [_]u8{ 1, 2 };
+    inline for (ints) |_| {
+        bad() orelse continue;
+    }
+}
+fn bad() ?void {
+    return null;
+}
+
+// error
+// backend=stage2
+// target=native
+//
+// :4:22: error: comptime control flow inside runtime block
+// :4:15: note: runtime control flow here
test/cases/compile_errors/stage1/obj/comptime_continue_inside_runtime_switch.zig → test/cases/compile_errors/comptime_continue_inside_runtime_switch.zig
@@ -11,8 +11,8 @@ export fn entry() void {
 }
 
 // error
-// backend=stage1
+// backend=stage2
 // target=native
 //
-// tmp.zig:6:19: error: comptime control flow inside runtime block
-// tmp.zig:5:9: note: runtime block created here
+// :6:19: error: comptime control flow inside runtime block
+// :5:17: note: runtime control flow here
test/cases/compile_errors/stage1/obj/comptime_continue_inside_runtime_while_bool.zig → test/cases/compile_errors/comptime_continue_inside_runtime_while_bool.zig
@@ -8,8 +8,8 @@ export fn entry() void {
 }
 
 // error
-// backend=stage1
+// backend=stage2
 // target=native
 //
-// tmp.zig:5:25: error: comptime control flow inside runtime block
-// tmp.zig:5:9: note: runtime block created here
+// :5:25: error: comptime control flow inside runtime block
+// :5:18: note: runtime control flow here
test/cases/compile_errors/stage1/obj/comptime_continue_inside_runtime_while_error.zig → test/cases/compile_errors/comptime_continue_inside_runtime_while_error.zig
@@ -10,8 +10,8 @@ export fn entry() void {
 }
 
 // error
-// backend=stage1
+// backend=stage2
 // target=native
 //
-// tmp.zig:6:13: error: comptime control flow inside runtime block
-// tmp.zig:5:9: note: runtime block created here
+// :6:13: error: comptime control flow inside runtime block
+// :5:16: note: runtime control flow here
test/cases/compile_errors/stage1/obj/comptime_continue_inside_runtime_while_optional.zig → test/cases/compile_errors/comptime_continue_inside_runtime_while_optional.zig
@@ -8,8 +8,8 @@ export fn entry() void {
 }
 
 // error
-// backend=stage1
+// backend=stage2
 // target=native
 //
-// tmp.zig:5:23: error: comptime control flow inside runtime block
-// tmp.zig:5:9: note: runtime block created here
+// :5:23: error: comptime control flow inside runtime block
+// :5:16: note: runtime control flow here