diff --git a/astgen.c b/astgen.c index 040528f9cc..528da42f9e 100644 --- a/astgen.c +++ b/astgen.c @@ -262,6 +262,7 @@ typedef struct { uint32_t label_token; // UINT32_MAX = no label uint32_t label_block_inst; // the BLOCK instruction index ResultLoc break_result_info; // RL for break values + uint32_t any_defer_node; // UINT32_MAX = none (AstGen.zig:11812) } GenZir; // Scope.LocalVal (AstGen.zig:11682). @@ -366,6 +367,7 @@ static GenZir makeSubBlock(GenZir* parent, Scope* scope) { sub.break_block = UINT32_MAX; sub.continue_block = UINT32_MAX; sub.label_token = UINT32_MAX; + sub.any_defer_node = parent->any_defer_node; return sub; } @@ -2299,6 +2301,18 @@ static bool refIsNoReturn(GenZir* gz, uint32_t inst_ref) { return false; } +// Mirrors reachableExpr (AstGen.zig:408-416). +// Wraps exprRl and emits an error if the result is noreturn. +static uint32_t reachableExpr(GenZir* gz, Scope* scope, ResultLoc rl, + uint32_t node, uint32_t reachable_node) { + uint32_t result = exprRl(gz, scope, rl, node); + if (refIsNoReturn(gz, result)) { + (void)reachable_node; + SET_ERROR(gz->astgen); + } + return result; +} + static uint32_t tryResolvePrimitiveIdent(GenZir* gz, uint32_t node); // SimpleComptimeReason (std.zig:727) — values used in block_comptime payload. @@ -3378,6 +3392,18 @@ static uint32_t retExpr(GenZir* gz, Scope* scope, uint32_t node) { AstGenCtx* ag = gz->astgen; const Ast* tree = ag->tree; + // AstGen.zig:8123: return outside function is an error. + if (ag->fn_block == NULL) { + SET_ERROR(ag); + return ZIR_REF_UNREACHABLE_VALUE; + } + + // AstGen.zig:8127-8135: cannot return from defer expression. + if (gz->any_defer_node != UINT32_MAX) { + SET_ERROR(ag); + return ZIR_REF_UNREACHABLE_VALUE; + } + // Ensure debug line/column information is emitted for this return // expression (AstGen.zig:8141-8144). if (!gz->is_comptime) { @@ -3386,11 +3412,6 @@ static uint32_t retExpr(GenZir* gz, Scope* scope, uint32_t node) { uint32_t ret_lc_line = ag->source_line - gz->decl_line; uint32_t ret_lc_column = ag->source_column; - // AstGen.zig:8123: return outside function is an error. - if (ag->fn_block == NULL) { - SET_ERROR(ag); - return ZIR_REF_UNREACHABLE_VALUE; - } const Scope* defer_outer = &((GenZir*)ag->fn_block)->base; AstData nd = tree->nodes.datas[node]; @@ -3441,7 +3462,9 @@ static uint32_t retExpr(GenZir* gz, Scope* scope, uint32_t node) { ret_rl.data = ag->fn_ret_ty; } ret_rl.ctx = RI_CTX_RETURN; - uint32_t operand = exprRl(gz, scope, ret_rl, operand_node); + // TODO: nameStratExpr(gz, scope, ret_rl, operand_node, .func) when + // containerDecl supports name_strategy parameter. + uint32_t operand = reachableExpr(gz, scope, ret_rl, operand_node, node); // Emit RESTORE_ERR_RET_INDEX based on nodeMayEvalToError // (AstGen.zig:8188-8253). @@ -7096,6 +7119,7 @@ static void blockExprStmts(GenZir* gz, Scope* scope, : SCOPE_DEFER_ERROR; // Create sub-block for defer body (AstGen.zig:3123-3126). GenZir defer_gen = makeSubBlock(gz, cur_scope); + defer_gen.any_defer_node = stmt; // AstGen.zig:3125 // Evaluate deferred expression (AstGen.zig:3165). // DEFER: lhs is the deferred expression, rhs = 0. @@ -8055,6 +8079,7 @@ static void testDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts, decl_block.is_comptime = true; decl_block.instructions_top = ag->scratch_inst_len; decl_block.break_block = UINT32_MAX; + decl_block.any_defer_node = UINT32_MAX; // Set up fn_block GenZir (AstGen.zig:4837-4845). GenZir fn_block; @@ -8067,6 +8092,7 @@ static void testDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts, fn_block.is_comptime = false; fn_block.instructions_top = ag->scratch_inst_len; fn_block.break_block = UINT32_MAX; + fn_block.any_defer_node = UINT32_MAX; // Set fn_block and fn_ret_ty for the body (AstGen.zig:4849-4853). void* prev_fn_block = ag->fn_block; @@ -8241,6 +8267,7 @@ static void fnDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts, decl_gz.is_comptime = true; decl_gz.instructions_top = ag->scratch_inst_len; decl_gz.break_block = UINT32_MAX; + decl_gz.any_defer_node = UINT32_MAX; // --- Parameter iteration (AstGen.zig:4260-4363) --- // Walk params, creating param instructions and ScopeLocalVal entries. @@ -8405,6 +8432,7 @@ static void fnDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts, body_gz.decl_line = decl_line; body_gz.is_comptime = false; body_gz.instructions_top = ag->scratch_inst_len; + body_gz.any_defer_node = UINT32_MAX; // Set fn_block and fn_ret_ty for the body (AstGen.zig:4442-4455). void* prev_fn_block = ag->fn_block; @@ -8535,6 +8563,7 @@ static void comptimeDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts, value_gz.decl_line = decl_line; value_gz.is_comptime = true; value_gz.instructions_top = ag->scratch_inst_len; + value_gz.any_defer_node = UINT32_MAX; // For comptime {}: body is empty block → no instructions generated. // comptime_gz.isEmpty() == true → addBreak(.break_inline, decl_inst, @@ -8726,6 +8755,7 @@ static void globalVarDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts, type_gz.instructions_top = ag->scratch_inst_len; type_gz.decl_line = ag->source_line; type_gz.is_comptime = true; + type_gz.any_defer_node = UINT32_MAX; if (vd.type_node != 0) { uint32_t type_inst = typeExpr(&type_gz, &type_gz.base, vd.type_node); @@ -8744,6 +8774,7 @@ static void globalVarDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts, align_gz.instructions_top = type_top; align_gz.decl_line = ag->source_line; align_gz.is_comptime = true; + align_gz.any_defer_node = UINT32_MAX; if (vd.align_node != 0) { uint32_t align_inst = expr(&align_gz, &align_gz.base, vd.align_node); @@ -8761,6 +8792,7 @@ static void globalVarDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts, linksection_gz.instructions_top = align_top; linksection_gz.decl_line = ag->source_line; linksection_gz.is_comptime = true; + linksection_gz.any_defer_node = UINT32_MAX; if (vd.section_node != 0) { uint32_t ls_inst @@ -8779,6 +8811,7 @@ static void globalVarDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts, addrspace_gz.instructions_top = linksection_top; addrspace_gz.decl_line = ag->source_line; addrspace_gz.is_comptime = true; + addrspace_gz.any_defer_node = UINT32_MAX; if (vd.addrspace_node != 0) { uint32_t as_inst @@ -8797,6 +8830,7 @@ static void globalVarDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts, value_gz.instructions_top = addrspace_top; value_gz.decl_line = ag->source_line; value_gz.is_comptime = true; + value_gz.any_defer_node = UINT32_MAX; if (vd.init_node != UINT32_MAX && vd.init_node != 0) { uint32_t init_ref = expr(&value_gz, &value_gz.base, vd.init_node); @@ -9425,6 +9459,7 @@ static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node, block_scope.decl_line = ag->source_line; block_scope.is_comptime = true; block_scope.instructions_top = ag->scratch_inst_len; + block_scope.any_defer_node = UINT32_MAX; bool known_non_opv = false; bool known_comptime_only = false; @@ -10873,6 +10908,7 @@ Zir astGen(const Ast* ast) { gen_scope.decl_node_index = 0; // root gen_scope.decl_line = 0; gen_scope.break_block = UINT32_MAX; + gen_scope.any_defer_node = UINT32_MAX; // Get root container members: containerDeclRoot (AstGen.zig:191-195). AstData root_data = ast->nodes.datas[0];