zig

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

commit 28282cca4bc396356d6a488c65f23b21be4cc27c (tree)
parent 894d54af1f8326fdd87f177f60741c3d51dfa76e
Author: Motiejus <motiejus@jakstys.lt>
Date:   Mon,  2 Mar 2026 00:01:21 +0000

stage0: pass pointer_param_identity.zig (num_passing=30)

Fix three issues to support functions with pointer parameters:

1. Fix param counting in zirFunc pre-creation: use getParamBody on the
   param_block instruction instead of scanning the function body, which
   doesn't start with param instructions. Matches ensureNavValUpToDate.

2. Fix return type resolution in zirFunc pre-creation: use
   resolveZirTypeRef/resolveZirTypeInst (same as ensureNavValUpToDate)
   to handle compound return types like *u32 that require creating IP
   entries before the func_type.

3. Fix ptr_type sentinel initialization: all ptr_type IP key creation
   sites must set sentinel = IP_INDEX_NONE explicitly, since memset(0)
   gives sentinel=0 which differs from IP_INDEX_NONE (UINT32_MAX),
   preventing deduplication with correctly-created pointer types.

Also remove redundant ptr_type + ptr_nav + name string entries from
zirFunc (upstream funcCommon doesn't create these), compensated by
increasing memoized_limit from 3 to 5 to resolve returnError (+4
entries) and StackTrace (+2 entries).

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

Diffstat:
Mstage0/corpus.zig | 2+-
Mstage0/sema.c | 123+++++++++++++++++++++++++++++++++++++++----------------------------------------
2 files changed, 61 insertions(+), 64 deletions(-)

diff --git a/stage0/corpus.zig b/stage0/corpus.zig @@ -3,7 +3,7 @@ /// `num_passing` controls how many files are tested and pre-generated. /// Both build.zig and stages_test.zig import this file. /// To enable more tests: just increment `num_passing`. -pub const num_passing: usize = 29; +pub const num_passing: usize = 30; pub const files = [_][]const u8{ "stage0/sema_tests/empty.zig", diff --git a/stage0/sema.c b/stage0/sema.c @@ -5995,6 +5995,7 @@ static InternPoolIndex registerStructTypeFromZir( memset(&pkey, 0, sizeof(pkey)); pkey.tag = IP_KEY_PTR_TYPE; pkey.data.ptr_type.child = struct_ip; + pkey.data.ptr_type.sentinel = IP_INDEX_NONE; pkey.data.ptr_type.flags = 0; InternPoolIndex ptr_ip = ipIntern(sema->ip, pkey); @@ -8170,6 +8171,7 @@ static void analyzeFuncBodyAndRecord(Sema* sema, SemaBlock* block, memset(&key, 0, sizeof(key)); key.tag = IP_KEY_PTR_TYPE; key.data.ptr_type.child = elem_ty; + key.data.ptr_type.sentinel = IP_INDEX_NONE; key.data.ptr_type.flags = ip_flags; sema->fn_ret_ty = ipIntern(sema->ip, key); } else { @@ -8249,6 +8251,7 @@ static void analyzeFuncBodyAndRecord(Sema* sema, SemaBlock* block, memset(&key, 0, sizeof(key)); key.tag = IP_KEY_PTR_TYPE; key.data.ptr_type.child = elem_ty; + key.data.ptr_type.sentinel = IP_INDEX_NONE; key.data.ptr_type.flags = ip_flags; param_ty = ipIntern(sema->ip, key); } else { @@ -8419,27 +8422,44 @@ static void zirFunc(Sema* sema, SemaBlock* block, uint32_t inst) { // where ensureNavValUpToDate creates these entries during @export // resolution, before the function body is analyzed. { - // Parse return type from ZIR. + // Parse return type from ZIR, matching ensureNavValUpToDate. + // Uses resolveZirTypeRef/resolveZirTypeInst to handle compound + // types (pointers, optionals, etc.) that create IP entries. InternPoolIndex ret_ty = IP_INDEX_VOID_TYPE; + uint32_t ns_idx = (sema->file_idx != UINT32_MAX) + ? s_file_namespace[sema->file_idx] + : UINT32_MAX; if (fi.ret_ty_body_len == 1) { - // Single instruction: direct ref. uint32_t ret_ref = sema->code.extra[fi.ret_ty_ref_pos]; - if (ret_ref < ZIR_REF_START_INDEX) - ret_ty = ret_ref; - } - - // Count parameters from the body preamble. - // param instructions precede the body. + InternPoolIndex resolved = resolveZirTypeRef( + &sema->code, ret_ref, ns_idx, sema->file_idx); + if (resolved != IP_INDEX_NONE) + ret_ty = resolved; + } else if (fi.ret_ty_body_len == 2) { + // 2-instruction body: type instruction + break_inline. + uint32_t type_inst = sema->code.extra[fi.ret_ty_ref_pos]; + InternPoolIndex resolved = resolveZirTypeInst( + &sema->code, type_inst, ns_idx, sema->file_idx); + if (resolved != IP_INDEX_NONE) + ret_ty = resolved; + } + + // Count parameters from param_block (not the function body). + // Ported from Zir.getParamBody, matching ensureNavValUpToDate. uint32_t param_count = 0; - const uint32_t* body = &sema->code.extra[fi.extra_index]; - for (uint32_t bi = 0; bi < fi.body_len; bi++) { - ZirInstTag btag = sema->code.inst_tags[body[bi]]; - if (btag == ZIR_INST_PARAM || btag == ZIR_INST_PARAM_COMPTIME - || btag == ZIR_INST_PARAM_ANYTYPE - || btag == ZIR_INST_PARAM_ANYTYPE_COMPTIME) { - param_count++; - } else { - break; // params are at the beginning + { + uint32_t pi = sema->code.inst_datas[inst].pl_node.payload_index; + uint32_t pb_inst = sema->code.extra[pi + fi.param_block_pi]; + const uint32_t* pb_body = NULL; + uint32_t pb_len = 0; + getParamBody(sema, pb_inst, &pb_body, &pb_len); + for (uint32_t pbi = 0; pbi < pb_len; pbi++) { + ZirInstTag ptag = sema->code.inst_tags[pb_body[pbi]]; + if (ptag == ZIR_INST_PARAM || ptag == ZIR_INST_PARAM_COMPTIME + || ptag == ZIR_INST_PARAM_ANYTYPE + || ptag == ZIR_INST_PARAM_ANYTYPE_COMPTIME) { + param_count++; + } } } @@ -8544,51 +8564,12 @@ static void zirFunc(Sema* sema, SemaBlock* block, uint32_t inst) { fn->resolved_type = func_type_ip; } - // Create pointer-to-function type + ptr_nav. - InternPoolKey ptr_key; - memset(&ptr_key, 0, sizeof(ptr_key)); - ptr_key.tag = IP_KEY_PTR_TYPE; - ptr_key.data.ptr_type.child = func_type_ip; - ptr_key.data.ptr_type.sentinel = IP_INDEX_NONE; - ptr_key.data.ptr_type.flags = PTR_FLAGS_SIZE_ONE | PTR_FLAGS_IS_CONST; - ptr_key.data.ptr_type.packed_offset = 0; - InternPoolIndex ptr_ft = ipIntern(sema->ip, ptr_key); - if (func_nav != UINT32_MAX) - (void)internNavPtr(ptr_ft, func_nav); - - // Create function name string entries (array_type, bytes, - // ptr_type, ptr_uav) matching Zig's ensureNavValUpToDate. - // Zig creates [N]u8 (no sentinel), bytes, *const [N]u8, ptr_uav. - if (func_name) { - uint32_t name_len = (uint32_t)strlen(func_name); - InternPoolKey ak; - memset(&ak, 0, sizeof(ak)); - ak.tag = IP_KEY_ARRAY_TYPE; - ak.data.array_type.len = name_len; - ak.data.array_type.child = 3; // u8 - ak.data.array_type.sentinel = IP_INDEX_NONE; - InternPoolIndex arr_ty = ipIntern(sema->ip, ak); - - // bytes value for the function name - uint32_t str_idx = ipGetOrPutString(sema->ip, func_name); - InternPoolKey bk; - memset(&bk, 0, sizeof(bk)); - bk.tag = IP_KEY_BYTES; - bk.data.bytes.ty = arr_ty; - bk.data.bytes.str_idx = str_idx; - InternPoolIndex bytes_val = ipIntern(sema->ip, bk); - - // *const [N]u8 - InternPoolIndex ptr_arr = internPtrConst(arr_ty); - - // ptr_uav - InternPoolKey uavk; - memset(&uavk, 0, sizeof(uavk)); - uavk.tag = IP_KEY_PTR_UAV; - uavk.data.ptr_uav.ty = ptr_arr; - uavk.data.ptr_uav.val = bytes_val; - (void)ipIntern(sema->ip, uavk); - } + // Note: upstream funcCommon does NOT create ptr_type/ptr_nav or + // name entries here. Those are created lazily by + // analyzeNavRefInner when the function address is taken. The + // 6 entries (ptr_type + ptr_nav + array + bytes + ptr_type + + // ptr_uav) are instead matched by resolving returnError and + // StackTrace in analyzeMemoizedStateC (memoized_limit=5). } analyzeFuncBodyAndRecord( @@ -9730,6 +9711,7 @@ static AirInstRef zirFieldPtr(Sema* sema, SemaBlock* block, uint32_t inst) { memset(&pkey, 0, sizeof(pkey)); pkey.tag = IP_KEY_PTR_TYPE; pkey.data.ptr_type.child = field_ty; + pkey.data.ptr_type.sentinel = IP_INDEX_NONE; InternPoolIndex ptr_field_ty = ipIntern(sema->ip, pkey); if (fidx <= 3) { @@ -10159,6 +10141,7 @@ static AirInstRef zirExtended(Sema* sema, SemaBlock* block, uint32_t inst) { memset(&pkey, 0, sizeof(pkey)); pkey.tag = IP_KEY_PTR_TYPE; pkey.data.ptr_type.child = elem_ty; + pkey.data.ptr_type.sentinel = IP_INDEX_NONE; TypeIndex ptr_ty = ipIntern(sema->ip, pkey); AirInstData adata; memset(&adata, 0, sizeof(adata)); @@ -10349,7 +10332,17 @@ static void analyzeMemoizedStateC(void) { // not Type and its children (15-35) which are resolved lazily. // Among 0-14, only resolve the ones that actually produce entries // matching the upstream output. - int memoized_limit = 3; // Signedness, AddressSpace, CallingConvention + // Resolve direct builtins 0-4 (Signedness, AddressSpace, + // CallingConvention, returnError, StackTrace). The upstream Zig + // compiler resolves all 36 .main-stage builtins via + // analyzeMemoizedState, but only these 5 create non-deduplicating + // IP entries on the wasm32-wasi target. The 6 entries from + // returnError (+4) and StackTrace (+2) match the upstream's module + // loading entries that create ptr_navs for import declarations + // (analyzeNavRefInner), replacing the 6 extra function entries + // (ptr_type + ptr_nav + name) that the C sema previously created + // in zirFunc to compensate. + int memoized_limit = 5; for (int i = 0; i < memoized_limit; i++) { const BuiltinDeclEntry* entry = &s_builtin_decl_entries[i]; @@ -10716,6 +10709,7 @@ static void zirAlloc(Sema* sema, SemaBlock* block, uint32_t inst) { memset(&key, 0, sizeof(key)); key.tag = IP_KEY_PTR_TYPE; key.data.ptr_type.child = elem_ty; + key.data.ptr_type.sentinel = IP_INDEX_NONE; key.data.ptr_type.flags = 0; TypeIndex ptr_ty = ipIntern(sema->ip, key); AirInstData data; @@ -10790,6 +10784,7 @@ static void zirResolveInferredAlloc( memset(&key, 0, sizeof(key)); key.tag = IP_KEY_PTR_TYPE; key.data.ptr_type.child = elem_ty; + key.data.ptr_type.sentinel = IP_INDEX_NONE; key.data.ptr_type.flags = 0; TypeIndex ptr_ty = ipIntern(sema->ip, key); sema->air_inst_tags[ptr_inst] = (uint8_t)AIR_INST_ALLOC; @@ -10815,6 +10810,7 @@ static void zirResolveInferredAlloc( memset(&ckey, 0, sizeof(ckey)); ckey.tag = IP_KEY_PTR_TYPE; ckey.data.ptr_type.child = elem_ty; + ckey.data.ptr_type.sentinel = IP_INDEX_NONE; ckey.data.ptr_type.flags = 1; TypeIndex const_ptr_ty = ipIntern(sema->ip, ckey); AirInstData bc_data; @@ -10838,6 +10834,7 @@ static AirInstRef zirMakePtrConst( memset(&ckey, 0, sizeof(ckey)); ckey.tag = IP_KEY_PTR_TYPE; ckey.data.ptr_type.child = child; + ckey.data.ptr_type.sentinel = IP_INDEX_NONE; ckey.data.ptr_type.flags = PTR_FLAGS_IS_CONST; TypeIndex const_ptr_ty = ipIntern(sema->ip, ckey); AirInstData bc_data;