mirror of
https://github.com/ziglang/zig.git
synced 2026-02-12 20:37:54 +00:00
Sema: check_comptime_control_flow needs to check runtime_index
This commit is contained in:
parent
bf4a3df9a9
commit
5e37da6ade
@ -1981,7 +1981,7 @@ fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index)
|
||||
else
|
||||
.@"break";
|
||||
if (break_tag == .break_inline) {
|
||||
_ = try parent_gz.addNode(.check_comptime_control_flow, node);
|
||||
_ = try parent_gz.addUnNode(.check_comptime_control_flow, Zir.indexToRef(continue_block), node);
|
||||
}
|
||||
_ = try parent_gz.addBreak(break_tag, continue_block, .void_value);
|
||||
return Zir.Inst.Ref.unreachable_value;
|
||||
|
||||
23
src/Sema.zig
23
src/Sema.zig
@ -144,6 +144,7 @@ pub const Block = struct {
|
||||
/// Non zero if a non-inline loop or a runtime conditional have been encountered.
|
||||
/// Stores to to comptime variables are only allowed when var.runtime_index <= runtime_index.
|
||||
runtime_index: Value.RuntimeIndex = .zero,
|
||||
inline_block: Zir.Inst.Index = 0,
|
||||
|
||||
is_comptime: bool,
|
||||
is_typeof: bool = false,
|
||||
@ -1157,9 +1158,20 @@ fn analyzeBodyInner(
|
||||
},
|
||||
.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 inst_data = sema.code.instructions.items(.data)[inst].un_node;
|
||||
const src = inst_data.src();
|
||||
const inline_block = Zir.refToIndex(inst_data.operand).?;
|
||||
|
||||
var check_block = block;
|
||||
const target_runtime_index = while (true) {
|
||||
if (check_block.inline_block == inline_block) {
|
||||
break check_block.runtime_index;
|
||||
}
|
||||
check_block = check_block.parent.?;
|
||||
} else unreachable;
|
||||
|
||||
if (@enumToInt(target_runtime_index) < @enumToInt(block.runtime_index)) {
|
||||
const runtime_src = block.runtime_cond orelse block.runtime_loop.?;
|
||||
const msg = msg: {
|
||||
const msg = try sema.errMsg(block, src, "comptime control flow inside runtime block", .{});
|
||||
errdefer msg.destroy(sema.gpa);
|
||||
@ -1272,10 +1284,15 @@ fn analyzeBodyInner(
|
||||
// current list of parameters and restore it later.
|
||||
// Note: this probably needs to be resolved in a more general manner.
|
||||
const prev_params = block.params;
|
||||
const prev_inline_block = block.inline_block;
|
||||
if (tags[inline_body[inline_body.len - 1]] == .repeat_inline) {
|
||||
block.inline_block = inline_body[0];
|
||||
}
|
||||
block.params = .{};
|
||||
defer {
|
||||
block.params.deinit(gpa);
|
||||
block.params = prev_params;
|
||||
block.inline_block = prev_inline_block;
|
||||
}
|
||||
const opt_break_data = try sema.analyzeBodyBreak(block, inline_body);
|
||||
// A runtime conditional branch that needs a post-hoc block to be
|
||||
|
||||
@ -287,7 +287,7 @@ pub const Inst = struct {
|
||||
/// Uses the `break` union field.
|
||||
break_inline,
|
||||
/// Checks that comptime control flow does not happen inside a runtime block.
|
||||
/// Uses the `node` union field.
|
||||
/// Uses the `un_node` union field.
|
||||
check_comptime_control_flow,
|
||||
/// Function call.
|
||||
/// Uses the `pl_node` union field with payload `Call`.
|
||||
@ -1600,7 +1600,7 @@ pub const Inst = struct {
|
||||
.bool_br_or = .bool_br,
|
||||
.@"break" = .@"break",
|
||||
.break_inline = .@"break",
|
||||
.check_comptime_control_flow = .node,
|
||||
.check_comptime_control_flow = .un_node,
|
||||
.call = .pl_node,
|
||||
.cmp_lt = .pl_node,
|
||||
.cmp_lte = .pl_node,
|
||||
|
||||
@ -232,6 +232,7 @@ const Writer = struct {
|
||||
.make_ptr_const,
|
||||
.validate_deref,
|
||||
.overflow_arithmetic_ptr,
|
||||
.check_comptime_control_flow,
|
||||
=> try self.writeUnNode(stream, inst),
|
||||
|
||||
.ref,
|
||||
@ -406,7 +407,6 @@ const Writer = struct {
|
||||
.alloc_inferred_comptime_mut,
|
||||
.ret_ptr,
|
||||
.ret_type,
|
||||
.check_comptime_control_flow,
|
||||
=> try self.writeNode(stream, inst),
|
||||
|
||||
.error_value,
|
||||
|
||||
@ -1371,3 +1371,30 @@ test "break from inline loop depends on runtime condition" {
|
||||
try expect(blk == 4);
|
||||
}
|
||||
}
|
||||
|
||||
test "inline for inside a runtime condition" {
|
||||
var a = false;
|
||||
if (a) {
|
||||
const arr = .{ 1, 2, 3 };
|
||||
inline for (arr) |val| {
|
||||
if (val < 3) continue;
|
||||
try expect(val == 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test "continue in inline for inside a comptime switch" {
|
||||
const arr = .{ 1, 2, 3 };
|
||||
var count: u8 = 0;
|
||||
switch (arr[1]) {
|
||||
2 => {
|
||||
inline for (arr) |val| {
|
||||
if (val == 2) continue;
|
||||
|
||||
count += val;
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
try expect(count == 4);
|
||||
}
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
pub export fn entry() void {
|
||||
var a = false;
|
||||
const arr1 = .{ 1, 2, 3 };
|
||||
loop: inline for (arr1) |val1| {
|
||||
_ = val1;
|
||||
if (a) {
|
||||
const arr = .{ 1, 2, 3 };
|
||||
inline for (arr) |val| {
|
||||
if (val < 3) continue :loop;
|
||||
if (val != 3) unreachable;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// :9:30: error: comptime control flow inside runtime block
|
||||
// :6:13: note: runtime control flow here
|
||||
Loading…
x
Reference in New Issue
Block a user