diff --git a/lib/std/zig/AstGen.zig b/lib/std/zig/AstGen.zig index d51302ac0b..4c535bc4cc 100644 --- a/lib/std/zig/AstGen.zig +++ b/lib/std/zig/AstGen.zig @@ -2963,6 +2963,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As .validate_array_init_result_ty, .validate_ptr_array_init, .validate_ref_ty, + .validate_const, .try_operand_ty, .try_ref_operand_ty, => break :b true, @@ -3280,6 +3281,7 @@ fn varDecl( const init_inst = try reachableExprComptime(gz, scope, result_info, var_decl.ast.init_node, node, if (force_comptime) .comptime_keyword else null); gz.anon_name_strategy = prev_anon_name_strategy; + _ = try gz.addUnNode(.validate_const, init_inst, var_decl.ast.init_node); try gz.addDbgVar(.dbg_var_val, ident_name, init_inst); // The const init expression may have modified the error return trace, so signal diff --git a/lib/std/zig/Zir.zig b/lib/std/zig/Zir.zig index 92b33e807c..9f420d2171 100644 --- a/lib/std/zig/Zir.zig +++ b/lib/std/zig/Zir.zig @@ -711,6 +711,12 @@ pub const Inst = struct { /// operator. Emit a compile error if not. /// Uses the `un_tok` union field. Token is the `&` operator. Operand is the type. validate_ref_ty, + /// Given a value, check whether it is a valid local constant in this scope. + /// In a runtime scope, this is always a nop. + /// In a comptime scope, raises a compile error if the value is runtime-known. + /// Result is always void. + /// Uses the `un_node` union field. Node is the initializer. Operand is the initializer value. + validate_const, /// Given a type `T`, construct the type `E!T`, where `E` is this function's error set, to be used /// as the result type of a `try` operand. Generic poison is propagated. /// Uses the `un_node` union field. Node is the `try` expression. Operand is the type `T`. @@ -1293,6 +1299,7 @@ pub const Inst = struct { .array_init_elem_type, .array_init_elem_ptr, .validate_ref_ty, + .validate_const, .try_operand_ty, .try_ref_operand_ty, .restore_err_ret_index_unconditional, @@ -1353,6 +1360,7 @@ pub const Inst = struct { .validate_array_init_result_ty, .validate_ptr_array_init, .validate_ref_ty, + .validate_const, .try_operand_ty, .try_ref_operand_ty, => true, @@ -1736,6 +1744,7 @@ pub const Inst = struct { .opt_eu_base_ptr_init = .un_node, .coerce_ptr_elem_ty = .pl_node, .validate_ref_ty = .un_tok, + .validate_const = .un_node, .try_operand_ty = .un_node, .try_ref_operand_ty = .un_node, @@ -4143,6 +4152,7 @@ fn findTrackableInner( .opt_eu_base_ptr_init, .coerce_ptr_elem_ty, .validate_ref_ty, + .validate_const, .try_operand_ty, .try_ref_operand_ty, .struct_init_empty, diff --git a/src/Sema.zig b/src/Sema.zig index 3eef15492c..6f2f3996b4 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -1502,6 +1502,11 @@ fn analyzeBodyInner( i += 1; continue; }, + .validate_const => { + try sema.zirValidateConst(block, inst); + i += 1; + continue; + }, .@"export" => { try sema.zirExport(block, inst); i += 1; @@ -4614,6 +4619,17 @@ fn zirValidateRefTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr } } +fn zirValidateConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { + if (!block.isComptime()) return; + + const un_node = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; + const src = block.nodeOffset(un_node.src_node); + const init_ref = try sema.resolveInst(un_node.operand); + if (!try sema.isComptimeKnown(init_ref)) { + return sema.failWithNeededComptime(block, src, null); + } +} + fn zirValidateArrayInitRefTy( sema: *Sema, block: *Block, diff --git a/src/print_zir.zig b/src/print_zir.zig index 2a2f3f4b0f..14502d8ba1 100644 --- a/src/print_zir.zig +++ b/src/print_zir.zig @@ -273,6 +273,7 @@ const Writer = struct { .@"await", .make_ptr_const, .validate_deref, + .validate_const, .check_comptime_control_flow, .opt_eu_base_ptr_init, .restore_err_ret_index_unconditional,