authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-07-11 22:34:03-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-07-13 02:38:13-04:00
log4a28c1d5c3627510cef97b88ee6b3988f65ac0dd
tree17d331556c594b52a4f03c143bf2720dbc3afeca
parent3708e26f4b8b9514f055ae2a0571d3290414bf8b

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 #12029

6 files changed, 331 insertions(+), 204 deletions(-)

src/AstGen.zig+56-27
...@@ -4148,7 +4148,6 @@ fn structDeclInner(...@@ -4148,7 +4148,6 @@ fn structDeclInner(
4148 .src_node = node,4148 .src_node = node,
4149 .layout = layout,4149 .layout = layout,
4150 .fields_len = 0,4150 .fields_len = 0,
4151 .body_len = 0,
4152 .decls_len = 0,4151 .decls_len = 0,
4153 .known_non_opv = false,4152 .known_non_opv = false,
4154 .known_comptime_only = false,4153 .known_comptime_only = false,
...@@ -4192,6 +4191,19 @@ fn structDeclInner(...@@ -4192,6 +4191,19 @@ fn structDeclInner(
4192 var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, field_count, bits_per_field, max_field_size);4191 var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, field_count, bits_per_field, max_field_size);
4193 defer wip_members.deinit();4192 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
4195 var known_non_opv = false;4207 var known_non_opv = false;
4196 var known_comptime_only = false;4208 var known_comptime_only = false;
4197 for (container_decl.ast.members) |member_node| {4209 for (container_decl.ast.members) |member_node| {
...@@ -4203,20 +4215,18 @@ fn structDeclInner(...@@ -4203,20 +4215,18 @@ fn structDeclInner(
4203 const field_name = try astgen.identAsString(member.ast.name_token);4215 const field_name = try astgen.identAsString(member.ast.name_token);
4204 wip_members.appendToField(field_name);4216 wip_members.appendToField(field_name);
42054217
4218 const doc_comment_index = try astgen.docCommentAsString(member.firstToken());
4219 wip_members.appendToField(doc_comment_index);
4220
4206 if (member.ast.type_expr == 0) {4221 if (member.ast.type_expr == 0) {
4207 return astgen.failTok(member.ast.name_token, "struct field missing type", .{});4222 return astgen.failTok(member.ast.name_token, "struct field missing type", .{});
4208 }4223 }
42094224
4210 const field_type = try typeExpr(&block_scope, &namespace.base, member.ast.type_expr);4225 const field_type = try typeExpr(&block_scope, &namespace.base, member.ast.type_expr);
4211 wip_members.appendToField(@enumToInt(field_type));4226 const have_type_body = !block_scope.isEmpty();
4212
4213 const doc_comment_index = try astgen.docCommentAsString(member.firstToken());
4214 wip_members.appendToField(doc_comment_index);
4215
4216 const have_align = member.ast.align_expr != 0;4227 const have_align = member.ast.align_expr != 0;
4217 const have_value = member.ast.value_expr != 0;4228 const have_value = member.ast.value_expr != 0;
4218 const is_comptime = member.comptime_token != null;4229 const is_comptime = member.comptime_token != null;
4219 const unused = false;
42204230
4221 if (!is_comptime) {4231 if (!is_comptime) {
4222 known_non_opv = known_non_opv or4232 known_non_opv = known_non_opv or
...@@ -4224,36 +4234,59 @@ fn structDeclInner(...@@ -4224,36 +4234,59 @@ fn structDeclInner(
4224 known_comptime_only = known_comptime_only or4234 known_comptime_only = known_comptime_only or
4225 nodeImpliesComptimeOnly(tree, member.ast.type_expr);4235 nodeImpliesComptimeOnly(tree, member.ast.type_expr);
4226 }4236 }
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
4229 if (have_align) {4253 if (have_align) {
4230 if (layout == .Packed) {4254 if (layout == .Packed) {
4231 try astgen.appendErrorNode(member.ast.align_expr, "unable to override alignment of packed struct fields", .{});4255 try astgen.appendErrorNode(member.ast.align_expr, "unable to override alignment of packed struct fields", .{});
4232 }4256 }
4233 const align_inst = try expr(&block_scope, &namespace.base, align_rl, member.ast.align_expr);4257 const align_ref = try expr(&block_scope, &namespace.base, coerced_align_rl, member.ast.align_expr);
4234 wip_members.appendToField(@enumToInt(align_inst));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;
4235 }4267 }
4268
4236 if (have_value) {4269 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
4239 const default_inst = try expr(&block_scope, &namespace.base, rl, member.ast.value_expr);4272 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;
4241 } else if (member.comptime_token) |comptime_token| {4282 } else if (member.comptime_token) |comptime_token| {
4242 return astgen.failTok(comptime_token, "comptime field without default initialization value", .{});4283 return astgen.failTok(comptime_token, "comptime field without default initialization value", .{});
4243 }4284 }
4244 }4285 }
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
4253 try gz.setStruct(decl_inst, .{4287 try gz.setStruct(decl_inst, .{
4254 .src_node = node,4288 .src_node = node,
4255 .layout = layout,4289 .layout = layout,
4256 .body_len = body_len,
4257 .fields_len = field_count,4290 .fields_len = field_count,
4258 .decls_len = decl_count,4291 .decls_len = decl_count,
4259 .known_non_opv = known_non_opv,4292 .known_non_opv = known_non_opv,
...@@ -4263,10 +4296,11 @@ fn structDeclInner(...@@ -4263,10 +4296,11 @@ fn structDeclInner(
4263 wip_members.finishBits(bits_per_field);4296 wip_members.finishBits(bits_per_field);
4264 const decls_slice = wip_members.declsSlice();4297 const decls_slice = wip_members.declsSlice();
4265 const fields_slice = wip_members.fieldsSlice();4298 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);
4267 astgen.extra.appendSliceAssumeCapacity(decls_slice);4301 astgen.extra.appendSliceAssumeCapacity(decls_slice);
4268 astgen.appendBodyWithFixups(body);
4269 astgen.extra.appendSliceAssumeCapacity(fields_slice);4302 astgen.extra.appendSliceAssumeCapacity(fields_slice);
4303 astgen.extra.appendSliceAssumeCapacity(bodies_slice);
42704304
4271 block_scope.unstack();4305 block_scope.unstack();
4272 try gz.addNamespaceCaptures(&namespace);4306 try gz.addNamespaceCaptures(&namespace);
...@@ -10981,7 +11015,6 @@ const GenZir = struct {...@@ -10981,7 +11015,6 @@ const GenZir = struct {
1098111015
10982 fn setStruct(gz: *GenZir, inst: Zir.Inst.Index, args: struct {11016 fn setStruct(gz: *GenZir, inst: Zir.Inst.Index, args: struct {
10983 src_node: Ast.Node.Index,11017 src_node: Ast.Node.Index,
10984 body_len: u32,
10985 fields_len: u32,11018 fields_len: u32,
10986 decls_len: u32,11019 decls_len: u32,
10987 layout: std.builtin.Type.ContainerLayout,11020 layout: std.builtin.Type.ContainerLayout,
...@@ -10998,9 +11031,6 @@ const GenZir = struct {...@@ -10998,9 +11031,6 @@ const GenZir = struct {
10998 const node_offset = gz.nodeIndexToRelative(args.src_node);11031 const node_offset = gz.nodeIndexToRelative(args.src_node);
10999 astgen.extra.appendAssumeCapacity(@bitCast(u32, node_offset));11032 astgen.extra.appendAssumeCapacity(@bitCast(u32, node_offset));
11000 }11033 }
11001 if (args.body_len != 0) {
11002 astgen.extra.appendAssumeCapacity(args.body_len);
11003 }
11004 if (args.fields_len != 0) {11034 if (args.fields_len != 0) {
11005 astgen.extra.appendAssumeCapacity(args.fields_len);11035 astgen.extra.appendAssumeCapacity(args.fields_len);
11006 }11036 }
...@@ -11013,7 +11043,6 @@ const GenZir = struct {...@@ -11013,7 +11043,6 @@ const GenZir = struct {
11013 .opcode = .struct_decl,11043 .opcode = .struct_decl,
11014 .small = @bitCast(u16, Zir.Inst.StructDecl.Small{11044 .small = @bitCast(u16, Zir.Inst.StructDecl.Small{
11015 .has_src_node = args.src_node != 0,11045 .has_src_node = args.src_node != 0,
11016 .has_body_len = args.body_len != 0,
11017 .has_fields_len = args.fields_len != 0,11046 .has_fields_len = args.fields_len != 0,
11018 .has_decls_len = args.decls_len != 0,11047 .has_decls_len = args.decls_len != 0,
11019 .known_non_opv = args.known_non_opv,11048 .known_non_opv = args.known_non_opv,
src/Module.zig+2-1
...@@ -916,13 +916,14 @@ pub const Struct = struct {...@@ -916,13 +916,14 @@ pub const Struct = struct {
916 /// one possible value.916 /// one possible value.
917 known_non_opv: bool,917 known_non_opv: bool,
918 requires_comptime: PropertyBoolean = .unknown,918 requires_comptime: PropertyBoolean = .unknown,
919 have_field_inits: bool = false,
919920
920 pub const Fields = std.StringArrayHashMapUnmanaged(Field);921 pub const Fields = std.StringArrayHashMapUnmanaged(Field);
921922
922 /// The `Type` and `Value` memory is owned by the arena of the Struct's owner_decl.923 /// The `Type` and `Value` memory is owned by the arena of the Struct's owner_decl.
923 pub const Field = struct {924 pub const Field = struct {
924 /// Uses `noreturn` to indicate `anytype`.925 /// Uses `noreturn` to indicate `anytype`.
925 /// undefined until `status` is `have_field_types` or `have_layout`.926 /// undefined until `status` is >= `have_field_types`.
926 ty: Type,927 ty: Type,
927 /// Uses `unreachable_value` to indicate no default.928 /// Uses `unreachable_value` to indicate no default.
928 default_val: Value,929 default_val: Value,
src/Sema.zig+154-109
...@@ -1862,13 +1862,15 @@ fn failWithOwnedErrorMsg(sema: *Sema, block: *Block, err_msg: *Module.ErrorMsg)...@@ -1862,13 +1862,15 @@ fn failWithOwnedErrorMsg(sema: *Sema, block: *Block, err_msg: *Module.ErrorMsg)
1862 return error.AnalysisFail;1862 return error.AnalysisFail;
1863}1863}
18641864
1865pub fn resolveAlign(1865const align_ty = Type.u29;
1866
1867fn analyzeAsAlign(
1866 sema: *Sema,1868 sema: *Sema,
1867 block: *Block,1869 block: *Block,
1868 src: LazySrcLoc,1870 src: LazySrcLoc,
1869 zir_ref: Zir.Inst.Ref,1871 air_ref: Air.Inst.Ref,
1870) !u32 {1872) !u32 {
1871 const alignment_big = try sema.resolveInt(block, src, zir_ref, Type.initTag(.u29));1873 const alignment_big = try sema.analyzeAsInt(block, src, air_ref, align_ty);
1872 const alignment = @intCast(u32, alignment_big); // We coerce to u16 in the prev line.1874 const alignment = @intCast(u32, alignment_big); // We coerce to u16 in the prev line.
1873 if (alignment == 0) return sema.fail(block, src, "alignment must be >= 1", .{});1875 if (alignment == 0) return sema.fail(block, src, "alignment must be >= 1", .{});
1874 if (!std.math.isPowerOfTwo(alignment)) {1876 if (!std.math.isPowerOfTwo(alignment)) {
...@@ -1879,6 +1881,16 @@ pub fn resolveAlign(...@@ -1879,6 +1881,16 @@ pub fn resolveAlign(
1879 return alignment;1881 return alignment;
1880}1882}
18811883
1884pub fn resolveAlign(
1885 sema: *Sema,
1886 block: *Block,
1887 src: LazySrcLoc,
1888 zir_ref: Zir.Inst.Ref,
1889) !u32 {
1890 const air_ref = try sema.resolveInst(zir_ref);
1891 return analyzeAsAlign(sema, block, src, air_ref);
1892}
1893
1882fn resolveInt(1894fn resolveInt(
1883 sema: *Sema,1895 sema: *Sema,
1884 block: *Block,1896 block: *Block,
...@@ -1886,8 +1898,18 @@ fn resolveInt(...@@ -1886,8 +1898,18 @@ fn resolveInt(
1886 zir_ref: Zir.Inst.Ref,1898 zir_ref: Zir.Inst.Ref,
1887 dest_ty: Type,1899 dest_ty: Type,
1888) !u64 {1900) !u64 {
1889 const air_inst = try sema.resolveInst(zir_ref);1901 const air_ref = try sema.resolveInst(zir_ref);
1890 const coerced = try sema.coerce(block, dest_ty, air_inst, src);1902 return analyzeAsInt(sema, block, src, air_ref, dest_ty);
1903}
1904
1905fn analyzeAsInt(
1906 sema: *Sema,
1907 block: *Block,
1908 src: LazySrcLoc,
1909 air_ref: Air.Inst.Ref,
1910 dest_ty: Type,
1911) !u64 {
1912 const coerced = try sema.coerce(block, dest_ty, air_ref, src);
1891 const val = try sema.resolveConstValue(block, src, coerced);1913 const val = try sema.resolveConstValue(block, src, coerced);
1892 const target = sema.mod.getTarget();1914 const target = sema.mod.getTarget();
1893 return (try val.getUnsignedIntAdvanced(target, sema.kit(block, src))).?;1915 return (try val.getUnsignedIntAdvanced(target, sema.kit(block, src))).?;
...@@ -2097,7 +2119,6 @@ pub fn analyzeStructDecl(...@@ -2097,7 +2119,6 @@ pub fn analyzeStructDecl(
20972119
2098 var extra_index: usize = extended.operand;2120 var extra_index: usize = extended.operand;
2099 extra_index += @boolToInt(small.has_src_node);2121 extra_index += @boolToInt(small.has_src_node);
2100 extra_index += @boolToInt(small.has_body_len);
2101 extra_index += @boolToInt(small.has_fields_len);2122 extra_index += @boolToInt(small.has_fields_len);
2102 const decls_len = if (small.has_decls_len) blk: {2123 const decls_len = if (small.has_decls_len) blk: {
2103 const decls_len = sema.code.extra[extra_index];2124 const decls_len = sema.code.extra[extra_index];
...@@ -24858,12 +24879,6 @@ fn resolveTypeFieldsStruct(...@@ -24858,12 +24879,6 @@ fn resolveTypeFieldsStruct(
2485824879
24859 struct_obj.status = .field_types_wip;24880 struct_obj.status = .field_types_wip;
24860 try semaStructFields(sema.mod, struct_obj);24881 try semaStructFields(sema.mod, struct_obj);
24861
24862 if (struct_obj.fields.count() == 0) {
24863 struct_obj.status = .have_layout;
24864 } else {
24865 struct_obj.status = .have_field_types;
24866 }
24867}24882}
2486824883
24869fn resolveTypeFieldsUnion(24884fn resolveTypeFieldsUnion(
...@@ -24954,13 +24969,7 @@ fn resolveInferredErrorSetTy(...@@ -24954,13 +24969,7 @@ fn resolveInferredErrorSetTy(
24954 }24969 }
24955}24970}
2495624971
24957fn semaStructFields(24972fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void {
24958 mod: *Module,
24959 struct_obj: *Module.Struct,
24960) CompileError!void {
24961 const tracy = trace(@src());
24962 defer tracy.end();
24963
24964 const gpa = mod.gpa;24973 const gpa = mod.gpa;
24965 const decl_index = struct_obj.owner_decl;24974 const decl_index = struct_obj.owner_decl;
24966 const zir = struct_obj.namespace.file_scope.zir;24975 const zir = struct_obj.namespace.file_scope.zir;
...@@ -24972,12 +24981,6 @@ fn semaStructFields(...@@ -24972,12 +24981,6 @@ fn semaStructFields(
24972 const src = LazySrcLoc.nodeOffset(struct_obj.node_offset);24981 const src = LazySrcLoc.nodeOffset(struct_obj.node_offset);
24973 extra_index += @boolToInt(small.has_src_node);24982 extra_index += @boolToInt(small.has_src_node);
2497424983
24975 const body_len = if (small.has_body_len) blk: {
24976 const body_len = zir.extra[extra_index];
24977 extra_index += 1;
24978 break :blk body_len;
24979 } else 0;
24980
24981 const fields_len = if (small.has_fields_len) blk: {24984 const fields_len = if (small.has_fields_len) blk: {
24982 const fields_len = zir.extra[extra_index];24985 const fields_len = zir.extra[extra_index];
24983 extra_index += 1;24986 extra_index += 1;
...@@ -24995,12 +24998,10 @@ fn semaStructFields(...@@ -24995,12 +24998,10 @@ fn semaStructFields(
24995 while (decls_it.next()) |_| {}24998 while (decls_it.next()) |_| {}
24996 extra_index = decls_it.extra_index;24999 extra_index = decls_it.extra_index;
2499725000
24998 const body = zir.extra[extra_index..][0..body_len];
24999 if (fields_len == 0) {25001 if (fields_len == 0) {
25000 assert(body.len == 0);25002 struct_obj.status = .have_layout;
25001 return;25003 return;
25002 }25004 }
25003 extra_index += body.len;
2500425005
25005 const decl = mod.declPtr(decl_index);25006 const decl = mod.declPtr(decl_index);
25006 var decl_arena = decl.value_arena.?.promote(gpa);25007 var decl_arena = decl.value_arena.?.promote(gpa);
...@@ -25042,106 +25043,150 @@ fn semaStructFields(...@@ -25042,106 +25043,150 @@ fn semaStructFields(
25042 block_scope.params.deinit(gpa);25043 block_scope.params.deinit(gpa);
25043 }25044 }
2504425045
25045 if (body.len != 0) {25046 try struct_obj.fields.ensureTotalCapacity(decl_arena_allocator, fields_len);
25046 try sema.analyzeBody(&block_scope, body);
25047 }
2504825047
25049 try wip_captures.finalize();25048 const Field = struct {
25049 type_body_len: u32 = 0,
25050 align_body_len: u32 = 0,
25051 init_body_len: u32 = 0,
25052 type_ref: Air.Inst.Ref = .none,
25053 };
25054 const fields = try sema.arena.alloc(Field, fields_len);
25055 var any_inits = false;
2505025056
25051 try struct_obj.fields.ensureTotalCapacity(decl_arena_allocator, fields_len);25057 {
25058 const bits_per_field = 4;
25059 const fields_per_u32 = 32 / bits_per_field;
25060 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
25061 const flags_index = extra_index;
25062 var bit_bag_index: usize = flags_index;
25063 extra_index += bit_bags_count;
25064 var cur_bit_bag: u32 = undefined;
25065 var field_i: u32 = 0;
25066 while (field_i < fields_len) : (field_i += 1) {
25067 if (field_i % fields_per_u32 == 0) {
25068 cur_bit_bag = zir.extra[bit_bag_index];
25069 bit_bag_index += 1;
25070 }
25071 const has_align = @truncate(u1, cur_bit_bag) != 0;
25072 cur_bit_bag >>= 1;
25073 const has_init = @truncate(u1, cur_bit_bag) != 0;
25074 cur_bit_bag >>= 1;
25075 const is_comptime = @truncate(u1, cur_bit_bag) != 0;
25076 cur_bit_bag >>= 1;
25077 const has_type_body = @truncate(u1, cur_bit_bag) != 0;
25078 cur_bit_bag >>= 1;
25079
25080 const field_name_zir = zir.nullTerminatedString(zir.extra[extra_index]);
25081 extra_index += 1;
25082 extra_index += 1; // doc_comment
2505225083
25053 const bits_per_field = 4;25084 fields[field_i] = .{};
25054 const fields_per_u32 = 32 / bits_per_field;
25055 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
25056 var bit_bag_index: usize = extra_index;
25057 extra_index += bit_bags_count;
25058 var cur_bit_bag: u32 = undefined;
25059 var field_i: u32 = 0;
25060 while (field_i < fields_len) : (field_i += 1) {
25061 if (field_i % fields_per_u32 == 0) {
25062 cur_bit_bag = zir.extra[bit_bag_index];
25063 bit_bag_index += 1;
25064 }
25065 const has_align = @truncate(u1, cur_bit_bag) != 0;
25066 cur_bit_bag >>= 1;
25067 const has_default = @truncate(u1, cur_bit_bag) != 0;
25068 cur_bit_bag >>= 1;
25069 const is_comptime = @truncate(u1, cur_bit_bag) != 0;
25070 cur_bit_bag >>= 1;
25071 const unused = @truncate(u1, cur_bit_bag) != 0;
25072 cur_bit_bag >>= 1;
2507325085
25074 _ = unused;25086 if (has_type_body) {
25087 fields[field_i].type_body_len = zir.extra[extra_index];
25088 } else {
25089 fields[field_i].type_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
25090 }
25091 extra_index += 1;
2507525092
25076 const field_name_zir = zir.nullTerminatedString(zir.extra[extra_index]);25093 // This string needs to outlive the ZIR code.
25077 extra_index += 1;25094 const field_name = try decl_arena_allocator.dupe(u8, field_name_zir);
25078 const field_type_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
25079 extra_index += 1;
2508025095
25081 // doc_comment25096 const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name);
25082 extra_index += 1;25097 if (gop.found_existing) {
25098 const msg = msg: {
25099 const tree = try sema.getAstTree(&block_scope);
25100 const field_src = enumFieldSrcLoc(decl, tree.*, struct_obj.node_offset, field_i);
25101 const msg = try sema.errMsg(&block_scope, field_src, "duplicate struct field: '{s}'", .{field_name});
25102 errdefer msg.destroy(gpa);
2508325103
25084 // This string needs to outlive the ZIR code.25104 const prev_field_index = struct_obj.fields.getIndex(field_name).?;
25085 const field_name = try decl_arena_allocator.dupe(u8, field_name_zir);25105 const prev_field_src = enumFieldSrcLoc(decl, tree.*, struct_obj.node_offset, prev_field_index);
25086 const field_ty: Type = if (field_type_ref == .none)25106 try sema.mod.errNoteNonLazy(prev_field_src.toSrcLoc(decl), msg, "other field here", .{});
25087 Type.initTag(.noreturn)25107 try sema.errNote(&block_scope, src, msg, "struct declared here", .{});
25088 else25108 break :msg msg;
25089 // TODO: if we need to report an error here, use a source location25109 };
25090 // that points to this type expression rather than the struct.25110 return sema.failWithOwnedErrorMsg(&block_scope, msg);
25091 // But only resolve the source location if we need to emit a compile error.25111 }
25092 try sema.resolveType(&block_scope, src, field_type_ref);25112 gop.value_ptr.* = .{
25113 .ty = Type.initTag(.noreturn),
25114 .abi_align = 0,
25115 .default_val = Value.initTag(.unreachable_value),
25116 .is_comptime = is_comptime,
25117 .offset = undefined,
25118 };
25119
25120 if (has_align) {
25121 fields[field_i].align_body_len = zir.extra[extra_index];
25122 extra_index += 1;
25123 }
25124 if (has_init) {
25125 fields[field_i].init_body_len = zir.extra[extra_index];
25126 extra_index += 1;
25127 any_inits = true;
25128 }
25129 }
25130 }
25131
25132 // Next we do only types and alignments, saving the inits for a second pass,
25133 // so that init values may depend on type layout.
25134 const bodies_index = extra_index;
2509325135
25136 for (fields) |zir_field, i| {
25094 // TODO emit compile errors for invalid field types25137 // TODO emit compile errors for invalid field types
25095 // such as arrays and pointers inside packed structs.25138 // such as arrays and pointers inside packed structs.
2509625139 const field_ty: Type = ty: {
25140 if (zir_field.type_ref != .none) {
25141 // TODO: if we need to report an error here, use a source location
25142 // that points to this type expression rather than the struct.
25143 // But only resolve the source location if we need to emit a compile error.
25144 break :ty try sema.resolveType(&block_scope, src, zir_field.type_ref);
25145 }
25146 assert(zir_field.type_body_len != 0);
25147 const body = zir.extra[extra_index..][0..zir_field.type_body_len];
25148 extra_index += body.len;
25149 const ty_ref = try sema.resolveBody(&block_scope, body, struct_obj.zir_index);
25150 break :ty try sema.analyzeAsType(&block_scope, src, ty_ref);
25151 };
25097 if (field_ty.tag() == .generic_poison) {25152 if (field_ty.tag() == .generic_poison) {
25098 return error.GenericPoison;25153 return error.GenericPoison;
25099 }25154 }
2510025155
25101 const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name);25156 const field = &struct_obj.fields.values()[i];
25102 if (gop.found_existing) {25157 field.ty = try field_ty.copy(decl_arena_allocator);
25103 const msg = msg: {
25104 const tree = try sema.getAstTree(&block_scope);
25105 const field_src = enumFieldSrcLoc(decl, tree.*, struct_obj.node_offset, field_i);
25106 const msg = try sema.errMsg(&block_scope, field_src, "duplicate struct field: '{s}'", .{field_name});
25107 errdefer msg.destroy(gpa);
2510825158
25109 const prev_field_index = struct_obj.fields.getIndex(field_name).?;25159 if (zir_field.align_body_len > 0) {
25110 const prev_field_src = enumFieldSrcLoc(decl, tree.*, struct_obj.node_offset, prev_field_index);25160 const body = zir.extra[extra_index..][0..zir_field.align_body_len];
25111 try sema.mod.errNoteNonLazy(prev_field_src.toSrcLoc(decl), msg, "other field here", .{});25161 extra_index += body.len;
25112 try sema.errNote(&block_scope, src, msg, "struct declared here", .{});25162 const align_ref = try sema.resolveBody(&block_scope, body, struct_obj.zir_index);
25113 break :msg msg;25163 field.abi_align = try sema.analyzeAsAlign(&block_scope, src, align_ref);
25114 };
25115 return sema.failWithOwnedErrorMsg(&block_scope, msg);
25116 }25164 }
25117 gop.value_ptr.* = .{
25118 .ty = try field_ty.copy(decl_arena_allocator),
25119 .abi_align = 0,
25120 .default_val = Value.initTag(.unreachable_value),
25121 .is_comptime = is_comptime,
25122 .offset = undefined,
25123 };
2512425165
25125 if (has_align) {25166 extra_index += zir_field.init_body_len;
25126 const align_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);25167 }
25127 extra_index += 1;25168
25128 // TODO: if we need to report an error here, use a source location25169 struct_obj.status = .have_field_types;
25129 // that points to this alignment expression rather than the struct.25170
25130 // But only resolve the source location if we need to emit a compile error.25171 if (any_inits) {
25131 gop.value_ptr.abi_align = try sema.resolveAlign(&block_scope, src, align_ref);25172 extra_index = bodies_index;
25132 }25173 for (fields) |zir_field, i| {
25133 if (has_default) {25174 extra_index += zir_field.type_body_len;
25134 const default_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);25175 extra_index += zir_field.align_body_len;
25135 extra_index += 1;25176 if (zir_field.init_body_len > 0) {
25136 const default_inst = try sema.resolveInst(default_ref);25177 const body = zir.extra[extra_index..][0..zir_field.init_body_len];
25137 // TODO: if we need to report an error here, use a source location25178 extra_index += body.len;
25138 // that points to this default value expression rather than the struct.25179 const init = try sema.resolveBody(&block_scope, body, struct_obj.zir_index);
25139 // But only resolve the source location if we need to emit a compile error.25180 const field = &struct_obj.fields.values()[i];
25140 const default_val = (try sema.resolveMaybeUndefVal(&block_scope, src, default_inst)) orelse25181 const coerced = try sema.coerce(&block_scope, field.ty, init, src);
25141 return sema.failWithNeededComptime(&block_scope, src);25182 const default_val = (try sema.resolveMaybeUndefVal(&block_scope, src, coerced)) orelse
25142 gop.value_ptr.default_val = try default_val.copy(decl_arena_allocator);25183 return sema.failWithNeededComptime(&block_scope, src);
25184 field.default_val = try default_val.copy(decl_arena_allocator);
25185 }
25143 }25186 }
25144 }25187 }
25188
25189 struct_obj.have_field_inits = true;
25145}25190}
2514625191
25147fn semaUnionFields(block: *Block, mod: *Module, union_obj: *Module.Union) CompileError!void {25192fn semaUnionFields(block: *Block, mod: *Module, union_obj: *Module.Union) CompileError!void {
src/Zir.zig+17-16
...@@ -3093,16 +3093,15 @@ pub const Inst = struct {...@@ -3093,16 +3093,15 @@ pub const Inst = struct {
30933093
3094 /// Trailing:3094 /// Trailing:
3095 /// 0. src_node: i32, // if has_src_node3095 /// 0. src_node: i32, // if has_src_node
3096 /// 1. body_len: u32, // if has_body_len3096 /// 1. fields_len: u32, // if has_fields_len
3097 /// 2. fields_len: u32, // if has_fields_len3097 /// 2. decls_len: u32, // if has_decls_len
3098 /// 3. decls_len: u32, // if has_decls_len3098 /// 3. decl_bits: u32 // for every 8 decls
3099 /// 4. decl_bits: u32 // for every 8 decls
3100 /// - sets of 4 bits:3099 /// - sets of 4 bits:
3101 /// 0b000X: whether corresponding decl is pub3100 /// 0b000X: whether corresponding decl is pub
3102 /// 0b00X0: whether corresponding decl is exported3101 /// 0b00X0: whether corresponding decl is exported
3103 /// 0b0X00: whether corresponding decl has an align expression3102 /// 0b0X00: whether corresponding decl has an align expression
3104 /// 0bX000: whether corresponding decl has a linksection or an address space expression3103 /// 0bX000: whether corresponding decl has a linksection or an address space expression
3105 /// 5. decl: { // for every decls_len3104 /// 4. decl: { // for every decls_len
3106 /// src_hash: [4]u32, // hash of source bytes3105 /// src_hash: [4]u32, // hash of source bytes
3107 /// line: u32, // line number of decl, relative to parent3106 /// line: u32, // line number of decl, relative to parent
3108 /// name: u32, // null terminated string index3107 /// name: u32, // null terminated string index
...@@ -3120,32 +3119,35 @@ pub const Inst = struct {...@@ -3120,32 +3119,35 @@ pub const Inst = struct {
3120 /// address_space: Ref,3119 /// address_space: Ref,
3121 /// }3120 /// }
3122 /// }3121 /// }
3123 /// 6. inst: Index // for every body_len3122 /// 5. flags: u32 // for every 8 fields
3124 /// 7. flags: u32 // for every 8 fields
3125 /// - sets of 4 bits:3123 /// - sets of 4 bits:
3126 /// 0b000X: whether corresponding field has an align expression3124 /// 0b000X: whether corresponding field has an align expression
3127 /// 0b00X0: whether corresponding field has a default expression3125 /// 0b00X0: whether corresponding field has a default expression
3128 /// 0b0X00: whether corresponding field is comptime3126 /// 0b0X00: whether corresponding field is comptime
3129 /// 0bX000: unused3127 /// 0bX000: whether corresponding field has a type expression
3130 /// 8. fields: { // for every fields_len3128 /// 6. fields: { // for every fields_len
3131 /// field_name: u32,3129 /// field_name: u32,
3132 /// field_type: Ref,
3133 /// - if none, means `anytype`.
3134 /// doc_comment: u32, // 0 if no doc comment3130 /// doc_comment: u32, // 0 if no doc comment
3135 /// align: Ref, // if corresponding bit is set3131 /// field_type: Ref, // if corresponding bit is not set. none means anytype.
3136 /// default_value: Ref, // if corresponding bit is set3132 /// field_type_body_len: u32, // if corresponding bit is set
3133 /// align_body_len: u32, // if corresponding bit is set
3134 /// init_body_len: u32, // if corresponding bit is set
3135 /// }
3136 /// 7. bodies: { // for every fields_len
3137 /// field_type_body_inst: Inst, // for each field_type_body_len
3138 /// align_body_inst: Inst, // for each align_body_len
3139 /// init_body_inst: Inst, // for each init_body_len
3137 /// }3140 /// }
3138 pub const StructDecl = struct {3141 pub const StructDecl = struct {
3139 pub const Small = packed struct {3142 pub const Small = packed struct {
3140 has_src_node: bool,3143 has_src_node: bool,
3141 has_body_len: bool,
3142 has_fields_len: bool,3144 has_fields_len: bool,
3143 has_decls_len: bool,3145 has_decls_len: bool,
3144 known_non_opv: bool,3146 known_non_opv: bool,
3145 known_comptime_only: bool,3147 known_comptime_only: bool,
3146 name_strategy: NameStrategy,3148 name_strategy: NameStrategy,
3147 layout: std.builtin.Type.ContainerLayout,3149 layout: std.builtin.Type.ContainerLayout,
3148 _: u6 = undefined,3150 _: u7 = undefined,
3149 };3151 };
3150 };3152 };
31513153
...@@ -3594,7 +3596,6 @@ pub fn declIterator(zir: Zir, decl_inst: u32) DeclIterator {...@@ -3594,7 +3596,6 @@ pub fn declIterator(zir: Zir, decl_inst: u32) DeclIterator {
3594 const small = @bitCast(Inst.StructDecl.Small, extended.small);3596 const small = @bitCast(Inst.StructDecl.Small, extended.small);
3595 var extra_index: usize = extended.operand;3597 var extra_index: usize = extended.operand;
3596 extra_index += @boolToInt(small.has_src_node);3598 extra_index += @boolToInt(small.has_src_node);
3597 extra_index += @boolToInt(small.has_body_len);
3598 extra_index += @boolToInt(small.has_fields_len);3599 extra_index += @boolToInt(small.has_fields_len);
3599 const decls_len = if (small.has_decls_len) decls_len: {3600 const decls_len = if (small.has_decls_len) decls_len: {
3600 const decls_len = zir.extra[extra_index];3601 const decls_len = zir.extra[extra_index];
src/print_zir.zig+88-51
...@@ -1227,12 +1227,6 @@ const Writer = struct {...@@ -1227,12 +1227,6 @@ const Writer = struct {
1227 break :blk src_node;1227 break :blk src_node;
1228 } else null;1228 } else null;
12291229
1230 const body_len = if (small.has_body_len) blk: {
1231 const body_len = self.code.extra[extra_index];
1232 extra_index += 1;
1233 break :blk body_len;
1234 } else 0;
1235
1236 const fields_len = if (small.has_fields_len) blk: {1230 const fields_len = if (small.has_fields_len) blk: {
1237 const fields_len = self.code.extra[extra_index];1231 const fields_len = self.code.extra[extra_index];
1238 extra_index += 1;1232 extra_index += 1;
...@@ -1262,71 +1256,114 @@ const Writer = struct {...@@ -1262,71 +1256,114 @@ const Writer = struct {
1262 try stream.writeAll("}, ");1256 try stream.writeAll("}, ");
1263 }1257 }
12641258
1265 const body = self.code.extra[extra_index..][0..body_len];
1266 extra_index += body.len;
1267
1268 if (fields_len == 0) {1259 if (fields_len == 0) {
1269 assert(body.len == 0);
1270 try stream.writeAll("{}, {})");1260 try stream.writeAll("{}, {})");
1271 } else {1261 } else {
1272 const prev_parent_decl_node = self.parent_decl_node;
1273 if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off);
1274 try self.writeBracedDecl(stream, body);
1275 try stream.writeAll(", {\n");
1276
1277 self.indent += 2;
1278 const bits_per_field = 4;1262 const bits_per_field = 4;
1279 const fields_per_u32 = 32 / bits_per_field;1263 const fields_per_u32 = 32 / bits_per_field;
1280 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;1264 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
1281 var bit_bag_index: usize = extra_index;1265 const Field = struct {
1282 extra_index += bit_bags_count;1266 doc_comment_index: u32,
1283 var cur_bit_bag: u32 = undefined;1267 type_len: u32 = 0,
1284 var field_i: u32 = 0;1268 align_len: u32 = 0,
1285 while (field_i < fields_len) : (field_i += 1) {1269 init_len: u32 = 0,
1286 if (field_i % fields_per_u32 == 0) {1270 field_type: Zir.Inst.Ref = .none,
1287 cur_bit_bag = self.code.extra[bit_bag_index];1271 name: u32,
1288 bit_bag_index += 1;1272 is_comptime: bool,
1289 }1273 };
1290 const has_align = @truncate(u1, cur_bit_bag) != 0;1274 const fields = try self.arena.alloc(Field, fields_len);
1291 cur_bit_bag >>= 1;1275 {
1292 const has_default = @truncate(u1, cur_bit_bag) != 0;1276 var bit_bag_index: usize = extra_index;
1293 cur_bit_bag >>= 1;1277 extra_index += bit_bags_count;
1294 const is_comptime = @truncate(u1, cur_bit_bag) != 0;1278 var cur_bit_bag: u32 = undefined;
1295 cur_bit_bag >>= 1;1279 var field_i: u32 = 0;
1296 const unused = @truncate(u1, cur_bit_bag) != 0;1280 while (field_i < fields_len) : (field_i += 1) {
1297 cur_bit_bag >>= 1;1281 if (field_i % fields_per_u32 == 0) {
1282 cur_bit_bag = self.code.extra[bit_bag_index];
1283 bit_bag_index += 1;
1284 }
1285 const has_align = @truncate(u1, cur_bit_bag) != 0;
1286 cur_bit_bag >>= 1;
1287 const has_default = @truncate(u1, cur_bit_bag) != 0;
1288 cur_bit_bag >>= 1;
1289 const is_comptime = @truncate(u1, cur_bit_bag) != 0;
1290 cur_bit_bag >>= 1;
1291 const has_type_body = @truncate(u1, cur_bit_bag) != 0;
1292 cur_bit_bag >>= 1;
1293
1294 const field_name = self.code.extra[extra_index];
1295 extra_index += 1;
1296 const doc_comment_index = self.code.extra[extra_index];
1297 extra_index += 1;
12981298
1299 _ = unused;1299 fields[field_i] = .{
1300 .doc_comment_index = doc_comment_index,
1301 .is_comptime = is_comptime,
1302 .name = field_name,
1303 };
13001304
1301 const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]);1305 if (has_type_body) {
1302 extra_index += 1;1306 fields[field_i].type_len = self.code.extra[extra_index];
1303 const field_type = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);1307 } else {
1304 extra_index += 1;1308 fields[field_i].field_type = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
1305 const doc_comment_index = self.code.extra[extra_index];1309 }
1306 extra_index += 1;1310 extra_index += 1;
13071311
1308 try self.writeDocComment(stream, doc_comment_index);1312 if (has_align) {
1313 fields[field_i].align_len = self.code.extra[extra_index];
1314 extra_index += 1;
1315 }
1316
1317 if (has_default) {
1318 fields[field_i].init_len = self.code.extra[extra_index];
1319 extra_index += 1;
1320 }
1321 }
1322 }
1323
1324 const prev_parent_decl_node = self.parent_decl_node;
1325 if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off);
1326 try stream.writeAll("{\n");
1327 self.indent += 2;
13091328
1329 for (fields) |field| {
1330 const field_name = self.code.nullTerminatedString(field.name);
1331
1332 try self.writeDocComment(stream, field.doc_comment_index);
1310 try stream.writeByteNTimes(' ', self.indent);1333 try stream.writeByteNTimes(' ', self.indent);
1311 try self.writeFlag(stream, "comptime ", is_comptime);1334 try self.writeFlag(stream, "comptime ", field.is_comptime);
1312 try stream.print("{}: ", .{std.zig.fmtId(field_name)});1335 try stream.print("{}: ", .{std.zig.fmtId(field_name)});
1313 try self.writeInstRef(stream, field_type);1336 if (field.field_type != .none) {
1337 try self.writeInstRef(stream, field.field_type);
1338 }
13141339
1315 if (has_align) {1340 if (field.type_len > 0) {
1316 const align_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);1341 const body = self.code.extra[extra_index..][0..field.type_len];
1317 extra_index += 1;1342 extra_index += body.len;
1343 self.indent += 2;
1344 try self.writeBracedDecl(stream, body);
1345 self.indent -= 2;
1346 }
13181347
1348 if (field.align_len > 0) {
1349 const body = self.code.extra[extra_index..][0..field.align_len];
1350 extra_index += body.len;
1351 self.indent += 2;
1319 try stream.writeAll(" align(");1352 try stream.writeAll(" align(");
1320 try self.writeInstRef(stream, align_ref);1353 try self.writeBracedDecl(stream, body);
1321 try stream.writeAll(")");1354 try stream.writeAll(")");
1355 self.indent -= 2;
1322 }1356 }
1323 if (has_default) {
1324 const default_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
1325 extra_index += 1;
13261357
1358 if (field.init_len > 0) {
1359 const body = self.code.extra[extra_index..][0..field.init_len];
1360 extra_index += body.len;
1361 self.indent += 2;
1327 try stream.writeAll(" = ");1362 try stream.writeAll(" = ");
1328 try self.writeInstRef(stream, default_ref);1363 try self.writeBracedDecl(stream, body);
1364 self.indent -= 2;
1329 }1365 }
1366
1330 try stream.writeAll(",\n");1367 try stream.writeAll(",\n");
1331 }1368 }
13321369
test/behavior/struct.zig+14
...@@ -1358,3 +1358,17 @@ test "store to comptime field" {...@@ -1358,3 +1358,17 @@ test "store to comptime field" {
1358 s.a.a = 1;1358 s.a.a = 1;
1359 }1359 }
1360}1360}
1361
1362test "struct field init value is size of the struct" {
1363 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1364 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1365
1366 const namespace = struct {
1367 const S = extern struct {
1368 size: u8 = @sizeOf(S),
1369 blah: u16,
1370 };
1371 };
1372 var s: namespace.S = .{ .blah = 1234 };
1373 try expect(s.size == 4);
1374}