astgen: RL threading, labeled blocks, comptime block payload
Port several AstGen.zig patterns to C: - Thread ResultLoc through fullBodyExpr, ifExpr, switchExpr, callExpr, calleeExpr (for proper type coercion and decl_literal handling) - Add rlBr() and breakResultInfo() helpers mirroring upstream ri.br() and setBreakResultInfo - Implement labeled blocks with label on GenZir (matching upstream), restoreErrRetIndex before break, and break_result_info - Fix breakExpr to emit restoreErrRetIndex and use break_result_info for value/void breaks (AstGen.zig:2150-2237) - Add setBlockComptimeBody with comptime_reason field (was using setBlockBody which omitted the reason, causing wrong extra layout) - Add comptime_reason parameter to comptimeExpr with correct reasons for type/array_sentinel/switch_item/comptime_keyword contexts - Handle enum_literal in calleeExpr (decl_literal_no_coerce) - Fix decl_literal rvalue wrapping for ty/coerced_ty result locs All 5 corpus files now pass byte-by-byte ZIR comparison. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
515
astgen.c
515
astgen.c
@@ -159,6 +159,32 @@ static bool refTableFetchRemove(AstGenCtx* ag, uint32_t key, uint32_t* val) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// --- Result location (AstGen.zig:11808) ---
|
||||
// Simplified version of ResultInfo.Loc.
|
||||
// Defined here (before GenZir) because GenZir.break_result_info uses it.
|
||||
|
||||
typedef enum {
|
||||
RL_NONE, // Just compute the value.
|
||||
RL_REF, // Compute a pointer to the value.
|
||||
RL_DISCARD, // Compute but discard (emit ensure_result_non_error).
|
||||
RL_TY, // Coerce to specific type.
|
||||
RL_COERCED_TY, // Coerce to specific type, result is the coercion.
|
||||
RL_PTR, // Store result to typed pointer. data=alloc inst, src_node=node.
|
||||
RL_INFERRED_PTR, // Store result to inferred pointer. data=alloc inst.
|
||||
} ResultLocTag;
|
||||
|
||||
typedef struct {
|
||||
ResultLocTag tag;
|
||||
uint32_t data; // ZirInstRef: ty_inst for TY/COERCED_TY, alloc inst for
|
||||
// PTR/INFERRED_PTR.
|
||||
uint32_t src_node; // Only used for RL_PTR.
|
||||
} ResultLoc;
|
||||
|
||||
#define RL_NONE_VAL ((ResultLoc) { .tag = RL_NONE, .data = 0, .src_node = 0 })
|
||||
#define RL_REF_VAL ((ResultLoc) { .tag = RL_REF, .data = 0, .src_node = 0 })
|
||||
#define RL_DISCARD_VAL \
|
||||
((ResultLoc) { .tag = RL_DISCARD, .data = 0, .src_node = 0 })
|
||||
|
||||
// --- Scope types (AstGen.zig:11621-11768) ---
|
||||
|
||||
typedef enum {
|
||||
@@ -193,6 +219,10 @@ typedef struct {
|
||||
uint32_t instructions_top; // start index in shared array
|
||||
uint32_t break_block; // UINT32_MAX = none (AstGen.zig:11780)
|
||||
uint32_t continue_block; // UINT32_MAX = none (AstGen.zig:11784)
|
||||
// Label for labeled blocks (AstGen.zig:11800, 11869-11874).
|
||||
uint32_t label_token; // UINT32_MAX = no label
|
||||
uint32_t label_block_inst; // the BLOCK instruction index
|
||||
ResultLoc break_result_info; // RL for break values
|
||||
} GenZir;
|
||||
|
||||
// Scope.LocalVal (AstGen.zig:11682).
|
||||
@@ -283,6 +313,7 @@ static GenZir makeSubBlock(GenZir* parent, Scope* scope) {
|
||||
sub.instructions_top = parent->astgen->scratch_inst_len;
|
||||
sub.break_block = UINT32_MAX;
|
||||
sub.continue_block = UINT32_MAX;
|
||||
sub.label_token = UINT32_MAX;
|
||||
return sub;
|
||||
}
|
||||
|
||||
@@ -764,6 +795,25 @@ static void setTryBody(
|
||||
gzUnstack(gz);
|
||||
}
|
||||
|
||||
// Mirrors GenZir.setBlockComptimeBody (AstGen.zig:11972).
|
||||
// Like setBlockBody but prepends comptime_reason before body_len.
|
||||
// Asserts inst is a BLOCK_COMPTIME.
|
||||
static void setBlockComptimeBody(
|
||||
AstGenCtx* ag, GenZir* gz, uint32_t inst, uint32_t comptime_reason) {
|
||||
uint32_t raw_body_len = gzInstructionsLen(gz);
|
||||
const uint32_t* body = gzInstructionsSlice(gz);
|
||||
uint32_t body_len = countBodyLenAfterFixups(ag, body, raw_body_len);
|
||||
ensureExtraCapacity(ag, 2 + body_len);
|
||||
uint32_t payload_index = ag->extra_len;
|
||||
ag->extra[ag->extra_len++] = comptime_reason;
|
||||
ag->extra[ag->extra_len++] = body_len;
|
||||
for (uint32_t i = 0; i < raw_body_len; i++) {
|
||||
appendPossiblyRefdBodyInst(ag, body[i]);
|
||||
}
|
||||
ag->inst_datas[inst].pl_node.payload_index = payload_index;
|
||||
gzUnstack(gz);
|
||||
}
|
||||
|
||||
// Mirrors GenZir.addBreak (AstGen.zig:12623).
|
||||
// Creates a ZIR_INST_BREAK instruction.
|
||||
static uint32_t addBreak(GenZir* gz, ZirInstTag tag, uint32_t block_inst,
|
||||
@@ -1081,30 +1131,46 @@ static void writeImports(AstGenCtx* ag) {
|
||||
ag->extra[ZIR_EXTRA_IMPORTS] = imports_index;
|
||||
}
|
||||
|
||||
// --- Result location (AstGen.zig:11808) ---
|
||||
// Simplified version of ResultInfo.Loc.
|
||||
// ri.br() (AstGen.zig:274-282): convert coerced_ty to ty for branching.
|
||||
static inline ResultLoc rlBr(ResultLoc rl) {
|
||||
if (rl.tag == RL_COERCED_TY) {
|
||||
return (ResultLoc) { .tag = RL_TY, .data = rl.data, .src_node = 0 };
|
||||
}
|
||||
return rl;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
RL_NONE, // Just compute the value.
|
||||
RL_REF, // Compute a pointer to the value.
|
||||
RL_DISCARD, // Compute but discard (emit ensure_result_non_error).
|
||||
RL_TY, // Coerce to specific type.
|
||||
RL_COERCED_TY, // Coerce to specific type, result is the coercion.
|
||||
RL_PTR, // Store result to typed pointer. data=alloc inst, src_node=node.
|
||||
RL_INFERRED_PTR, // Store result to inferred pointer. data=alloc inst.
|
||||
} ResultLocTag;
|
||||
|
||||
typedef struct {
|
||||
ResultLocTag tag;
|
||||
uint32_t data; // ZirInstRef: ty_inst for TY/COERCED_TY, alloc inst for
|
||||
// PTR/INFERRED_PTR.
|
||||
uint32_t src_node; // Only used for RL_PTR.
|
||||
} ResultLoc;
|
||||
|
||||
#define RL_NONE_VAL ((ResultLoc) { .tag = RL_NONE, .data = 0, .src_node = 0 })
|
||||
#define RL_REF_VAL ((ResultLoc) { .tag = RL_REF, .data = 0, .src_node = 0 })
|
||||
#define RL_DISCARD_VAL \
|
||||
((ResultLoc) { .tag = RL_DISCARD, .data = 0, .src_node = 0 })
|
||||
// setBreakResultInfo (AstGen.zig:11905-11926): compute break result info
|
||||
// from parent RL. Converts coerced_ty → ty, discard → discard, else passes
|
||||
// through. For ptr/inferred_ptr, converts to ty/none respectively.
|
||||
static ResultLoc breakResultInfo(
|
||||
GenZir* gz, ResultLoc parent_rl, uint32_t node) {
|
||||
// First: compute block_ri (AstGen.zig:7639-7646).
|
||||
ResultLoc block_ri;
|
||||
switch (parent_rl.tag) {
|
||||
case RL_PTR: {
|
||||
uint32_t ptr_ty = addUnNode(gz, ZIR_INST_TYPEOF, parent_rl.data, node);
|
||||
uint32_t ty = addUnNode(gz, ZIR_INST_ELEM_TYPE, ptr_ty, node);
|
||||
block_ri = (ResultLoc) { .tag = RL_TY, .data = ty, .src_node = 0 };
|
||||
break;
|
||||
}
|
||||
case RL_INFERRED_PTR:
|
||||
block_ri = RL_NONE_VAL;
|
||||
break;
|
||||
default:
|
||||
block_ri = parent_rl;
|
||||
break;
|
||||
}
|
||||
// Then: setBreakResultInfo (AstGen.zig:11910-11925).
|
||||
switch (block_ri.tag) {
|
||||
case RL_COERCED_TY:
|
||||
return (
|
||||
ResultLoc) { .tag = RL_TY, .data = block_ri.data, .src_node = 0 };
|
||||
case RL_DISCARD:
|
||||
return RL_DISCARD_VAL;
|
||||
default:
|
||||
return block_ri;
|
||||
}
|
||||
}
|
||||
|
||||
// resultType (AstGen.zig:341-351): extract result type from RL.
|
||||
// Returns 0 if no result type available.
|
||||
@@ -1309,15 +1375,18 @@ static void emitDbgStmtForceCurrentIndex(
|
||||
static void emitDbgNode(GenZir* gz, uint32_t node);
|
||||
static void addDbgVar(
|
||||
GenZir* gz, ZirInstTag tag, uint32_t name, uint32_t inst);
|
||||
static void addEnsureResult(
|
||||
GenZir* gz, uint32_t maybe_unused_result, uint32_t statement);
|
||||
static void blockExprStmts(
|
||||
GenZir* gz, Scope* scope, const uint32_t* statements, uint32_t stmt_count);
|
||||
static uint32_t fullBodyExpr(GenZir* gz, Scope* scope, uint32_t node);
|
||||
static uint32_t fullBodyExpr(
|
||||
GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node);
|
||||
static uint32_t containerDecl(GenZir* gz, Scope* scope, uint32_t node);
|
||||
static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
|
||||
const uint32_t* members, uint32_t members_len);
|
||||
static uint32_t blockExprExpr(
|
||||
GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node);
|
||||
static uint32_t ifExpr(GenZir* gz, Scope* scope, uint32_t node);
|
||||
static uint32_t ifExpr(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node);
|
||||
static uint32_t forExpr(GenZir* gz, Scope* scope, uint32_t node);
|
||||
static uint32_t orelseCatchExpr(
|
||||
GenZir* gz, Scope* scope, uint32_t node, bool is_catch);
|
||||
@@ -1332,6 +1401,10 @@ static uint32_t whileExpr(GenZir* gz, Scope* scope, uint32_t node);
|
||||
static int nodeMayEvalToError(const Ast* tree, uint32_t node);
|
||||
static bool nodeMayAppendToErrorTrace(const Ast* tree, uint32_t node);
|
||||
static void addSaveErrRetIndex(GenZir* gz, uint32_t operand);
|
||||
static void addRestoreErrRetIndexBlock(
|
||||
GenZir* gz, uint32_t block_inst, uint32_t operand, uint32_t node);
|
||||
static void restoreErrRetIndex(GenZir* gz, uint32_t block_inst, ResultLoc rl,
|
||||
uint32_t node, uint32_t result);
|
||||
static uint32_t identAsString(AstGenCtx* ag, uint32_t token);
|
||||
static uint32_t lastToken(const Ast* tree, uint32_t node);
|
||||
static uint32_t simpleBinOp(
|
||||
@@ -1364,9 +1437,17 @@ static bool endsWithNoReturn(GenZir* gz) {
|
||||
|
||||
static uint32_t tryResolvePrimitiveIdent(GenZir* gz, uint32_t node);
|
||||
|
||||
// SimpleComptimeReason (std.zig:727) — values used in block_comptime payload.
|
||||
#define COMPTIME_REASON_TYPE 29
|
||||
#define COMPTIME_REASON_ARRAY_SENTINEL 30
|
||||
#define COMPTIME_REASON_ARRAY_LENGTH 33
|
||||
#define COMPTIME_REASON_COMPTIME_KEYWORD 53
|
||||
#define COMPTIME_REASON_SWITCH_ITEM 56
|
||||
|
||||
// Mirrors comptimeExpr2 (AstGen.zig:1982).
|
||||
// Evaluates a node in a comptime block_comptime scope.
|
||||
static uint32_t comptimeExpr(GenZir* gz, Scope* scope, uint32_t node) {
|
||||
static uint32_t comptimeExpr(
|
||||
GenZir* gz, Scope* scope, uint32_t node, uint32_t reason) {
|
||||
// Skip wrapping when already in comptime context (AstGen.zig:1990).
|
||||
if (gz->is_comptime)
|
||||
return expr(gz, scope, node);
|
||||
@@ -1430,7 +1511,7 @@ static uint32_t comptimeExpr(GenZir* gz, Scope* scope, uint32_t node) {
|
||||
uint32_t result = expr(&block_scope, scope, node);
|
||||
addBreak(&block_scope, ZIR_INST_BREAK_INLINE, block_inst, result,
|
||||
AST_NODE_OFFSET_NONE);
|
||||
setBlockBody(ag, &block_scope, block_inst);
|
||||
setBlockComptimeBody(ag, &block_scope, block_inst, reason);
|
||||
gzAppendInstruction(gz, block_inst);
|
||||
return block_inst + ZIR_REF_START_INDEX;
|
||||
}
|
||||
@@ -1438,7 +1519,7 @@ static uint32_t comptimeExpr(GenZir* gz, Scope* scope, uint32_t node) {
|
||||
// Mirrors typeExpr (AstGen.zig:1966).
|
||||
// Evaluates a type expression in comptime context.
|
||||
static uint32_t typeExpr(GenZir* gz, Scope* scope, uint32_t node) {
|
||||
return comptimeExpr(gz, scope, node);
|
||||
return comptimeExpr(gz, scope, node, COMPTIME_REASON_TYPE);
|
||||
}
|
||||
|
||||
// Mirrors numberLiteral (AstGen.zig:8544).
|
||||
@@ -1549,7 +1630,7 @@ static uint32_t cImportExpr(GenZir* gz, Scope* scope, uint32_t node) {
|
||||
block_scope.c_import = true;
|
||||
|
||||
// Use fullBodyExpr to inline unlabeled block body (AstGen.zig:10028).
|
||||
fullBodyExpr(&block_scope, &block_scope.base, body_node);
|
||||
fullBodyExpr(&block_scope, &block_scope.base, RL_NONE_VAL, body_node);
|
||||
|
||||
// ensure_result_used on gz (parent), not block_scope (AstGen.zig:10029).
|
||||
addUnNode(gz, ZIR_INST_ENSURE_RESULT_USED, ZIR_REF_VOID_VALUE, node);
|
||||
@@ -1638,10 +1719,12 @@ static uint32_t builtinCall(GenZir* gz, Scope* scope, uint32_t node) {
|
||||
uint32_t operand = expr(gz, scope, nd.lhs);
|
||||
return addUnNode(gz, ZIR_INST_INT_FROM_ENUM, operand, node);
|
||||
}
|
||||
// @tagName (AstGen.zig:9740).
|
||||
// @tagName (AstGen.zig:9407) — simpleUnOp with dbg_stmt.
|
||||
if (name_len == 7 && memcmp(source + name_start, "tagName", 7) == 0) {
|
||||
advanceSourceCursorToMainToken(ag, node);
|
||||
AstData nd = tree->nodes.datas[node];
|
||||
uint32_t operand = expr(gz, scope, nd.lhs);
|
||||
emitDbgStmt(gz, ag->source_line - gz->decl_line, ag->source_column);
|
||||
return addUnNode(gz, ZIR_INST_TAG_NAME, operand, node);
|
||||
}
|
||||
// @as (AstGen.zig:9388).
|
||||
@@ -1974,7 +2057,7 @@ static uint32_t arrayTypeExpr(GenZir* gz, Scope* scope, uint32_t node) {
|
||||
SET_ERROR(ag);
|
||||
return ZIR_REF_VOID_VALUE;
|
||||
}
|
||||
uint32_t len = comptimeExpr(gz, scope, nd.lhs);
|
||||
uint32_t len = comptimeExpr(gz, scope, nd.lhs, COMPTIME_REASON_TYPE);
|
||||
uint32_t elem_type = typeExpr(gz, scope, nd.rhs);
|
||||
return addPlNodeBin(gz, ZIR_INST_ARRAY_TYPE, node, len, elem_type);
|
||||
}
|
||||
@@ -2206,7 +2289,8 @@ typedef struct {
|
||||
uint32_t direct; // for direct calls: ref to callee
|
||||
} Callee;
|
||||
|
||||
static Callee calleeExpr(GenZir* gz, Scope* scope, uint32_t fn_expr_node) {
|
||||
static Callee calleeExpr(
|
||||
GenZir* gz, Scope* scope, ResultLoc rl, uint32_t fn_expr_node) {
|
||||
AstGenCtx* ag = gz->astgen;
|
||||
const Ast* tree = ag->tree;
|
||||
AstNodeTag tag = tree->nodes.tags[fn_expr_node];
|
||||
@@ -2236,6 +2320,24 @@ static Callee calleeExpr(GenZir* gz, Scope* scope, uint32_t fn_expr_node) {
|
||||
return c;
|
||||
}
|
||||
|
||||
// enum_literal callee: decl literal call syntax (AstGen.zig:10217-10233).
|
||||
if (tag == AST_NODE_ENUM_LITERAL) {
|
||||
uint32_t res_ty = rlResultType(gz, rl, fn_expr_node);
|
||||
if (res_ty != 0) {
|
||||
uint32_t str_index
|
||||
= identAsString(ag, tree->nodes.main_tokens[fn_expr_node]);
|
||||
uint32_t callee = addPlNodeBin(gz, ZIR_INST_DECL_LITERAL_NO_COERCE,
|
||||
fn_expr_node, res_ty, str_index);
|
||||
Callee c;
|
||||
c.is_field = false;
|
||||
c.direct = callee;
|
||||
c.obj_ptr = 0;
|
||||
c.field_name_start = 0;
|
||||
return c;
|
||||
}
|
||||
// No result type: fall through to expr with rl=none.
|
||||
}
|
||||
|
||||
// Default: direct call (AstGen.zig:10235).
|
||||
Callee c;
|
||||
c.is_field = false;
|
||||
@@ -2246,7 +2348,8 @@ static Callee calleeExpr(GenZir* gz, Scope* scope, uint32_t fn_expr_node) {
|
||||
}
|
||||
|
||||
// --- callExpr (AstGen.zig:10058) ---
|
||||
static uint32_t callExpr(GenZir* gz, Scope* scope, uint32_t node) {
|
||||
static uint32_t callExpr(
|
||||
GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) {
|
||||
AstGenCtx* ag = gz->astgen;
|
||||
const Ast* tree = ag->tree;
|
||||
AstNodeTag tag = tree->nodes.tags[node];
|
||||
@@ -2287,7 +2390,7 @@ static uint32_t callExpr(GenZir* gz, Scope* scope, uint32_t node) {
|
||||
return ZIR_REF_VOID_VALUE;
|
||||
}
|
||||
|
||||
Callee callee = calleeExpr(gz, scope, fn_expr_node);
|
||||
Callee callee = calleeExpr(gz, scope, rl, fn_expr_node);
|
||||
|
||||
// dbg_stmt before call (AstGen.zig:10078-10083).
|
||||
{
|
||||
@@ -2502,7 +2605,8 @@ static uint32_t structInitExpr(
|
||||
= tree->extra_data.arr[type_nd.rhs + 1];
|
||||
uint32_t elem_type
|
||||
= exprRl(gz, scope, RL_NONE_VAL, elem_type_node);
|
||||
uint32_t sentinel = comptimeExpr(gz, scope, sentinel_node);
|
||||
uint32_t sentinel = comptimeExpr(
|
||||
gz, scope, sentinel_node, COMPTIME_REASON_ARRAY_SENTINEL);
|
||||
uint32_t array_type_inst = addPlNodeTriple(gz,
|
||||
ZIR_INST_ARRAY_TYPE_SENTINEL, type_expr_node,
|
||||
ZIR_REF_ZERO_USIZE, elem_type, sentinel);
|
||||
@@ -2730,6 +2834,10 @@ static uint32_t exprRl(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) {
|
||||
if (res_ty != 0) {
|
||||
uint32_t res = addPlNodeBin(
|
||||
gz, ZIR_INST_DECL_LITERAL, node, res_ty, str_index);
|
||||
// decl_literal does the coercion for us (AstGen.zig:1001).
|
||||
// Only need rvalue for ptr/inferred_ptr/ref_coerced_ty.
|
||||
if (rl.tag == RL_TY || rl.tag == RL_COERCED_TY)
|
||||
return res;
|
||||
return rvalue(gz, rl, res, node);
|
||||
}
|
||||
return rvalue(gz, rl,
|
||||
@@ -2747,7 +2855,7 @@ static uint32_t exprRl(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) {
|
||||
case AST_NODE_CALL_ONE_COMMA:
|
||||
case AST_NODE_CALL:
|
||||
case AST_NODE_CALL_COMMA:
|
||||
return rvalue(gz, rl, callExpr(gz, scope, node), node);
|
||||
return rvalue(gz, rl, callExpr(gz, scope, rl, node), node);
|
||||
// struct_init (AstGen.zig:836-839).
|
||||
case AST_NODE_STRUCT_INIT_DOT_TWO:
|
||||
case AST_NODE_STRUCT_INIT_DOT_TWO_COMMA:
|
||||
@@ -2968,7 +3076,7 @@ static uint32_t exprRl(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) {
|
||||
// if (AstGen.zig:1013-1024).
|
||||
case AST_NODE_IF_SIMPLE:
|
||||
case AST_NODE_IF:
|
||||
return rvalue(gz, rl, ifExpr(gz, scope, node), node);
|
||||
return ifExpr(gz, scope, rlBr(rl), node);
|
||||
// for (AstGen.zig:1043-1060).
|
||||
case AST_NODE_FOR_SIMPLE:
|
||||
case AST_NODE_FOR:
|
||||
@@ -2984,68 +3092,87 @@ static uint32_t exprRl(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) {
|
||||
case AST_NODE_SUB_WRAP:
|
||||
return rvalue(
|
||||
gz, rl, simpleBinOp(gz, scope, node, ZIR_INST_SUBWRAP), node);
|
||||
// break (AstGen.zig:2358).
|
||||
// break (AstGen.zig:2150-2237).
|
||||
case AST_NODE_BREAK: {
|
||||
// break :label value
|
||||
// lhs = OptionalTokenIndex to label (UINT32_MAX if none),
|
||||
// rhs = node index for value (0 if none)
|
||||
uint32_t value_node = nd.rhs;
|
||||
uint32_t value_ref = ZIR_REF_VOID_VALUE;
|
||||
if (value_node != 0)
|
||||
value_ref = expr(gz, scope, value_node);
|
||||
uint32_t opt_break_label = nd.lhs; // UINT32_MAX = none
|
||||
uint32_t opt_rhs = nd.rhs; // 0 = none
|
||||
|
||||
// Find target block via scope chain (AstGen.zig:2359-2460).
|
||||
uint32_t label_tok = nd.lhs;
|
||||
if (label_tok != UINT32_MAX) {
|
||||
// Labeled break: walk scope chain for ScopeLabel.
|
||||
uint32_t label_name = identAsString(ag, label_tok);
|
||||
for (Scope* s = scope; s != NULL;) {
|
||||
if (s->tag == SCOPE_LABEL) {
|
||||
ScopeLabel* sl = (ScopeLabel*)s;
|
||||
if (sl->label_name == label_name) {
|
||||
addBreak(gz, ZIR_INST_BREAK, sl->block_inst, value_ref,
|
||||
(int32_t)node - (int32_t)gz->decl_node_index);
|
||||
return ZIR_REF_UNREACHABLE_VALUE;
|
||||
// Walk scope chain to find target block (AstGen.zig:2157-2187).
|
||||
for (Scope* s = scope; s != NULL;) {
|
||||
if (s->tag == SCOPE_GEN_ZIR) {
|
||||
GenZir* block_gz = (GenZir*)s;
|
||||
uint32_t block_inst = UINT32_MAX;
|
||||
if (opt_break_label != UINT32_MAX) {
|
||||
// Labeled break: check label on GenZir.
|
||||
if (block_gz->label_token != UINT32_MAX) {
|
||||
uint32_t break_name
|
||||
= identAsString(ag, opt_break_label);
|
||||
uint32_t label_name
|
||||
= identAsString(ag, block_gz->label_token);
|
||||
if (break_name == label_name)
|
||||
block_inst = block_gz->label_block_inst;
|
||||
}
|
||||
s = sl->parent;
|
||||
} else if (s->tag == SCOPE_GEN_ZIR) {
|
||||
s = ((GenZir*)s)->parent;
|
||||
} else if (s->tag == SCOPE_LOCAL_VAL) {
|
||||
s = ((ScopeLocalVal*)s)->parent;
|
||||
} else if (s->tag == SCOPE_LOCAL_PTR) {
|
||||
s = ((ScopeLocalPtr*)s)->parent;
|
||||
} else if (s->tag == SCOPE_DEFER_NORMAL
|
||||
|| s->tag == SCOPE_DEFER_ERROR) {
|
||||
s = ((ScopeDefer*)s)->parent;
|
||||
} else {
|
||||
break;
|
||||
// Unlabeled break: check break_block.
|
||||
if (block_gz->break_block != UINT32_MAX)
|
||||
block_inst = block_gz->break_block;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Unlabeled break: find innermost GenZir with break_block
|
||||
// (AstGen.zig:2435-2460).
|
||||
for (Scope* s = scope; s != NULL;) {
|
||||
if (s->tag == SCOPE_GEN_ZIR) {
|
||||
GenZir* gz2 = (GenZir*)s;
|
||||
if (gz2->break_block != UINT32_MAX) {
|
||||
addBreak(gz, ZIR_INST_BREAK, gz2->break_block,
|
||||
value_ref,
|
||||
(int32_t)node - (int32_t)gz->decl_node_index);
|
||||
return ZIR_REF_UNREACHABLE_VALUE;
|
||||
if (block_inst != UINT32_MAX) {
|
||||
// Found target (AstGen.zig:2188-2228).
|
||||
ZirInstTag break_tag = block_gz->is_comptime
|
||||
? ZIR_INST_BREAK_INLINE
|
||||
: ZIR_INST_BREAK;
|
||||
if (opt_rhs == 0) {
|
||||
// Void break (AstGen.zig:2195-2206).
|
||||
rvalue(gz, block_gz->break_result_info,
|
||||
ZIR_REF_VOID_VALUE, node);
|
||||
if (!block_gz->is_comptime) {
|
||||
ZirInstData rdata;
|
||||
rdata.un_node.operand
|
||||
= block_inst + ZIR_REF_START_INDEX;
|
||||
rdata.un_node.src_node = (int32_t)node
|
||||
- (int32_t)gz->decl_node_index;
|
||||
addInstruction(gz,
|
||||
ZIR_INST_RESTORE_ERR_RET_INDEX_UNCONDITIONAL,
|
||||
rdata);
|
||||
}
|
||||
addBreak(gz, break_tag, block_inst,
|
||||
ZIR_REF_VOID_VALUE, AST_NODE_OFFSET_NONE);
|
||||
} else {
|
||||
// Value break (AstGen.zig:2208-2228).
|
||||
uint32_t operand = exprRl(gz, scope,
|
||||
block_gz->break_result_info, opt_rhs);
|
||||
if (!block_gz->is_comptime)
|
||||
restoreErrRetIndex(gz, block_inst,
|
||||
block_gz->break_result_info, opt_rhs,
|
||||
operand);
|
||||
switch (block_gz->break_result_info.tag) {
|
||||
case RL_PTR:
|
||||
case RL_DISCARD:
|
||||
addBreak(gz, break_tag, block_inst,
|
||||
ZIR_REF_VOID_VALUE, AST_NODE_OFFSET_NONE);
|
||||
break;
|
||||
default:
|
||||
addBreak(gz, break_tag, block_inst, operand,
|
||||
(int32_t)opt_rhs
|
||||
- (int32_t)gz->decl_node_index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
s = gz2->parent;
|
||||
} else if (s->tag == SCOPE_LOCAL_VAL) {
|
||||
s = ((ScopeLocalVal*)s)->parent;
|
||||
} else if (s->tag == SCOPE_LOCAL_PTR) {
|
||||
s = ((ScopeLocalPtr*)s)->parent;
|
||||
} else if (s->tag == SCOPE_DEFER_NORMAL
|
||||
|| s->tag == SCOPE_DEFER_ERROR) {
|
||||
s = ((ScopeDefer*)s)->parent;
|
||||
} else if (s->tag == SCOPE_LABEL) {
|
||||
s = ((ScopeLabel*)s)->parent;
|
||||
} else {
|
||||
break;
|
||||
return ZIR_REF_UNREACHABLE_VALUE;
|
||||
}
|
||||
s = block_gz->parent;
|
||||
} else if (s->tag == SCOPE_LOCAL_VAL) {
|
||||
s = ((ScopeLocalVal*)s)->parent;
|
||||
} else if (s->tag == SCOPE_LOCAL_PTR) {
|
||||
s = ((ScopeLocalPtr*)s)->parent;
|
||||
} else if (s->tag == SCOPE_DEFER_NORMAL
|
||||
|| s->tag == SCOPE_DEFER_ERROR) {
|
||||
s = ((ScopeDefer*)s)->parent;
|
||||
} else if (s->tag == SCOPE_LABEL) {
|
||||
s = ((ScopeLabel*)s)->parent;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
SET_ERROR(ag);
|
||||
@@ -3109,7 +3236,8 @@ static uint32_t exprRl(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) {
|
||||
uint32_t result = exprRl(&block_scope, scope, ty_only_rl, body_node);
|
||||
addBreak(&block_scope, ZIR_INST_BREAK_INLINE, block_inst, result,
|
||||
(int32_t)body_node - (int32_t)gz->decl_node_index);
|
||||
setBlockBody(ag, &block_scope, block_inst);
|
||||
setBlockComptimeBody(
|
||||
ag, &block_scope, block_inst, COMPTIME_REASON_COMPTIME_KEYWORD);
|
||||
gzAppendInstruction(gz, block_inst);
|
||||
|
||||
// Apply rvalue to handle RL_PTR etc (AstGen.zig:2098).
|
||||
@@ -3118,7 +3246,7 @@ static uint32_t exprRl(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) {
|
||||
// switch (AstGen.zig:1072-1078).
|
||||
case AST_NODE_SWITCH:
|
||||
case AST_NODE_SWITCH_COMMA:
|
||||
return switchExpr(gz, scope, rl, node);
|
||||
return switchExpr(gz, scope, rlBr(rl), node);
|
||||
// while (AstGen.zig:1037-1042).
|
||||
case AST_NODE_WHILE_SIMPLE:
|
||||
case AST_NODE_WHILE_CONT:
|
||||
@@ -3278,43 +3406,59 @@ static uint32_t blockExprExpr(
|
||||
}
|
||||
|
||||
// Labeled block (AstGen.zig:2466-2536).
|
||||
// Create block instruction.
|
||||
uint32_t block_inst = makeBlockInst(ag, ZIR_INST_BLOCK, gz, node);
|
||||
bool force_comptime = gz->is_comptime;
|
||||
uint32_t label_token = lbrace - 2;
|
||||
|
||||
// Compute break result info (AstGen.zig:2484-2492).
|
||||
ResultLoc break_ri = breakResultInfo(gz, rl, node);
|
||||
bool need_result_rvalue = (break_ri.tag != rl.tag);
|
||||
|
||||
// Reserve the block instruction (AstGen.zig:2500-2501).
|
||||
ZirInstTag block_tag
|
||||
= force_comptime ? ZIR_INST_BLOCK_COMPTIME : ZIR_INST_BLOCK;
|
||||
uint32_t block_inst = makeBlockInst(ag, block_tag, gz, node);
|
||||
gzAppendInstruction(gz, block_inst);
|
||||
|
||||
GenZir block_scope = makeSubBlock(gz, scope);
|
||||
if (force_comptime)
|
||||
block_scope.is_comptime = true;
|
||||
// Set label on block_scope (AstGen.zig:2504-2508).
|
||||
block_scope.label_token = label_token;
|
||||
block_scope.label_block_inst = block_inst;
|
||||
block_scope.break_result_info = break_ri;
|
||||
|
||||
// Create label scope so break :label can find the block_inst.
|
||||
// These fields are read by breakExpr via scope chain walk.
|
||||
uint32_t label_token = lbrace - 2;
|
||||
ScopeLabel label_scope;
|
||||
label_scope.base.tag = SCOPE_LABEL;
|
||||
// cppcheck-suppress unreadVariable
|
||||
label_scope.parent = &block_scope.base;
|
||||
// cppcheck-suppress unreadVariable
|
||||
label_scope.label_name = identAsString(ag, label_token);
|
||||
// cppcheck-suppress unreadVariable
|
||||
label_scope.block_inst = block_inst;
|
||||
// Process statements (AstGen.zig:2512).
|
||||
blockExprStmts(&block_scope, &block_scope.base, statements, stmt_count);
|
||||
|
||||
// Process statements with label scope.
|
||||
blockExprStmts(&block_scope, &label_scope.base, statements, stmt_count);
|
||||
|
||||
// If we reach here without a break, the block evaluates to void.
|
||||
uint32_t gz_len = gzInstructionsLen(&block_scope);
|
||||
bool has_noreturn = false;
|
||||
if (gz_len > 0) {
|
||||
uint32_t last_inst = gzInstructionsSlice(&block_scope)[gz_len - 1];
|
||||
if (ag->inst_tags[last_inst] == ZIR_INST_BREAK
|
||||
|| ag->inst_tags[last_inst] == ZIR_INST_BREAK_INLINE) {
|
||||
has_noreturn = true;
|
||||
if (!endsWithNoReturn(&block_scope)) {
|
||||
// Emit restore_err_ret_index (AstGen.zig:2515).
|
||||
if (!force_comptime) {
|
||||
ZirInstData rdata;
|
||||
rdata.un_node.operand = block_inst + ZIR_REF_START_INDEX;
|
||||
rdata.un_node.src_node
|
||||
= (int32_t)node - (int32_t)gz->decl_node_index;
|
||||
addInstruction(
|
||||
gz, ZIR_INST_RESTORE_ERR_RET_INDEX_UNCONDITIONAL, rdata);
|
||||
}
|
||||
}
|
||||
if (!has_noreturn) {
|
||||
addBreak(&block_scope, ZIR_INST_BREAK, block_inst, ZIR_REF_VOID_VALUE,
|
||||
// rvalue + break (AstGen.zig:2516-2518).
|
||||
uint32_t result = rvalue(
|
||||
gz, block_scope.break_result_info, ZIR_REF_VOID_VALUE, node);
|
||||
ZirInstTag break_tag
|
||||
= force_comptime ? ZIR_INST_BREAK_INLINE : ZIR_INST_BREAK;
|
||||
addBreak(&block_scope, break_tag, block_inst, result,
|
||||
AST_NODE_OFFSET_NONE);
|
||||
}
|
||||
|
||||
setBlockBody(ag, &block_scope, block_inst);
|
||||
gzAppendInstruction(gz, block_inst);
|
||||
if (force_comptime) {
|
||||
setBlockComptimeBody(
|
||||
ag, &block_scope, block_inst, COMPTIME_REASON_COMPTIME_KEYWORD);
|
||||
} else {
|
||||
setBlockBody(ag, &block_scope, block_inst);
|
||||
}
|
||||
|
||||
// AstGen.zig:2531-2534.
|
||||
if (need_result_rvalue)
|
||||
return rvalue(gz, rl, block_inst + ZIR_REF_START_INDEX, node);
|
||||
return block_inst + ZIR_REF_START_INDEX;
|
||||
}
|
||||
|
||||
@@ -3471,9 +3615,10 @@ static uint32_t arrayInitDotExpr(
|
||||
// Handles if and if_simple expressions.
|
||||
// Pattern: block_scope with condbr → then/else branches → setCondBrPayload.
|
||||
|
||||
static uint32_t ifExpr(GenZir* gz, Scope* scope, uint32_t node) {
|
||||
static uint32_t ifExpr(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) {
|
||||
AstGenCtx* ag = gz->astgen;
|
||||
const Ast* tree = ag->tree;
|
||||
ResultLoc break_rl = breakResultInfo(gz, rl, node);
|
||||
AstNodeTag tag = tree->nodes.tags[node];
|
||||
AstData nd = tree->nodes.datas[node];
|
||||
|
||||
@@ -3576,7 +3721,7 @@ static uint32_t ifExpr(GenZir* gz, Scope* scope, uint32_t node) {
|
||||
|
||||
// Use fullBodyExpr for then body (AstGen.zig:6437).
|
||||
uint32_t then_result
|
||||
= fullBodyExpr(&then_scope, then_sub_scope, then_node);
|
||||
= fullBodyExpr(&then_scope, then_sub_scope, break_rl, then_node);
|
||||
if (!endsWithNoReturn(&then_scope)) {
|
||||
addBreak(&then_scope, ZIR_INST_BREAK, block_inst, then_result,
|
||||
(int32_t)then_node - (int32_t)gz->decl_node_index);
|
||||
@@ -3614,8 +3759,12 @@ static uint32_t ifExpr(GenZir* gz, Scope* scope, uint32_t node) {
|
||||
|
||||
// Use fullBodyExpr for else body (AstGen.zig:6478).
|
||||
uint32_t else_result
|
||||
= fullBodyExpr(&else_scope, else_sub_scope, else_node);
|
||||
= fullBodyExpr(&else_scope, else_sub_scope, break_rl, else_node);
|
||||
if (!endsWithNoReturn(&else_scope)) {
|
||||
// Restore error return index (AstGen.zig:6480-6482).
|
||||
if (do_err_trace)
|
||||
restoreErrRetIndex(
|
||||
&else_scope, block_inst, break_rl, else_node, else_result);
|
||||
addBreak(&else_scope, ZIR_INST_BREAK, block_inst, else_result,
|
||||
(int32_t)else_node - (int32_t)gz->decl_node_index);
|
||||
}
|
||||
@@ -3842,8 +3991,22 @@ static uint32_t forExpr(GenZir* gz, Scope* scope, uint32_t node) {
|
||||
}
|
||||
}
|
||||
|
||||
// Execute body (AstGen.zig:7047).
|
||||
fullBodyExpr(&then_scope, body_scope_parent, body_node);
|
||||
// Execute body (AstGen.zig:7047-7048).
|
||||
uint32_t then_result
|
||||
= fullBodyExpr(&then_scope, body_scope_parent, RL_NONE_VAL, body_node);
|
||||
addEnsureResult(&then_scope, then_result, body_node);
|
||||
|
||||
// dbg_stmt + dbg_empty_stmt (AstGen.zig:7052-7061).
|
||||
advanceSourceCursor(ag, tree->tokens.starts[lastToken(tree, body_node)]);
|
||||
emitDbgStmt(gz, ag->source_line - gz->decl_line, ag->source_column);
|
||||
{
|
||||
ZirInstData ext_data;
|
||||
ext_data.extended.opcode = (uint16_t)ZIR_EXT_DBG_EMPTY_STMT;
|
||||
ext_data.extended.small = 0;
|
||||
ext_data.extended.operand = 0;
|
||||
addInstruction(gz, ZIR_INST_EXTENDED, ext_data);
|
||||
}
|
||||
|
||||
addBreak(&then_scope, ZIR_INST_BREAK, cond_block, ZIR_REF_VOID_VALUE,
|
||||
AST_NODE_OFFSET_NONE);
|
||||
|
||||
@@ -3990,16 +4153,30 @@ static uint32_t whileExpr(GenZir* gz, Scope* scope, uint32_t node) {
|
||||
|
||||
// Execute body (AstGen.zig:6727-6730).
|
||||
emitDbgNode(&continue_scope, body_node);
|
||||
fullBodyExpr(&continue_scope, &continue_scope.base, body_node);
|
||||
fullBodyExpr(
|
||||
&continue_scope, &continue_scope.base, RL_NONE_VAL, body_node);
|
||||
|
||||
// Break continue_block if not noreturn (AstGen.zig:6733-6744).
|
||||
// Break continue_block if not noreturn (AstGen.zig:6735-6747).
|
||||
if (!endsWithNoReturn(&continue_scope)) {
|
||||
// dbg_stmt + dbg_empty_stmt (AstGen.zig:6737-6745).
|
||||
advanceSourceCursor(
|
||||
ag, tree->tokens.starts[lastToken(tree, body_node)]);
|
||||
fprintf(stderr, "DBG: forExpr dbg_empty_stmt, is_comptime=%d\n",
|
||||
gz->is_comptime);
|
||||
emitDbgStmt(gz, ag->source_line - gz->decl_line, ag->source_column);
|
||||
{
|
||||
ZirInstData ext_data;
|
||||
ext_data.extended.opcode = (uint16_t)ZIR_EXT_DBG_EMPTY_STMT;
|
||||
ext_data.extended.small = 0;
|
||||
ext_data.extended.operand = 0;
|
||||
addInstruction(gz, ZIR_INST_EXTENDED, ext_data);
|
||||
}
|
||||
addBreak(&continue_scope, ZIR_INST_BREAK, continue_block,
|
||||
ZIR_REF_VOID_VALUE, AST_NODE_OFFSET_NONE);
|
||||
}
|
||||
setBlockBody(ag, &continue_scope, continue_block);
|
||||
|
||||
// Break cond_block from then_scope (AstGen.zig:6746).
|
||||
// Break cond_block from then_scope (AstGen.zig:7064).
|
||||
addBreak(&then_scope, ZIR_INST_BREAK, cond_block, ZIR_REF_VOID_VALUE,
|
||||
AST_NODE_OFFSET_NONE);
|
||||
|
||||
@@ -4022,6 +4199,7 @@ static uint32_t switchExpr(
|
||||
GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) {
|
||||
AstGenCtx* ag = gz->astgen;
|
||||
const Ast* tree = ag->tree;
|
||||
ResultLoc break_rl = breakResultInfo(gz, rl, node);
|
||||
AstData nd = tree->nodes.datas[node];
|
||||
|
||||
// AST_NODE_SWITCH: lhs = condition node, rhs = extra index for SubRange.
|
||||
@@ -4125,12 +4303,12 @@ static uint32_t switchExpr(
|
||||
pay[pay_len++] = 1;
|
||||
prong_info_slot = pay_len++;
|
||||
AstData rng = tree->nodes.datas[cd.lhs];
|
||||
pay[pay_len++] = comptimeExpr(gz, scope, rng.lhs);
|
||||
pay[pay_len++] = comptimeExpr(gz, scope, rng.rhs);
|
||||
pay[pay_len++] = comptimeExpr(gz, scope, rng.lhs, COMPTIME_REASON_SWITCH_ITEM);
|
||||
pay[pay_len++] = comptimeExpr(gz, scope, rng.rhs, COMPTIME_REASON_SWITCH_ITEM);
|
||||
} else {
|
||||
// Scalar: [item_ref, prong_info, body...]
|
||||
pay[scalar_tbl + scalar_ci++] = hdr;
|
||||
pay[pay_len++] = comptimeExpr(gz, scope, cd.lhs);
|
||||
pay[pay_len++] = comptimeExpr(gz, scope, cd.lhs, COMPTIME_REASON_SWITCH_ITEM);
|
||||
prong_info_slot = pay_len++;
|
||||
}
|
||||
break;
|
||||
@@ -4162,7 +4340,7 @@ static uint32_t switchExpr(
|
||||
abort();
|
||||
pay = p;
|
||||
}
|
||||
pay[pay_len++] = comptimeExpr(gz, scope, item);
|
||||
pay[pay_len++] = comptimeExpr(gz, scope, item, COMPTIME_REASON_SWITCH_ITEM);
|
||||
}
|
||||
}
|
||||
// Range pairs.
|
||||
@@ -4177,8 +4355,8 @@ static uint32_t switchExpr(
|
||||
abort();
|
||||
pay = p;
|
||||
}
|
||||
pay[pay_len++] = comptimeExpr(gz, scope, rng.lhs);
|
||||
pay[pay_len++] = comptimeExpr(gz, scope, rng.rhs);
|
||||
pay[pay_len++] = comptimeExpr(gz, scope, rng.lhs, COMPTIME_REASON_SWITCH_ITEM);
|
||||
pay[pay_len++] = comptimeExpr(gz, scope, rng.rhs, COMPTIME_REASON_SWITCH_ITEM);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -4195,7 +4373,9 @@ static uint32_t switchExpr(
|
||||
if (ag->fn_ret_ty != 0 && nodeMayAppendToErrorTrace(tree, cond_node))
|
||||
addSaveErrRetIndex(&case_scope, ZIR_REF_NONE);
|
||||
|
||||
uint32_t result = exprRl(&case_scope, &case_scope.base, rl, body_node);
|
||||
// Use fullBodyExpr to process body inline (AstGen.zig:8009).
|
||||
uint32_t result
|
||||
= fullBodyExpr(&case_scope, &case_scope.base, break_rl, body_node);
|
||||
if (!endsWithNoReturn(&case_scope)) {
|
||||
addBreak(&case_scope, ZIR_INST_BREAK, switch_inst, result,
|
||||
(int32_t)body_node - (int32_t)gz->decl_node_index);
|
||||
@@ -4551,6 +4731,52 @@ static void addSaveErrRetIndex(GenZir* gz, uint32_t operand) {
|
||||
addInstruction(gz, ZIR_INST_SAVE_ERR_RET_INDEX, data);
|
||||
}
|
||||
|
||||
// --- addRestoreErrRetIndexBlock (AstGen.zig:12607-12614) ---
|
||||
// Emits extended RESTORE_ERR_RET_INDEX with block target (if_non_error
|
||||
// condition). Payload: src_node, block_ref, operand.
|
||||
static void addRestoreErrRetIndexBlock(
|
||||
GenZir* gz, uint32_t block_inst, uint32_t operand, uint32_t node) {
|
||||
AstGenCtx* ag = gz->astgen;
|
||||
ensureExtraCapacity(ag, 3);
|
||||
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++] = block_inst + ZIR_REF_START_INDEX;
|
||||
ag->extra[ag->extra_len++] = operand;
|
||||
|
||||
ZirInstData ext_data;
|
||||
ext_data.extended.opcode = (uint16_t)ZIR_EXT_RESTORE_ERR_RET_INDEX;
|
||||
ext_data.extended.small = 0;
|
||||
ext_data.extended.operand = payload_index;
|
||||
addInstruction(gz, ZIR_INST_EXTENDED, ext_data);
|
||||
}
|
||||
|
||||
// --- restoreErrRetIndex (AstGen.zig:2121-2148) ---
|
||||
// Emits restore_err_ret_index for block target based on nodeMayEvalToError.
|
||||
static void restoreErrRetIndex(GenZir* gz, uint32_t block_inst, ResultLoc rl,
|
||||
uint32_t node, uint32_t result) {
|
||||
const Ast* tree = gz->astgen->tree;
|
||||
int eval = nodeMayEvalToError(tree, node);
|
||||
if (eval == EVAL_TO_ERROR_ALWAYS)
|
||||
return; // never restore/pop
|
||||
uint32_t op;
|
||||
if (eval == EVAL_TO_ERROR_NEVER) {
|
||||
op = ZIR_REF_NONE; // always restore/pop
|
||||
} else {
|
||||
// EVAL_TO_ERROR_MAYBE
|
||||
// Simplified: without ri.ctx, treat non-ptr RL as result
|
||||
// (AstGen.zig:2131-2144).
|
||||
if (rl.tag == RL_PTR) {
|
||||
op = addUnNode(gz, ZIR_INST_LOAD, rl.data, node);
|
||||
} else if (rl.tag == RL_INFERRED_PTR) {
|
||||
op = ZIR_REF_NONE;
|
||||
} else {
|
||||
op = result;
|
||||
}
|
||||
}
|
||||
addRestoreErrRetIndexBlock(gz, block_inst, op, node);
|
||||
}
|
||||
|
||||
// --- varDecl (AstGen.zig:3189) ---
|
||||
// Handles local const/var declarations. Returns new scope with the variable.
|
||||
// scope_out: set to new scope if variable is added; unchanged otherwise.
|
||||
@@ -5030,7 +5256,8 @@ static void blockExprStmts(GenZir* gz, Scope* scope,
|
||||
// statements inline without creating a BLOCK instruction (unlike blockExprExpr
|
||||
// which wraps in BLOCK). Returns the result ref.
|
||||
|
||||
static uint32_t fullBodyExpr(GenZir* gz, Scope* scope, uint32_t node) {
|
||||
static uint32_t fullBodyExpr(
|
||||
GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) {
|
||||
const Ast* tree = gz->astgen->tree;
|
||||
AstNodeTag tag = tree->nodes.tags[node];
|
||||
|
||||
@@ -5062,7 +5289,7 @@ static uint32_t fullBodyExpr(GenZir* gz, Scope* scope, uint32_t node) {
|
||||
}
|
||||
default:
|
||||
// Not a block — treat as single expression (AstGen.zig:2369).
|
||||
return expr(gz, scope, node);
|
||||
return exprRl(gz, scope, rl, node);
|
||||
}
|
||||
|
||||
// Check if labeled (AstGen.zig:2373-2377).
|
||||
@@ -5072,13 +5299,13 @@ static uint32_t fullBodyExpr(GenZir* gz, Scope* scope, uint32_t node) {
|
||||
&& tree->tokens.tags[lbrace - 2] == TOKEN_IDENTIFIER);
|
||||
if (is_labeled) {
|
||||
// Labeled blocks need a proper block instruction.
|
||||
return blockExprExpr(gz, scope, RL_NONE_VAL, node);
|
||||
return blockExprExpr(gz, scope, rl, node);
|
||||
}
|
||||
|
||||
// Unlabeled block: process statements inline (AstGen.zig:2380-2383).
|
||||
GenZir sub_gz = makeSubBlock(gz, scope);
|
||||
blockExprStmts(&sub_gz, &sub_gz.base, statements, stmt_count);
|
||||
return ZIR_REF_VOID_VALUE;
|
||||
return rvalue(gz, rl, ZIR_REF_VOID_VALUE, node);
|
||||
}
|
||||
|
||||
// --- lastToken (Ast.zig:874) ---
|
||||
@@ -5919,7 +6146,7 @@ static void testDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
uint32_t lbrace_column = ag->source_column;
|
||||
|
||||
// Process test body (AstGen.zig:4864).
|
||||
fullBodyExpr(&fn_block, &fn_block.base, body_node);
|
||||
fullBodyExpr(&fn_block, &fn_block.base, RL_NONE_VAL, body_node);
|
||||
|
||||
// If we hit unimplemented features, bail out.
|
||||
if (ag->has_compile_errors)
|
||||
@@ -6263,7 +6490,7 @@ static void fnDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
uint32_t lbrace_line = ag->source_line - decl_line;
|
||||
uint32_t lbrace_column = ag->source_column;
|
||||
|
||||
fullBodyExpr(&body_gz, params_scope, body_node);
|
||||
fullBodyExpr(&body_gz, params_scope, RL_NONE_VAL, body_node);
|
||||
|
||||
ag->fn_ret_ty = prev_fn_ret_ty;
|
||||
|
||||
|
||||
@@ -609,7 +609,7 @@ fn expectEqualData(
|
||||
fn zirMatches(gpa: Allocator, ref: Zir, got: c.Zir) bool {
|
||||
const ref_len: u32 = @intCast(ref.instructions.len);
|
||||
if (ref_len != got.inst_len) {
|
||||
//std.debug.print(" inst_len: ref={d} got={d}\n", .{ ref_len, got.inst_len });
|
||||
std.debug.print(" inst_len: ref={d} got={d}\n", .{ ref_len, got.inst_len });
|
||||
}
|
||||
|
||||
const ref_tags = ref.instructions.items(.tag);
|
||||
@@ -624,21 +624,26 @@ fn zirMatches(gpa: Allocator, ref: Zir, got: c.Zir) bool {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (first_tag_mismatch) |_| {
|
||||
//const start = if (ftm > 5) ftm - 5 else 0;
|
||||
//const end = @min(ftm + 10, min_len);
|
||||
//std.debug.print(" first tag mismatch at inst[{d}]:\n", .{ftm});
|
||||
//for (start..end) |i| {
|
||||
// const ref_tag: u8 = @intFromEnum(ref_tags[i]);
|
||||
// const got_tag: u8 = @intCast(got.inst_tags[i]);
|
||||
// const marker: u8 = if (i == ftm) '>' else ' ';
|
||||
// std.debug.print(" {c} [{d}] ref_tag={d} got_tag={d}\n", .{ marker, i, ref_tag, got_tag });
|
||||
//}
|
||||
if (first_tag_mismatch) |ftm| {
|
||||
const start = if (ftm > 5) ftm - 5 else 0;
|
||||
const end = @min(ftm + 10, min_len);
|
||||
std.debug.print(" first tag mismatch at inst[{d}]:\n", .{ftm});
|
||||
for (start..end) |i| {
|
||||
const ref_tag: u8 = @intFromEnum(ref_tags[i]);
|
||||
const got_tag: u8 = @intCast(got.inst_tags[i]);
|
||||
const marker: u8 = if (i == ftm) '>' else ' ';
|
||||
if (ref_tag == 251) {
|
||||
const ext_op: u16 = @intFromEnum(ref_datas[i].extended.opcode);
|
||||
std.debug.print(" {c} [{d}] ref_tag=251(EXT:{d}) got_tag={d}\n", .{ marker, i, ext_op, got_tag });
|
||||
} else {
|
||||
std.debug.print(" {c} [{d}] ref_tag={d} got_tag={d}\n", .{ marker, i, ref_tag, got_tag });
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
for (0..min_len) |i| {
|
||||
if (!dataMatches(ref_tags[i], ref_datas[i], got.inst_datas[i])) {
|
||||
//std.debug.print(" inst_datas[{d}] mismatch (tag={d})\n", .{ i, @as(u8, @intFromEnum(ref_tags[i])) });
|
||||
std.debug.print(" inst_datas[{d}] mismatch (tag={d})\n", .{ i, @as(u8, @intFromEnum(ref_tags[i])) });
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -646,7 +651,7 @@ fn zirMatches(gpa: Allocator, ref: Zir, got: c.Zir) bool {
|
||||
|
||||
const ref_extra_len: u32 = @intCast(ref.extra.len);
|
||||
if (ref_extra_len != got.extra_len) {
|
||||
//std.debug.print(" extra_len: ref={d} got={d}\n", .{ ref_extra_len, got.extra_len });
|
||||
std.debug.print(" extra_len: ref={d} got={d}\n", .{ ref_extra_len, got.extra_len });
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -656,19 +661,19 @@ fn zirMatches(gpa: Allocator, ref: Zir, got: c.Zir) bool {
|
||||
for (0..ref_extra_len) |i| {
|
||||
if (skip[i]) continue;
|
||||
if (ref.extra[i] != got.extra[i]) {
|
||||
//std.debug.print(" extra[{d}]: ref=0x{x:0>8} got=0x{x:0>8}\n", .{ i, ref.extra[i], got.extra[i] });
|
||||
std.debug.print(" extra[{d}]: ref=0x{x:0>8} got=0x{x:0>8}\n", .{ i, ref.extra[i], got.extra[i] });
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const ref_sb_len: u32 = @intCast(ref.string_bytes.len);
|
||||
if (ref_sb_len != got.string_bytes_len) {
|
||||
//std.debug.print(" string_bytes_len: ref={d} got={d}\n", .{ ref_sb_len, got.string_bytes_len });
|
||||
std.debug.print(" string_bytes_len: ref={d} got={d}\n", .{ ref_sb_len, got.string_bytes_len });
|
||||
return false;
|
||||
}
|
||||
for (0..ref_sb_len) |i| {
|
||||
if (ref.string_bytes[i] != got.string_bytes[i]) {
|
||||
//std.debug.print(" string_bytes[{d}]: ref=0x{x:0>2} got=0x{x:0>2}\n", .{ i, ref.string_bytes[i], got.string_bytes[i] });
|
||||
std.debug.print(" string_bytes[{d}]: ref=0x{x:0>2} got=0x{x:0>2}\n", .{ i, ref.string_bytes[i], got.string_bytes[i] });
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -778,17 +783,16 @@ fn corpusCheck(gpa: Allocator, name: []const u8, source: [:0]const u8) enum { pa
|
||||
defer c.zirDeinit(&c_zir);
|
||||
|
||||
if (c_zir.has_compile_errors) {
|
||||
//std.debug.print(" -> has_compile_errors\n", .{});
|
||||
std.debug.print(" {s} -> has_compile_errors\n", .{name});
|
||||
return .skip;
|
||||
}
|
||||
|
||||
if (zirMatches(gpa, ref_zir, c_zir)) {
|
||||
return .pass;
|
||||
} else {
|
||||
//std.debug.print(" -> zir mismatch\n", .{});
|
||||
std.debug.print(" {s} -> zir mismatch\n", .{name});
|
||||
return .skip;
|
||||
}
|
||||
_ = name;
|
||||
}
|
||||
|
||||
test "astgen: corpus" {
|
||||
|
||||
Reference in New Issue
Block a user