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:
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") },