zig

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

commit da9534f39a6b46db34c36c6caa6ba9e5a6c08041 (tree)
parent 82f597bfe178b5b2ca1025d10a107aefeb0be018
Author: Motiejus Jakštys <motiejus@jakstys.lt>
Date:   Sun, 15 Feb 2026 17:35:39 +0000

astgen: fix OptionalIndex handling, enable addrspace_and_linksection.zig corpus test

Fix segfaults caused by reading AST OptionalIndex fields (none=UINT32_MAX)
without converting to the C convention (none=0):

- extractVarDecl: convert GlobalVarDecl extra_data OptionalIndex fields
  (type_node, align_node, addrspace_node, section_node) from UINT32_MAX
  to 0 when none. Also handle simple_var_decl's opt_node_and_opt_node.

- fnDecl: extract align_expr, addrspace_expr, section_expr from
  FnProtoOne/FnProto extra_data with proper OptionalIndex conversion.
  Also fix FN_PROTO_SIMPLE param check to use UINT32_MAX.

- fnDecl: add separate type_gz, align_gz, linksection_gz, addrspace_gz
  sub-blocks matching upstream AstGen.zig:4149-4192, and pass their
  bodies to setDeclaration. Update decl_id selection to account for
  has_type_body and has_special_body.

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

Diffstat:
Mstage0/astgen.c | 262++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Mstage0/astgen_test.zig | 2+-
2 files changed, 228 insertions(+), 36 deletions(-)

diff --git a/stage0/astgen.c b/stage0/astgen.c @@ -13545,49 +13545,173 @@ static void fnDecl(AstGenCtx* ag, GenZir* gz, Scope* scope, const uint32_t* param_nodes = NULL; uint32_t params_len = 0; uint32_t callconv_expr_node = 0; // 0 = none (OptionalIndex) + uint32_t align_expr_node = 0; // 0 = none (OptionalIndex) + uint32_t addrspace_expr_node = 0; // 0 = none (OptionalIndex) + uint32_t section_expr_node = 0; // 0 = none (OptionalIndex) if (proto_tag == AST_NODE_FN_PROTO_SIMPLE) { - // data.lhs = optional param node, data.rhs = return type. - // callconv_expr = .none (Ast.zig:1468). - if (proto_data.lhs != 0) { + // data = opt_node_and_opt_node: lhs = param (OptionalIndex), + // rhs = return type (OptionalIndex). + // align/addrspace/section/callconv = .none (Ast.zig:1458-1468). + if (proto_data.lhs != UINT32_MAX) { param_nodes_buf[0] = proto_data.lhs; param_nodes = param_nodes_buf; params_len = 1; } } else if (proto_tag == AST_NODE_FN_PROTO_ONE) { - // data.lhs = extra_data index → AstFnProtoOne. + // data = extra_and_opt_node: lhs = extra_data index → FnProtoOne. + // FnProtoOne layout (Ast.zig:4066-4077): + // [0] param (OptionalIndex) + // [1] align_expr (OptionalIndex) + // [2] addrspace_expr (OptionalIndex) + // [3] section_expr (OptionalIndex) + // [4] callconv_expr (OptionalIndex) uint32_t extra_idx = proto_data.lhs; - uint32_t param - = tree->extra_data.arr[extra_idx]; // AstFnProtoOne.param - if (param != 0) { + uint32_t param = tree->extra_data.arr[extra_idx]; + if (param != UINT32_MAX) { param_nodes_buf[0] = param; param_nodes = param_nodes_buf; params_len = 1; } - // AstFnProtoOne.callconv_expr at offset 4 (Ast.zig:4076). - callconv_expr_node = tree->extra_data.arr[extra_idx + 4]; + uint32_t raw; + raw = tree->extra_data.arr[extra_idx + 1]; + if (raw != UINT32_MAX) + align_expr_node = raw; + raw = tree->extra_data.arr[extra_idx + 2]; + if (raw != UINT32_MAX) + addrspace_expr_node = raw; + raw = tree->extra_data.arr[extra_idx + 3]; + if (raw != UINT32_MAX) + section_expr_node = raw; + raw = tree->extra_data.arr[extra_idx + 4]; + if (raw != UINT32_MAX) + callconv_expr_node = raw; } else if (proto_tag == AST_NODE_FN_PROTO_MULTI) { - // data.lhs = extra_data index → SubRange{start, end}. - // callconv_expr = .none (Ast.zig:1484). + // data = extra_and_opt_node: lhs = extra_data index → SubRange. + // align/addrspace/section/callconv = .none (Ast.zig:1484). uint32_t extra_idx = proto_data.lhs; uint32_t range_start = tree->extra_data.arr[extra_idx]; uint32_t range_end = tree->extra_data.arr[extra_idx + 1]; param_nodes = tree->extra_data.arr + range_start; params_len = range_end - range_start; } else if (proto_tag == AST_NODE_FN_PROTO) { - // data.lhs = extra_data index → AstFnProto{params_start, params_end, - // ...}. + // data = extra_and_opt_node: lhs = extra_data index → FnProto. + // FnProto layout (Ast.zig:4079-4090): + // [0] params_start (ExtraIndex) + // [1] params_end (ExtraIndex) + // [2] align_expr (OptionalIndex) + // [3] addrspace_expr (OptionalIndex) + // [4] section_expr (OptionalIndex) + // [5] callconv_expr (OptionalIndex) uint32_t extra_idx = proto_data.lhs; - uint32_t pstart = tree->extra_data.arr[extra_idx]; // params_start - uint32_t pend = tree->extra_data.arr[extra_idx + 1]; // params_end + uint32_t pstart = tree->extra_data.arr[extra_idx]; + uint32_t pend = tree->extra_data.arr[extra_idx + 1]; param_nodes = tree->extra_data.arr + pstart; params_len = pend - pstart; - // AstFnProto.callconv_expr at offset 5 (Ast.zig:4089). - callconv_expr_node = tree->extra_data.arr[extra_idx + 5]; + uint32_t raw; + raw = tree->extra_data.arr[extra_idx + 2]; + if (raw != UINT32_MAX) + align_expr_node = raw; + raw = tree->extra_data.arr[extra_idx + 3]; + if (raw != UINT32_MAX) + addrspace_expr_node = raw; + raw = tree->extra_data.arr[extra_idx + 4]; + if (raw != UINT32_MAX) + section_expr_node = raw; + raw = tree->extra_data.arr[extra_idx + 5]; + if (raw != UINT32_MAX) + callconv_expr_node = raw; + } + + // type_gz sub-block (AstGen.zig:4149-4163). For extern: fn type. + GenZir type_gz; + memset(&type_gz, 0, sizeof(type_gz)); + type_gz.base.tag = SCOPE_GEN_ZIR; + type_gz.parent = scope; + type_gz.astgen = ag; + type_gz.decl_node_index = proto_node; + type_gz.decl_line = decl_line; + type_gz.is_comptime = true; + type_gz.instructions_top = ag->scratch_inst_len; + type_gz.any_defer_node = UINT32_MAX; + // type_gz body is filled later (extern only). Record top after. + uint32_t type_top = ag->scratch_inst_len; + + // align_gz sub-block (AstGen.zig:4166-4173). + GenZir align_gz; + memset(&align_gz, 0, sizeof(align_gz)); + align_gz.base.tag = SCOPE_GEN_ZIR; + align_gz.parent = scope; + align_gz.astgen = ag; + align_gz.decl_node_index = proto_node; + align_gz.decl_line = decl_line; + align_gz.is_comptime = true; + align_gz.instructions_top = type_top; + align_gz.any_defer_node = UINT32_MAX; + + if (align_expr_node != 0) { + ResultLoc align_rl = { .tag = RL_COERCED_TY, + .data = ZIR_REF_U29_TYPE, + .src_node = 0, + .ctx = RI_CTX_NONE }; + uint32_t align_inst + = exprRl(&align_gz, &align_gz.base, align_rl, align_expr_node); + makeBreakInline(&align_gz, decl_inst, align_inst, + (int32_t)node - (int32_t)proto_node); + } + uint32_t align_top = ag->scratch_inst_len; + + // linksection_gz sub-block (AstGen.zig:4175-4182). + GenZir linksection_gz; + memset(&linksection_gz, 0, sizeof(linksection_gz)); + linksection_gz.base.tag = SCOPE_GEN_ZIR; + linksection_gz.parent = scope; + linksection_gz.astgen = ag; + linksection_gz.decl_node_index = proto_node; + linksection_gz.decl_line = decl_line; + linksection_gz.is_comptime = true; + linksection_gz.instructions_top = align_top; + linksection_gz.any_defer_node = UINT32_MAX; + + if (section_expr_node != 0) { + ResultLoc ls_rl = { .tag = RL_COERCED_TY, + .data = ZIR_REF_SLICE_CONST_U8_TYPE, + .src_node = 0, + .ctx = RI_CTX_NONE }; + uint32_t ls_inst = exprRl( + &linksection_gz, &linksection_gz.base, ls_rl, section_expr_node); + makeBreakInline(&linksection_gz, decl_inst, ls_inst, + (int32_t)node - (int32_t)proto_node); + } + uint32_t linksection_top = ag->scratch_inst_len; + + // addrspace_gz sub-block (AstGen.zig:4184-4192). + GenZir addrspace_gz; + memset(&addrspace_gz, 0, sizeof(addrspace_gz)); + addrspace_gz.base.tag = SCOPE_GEN_ZIR; + addrspace_gz.parent = scope; + addrspace_gz.astgen = ag; + addrspace_gz.decl_node_index = proto_node; + addrspace_gz.decl_line = decl_line; + addrspace_gz.is_comptime = true; + addrspace_gz.instructions_top = linksection_top; + addrspace_gz.any_defer_node = UINT32_MAX; + + if (addrspace_expr_node != 0) { + uint32_t addrspace_ty = addBuiltinValue(&addrspace_gz, + addrspace_expr_node, ZIR_BUILTIN_VALUE_ADDRESS_SPACE); + ResultLoc as_rl = { .tag = RL_COERCED_TY, + .data = addrspace_ty, + .src_node = 0, + .ctx = RI_CTX_NONE }; + uint32_t as_inst = exprRl( + &addrspace_gz, &addrspace_gz.base, as_rl, addrspace_expr_node); + makeBreakInline(&addrspace_gz, decl_inst, as_inst, + (int32_t)node - (int32_t)proto_node); } + uint32_t addrspace_top = ag->scratch_inst_len; - // decl_gz (called value_gz in caller, decl_gz in fnDeclInner) - // (AstGen.zig:4194-4201). + // decl_gz = value_gz sub-block (AstGen.zig:4194-4201). GenZir decl_gz; memset(&decl_gz, 0, sizeof(decl_gz)); decl_gz.base.tag = SCOPE_GEN_ZIR; @@ -13596,7 +13720,7 @@ static void fnDecl(AstGenCtx* ag, GenZir* gz, Scope* scope, decl_gz.decl_node_index = proto_node; decl_gz.decl_line = decl_line; decl_gz.is_comptime = true; - decl_gz.instructions_top = ag->scratch_inst_len; + decl_gz.instructions_top = addrspace_top; decl_gz.break_block = UINT32_MAX; decl_gz.any_defer_node = UINT32_MAX; @@ -14055,15 +14179,54 @@ static void fnDecl(AstGenCtx* ag, GenZir* gz, Scope* scope, fn_decl_finish: // setDeclaration (AstGen.zig:4208-4225). - // Linkage: extern > export > normal (AstGen.zig:4217). ; + // Compute sub-block body slices. + const uint32_t* type_body + = ag->scratch_instructions + type_gz.instructions_top; + uint32_t type_body_len = type_top - type_gz.instructions_top; + const uint32_t* align_body + = ag->scratch_instructions + align_gz.instructions_top; + uint32_t align_body_len = align_top - align_gz.instructions_top; + const uint32_t* ls_body + = ag->scratch_instructions + linksection_gz.instructions_top; + uint32_t ls_body_len = linksection_top - linksection_gz.instructions_top; + const uint32_t* as_body + = ag->scratch_instructions + addrspace_gz.instructions_top; + uint32_t as_body_len = addrspace_top - addrspace_gz.instructions_top; + + bool has_type_body = (type_body_len > 0); + bool has_special_body + = (align_body_len > 0 || ls_body_len > 0 || as_body_len > 0); + + // Linkage: extern > export > normal (AstGen.zig:4217). DeclFlagsId decl_id; - if (is_extern) - decl_id = is_pub ? DECL_ID_PUB_EXTERN_CONST : DECL_ID_EXTERN_CONST; - else if (is_export) + if (is_extern) { + if (is_pub) { + decl_id = (has_special_body) ? DECL_ID_PUB_EXTERN_CONST + : DECL_ID_PUB_EXTERN_CONST_SIMPLE; + } else { + decl_id = (has_special_body) ? DECL_ID_EXTERN_CONST + : DECL_ID_EXTERN_CONST_SIMPLE; + } + } else if (is_export) { decl_id = is_pub ? DECL_ID_PUB_EXPORT_CONST : DECL_ID_EXPORT_CONST; - else - decl_id = is_pub ? DECL_ID_PUB_CONST_SIMPLE : DECL_ID_CONST_SIMPLE; + } else { + if (is_pub) { + if (has_special_body) + decl_id = DECL_ID_PUB_CONST; + else if (has_type_body) + decl_id = DECL_ID_PUB_CONST_TYPED; + else + decl_id = DECL_ID_PUB_CONST_SIMPLE; + } else { + if (has_special_body) + decl_id = DECL_ID_CONST; + else if (has_type_body) + decl_id = DECL_ID_CONST_TYPED; + else + decl_id = DECL_ID_CONST_SIMPLE; + } + } uint32_t name_str = identAsString(ag, fn_name_token); setDeclaration(ag, decl_inst, (SetDeclArgs) { .src_line = decl_line, @@ -14071,9 +14234,21 @@ fn_decl_finish: .id = decl_id, .name = name_str, .lib_name = UINT32_MAX, + .type_body = type_body, + .type_body_len = type_body_len, + .align_body = align_body, + .align_body_len = align_body_len, + .linksection_body = ls_body, + .linksection_body_len = ls_body_len, + .addrspace_body = as_body, + .addrspace_body_len = as_body_len, .value_body = gzInstructionsSlice(&decl_gz), .value_body_len = gzInstructionsLen(&decl_gz) }); gzUnstack(&decl_gz); + gzUnstack(&addrspace_gz); + gzUnstack(&linksection_gz); + gzUnstack(&align_gz); + gzUnstack(&type_gz); (void)gz; } @@ -14163,27 +14338,44 @@ static VarDeclInfo extractVarDecl(const Ast* tree, uint32_t node) { switch (tag) { case AST_NODE_SIMPLE_VAR_DECL: - // lhs = type_node (optional), rhs = init_node (optional) - info.type_node = nd.lhs; + // opt_node_and_opt_node: lhs = type_node (OptionalIndex), + // rhs = init_node (OptionalIndex). Convert UINT32_MAX -> 0 for + // type_node to match C "0 = none" convention. + if (nd.lhs != UINT32_MAX) + info.type_node = nd.lhs; info.init_node = nd.rhs; break; case AST_NODE_ALIGNED_VAR_DECL: - // lhs = align_node, rhs = init_node (optional) + // node_and_opt_node: lhs = align_node (always present), + // rhs = init_node (OptionalIndex). info.align_node = nd.lhs; info.init_node = nd.rhs; break; case AST_NODE_GLOBAL_VAR_DECL: { - // lhs = extra_data index, rhs = init_node (optional) + // extra_and_opt_node: lhs = extra_data index, + // rhs = init_node (OptionalIndex). + // Extra data: GlobalVarDecl with OptionalIndex fields. + // Convert UINT32_MAX -> 0 for C "0 = none" convention. uint32_t ei = nd.lhs; - info.type_node = tree->extra_data.arr[ei + 0]; - info.align_node = tree->extra_data.arr[ei + 1]; - info.addrspace_node = tree->extra_data.arr[ei + 2]; - info.section_node = tree->extra_data.arr[ei + 3]; + uint32_t raw_type = tree->extra_data.arr[ei + 0]; + uint32_t raw_align = tree->extra_data.arr[ei + 1]; + uint32_t raw_addrspace = tree->extra_data.arr[ei + 2]; + uint32_t raw_section = tree->extra_data.arr[ei + 3]; + if (raw_type != UINT32_MAX) + info.type_node = raw_type; + if (raw_align != UINT32_MAX) + info.align_node = raw_align; + if (raw_addrspace != UINT32_MAX) + info.addrspace_node = raw_addrspace; + if (raw_section != UINT32_MAX) + info.section_node = raw_section; info.init_node = nd.rhs; break; } case AST_NODE_LOCAL_VAR_DECL: { - // lhs = extra_data index, rhs = init_node (optional) + // extra_and_opt_node: lhs = extra_data index, + // rhs = init_node (OptionalIndex). + // Extra data: LocalVarDecl with plain Index fields (always present). uint32_t ei = nd.lhs; info.type_node = tree->extra_data.arr[ei + 0]; info.align_node = tree->extra_data.arr[ei + 1]; diff --git a/stage0/astgen_test.zig b/stage0/astgen_test.zig @@ -1213,7 +1213,7 @@ const corpus_files = .{ .{ "vector.zig", @embedFile("../test/behavior/vector.zig") }, .{ "cast.zig", @embedFile("../test/behavior/cast.zig") }, .{ "abs.zig", @embedFile("../test/behavior/abs.zig") }, - //.{ "addrspace_and_linksection.zig", @embedFile("../test/behavior/addrspace_and_linksection.zig") }, + .{ "addrspace_and_linksection.zig", @embedFile("../test/behavior/addrspace_and_linksection.zig") }, //.{ "align.zig", @embedFile("../test/behavior/align.zig") }, //.{ "alignof.zig", @embedFile("../test/behavior/alignof.zig") }, //.{ "asm.zig", @embedFile("../test/behavior/asm.zig") },