astgen: fix defer RL annotation, compile_error noreturn, block force_comptime

Three bugs found by auditing against upstream AstGen.zig/AstRlAnnotate.zig:

1. rlExpr: defer was recursing into nd.rhs (always 0) instead of nd.lhs
   (the actual deferred expression), so the RL annotation pass never
   visited defer bodies.

2. addEnsureResult: compile_error was missing from the noreturn
   instruction list, causing spurious ensure_result_used instructions
   to be emitted after @compileError calls.

3. blockExprExpr: force_comptime was derived from gz->is_comptime,
   but upstream blockExpr always passes force_comptime=false to
   labeledBlockExpr. This caused labeled blocks in comptime contexts
   to incorrectly emit BLOCK_COMPTIME + BREAK_INLINE instead of
   BLOCK + BREAK.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-13 21:48:16 +00:00
parent befbe18ebc
commit 52bfd87de7

View File

@@ -4762,7 +4762,7 @@ static uint32_t blockExprExpr(
}
// Labeled block (AstGen.zig:2466-2536).
bool force_comptime = gz->is_comptime;
// Note: upstream blockExpr always passes force_comptime=false.
uint32_t label_token = lbrace - 2;
// Compute break result info (AstGen.zig:2484-2492).
@@ -4771,15 +4771,10 @@ static uint32_t blockExprExpr(
bool need_result_rvalue = (break_ri.tag != rl.tag);
// Reserve the block instruction (AstGen.zig:2500-2501).
ZirInstTag block_tag
= force_comptime ? ZIR_INST_BLOCK_COMPTIME : ZIR_INST_BLOCK;
uint32_t block_inst = makeBlockInst(ag, block_tag, gz, node);
uint32_t block_inst = makeBlockInst(ag, ZIR_INST_BLOCK, gz, node);
gzAppendInstruction(gz, block_inst);
GenZir block_scope = makeSubBlock(gz, scope);
block_scope.is_inline = force_comptime; // AstGen.zig:2503
if (force_comptime)
block_scope.is_comptime = true;
// Set label on block_scope (AstGen.zig:2504-2508).
block_scope.label_token = label_token;
block_scope.label_block_inst = block_inst;
@@ -4790,29 +4785,19 @@ static uint32_t blockExprExpr(
if (!endsWithNoReturn(&block_scope)) {
// Emit restore_err_ret_index (AstGen.zig:2515).
if (!force_comptime) {
ZirInstData rdata;
rdata.un_node.operand = block_inst + ZIR_REF_START_INDEX;
rdata.un_node.src_node
= (int32_t)node - (int32_t)gz->decl_node_index;
addInstruction(
gz, ZIR_INST_RESTORE_ERR_RET_INDEX_UNCONDITIONAL, rdata);
}
ZirInstData rdata;
rdata.un_node.operand = block_inst + ZIR_REF_START_INDEX;
rdata.un_node.src_node = (int32_t)node - (int32_t)gz->decl_node_index;
addInstruction(
gz, ZIR_INST_RESTORE_ERR_RET_INDEX_UNCONDITIONAL, rdata);
// rvalue + break (AstGen.zig:2516-2518).
uint32_t result = rvalue(
gz, block_scope.break_result_info, ZIR_REF_VOID_VALUE, node);
ZirInstTag break_tag
= force_comptime ? ZIR_INST_BREAK_INLINE : ZIR_INST_BREAK;
addBreak(
&block_scope, break_tag, block_inst, result, AST_NODE_OFFSET_NONE);
addBreak(&block_scope, ZIR_INST_BREAK, block_inst, result,
AST_NODE_OFFSET_NONE);
}
if (force_comptime) {
setBlockComptimeBody(
ag, &block_scope, block_inst, COMPTIME_REASON_COMPTIME_KEYWORD);
} else {
setBlockBody(ag, &block_scope, block_inst);
}
setBlockBody(ag, &block_scope, block_inst);
// AstGen.zig:2531-2534.
if (need_result_rvalue)
@@ -6602,6 +6587,7 @@ static bool addEnsureResult(
case ZIR_INST_TRAP:
case ZIR_INST_CHECK_COMPTIME_CONTROL_FLOW:
case ZIR_INST_SWITCH_CONTINUE:
case ZIR_INST_COMPILE_ERROR:
is_noreturn = true;
elide_check = true;
break;
@@ -9577,7 +9563,7 @@ static bool rlExpr(
// defer (AstRlAnnotate.zig:148-151).
case AST_NODE_DEFER:
(void)rlExpr(ag, nd.rhs, block, RL_RI_NONE);
(void)rlExpr(ag, nd.lhs, block, RL_RI_NONE);
return false;
// container_field (AstRlAnnotate.zig:153-167).