astgen: fix structDeclInner layout, coercion, fn_proto handling, and error diagnostics
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
404
astgen.c
404
astgen.c
@@ -2331,7 +2331,11 @@ static bool tokenIsUnderscore(const Ast* tree, uint32_t ident_token);
|
||||
static uint32_t containerDecl(
|
||||
GenZir* gz, Scope* scope, uint32_t node, uint8_t name_strategy);
|
||||
static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
|
||||
const uint32_t* members, uint32_t members_len, uint8_t name_strategy);
|
||||
const uint32_t* members, uint32_t members_len, uint8_t layout,
|
||||
uint32_t backing_int_node, uint8_t name_strategy);
|
||||
static uint32_t tupleDecl(AstGenCtx* ag, GenZir* gz, uint32_t node,
|
||||
const uint32_t* members, uint32_t members_len, uint8_t layout,
|
||||
uint32_t backing_int_node);
|
||||
static uint32_t enumDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
|
||||
const uint32_t* members, uint32_t members_len, uint32_t arg_node,
|
||||
uint8_t name_strategy);
|
||||
@@ -2473,6 +2477,7 @@ static uint32_t tryResolvePrimitiveIdent(GenZir* gz, uint32_t node);
|
||||
#define COMPTIME_REASON_ADDRSPACE 51
|
||||
#define COMPTIME_REASON_COMPTIME_KEYWORD 53
|
||||
#define COMPTIME_REASON_SWITCH_ITEM 56
|
||||
#define COMPTIME_REASON_TUPLE_FIELD_DEFAULT_VALUE 57
|
||||
|
||||
// Mirrors comptimeExpr2 (AstGen.zig:1982).
|
||||
// Evaluates a node in a comptime block_comptime scope.
|
||||
@@ -9628,16 +9633,27 @@ static void testDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
}
|
||||
|
||||
// --- fnDecl (AstGen.zig:4067) / fnDeclInner (AstGen.zig:4228) ---
|
||||
// Handles non-extern function declarations with bodies, including params.
|
||||
// Handles function declarations with bodies (fn_decl) and
|
||||
// function prototypes without bodies (fn_proto*).
|
||||
|
||||
static void fnDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
uint32_t* decl_idx, uint32_t node) {
|
||||
const Ast* tree = ag->tree;
|
||||
AstNodeTag node_tag = tree->nodes.tags[node];
|
||||
AstData nd = tree->nodes.datas[node];
|
||||
|
||||
// For fn_decl: data.lhs = fn_proto node, data.rhs = body node.
|
||||
uint32_t proto_node = nd.lhs;
|
||||
uint32_t body_node = nd.rhs;
|
||||
// For fn_proto*: the node itself IS the proto, no body.
|
||||
uint32_t proto_node;
|
||||
uint32_t body_node;
|
||||
if (node_tag == AST_NODE_FN_DECL) {
|
||||
proto_node = nd.lhs;
|
||||
body_node = nd.rhs;
|
||||
} else {
|
||||
// fn_proto_simple, fn_proto_multi, fn_proto_one, fn_proto
|
||||
proto_node = node;
|
||||
body_node = 0;
|
||||
}
|
||||
|
||||
// Get function name token (main_token of proto + 1 = fn name).
|
||||
uint32_t fn_token = tree->nodes.main_tokens[proto_node];
|
||||
@@ -10037,6 +10053,24 @@ static void fnDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
}
|
||||
gzUnstack(&cc_gz);
|
||||
|
||||
// --- Body handling ---
|
||||
// For fn_proto* (no body): extern function, emit type only
|
||||
// (AstGen.zig:4136-4164).
|
||||
// For fn_decl (has body): emit function value (AstGen.zig:4197-4201).
|
||||
uint32_t func_ref;
|
||||
if (body_node == 0) {
|
||||
// fn_proto without body: extern function type.
|
||||
// Upstream emits fnProtoExprInner; we SET_ERROR for now as
|
||||
// fnProtoExprInner is not yet ported.
|
||||
// TODO: implement fnProtoExprInner for extern fn support.
|
||||
SET_ERROR(ag);
|
||||
free(ret_body);
|
||||
free(cc_body);
|
||||
gzUnstack(&decl_gz);
|
||||
ag->within_fn = prev_within_fn;
|
||||
return;
|
||||
}
|
||||
|
||||
// --- Body (AstGen.zig:4415-4424) ---
|
||||
GenZir body_gz;
|
||||
memset(&body_gz, 0, sizeof(body_gz));
|
||||
@@ -10125,7 +10159,6 @@ static void fnDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
// 12112-12173).
|
||||
bool need_fancy = cc_ref != ZIR_REF_NONE || is_var_args
|
||||
|| noalias_bits != 0 || is_noinline;
|
||||
uint32_t func_ref;
|
||||
if (need_fancy) {
|
||||
func_ref = addFuncFancy(&decl_gz, node, body_node, decl_inst, ret_ref,
|
||||
ret_body, ret_body_len, cc_ref, cc_body, cc_body_len, fn_body,
|
||||
@@ -11033,10 +11066,21 @@ static uint32_t containerDecl(
|
||||
TokenizerTag kw_tag = tree->tokens.tags[main_token];
|
||||
uint32_t decl_inst;
|
||||
switch (kw_tag) {
|
||||
case TOKEN_KEYWORD_STRUCT:
|
||||
decl_inst = structDeclInner(
|
||||
ag, gz, node, members, members_len, name_strategy);
|
||||
case TOKEN_KEYWORD_STRUCT: {
|
||||
// Extract layout from token before main_token (AstGen.zig:5489-5493).
|
||||
// auto=0, extern=1, packed=2.
|
||||
uint8_t layout = 0; // auto
|
||||
if (main_token > 0) {
|
||||
TokenizerTag prev_tag = tree->tokens.tags[main_token - 1];
|
||||
if (prev_tag == TOKEN_KEYWORD_PACKED)
|
||||
layout = 2;
|
||||
else if (prev_tag == TOKEN_KEYWORD_EXTERN)
|
||||
layout = 1;
|
||||
}
|
||||
decl_inst = structDeclInner(ag, gz, node, members, members_len, layout,
|
||||
arg_node, name_strategy);
|
||||
break;
|
||||
}
|
||||
case TOKEN_KEYWORD_ENUM:
|
||||
decl_inst = enumDeclInner(
|
||||
ag, gz, node, members, members_len, arg_node, name_strategy);
|
||||
@@ -11044,7 +11088,7 @@ static uint32_t containerDecl(
|
||||
default:
|
||||
// union/opaque: fall back to struct for now.
|
||||
decl_inst = structDeclInner(
|
||||
ag, gz, node, members, members_len, name_strategy);
|
||||
ag, gz, node, members, members_len, 0, 0, name_strategy);
|
||||
break;
|
||||
}
|
||||
(void)scope;
|
||||
@@ -11312,18 +11356,210 @@ static uint32_t enumDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
|
||||
return decl_inst;
|
||||
}
|
||||
|
||||
// --- tupleDecl (AstGen.zig:5192) ---
|
||||
|
||||
static uint32_t tupleDecl(AstGenCtx* ag, GenZir* gz, uint32_t node,
|
||||
const uint32_t* members, uint32_t members_len, uint8_t layout,
|
||||
uint32_t backing_int_node) {
|
||||
const Ast* tree = ag->tree;
|
||||
|
||||
// layout must be auto for tuples (AstGen.zig:5204-5207).
|
||||
if (layout != 0) {
|
||||
SET_ERROR(ag);
|
||||
return reserveInstructionIndex(ag);
|
||||
}
|
||||
// tuples don't support backing int (AstGen.zig:5209-5211).
|
||||
if (backing_int_node != 0) {
|
||||
SET_ERROR(ag);
|
||||
return reserveInstructionIndex(ag);
|
||||
}
|
||||
|
||||
// Build fields_start scratch area: for each field, type ref + init ref.
|
||||
uint32_t fields_start = ag->extra_len;
|
||||
// We use extra as scratch temporarily; will finalize below.
|
||||
// Actually, upstream uses astgen.scratch; we use a temporary buffer.
|
||||
uint32_t* tuple_scratch = NULL;
|
||||
uint32_t tuple_scratch_len = 0;
|
||||
uint32_t tuple_scratch_cap = 0;
|
||||
|
||||
for (uint32_t i = 0; i < members_len; i++) {
|
||||
uint32_t member_node = members[i];
|
||||
AstNodeTag mtag = tree->nodes.tags[member_node];
|
||||
|
||||
// Non-field nodes are errors in tuples (AstGen.zig:5224-5238).
|
||||
if (mtag != AST_NODE_CONTAINER_FIELD_INIT
|
||||
&& mtag != AST_NODE_CONTAINER_FIELD_ALIGN
|
||||
&& mtag != AST_NODE_CONTAINER_FIELD) {
|
||||
SET_ERROR(ag);
|
||||
free(tuple_scratch);
|
||||
return reserveInstructionIndex(ag);
|
||||
}
|
||||
|
||||
// Extract field info.
|
||||
uint32_t main_token = tree->nodes.main_tokens[member_node];
|
||||
AstData nd = tree->nodes.datas[member_node];
|
||||
uint32_t type_node = nd.lhs;
|
||||
uint32_t align_node = 0;
|
||||
uint32_t value_node = 0;
|
||||
bool has_comptime_token = false;
|
||||
|
||||
switch (mtag) {
|
||||
case AST_NODE_CONTAINER_FIELD_INIT:
|
||||
value_node = nd.rhs;
|
||||
break;
|
||||
case AST_NODE_CONTAINER_FIELD_ALIGN:
|
||||
align_node = nd.rhs;
|
||||
break;
|
||||
case AST_NODE_CONTAINER_FIELD:
|
||||
if (nd.rhs != 0) {
|
||||
align_node = tree->extra_data.arr[nd.rhs];
|
||||
value_node = tree->extra_data.arr[nd.rhs + 1];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (main_token > 0
|
||||
&& tree->tokens.tags[main_token - 1] == TOKEN_KEYWORD_COMPTIME) {
|
||||
has_comptime_token = true;
|
||||
}
|
||||
|
||||
// Check tuple_like: must be tuple-like (AstGen.zig:5240-5241).
|
||||
bool tuple_like = tree->tokens.tags[main_token] != TOKEN_IDENTIFIER
|
||||
|| tree->tokens.tags[main_token + 1] != TOKEN_COLON;
|
||||
if (!tuple_like) {
|
||||
// Named field in tuple: error (AstGen.zig:5241).
|
||||
SET_ERROR(ag);
|
||||
free(tuple_scratch);
|
||||
return reserveInstructionIndex(ag);
|
||||
}
|
||||
|
||||
// Tuple fields cannot have alignment (AstGen.zig:5244-5246).
|
||||
if (align_node != 0) {
|
||||
SET_ERROR(ag);
|
||||
free(tuple_scratch);
|
||||
return reserveInstructionIndex(ag);
|
||||
}
|
||||
|
||||
// Non-comptime tuple field with default init: error
|
||||
// (AstGen.zig:5248-5250).
|
||||
if (value_node != 0 && !has_comptime_token) {
|
||||
SET_ERROR(ag);
|
||||
free(tuple_scratch);
|
||||
return reserveInstructionIndex(ag);
|
||||
}
|
||||
|
||||
// Comptime field without default init: error
|
||||
// (AstGen.zig:5252-5254).
|
||||
if (value_node == 0 && has_comptime_token) {
|
||||
SET_ERROR(ag);
|
||||
free(tuple_scratch);
|
||||
return reserveInstructionIndex(ag);
|
||||
}
|
||||
|
||||
// Type expression (AstGen.zig:5256).
|
||||
uint32_t field_type_ref = typeExpr(gz, &gz->base, type_node);
|
||||
|
||||
// Grow scratch buffer.
|
||||
if (tuple_scratch_len + 2 > tuple_scratch_cap) {
|
||||
uint32_t new_cap
|
||||
= tuple_scratch_cap == 0 ? 16 : tuple_scratch_cap * 2;
|
||||
tuple_scratch = realloc(tuple_scratch, new_cap * sizeof(uint32_t));
|
||||
if (!tuple_scratch)
|
||||
exit(1);
|
||||
tuple_scratch_cap = new_cap;
|
||||
}
|
||||
tuple_scratch[tuple_scratch_len++] = field_type_ref;
|
||||
|
||||
// Default init (AstGen.zig:5259-5264).
|
||||
if (value_node != 0) {
|
||||
ResultLoc init_rl = { .tag = RL_COERCED_TY,
|
||||
.data = field_type_ref,
|
||||
.src_node = 0,
|
||||
.ctx = RI_CTX_NONE };
|
||||
uint32_t field_init_ref = comptimeExpr(gz, &gz->base, init_rl,
|
||||
value_node, COMPTIME_REASON_TUPLE_FIELD_DEFAULT_VALUE);
|
||||
tuple_scratch[tuple_scratch_len++] = field_init_ref;
|
||||
} else {
|
||||
tuple_scratch[tuple_scratch_len++] = ZIR_REF_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
if (members_len > 65535) {
|
||||
SET_ERROR(ag);
|
||||
free(tuple_scratch);
|
||||
return reserveInstructionIndex(ag);
|
||||
}
|
||||
uint16_t fields_len = (uint16_t)members_len;
|
||||
|
||||
// Write TupleDecl payload (AstGen.zig:5274-5286).
|
||||
(void)fields_start;
|
||||
ensureExtraCapacity(ag, 1 + tuple_scratch_len);
|
||||
uint32_t payload_index = ag->extra_len;
|
||||
// src_node as node offset relative to gz->decl_node_index.
|
||||
ag->extra[ag->extra_len++]
|
||||
= (uint32_t)((int32_t)node - (int32_t)gz->decl_node_index);
|
||||
|
||||
for (uint32_t i = 0; i < tuple_scratch_len; i++)
|
||||
ag->extra[ag->extra_len++] = tuple_scratch[i];
|
||||
|
||||
free(tuple_scratch);
|
||||
|
||||
// Emit extended instruction (AstGen.zig:5279-5286).
|
||||
ensureInstCapacity(ag, 1);
|
||||
uint32_t idx = ag->inst_len;
|
||||
ag->inst_tags[idx] = ZIR_INST_EXTENDED;
|
||||
ZirInstData data;
|
||||
memset(&data, 0, sizeof(data));
|
||||
data.extended.opcode = (uint16_t)ZIR_EXT_TUPLE_DECL;
|
||||
data.extended.small = fields_len;
|
||||
data.extended.operand = payload_index;
|
||||
ag->inst_datas[idx] = data;
|
||||
ag->inst_len++;
|
||||
gzAppendInstruction(gz, idx);
|
||||
return idx;
|
||||
}
|
||||
|
||||
// --- structDeclInner (AstGen.zig:4926) ---
|
||||
|
||||
static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
|
||||
const uint32_t* members, uint32_t members_len, uint8_t name_strategy) {
|
||||
const uint32_t* members, uint32_t members_len, uint8_t layout,
|
||||
uint32_t backing_int_node, uint8_t name_strategy) {
|
||||
const Ast* tree = ag->tree;
|
||||
|
||||
// Tuple detection (AstGen.zig:4939-4950).
|
||||
// Scan for tuple-like fields; if any found, dispatch to tupleDecl.
|
||||
for (uint32_t i = 0; i < members_len; i++) {
|
||||
uint32_t member_node = members[i];
|
||||
AstNodeTag mtag = tree->nodes.tags[member_node];
|
||||
if (mtag != AST_NODE_CONTAINER_FIELD_INIT
|
||||
&& mtag != AST_NODE_CONTAINER_FIELD_ALIGN
|
||||
&& mtag != AST_NODE_CONTAINER_FIELD)
|
||||
continue;
|
||||
uint32_t main_token = tree->nodes.main_tokens[member_node];
|
||||
bool tuple_like = tree->tokens.tags[main_token] != TOKEN_IDENTIFIER
|
||||
|| tree->tokens.tags[main_token + 1] != TOKEN_COLON;
|
||||
if (tuple_like) {
|
||||
if (node == 0) {
|
||||
// Root node: file cannot be a tuple
|
||||
// (AstGen.zig:4946).
|
||||
SET_ERROR(ag);
|
||||
return reserveInstructionIndex(ag);
|
||||
}
|
||||
return tupleDecl(
|
||||
ag, gz, node, members, members_len, layout, backing_int_node);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t decl_inst = reserveInstructionIndex(ag);
|
||||
gzAppendInstruction(gz, decl_inst);
|
||||
|
||||
// Fast path: no members, no backing int (AstGen.zig:4954-4970).
|
||||
if (members_len == 0) {
|
||||
if (members_len == 0 && backing_int_node == 0) {
|
||||
StructDeclSmall small;
|
||||
memset(&small, 0, sizeof(small));
|
||||
small.layout = layout;
|
||||
small.name_strategy = name_strategy;
|
||||
setStruct(ag, decl_inst, node, small, 0, 0, 0);
|
||||
return decl_inst;
|
||||
@@ -11338,18 +11574,47 @@ static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
|
||||
WipMembers wm = wipMembersInit(decl_count, field_count);
|
||||
|
||||
// Set up block_scope for field type/align/init expressions.
|
||||
// (AstGen.zig:4983-4992)
|
||||
// (AstGen.zig:4986-4994)
|
||||
GenZir block_scope;
|
||||
memset(&block_scope, 0, sizeof(block_scope));
|
||||
block_scope.base.tag = SCOPE_GEN_ZIR;
|
||||
block_scope.parent = NULL;
|
||||
block_scope.astgen = ag;
|
||||
block_scope.decl_node_index = node;
|
||||
block_scope.decl_line = ag->source_line;
|
||||
block_scope.decl_line = gz->decl_line; // Fix #7: use gz->decl_line
|
||||
block_scope.is_comptime = true;
|
||||
block_scope.instructions_top = ag->scratch_inst_len;
|
||||
block_scope.any_defer_node = UINT32_MAX;
|
||||
|
||||
// Handle backing_int_node for packed structs (AstGen.zig:5000-5024).
|
||||
// We store the raw body instructions and apply fixups at the final append.
|
||||
uint32_t backing_int_body_raw_len = 0;
|
||||
uint32_t backing_int_ref = ZIR_REF_NONE;
|
||||
uint32_t* backing_int_body_raw = NULL;
|
||||
if (backing_int_node != 0) {
|
||||
if (layout != 2) { // not packed
|
||||
SET_ERROR(ag); // non-packed struct with backing int
|
||||
} else {
|
||||
backing_int_ref
|
||||
= typeExpr(&block_scope, &block_scope.base, backing_int_node);
|
||||
if (gzInstructionsLen(&block_scope) > 0) {
|
||||
if (!endsWithNoReturn(&block_scope)) {
|
||||
makeBreakInline(&block_scope, decl_inst, backing_int_ref,
|
||||
AST_NODE_OFFSET_NONE);
|
||||
}
|
||||
backing_int_body_raw_len = gzInstructionsLen(&block_scope);
|
||||
const uint32_t* body = gzInstructionsSlice(&block_scope);
|
||||
backing_int_body_raw
|
||||
= malloc(backing_int_body_raw_len * sizeof(uint32_t));
|
||||
if (!backing_int_body_raw)
|
||||
exit(1);
|
||||
memcpy(backing_int_body_raw, body,
|
||||
backing_int_body_raw_len * sizeof(uint32_t));
|
||||
ag->scratch_inst_len = block_scope.instructions_top;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool known_non_opv = false;
|
||||
bool known_comptime_only = false;
|
||||
bool any_comptime_fields = false;
|
||||
@@ -11373,6 +11638,13 @@ static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
|
||||
case AST_NODE_FN_DECL:
|
||||
fnDecl(ag, gz, wm.payload, &wm.decl_index, member_node);
|
||||
break;
|
||||
// fn_proto* dispatch (AstGen.zig:5809-5813, issue #9).
|
||||
case AST_NODE_FN_PROTO_SIMPLE:
|
||||
case AST_NODE_FN_PROTO_MULTI:
|
||||
case AST_NODE_FN_PROTO_ONE:
|
||||
case AST_NODE_FN_PROTO:
|
||||
fnDecl(ag, gz, wm.payload, &wm.decl_index, member_node);
|
||||
break;
|
||||
case AST_NODE_USINGNAMESPACE:
|
||||
case AST_NODE_GLOBAL_VAR_DECL:
|
||||
case AST_NODE_LOCAL_VAR_DECL:
|
||||
@@ -11418,34 +11690,44 @@ static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
|
||||
has_comptime_token = true;
|
||||
}
|
||||
|
||||
// Field name (AstGen.zig:5080).
|
||||
// Field name (AstGen.zig:5068).
|
||||
// convertToNonTupleLike: for struct fields, if type_expr is
|
||||
// an identifier node, it's actually a named field with the
|
||||
// identifier as the name (AstGen.zig:5069-5070).
|
||||
uint32_t field_name = identAsString(ag, main_token);
|
||||
wipMembersAppendToField(&wm, field_name);
|
||||
|
||||
// Type expression (AstGen.zig:5089-5109).
|
||||
// Type expression: struct field missing type is an error
|
||||
// (AstGen.zig:5073-5075, issue #12).
|
||||
if (type_node == 0) {
|
||||
SET_ERROR(ag);
|
||||
break;
|
||||
}
|
||||
|
||||
bool have_type_body = false;
|
||||
uint32_t field_type = 0;
|
||||
if (type_node != 0) {
|
||||
field_type
|
||||
= typeExpr(&block_scope, &block_scope.base, type_node);
|
||||
have_type_body = (gzInstructionsLen(&block_scope) > 0);
|
||||
}
|
||||
field_type = typeExpr(&block_scope, &block_scope.base, type_node);
|
||||
have_type_body = (gzInstructionsLen(&block_scope) > 0);
|
||||
|
||||
bool have_align = (align_node != 0);
|
||||
bool have_value = (value_node != 0);
|
||||
bool is_comptime = has_comptime_token;
|
||||
|
||||
// Packed/extern struct comptime field error
|
||||
// (AstGen.zig:5083-5087, issue #15).
|
||||
if (is_comptime) {
|
||||
if (layout == 2 || layout == 1) {
|
||||
// packed or extern struct fields cannot be comptime.
|
||||
SET_ERROR(ag);
|
||||
break;
|
||||
}
|
||||
any_comptime_fields = true;
|
||||
} else {
|
||||
// (AstGen.zig:5106-5109)
|
||||
if (type_node != 0) {
|
||||
known_non_opv = known_non_opv
|
||||
|| nodeImpliesMoreThanOnePossibleValue(
|
||||
tree, type_node);
|
||||
known_comptime_only = known_comptime_only
|
||||
|| nodeImpliesComptimeOnly(tree, type_node);
|
||||
}
|
||||
// (AstGen.zig:5089-5093)
|
||||
known_non_opv = known_non_opv
|
||||
|| nodeImpliesMoreThanOnePossibleValue(tree, type_node);
|
||||
known_comptime_only = known_comptime_only
|
||||
|| nodeImpliesComptimeOnly(tree, type_node);
|
||||
}
|
||||
|
||||
bool field_bits[4]
|
||||
@@ -11473,9 +11755,21 @@ static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
|
||||
}
|
||||
|
||||
if (have_align) {
|
||||
// Packed struct fields cannot have alignment overrides
|
||||
// (AstGen.zig:5111-5113, issue #15).
|
||||
if (layout == 2) { // packed
|
||||
SET_ERROR(ag);
|
||||
break;
|
||||
}
|
||||
any_aligned_fields = true;
|
||||
uint32_t align_ref
|
||||
= expr(&block_scope, &block_scope.base, align_node);
|
||||
// Use coerced_align_ri: RL_COERCED_TY with u29_type
|
||||
// (AstGen.zig:5115, issue #14).
|
||||
ResultLoc align_rl = { .tag = RL_COERCED_TY,
|
||||
.data = ZIR_REF_U29_TYPE,
|
||||
.src_node = 0,
|
||||
.ctx = RI_CTX_NONE };
|
||||
uint32_t align_ref = exprRl(
|
||||
&block_scope, &block_scope.base, align_rl, align_node);
|
||||
if (!endsWithNoReturn(&block_scope)) {
|
||||
makeBreakInline(&block_scope, decl_inst, align_ref,
|
||||
AST_NODE_OFFSET_NONE);
|
||||
@@ -11490,8 +11784,20 @@ static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
|
||||
|
||||
if (have_value) {
|
||||
any_default_inits = true;
|
||||
uint32_t default_ref
|
||||
= expr(&block_scope, &block_scope.base, value_node);
|
||||
// Use coerced_ty with decl_inst when field type is present
|
||||
// (AstGen.zig:5132, issue #11).
|
||||
ResultLoc value_rl;
|
||||
if (field_type == 0) {
|
||||
value_rl = RL_NONE_VAL;
|
||||
} else {
|
||||
uint32_t dref = decl_inst + ZIR_REF_START_INDEX;
|
||||
value_rl = (ResultLoc) { .tag = RL_COERCED_TY,
|
||||
.data = dref,
|
||||
.src_node = 0,
|
||||
.ctx = RI_CTX_NONE };
|
||||
}
|
||||
uint32_t default_ref = exprRl(
|
||||
&block_scope, &block_scope.base, value_rl, value_node);
|
||||
if (!endsWithNoReturn(&block_scope)) {
|
||||
makeBreakInline(&block_scope, decl_inst, default_ref,
|
||||
AST_NODE_OFFSET_NONE);
|
||||
@@ -11502,6 +11808,10 @@ static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
|
||||
wipMembersBodiesAppendWithFixups(&wm, ag, body, raw_len);
|
||||
wipMembersAppendToField(&wm, body_len);
|
||||
ag->scratch_inst_len = block_scope.instructions_top;
|
||||
} else if (has_comptime_token) {
|
||||
// Comptime field without default init: error
|
||||
// (AstGen.zig:5144-5145, issue #13).
|
||||
SET_ERROR(ag);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -11518,22 +11828,43 @@ static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
|
||||
memset(&small, 0, sizeof(small));
|
||||
small.has_decls_len = (decl_count > 0);
|
||||
small.has_fields_len = (field_count > 0);
|
||||
small.has_backing_int = (backing_int_ref != ZIR_REF_NONE);
|
||||
small.known_non_opv = known_non_opv;
|
||||
small.known_comptime_only = known_comptime_only;
|
||||
small.any_comptime_fields = any_comptime_fields;
|
||||
small.any_default_inits = any_default_inits;
|
||||
small.any_aligned_fields = any_aligned_fields;
|
||||
small.layout = layout;
|
||||
small.name_strategy = name_strategy;
|
||||
setStruct(ag, decl_inst, node, small, 0, field_count, decl_count);
|
||||
|
||||
// Append: captures (none), backing_int (none), decls, fields, bodies
|
||||
// (AstGen.zig:5176-5189).
|
||||
// Append: captures (none), backing_int, decls, fields, bodies
|
||||
// (AstGen.zig:5172-5186).
|
||||
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);
|
||||
|
||||
ensureExtraCapacity(ag, decls_len + fields_len + wm.bodies_len);
|
||||
// Compute backing_int_body_len (with fixups) for capacity estimation.
|
||||
uint32_t backing_int_body_len = 0;
|
||||
if (backing_int_body_raw_len > 0) {
|
||||
backing_int_body_len = countBodyLenAfterFixups(
|
||||
ag, backing_int_body_raw, backing_int_body_raw_len);
|
||||
}
|
||||
ensureExtraCapacity(ag,
|
||||
(backing_int_ref != ZIR_REF_NONE ? backing_int_body_len + 2 : 0)
|
||||
+ decls_len + fields_len + wm.bodies_len);
|
||||
// backing_int (AstGen.zig:5176-5183).
|
||||
if (backing_int_ref != ZIR_REF_NONE) {
|
||||
ag->extra[ag->extra_len++] = backing_int_body_len;
|
||||
if (backing_int_body_len == 0) {
|
||||
ag->extra[ag->extra_len++] = backing_int_ref;
|
||||
} else {
|
||||
for (uint32_t j = 0; j < backing_int_body_raw_len; j++)
|
||||
appendPossiblyRefdBodyInst(ag, backing_int_body_raw[j]);
|
||||
}
|
||||
}
|
||||
free(backing_int_body_raw);
|
||||
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++)
|
||||
@@ -12807,7 +13138,8 @@ Zir astGen(const Ast* ast) {
|
||||
const uint32_t* members = ast->extra_data.arr + members_start;
|
||||
uint32_t members_len = members_end - members_start;
|
||||
|
||||
structDeclInner(&ag, &gen_scope, 0, members, members_len, 0 /* parent */);
|
||||
structDeclInner(
|
||||
&ag, &gen_scope, 0, members, members_len, 0, 0, 0 /* parent */);
|
||||
|
||||
// Write imports list (AstGen.zig:227-244).
|
||||
writeImports(&ag);
|
||||
|
||||
@@ -325,6 +325,11 @@ fn expectEqualData(
|
||||
.shl_with_overflow,
|
||||
.restore_err_ret_index,
|
||||
.branch_hint,
|
||||
// Container decl Small packed structs have undefined padding bits.
|
||||
.struct_decl,
|
||||
.enum_decl,
|
||||
.union_decl,
|
||||
.opaque_decl,
|
||||
=> true,
|
||||
else => false,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user