| author | |
| committer | |
| log | 9a70eeeac52f1526b9df45614b86912565e53e54 |
| tree | 9509465bcd10becdf6dff9b49a3682235df246f5 |
| parent | 6026a5f217398b202b92a4ecc2e129691bbb3a69 |
| signature |
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.4 files changed, 29 insertions(+), 0 deletions(-)
lib/std/zig/AstGen.zig+2| ... | @@ -2963,6 +2963,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As | ... | @@ -2963,6 +2963,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As |
| 2963 | .validate_array_init_result_ty, | 2963 | .validate_array_init_result_ty, |
| 2964 | .validate_ptr_array_init, | 2964 | .validate_ptr_array_init, |
| 2965 | .validate_ref_ty, | 2965 | .validate_ref_ty, |
| 2966 | .validate_const, | ||
| 2966 | .try_operand_ty, | 2967 | .try_operand_ty, |
| 2967 | .try_ref_operand_ty, | 2968 | .try_ref_operand_ty, |
| 2968 | => break :b true, | 2969 | => break :b true, |
| ... | @@ -3280,6 +3281,7 @@ fn varDecl( | ... | @@ -3280,6 +3281,7 @@ fn varDecl( |
| 3280 | const init_inst = try reachableExprComptime(gz, scope, result_info, var_decl.ast.init_node, node, if (force_comptime) .comptime_keyword else null); | 3281 | const init_inst = try reachableExprComptime(gz, scope, result_info, var_decl.ast.init_node, node, if (force_comptime) .comptime_keyword else null); |
| 3281 | gz.anon_name_strategy = prev_anon_name_strategy; | 3282 | gz.anon_name_strategy = prev_anon_name_strategy; |
| 3282 | 3283 | ||
| 3284 | _ = try gz.addUnNode(.validate_const, init_inst, var_decl.ast.init_node); | ||
| 3283 | try gz.addDbgVar(.dbg_var_val, ident_name, init_inst); | 3285 | try gz.addDbgVar(.dbg_var_val, ident_name, init_inst); |
| 3284 | 3286 | ||
| 3285 | // The const init expression may have modified the error return trace, so signal | 3287 | // The const init expression may have modified the error return trace, so signal |
lib/std/zig/Zir.zig+10| ... | @@ -711,6 +711,12 @@ pub const Inst = struct { | ... | @@ -711,6 +711,12 @@ pub const Inst = struct { |
| 711 | /// operator. Emit a compile error if not. | 711 | /// operator. Emit a compile error if not. |
| 712 | /// Uses the `un_tok` union field. Token is the `&` operator. Operand is the type. | 712 | /// Uses the `un_tok` union field. Token is the `&` operator. Operand is the type. |
| 713 | validate_ref_ty, | 713 | 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, | ||
| 714 | /// Given a type `T`, construct the type `E!T`, where `E` is this function's error set, to be used | 720 | /// Given a type `T`, construct the type `E!T`, where `E` is this function's error set, to be used |
| 715 | /// as the result type of a `try` operand. Generic poison is propagated. | 721 | /// as the result type of a `try` operand. Generic poison is propagated. |
| 716 | /// Uses the `un_node` union field. Node is the `try` expression. Operand is the type `T`. | 722 | /// Uses the `un_node` union field. Node is the `try` expression. Operand is the type `T`. |
| ... | @@ -1293,6 +1299,7 @@ pub const Inst = struct { | ... | @@ -1293,6 +1299,7 @@ pub const Inst = struct { |
| 1293 | .array_init_elem_type, | 1299 | .array_init_elem_type, |
| 1294 | .array_init_elem_ptr, | 1300 | .array_init_elem_ptr, |
| 1295 | .validate_ref_ty, | 1301 | .validate_ref_ty, |
| 1302 | .validate_const, | ||
| 1296 | .try_operand_ty, | 1303 | .try_operand_ty, |
| 1297 | .try_ref_operand_ty, | 1304 | .try_ref_operand_ty, |
| 1298 | .restore_err_ret_index_unconditional, | 1305 | .restore_err_ret_index_unconditional, |
| ... | @@ -1353,6 +1360,7 @@ pub const Inst = struct { | ... | @@ -1353,6 +1360,7 @@ pub const Inst = struct { |
| 1353 | .validate_array_init_result_ty, | 1360 | .validate_array_init_result_ty, |
| 1354 | .validate_ptr_array_init, | 1361 | .validate_ptr_array_init, |
| 1355 | .validate_ref_ty, | 1362 | .validate_ref_ty, |
| 1363 | .validate_const, | ||
| 1356 | .try_operand_ty, | 1364 | .try_operand_ty, |
| 1357 | .try_ref_operand_ty, | 1365 | .try_ref_operand_ty, |
| 1358 | => true, | 1366 | => true, |
| ... | @@ -1736,6 +1744,7 @@ pub const Inst = struct { | ... | @@ -1736,6 +1744,7 @@ pub const Inst = struct { |
| 1736 | .opt_eu_base_ptr_init = .un_node, | 1744 | .opt_eu_base_ptr_init = .un_node, |
| 1737 | .coerce_ptr_elem_ty = .pl_node, | 1745 | .coerce_ptr_elem_ty = .pl_node, |
| 1738 | .validate_ref_ty = .un_tok, | 1746 | .validate_ref_ty = .un_tok, |
| 1747 | .validate_const = .un_node, | ||
| 1739 | .try_operand_ty = .un_node, | 1748 | .try_operand_ty = .un_node, |
| 1740 | .try_ref_operand_ty = .un_node, | 1749 | .try_ref_operand_ty = .un_node, |
| 1741 | 1750 | ||
| ... | @@ -4143,6 +4152,7 @@ fn findTrackableInner( | ... | @@ -4143,6 +4152,7 @@ fn findTrackableInner( |
| 4143 | .opt_eu_base_ptr_init, | 4152 | .opt_eu_base_ptr_init, |
| 4144 | .coerce_ptr_elem_ty, | 4153 | .coerce_ptr_elem_ty, |
| 4145 | .validate_ref_ty, | 4154 | .validate_ref_ty, |
| 4155 | .validate_const, | ||
| 4146 | .try_operand_ty, | 4156 | .try_operand_ty, |
| 4147 | .try_ref_operand_ty, | 4157 | .try_ref_operand_ty, |
| 4148 | .struct_init_empty, | 4158 | .struct_init_empty, |
src/Sema.zig+16| ... | @@ -1502,6 +1502,11 @@ fn analyzeBodyInner( | ... | @@ -1502,6 +1502,11 @@ fn analyzeBodyInner( |
| 1502 | i += 1; | 1502 | i += 1; |
| 1503 | continue; | 1503 | continue; |
| 1504 | }, | 1504 | }, |
| 1505 | .validate_const => { | ||
| 1506 | try sema.zirValidateConst(block, inst); | ||
| 1507 | i += 1; | ||
| 1508 | continue; | ||
| 1509 | }, | ||
| 1505 | .@"export" => { | 1510 | .@"export" => { |
| 1506 | try sema.zirExport(block, inst); | 1511 | try sema.zirExport(block, inst); |
| 1507 | i += 1; | 1512 | i += 1; |
| ... | @@ -4614,6 +4619,17 @@ fn zirValidateRefTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr | ... | @@ -4614,6 +4619,17 @@ fn zirValidateRefTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr |
| 4614 | } | 4619 | } |
| 4615 | } | 4620 | } |
| 4616 | 4621 | ||
| 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 | |||
| 4617 | fn zirValidateArrayInitRefTy( | 4633 | fn zirValidateArrayInitRefTy( |
| 4618 | sema: *Sema, | 4634 | sema: *Sema, |
| 4619 | block: *Block, | 4635 | block: *Block, |
src/print_zir.zig+1| ... | @@ -273,6 +273,7 @@ const Writer = struct { | ... | @@ -273,6 +273,7 @@ const Writer = struct { |
| 273 | .@"await", | 273 | .@"await", |
| 274 | .make_ptr_const, | 274 | .make_ptr_const, |
| 275 | .validate_deref, | 275 | .validate_deref, |
| 276 | .validate_const, | ||
| 276 | .check_comptime_control_flow, | 277 | .check_comptime_control_flow, |
| 277 | .opt_eu_base_ptr_init, | 278 | .opt_eu_base_ptr_init, |
| 278 | .restore_err_ret_index_unconditional, | 279 | .restore_err_ret_index_unconditional, |