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:
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.