| author | |
| committer | |
| log | 9e0a930ce3be01923602adbfee13b50842da08b7 |
| tree | f48fa98efd8c6d75cf431fa3c10e231e3688d0ff |
| parent | b5861193e072ba6780730a559f2b879378b8587f |
22 files changed, 173 insertions(+), 126 deletions(-)
src/AstGen.zig+4| ... | @@ -1940,6 +1940,9 @@ fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) | ... | @@ -1940,6 +1940,9 @@ fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) |
| 1940 | .break_inline | 1940 | .break_inline |
| 1941 | else | 1941 | else |
| 1942 | .@"break"; | 1942 | .@"break"; |
| 1943 | if (break_tag == .break_inline) { | ||
| 1944 | _ = try parent_gz.addNode(.check_comptime_control_flow, node); | ||
| 1945 | } | ||
| 1943 | _ = try parent_gz.addBreak(break_tag, continue_block, .void_value); | 1946 | _ = try parent_gz.addBreak(break_tag, continue_block, .void_value); |
| 1944 | return Zir.Inst.Ref.unreachable_value; | 1947 | return Zir.Inst.Ref.unreachable_value; |
| 1945 | }, | 1948 | }, |
| ... | @@ -2473,6 +2476,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner | ... | @@ -2473,6 +2476,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner |
| 2473 | .repeat_inline, | 2476 | .repeat_inline, |
| 2474 | .panic, | 2477 | .panic, |
| 2475 | .panic_comptime, | 2478 | .panic_comptime, |
| 2479 | .check_comptime_control_flow, | ||
| 2476 | => { | 2480 | => { |
| 2477 | noreturn_src_node = statement; | 2481 | noreturn_src_node = statement; |
| 2478 | break :b true; | 2482 | break :b true; |
src/Module.zig+2| ... | @@ -2283,6 +2283,8 @@ pub const SrcLoc = struct { | ... | @@ -2283,6 +2283,8 @@ pub const SrcLoc = struct { |
| 2283 | .@"while" => tree.whileFull(node).ast.cond_expr, | 2283 | .@"while" => tree.whileFull(node).ast.cond_expr, |
| 2284 | .for_simple => tree.forSimple(node).ast.cond_expr, | 2284 | .for_simple => tree.forSimple(node).ast.cond_expr, |
| 2285 | .@"for" => tree.forFull(node).ast.cond_expr, | 2285 | .@"for" => tree.forFull(node).ast.cond_expr, |
| 2286 | .@"orelse" => node, | ||
| 2287 | .@"catch" => node, | ||
| 2286 | else => unreachable, | 2288 | else => unreachable, |
| 2287 | }; | 2289 | }; |
| 2288 | return nodeToSpan(tree, src_node); | 2290 | return nodeToSpan(tree, src_node); |
src/Sema.zig+18| ... | @@ -1146,6 +1146,24 @@ fn analyzeBodyInner( | ... | @@ -1146,6 +1146,24 @@ fn analyzeBodyInner( |
| 1146 | i += 1; | 1146 | i += 1; |
| 1147 | continue; | 1147 | continue; |
| 1148 | }, | 1148 | }, |
| 1149 | .check_comptime_control_flow => { | ||
| 1150 | if (!block.is_comptime) { | ||
| 1151 | if (block.runtime_cond orelse block.runtime_loop) |runtime_src| { | ||
| 1152 | const inst_data = sema.code.instructions.items(.data)[inst].node; | ||
| 1153 | const src = LazySrcLoc.nodeOffset(inst_data); | ||
| 1154 | const msg = msg: { | ||
| 1155 | const msg = try sema.errMsg(block, src, "comptime control flow inside runtime block", .{}); | ||
| 1156 | errdefer msg.destroy(sema.gpa); | ||
| 1157 | |||
| 1158 | try sema.errNote(block, runtime_src, msg, "runtime control flow here", .{}); | ||
| 1159 | break :msg msg; | ||
| 1160 | }; | ||
| 1161 | return sema.failWithOwnedErrorMsg(block, msg); | ||
| 1162 | } | ||
| 1163 | } | ||
| 1164 | i += 1; | ||
| 1165 | continue; | ||
| 1166 | }, | ||
| 1149 | 1167 | ||
| 1150 | // Special case instructions to handle comptime control flow. | 1168 | // Special case instructions to handle comptime control flow. |
| 1151 | .@"break" => { | 1169 | .@"break" => { |
src/Zir.zig+6| ... | @@ -280,6 +280,9 @@ pub const Inst = struct { | ... | @@ -280,6 +280,9 @@ pub const Inst = struct { |
| 280 | /// break instruction in a block, and the target block is the parent. | 280 | /// break instruction in a block, and the target block is the parent. |
| 281 | /// Uses the `break` union field. | 281 | /// Uses the `break` union field. |
| 282 | break_inline, | 282 | break_inline, |
| 283 | /// Checks that comptime control flow does not happen inside a runtime block. | ||
| 284 | /// Uses the `node` union field. | ||
| 285 | check_comptime_control_flow, | ||
| 283 | /// Function call. | 286 | /// Function call. |
| 284 | /// Uses the `pl_node` union field with payload `Call`. | 287 | /// Uses the `pl_node` union field with payload `Call`. |
| 285 | /// AST node is the function call. | 288 | /// AST node is the function call. |
| ... | @@ -1266,6 +1269,7 @@ pub const Inst = struct { | ... | @@ -1266,6 +1269,7 @@ pub const Inst = struct { |
| 1266 | .repeat_inline, | 1269 | .repeat_inline, |
| 1267 | .panic, | 1270 | .panic, |
| 1268 | .panic_comptime, | 1271 | .panic_comptime, |
| 1272 | .check_comptime_control_flow, | ||
| 1269 | => true, | 1273 | => true, |
| 1270 | }; | 1274 | }; |
| 1271 | } | 1275 | } |
| ... | @@ -1315,6 +1319,7 @@ pub const Inst = struct { | ... | @@ -1315,6 +1319,7 @@ pub const Inst = struct { |
| 1315 | .set_runtime_safety, | 1319 | .set_runtime_safety, |
| 1316 | .memcpy, | 1320 | .memcpy, |
| 1317 | .memset, | 1321 | .memset, |
| 1322 | .check_comptime_control_flow, | ||
| 1318 | => true, | 1323 | => true, |
| 1319 | 1324 | ||
| 1320 | .param, | 1325 | .param, |
| ... | @@ -1595,6 +1600,7 @@ pub const Inst = struct { | ... | @@ -1595,6 +1600,7 @@ pub const Inst = struct { |
| 1595 | .bool_br_or = .bool_br, | 1600 | .bool_br_or = .bool_br, |
| 1596 | .@"break" = .@"break", | 1601 | .@"break" = .@"break", |
| 1597 | .break_inline = .@"break", | 1602 | .break_inline = .@"break", |
| 1603 | .check_comptime_control_flow = .node, | ||
| 1598 | .call = .pl_node, | 1604 | .call = .pl_node, |
| 1599 | .cmp_lt = .pl_node, | 1605 | .cmp_lt = .pl_node, |
| 1600 | .cmp_lte = .pl_node, | 1606 | .cmp_lte = .pl_node, |
src/print_zir.zig+1| ... | @@ -409,6 +409,7 @@ const Writer = struct { | ... | @@ -409,6 +409,7 @@ const Writer = struct { |
| 409 | .alloc_inferred_comptime_mut, | 409 | .alloc_inferred_comptime_mut, |
| 410 | .ret_ptr, | 410 | .ret_ptr, |
| 411 | .ret_type, | 411 | .ret_type, |
| 412 | .check_comptime_control_flow, | ||
| 412 | => try self.writeNode(stream, inst), | 413 | => try self.writeNode(stream, inst), |
| 413 | 414 | ||
| 414 | .error_value, | 415 | .error_value, |
test/cases/compile_errors/comptime_continue_inside_runtime_catch.zig created+16| ... | @@ -0,0 +1,16 @@ | ||
| 1 | export fn entry() void { | ||
| 2 | const ints = [_]u8{ 1, 2 }; | ||
| 3 | inline for (ints) |_| { | ||
| 4 | bad() catch continue; | ||
| 5 | } | ||
| 6 | } | ||
| 7 | fn bad() !void { | ||
| 8 | return error.Bad; | ||
| 9 | } | ||
| 10 | |||
| 11 | // error | ||
| 12 | // backend=stage2 | ||
| 13 | // target=native | ||
| 14 | // | ||
| 15 | // :4:21: error: comptime control flow inside runtime block | ||
| 16 | // :4:15: note: runtime control flow here | ||
test/cases/compile_errors/comptime_continue_inside_runtime_if_bool.zig created+15| ... | @@ -0,0 +1,15 @@ | ||
| 1 | export fn entry() void { | ||
| 2 | var p: usize = undefined; | ||
| 3 | comptime var q = true; | ||
| 4 | inline while (q) { | ||
| 5 | if (p == 11) continue; | ||
| 6 | q = false; | ||
| 7 | } | ||
| 8 | } | ||
| 9 | |||
| 10 | // error | ||
| 11 | // backend=stage2 | ||
| 12 | // target=native | ||
| 13 | // | ||
| 14 | // :5:22: error: comptime control flow inside runtime block | ||
| 15 | // :5:15: note: runtime control flow here | ||
test/cases/compile_errors/comptime_continue_inside_runtime_if_error.zig created+15| ... | @@ -0,0 +1,15 @@ | ||
| 1 | export fn entry() void { | ||
| 2 | var p: anyerror!i32 = undefined; | ||
| 3 | comptime var q = true; | ||
| 4 | inline while (q) { | ||
| 5 | if (p) |_| continue else |_| {} | ||
| 6 | q = false; | ||
| 7 | } | ||
| 8 | } | ||
| 9 | |||
| 10 | // error | ||
| 11 | // backend=stage2 | ||
| 12 | // target=native | ||
| 13 | // | ||
| 14 | // :5:20: error: comptime control flow inside runtime block | ||
| 15 | // :5:13: note: runtime control flow here | ||
test/cases/compile_errors/comptime_continue_inside_runtime_if_optional.zig created+15| ... | @@ -0,0 +1,15 @@ | ||
| 1 | export fn entry() void { | ||
| 2 | var p: ?i32 = undefined; | ||
| 3 | comptime var q = true; | ||
| 4 | inline while (q) { | ||
| 5 | if (p) |_| continue; | ||
| 6 | q = false; | ||
| 7 | } | ||
| 8 | } | ||
| 9 | |||
| 10 | // error | ||
| 11 | // backend=stage2 | ||
| 12 | // target=native | ||
| 13 | // | ||
| 14 | // :5:20: error: comptime control flow inside runtime block | ||
| 15 | // :5:13: note: runtime control flow here | ||
test/cases/compile_errors/comptime_continue_inside_runtime_orelse.zig created+16| ... | @@ -0,0 +1,16 @@ | ||
| 1 | export fn entry() void { | ||
| 2 | const ints = [_]u8{ 1, 2 }; | ||
| 3 | inline for (ints) |_| { | ||
| 4 | bad() orelse continue; | ||
| 5 | } | ||
| 6 | } | ||
| 7 | fn bad() ?void { | ||
| 8 | return null; | ||
| 9 | } | ||
| 10 | |||
| 11 | // error | ||
| 12 | // backend=stage2 | ||
| 13 | // target=native | ||
| 14 | // | ||
| 15 | // :4:22: error: comptime control flow inside runtime block | ||
| 16 | // :4:15: note: runtime control flow here | ||
test/cases/compile_errors/comptime_continue_inside_runtime_switch.zig created+18| ... | @@ -0,0 +1,18 @@ | ||
| 1 | export fn entry() void { | ||
| 2 | var p: i32 = undefined; | ||
| 3 | comptime var q = true; | ||
| 4 | inline while (q) { | ||
| 5 | switch (p) { | ||
| 6 | 11 => continue, | ||
| 7 | else => {}, | ||
| 8 | } | ||
| 9 | q = false; | ||
| 10 | } | ||
| 11 | } | ||
| 12 | |||
| 13 | // error | ||
| 14 | // backend=stage2 | ||
| 15 | // target=native | ||
| 16 | // | ||
| 17 | // :6:19: error: comptime control flow inside runtime block | ||
| 18 | // :5:17: note: runtime control flow here | ||
test/cases/compile_errors/comptime_continue_inside_runtime_while_bool.zig created+15| ... | @@ -0,0 +1,15 @@ | ||
| 1 | export fn entry() void { | ||
| 2 | var p: usize = undefined; | ||
| 3 | comptime var q = true; | ||
| 4 | outer: inline while (q) { | ||
| 5 | while (p == 11) continue :outer; | ||
| 6 | q = false; | ||
| 7 | } | ||
| 8 | } | ||
| 9 | |||
| 10 | // error | ||
| 11 | // backend=stage2 | ||
| 12 | // target=native | ||
| 13 | // | ||
| 14 | // :5:25: error: comptime control flow inside runtime block | ||
| 15 | // :5:18: note: runtime control flow here | ||
test/cases/compile_errors/comptime_continue_inside_runtime_while_error.zig created+17| ... | @@ -0,0 +1,17 @@ | ||
| 1 | export fn entry() void { | ||
| 2 | var p: anyerror!usize = undefined; | ||
| 3 | comptime var q = true; | ||
| 4 | outer: inline while (q) { | ||
| 5 | while (p) |_| { | ||
| 6 | continue :outer; | ||
| 7 | } else |_| {} | ||
| 8 | q = false; | ||
| 9 | } | ||
| 10 | } | ||
| 11 | |||
| 12 | // error | ||
| 13 | // backend=stage2 | ||
| 14 | // target=native | ||
| 15 | // | ||
| 16 | // :6:13: error: comptime control flow inside runtime block | ||
| 17 | // :5:16: note: runtime control flow here | ||
test/cases/compile_errors/comptime_continue_inside_runtime_while_optional.zig created+15| ... | @@ -0,0 +1,15 @@ | ||
| 1 | export fn entry() void { | ||
| 2 | var p: ?usize = undefined; | ||
| 3 | comptime var q = true; | ||
| 4 | outer: inline while (q) { | ||
| 5 | while (p) |_| continue :outer; | ||
| 6 | q = false; | ||
| 7 | } | ||
| 8 | } | ||
| 9 | |||
| 10 | // error | ||
| 11 | // backend=stage2 | ||
| 12 | // target=native | ||
| 13 | // | ||
| 14 | // :5:23: error: comptime control flow inside runtime block | ||
| 15 | // :5:16: note: runtime control flow here | ||
test/cases/compile_errors/stage1/obj/comptime_continue_inside_runtime_catch.zig deleted-16| ... | @@ -1,16 +0,0 @@ | ||
| 1 | export fn entry() void { | ||
| 2 | const ints = [_]u8{ 1, 2 }; | ||
| 3 | inline for (ints) |_| { | ||
| 4 | bad() catch continue; | ||
| 5 | } | ||
| 6 | } | ||
| 7 | fn bad() !void { | ||
| 8 | return error.Bad; | ||
| 9 | } | ||
| 10 | |||
| 11 | // error | ||
| 12 | // backend=stage1 | ||
| 13 | // target=native | ||
| 14 | // | ||
| 15 | // tmp.zig:4:21: error: comptime control flow inside runtime block | ||
| 16 | // tmp.zig:4:15: note: runtime block created here | ||
test/cases/compile_errors/stage1/obj/comptime_continue_inside_runtime_if_bool.zig deleted-15| ... | @@ -1,15 +0,0 @@ | ||
| 1 | export fn entry() void { | ||
| 2 | var p: usize = undefined; | ||
| 3 | comptime var q = true; | ||
| 4 | inline while (q) { | ||
| 5 | if (p == 11) continue; | ||
| 6 | q = false; | ||
| 7 | } | ||
| 8 | } | ||
| 9 | |||
| 10 | // error | ||
| 11 | // backend=stage1 | ||
| 12 | // target=native | ||
| 13 | // | ||
| 14 | // tmp.zig:5:22: error: comptime control flow inside runtime block | ||
| 15 | // tmp.zig:5:9: note: runtime block created here | ||
test/cases/compile_errors/stage1/obj/comptime_continue_inside_runtime_if_error.zig deleted-15| ... | @@ -1,15 +0,0 @@ | ||
| 1 | export fn entry() void { | ||
| 2 | var p: anyerror!i32 = undefined; | ||
| 3 | comptime var q = true; | ||
| 4 | inline while (q) { | ||
| 5 | if (p) |_| continue else |_| {} | ||
| 6 | q = false; | ||
| 7 | } | ||
| 8 | } | ||
| 9 | |||
| 10 | // error | ||
| 11 | // backend=stage1 | ||
| 12 | // target=native | ||
| 13 | // | ||
| 14 | // tmp.zig:5:20: error: comptime control flow inside runtime block | ||
| 15 | // tmp.zig:5:9: note: runtime block created here | ||
test/cases/compile_errors/stage1/obj/comptime_continue_inside_runtime_if_optional.zig deleted-15| ... | @@ -1,15 +0,0 @@ | ||
| 1 | export fn entry() void { | ||
| 2 | var p: ?i32 = undefined; | ||
| 3 | comptime var q = true; | ||
| 4 | inline while (q) { | ||
| 5 | if (p) |_| continue; | ||
| 6 | q = false; | ||
| 7 | } | ||
| 8 | } | ||
| 9 | |||
| 10 | // error | ||
| 11 | // backend=stage1 | ||
| 12 | // target=native | ||
| 13 | // | ||
| 14 | // tmp.zig:5:20: error: comptime control flow inside runtime block | ||
| 15 | // tmp.zig:5:9: note: runtime block created here | ||
test/cases/compile_errors/stage1/obj/comptime_continue_inside_runtime_switch.zig deleted-18| ... | @@ -1,18 +0,0 @@ | ||
| 1 | export fn entry() void { | ||
| 2 | var p: i32 = undefined; | ||
| 3 | comptime var q = true; | ||
| 4 | inline while (q) { | ||
| 5 | switch (p) { | ||
| 6 | 11 => continue, | ||
| 7 | else => {}, | ||
| 8 | } | ||
| 9 | q = false; | ||
| 10 | } | ||
| 11 | } | ||
| 12 | |||
| 13 | // error | ||
| 14 | // backend=stage1 | ||
| 15 | // target=native | ||
| 16 | // | ||
| 17 | // tmp.zig:6:19: error: comptime control flow inside runtime block | ||
| 18 | // tmp.zig:5:9: note: runtime block created here | ||
test/cases/compile_errors/stage1/obj/comptime_continue_inside_runtime_while_bool.zig deleted-15| ... | @@ -1,15 +0,0 @@ | ||
| 1 | export fn entry() void { | ||
| 2 | var p: usize = undefined; | ||
| 3 | comptime var q = true; | ||
| 4 | outer: inline while (q) { | ||
| 5 | while (p == 11) continue :outer; | ||
| 6 | q = false; | ||
| 7 | } | ||
| 8 | } | ||
| 9 | |||
| 10 | // error | ||
| 11 | // backend=stage1 | ||
| 12 | // target=native | ||
| 13 | // | ||
| 14 | // tmp.zig:5:25: error: comptime control flow inside runtime block | ||
| 15 | // tmp.zig:5:9: note: runtime block created here | ||
test/cases/compile_errors/stage1/obj/comptime_continue_inside_runtime_while_error.zig deleted-17| ... | @@ -1,17 +0,0 @@ | ||
| 1 | export fn entry() void { | ||
| 2 | var p: anyerror!usize = undefined; | ||
| 3 | comptime var q = true; | ||
| 4 | outer: inline while (q) { | ||
| 5 | while (p) |_| { | ||
| 6 | continue :outer; | ||
| 7 | } else |_| {} | ||
| 8 | q = false; | ||
| 9 | } | ||
| 10 | } | ||
| 11 | |||
| 12 | // error | ||
| 13 | // backend=stage1 | ||
| 14 | // target=native | ||
| 15 | // | ||
| 16 | // tmp.zig:6:13: error: comptime control flow inside runtime block | ||
| 17 | // tmp.zig:5:9: note: runtime block created here | ||
test/cases/compile_errors/stage1/obj/comptime_continue_inside_runtime_while_optional.zig deleted-15| ... | @@ -1,15 +0,0 @@ | ||
| 1 | export fn entry() void { | ||
| 2 | var p: ?usize = undefined; | ||
| 3 | comptime var q = true; | ||
| 4 | outer: inline while (q) { | ||
| 5 | while (p) |_| continue :outer; | ||
| 6 | q = false; | ||
| 7 | } | ||
| 8 | } | ||
| 9 | |||
| 10 | // error | ||
| 11 | // backend=stage1 | ||
| 12 | // target=native | ||
| 13 | // | ||
| 14 | // tmp.zig:5:23: error: comptime control flow inside runtime block | ||
| 15 | // tmp.zig:5:9: note: runtime block created here | ||