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(
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,20 +4215,18 @@ 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
......@@ -4224,36 +4234,59 @@ fn structDeclInner(
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
......@@ -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,
src/Sema.zig+154-109
......@@ -1862,13 +1862,15 @@ fn failWithOwnedErrorMsg(sema: *Sema, block: *Block, err_msg: *Module.ErrorMsg)
18621862 return error.AnalysisFail;
18631863}
18641864
1865pub fn resolveAlign(
1865const align_ty = Type.u29;
1866
1867fn analyzeAsAlign(
18661868 sema: *Sema,
18671869 block: *Block,
18681870 src: LazySrcLoc,
1869 zir_ref: Zir.Inst.Ref,
1871 air_ref: Air.Inst.Ref,
18701872) !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);
18721874 const alignment = @intCast(u32, alignment_big); // We coerce to u16 in the prev line.
18731875 if (alignment == 0) return sema.fail(block, src, "alignment must be >= 1", .{});
18741876 if (!std.math.isPowerOfTwo(alignment)) {
......@@ -1879,6 +1881,16 @@ pub fn resolveAlign(
18791881 return alignment;
18801882}
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
18821894fn resolveInt(
18831895 sema: *Sema,
18841896 block: *Block,
......@@ -1886,8 +1898,18 @@ fn resolveInt(
18861898 zir_ref: Zir.Inst.Ref,
18871899 dest_ty: Type,
18881900) !u64 {
1889 const air_inst = try sema.resolveInst(zir_ref);
1890 const coerced = try sema.coerce(block, dest_ty, air_inst, src);
1901 const air_ref = try sema.resolveInst(zir_ref);
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);
18911913 const val = try sema.resolveConstValue(block, src, coerced);
18921914 const target = sema.mod.getTarget();
18931915 return (try val.getUnsignedIntAdvanced(target, sema.kit(block, src))).?;
......@@ -2097,7 +2119,6 @@ pub fn analyzeStructDecl(
20972119
20982120 var extra_index: usize = extended.operand;
20992121 extra_index += @boolToInt(small.has_src_node);
2100 extra_index += @boolToInt(small.has_body_len);
21012122 extra_index += @boolToInt(small.has_fields_len);
21022123 const decls_len = if (small.has_decls_len) blk: {
21032124 const decls_len = sema.code.extra[extra_index];
......@@ -24858,12 +24879,6 @@ fn resolveTypeFieldsStruct(
2485824879
2485924880 struct_obj.status = .field_types_wip;
2486024881 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 }
2486724882}
2486824883
2486924884fn resolveTypeFieldsUnion(
......@@ -24954,13 +24969,7 @@ fn resolveInferredErrorSetTy(
2495424969 }
2495524970}
2495624971
24957fn semaStructFields(
24958 mod: *Module,
24959 struct_obj: *Module.Struct,
24960) CompileError!void {
24961 const tracy = trace(@src());
24962 defer tracy.end();
24963
24972fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void {
2496424973 const gpa = mod.gpa;
2496524974 const decl_index = struct_obj.owner_decl;
2496624975 const zir = struct_obj.namespace.file_scope.zir;
......@@ -24972,12 +24981,6 @@ fn semaStructFields(
2497224981 const src = LazySrcLoc.nodeOffset(struct_obj.node_offset);
2497324982 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
2498124984 const fields_len = if (small.has_fields_len) blk: {
2498224985 const fields_len = zir.extra[extra_index];
2498324986 extra_index += 1;
......@@ -24995,12 +24998,10 @@ fn semaStructFields(
2499524998 while (decls_it.next()) |_| {}
2499624999 extra_index = decls_it.extra_index;
2499725000
24998 const body = zir.extra[extra_index..][0..body_len];
2499925001 if (fields_len == 0) {
25000 assert(body.len == 0);
25002 struct_obj.status = .have_layout;
2500125003 return;
2500225004 }
25003 extra_index += body.len;
2500425005
2500525006 const decl = mod.declPtr(decl_index);
2500625007 var decl_arena = decl.value_arena.?.promote(gpa);
......@@ -25042,106 +25043,150 @@ fn semaStructFields(
2504225043 block_scope.params.deinit(gpa);
2504325044 }
2504425045
25045 if (body.len != 0) {
25046 try sema.analyzeBody(&block_scope, body);
25047 }
25046 try struct_obj.fields.ensureTotalCapacity(decl_arena_allocator, fields_len);
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;
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;
25084 fields[field_i] = .{};
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]);
25077 extra_index += 1;
25078 const field_type_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
25079 extra_index += 1;
25093 // This string needs to outlive the ZIR code.
25094 const field_name = try decl_arena_allocator.dupe(u8, field_name_zir);
2508025095
25081 // doc_comment
25082 extra_index += 1;
25096 const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name);
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.
25085 const field_name = try decl_arena_allocator.dupe(u8, field_name_zir);
25086 const field_ty: Type = if (field_type_ref == .none)
25087 Type.initTag(.noreturn)
25088 else
25089 // TODO: if we need to report an error here, use a source location
25090 // that points to this type expression rather than the struct.
25091 // But only resolve the source location if we need to emit a compile error.
25092 try sema.resolveType(&block_scope, src, field_type_ref);
25104 const prev_field_index = struct_obj.fields.getIndex(field_name).?;
25105 const prev_field_src = enumFieldSrcLoc(decl, tree.*, struct_obj.node_offset, prev_field_index);
25106 try sema.mod.errNoteNonLazy(prev_field_src.toSrcLoc(decl), msg, "other field here", .{});
25107 try sema.errNote(&block_scope, src, msg, "struct declared here", .{});
25108 break :msg msg;
25109 };
25110 return sema.failWithOwnedErrorMsg(&block_scope, msg);
25111 }
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| {
2509425137 // TODO emit compile errors for invalid field types
2509525138 // such as arrays and pointers inside packed structs.
25096
25139 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 };
2509725152 if (field_ty.tag() == .generic_poison) {
2509825153 return error.GenericPoison;
2509925154 }
2510025155
25101 const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name);
25102 if (gop.found_existing) {
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);
25156 const field = &struct_obj.fields.values()[i];
25157 field.ty = try field_ty.copy(decl_arena_allocator);
2510825158
25109 const prev_field_index = struct_obj.fields.getIndex(field_name).?;
25110 const prev_field_src = enumFieldSrcLoc(decl, tree.*, struct_obj.node_offset, prev_field_index);
25111 try sema.mod.errNoteNonLazy(prev_field_src.toSrcLoc(decl), msg, "other field here", .{});
25112 try sema.errNote(&block_scope, src, msg, "struct declared here", .{});
25113 break :msg msg;
25114 };
25115 return sema.failWithOwnedErrorMsg(&block_scope, msg);
25159 if (zir_field.align_body_len > 0) {
25160 const body = zir.extra[extra_index..][0..zir_field.align_body_len];
25161 extra_index += body.len;
25162 const align_ref = try sema.resolveBody(&block_scope, body, struct_obj.zir_index);
25163 field.abi_align = try sema.analyzeAsAlign(&block_scope, src, align_ref);
2511625164 }
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) {
25126 const align_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
25127 extra_index += 1;
25128 // TODO: if we need to report an error here, use a source location
25129 // that points to this alignment expression rather than the struct.
25130 // But only resolve the source location if we need to emit a compile error.
25131 gop.value_ptr.abi_align = try sema.resolveAlign(&block_scope, src, align_ref);
25132 }
25133 if (has_default) {
25134 const default_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
25135 extra_index += 1;
25136 const default_inst = try sema.resolveInst(default_ref);
25137 // TODO: if we need to report an error here, use a source location
25138 // that points to this default value expression rather than the struct.
25139 // But only resolve the source location if we need to emit a compile error.
25140 const default_val = (try sema.resolveMaybeUndefVal(&block_scope, src, default_inst)) orelse
25141 return sema.failWithNeededComptime(&block_scope, src);
25142 gop.value_ptr.default_val = try default_val.copy(decl_arena_allocator);
25166 extra_index += zir_field.init_body_len;
25167 }
25168
25169 struct_obj.status = .have_field_types;
25170
25171 if (any_inits) {
25172 extra_index = bodies_index;
25173 for (fields) |zir_field, i| {
25174 extra_index += zir_field.type_body_len;
25175 extra_index += zir_field.align_body_len;
25176 if (zir_field.init_body_len > 0) {
25177 const body = zir.extra[extra_index..][0..zir_field.init_body_len];
25178 extra_index += body.len;
25179 const init = try sema.resolveBody(&block_scope, body, struct_obj.zir_index);
25180 const field = &struct_obj.fields.values()[i];
25181 const coerced = try sema.coerce(&block_scope, field.ty, init, src);
25182 const default_val = (try sema.resolveMaybeUndefVal(&block_scope, src, coerced)) orelse
25183 return sema.failWithNeededComptime(&block_scope, src);
25184 field.default_val = try default_val.copy(decl_arena_allocator);
25185 }
2514325186 }
2514425187 }
25188
25189 struct_obj.have_field_inits = true;
2514525190}
2514625191
2514725192fn semaUnionFields(block: *Block, mod: *Module, union_obj: *Module.Union) CompileError!void {
src/Zir.zig+17-16
......@@ -3093,16 +3093,15 @@ pub const Inst = struct {
30933093
30943094 /// Trailing:
30953095 /// 0. src_node: i32, // if has_src_node
3096 /// 1. body_len: u32, // if has_body_len
3097 /// 2. fields_len: u32, // if has_fields_len
3098 /// 3. decls_len: u32, // if has_decls_len
3099 /// 4. decl_bits: u32 // for every 8 decls
3096 /// 1. fields_len: u32, // if has_fields_len
3097 /// 2. decls_len: u32, // if has_decls_len
3098 /// 3. decl_bits: u32 // for every 8 decls
31003099 /// - sets of 4 bits:
31013100 /// 0b000X: whether corresponding decl is pub
31023101 /// 0b00X0: whether corresponding decl is exported
31033102 /// 0b0X00: whether corresponding decl has an align expression
31043103 /// 0bX000: whether corresponding decl has a linksection or an address space expression
3105 /// 5. decl: { // for every decls_len
3104 /// 4. decl: { // for every decls_len
31063105 /// src_hash: [4]u32, // hash of source bytes
31073106 /// line: u32, // line number of decl, relative to parent
31083107 /// name: u32, // null terminated string index
......@@ -3120,32 +3119,35 @@ pub const Inst = struct {
31203119 /// address_space: Ref,
31213120 /// }
31223121 /// }
3123 /// 6. inst: Index // for every body_len
3124 /// 7. flags: u32 // for every 8 fields
3122 /// 5. flags: u32 // for every 8 fields
31253123 /// - sets of 4 bits:
31263124 /// 0b000X: whether corresponding field has an align expression
31273125 /// 0b00X0: whether corresponding field has a default expression
31283126 /// 0b0X00: whether corresponding field is comptime
3129 /// 0bX000: unused
3130 /// 8. fields: { // for every fields_len
3127 /// 0bX000: whether corresponding field has a type expression
3128 /// 6. fields: { // for every fields_len
31313129 /// field_name: u32,
3132 /// field_type: Ref,
3133 /// - if none, means `anytype`.
31343130 /// doc_comment: u32, // 0 if no doc comment
3135 /// align: Ref, // if corresponding bit is set
3136 /// default_value: Ref, // if corresponding bit is set
3131 /// field_type: Ref, // if corresponding bit is not set. none means anytype.
3132 /// 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
31373140 /// }
31383141 pub const StructDecl = struct {
31393142 pub const Small = packed struct {
31403143 has_src_node: bool,
3141 has_body_len: bool,
31423144 has_fields_len: bool,
31433145 has_decls_len: bool,
31443146 known_non_opv: bool,
31453147 known_comptime_only: bool,
31463148 name_strategy: NameStrategy,
31473149 layout: std.builtin.Type.ContainerLayout,
3148 _: u6 = undefined,
3150 _: u7 = undefined,
31493151 };
31503152 };
31513153
......@@ -3594,7 +3596,6 @@ pub fn declIterator(zir: Zir, decl_inst: u32) DeclIterator {
35943596 const small = @bitCast(Inst.StructDecl.Small, extended.small);
35953597 var extra_index: usize = extended.operand;
35963598 extra_index += @boolToInt(small.has_src_node);
3597 extra_index += @boolToInt(small.has_body_len);
35983599 extra_index += @boolToInt(small.has_fields_len);
35993600 const decls_len = if (small.has_decls_len) decls_len: {
36003601 const decls_len = zir.extra[extra_index];
src/print_zir.zig+88-51
......@@ -1227,12 +1227,6 @@ const Writer = struct {
12271227 break :blk src_node;
12281228 } 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
12361230 const fields_len = if (small.has_fields_len) blk: {
12371231 const fields_len = self.code.extra[extra_index];
12381232 extra_index += 1;
......@@ -1262,71 +1256,114 @@ const Writer = struct {
12621256 try stream.writeAll("}, ");
12631257 }
12641258
1265 const body = self.code.extra[extra_index..][0..body_len];
1266 extra_index += body.len;
1267
12681259 if (fields_len == 0) {
1269 assert(body.len == 0);
12701260 try stream.writeAll("{}, {})");
12711261 } 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;
12781262 const bits_per_field = 4;
12791263 const fields_per_u32 = 32 / bits_per_field;
12801264 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
1281 var bit_bag_index: usize = extra_index;
1282 extra_index += bit_bags_count;
1283 var cur_bit_bag: u32 = undefined;
1284 var field_i: u32 = 0;
1285 while (field_i < fields_len) : (field_i += 1) {
1286 if (field_i % fields_per_u32 == 0) {
1287 cur_bit_bag = self.code.extra[bit_bag_index];
1288 bit_bag_index += 1;
1289 }
1290 const has_align = @truncate(u1, cur_bit_bag) != 0;
1291 cur_bit_bag >>= 1;
1292 const has_default = @truncate(u1, cur_bit_bag) != 0;
1293 cur_bit_bag >>= 1;
1294 const is_comptime = @truncate(u1, cur_bit_bag) != 0;
1295 cur_bit_bag >>= 1;
1296 const unused = @truncate(u1, cur_bit_bag) != 0;
1297 cur_bit_bag >>= 1;
1265 const Field = struct {
1266 doc_comment_index: u32,
1267 type_len: u32 = 0,
1268 align_len: u32 = 0,
1269 init_len: u32 = 0,
1270 field_type: Zir.Inst.Ref = .none,
1271 name: u32,
1272 is_comptime: bool,
1273 };
1274 const fields = try self.arena.alloc(Field, fields_len);
1275 {
1276 var bit_bag_index: usize = extra_index;
1277 extra_index += bit_bags_count;
1278 var cur_bit_bag: u32 = undefined;
1279 var field_i: u32 = 0;
1280 while (field_i < fields_len) : (field_i += 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]);
1302 extra_index += 1;
1303 const field_type = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
1304 extra_index += 1;
1305 const doc_comment_index = self.code.extra[extra_index];
1306 extra_index += 1;
1305 if (has_type_body) {
1306 fields[field_i].type_len = self.code.extra[extra_index];
1307 } else {
1308 fields[field_i].field_type = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
1309 }
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);
13101333 try stream.writeByteNTimes(' ', self.indent);
1311 try self.writeFlag(stream, "comptime ", is_comptime);
1334 try self.writeFlag(stream, "comptime ", field.is_comptime);
13121335 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) {
1316 const align_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
1317 extra_index += 1;
1340 if (field.type_len > 0) {
1341 const body = self.code.extra[extra_index..][0..field.type_len];
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;
13191352 try stream.writeAll(" align(");
1320 try self.writeInstRef(stream, align_ref);
1353 try self.writeBracedDecl(stream, body);
13211354 try stream.writeAll(")");
1355 self.indent -= 2;
13221356 }
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;
13271362 try stream.writeAll(" = ");
1328 try self.writeInstRef(stream, default_ref);
1363 try self.writeBracedDecl(stream, body);
1364 self.indent -= 2;
13291365 }
1366
13301367 try stream.writeAll(",\n");
13311368 }
13321369
test/behavior/struct.zig+14
......@@ -1358,3 +1358,17 @@ test "store to comptime field" {
13581358 s.a.a = 1;
13591359 }
13601360}
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}