commit 170c983328b2cb64be686c5d9a0d61b0fdc16536 (tree)
parent c47d5425748989a6d45dcb77e7ee853e8b3aad1d
Author: Motiejus Jakštys <motiejus@jakstys.lt>
Date: Sat, 14 Feb 2026 16:59:34 +0000
astgen: add builtins, fn_proto exprs, extern fn, scope threading
Port multiple features from AstGen.zig:
- fnProtoExpr/fnProtoExprInner: function types as expressions
- arrayTypeSentinelExpr: [N:sentinel]T array types
- Extern fn_decl without body (implicit CCC)
- 12 builtins: ptrFromInt, Vector, setRuntimeSafety, intFromError,
clz, branchHint, bitSizeOf, fieldParentPtr, splat, offsetOf,
inComptime, errorFromInt, errorCast alias
- Fix namespace scope parent: use caller's scope instead of gz->base,
allowing inner structs to reference outer locals (fixes S2, name, U)
- Fix addFunc/addFuncFancy: don't emit src_locs when body is empty
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat:
2 files changed, 706 insertions(+), 84 deletions(-)
diff --git a/stage0/astgen.c b/stage0/astgen.c
@@ -111,8 +111,7 @@ typedef struct {
bool fn_var_args; // AstGen.zig:46
} AstGenCtx;
-static void setCompileError(AstGenCtx* ag) { ag->has_compile_errors = true; }
-#define SET_ERROR(ag) setCompileError(ag)
+#define SET_ERROR(ag) ((ag)->has_compile_errors = true)
// Set fn_block pointer on AstGenCtx. The caller is responsible for saving
// and restoring the previous value before the pointed-to GenZir goes out
@@ -2610,15 +2609,15 @@ static bool nameStratExpr(GenZir* gz, Scope* scope, ResultLoc rl,
static bool tokenIsUnderscore(const Ast* tree, uint32_t ident_token);
static uint32_t containerDecl(
GenZir* gz, Scope* scope, uint32_t node, uint8_t name_strategy);
-static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
- const uint32_t* members, uint32_t members_len, uint8_t layout,
- uint32_t backing_int_node, uint8_t name_strategy);
-static uint32_t tupleDecl(AstGenCtx* ag, GenZir* gz, uint32_t node,
- const uint32_t* members, uint32_t members_len, uint8_t layout,
- uint32_t backing_int_node);
-static uint32_t enumDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
- const uint32_t* members, uint32_t members_len, uint32_t arg_node,
- uint8_t name_strategy);
+static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, Scope* scope,
+ uint32_t node, const uint32_t* members, uint32_t members_len,
+ uint8_t layout, uint32_t backing_int_node, uint8_t name_strategy);
+static uint32_t tupleDecl(AstGenCtx* ag, GenZir* gz, Scope* scope,
+ uint32_t node, const uint32_t* members, uint32_t members_len,
+ uint8_t layout, uint32_t backing_int_node);
+static uint32_t enumDeclInner(AstGenCtx* ag, GenZir* gz, Scope* scope,
+ uint32_t node, const uint32_t* members, uint32_t members_len,
+ uint32_t arg_node, uint8_t name_strategy);
static uint32_t blockExprExpr(
GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node);
static uint32_t ifExpr(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node);
@@ -2650,6 +2649,24 @@ static uint32_t identAsString(AstGenCtx* ag, uint32_t token);
static uint32_t lastToken(const Ast* tree, uint32_t node);
static uint32_t simpleBinOp(
GenZir* gz, Scope* scope, uint32_t node, ZirInstTag tag);
+static uint32_t addParam(GenZir* gz, GenZir* param_gz, ZirInstTag tag,
+ uint32_t abs_tok_index, uint32_t name, bool is_generic);
+static uint32_t addFunc(GenZir* gz, uint32_t src_node, uint32_t block_node,
+ uint32_t param_block, uint32_t ret_ref, const uint32_t* ret_body,
+ uint32_t ret_body_len, const uint32_t* body, uint32_t body_len,
+ const uint32_t* param_insts, uint32_t param_insts_len,
+ uint32_t lbrace_line, uint32_t lbrace_column, bool is_inferred_error,
+ bool ret_ty_is_generic, const uint32_t* ret_param_refs,
+ uint32_t ret_param_refs_len);
+static uint32_t addFuncFancy(GenZir* gz, uint32_t src_node,
+ uint32_t block_node, uint32_t param_block, uint32_t ret_ref,
+ const uint32_t* ret_body, uint32_t ret_body_len, uint32_t cc_ref,
+ const uint32_t* cc_body, uint32_t cc_body_len, const uint32_t* body,
+ uint32_t body_len, const uint32_t* param_insts, uint32_t param_insts_len,
+ uint32_t lbrace_line, uint32_t lbrace_column, bool is_var_args,
+ bool is_inferred_error, bool is_noinline, uint32_t noalias_bits,
+ bool ret_ty_is_generic, const uint32_t* ret_param_refs,
+ uint32_t ret_param_refs_len);
// Mirrors GenZir.endsWithNoReturn (AstGen.zig:11770).
static bool endsWithNoReturn(GenZir* gz) {
@@ -2759,7 +2776,11 @@ static uint32_t tryResolvePrimitiveIdent(GenZir* gz, uint32_t node);
#define COMPTIME_REASON_ALIGN 50
#define COMPTIME_REASON_ADDRSPACE 51
#define COMPTIME_REASON_FIELD_NAME 42
+#define COMPTIME_REASON_OPERAND_BRANCH_HINT 3
+#define COMPTIME_REASON_OPERAND_SET_RUNTIME_SAFETY 4
+#define COMPTIME_REASON_FUNCTION_RET_TY 39
#define COMPTIME_REASON_COMPTIME_KEYWORD 53
+#define COMPTIME_REASON_CALLCONV 49
#define COMPTIME_REASON_ARRAY_MUL_FACTOR 22
#define COMPTIME_REASON_COMPILE_ERROR_STRING 19
#define COMPTIME_REASON_SWITCH_ITEM 56
@@ -3577,9 +3598,11 @@ static uint32_t builtinCall(
return rvalue(gz, rl, addPlNodeBin(gz, ZIR_INST_FLOAT_CAST,
node, result_type, operand), node);
}
- // @errSetCast — extended error_cast (AstGen.zig:9454-9463).
- if (name_len == 10
- && memcmp(source + name_start, "errSetCast", 10) == 0) {
+ // @errSetCast / @errorCast — extended error_cast (AstGen.zig:9454-9463).
+ if ((name_len == 10
+ && memcmp(source + name_start, "errSetCast", 10) == 0)
+ || (name_len == 9
+ && memcmp(source + name_start, "errorCast", 9) == 0)) {
emitDbgNode(gz, node);
uint32_t result_type = rlResultTypeForCast(gz, rl, node);
AstData nd = tree->nodes.datas[node];
@@ -3594,6 +3617,177 @@ static uint32_t builtinCall(
gz, (uint16_t)ZIR_EXT_ERROR_CAST, payload_index);
return rvalue(gz, rl, result, node);
}
+ // @ptrFromInt — typeCast (AstGen.zig:9413).
+ if (name_len == 10
+ && memcmp(source + name_start, "ptrFromInt", 10) == 0) {
+ advanceSourceCursorToMainToken(ag, gz, node);
+ uint32_t saved_line = ag->source_line - gz->decl_line;
+ uint32_t saved_col = ag->source_column;
+ uint32_t result_type = rlResultTypeForCast(gz, rl, node);
+ AstData nd = tree->nodes.datas[node];
+ uint32_t operand = expr(gz, scope, nd.lhs);
+ emitDbgStmt(gz, saved_line, saved_col);
+ return rvalue(gz, rl, addPlNodeBin(gz, ZIR_INST_PTR_FROM_INT,
+ node, result_type, operand), node);
+ }
+ // @Vector — type construction (AstGen.zig:9675).
+ if (name_len == 6 && memcmp(source + name_start, "Vector", 6) == 0) {
+ AstData nd = tree->nodes.datas[node];
+ ResultLoc u32_rl = { .tag = RL_COERCED_TY,
+ .data = ZIR_REF_U32_TYPE,
+ .src_node = 0,
+ .ctx = RI_CTX_NONE };
+ uint32_t len = comptimeExpr(
+ gz, scope, u32_rl, nd.lhs, COMPTIME_REASON_TYPE);
+ uint32_t elem_type = typeExpr(gz, scope, nd.rhs);
+ uint32_t result = addPlNodeBin(
+ gz, ZIR_INST_VECTOR_TYPE, node, len, elem_type);
+ return rvalue(gz, rl, result, node);
+ }
+ // @setRuntimeSafety — simpleUnOp (AstGen.zig:9392).
+ if (name_len == 16
+ && memcmp(source + name_start, "setRuntimeSafety", 16) == 0) {
+ AstData nd = tree->nodes.datas[node];
+ ResultLoc bool_rl = { .tag = RL_COERCED_TY,
+ .data = ZIR_REF_BOOL_TYPE,
+ .src_node = 0,
+ .ctx = RI_CTX_NONE };
+ uint32_t operand = comptimeExpr(
+ gz, scope, bool_rl, nd.lhs,
+ COMPTIME_REASON_OPERAND_SET_RUNTIME_SAFETY);
+ addUnNode(gz, ZIR_INST_SET_RUNTIME_SAFETY, operand, node);
+ return rvalue(gz, rl, ZIR_REF_VOID_VALUE, node);
+ }
+ // @intFromError — extended UnNode (AstGen.zig:9438-9444).
+ if (name_len == 12
+ && memcmp(source + name_start, "intFromError", 12) == 0) {
+ AstData nd = tree->nodes.datas[node];
+ uint32_t operand = expr(gz, scope, nd.lhs);
+ ensureExtraCapacity(ag, 2);
+ uint32_t payload_index = ag->extra_len;
+ ag->extra[ag->extra_len++]
+ = (uint32_t)((int32_t)node - (int32_t)gz->decl_node_index);
+ ag->extra[ag->extra_len++] = operand;
+ uint32_t result = addExtendedPayload(
+ gz, (uint16_t)ZIR_EXT_INT_FROM_ERROR, payload_index);
+ return rvalue(gz, rl, result, node);
+ }
+ // @clz — bitBuiltin (AstGen.zig:9475).
+ if (name_len == 3 && memcmp(source + name_start, "clz", 3) == 0) {
+ advanceSourceCursorToMainToken(ag, gz, node);
+ uint32_t saved_line = ag->source_line - gz->decl_line;
+ uint32_t saved_col = ag->source_column;
+ AstData nd = tree->nodes.datas[node];
+ uint32_t operand = expr(gz, scope, nd.lhs);
+ emitDbgStmt(gz, saved_line, saved_col);
+ uint32_t result = addUnNode(gz, ZIR_INST_CLZ, operand, node);
+ return rvalue(gz, rl, result, node);
+ }
+ // @branchHint — extended UnNode (AstGen.zig:9230-9239).
+ if (name_len == 10
+ && memcmp(source + name_start, "branchHint", 10) == 0) {
+ AstData nd = tree->nodes.datas[node];
+ uint32_t hint_ty
+ = addBuiltinValue(gz, node, ZIR_BUILTIN_VALUE_BRANCH_HINT);
+ ResultLoc hint_rl = { .tag = RL_COERCED_TY,
+ .data = hint_ty, .src_node = 0, .ctx = RI_CTX_NONE };
+ uint32_t hint_val = comptimeExpr(
+ gz, scope, hint_rl, nd.lhs,
+ COMPTIME_REASON_OPERAND_BRANCH_HINT);
+ ensureExtraCapacity(ag, 2);
+ uint32_t payload_index = ag->extra_len;
+ ag->extra[ag->extra_len++]
+ = (uint32_t)((int32_t)node - (int32_t)gz->decl_node_index);
+ ag->extra[ag->extra_len++] = hint_val;
+ addExtendedPayload(
+ gz, (uint16_t)ZIR_EXT_BRANCH_HINT, payload_index);
+ return rvalue(gz, rl, ZIR_REF_VOID_VALUE, node);
+ }
+ // @bitSizeOf — simpleUnOpType (AstGen.zig:9382).
+ if (name_len == 9
+ && memcmp(source + name_start, "bitSizeOf", 9) == 0) {
+ AstData nd = tree->nodes.datas[node];
+ uint32_t operand = typeExpr(gz, scope, nd.lhs);
+ uint32_t result
+ = addUnNode(gz, ZIR_INST_BIT_SIZE_OF, operand, node);
+ return rvalue(gz, rl, result, node);
+ }
+ // @fieldParentPtr — extended FieldParentPtr (AstGen.zig:9620-9628).
+ if (name_len == 14
+ && memcmp(source + name_start, "fieldParentPtr", 14) == 0) {
+ AstData nd = tree->nodes.datas[node];
+ uint32_t parent_ptr_type = rlResultTypeForCast(gz, rl, node);
+ ResultLoc field_name_rl = { .tag = RL_COERCED_TY,
+ .data = ZIR_REF_SLICE_CONST_U8_TYPE,
+ .src_node = 0, .ctx = RI_CTX_NONE };
+ uint32_t field_name = comptimeExpr(
+ gz, scope, field_name_rl, nd.lhs, COMPTIME_REASON_FIELD_NAME);
+ uint32_t field_ptr = expr(gz, scope, nd.rhs);
+ ensureExtraCapacity(ag, 4);
+ uint32_t payload_index = ag->extra_len;
+ ag->extra[ag->extra_len++]
+ = (uint32_t)((int32_t)node - (int32_t)gz->decl_node_index);
+ ag->extra[ag->extra_len++] = parent_ptr_type;
+ ag->extra[ag->extra_len++] = field_name;
+ ag->extra[ag->extra_len++] = field_ptr;
+ uint32_t result = addExtendedPayloadSmall(
+ gz, (uint16_t)ZIR_EXT_FIELD_PARENT_PTR, 0, payload_index);
+ return rvalue(gz, rl, result, node);
+ }
+ // @splat — AstGen.zig:9529-9537.
+ if (name_len == 5
+ && memcmp(source + name_start, "splat", 5) == 0) {
+ uint32_t result_type = rlResultTypeForCast(gz, rl, node);
+ uint32_t elem_type
+ = addUnNode(gz, ZIR_INST_SPLAT_OP_RESULT_TY, result_type, node);
+ ResultLoc elem_rl
+ = { .tag = RL_TY, .data = elem_type, .src_node = 0,
+ .ctx = RI_CTX_NONE };
+ AstData nd = tree->nodes.datas[node];
+ uint32_t scalar = exprRl(gz, scope, elem_rl, nd.lhs);
+ uint32_t result = addPlNodeBin(
+ gz, ZIR_INST_SPLAT, node, result_type, scalar);
+ return rvalue(gz, rl, result, node);
+ }
+ // @offsetOf — AstGen.zig:9962-9978.
+ if (name_len == 8
+ && memcmp(source + name_start, "offsetOf", 8) == 0) {
+ AstData nd = tree->nodes.datas[node];
+ uint32_t type_inst = typeExpr(gz, scope, nd.lhs);
+ ResultLoc field_name_rl = { .tag = RL_COERCED_TY,
+ .data = ZIR_REF_SLICE_CONST_U8_TYPE,
+ .src_node = 0, .ctx = RI_CTX_NONE };
+ uint32_t field_name = comptimeExpr(
+ gz, scope, field_name_rl, nd.rhs, COMPTIME_REASON_FIELD_NAME);
+ uint32_t result = addPlNodeBin(
+ gz, ZIR_INST_OFFSET_OF, node, type_inst, field_name);
+ return rvalue(gz, rl, result, node);
+ }
+ // @inComptime — AstGen.zig:9420-9424.
+ if (name_len == 10
+ && memcmp(source + name_start, "inComptime", 10) == 0) {
+ if (gz->is_comptime) {
+ SET_ERROR(ag);
+ return ZIR_REF_VOID_VALUE;
+ }
+ uint32_t result
+ = addNodeExtended(gz, (uint16_t)ZIR_EXT_IN_COMPTIME, node);
+ return rvalue(gz, rl, result, node);
+ }
+ // @errorFromInt — AstGen.zig:9446-9452.
+ if (name_len == 12
+ && memcmp(source + name_start, "errorFromInt", 12) == 0) {
+ AstData nd = tree->nodes.datas[node];
+ uint32_t operand = expr(gz, scope, nd.lhs);
+ ensureExtraCapacity(ag, 2);
+ uint32_t payload_index = ag->extra_len;
+ ag->extra[ag->extra_len++]
+ = (uint32_t)((int32_t)node - (int32_t)gz->decl_node_index);
+ ag->extra[ag->extra_len++] = operand;
+ uint32_t result = addExtendedPayloadSmall(
+ gz, (uint16_t)ZIR_EXT_ERROR_FROM_INT, 0, payload_index);
+ return rvalue(gz, rl, result, node);
+ }
// clang-format on
// TODO: handle other builtins.
@@ -4297,6 +4491,370 @@ static uint32_t arrayTypeExpr(GenZir* gz, Scope* scope, uint32_t node) {
return addPlNodeBin(gz, ZIR_INST_ARRAY_TYPE, node, len, elem_type);
}
+// --- arrayTypeSentinel (AstGen.zig:3965) ---
+// Handles [N:sentinel]T array type expressions.
+
+static uint32_t arrayTypeSentinelExpr(
+ GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) {
+ AstGenCtx* ag = gz->astgen;
+ const Ast* tree = ag->tree;
+ AstData nd = tree->nodes.datas[node];
+
+ // data.lhs = length expression node, data.rhs = extra index.
+ uint32_t len_node = nd.lhs;
+ uint32_t extra_idx = nd.rhs;
+ uint32_t sentinel_node = tree->extra_data.arr[extra_idx]; // sentinel
+ uint32_t elem_type_node = tree->extra_data.arr[extra_idx + 1]; // elem_type
+
+ // Check for `_` identifier → compile error (AstGen.zig:3972-3975).
+ if (tree->nodes.tags[len_node] == AST_NODE_IDENTIFIER
+ && isUnderscoreIdent(tree, len_node)) {
+ SET_ERROR(ag);
+ return ZIR_REF_VOID_VALUE;
+ }
+
+ // Length expression (AstGen.zig:3977).
+ ResultLoc usize_rl = { .tag = RL_COERCED_TY,
+ .data = ZIR_REF_USIZE_TYPE,
+ .src_node = 0,
+ .ctx = RI_CTX_NONE };
+ uint32_t len = reachableExprComptime(
+ gz, scope, usize_rl, len_node, node, COMPTIME_REASON_ARRAY_LENGTH);
+ // Element type (AstGen.zig:3978).
+ uint32_t elem_type = typeExpr(gz, scope, elem_type_node);
+ // Sentinel expression (AstGen.zig:3979).
+ ResultLoc sentinel_rl = { .tag = RL_COERCED_TY,
+ .data = elem_type,
+ .src_node = 0,
+ .ctx = RI_CTX_NONE };
+ uint32_t sentinel = reachableExprComptime(gz, scope, sentinel_rl,
+ sentinel_node, node, COMPTIME_REASON_ARRAY_SENTINEL);
+
+ uint32_t result = addPlNodeTriple(
+ gz, ZIR_INST_ARRAY_TYPE_SENTINEL, node, len, elem_type, sentinel);
+ return rvalue(gz, rl, result, node);
+}
+
+// --- fnProtoExprInner (AstGen.zig:1313) ---
+// Handles function type expressions: fn(params) RetType.
+// Used for fn_proto_simple/fn_proto_one/fn_proto_multi/fn_proto as
+// expressions (not declarations), and for extern fn_proto in fnDecl.
+
+static uint32_t fnProtoExprInner(
+ GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node, bool implicit_ccc) {
+ AstGenCtx* ag = gz->astgen;
+ const Ast* tree = ag->tree;
+ AstNodeTag proto_tag = tree->nodes.tags[node];
+ AstData proto_data = tree->nodes.datas[node];
+
+ // Extract param nodes and callconv_expr from the proto node
+ // (same logic as fnDecl, AstGen.zig:4067-4136).
+ uint32_t param_nodes_buf[1];
+ const uint32_t* param_nodes = NULL;
+ uint32_t params_len = 0;
+ uint32_t callconv_expr_node = 0;
+ uint32_t return_type_rhs = proto_data.rhs;
+
+ if (proto_tag == AST_NODE_FN_PROTO_SIMPLE) {
+ if (proto_data.lhs != 0) {
+ param_nodes_buf[0] = proto_data.lhs;
+ param_nodes = param_nodes_buf;
+ params_len = 1;
+ }
+ } else if (proto_tag == AST_NODE_FN_PROTO_ONE) {
+ uint32_t extra_idx = proto_data.lhs;
+ uint32_t param = tree->extra_data.arr[extra_idx];
+ if (param != 0) {
+ param_nodes_buf[0] = param;
+ param_nodes = param_nodes_buf;
+ params_len = 1;
+ }
+ callconv_expr_node = tree->extra_data.arr[extra_idx + 4];
+ } else if (proto_tag == AST_NODE_FN_PROTO_MULTI) {
+ 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) {
+ uint32_t extra_idx = proto_data.lhs;
+ 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;
+ callconv_expr_node = tree->extra_data.arr[extra_idx + 5];
+ }
+ // Normalize OPT() sentinel for callconv_expr (parser uses OPT()).
+ if (callconv_expr_node == UINT32_MAX)
+ callconv_expr_node = 0;
+
+ GenZir block_scope = makeSubBlock(gz, scope);
+ uint32_t block_inst = makeBlockInst(ag, ZIR_INST_BLOCK_INLINE, gz, node);
+
+ // Parameter iteration (AstGen.zig:1329-1384).
+ // Token-based iterator matching Ast.zig:2680-2768.
+ uint32_t noalias_bits = 0;
+ bool is_var_args = false;
+
+ uint32_t fn_token = tree->nodes.main_tokens[node];
+ uint32_t lparen = fn_token + 1;
+ uint32_t iter_tok_i = lparen + 1;
+ bool iter_tok_flag = true;
+ uint32_t iter_param_i = 0;
+ uint32_t param_type_i = 0;
+
+ ResultLoc coerced_type_ri = { .tag = RL_COERCED_TY,
+ .data = ZIR_REF_TYPE_TYPE,
+ .src_node = 0,
+ .ctx = RI_CTX_NONE };
+
+ while (true) {
+ uint32_t name_token = 0;
+ uint32_t comptime_noalias_token = 0;
+ bool is_comptime_param = false;
+ bool is_anytype = false;
+ uint32_t param_type_node = 0;
+
+ if (!iter_tok_flag) {
+ if (iter_param_i >= params_len)
+ break;
+ param_type_node = param_nodes[iter_param_i];
+ uint32_t tok_i = firstToken(tree, param_type_node);
+ while (tok_i > 0) {
+ tok_i--;
+ uint32_t ttag = tree->tokens.tags[tok_i];
+ if (ttag == TOKEN_COLON)
+ continue;
+ if (ttag == TOKEN_IDENTIFIER) {
+ name_token = tok_i;
+ continue;
+ }
+ if (ttag == TOKEN_KEYWORD_COMPTIME
+ || ttag == TOKEN_KEYWORD_NOALIAS) {
+ comptime_noalias_token = tok_i;
+ continue;
+ }
+ break;
+ }
+ iter_param_i++;
+ iter_tok_i = lastToken(tree, param_type_node) + 1;
+ if (tree->tokens.tags[iter_tok_i] == TOKEN_COMMA)
+ iter_tok_i++;
+ iter_tok_flag = true;
+ } else {
+ if (tree->tokens.tags[iter_tok_i] == TOKEN_COMMA)
+ iter_tok_i++;
+ if (tree->tokens.tags[iter_tok_i] == TOKEN_R_PAREN)
+ break;
+ while (tree->tokens.tags[iter_tok_i] == TOKEN_DOC_COMMENT)
+ iter_tok_i++;
+ if (tree->tokens.tags[iter_tok_i] == TOKEN_ELLIPSIS3) {
+ is_var_args = true;
+ break;
+ }
+ if (tree->tokens.tags[iter_tok_i] == TOKEN_KEYWORD_COMPTIME
+ || tree->tokens.tags[iter_tok_i] == TOKEN_KEYWORD_NOALIAS) {
+ comptime_noalias_token = iter_tok_i;
+ iter_tok_i++;
+ }
+ if (tree->tokens.tags[iter_tok_i] == TOKEN_IDENTIFIER
+ && tree->tokens.tags[iter_tok_i + 1] == TOKEN_COLON) {
+ name_token = iter_tok_i;
+ iter_tok_i += 2;
+ }
+ if (tree->tokens.tags[iter_tok_i] == TOKEN_KEYWORD_ANYTYPE) {
+ is_anytype = true;
+ iter_tok_i++;
+ } else {
+ iter_tok_flag = false;
+ continue;
+ }
+ }
+
+ // Determine noalias/comptime (AstGen.zig:1334-1342).
+ if (comptime_noalias_token != 0
+ && tree->tokens.tags[comptime_noalias_token]
+ == TOKEN_KEYWORD_NOALIAS) {
+ if (param_type_i < 32)
+ noalias_bits |= (1u << param_type_i);
+ }
+ if (comptime_noalias_token != 0
+ && tree->tokens.tags[comptime_noalias_token]
+ == TOKEN_KEYWORD_COMPTIME) {
+ is_comptime_param = true;
+ }
+
+ // Param name (AstGen.zig:1352-1357).
+ uint32_t param_name_str = 0; // empty
+ if (name_token != 0) {
+ uint32_t name_start = tree->tokens.starts[name_token];
+ char nch = tree->source[name_start];
+ if (nch == '_') {
+ uint32_t next_start = tree->tokens.starts[name_token + 1];
+ if (next_start != name_start + 1)
+ param_name_str = identAsString(ag, name_token);
+ } else {
+ param_name_str = identAsString(ag, name_token);
+ }
+ }
+
+ if (is_anytype) {
+ // anytype param (AstGen.zig:1359-1366).
+ uint32_t anytype_name_token
+ = name_token != 0 ? name_token : (iter_tok_i - 1);
+ ZirInstTag anytype_tag = is_comptime_param
+ ? ZIR_INST_PARAM_ANYTYPE_COMPTIME
+ : ZIR_INST_PARAM_ANYTYPE;
+ addStrTok(
+ &block_scope, anytype_tag, param_name_str, anytype_name_token);
+ } else {
+ // Typed param (AstGen.zig:1367-1381).
+ GenZir param_gz = makeSubBlock(&block_scope, scope);
+ param_gz.is_comptime = true;
+ uint32_t param_type_ref = fullBodyExpr(
+ ¶m_gz, scope, coerced_type_ri, param_type_node);
+ if (ag->has_compile_errors) {
+ gzUnstack(¶m_gz);
+ gzUnstack(&block_scope);
+ return ZIR_REF_VOID_VALUE;
+ }
+ // break_inline target is the param inst we're about to create
+ // (AstGen.zig:1373-1374).
+ uint32_t param_inst_expected = ag->inst_len + 1;
+ makeBreakInline(¶m_gz, param_inst_expected, param_type_ref,
+ (int32_t)param_type_node - (int32_t)param_gz.decl_node_index);
+ uint32_t name_tok_for_src = name_token != 0
+ ? name_token
+ : tree->nodes.main_tokens[param_type_node];
+ ZirInstTag param_tag
+ = is_comptime_param ? ZIR_INST_PARAM_COMPTIME : ZIR_INST_PARAM;
+ // prev_param_insts = &.{}, is_generic = false for fn proto exprs
+ // (AstGen.zig:1377-1380).
+ uint32_t param_inst = addParam(&block_scope, ¶m_gz, param_tag,
+ name_tok_for_src, param_name_str, false);
+ (void)param_inst_expected;
+ (void)param_inst;
+ }
+ param_type_i++;
+ }
+
+ // Calling convention (AstGen.zig:1386-1397).
+ uint32_t cc_ref = ZIR_REF_NONE;
+ if (callconv_expr_node != 0) {
+ uint32_t cc_ty = addBuiltinValue(&block_scope, callconv_expr_node,
+ ZIR_BUILTIN_VALUE_CALLING_CONVENTION);
+ ResultLoc cc_ri = { .tag = RL_COERCED_TY,
+ .data = cc_ty,
+ .src_node = 0,
+ .ctx = RI_CTX_NONE };
+ cc_ref = comptimeExpr(&block_scope, scope, cc_ri, callconv_expr_node,
+ COMPTIME_REASON_CALLCONV);
+ } else if (implicit_ccc) {
+ cc_ref = addBuiltinValue(
+ &block_scope, node, ZIR_BUILTIN_VALUE_CALLING_CONVENTION_C);
+ }
+
+ // Return type (AstGen.zig:1399-1400).
+ uint32_t ret_ty_node = return_type_rhs;
+ uint32_t ret_ty = comptimeExpr(&block_scope, scope, coerced_type_ri,
+ ret_ty_node, COMPTIME_REASON_FUNCTION_RET_TY);
+ if (ag->has_compile_errors) {
+ gzUnstack(&block_scope);
+ return ZIR_REF_VOID_VALUE;
+ }
+ // Map void_type → .none (AstGen.zig:12054).
+ if (ret_ty == ZIR_REF_VOID_TYPE)
+ ret_ty = ZIR_REF_NONE;
+
+ // addFunc with no body (AstGen.zig:1402-1422).
+ uint32_t result;
+ bool need_fancy
+ = cc_ref != ZIR_REF_NONE || is_var_args || noalias_bits != 0;
+ if (need_fancy) {
+ result = addFuncFancy(&block_scope, node, 0, block_inst, ret_ty, NULL,
+ 0, cc_ref, NULL, 0, NULL, 0, NULL, 0, 0, 0, is_var_args, false,
+ false, noalias_bits, false, NULL, 0);
+ } else {
+ result = addFunc(&block_scope, node, 0, block_inst, ret_ty, NULL, 0,
+ NULL, 0, NULL, 0, 0, 0, false, false, NULL, 0);
+ }
+
+ // break_inline + setBlockBody + append (AstGen.zig:1424-1426).
+ makeBreakInline(&block_scope, block_inst, result, AST_NODE_OFFSET_NONE);
+ setBlockBody(ag, &block_scope, block_inst);
+ gzAppendInstruction(gz, block_inst);
+
+ return rvalue(gz, rl, block_inst + ZIR_REF_START_INDEX, node);
+}
+
+// --- fnProtoExpr (AstGen.zig:1271) ---
+// Wrapper that validates fn_proto used as expression (no name, no align, etc.)
+// then calls fnProtoExprInner.
+
+static uint32_t fnProtoExpr(
+ GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) {
+ AstGenCtx* ag = gz->astgen;
+ const Ast* tree = ag->tree;
+ AstNodeTag proto_tag = tree->nodes.tags[node];
+ AstData proto_data = tree->nodes.datas[node];
+
+ // Validate: no name token (AstGen.zig:1281-1283).
+ // fn_proto_simple main_token is 'fn', next token would be name or '('.
+ // If there's a name, main_token+1 is an identifier before '('.
+ // For function type expressions, fn keyword is followed by '('.
+ // name_token check: upstream checks fn_proto.name_token which is
+ // derived from AST node. For fn_proto_simple, name_token is null.
+ // We just skip this validation since the parser already handles it.
+
+ // Validate: no align/addrspace/section (AstGen.zig:1285-1295).
+ // These are only present in fn_proto_one and fn_proto.
+ if (proto_tag == AST_NODE_FN_PROTO_ONE) {
+ uint32_t extra_idx = proto_data.lhs;
+ uint32_t align_expr = tree->extra_data.arr[extra_idx + 1];
+ uint32_t addrspace_expr = tree->extra_data.arr[extra_idx + 2];
+ uint32_t section_expr = tree->extra_data.arr[extra_idx + 3];
+ if (align_expr != UINT32_MAX && align_expr != 0) {
+ SET_ERROR(ag);
+ return ZIR_REF_VOID_VALUE;
+ }
+ if (addrspace_expr != UINT32_MAX && addrspace_expr != 0) {
+ SET_ERROR(ag);
+ return ZIR_REF_VOID_VALUE;
+ }
+ if (section_expr != UINT32_MAX && section_expr != 0) {
+ SET_ERROR(ag);
+ return ZIR_REF_VOID_VALUE;
+ }
+ } else if (proto_tag == AST_NODE_FN_PROTO) {
+ uint32_t extra_idx = proto_data.lhs;
+ uint32_t align_expr = tree->extra_data.arr[extra_idx + 2];
+ uint32_t addrspace_expr = tree->extra_data.arr[extra_idx + 3];
+ uint32_t section_expr = tree->extra_data.arr[extra_idx + 4];
+ if (align_expr != UINT32_MAX && align_expr != 0) {
+ SET_ERROR(ag);
+ return ZIR_REF_VOID_VALUE;
+ }
+ if (addrspace_expr != UINT32_MAX && addrspace_expr != 0) {
+ SET_ERROR(ag);
+ return ZIR_REF_VOID_VALUE;
+ }
+ if (section_expr != UINT32_MAX && section_expr != 0) {
+ SET_ERROR(ag);
+ return ZIR_REF_VOID_VALUE;
+ }
+ }
+
+ // Validate: no inferred error set (AstGen.zig:1297-1302).
+ uint32_t return_type_node = proto_data.rhs;
+ uint32_t maybe_bang = firstToken(tree, return_type_node) - 1;
+ if (tree->tokens.tags[maybe_bang] == TOKEN_BANG) {
+ SET_ERROR(ag);
+ return ZIR_REF_VOID_VALUE;
+ }
+
+ return fnProtoExprInner(gz, scope, rl, node, false);
+}
+
// --- arrayInitExpr (AstGen.zig:1431) ---
// Handles typed array init: [_]T{...}, [_:s]T{...}, and [N]T{...}.
@@ -5468,6 +6026,15 @@ static uint32_t exprRl(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) {
// array_type (AstGen.zig:940).
case AST_NODE_ARRAY_TYPE:
return rvalue(gz, rl, arrayTypeExpr(gz, scope, node), node);
+ // array_type_sentinel (AstGen.zig:3965).
+ case AST_NODE_ARRAY_TYPE_SENTINEL:
+ return arrayTypeSentinelExpr(gz, scope, rl, node);
+ // fn_proto as expression (AstGen.zig:1271-1311).
+ case AST_NODE_FN_PROTO_SIMPLE:
+ case AST_NODE_FN_PROTO_MULTI:
+ case AST_NODE_FN_PROTO_ONE:
+ case AST_NODE_FN_PROTO:
+ return fnProtoExpr(gz, scope, rl, node);
// array_init variants (AstGen.zig:836-856).
case AST_NODE_ARRAY_INIT:
case AST_NODE_ARRAY_INIT_COMMA:
@@ -11364,11 +11931,19 @@ static uint32_t addFunc(GenZir* gz, uint32_t src_node, uint32_t block_node,
uint32_t ret_param_refs_len) {
AstGenCtx* ag = gz->astgen;
const Ast* tree = ag->tree;
- uint32_t rbrace_tok = lastToken(tree, block_node);
- uint32_t rbrace_start = tree->tokens.starts[rbrace_tok];
- advanceSourceCursor(ag, rbrace_start);
- uint32_t rbrace_line = ag->source_line - gz->decl_line;
- uint32_t rbrace_column = ag->source_column;
+
+ // SrcLocs only emitted when there's a body (AstGen.zig:12081-12108).
+ uint32_t src_locs_len = 0;
+ uint32_t rbrace_line = 0;
+ uint32_t rbrace_column = 0;
+ if (body_len > 0) {
+ uint32_t rbrace_tok = lastToken(tree, block_node);
+ uint32_t rbrace_start = tree->tokens.starts[rbrace_tok];
+ advanceSourceCursor(ag, rbrace_start);
+ rbrace_line = ag->source_line - gz->decl_line;
+ rbrace_column = ag->source_column;
+ src_locs_len = 7;
+ }
// Build Func payload (Zir.Inst.Func: ret_ty, param_block, body_len).
// (AstGen.zig:12182-12194)
@@ -11388,7 +11963,8 @@ static uint32_t addFunc(GenZir* gz, uint32_t src_node, uint32_t block_node,
uint32_t fixup_body_len = countBodyLenAfterFixupsExtraRefs(
ag, body, body_len, param_insts, param_insts_len);
- ensureExtraCapacity(ag, 3 + ret_ty_packed_len + fixup_body_len + 7);
+ ensureExtraCapacity(
+ ag, 3 + ret_ty_packed_len + fixup_body_len + src_locs_len);
uint32_t payload_index = ag->extra_len;
ag->extra[ag->extra_len++] = ret_ty_packed; // Func.ret_ty
ag->extra[ag->extra_len++] = param_block; // Func.param_block
@@ -11408,16 +11984,18 @@ static uint32_t addFunc(GenZir* gz, uint32_t src_node, uint32_t block_node,
appendBodyWithFixupsExtraRefs(
ag, body, body_len, param_insts, param_insts_len);
- // SrcLocs (AstGen.zig:12098-12106).
- uint32_t columns = (lbrace_column & 0xFFFFu) | (rbrace_column << 16);
- ag->extra[ag->extra_len++] = lbrace_line;
- ag->extra[ag->extra_len++] = rbrace_line;
- ag->extra[ag->extra_len++] = columns;
- // proto_hash (4 words): zero for now.
- ag->extra[ag->extra_len++] = 0;
- ag->extra[ag->extra_len++] = 0;
- ag->extra[ag->extra_len++] = 0;
- ag->extra[ag->extra_len++] = 0;
+ // SrcLocs + proto_hash only when body present (AstGen.zig:12081-12108).
+ if (body_len > 0) {
+ uint32_t columns = (lbrace_column & 0xFFFFu) | (rbrace_column << 16);
+ ag->extra[ag->extra_len++] = lbrace_line;
+ ag->extra[ag->extra_len++] = rbrace_line;
+ ag->extra[ag->extra_len++] = columns;
+ // proto_hash (4 words): zero for now.
+ ag->extra[ag->extra_len++] = 0;
+ ag->extra[ag->extra_len++] = 0;
+ ag->extra[ag->extra_len++] = 0;
+ ag->extra[ag->extra_len++] = 0;
+ }
// Emit the func instruction (AstGen.zig:12220-12226).
ZirInstTag tag
@@ -11443,11 +12021,19 @@ static uint32_t addFuncFancy(GenZir* gz, uint32_t src_node,
uint32_t ret_param_refs_len) {
AstGenCtx* ag = gz->astgen;
const Ast* tree = ag->tree;
- uint32_t rbrace_tok = lastToken(tree, block_node);
- uint32_t rbrace_start = tree->tokens.starts[rbrace_tok];
- advanceSourceCursor(ag, rbrace_start);
- uint32_t rbrace_line = ag->source_line - gz->decl_line;
- uint32_t rbrace_column = ag->source_column;
+
+ // SrcLocs only emitted when there's a body (AstGen.zig:12081-12108).
+ uint32_t src_locs_len = 0;
+ uint32_t rbrace_line = 0;
+ uint32_t rbrace_column = 0;
+ if (body_len > 0) {
+ uint32_t rbrace_tok = lastToken(tree, block_node);
+ uint32_t rbrace_start = tree->tokens.starts[rbrace_tok];
+ advanceSourceCursor(ag, rbrace_start);
+ rbrace_line = ag->source_line - gz->decl_line;
+ rbrace_column = ag->source_column;
+ src_locs_len = 7;
+ }
uint32_t fixup_body_len = countBodyLenAfterFixupsExtraRefs(
ag, body, body_len, param_insts, param_insts_len);
@@ -11472,7 +12058,7 @@ static uint32_t addFuncFancy(GenZir* gz, uint32_t src_node,
// FuncFancy has 3 fields: param_block, body_len, bits.
uint32_t total_extra = 3 + cc_extra_len + ret_extra_len
- + ((noalias_bits != 0) ? 1u : 0u) + fixup_body_len + 7;
+ + ((noalias_bits != 0) ? 1u : 0u) + fixup_body_len + src_locs_len;
ensureExtraCapacity(ag, total_extra);
// FuncFancy payload (Zir.zig:2589-2610).
@@ -11530,16 +12116,18 @@ static uint32_t addFuncFancy(GenZir* gz, uint32_t src_node,
appendBodyWithFixupsExtraRefs(
ag, body, body_len, param_insts, param_insts_len);
- // SrcLocs (AstGen.zig:12098-12106).
- uint32_t columns = (lbrace_column & 0xFFFFu) | (rbrace_column << 16);
- ag->extra[ag->extra_len++] = lbrace_line;
- ag->extra[ag->extra_len++] = rbrace_line;
- ag->extra[ag->extra_len++] = columns;
- // proto_hash (4 words): zero for now.
- ag->extra[ag->extra_len++] = 0;
- ag->extra[ag->extra_len++] = 0;
- ag->extra[ag->extra_len++] = 0;
- ag->extra[ag->extra_len++] = 0;
+ // SrcLocs + proto_hash only when body present (AstGen.zig:12081-12108).
+ if (body_len > 0) {
+ uint32_t columns = (lbrace_column & 0xFFFFu) | (rbrace_column << 16);
+ ag->extra[ag->extra_len++] = lbrace_line;
+ ag->extra[ag->extra_len++] = rbrace_line;
+ ag->extra[ag->extra_len++] = columns;
+ // proto_hash (4 words): zero for now.
+ ag->extra[ag->extra_len++] = 0;
+ ag->extra[ag->extra_len++] = 0;
+ ag->extra[ag->extra_len++] = 0;
+ ag->extra[ag->extra_len++] = 0;
+ }
// Emit the func_fancy instruction (AstGen.zig:12220-12226).
ZirInstData data;
@@ -11718,6 +12306,7 @@ static void fnDecl(AstGenCtx* ag, GenZir* gz, Scope* scope,
// (Ast.zig:2003-2025, AstGen.zig:4102-4106, 4240-4247).
bool is_pub = false;
bool is_export = false;
+ bool is_extern = false;
bool is_noinline = false;
bool has_inline_keyword = false;
for (uint32_t i = fn_token; i > 0;) {
@@ -11727,6 +12316,8 @@ static void fnDecl(AstGenCtx* ag, GenZir* gz, Scope* scope,
is_pub = true;
else if (ttag == TOKEN_KEYWORD_EXPORT)
is_export = true;
+ else if (ttag == TOKEN_KEYWORD_EXTERN)
+ is_extern = true;
else if (ttag == TOKEN_KEYWORD_NOINLINE)
is_noinline = true;
else if (ttag == TOKEN_KEYWORD_INLINE)
@@ -12121,21 +12712,54 @@ static void fnDecl(AstGenCtx* ag, GenZir* gz, Scope* scope,
gzUnstack(&cc_gz);
// --- Body handling ---
- // For fn_proto* (no body): extern function, emit type only
+ // For fn_proto* (no body): extern function type
// (AstGen.zig:4136-4164).
// For fn_decl (has body): emit function value (AstGen.zig:4197-4201).
uint32_t func_ref;
if (body_node == 0) {
// fn_proto without body: extern function type.
- // Upstream emits fnProtoExprInner; we SET_ERROR for now as
- // fnProtoExprInner is not yet ported.
- // TODO: implement fnProtoExprInner for extern fn support.
- SET_ERROR(ag);
+ // Upstream calls fnProtoExprInner with implicit_ccc=true.
+ // We use the already-computed params/ret but add implicit CCC
+ // if no explicit callconv was provided (AstGen.zig:1394-1396).
+ if (cc_ref == ZIR_REF_NONE && !has_inline_keyword) {
+ // Extern fn without explicit callconv: implicit C calling
+ // convention (AstGen.zig:1394-1396 via fnProtoExprInner).
+ cc_ref = addBuiltinValue(
+ &decl_gz, node, ZIR_BUILTIN_VALUE_CALLING_CONVENTION_C);
+ }
+ // Emit func instruction with no body (AstGen.zig:1402-1422).
+ bool need_fancy
+ = cc_ref != ZIR_REF_NONE || is_var_args || noalias_bits != 0;
+ if (need_fancy) {
+ func_ref = addFuncFancy(&decl_gz, node, 0, decl_inst, ret_ref,
+ ret_body, ret_body_len, cc_ref, cc_body, cc_body_len, NULL, 0,
+ param_insts, param_insts_len, 0, 0, is_var_args, false, false,
+ noalias_bits, ret_ty_is_generic, ret_param_refs,
+ ret_param_refs_len);
+ } else {
+ func_ref = addFunc(&decl_gz, node, 0, decl_inst, ret_ref, ret_body,
+ ret_body_len, NULL, 0, param_insts, param_insts_len, 0, 0,
+ false, ret_ty_is_generic, ret_param_refs, ret_param_refs_len);
+ }
+ // Patch ret_body/cc_body break_inlines (AstGen.zig:12199-12202).
+ if (ret_body_len > 0) {
+ uint32_t break_inst = ret_body[ret_body_len - 1];
+ uint32_t break_payload
+ = ag->inst_datas[break_inst].break_data.payload_index;
+ ag->extra[break_payload + 1] = func_ref - ZIR_REF_START_INDEX;
+ }
+ if (cc_body_len > 0) {
+ uint32_t break_inst = cc_body[cc_body_len - 1];
+ uint32_t break_payload
+ = ag->inst_datas[break_inst].break_data.payload_index;
+ ag->extra[break_payload + 1] = func_ref - ZIR_REF_START_INDEX;
+ }
free(ret_body);
free(cc_body);
- gzUnstack(&decl_gz);
- ag->within_fn = prev_within_fn;
- return;
+ // break_inline from decl_gz to decl_inst (AstGen.zig:4163).
+ makeBreakInline(&decl_gz, decl_inst, func_ref,
+ (int32_t)node - (int32_t)proto_node);
+ goto fn_decl_finish;
}
// --- Body (AstGen.zig:4415-4424) ---
@@ -12264,10 +12888,14 @@ static void fnDecl(AstGenCtx* ag, GenZir* gz, Scope* scope,
makeBreakInline(
&decl_gz, decl_inst, func_ref, (int32_t)node - (int32_t)proto_node);
+fn_decl_finish:
// setDeclaration (AstGen.zig:4208-4225).
- // Linkage: export > normal (AstGen.zig:4217).
+ // Linkage: extern > export > normal (AstGen.zig:4217).
+ ;
DeclFlagsId decl_id;
- if (is_export)
+ if (is_extern)
+ decl_id = is_pub ? DECL_ID_PUB_EXTERN_CONST : DECL_ID_EXTERN_CONST;
+ 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;
@@ -13151,21 +13779,20 @@ static uint32_t containerDecl(
else if (prev_tag == TOKEN_KEYWORD_EXTERN)
layout = 1;
}
- decl_inst = structDeclInner(ag, gz, node, members, members_len, layout,
- arg_node, name_strategy);
+ decl_inst = structDeclInner(ag, gz, scope, node, members, members_len,
+ layout, arg_node, name_strategy);
break;
}
case TOKEN_KEYWORD_ENUM:
- decl_inst = enumDeclInner(
- ag, gz, node, members, members_len, arg_node, name_strategy);
+ decl_inst = enumDeclInner(ag, gz, scope, node, members, members_len,
+ arg_node, name_strategy);
break;
default:
// union/opaque: fall back to struct for now.
decl_inst = structDeclInner(
- ag, gz, node, members, members_len, 0, 0, name_strategy);
+ ag, gz, scope, node, members, members_len, 0, 0, name_strategy);
break;
}
- (void)scope;
ag->fn_block = prev_fn_block;
return decl_inst + ZIR_REF_START_INDEX;
@@ -13269,9 +13896,9 @@ static bool tokenIsUnderscore(const Ast* tree, uint32_t ident_token) {
// Handles enum container declarations.
// arg_node: the tag type expression node (e.g. u8 in enum(u8)), 0 if none.
-static uint32_t enumDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
- const uint32_t* members, uint32_t members_len, uint32_t arg_node,
- uint8_t name_strategy) {
+static uint32_t enumDeclInner(AstGenCtx* ag, GenZir* gz, Scope* scope,
+ uint32_t node, const uint32_t* members, uint32_t members_len,
+ uint32_t arg_node, uint8_t name_strategy) {
const Ast* tree = ag->tree;
// --- First pass: count fields, values, decls, detect nonexhaustive ---
@@ -13307,8 +13934,7 @@ static uint32_t enumDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
// Create namespace scope (AstGen.zig:5618-5623).
ScopeNamespace namespace;
- scopeNamespaceInit(
- &namespace, &gz->base, node, decl_inst, gz, ag->within_fn);
+ scopeNamespaceInit(&namespace, scope, node, decl_inst, gz, ag->within_fn);
advanceSourceCursorToNode(ag, node);
@@ -13449,9 +14075,10 @@ static uint32_t enumDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
// --- tupleDecl (AstGen.zig:5192) ---
-static uint32_t tupleDecl(AstGenCtx* ag, GenZir* gz, uint32_t node,
- const uint32_t* members, uint32_t members_len, uint8_t layout,
- uint32_t backing_int_node) {
+static uint32_t tupleDecl(AstGenCtx* ag, GenZir* gz, Scope* scope,
+ uint32_t node, const uint32_t* members, uint32_t members_len,
+ uint8_t layout, uint32_t backing_int_node) {
+ (void)scope;
const Ast* tree = ag->tree;
// layout must be auto for tuples (AstGen.zig:5204-5207).
@@ -13614,9 +14241,9 @@ static uint32_t tupleDecl(AstGenCtx* ag, GenZir* gz, uint32_t node,
// --- structDeclInner (AstGen.zig:4926) ---
-static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
- const uint32_t* members, uint32_t members_len, uint8_t layout,
- uint32_t backing_int_node, uint8_t name_strategy) {
+static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, Scope* scope,
+ uint32_t node, const uint32_t* members, uint32_t members_len,
+ uint8_t layout, uint32_t backing_int_node, uint8_t name_strategy) {
const Ast* tree = ag->tree;
// Tuple detection (AstGen.zig:4939-4950).
@@ -13638,8 +14265,8 @@ static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
SET_ERROR(ag);
return reserveInstructionIndex(ag);
}
- return tupleDecl(
- ag, gz, node, members, members_len, layout, backing_int_node);
+ return tupleDecl(ag, gz, scope, node, members, members_len, layout,
+ backing_int_node);
}
}
@@ -13660,8 +14287,7 @@ static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
// Create namespace scope (AstGen.zig:4973-4979).
ScopeNamespace namespace;
- scopeNamespaceInit(
- &namespace, &gz->base, node, decl_inst, gz, ag->within_fn);
+ scopeNamespaceInit(&namespace, scope, node, decl_inst, gz, ag->within_fn);
advanceSourceCursorToNode(ag, node);
@@ -15246,8 +15872,8 @@ Zir astGen(const Ast* ast) {
const uint32_t* members = ast->extra_data.arr + members_start;
uint32_t members_len = members_end - members_start;
- structDeclInner(
- &ag, &gen_scope, 0, members, members_len, 0, 0, 0 /* parent */);
+ structDeclInner(&ag, &gen_scope, &gen_scope.base, 0, members, members_len,
+ 0, 0, 0 /* parent */);
// Write imports list (AstGen.zig:227-244).
writeImports(&ag);
diff --git a/stage0/astgen_test.zig b/stage0/astgen_test.zig
@@ -297,11 +297,7 @@ fn expectEqualZir(gpa: Allocator, ref: Zir, got: c.Zir) !void {
const got_tag: u8 = @intCast(got.inst_tags[i]);
if (ref_tag != got_tag) {
std.debug.print("first divergence at [{d}]: ref_tag={d} got_tag={d}\n", .{ i, ref_tag, got_tag });
- // Show ref instruction data for this position.
- const rd = ref_datas[i];
- std.debug.print(" ref pl_node: src_node={d} payload={d}\n", .{
- rd.pl_node.src_node, rd.pl_node.payload_index,
- });
+ // Data printing skipped to avoid tagged union safety panics.
// Scan for nearest declaration.
var j: usize = i;
while (j > 0) {