Skip to content

Commit 40f4ada

Browse files
andrewrkwooster0
authored andcommitted
stage2: lower each struct field type, align, init separately
Previously, struct types, alignment values, and initialization expressions were all lowered into the same ZIR body, which caused false positive "depends on itself" errors when the initialization expression depended on the size of the struct. This also uses ResultLoc.coerced_ty for struct field alignment and initialization values. The resulting ZIR encoding ends up being roughly the same, neither smaller nor larger than previously. Closes ziglang#12029
1 parent dffb30f commit 40f4ada

File tree

6 files changed

+331
-204
lines changed

6 files changed

+331
-204
lines changed

src/AstGen.zig

+56-27
Original file line numberDiff line numberDiff line change
@@ -4148,7 +4148,6 @@ fn structDeclInner(
41484148
.src_node = node,
41494149
.layout = layout,
41504150
.fields_len = 0,
4151-
.body_len = 0,
41524151
.decls_len = 0,
41534152
.known_non_opv = false,
41544153
.known_comptime_only = false,
@@ -4192,6 +4191,19 @@ fn structDeclInner(
41924191
var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, field_count, bits_per_field, max_field_size);
41934192
defer wip_members.deinit();
41944193

4194+
// We will use the scratch buffer, starting here, for the bodies:
4195+
// bodies: { // for every fields_len
4196+
// field_type_body_inst: Inst, // for each field_type_body_len
4197+
// align_body_inst: Inst, // for each align_body_len
4198+
// init_body_inst: Inst, // for each init_body_len
4199+
// }
4200+
// Note that the scratch buffer is simultaneously being used by WipMembers, however
4201+
// it will not access any elements beyond this point in the ArrayList. It also
4202+
// accesses via the ArrayList items field so it can handle the scratch buffer being
4203+
// reallocated.
4204+
// No defer needed here because it is handled by `wip_members.deinit()` above.
4205+
const bodies_start = astgen.scratch.items.len;
4206+
41954207
var known_non_opv = false;
41964208
var known_comptime_only = false;
41974209
for (container_decl.ast.members) |member_node| {
@@ -4203,57 +4215,78 @@ fn structDeclInner(
42034215
const field_name = try astgen.identAsString(member.ast.name_token);
42044216
wip_members.appendToField(field_name);
42054217

4218+
const doc_comment_index = try astgen.docCommentAsString(member.firstToken());
4219+
wip_members.appendToField(doc_comment_index);
4220+
42064221
if (member.ast.type_expr == 0) {
42074222
return astgen.failTok(member.ast.name_token, "struct field missing type", .{});
42084223
}
42094224

42104225
const field_type = try typeExpr(&block_scope, &namespace.base, member.ast.type_expr);
4211-
wip_members.appendToField(@enumToInt(field_type));
4212-
4213-
const doc_comment_index = try astgen.docCommentAsString(member.firstToken());
4214-
wip_members.appendToField(doc_comment_index);
4215-
4226+
const have_type_body = !block_scope.isEmpty();
42164227
const have_align = member.ast.align_expr != 0;
42174228
const have_value = member.ast.value_expr != 0;
42184229
const is_comptime = member.comptime_token != null;
4219-
const unused = false;
42204230

42214231
if (!is_comptime) {
42224232
known_non_opv = known_non_opv or
42234233
nodeImpliesMoreThanOnePossibleValue(tree, member.ast.type_expr);
42244234
known_comptime_only = known_comptime_only or
42254235
nodeImpliesComptimeOnly(tree, member.ast.type_expr);
42264236
}
4227-
wip_members.nextField(bits_per_field, .{ have_align, have_value, is_comptime, unused });
4237+
wip_members.nextField(bits_per_field, .{ have_align, have_value, is_comptime, have_type_body });
4238+
4239+
if (have_type_body) {
4240+
if (!block_scope.endsWithNoReturn()) {
4241+
_ = try block_scope.addBreak(.break_inline, decl_inst, field_type);
4242+
}
4243+
const body = block_scope.instructionsSlice();
4244+
const old_scratch_len = astgen.scratch.items.len;
4245+
try astgen.scratch.ensureUnusedCapacity(gpa, countBodyLenAfterFixups(astgen, body));
4246+
appendBodyWithFixupsArrayList(astgen, &astgen.scratch, body);
4247+
wip_members.appendToField(@intCast(u32, astgen.scratch.items.len - old_scratch_len));
4248+
block_scope.instructions.items.len = block_scope.instructions_top;
4249+
} else {
4250+
wip_members.appendToField(@enumToInt(field_type));
4251+
}
42284252

42294253
if (have_align) {
42304254
if (layout == .Packed) {
42314255
try astgen.appendErrorNode(member.ast.align_expr, "unable to override alignment of packed struct fields", .{});
42324256
}
4233-
const align_inst = try expr(&block_scope, &namespace.base, align_rl, member.ast.align_expr);
4234-
wip_members.appendToField(@enumToInt(align_inst));
4257+
const align_ref = try expr(&block_scope, &namespace.base, coerced_align_rl, member.ast.align_expr);
4258+
if (!block_scope.endsWithNoReturn()) {
4259+
_ = try block_scope.addBreak(.break_inline, decl_inst, align_ref);
4260+
}
4261+
const body = block_scope.instructionsSlice();
4262+
const old_scratch_len = astgen.scratch.items.len;
4263+
try astgen.scratch.ensureUnusedCapacity(gpa, countBodyLenAfterFixups(astgen, body));
4264+
appendBodyWithFixupsArrayList(astgen, &astgen.scratch, body);
4265+
wip_members.appendToField(@intCast(u32, astgen.scratch.items.len - old_scratch_len));
4266+
block_scope.instructions.items.len = block_scope.instructions_top;
42354267
}
4268+
42364269
if (have_value) {
4237-
const rl: ResultLoc = if (field_type == .none) .none else .{ .ty = field_type };
4270+
const rl: ResultLoc = if (field_type == .none) .none else .{ .coerced_ty = field_type };
42384271

42394272
const default_inst = try expr(&block_scope, &namespace.base, rl, member.ast.value_expr);
4240-
wip_members.appendToField(@enumToInt(default_inst));
4273+
if (!block_scope.endsWithNoReturn()) {
4274+
_ = try block_scope.addBreak(.break_inline, decl_inst, default_inst);
4275+
}
4276+
const body = block_scope.instructionsSlice();
4277+
const old_scratch_len = astgen.scratch.items.len;
4278+
try astgen.scratch.ensureUnusedCapacity(gpa, countBodyLenAfterFixups(astgen, body));
4279+
appendBodyWithFixupsArrayList(astgen, &astgen.scratch, body);
4280+
wip_members.appendToField(@intCast(u32, astgen.scratch.items.len - old_scratch_len));
4281+
block_scope.instructions.items.len = block_scope.instructions_top;
42414282
} else if (member.comptime_token) |comptime_token| {
42424283
return astgen.failTok(comptime_token, "comptime field without default initialization value", .{});
42434284
}
42444285
}
42454286

4246-
if (!block_scope.isEmpty()) {
4247-
_ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
4248-
}
4249-
4250-
const body = block_scope.instructionsSlice();
4251-
const body_len = astgen.countBodyLenAfterFixups(body);
4252-
42534287
try gz.setStruct(decl_inst, .{
42544288
.src_node = node,
42554289
.layout = layout,
4256-
.body_len = body_len,
42574290
.fields_len = field_count,
42584291
.decls_len = decl_count,
42594292
.known_non_opv = known_non_opv,
@@ -4263,10 +4296,11 @@ fn structDeclInner(
42634296
wip_members.finishBits(bits_per_field);
42644297
const decls_slice = wip_members.declsSlice();
42654298
const fields_slice = wip_members.fieldsSlice();
4266-
try astgen.extra.ensureUnusedCapacity(gpa, decls_slice.len + body_len + fields_slice.len);
4299+
const bodies_slice = astgen.scratch.items[bodies_start..];
4300+
try astgen.extra.ensureUnusedCapacity(gpa, decls_slice.len + fields_slice.len + bodies_slice.len);
42674301
astgen.extra.appendSliceAssumeCapacity(decls_slice);
4268-
astgen.appendBodyWithFixups(body);
42694302
astgen.extra.appendSliceAssumeCapacity(fields_slice);
4303+
astgen.extra.appendSliceAssumeCapacity(bodies_slice);
42704304

42714305
block_scope.unstack();
42724306
try gz.addNamespaceCaptures(&namespace);
@@ -10981,7 +11015,6 @@ const GenZir = struct {
1098111015

1098211016
fn setStruct(gz: *GenZir, inst: Zir.Inst.Index, args: struct {
1098311017
src_node: Ast.Node.Index,
10984-
body_len: u32,
1098511018
fields_len: u32,
1098611019
decls_len: u32,
1098711020
layout: std.builtin.Type.ContainerLayout,
@@ -10998,9 +11031,6 @@ const GenZir = struct {
1099811031
const node_offset = gz.nodeIndexToRelative(args.src_node);
1099911032
astgen.extra.appendAssumeCapacity(@bitCast(u32, node_offset));
1100011033
}
11001-
if (args.body_len != 0) {
11002-
astgen.extra.appendAssumeCapacity(args.body_len);
11003-
}
1100411034
if (args.fields_len != 0) {
1100511035
astgen.extra.appendAssumeCapacity(args.fields_len);
1100611036
}
@@ -11013,7 +11043,6 @@ const GenZir = struct {
1101311043
.opcode = .struct_decl,
1101411044
.small = @bitCast(u16, Zir.Inst.StructDecl.Small{
1101511045
.has_src_node = args.src_node != 0,
11016-
.has_body_len = args.body_len != 0,
1101711046
.has_fields_len = args.fields_len != 0,
1101811047
.has_decls_len = args.decls_len != 0,
1101911048
.known_non_opv = args.known_non_opv,

src/Module.zig

+2-1
Original file line numberDiff line numberDiff line change
@@ -916,13 +916,14 @@ pub const Struct = struct {
916916
/// one possible value.
917917
known_non_opv: bool,
918918
requires_comptime: PropertyBoolean = .unknown,
919+
have_field_inits: bool = false,
919920

920921
pub const Fields = std.StringArrayHashMapUnmanaged(Field);
921922

922923
/// The `Type` and `Value` memory is owned by the arena of the Struct's owner_decl.
923924
pub const Field = struct {
924925
/// Uses `noreturn` to indicate `anytype`.
925-
/// undefined until `status` is `have_field_types` or `have_layout`.
926+
/// undefined until `status` is >= `have_field_types`.
926927
ty: Type,
927928
/// Uses `unreachable_value` to indicate no default.
928929
default_val: Value,

0 commit comments

Comments
 (0)