zig

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

commit ddc24a0596578b5be39b4635f86fec7f5a64239f (tree)
parent 09b40057d2d3fce78900e7f8d428556a3aa716cd
Author: Motiejus Jakštys <motiejus@jakstys.lt>
Date:   Sun, 15 Feb 2026 08:25:24 +0000

astgen: port ret have_err path, comptimeDecl body, @Type name strategy, fix union_init field order, @TypeOf break src_node

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Diffstat:
Mstage0/astgen.c | 142+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
Mstage0/astgen_test.zig | 7++++---
2 files changed, 118 insertions(+), 31 deletions(-)

diff --git a/stage0/astgen.c b/stage0/astgen.c @@ -111,9 +111,10 @@ typedef struct { bool fn_var_args; // AstGen.zig:46 } AstGenCtx; -#define SET_ERROR(ag) do { \ - (ag)->has_compile_errors = true; \ -} while(0) +#define SET_ERROR(ag) \ + do { \ + (ag)->has_compile_errors = true; \ + } while (0) // Set fn_block pointer on AstGenCtx. The caller is responsible for saving // and restoring the previous value before the pointed-to GenZir goes out @@ -3823,7 +3824,7 @@ static uint32_t builtinCall( if (!refIsNoReturn(&typeof_scope, ty_expr_ref)) { addBreak(&typeof_scope, ZIR_INST_BREAK_INLINE, typeof_inst, ty_expr_ref, - (int32_t)nd.lhs - (int32_t)gz->decl_node_index); + AST_NODE_OFFSET_NONE); } setBlockBody(ag, &typeof_scope, typeof_inst); // typeof_scope unstacked now, add instruction to gz. @@ -4445,12 +4446,13 @@ static uint32_t builtinCallMultiArg(GenZir* gz, Scope* scope, ResultLoc rl, .tag = RL_TY, .data = field_type, .src_node = 0, .ctx = rl.ctx }; uint32_t init = reachableExpr(gz, scope, init_rl, params[2], node); - // Emit union_init: payload = union_type, init, field_name_ref. + // Emit union_init: payload = union_type, field_name, init + // (Zir.zig:3707-3711). ensureExtraCapacity(ag, 3); uint32_t payload_index = ag->extra_len; ag->extra[ag->extra_len++] = union_type; - ag->extra[ag->extra_len++] = init; ag->extra[ag->extra_len++] = field_name_ref; + ag->extra[ag->extra_len++] = init; uint32_t result = addPlNodePayloadIndex( gz, ZIR_INST_UNION_INIT, node, payload_index); return rvalue(gz, rl, result, node); @@ -5964,8 +5966,10 @@ static uint32_t retExpr(GenZir* gz, Scope* scope, uint32_t node) { ? addUnNode(gz, ZIR_INST_LOAD, ret_ptr_inst, node) : operand; (void)err_code; - // TODO: genDefers with .both = err_code when errdefer is implemented. - genDefers(gz, defer_outer, scope, DEFER_NORMAL_ONLY); + // TODO: genDefers with .both = err_code when remapped_err_code + // is implemented. For now, both_sans_err matches when + // need_err_code is false (AstGen.zig:8203). + genDefers(gz, defer_outer, scope, DEFER_BOTH_SANS_ERR); emitDbgStmt(gz, ret_lc_line, ret_lc_column); if (use_ptr) { addUnNode(gz, ZIR_INST_RET_LOAD, ret_ptr_inst, node); @@ -5995,15 +5999,54 @@ static uint32_t retExpr(GenZir* gz, Scope* scope, uint32_t node) { } return ZIR_REF_UNREACHABLE_VALUE; } - // have_err path: emit conditional branch (not yet implemented). - // Fall through to simplified path. - genDefers(gz, defer_outer, scope, DEFER_NORMAL_ONLY); - emitDbgStmt(gz, ret_lc_line, ret_lc_column); + // have_err path: emit conditional branch for errdefers + // (AstGen.zig:8222-8251). + uint32_t result = use_ptr + ? addUnNode(gz, ZIR_INST_LOAD, ret_ptr_inst, node) + : operand; + uint32_t is_non_err + = addUnNode(gz, ZIR_INST_RET_IS_NON_ERR, result, node); + uint32_t condbr = addCondBr(gz, ZIR_INST_CONDBR, node); + + // Then scope: normal defers only (AstGen.zig:8228-8237). + GenZir then_scope = makeSubBlock(gz, scope); + genDefers(&then_scope, defer_outer, scope, DEFER_NORMAL_ONLY); + // Restore error return index unconditionally + // (AstGen.zig:8234). + { + ZirInstData rdata; + rdata.un_node.operand = ZIR_REF_NONE; + rdata.un_node.src_node + = (int32_t)node - (int32_t)gz->decl_node_index; + addInstruction(&then_scope, + ZIR_INST_RESTORE_ERR_RET_INDEX_UNCONDITIONAL, rdata); + } + emitDbgStmt(&then_scope, ret_lc_line, ret_lc_column); if (use_ptr) { - addUnNode(gz, ZIR_INST_RET_LOAD, ret_ptr_inst, node); + addUnNode(&then_scope, ZIR_INST_RET_LOAD, ret_ptr_inst, node); } else { - addUnNode(gz, ZIR_INST_RET_NODE, operand, node); + addUnNode(&then_scope, ZIR_INST_RET_NODE, operand, node); + } + + // Else scope: both error and normal defers + // (AstGen.zig:8239-8247). + GenZir else_scope = makeSubBlock(gz, scope); + if (!dc.need_err_code) { + genDefers(&else_scope, defer_outer, scope, DEFER_BOTH_SANS_ERR); + } else { + // need_err_code: emit err_union_code + genDefers with + // .both (not yet implemented; need_err_code is always + // false currently). + genDefers(&else_scope, defer_outer, scope, DEFER_BOTH_SANS_ERR); + } + emitDbgStmt(&else_scope, ret_lc_line, ret_lc_column); + if (use_ptr) { + addUnNode(&else_scope, ZIR_INST_RET_LOAD, ret_ptr_inst, node); + } else { + addUnNode(&else_scope, ZIR_INST_RET_NODE, operand, node); } + + setCondBrPayload(ag, condbr, is_non_err, &then_scope, &else_scope); return ZIR_REF_UNREACHABLE_VALUE; } } @@ -7551,15 +7594,15 @@ static uint32_t exprRl(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) { } // anyframe_literal (AstGen.zig:1008-1011). case AST_NODE_ANYFRAME_LITERAL: { - uint32_t result = addUnNode(gz, ZIR_INST_ANYFRAME_TYPE, - ZIR_REF_VOID_TYPE, node); + uint32_t result + = addUnNode(gz, ZIR_INST_ANYFRAME_TYPE, ZIR_REF_VOID_TYPE, node); return rvalue(gz, rl, result, node); } // anyframe_type (AstGen.zig:1012-1016). case AST_NODE_ANYFRAME_TYPE: { uint32_t return_type = typeExpr(gz, scope, nd.rhs); - uint32_t result = addUnNode(gz, ZIR_INST_ANYFRAME_TYPE, - return_type, node); + uint32_t result + = addUnNode(gz, ZIR_INST_ANYFRAME_TYPE, return_type, node); return rvalue(gz, rl, result, node); } // error_set_decl (AstGen.zig:5905-5955). @@ -13634,6 +13677,8 @@ fn_decl_finish: static void comptimeDecl(AstGenCtx* ag, GenZir* gz, Scope* scope, uint32_t* wip_decl_insts, uint32_t* decl_idx, uint32_t node) { + const Ast* tree = ag->tree; + // makeDeclaration before advanceSourceCursorToNode (AstGen.zig:4663-4665). uint32_t decl_inst = makeDeclaration(ag, node); wip_decl_insts[*decl_idx] = decl_inst; @@ -13644,7 +13689,10 @@ static void comptimeDecl(AstGenCtx* ag, GenZir* gz, Scope* scope, uint32_t decl_line = ag->source_line; uint32_t decl_column = ag->source_column; - // Value sub-block (AstGen.zig:4675-4686). + // body_node (AstGen.zig:4653). + uint32_t body_node = tree->nodes.datas[node].lhs; + + // Value sub-block (AstGen.zig:4671-4686). GenZir value_gz; memset(&value_gz, 0, sizeof(value_gz)); value_gz.base.tag = SCOPE_GEN_ZIR; @@ -13656,11 +13704,16 @@ static void comptimeDecl(AstGenCtx* ag, GenZir* gz, Scope* scope, 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, - // .void_value) (AstGen.zig:4685-4686) - makeBreakInline( - &value_gz, decl_inst, ZIR_REF_VOID_VALUE, AST_NODE_OFFSET_NONE); + // Evaluate the body expression (AstGen.zig:4684). + uint32_t block_result + = fullBodyExpr(&value_gz, &value_gz.base, RL_NONE_VAL, body_node); + // Add break_inline if body is empty or not noreturn + // (AstGen.zig:4685-4686). + if (gzInstructionsLen(&value_gz) == 0 + || !refIsNoReturn(&value_gz, block_result)) { + makeBreakInline( + &value_gz, decl_inst, ZIR_REF_VOID_VALUE, AST_NODE_OFFSET_NONE); + } setDeclaration(ag, decl_inst, (SetDeclArgs) { .src_line = decl_line, @@ -13829,10 +13882,9 @@ static DeclFlagsId computeVarDeclId(bool is_mutable, bool is_pub, // *out_ref), false if caller should fall back to expr(). static bool nameStratExpr(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node, uint8_t name_strategy, uint32_t* out_ref) { - const AstGenCtx* ag = gz->astgen; + AstGenCtx* ag = gz->astgen; const Ast* tree = ag->tree; AstNodeTag tag = tree->nodes.tags[node]; - (void)rl; // Used by builtinReify (not yet implemented). switch (tag) { case AST_NODE_CONTAINER_DECL: @@ -13849,8 +13901,42 @@ static bool nameStratExpr(GenZir* gz, Scope* scope, ResultLoc rl, case AST_NODE_TAGGED_UNION_ENUM_TAG_TRAILING: *out_ref = containerDecl(gz, scope, node, name_strategy); return true; - // @Type builtin: upstream calls builtinReify (AstGen.zig:1186-1196). - // Not yet implemented; fall through to expr(). + // @Type builtin: builtinReify (AstGen.zig:1186-1196). + case AST_NODE_BUILTIN_CALL_TWO: + case AST_NODE_BUILTIN_CALL_TWO_COMMA: { + uint32_t builtin_token = tree->nodes.main_tokens[node]; + uint32_t tok_start = tree->tokens.starts[builtin_token]; + const char* source = tree->source; + uint32_t ns = tok_start + 1; // skip '@' + if (ns + 4 <= tree->source_len && memcmp(source + ns, "Type", 4) == 0 + && (ns + 4 >= tree->source_len + || !((source[ns + 4] >= 'a' && source[ns + 4] <= 'z') + || (source[ns + 4] >= 'A' && source[ns + 4] <= 'Z') + || source[ns + 4] == '_'))) { + // builtinReify with the given name_strategy + // (AstGen.zig:9747-9781). + AstData nd = tree->nodes.datas[node]; + uint32_t arg_node = nd.lhs; + uint32_t type_info_ty + = addBuiltinValue(gz, node, ZIR_BUILTIN_VALUE_TYPE_INFO); + ResultLoc operand_rl = { .tag = RL_COERCED_TY, + .data = type_info_ty, + .src_node = 0, + .ctx = RI_CTX_NONE }; + uint32_t operand = exprRl(gz, scope, operand_rl, arg_node); + ensureExtraCapacity(ag, 3); + uint32_t payload_index = ag->extra_len; + ag->extra[ag->extra_len++] = node; // absolute node index + ag->extra[ag->extra_len++] = operand; + ag->extra[ag->extra_len++] = ag->source_line; + uint32_t result + = addExtendedPayloadSmall(gz, (uint16_t)ZIR_EXT_REIFY, + (uint16_t)name_strategy, payload_index); + *out_ref = rvalue(gz, rl, result, node); + return true; + } + return false; + } default: return false; } diff --git a/stage0/astgen_test.zig b/stage0/astgen_test.zig @@ -52,8 +52,10 @@ fn buildHashSkipMask(gpa: Allocator, ref: Zir) ![]bool { switch (ref_tags[i]) { .extended => { const ext = ref_datas[i].extended; - if (ext.opcode == .struct_decl or ext.opcode == .enum_decl) { - // StructDecl/EnumDecl starts with fields_hash[4]. + if (ext.opcode == .struct_decl or ext.opcode == .enum_decl or + ext.opcode == .union_decl or ext.opcode == .opaque_decl) + { + // StructDecl/EnumDecl/UnionDecl/OpaqueDecl starts with fields_hash[4]. const pi = ext.operand; for (0..4) |j| skip[pi + j] = true; } @@ -953,7 +955,6 @@ test "astgen: corpus array_list.zig" { } test "astgen: corpus multi_array_list.zig" { - if (true) return error.SkipZigTest; // TODO: remaining diffs: bool_not, bool_br_and, ret_is_non_err, plus small instruction count differences const gpa = std.testing.allocator; try corpusCheck(gpa, @embedFile("../lib/std/multi_array_list.zig")); }