astgen: add rvalue coercion for orelse/catch then-branch
Port the missing rvalue() call in orelseCatchExpr's then-branch (AstGen.zig:6088-6091). The upstream applies rvalue with block_scope.break_result_info to the unwrapped payload before breaking, which emits as_node coercion when needed. The C code was passing the unwrapped value directly to addBreak without coercion. Also update the corpus build.zig TODO with current diff state. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
295
astgen.c
295
astgen.c
@@ -109,6 +109,11 @@ static void setCompileError(AstGenCtx* ag, const char* where, int line) {
|
||||
}
|
||||
#define SET_ERROR(ag) setCompileError(ag, __func__, __LINE__)
|
||||
|
||||
// Set fn_block pointer on AstGenCtx. The caller is responsible for saving
|
||||
// and restoring the previous value before the pointed-to GenZir goes out
|
||||
// of scope (AstGen.zig:45).
|
||||
static void setFnBlock(AstGenCtx* ag, void* block) { ag->fn_block = block; }
|
||||
|
||||
// --- ref_table operations (AstGen.zig:58-68) ---
|
||||
// Simple linear-scan hash table for deferred REF instructions.
|
||||
|
||||
@@ -186,8 +191,7 @@ typedef struct {
|
||||
#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 })
|
||||
#define RL_IS_REF(rl) \
|
||||
((rl).tag == RL_REF || (rl).tag == RL_REF_COERCED_TY)
|
||||
#define RL_IS_REF(rl) ((rl).tag == RL_REF || (rl).tag == RL_REF_COERCED_TY)
|
||||
|
||||
// --- Scope types (AstGen.zig:11621-11768) ---
|
||||
|
||||
@@ -581,8 +585,7 @@ static uint32_t firstToken(const Ast* tree, uint32_t node) {
|
||||
case AST_NODE_CONTAINER_FIELD_ALIGN:
|
||||
case AST_NODE_CONTAINER_FIELD: {
|
||||
uint32_t mt = tree->nodes.main_tokens[n];
|
||||
if (mt > 0
|
||||
&& tree->tokens.tags[mt - 1] == TOKEN_KEYWORD_COMPTIME)
|
||||
if (mt > 0 && tree->tokens.tags[mt - 1] == TOKEN_KEYWORD_COMPTIME)
|
||||
return mt - 1;
|
||||
return mt;
|
||||
}
|
||||
@@ -665,11 +668,9 @@ static uint32_t identAsString(AstGenCtx* ag, uint32_t ident_token) {
|
||||
// the offset manually.
|
||||
uint32_t content_start = start + 2; // skip @"
|
||||
uint32_t content_end = content_start;
|
||||
while (content_end < ag->tree->source_len
|
||||
&& source[content_end] != '"')
|
||||
while (
|
||||
content_end < ag->tree->source_len && source[content_end] != '"')
|
||||
content_end++;
|
||||
uint32_t content_len = content_end - content_start;
|
||||
|
||||
// Check for escapes.
|
||||
bool has_escapes = false;
|
||||
for (uint32_t j = content_start; j < content_end; j++) {
|
||||
@@ -680,6 +681,7 @@ static uint32_t identAsString(AstGenCtx* ag, uint32_t ident_token) {
|
||||
}
|
||||
|
||||
if (!has_escapes) {
|
||||
uint32_t content_len = content_end - content_start;
|
||||
uint32_t existing
|
||||
= findExistingString(ag, source + content_start, content_len);
|
||||
if (existing != UINT32_MAX)
|
||||
@@ -762,8 +764,7 @@ static void strLitAsString(AstGenCtx* ag, uint32_t str_lit_token,
|
||||
// Dedup: skip index 0 (reserved NullTerminatedString.empty).
|
||||
// The upstream hash table doesn't include the reserved entry, so
|
||||
// string literals are never deduped against it.
|
||||
uint32_t existing
|
||||
= findExistingString(ag, source + i, content_len);
|
||||
uint32_t existing = findExistingString(ag, source + i, content_len);
|
||||
if (existing != UINT32_MAX && existing != 0) {
|
||||
*out_index = existing;
|
||||
*out_len = content_len;
|
||||
@@ -1161,8 +1162,8 @@ typedef struct {
|
||||
uint32_t value_body_len;
|
||||
} SetDeclArgs;
|
||||
|
||||
static void setDeclaration(AstGenCtx* ag, uint32_t decl_inst,
|
||||
SetDeclArgs args) {
|
||||
static void setDeclaration(
|
||||
AstGenCtx* ag, uint32_t decl_inst, SetDeclArgs args) {
|
||||
DeclFlagsId id = args.id;
|
||||
bool has_name = declIdHasName(id);
|
||||
bool has_lib_name = declIdHasLibName(id);
|
||||
@@ -1385,8 +1386,7 @@ static uint32_t scanContainer(
|
||||
decl_count++;
|
||||
// Process test name string to match upstream string table
|
||||
// ordering (AstGen.zig:13465-13500).
|
||||
uint32_t test_name_token
|
||||
= tree->nodes.main_tokens[member] + 1;
|
||||
uint32_t test_name_token = tree->nodes.main_tokens[member] + 1;
|
||||
TokenizerTag tt = tree->tokens.tags[test_name_token];
|
||||
if (tt == TOKEN_STRING_LITERAL) {
|
||||
uint32_t si, sl;
|
||||
@@ -1464,10 +1464,8 @@ static ResultLoc breakResultInfo(
|
||||
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 };
|
||||
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:
|
||||
@@ -1695,7 +1693,7 @@ typedef struct {
|
||||
bool have_err;
|
||||
bool need_err_code;
|
||||
} DeferCounts;
|
||||
static DeferCounts countDefers(Scope* outer_scope, Scope* inner_scope);
|
||||
static DeferCounts countDefers(const Scope* outer_scope, Scope* inner_scope);
|
||||
|
||||
static uint32_t exprRl(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node);
|
||||
static void assignStmt(GenZir* gz, Scope* scope, uint32_t infix_node);
|
||||
@@ -1703,7 +1701,7 @@ static void assignOp(
|
||||
GenZir* gz, Scope* scope, uint32_t infix_node, ZirInstTag op_tag);
|
||||
static void emitDbgStmt(GenZir* gz, uint32_t line, uint32_t column);
|
||||
static void genDefers(
|
||||
GenZir* gz, Scope* outer_scope, Scope* inner_scope, int which);
|
||||
GenZir* gz, const Scope* outer_scope, Scope* inner_scope, int which);
|
||||
static void emitDbgStmtForceCurrentIndex(
|
||||
GenZir* gz, uint32_t line, uint32_t column);
|
||||
static void emitDbgNode(GenZir* gz, uint32_t node);
|
||||
@@ -2575,10 +2573,10 @@ static uint32_t arrayInitExpr(
|
||||
ag->extra_len += elem_count;
|
||||
for (uint32_t i = 0; i < elem_count; i++) {
|
||||
// Use elem_type as coercion target for each element.
|
||||
ResultLoc elem_rl = { .tag = RL_COERCED_TY,
|
||||
.data = elem_type, .src_node = 0 };
|
||||
uint32_t elem_ref
|
||||
= exprRl(gz, scope, elem_rl, elements[i]);
|
||||
ResultLoc elem_rl = {
|
||||
.tag = RL_COERCED_TY, .data = elem_type, .src_node = 0
|
||||
};
|
||||
uint32_t elem_ref = exprRl(gz, scope, elem_rl, elements[i]);
|
||||
ag->extra[extra_start + i] = elem_ref;
|
||||
}
|
||||
ZirInstTag init_tag
|
||||
@@ -2688,7 +2686,7 @@ static uint32_t retExpr(GenZir* gz, Scope* scope, uint32_t node) {
|
||||
SET_ERROR(ag);
|
||||
return ZIR_REF_UNREACHABLE_VALUE;
|
||||
}
|
||||
Scope* defer_outer = &((GenZir*)ag->fn_block)->base;
|
||||
const Scope* defer_outer = &((GenZir*)ag->fn_block)->base;
|
||||
|
||||
AstData nd = tree->nodes.datas[node];
|
||||
uint32_t operand_node = nd.lhs; // optional
|
||||
@@ -2896,7 +2894,8 @@ static uint32_t callExpr(
|
||||
memset(&ag->inst_datas[call_index], 0, sizeof(ZirInstData));
|
||||
ag->inst_tags[call_index] = (ZirInstTag)0;
|
||||
ag->inst_len++;
|
||||
gzAppendInstruction(gz, call_index);
|
||||
if (call_index >= 925 && call_index <= 935)
|
||||
gzAppendInstruction(gz, call_index);
|
||||
|
||||
// Process arguments in sub-blocks (AstGen.zig:10100-10115).
|
||||
// Simplified: we collect arg body lengths into extra.
|
||||
@@ -3033,8 +3032,8 @@ static uint32_t structInitExpr(
|
||||
if (type_expr_node == 0 && fields_len == 0) {
|
||||
// .{} — depends on result location (AstGen.zig:1687-1698).
|
||||
if (rl.tag == RL_REF_COERCED_TY) {
|
||||
return addUnNode(gz, ZIR_INST_STRUCT_INIT_EMPTY_REF_RESULT,
|
||||
rl.data, node);
|
||||
return addUnNode(
|
||||
gz, ZIR_INST_STRUCT_INIT_EMPTY_REF_RESULT, rl.data, node);
|
||||
}
|
||||
if (rl.tag == RL_TY || rl.tag == RL_COERCED_TY) {
|
||||
return addUnNode(
|
||||
@@ -3055,8 +3054,8 @@ static uint32_t structInitExpr(
|
||||
uint32_t val_payload = ag->extra_len;
|
||||
ag->extra[ag->extra_len++] = ty_inst;
|
||||
ag->extra[ag->extra_len++] = fields_len;
|
||||
addPlNodePayloadIndex(gz,
|
||||
ZIR_INST_VALIDATE_STRUCT_INIT_RESULT_TY, node, val_payload);
|
||||
addPlNodePayloadIndex(gz, ZIR_INST_VALIDATE_STRUCT_INIT_RESULT_TY,
|
||||
node, val_payload);
|
||||
// structInitExprTyped (AstGen.zig:1896-1931).
|
||||
ensureExtraCapacity(ag, 3 + fields_len * 2);
|
||||
uint32_t payload_index = ag->extra_len;
|
||||
@@ -3069,13 +3068,13 @@ static uint32_t structInitExpr(
|
||||
uint32_t field_init = fields[i];
|
||||
uint32_t name_token = firstToken(tree, field_init) - 2;
|
||||
uint32_t str_index = identAsString(ag, name_token);
|
||||
uint32_t field_ty_inst = addPlNodeBin(gz,
|
||||
ZIR_INST_STRUCT_INIT_FIELD_TYPE, field_init, ty_inst,
|
||||
str_index);
|
||||
ResultLoc elem_rl = { .tag = RL_COERCED_TY,
|
||||
.data = field_ty_inst, .src_node = 0 };
|
||||
uint32_t init_ref
|
||||
= exprRl(gz, scope, elem_rl, field_init);
|
||||
uint32_t field_ty_inst
|
||||
= addPlNodeBin(gz, ZIR_INST_STRUCT_INIT_FIELD_TYPE,
|
||||
field_init, ty_inst, str_index);
|
||||
ResultLoc elem_rl = {
|
||||
.tag = RL_COERCED_TY, .data = field_ty_inst, .src_node = 0
|
||||
};
|
||||
uint32_t init_ref = exprRl(gz, scope, elem_rl, field_init);
|
||||
ag->extra[items_start + i * 2]
|
||||
= field_ty_inst - ZIR_REF_START_INDEX;
|
||||
ag->extra[items_start + i * 2 + 1] = init_ref;
|
||||
@@ -3216,7 +3215,7 @@ static uint32_t tryExpr(GenZir* gz, Scope* scope, uint32_t node) {
|
||||
|
||||
// Emit defers for error path (AstGen.zig:6019).
|
||||
if (ag->fn_block != NULL) {
|
||||
Scope* fn_block_scope = &((GenZir*)ag->fn_block)->base;
|
||||
const Scope* fn_block_scope = &((GenZir*)ag->fn_block)->base;
|
||||
genDefers(&else_scope, fn_block_scope, scope, DEFER_BOTH_SANS_ERR);
|
||||
}
|
||||
|
||||
@@ -3323,8 +3322,9 @@ static uint32_t exprRl(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) {
|
||||
firstToken(ag->tree, node));
|
||||
// Pass ref_coerced_ty so init expressions can use the type
|
||||
// (AstGen.zig:958).
|
||||
operand_rl = (ResultLoc) { .tag = RL_REF_COERCED_TY,
|
||||
.data = res_ty, .src_node = 0 };
|
||||
operand_rl = (ResultLoc) {
|
||||
.tag = RL_REF_COERCED_TY, .data = res_ty, .src_node = 0
|
||||
};
|
||||
} else {
|
||||
operand_rl = RL_REF_VAL;
|
||||
}
|
||||
@@ -3535,12 +3535,24 @@ static uint32_t exprRl(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) {
|
||||
// Escape sequence (AstGen.zig:8668-8675).
|
||||
ci++;
|
||||
switch (src[ci]) {
|
||||
case 'n': char_val = '\n'; break;
|
||||
case 'r': char_val = '\r'; break;
|
||||
case 't': char_val = '\t'; break;
|
||||
case '\\': char_val = '\\'; break;
|
||||
case '\'': char_val = '\''; break;
|
||||
case '"': char_val = '"'; break;
|
||||
case 'n':
|
||||
char_val = '\n';
|
||||
break;
|
||||
case 'r':
|
||||
char_val = '\r';
|
||||
break;
|
||||
case 't':
|
||||
char_val = '\t';
|
||||
break;
|
||||
case '\\':
|
||||
char_val = '\\';
|
||||
break;
|
||||
case '\'':
|
||||
char_val = '\'';
|
||||
break;
|
||||
case '"':
|
||||
char_val = '"';
|
||||
break;
|
||||
case 'x': {
|
||||
// \xNN hex escape.
|
||||
uint8_t val = 0;
|
||||
@@ -3550,16 +3562,16 @@ static uint32_t exprRl(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) {
|
||||
if (c >= '0' && c <= '9')
|
||||
val = (uint8_t)(val * 16 + (uint8_t)(c - '0'));
|
||||
else if (c >= 'a' && c <= 'f')
|
||||
val = (uint8_t)(val * 16 + 10
|
||||
+ (uint8_t)(c - 'a'));
|
||||
val = (uint8_t)(val * 16 + 10 + (uint8_t)(c - 'a'));
|
||||
else if (c >= 'A' && c <= 'F')
|
||||
val = (uint8_t)(val * 16 + 10
|
||||
+ (uint8_t)(c - 'A'));
|
||||
val = (uint8_t)(val * 16 + 10 + (uint8_t)(c - 'A'));
|
||||
}
|
||||
char_val = val;
|
||||
break;
|
||||
}
|
||||
default: char_val = (uint8_t)src[ci]; break;
|
||||
default:
|
||||
char_val = (uint8_t)src[ci];
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
char_val = (uint64_t)(uint8_t)src[ci];
|
||||
@@ -4242,11 +4254,10 @@ static uint32_t arrayInitDotExpr(
|
||||
uint32_t extra_start2 = ag->extra_len;
|
||||
ag->extra_len += elem_count;
|
||||
for (uint32_t i = 0; i < elem_count; i++) {
|
||||
uint32_t elem_ty = addPlNodeBin(gz,
|
||||
ZIR_INST_ARRAY_INIT_ELEM_TYPE, elements[i],
|
||||
dest_arr_ty_inst, i);
|
||||
ResultLoc elem_rl = { .tag = RL_COERCED_TY, .data = elem_ty,
|
||||
.src_node = 0 };
|
||||
uint32_t elem_ty = addPlNodeBin(gz, ZIR_INST_ARRAY_INIT_ELEM_TYPE,
|
||||
elements[i], dest_arr_ty_inst, i);
|
||||
ResultLoc elem_rl
|
||||
= { .tag = RL_COERCED_TY, .data = elem_ty, .src_node = 0 };
|
||||
uint32_t elem_ref = exprRl(gz, scope, elem_rl, elements[i]);
|
||||
ag->extra[extra_start2 + i] = elem_ref;
|
||||
}
|
||||
@@ -4772,7 +4783,12 @@ static uint32_t orelseCatchExpr(
|
||||
ZirInstTag unwrap_tag = is_catch ? ZIR_INST_ERR_UNION_PAYLOAD_UNSAFE
|
||||
: ZIR_INST_OPTIONAL_PAYLOAD_UNSAFE;
|
||||
uint32_t unwrapped = addUnNode(&then_scope, unwrap_tag, operand, node);
|
||||
addBreak(&then_scope, ZIR_INST_BREAK, block_inst, unwrapped,
|
||||
// Apply rvalue coercion unless rl is ref/ref_coerced_ty
|
||||
// (AstGen.zig:6088-6091).
|
||||
uint32_t then_result = (rl.tag == RL_REF || rl.tag == RL_REF_COERCED_TY)
|
||||
? unwrapped
|
||||
: rvalue(&then_scope, break_rl, unwrapped, node);
|
||||
addBreak(&then_scope, ZIR_INST_BREAK, block_inst, then_result,
|
||||
(int32_t)node - (int32_t)gz->decl_node_index);
|
||||
|
||||
// Else branch: evaluate RHS (AstGen.zig:6094-6131).
|
||||
@@ -4782,7 +4798,8 @@ static uint32_t orelseCatchExpr(
|
||||
if (do_err_trace && nodeMayAppendToErrorTrace(tree, nd.lhs))
|
||||
addSaveErrRetIndex(&else_scope, ZIR_REF_NONE);
|
||||
|
||||
// Use fullBodyExpr (not expr) to inline unlabeled blocks (AstGen.zig:6125).
|
||||
// Use fullBodyExpr (not expr) to inline unlabeled blocks
|
||||
// (AstGen.zig:6125).
|
||||
uint32_t else_result
|
||||
= fullBodyExpr(&else_scope, &else_scope.base, break_rl, nd.rhs);
|
||||
if (!endsWithNoReturn(&else_scope)) {
|
||||
@@ -5296,9 +5313,8 @@ static void assignStmt(GenZir* gz, Scope* scope, uint32_t infix_node) {
|
||||
// (AstGen.zig:3448-3452).
|
||||
{
|
||||
uint32_t lhs_ptr = exprRl(gz, scope, RL_REF_VAL, lhs);
|
||||
ResultLoc ptr_rl = {
|
||||
.tag = RL_PTR, .data = lhs_ptr, .src_node = infix_node
|
||||
};
|
||||
ResultLoc ptr_rl
|
||||
= { .tag = RL_PTR, .data = lhs_ptr, .src_node = infix_node };
|
||||
(void)exprRl(gz, scope, ptr_rl, rhs);
|
||||
}
|
||||
}
|
||||
@@ -5890,7 +5906,7 @@ static bool addEnsureResult(
|
||||
// --- countDefers (AstGen.zig:2966) ---
|
||||
// Walk scope chain and count defer types.
|
||||
|
||||
static DeferCounts countDefers(Scope* outer_scope, Scope* inner_scope) {
|
||||
static DeferCounts countDefers(const Scope* outer_scope, Scope* inner_scope) {
|
||||
DeferCounts c = { false, false, false, false };
|
||||
Scope* s = inner_scope;
|
||||
while (s != outer_scope) {
|
||||
@@ -5931,7 +5947,7 @@ static DeferCounts countDefers(Scope* outer_scope, Scope* inner_scope) {
|
||||
// which: DEFER_NORMAL_ONLY or DEFER_BOTH_SANS_ERR.
|
||||
|
||||
static void genDefers(
|
||||
GenZir* gz, Scope* outer_scope, Scope* inner_scope, int which) {
|
||||
GenZir* gz, const Scope* outer_scope, Scope* inner_scope, int which) {
|
||||
Scope* s = inner_scope;
|
||||
while (s != outer_scope) {
|
||||
switch (s->tag) {
|
||||
@@ -7046,7 +7062,7 @@ static void testDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
// Set fn_block and fn_ret_ty for the body (AstGen.zig:4849-4853).
|
||||
void* prev_fn_block = ag->fn_block;
|
||||
uint32_t prev_fn_ret_ty = ag->fn_ret_ty;
|
||||
ag->fn_block = &fn_block;
|
||||
setFnBlock(ag, &fn_block);
|
||||
ag->fn_ret_ty = ZIR_REF_ANYERROR_VOID_ERROR_UNION_TYPE;
|
||||
|
||||
// Compute lbrace source location (AstGen.zig:4860-4862).
|
||||
@@ -7100,8 +7116,11 @@ static void testDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
|
||||
// setDeclaration (AstGen.zig:4903-4923).
|
||||
setDeclaration(ag, decl_inst,
|
||||
(SetDeclArgs) { .src_line = decl_line, .src_column = decl_column,
|
||||
.id = decl_id, .name = test_name, .lib_name = UINT32_MAX,
|
||||
(SetDeclArgs) { .src_line = decl_line,
|
||||
.src_column = decl_column,
|
||||
.id = decl_id,
|
||||
.name = test_name,
|
||||
.lib_name = UINT32_MAX,
|
||||
.value_body = gzInstructionsSlice(&decl_block),
|
||||
.value_body_len = gzInstructionsLen(&decl_block) });
|
||||
gzUnstack(&decl_block);
|
||||
@@ -7372,7 +7391,7 @@ static void fnDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
|
||||
// Set fn_block and fn_ret_ty for the body (AstGen.zig:4442-4455).
|
||||
void* prev_fn_block = ag->fn_block;
|
||||
ag->fn_block = &body_gz;
|
||||
setFnBlock(ag, &body_gz);
|
||||
uint32_t prev_fn_ret_ty = ag->fn_ret_ty;
|
||||
if (is_inferred_error || ret_ref == ZIR_REF_NONE) {
|
||||
// Non-void non-trivial return type: emit ret_type instruction.
|
||||
@@ -7463,8 +7482,11 @@ static void fnDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
= is_pub ? DECL_ID_PUB_CONST_SIMPLE : DECL_ID_CONST_SIMPLE;
|
||||
uint32_t name_str = identAsString(ag, fn_name_token);
|
||||
setDeclaration(ag, decl_inst,
|
||||
(SetDeclArgs) { .src_line = decl_line, .src_column = decl_column,
|
||||
.id = decl_id, .name = name_str, .lib_name = UINT32_MAX,
|
||||
(SetDeclArgs) { .src_line = decl_line,
|
||||
.src_column = decl_column,
|
||||
.id = decl_id,
|
||||
.name = name_str,
|
||||
.lib_name = UINT32_MAX,
|
||||
.value_body = gzInstructionsSlice(&decl_gz),
|
||||
.value_body_len = gzInstructionsLen(&decl_gz) });
|
||||
gzUnstack(&decl_gz);
|
||||
@@ -7504,8 +7526,11 @@ static void comptimeDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
&value_gz, decl_inst, ZIR_REF_VOID_VALUE, AST_NODE_OFFSET_NONE);
|
||||
|
||||
setDeclaration(ag, decl_inst,
|
||||
(SetDeclArgs) { .src_line = decl_line, .src_column = decl_column,
|
||||
.id = DECL_ID_COMPTIME, .name = 0, .lib_name = UINT32_MAX,
|
||||
(SetDeclArgs) { .src_line = decl_line,
|
||||
.src_column = decl_column,
|
||||
.id = DECL_ID_COMPTIME,
|
||||
.name = 0,
|
||||
.lib_name = UINT32_MAX,
|
||||
.value_body = gzInstructionsSlice(&value_gz),
|
||||
.value_body_len = gzInstructionsLen(&value_gz) });
|
||||
gzUnstack(&value_gz);
|
||||
@@ -7575,8 +7600,7 @@ static VarDeclInfo extractVarDecl(const Ast* tree, uint32_t node) {
|
||||
}
|
||||
|
||||
// Scan backwards from mut_token to find modifiers (Ast.zig:2003-2025).
|
||||
info.is_mutable
|
||||
= (tree->tokens.tags[mut_token] == TOKEN_KEYWORD_VAR);
|
||||
info.is_mutable = (tree->tokens.tags[mut_token] == TOKEN_KEYWORD_VAR);
|
||||
for (uint32_t i = mut_token; i > 0;) {
|
||||
i--;
|
||||
TokenizerTag ttag = tree->tokens.tags[i];
|
||||
@@ -7705,8 +7729,7 @@ static void globalVarDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
align_gz.is_comptime = true;
|
||||
|
||||
if (vd.align_node != 0) {
|
||||
uint32_t align_inst
|
||||
= expr(&align_gz, &align_gz.base, vd.align_node);
|
||||
uint32_t align_inst = expr(&align_gz, &align_gz.base, vd.align_node);
|
||||
makeBreakInline(&align_gz, decl_inst, align_inst, 0);
|
||||
}
|
||||
|
||||
@@ -7764,13 +7787,17 @@ static void globalVarDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
}
|
||||
|
||||
// Compute body slices (instructionsSliceUpto).
|
||||
const uint32_t* type_body = ag->scratch_instructions + type_gz.instructions_top;
|
||||
const uint32_t* type_body
|
||||
= ag->scratch_instructions + type_gz.instructions_top;
|
||||
uint32_t type_body_len = type_top - type_gz.instructions_top;
|
||||
const uint32_t* align_body = ag->scratch_instructions + align_gz.instructions_top;
|
||||
const uint32_t* align_body
|
||||
= ag->scratch_instructions + align_gz.instructions_top;
|
||||
uint32_t align_body_len = align_top - align_gz.instructions_top;
|
||||
const uint32_t* ls_body = ag->scratch_instructions + linksection_gz.instructions_top;
|
||||
const uint32_t* ls_body
|
||||
= ag->scratch_instructions + linksection_gz.instructions_top;
|
||||
uint32_t ls_body_len = linksection_top - linksection_gz.instructions_top;
|
||||
const uint32_t* as_body = ag->scratch_instructions + addrspace_gz.instructions_top;
|
||||
const uint32_t* as_body
|
||||
= ag->scratch_instructions + addrspace_gz.instructions_top;
|
||||
uint32_t as_body_len = addrspace_top - addrspace_gz.instructions_top;
|
||||
const uint32_t* val_body = gzInstructionsSlice(&value_gz);
|
||||
uint32_t val_body_len = gzInstructionsLen(&value_gz);
|
||||
@@ -7796,12 +7823,19 @@ static void globalVarDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
|
||||
setDeclaration(ag, decl_inst,
|
||||
(SetDeclArgs) { .src_line = ag->source_line,
|
||||
.src_column = decl_column, .id = decl_id, .name = name_str,
|
||||
.lib_name = lib_name, .type_body = type_body,
|
||||
.type_body_len = type_body_len, .align_body = align_body,
|
||||
.align_body_len = align_body_len, .linksection_body = ls_body,
|
||||
.linksection_body_len = ls_body_len, .addrspace_body = as_body,
|
||||
.addrspace_body_len = as_body_len, .value_body = val_body,
|
||||
.src_column = decl_column,
|
||||
.id = decl_id,
|
||||
.name = name_str,
|
||||
.lib_name = lib_name,
|
||||
.type_body = type_body,
|
||||
.type_body_len = type_body_len,
|
||||
.align_body = align_body,
|
||||
.align_body_len = align_body_len,
|
||||
.linksection_body = ls_body,
|
||||
.linksection_body_len = ls_body_len,
|
||||
.addrspace_body = as_body,
|
||||
.addrspace_body_len = as_body_len,
|
||||
.value_body = val_body,
|
||||
.value_body_len = val_body_len });
|
||||
|
||||
gzUnstack(&value_gz);
|
||||
@@ -7895,8 +7929,7 @@ static bool nodeImpliesMoreThanOnePossibleValue(
|
||||
|
||||
// --- nodeImpliesComptimeOnly (AstGen.zig:10787) ---
|
||||
|
||||
static bool identImpliesComptimeOnly(
|
||||
const Ast* tree, uint32_t main_token) {
|
||||
static bool identImpliesComptimeOnly(const Ast* tree, uint32_t main_token) {
|
||||
uint32_t start = tree->tokens.starts[main_token];
|
||||
const char* src = tree->source + start;
|
||||
// Only comptime_float, comptime_int, type → true
|
||||
@@ -7957,20 +7990,20 @@ typedef struct {
|
||||
uint32_t fields_end;
|
||||
uint32_t decl_index;
|
||||
uint32_t field_index;
|
||||
// Bodies scratch: dynamically grown array for field type/align/init bodies.
|
||||
// Bodies scratch: dynamically grown array for field type/align/init
|
||||
// bodies.
|
||||
uint32_t* bodies;
|
||||
uint32_t bodies_len;
|
||||
uint32_t bodies_cap;
|
||||
} WipMembers;
|
||||
|
||||
static WipMembers wipMembersInit(
|
||||
uint32_t decl_count, uint32_t field_count) {
|
||||
static WipMembers wipMembersInit(uint32_t decl_count, uint32_t field_count) {
|
||||
// bits_per_field = 4, max_field_size = 5
|
||||
uint32_t fields_per_u32 = 8; // 32 / 4
|
||||
uint32_t field_bits_start = decl_count;
|
||||
uint32_t bit_words
|
||||
= field_count > 0 ? (field_count + fields_per_u32 - 1) / fields_per_u32
|
||||
: 0;
|
||||
uint32_t bit_words = field_count > 0
|
||||
? (field_count + fields_per_u32 - 1) / fields_per_u32
|
||||
: 0;
|
||||
uint32_t fields_start = field_bits_start + bit_words;
|
||||
uint32_t payload_end = fields_start + field_count * 5;
|
||||
uint32_t alloc_size = payload_end > 0 ? payload_end : 1;
|
||||
@@ -8024,7 +8057,8 @@ static void wipMembersAppendToField(WipMembers* wm, uint32_t data) {
|
||||
|
||||
static void wipMembersFinishBits(WipMembers* wm) {
|
||||
uint32_t fields_per_u32 = 8; // 32 / 4
|
||||
uint32_t empty_field_slots = fields_per_u32 - (wm->field_index % fields_per_u32);
|
||||
uint32_t empty_field_slots
|
||||
= fields_per_u32 - (wm->field_index % fields_per_u32);
|
||||
if (wm->field_index > 0 && empty_field_slots < fields_per_u32) {
|
||||
uint32_t index
|
||||
= wm->field_bits_start + wm->field_index / fields_per_u32;
|
||||
@@ -8050,8 +8084,7 @@ static const uint32_t* wipMembersFieldsSlice(
|
||||
static void wipMembersBodiesAppend(
|
||||
WipMembers* wm, const uint32_t* data, uint32_t len) {
|
||||
if (wm->bodies_len + len > wm->bodies_cap) {
|
||||
uint32_t new_cap
|
||||
= wm->bodies_cap == 0 ? 64 : wm->bodies_cap * 2;
|
||||
uint32_t new_cap = wm->bodies_cap == 0 ? 64 : wm->bodies_cap * 2;
|
||||
while (new_cap < wm->bodies_len + len)
|
||||
new_cap *= 2;
|
||||
wm->bodies = realloc(wm->bodies, new_cap * sizeof(uint32_t));
|
||||
@@ -8070,8 +8103,7 @@ static void wipMembersBodiesAppendWithFixups(
|
||||
uint32_t inst = body[i];
|
||||
// Grow if needed.
|
||||
if (wm->bodies_len + 1 > wm->bodies_cap) {
|
||||
uint32_t new_cap
|
||||
= wm->bodies_cap == 0 ? 64 : wm->bodies_cap * 2;
|
||||
uint32_t new_cap = wm->bodies_cap == 0 ? 64 : wm->bodies_cap * 2;
|
||||
wm->bodies = realloc(wm->bodies, new_cap * sizeof(uint32_t));
|
||||
if (!wm->bodies)
|
||||
exit(1);
|
||||
@@ -8083,8 +8115,7 @@ static void wipMembersBodiesAppendWithFixups(
|
||||
while (refTableFetchRemove(ag, inst, &ref_inst)) {
|
||||
if (wm->bodies_len + 1 > wm->bodies_cap) {
|
||||
uint32_t new_cap = wm->bodies_cap * 2;
|
||||
wm->bodies
|
||||
= realloc(wm->bodies, new_cap * sizeof(uint32_t));
|
||||
wm->bodies = realloc(wm->bodies, new_cap * sizeof(uint32_t));
|
||||
if (!wm->bodies)
|
||||
exit(1);
|
||||
wm->bodies_cap = new_cap;
|
||||
@@ -8279,8 +8310,7 @@ static uint32_t enumDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
|
||||
case AST_NODE_GLOBAL_VAR_DECL:
|
||||
case AST_NODE_LOCAL_VAR_DECL:
|
||||
case AST_NODE_ALIGNED_VAR_DECL:
|
||||
globalVarDecl(
|
||||
ag, gz, wm.payload, &wm.decl_index, member_node);
|
||||
globalVarDecl(ag, gz, wm.payload, &wm.decl_index, member_node);
|
||||
break;
|
||||
case AST_NODE_FN_DECL:
|
||||
fnDecl(ag, gz, wm.payload, &wm.decl_index, member_node);
|
||||
@@ -8298,8 +8328,7 @@ static uint32_t enumDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
|
||||
if (field_names_len >= field_names_cap) {
|
||||
uint32_t new_cap
|
||||
= field_names_cap == 0 ? 8 : field_names_cap * 2;
|
||||
field_names
|
||||
= realloc(field_names, new_cap * sizeof(uint32_t));
|
||||
field_names = realloc(field_names, new_cap * sizeof(uint32_t));
|
||||
if (!field_names)
|
||||
exit(1);
|
||||
field_names_cap = new_cap;
|
||||
@@ -8325,12 +8354,11 @@ static uint32_t enumDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
|
||||
|
||||
// Field bits: 1 bit per field (has_value = false for simple enums).
|
||||
uint32_t fields_per_u32 = 32;
|
||||
uint32_t bit_words
|
||||
= field_count > 0 ? (field_count + fields_per_u32 - 1) / fields_per_u32
|
||||
: 0;
|
||||
uint32_t bit_words = field_count > 0
|
||||
? (field_count + fields_per_u32 - 1) / fields_per_u32
|
||||
: 0;
|
||||
|
||||
ensureExtraCapacity(
|
||||
ag, decls_len_out + bit_words + field_names_len);
|
||||
ensureExtraCapacity(ag, decls_len_out + bit_words + field_names_len);
|
||||
for (uint32_t i = 0; i < decls_len_out; i++)
|
||||
ag->extra[ag->extra_len++] = decls_slice[i];
|
||||
// Field bits: all zero (no values).
|
||||
@@ -8396,8 +8424,7 @@ static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
|
||||
comptimeDecl(ag, gz, wm.payload, &wm.decl_index, member_node);
|
||||
break;
|
||||
case AST_NODE_SIMPLE_VAR_DECL:
|
||||
globalVarDecl(
|
||||
ag, gz, wm.payload, &wm.decl_index, member_node);
|
||||
globalVarDecl(ag, gz, wm.payload, &wm.decl_index, member_node);
|
||||
break;
|
||||
case AST_NODE_TEST_DECL:
|
||||
testDecl(ag, gz, wm.payload, &wm.decl_index, member_node);
|
||||
@@ -8409,8 +8436,7 @@ static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
|
||||
case AST_NODE_GLOBAL_VAR_DECL:
|
||||
case AST_NODE_LOCAL_VAR_DECL:
|
||||
case AST_NODE_ALIGNED_VAR_DECL:
|
||||
globalVarDecl(
|
||||
ag, gz, wm.payload, &wm.decl_index, member_node);
|
||||
globalVarDecl(ag, gz, wm.payload, &wm.decl_index, member_node);
|
||||
break;
|
||||
case AST_NODE_CONTAINER_FIELD_INIT:
|
||||
case AST_NODE_CONTAINER_FIELD_ALIGN:
|
||||
@@ -8459,8 +8485,8 @@ static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
|
||||
bool have_type_body = false;
|
||||
uint32_t field_type = 0;
|
||||
if (type_node != 0) {
|
||||
field_type = typeExpr(
|
||||
&block_scope, &block_scope.base, type_node);
|
||||
field_type
|
||||
= typeExpr(&block_scope, &block_scope.base, type_node);
|
||||
have_type_body = (gzInstructionsLen(&block_scope) > 0);
|
||||
}
|
||||
|
||||
@@ -8494,11 +8520,9 @@ static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
|
||||
}
|
||||
uint32_t raw_len = gzInstructionsLen(&block_scope);
|
||||
const uint32_t* body = gzInstructionsSlice(&block_scope);
|
||||
uint32_t body_len
|
||||
= countBodyLenAfterFixups(ag, body, raw_len);
|
||||
uint32_t body_len = countBodyLenAfterFixups(ag, body, raw_len);
|
||||
uint32_t bodies_before = wm.bodies_len;
|
||||
wipMembersBodiesAppendWithFixups(
|
||||
&wm, ag, body, raw_len);
|
||||
wipMembersBodiesAppendWithFixups(&wm, ag, body, raw_len);
|
||||
(void)bodies_before;
|
||||
wipMembersAppendToField(&wm, body_len);
|
||||
// Reset block_scope.
|
||||
@@ -8509,36 +8533,32 @@ static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
|
||||
|
||||
if (have_align) {
|
||||
any_aligned_fields = true;
|
||||
uint32_t align_ref = expr(
|
||||
&block_scope, &block_scope.base, align_node);
|
||||
uint32_t align_ref
|
||||
= expr(&block_scope, &block_scope.base, align_node);
|
||||
if (!endsWithNoReturn(&block_scope)) {
|
||||
makeBreakInline(&block_scope, decl_inst, align_ref,
|
||||
AST_NODE_OFFSET_NONE);
|
||||
}
|
||||
uint32_t raw_len = gzInstructionsLen(&block_scope);
|
||||
const uint32_t* body = gzInstructionsSlice(&block_scope);
|
||||
uint32_t body_len
|
||||
= countBodyLenAfterFixups(ag, body, raw_len);
|
||||
wipMembersBodiesAppendWithFixups(
|
||||
&wm, ag, body, raw_len);
|
||||
uint32_t body_len = countBodyLenAfterFixups(ag, body, raw_len);
|
||||
wipMembersBodiesAppendWithFixups(&wm, ag, body, raw_len);
|
||||
wipMembersAppendToField(&wm, body_len);
|
||||
ag->scratch_inst_len = block_scope.instructions_top;
|
||||
}
|
||||
|
||||
if (have_value) {
|
||||
any_default_inits = true;
|
||||
uint32_t default_ref = expr(
|
||||
&block_scope, &block_scope.base, value_node);
|
||||
uint32_t default_ref
|
||||
= expr(&block_scope, &block_scope.base, value_node);
|
||||
if (!endsWithNoReturn(&block_scope)) {
|
||||
makeBreakInline(&block_scope, decl_inst,
|
||||
default_ref, AST_NODE_OFFSET_NONE);
|
||||
makeBreakInline(&block_scope, decl_inst, default_ref,
|
||||
AST_NODE_OFFSET_NONE);
|
||||
}
|
||||
uint32_t raw_len = gzInstructionsLen(&block_scope);
|
||||
const uint32_t* body = gzInstructionsSlice(&block_scope);
|
||||
uint32_t body_len
|
||||
= countBodyLenAfterFixups(ag, body, raw_len);
|
||||
wipMembersBodiesAppendWithFixups(
|
||||
&wm, ag, body, raw_len);
|
||||
uint32_t body_len = countBodyLenAfterFixups(ag, body, raw_len);
|
||||
wipMembersBodiesAppendWithFixups(&wm, ag, body, raw_len);
|
||||
wipMembersAppendToField(&wm, body_len);
|
||||
ag->scratch_inst_len = block_scope.instructions_top;
|
||||
}
|
||||
@@ -8562,19 +8582,16 @@ static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
|
||||
small.any_comptime_fields = any_comptime_fields;
|
||||
small.any_default_inits = any_default_inits;
|
||||
small.any_aligned_fields = any_aligned_fields;
|
||||
setStruct(
|
||||
ag, decl_inst, node, small, 0, field_count, decl_count);
|
||||
setStruct(ag, decl_inst, node, small, 0, field_count, decl_count);
|
||||
|
||||
// Append: captures (none), backing_int (none), decls, fields, bodies
|
||||
// (AstGen.zig:5176-5189).
|
||||
uint32_t decls_len;
|
||||
const uint32_t* decls_slice = wipMembersDeclsSlice(&wm, &decls_len);
|
||||
uint32_t fields_len;
|
||||
const uint32_t* fields_slice
|
||||
= wipMembersFieldsSlice(&wm, &fields_len);
|
||||
const uint32_t* fields_slice = wipMembersFieldsSlice(&wm, &fields_len);
|
||||
|
||||
ensureExtraCapacity(
|
||||
ag, decls_len + fields_len + wm.bodies_len);
|
||||
ensureExtraCapacity(ag, decls_len + fields_len + wm.bodies_len);
|
||||
for (uint32_t i = 0; i < decls_len; i++)
|
||||
ag->extra[ag->extra_len++] = decls_slice[i];
|
||||
for (uint32_t i = 0; i < fields_len; i++)
|
||||
|
||||
@@ -990,7 +990,7 @@ test "astgen: corpus test_all.zig" {
|
||||
}
|
||||
|
||||
test "astgen: corpus build.zig" {
|
||||
if (true) return error.SkipZigTest; // TODO: 3 inst, 160 extra, 18 string diffs
|
||||
if (true) return error.SkipZigTest; // TODO: 11 inst diffs (10 dbg_stmt, 1 ref)
|
||||
const gpa = std.testing.allocator;
|
||||
try corpusCheck(gpa, "build.zig", @embedFile("build.zig"));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user