| author | |
| committer | |
| log | 4a28c1d5c3627510cef97b88ee6b3988f65ac0dd |
| tree | 17d331556c594b52a4f03c143bf2720dbc3afeca |
| parent | 3708e26f4b8b9514f055ae2a0571d3290414bf8b |
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 #120296 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(); |
| 4194 | 4193 | ||
| 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); |
| 4205 | 4217 | ||
| 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 | } |
| 4209 | 4224 | ||
| 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; | ||
| 4220 | 4230 | ||
| 4221 | if (!is_comptime) { | 4231 | if (!is_comptime) { |
| 4222 | known_non_opv = known_non_opv or | 4232 | 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 or | 4234 | 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 | } | ||
| 4228 | 4252 | ||
| 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 }; |
| 4238 | 4271 | ||
| 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 | } |
| 4245 | 4286 | ||
| 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); | ||
| 4270 | 4304 | ||
| 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 { |
| 10981 | 11015 | ||
| 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, | ||
| 919 | 920 | ||
| 920 | pub const Fields = std.StringArrayHashMapUnmanaged(Field); | 921 | pub const Fields = std.StringArrayHashMapUnmanaged(Field); |
| 921 | 922 | ||
| 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 | } |
| 1864 | 1864 | ||
| 1865 | pub fn resolveAlign( | 1865 | const align_ty = Type.u29; |
| 1866 | |||
| 1867 | fn 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 | } |
| 1881 | 1883 | ||
| 1884 | pub 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 | |||
| 1882 | fn resolveInt( | 1894 | fn 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 | |||
| 1905 | fn 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( |
| 2097 | 2119 | ||
| 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( |
| 24858 | 24879 | ||
| 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 | } |
| 24868 | 24883 | ||
| 24869 | fn resolveTypeFieldsUnion( | 24884 | fn resolveTypeFieldsUnion( |
| ... | @@ -24954,13 +24969,7 @@ fn resolveInferredErrorSetTy( | ... | @@ -24954,13 +24969,7 @@ fn resolveInferredErrorSetTy( |
| 24954 | } | 24969 | } |
| 24955 | } | 24970 | } |
| 24956 | 24971 | ||
| 24957 | fn semaStructFields( | 24972 | fn 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); |
| 24974 | 24983 | ||
| 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; |
| 24997 | 25000 | ||
| 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; | ||
| 25004 | 25005 | ||
| 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 | } |
| 25044 | 25045 | ||
| 25045 | if (body.len != 0) { | 25046 | try struct_obj.fields.ensureTotalCapacity(decl_arena_allocator, fields_len); |
| 25046 | try sema.analyzeBody(&block_scope, body); | ||
| 25047 | } | ||
| 25048 | 25047 | ||
| 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; | ||
| 25050 | 25056 | ||
| 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 | ||
| 25052 | 25083 | ||
| 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; | ||
| 25073 | 25085 | ||
| 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; | ||
| 25075 | 25092 | ||
| 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; | ||
| 25080 | 25095 | ||
| 25081 | // doc_comment | 25096 | 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); | ||
| 25083 | 25103 | ||
| 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 | else | 25108 | break :msg msg; |
| 25089 | // TODO: if we need to report an error here, use a source location | 25109 | }; |
| 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; | ||
| 25093 | 25135 | ||
| 25136 | for (fields) |zir_field, i| { | ||
| 25094 | // TODO emit compile errors for invalid field types | 25137 | // 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. |
| 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 | }; | ||
| 25097 | if (field_ty.tag() == .generic_poison) { | 25152 | if (field_ty.tag() == .generic_poison) { |
| 25098 | return error.GenericPoison; | 25153 | return error.GenericPoison; |
| 25099 | } | 25154 | } |
| 25100 | 25155 | ||
| 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); | ||
| 25108 | 25158 | ||
| 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 | }; | ||
| 25124 | 25165 | ||
| 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 location | 25169 | 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 location | 25178 | 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)) orelse | 25181 | 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 | } |
| 25146 | 25191 | ||
| 25147 | fn semaUnionFields(block: *Block, mod: *Module, union_obj: *Module.Union) CompileError!void { | 25192 | fn 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 { |
| 3093 | 3093 | ||
| 3094 | /// Trailing: | 3094 | /// Trailing: |
| 3095 | /// 0. src_node: i32, // if has_src_node | 3095 | /// 0. src_node: i32, // if has_src_node |
| 3096 | /// 1. body_len: u32, // if has_body_len | 3096 | /// 1. fields_len: u32, // if has_fields_len |
| 3097 | /// 2. fields_len: u32, // if has_fields_len | 3097 | /// 2. decls_len: u32, // if has_decls_len |
| 3098 | /// 3. decls_len: u32, // if has_decls_len | 3098 | /// 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 pub | 3100 | /// 0b000X: whether corresponding decl is pub |
| 3102 | /// 0b00X0: whether corresponding decl is exported | 3101 | /// 0b00X0: whether corresponding decl is exported |
| 3103 | /// 0b0X00: whether corresponding decl has an align expression | 3102 | /// 0b0X00: whether corresponding decl has an align expression |
| 3104 | /// 0bX000: whether corresponding decl has a linksection or an address space expression | 3103 | /// 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 |
| 3106 | /// src_hash: [4]u32, // hash of source bytes | 3105 | /// src_hash: [4]u32, // hash of source bytes |
| 3107 | /// line: u32, // line number of decl, relative to parent | 3106 | /// line: u32, // line number of decl, relative to parent |
| 3108 | /// name: u32, // null terminated string index | 3107 | /// 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_len | 3122 | /// 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 expression | 3124 | /// 0b000X: whether corresponding field has an align expression |
| 3127 | /// 0b00X0: whether corresponding field has a default expression | 3125 | /// 0b00X0: whether corresponding field has a default expression |
| 3128 | /// 0b0X00: whether corresponding field is comptime | 3126 | /// 0b0X00: whether corresponding field is comptime |
| 3129 | /// 0bX000: unused | 3127 | /// 0bX000: whether corresponding field has a type expression |
| 3130 | /// 8. fields: { // for every fields_len | 3128 | /// 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 comment | 3130 | /// doc_comment: u32, // 0 if no doc comment |
| 3135 | /// align: Ref, // if corresponding bit is set | 3131 | /// field_type: Ref, // if corresponding bit is not set. none means anytype. |
| 3136 | /// default_value: Ref, // if corresponding bit is set | 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 | ||
| 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 | }; |
| 3151 | 3153 | ||
| ... | @@ -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; |
| 1229 | 1229 | ||
| 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 | } |
| 1264 | 1258 | ||
| 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; | ||
| 1298 | 1298 | ||
| 1299 | _ = unused; | 1299 | fields[field_i] = .{ |
| 1300 | .doc_comment_index = doc_comment_index, | ||
| 1301 | .is_comptime = is_comptime, | ||
| 1302 | .name = field_name, | ||
| 1303 | }; | ||
| 1300 | 1304 | ||
| 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; |
| 1307 | 1311 | ||
| 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; | ||
| 1309 | 1328 | ||
| 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 | } | ||
| 1314 | 1339 | ||
| 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 | } | ||
| 1318 | 1347 | ||
| 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; | ||
| 1326 | 1357 | ||
| 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 | } |
| 1332 | 1369 |
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 | |||
| 1362 | test "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 | } |