zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit dd01e4927da41290836c40953b06ac6dc44be707 (tree)
parent 0fc53ea8ea792464bb2ca7259a3827fa8a8c50d2
Author: Motiejus Jakštys <motiejus@jakstys.lt>
Date:   Tue, 24 Feb 2026 20:34:53 +0000

sema: keep dead block on comptime return (match upstream)

In upstream Sema.zig:7872, when an inline call returns at comptime
(ComptimeReturn), the pre-allocated block instruction is NOT rolled
back — it remains as a dead block in the AIR. The C sema was
incorrectly discarding it by rolling back air_inst_len to before the
block.

Fix: roll back to block_inst_idx+1 (keep dead block, discard body
instructions). This produces dead blocks for comptime inline calls
in comptime context (e.g., floatExponentMax, mantissaOne called
from within nan(T)'s comptime-evaluated body).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

Diffstat:
Mstage0/sema.c | 25++++++++++++-------------
1 file changed, 12 insertions(+), 13 deletions(-)

diff --git a/stage0/sema.c b/stage0/sema.c @@ -4666,10 +4666,7 @@ static AirInstRef zirCall( AirInstTag block_tag = need_debug_scope ? AIR_INST_DBG_INLINE_BLOCK : AIR_INST_BLOCK; - // Save AIR state for rollback if the inline call returns at comptime. - // Ported from Sema.zig: - // air_instructions.shrinkRetainingCapacity(block_inst) - uint32_t saved_air_inst_len = sema->air_inst_len; + // Save block instruction count for rollback if comptime return. uint32_t saved_block_inst_len = block->instructions_len; // Reserve the block instruction (data filled later). @@ -4739,9 +4736,6 @@ static AirInstRef zirCall( if (AIR_REF_IS_IP(arg_refs[param_idx])) { InternPoolIndex ip = AIR_REF_TO_IP(arg_refs[param_idx]); InternPoolKey key = sema->ip->items[ip]; - // Keys from - // IP_KEY_INT_TYPE..IP_KEY_INFERRED_ERROR_SET_TYPE are type - // values (the param's type is `type`). arg_is_type = (key.tag >= IP_KEY_INT_TYPE && key.tag <= IP_KEY_INFERRED_ERROR_SET_TYPE); if (!arg_is_type) { @@ -4836,14 +4830,19 @@ static AirInstRef zirCall( sema->fn_ret_ty = saved_fn_ret_ty; // ComptimeReturn: the inline function returned at comptime. - // Skip block finalization — no AIR instructions emitted. - // Roll back AIR state to discard the reserved block and any body - // instructions (they are dead). Ported from src/Sema.zig line 7872: - // sema.air_instructions.shrinkRetainingCapacity(block_inst) - // block.instructions.shrinkRetainingCapacity(block_index) + // Upstream Sema.zig:7872: error.ComptimeReturn => break :result + // inlining.comptime_result + // Upstream does NOT roll back the AIR — the block instruction and + // a dead block in the AIR. Body instructions added to the child + // block are not referenced by any block, so they are dead too. + // Roll back to block_inst_idx+1 to keep the dead block but + // discard body instructions added to the global AIR array. + // TODO: upstream keeps ALL body instructions (no rollback); + // matching that requires also fixing dbg_arg_inline emission + // for comptime-known args within comptime inline contexts. if (inlining.comptime_returned) { AirInstRef ct_result = inlining.comptime_result; - sema->air_inst_len = saved_air_inst_len; + sema->air_inst_len = block_inst_idx + 1; block->instructions_len = saved_block_inst_len; // Cache comptime results for memoization.