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>
The C parser uses OPT() macro which stores UINT32_MAX as the "none"
sentinel for optional AST node indices in extra_data. The rlExpr
(AstRlAnnotate) and exprRl functions were checking `!= 0` for these
fields, treating UINT32_MAX as a valid node index and causing segfaults.
Fixed optional field checks for fn_proto_one, fn_proto extra data
(param, align, addrspace, section, callconv), while cont_expr,
global_var_decl type_node, and slice_sentinel end_node.
Also added behavior test corpus files and FAIL: diagnostic to
the corpus test runner.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix multiple bugs found via the array_list.zig corpus test:
- Fix anytype param ref/index double-conversion (addStrTok returns
a ref, don't add ZIR_REF_START_INDEX again)
- Implement is_generic param tracking via is_used_or_discarded
pointer in ScopeLocalVal
- Fix globalVarDecl declaration src_line: use type_gz.decl_line
instead of ag->source_line (which was advanced by init expression)
- Fix cppcheck warning: remove redundant (0u << 2) in bitmask
- Implement fetchRemoveRefEntries and ret_param_refs in addFunc
- Add func_fancy case to buildHashSkipMask in test
- Fix valgrind: zero elem_val_imm padding, skip addNodeExtended
undefined small field, handle more padding-sensitive tags
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Consolidate the two separate test modules (test_mod via
lib/std/zig/zig0_test.zig + astgen_test_mod via stage0_test_root.zig)
into a single test module rooted at stage0_test_root.zig.
The zig0_test.zig bridge approach ran std's parser/tokenizer tests with
C comparison enabled, but the stage0/ test files already do the same
C-vs-Zig comparison directly via @cImport. The only "lost" tests are an
unnamed root test block and a Zig-only fuzz test — no zig0 coverage lost.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Consolidate the two separate test modules (test_mod via
lib/std/zig/zig0_test.zig + astgen_test_mod via stage0_test_root.zig)
into a single test module rooted at stage0_test_root.zig.
The zig0_test.zig bridge approach ran std's parser/tokenizer tests with
C comparison enabled, but the stage0/ test files already do the same
C-vs-Zig comparison directly via @cImport. The only "lost" tests are an
unnamed root test block and a Zig-only fuzz test — no zig0 coverage lost.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Implement assignDestructure() and assignDestructureMaybeDecls() with
RL_DESTRUCTURE result location, DestructureComponent types, rvalue
handling for validate_destructure/elem_val_imm/store_node, and array
init optimization.
- Fix tryResolvePrimitiveIdent to allow bit_count==0 (u0/i0 types) and
reject leading zeros (u01, i007).
- Add nodeIsTriviallyZero and slice_length optimization for
arr[start..][0..len] patterns in AST_NODE_SLICE and
AST_NODE_SLICE_SENTINEL cases.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- blockExpr: call rvalue on void result for unlabeled blocks, matching
upstream AstGen.zig:2431. This was causing a missing STORE_NODE when
empty blocks like {} were used as struct field values with pointer RL.
- identifierExpr: call rvalueNoCoercePreRef after LOAD in local_ptr case,
matching upstream AstGen.zig:8453-8454.
- Implement AST_NODE_ARRAY_MULT (** operator) with ArrayMul payload,
matching upstream AstGen.zig:774-785.
- Enable parser_test.zig and astgen_test.zig corpus tests.
- Enable combined corpus test (all 5 files pass).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Port switchExprErrUnion optimization for both catch and if patterns,
fix missing rvalue call in decl table lookup, fix identAsString
ordering for underscore error captures, and fill value_placeholder
with 0xaa to match upstream undefined pattern.
Enables corpus build.zig test.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add error capture scope to orelseCatchExpr (catch |err| now creates
a ScopeLocalVal for the captured error variable)
- Add @panic, @errorName, @field builtins
- Increase blockExprStmts scope arrays from 64 to 128 entries
(build.zig has 93 var decls in a single block)
corpus build.zig still skipped: needs switchExprErrUnion optimization
(catch |err| switch(err) pattern).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Valgrind doesn't support AVX-512 instructions (EVEX prefix 0x62).
The zig CC generates them for large struct copies on native x86_64
targets even at -O0 (e.g. vmovdqu64 with zmm registers).
Previously only avx512f was subtracted, which was insufficient —
the .evex512 feature (and other AVX-512 sub-features) also need
to be disabled to prevent EVEX-encoded 512-bit instructions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implement several interconnected features for function declarations:
- noalias_bits: Track which parameters have the noalias keyword by setting
corresponding bits in a uint32_t (supports up to 32 parameters)
- is_var_args: Detect ellipsis3 (...) token in parameter list
- is_noinline/has_inline_keyword: Detect noinline/inline modifiers
- callconv handling: Extract callconv_expr from fn_proto variants, create
cc_gz sub-block, emit builtin_value for explicit callconv() or inline
- func_fancy instruction: When any of cc_ref, is_var_args, noalias_bits,
or is_noinline are present, emit func_fancy instead of func/func_inferred
with the appropriate FuncFancy payload layout
- fn_var_args: Track in AstGenCtx for body code that checks it
- BuiltinValue constants: Add all ZIR_BUILTIN_VALUE_* defines to zir.h
- addBuiltinValue helper: Emit extended builtin_value instructions
Generic tracking (any_param_used, ret_ty_is_generic, ret_body_param_refs)
is not yet implemented as it requires is_used_or_discarded support in
ScopeLocalVal scope lookups.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Move rvalue calls inside builtinCall (all builtins now call rvalue
internally, matching upstream) and remove outer rvalue wrap from
call site
- Add rlResultTypeForCast that errors when no result type is available,
used by @bitCast, @intCast, @truncate, @ptrCast, @enumFromInt
- Fix @import to compute res_ty from result location instead of
hardcoding ZIR_REF_NONE
- Fix @embedFile to evaluate operand with coerced_ty=slice_const_u8_type
- Fix @cInclude/simpleCBuiltin to check c_import scope and use
comptimeExpr with coerced_ty=slice_const_u8_type
- Fix @cImport to pass actual block_result to ensure_result_used instead
of hardcoded ZIR_REF_VOID_VALUE
Not fixed: Issue 14 (ptrCast nested pointer cast collapsing) — upstream
routes @ptrCast through a dedicated ptrCast() function that walks nested
pointer cast builtins. Currently uses simple typeCast path only.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Port two missing features from upstream AstGen.zig varDecl:
1. Add reachableExprComptime (AstGen.zig:418-438) which wraps init
expressions in comptimeExpr when force_comptime is set, and checks
for noreturn results. Replace plain exprRl calls in all three varDecl
paths (const rvalue, const alloc, var) with reachableExprComptime.
2. Extract comptime_token by scanning backwards from mut_token (matching
Ast.zig fullVarDeclComponents). For const path, set force_comptime to
wrap init in comptime block. For var path, use comptime_token to set
is_comptime which selects alloc_comptime_mut/alloc_inferred_comptime_mut
tags and sets maybe_comptime on the scope.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Port two missing features from upstream AstGen.zig:
1. Handle identifier-named tests (decltest): when the token after `test`
is an identifier, set decl_id to DECL_ID_DECLTEST and record the
identifier string as the test name. Upstream performs full scope
resolution for validation which is skipped here.
2. Add `within_fn` field to AstGenCtx (mirrors AstGen.within_fn). Save,
set to true, and restore in both testDecl and fnDecl. This flag
propagates to maybe_generic on namespace scopes for container
declarations inside function/test bodies.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Port two missing features from upstream AstGen.zig ret() function:
1. Add any_defer_node field to GenZir (AstGen.zig:11812) to track
whether we're inside a defer expression. Set it in defer body
generation and propagate via makeSubBlock. retExpr now checks
this field and errors with "cannot return from defer expression"
(AstGen.zig:8127-8135). Also reorder retExpr checks to match
upstream: fn_block null check first, then any_defer_node check,
then emitDbgNode.
2. Add reachableExpr wrapper (AstGen.zig:408-416) that calls exprRl
and checks refIsNoReturn to detect unreachable code. Use it in
retExpr instead of plain exprRl for the return operand
(AstGen.zig:8185-8186). nameStratExpr is left as TODO since
containerDecl does not yet accept a name_strategy parameter.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add two fixes from audit of ptrTypeExpr against upstream AstGen.zig ptrType:
1. Reject `[*c]allowzero T` with a compile error matching upstream
(AstGen.zig:3840-3842). C pointers always allow address zero, so
the allowzero modifier is invalid on them.
2. Save source_offset/source_line/source_column before typeExpr and
restore them before evaluating each trailing expression (sentinel,
addrspace, align). This ensures correct debug info source locations
matching upstream (AstGen.zig:3844-3846, 3859-3861, 3876-3878,
3885-3887).
Issue 3 (addrspace RL using addBuiltinValue) is skipped as
addBuiltinValue is not yet implemented.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Port assignShift (AstGen.zig:3786) and assignShiftSat (AstGen.zig:3812)
from upstream, handling <<=, >>=, and <<|= operators as both statements
in blockExprStmts and expressions in exprRl. Previously these fell
through to SET_ERROR.
Add grouped_expression unwrapping loop in blockExprStmts (matching
AstGen.zig:2569-2630) so that parenthesized statements like `(x += 1)`
are correctly dispatched to assignment handlers instead of going through
the default unusedResultExpr path.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix three issues in the RL annotation pre-pass (rlExpr):
1. Label detection for `inline while`/`inline for` now accounts for
the `keyword_inline` token before checking for `identifier colon`,
matching upstream fullWhileComponents/fullForComponents logic.
2. `assign_destructure` now recurses into variable nodes and the value
expression with RL_RI_NONE, matching upstream behavior instead of
returning false without visiting sub-expressions.
3. `rlTokenIdentEqual` now handles @"..."-quoted identifiers by comparing
the quoted content rather than stopping at the `@` character, which
previously caused all @-quoted identifiers to compare as equal.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The exprRl function was wrapping blockExprExpr's return value in an
extra rvalue() call, but blockExprExpr already applies rvalue internally
for labeled blocks when need_result_rvalue=true. The upstream expr()
function at AstGen.zig:991 returns blockExpr's result directly without
extra rvalue wrapping. This could produce duplicate coercion/store
instructions for non-trivial result locations.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Port two missing checks from upstream AstGen.zig rvalueInner to the C
rvalue function:
1. isAlwaysVoid (Zir.zig:1343-1608): When the result refers to an
instruction that always produces void (e.g., dbg_stmt, store_node,
export, memcpy, etc.), replace the result with void_value before
proceeding. This prevents emitting unnecessary type coercions or
stores on always-void instructions.
2. endsWithNoReturn (AstGen.zig:11068): When the current GenZir block
ends with a noreturn instruction, return the result immediately
without emitting any rvalue instructions. This avoids emitting dead
ZIR instructions after noreturn.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Port the \u{NNNNNN} unicode escape parsing from upstream Zig's
string_literal.zig:parseEscapeSequence into both strLitAsString
(string literal decoding with UTF-8 encoding) and char_literal
(codepoint value extraction). Without this, \u escapes fell through
to the default branch which wrote a literal 'u' character, producing
incorrect ZIR string bytes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
BuiltinCall.Flags has ensure_result_used at bit 1, not bit 3 like
Call/FieldCall. Separate the case to use the correct bit.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three bugs found by auditing against upstream AstGen.zig/AstRlAnnotate.zig:
1. rlExpr: defer was recursing into nd.rhs (always 0) instead of nd.lhs
(the actual deferred expression), so the RL annotation pass never
visited defer bodies.
2. addEnsureResult: compile_error was missing from the noreturn
instruction list, causing spurious ensure_result_used instructions
to be emitted after @compileError calls.
3. blockExprExpr: force_comptime was derived from gz->is_comptime,
but upstream blockExpr always passes force_comptime=false to
labeledBlockExpr. This caused labeled blocks in comptime contexts
to incorrectly emit BLOCK_COMPTIME + BREAK_INLINE instead of
BLOCK + BREAK.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>