Skip to content

Commit 9a70eee

Browse files
committed
compiler: ensure local consts in comptime scope are comptime-known
This fixes a bug which exposed a compiler implementation detail (ZIR alloc elision). Previously, `const` declarations with a runtime-known value in a comptime scope were permitted only if AstGen was able to elide the alloc in ZIR, since the error was reported by storing to the comptime alloc. This just adds a new instruction to also emit this error when the alloc is elided.
1 parent 6026a5f commit 9a70eee

File tree

4 files changed

+29
-0
lines changed

4 files changed

+29
-0
lines changed

lib/std/zig/AstGen.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2963,6 +2963,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
29632963
.validate_array_init_result_ty,
29642964
.validate_ptr_array_init,
29652965
.validate_ref_ty,
2966+
.validate_const,
29662967
.try_operand_ty,
29672968
.try_ref_operand_ty,
29682969
=> break :b true,
@@ -3280,6 +3281,7 @@ fn varDecl(
32803281
const init_inst = try reachableExprComptime(gz, scope, result_info, var_decl.ast.init_node, node, if (force_comptime) .comptime_keyword else null);
32813282
gz.anon_name_strategy = prev_anon_name_strategy;
32823283

3284+
_ = try gz.addUnNode(.validate_const, init_inst, var_decl.ast.init_node);
32833285
try gz.addDbgVar(.dbg_var_val, ident_name, init_inst);
32843286

32853287
// The const init expression may have modified the error return trace, so signal

lib/std/zig/Zir.zig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -711,6 +711,12 @@ pub const Inst = struct {
711711
/// operator. Emit a compile error if not.
712712
/// Uses the `un_tok` union field. Token is the `&` operator. Operand is the type.
713713
validate_ref_ty,
714+
/// Given a value, check whether it is a valid local constant in this scope.
715+
/// In a runtime scope, this is always a nop.
716+
/// In a comptime scope, raises a compile error if the value is runtime-known.
717+
/// Result is always void.
718+
/// Uses the `un_node` union field. Node is the initializer. Operand is the initializer value.
719+
validate_const,
714720
/// Given a type `T`, construct the type `E!T`, where `E` is this function's error set, to be used
715721
/// as the result type of a `try` operand. Generic poison is propagated.
716722
/// Uses the `un_node` union field. Node is the `try` expression. Operand is the type `T`.
@@ -1293,6 +1299,7 @@ pub const Inst = struct {
12931299
.array_init_elem_type,
12941300
.array_init_elem_ptr,
12951301
.validate_ref_ty,
1302+
.validate_const,
12961303
.try_operand_ty,
12971304
.try_ref_operand_ty,
12981305
.restore_err_ret_index_unconditional,
@@ -1353,6 +1360,7 @@ pub const Inst = struct {
13531360
.validate_array_init_result_ty,
13541361
.validate_ptr_array_init,
13551362
.validate_ref_ty,
1363+
.validate_const,
13561364
.try_operand_ty,
13571365
.try_ref_operand_ty,
13581366
=> true,
@@ -1736,6 +1744,7 @@ pub const Inst = struct {
17361744
.opt_eu_base_ptr_init = .un_node,
17371745
.coerce_ptr_elem_ty = .pl_node,
17381746
.validate_ref_ty = .un_tok,
1747+
.validate_const = .un_node,
17391748
.try_operand_ty = .un_node,
17401749
.try_ref_operand_ty = .un_node,
17411750

@@ -4143,6 +4152,7 @@ fn findTrackableInner(
41434152
.opt_eu_base_ptr_init,
41444153
.coerce_ptr_elem_ty,
41454154
.validate_ref_ty,
4155+
.validate_const,
41464156
.try_operand_ty,
41474157
.try_ref_operand_ty,
41484158
.struct_init_empty,

src/Sema.zig

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1502,6 +1502,11 @@ fn analyzeBodyInner(
15021502
i += 1;
15031503
continue;
15041504
},
1505+
.validate_const => {
1506+
try sema.zirValidateConst(block, inst);
1507+
i += 1;
1508+
continue;
1509+
},
15051510
.@"export" => {
15061511
try sema.zirExport(block, inst);
15071512
i += 1;
@@ -4614,6 +4619,17 @@ fn zirValidateRefTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
46144619
}
46154620
}
46164621

4622+
fn zirValidateConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
4623+
if (!block.isComptime()) return;
4624+
4625+
const un_node = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
4626+
const src = block.nodeOffset(un_node.src_node);
4627+
const init_ref = try sema.resolveInst(un_node.operand);
4628+
if (!try sema.isComptimeKnown(init_ref)) {
4629+
return sema.failWithNeededComptime(block, src, null);
4630+
}
4631+
}
4632+
46174633
fn zirValidateArrayInitRefTy(
46184634
sema: *Sema,
46194635
block: *Block,

src/print_zir.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ const Writer = struct {
273273
.@"await",
274274
.make_ptr_const,
275275
.validate_deref,
276+
.validate_const,
276277
.check_comptime_control_flow,
277278
.opt_eu_base_ptr_init,
278279
.restore_err_ret_index_unconditional,

0 commit comments

Comments
 (0)