authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-01-19 01:56:45+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-01-23 19:16:47+00:00
logae845a33c04fb287ae5a7445743c2b570e40ca1f
tree65bbaa19d241453a95f7a1561d2815106cf36844
parent993a83081a975464d1201597cf6f4cb7f6735284
signaturelock-open Commit is signed but in an unrecognized format.

Zir: represent declarations via an instruction

This commit changes how declarations (`const`, `fn`, `usingnamespace`, etc) are represented in ZIR. Previously, these were represented in the container type's extra data (e.g. as trailing data on a `struct_decl`). However, this introduced the complexity of the ZIR mapping logic having to also correlate some ZIR extra data indices. That isn't really a problem today, but it's tricky for the introduction of `TrackedInst` in the commit following this one. Instead, these type declarations now simply contain a trailing list of ZIR indices to `declaration` instructions, which directly encode all data related to the declaration (including containing the declaration's body). Additionally, the ZIR for `align` etc have been split out into their own bodies. This is not strictly necessary, but it's much simpler to understand for an insignificant cost in bytes, and will simplify the resolution of #131 (where we may need to evaluate the pointer type, including align etc, without immediately evaluating the value body).

8 files changed, 863 insertions(+), 939 deletions(-)

src/AstGen.zig+225-159
......@@ -86,6 +86,7 @@ fn setExtra(astgen: *AstGen, index: usize, extra: anytype) void {
8686
8787 Zir.Inst.Ref,
8888 Zir.Inst.Index,
89 Zir.Inst.Declaration.Name,
8990 Zir.NullTerminatedString,
9091 => @intFromEnum(@field(extra, field.name)),
9192
......@@ -95,6 +96,7 @@ fn setExtra(astgen: *AstGen, index: usize, extra: anytype) void {
9596 Zir.Inst.SwitchBlock.Bits,
9697 Zir.Inst.SwitchBlockErrUnion.Bits,
9798 Zir.Inst.FuncFancy.Bits,
99 Zir.Inst.Declaration.Flags,
98100 => @bitCast(@field(extra, field.name)),
99101
100102 else => @compileError("bad field type"),
......@@ -132,8 +134,8 @@ pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir {
132134 };
133135 defer astgen.deinit(gpa);
134136
135 // String table indexes 0, 1, 2 are reserved for special meaning.
136 try astgen.string_bytes.appendSlice(gpa, &[_]u8{ 0, 0, 0 });
137 // String table index 0 is reserved for `NullTerminatedString.empty`.
138 try astgen.string_bytes.append(gpa, 0);
137139
138140 // We expect at least as many ZIR instructions and extra data items
139141 // as AST nodes.
......@@ -355,8 +357,13 @@ const ResultInfo = struct {
355357 };
356358};
357359
360/// TODO: modify Sema to remove in favour of `coerced_align_ri`
358361const align_ri: ResultInfo = .{ .rl = .{ .ty = .u29_type } };
359362const coerced_align_ri: ResultInfo = .{ .rl = .{ .coerced_ty = .u29_type } };
363/// TODO: modify Sema to remove in favour of `coerced_addrspace_ri`
364const addrspace_ri: ResultInfo = .{ .rl = .{ .ty = .address_space_type } };
365const coerced_addrspace_ri: ResultInfo = .{ .rl = .{ .coerced_ty = .address_space_type } };
366const coerced_linksection_ri: ResultInfo = .{ .rl = .{ .coerced_ty = .slice_const_u8_type } };
360367const bool_ri: ResultInfo = .{ .rl = .{ .ty = .bool_type } };
361368const type_ri: ResultInfo = .{ .rl = .{ .ty = .type_type } };
362369const coerced_type_ri: ResultInfo = .{ .rl = .{ .coerced_ty = .type_type } };
......@@ -2592,6 +2599,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
25922599 .block,
25932600 .block_comptime,
25942601 .block_inline,
2602 .declaration,
25952603 .suspend_block,
25962604 .loop,
25972605 .bool_br_and,
......@@ -3783,7 +3791,7 @@ fn ptrType(
37833791 gz.astgen.source_line = source_line;
37843792 gz.astgen.source_column = source_column;
37853793
3786 addrspace_ref = try expr(gz, scope, .{ .rl = .{ .ty = .address_space_type } }, ptr_info.ast.addrspace_node);
3794 addrspace_ref = try expr(gz, scope, addrspace_ri, ptr_info.ast.addrspace_node);
37873795 trailing_count += 1;
37883796 }
37893797 if (ptr_info.ast.align_node != 0) {
......@@ -3899,8 +3907,6 @@ fn arrayTypeSentinel(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.
38993907const WipMembers = struct {
39003908 payload: *ArrayListUnmanaged(u32),
39013909 payload_top: usize,
3902 decls_start: u32,
3903 decls_end: u32,
39043910 field_bits_start: u32,
39053911 fields_start: u32,
39063912 fields_end: u32,
......@@ -3908,43 +3914,27 @@ const WipMembers = struct {
39083914 field_index: u32 = 0,
39093915
39103916 const Self = @This();
3911 /// struct, union, enum, and opaque decls all use same 4 bits per decl
3912 const bits_per_decl = 4;
3913 const decls_per_u32 = 32 / bits_per_decl;
3914 /// struct, union, enum, and opaque decls all have maximum size of 11 u32 slots
3915 /// (4 for src_hash + line + name + value + doc_comment + align + link_section + address_space )
3916 const max_decl_size = 11;
39173917
39183918 fn init(gpa: Allocator, payload: *ArrayListUnmanaged(u32), decl_count: u32, field_count: u32, comptime bits_per_field: u32, comptime max_field_size: u32) Allocator.Error!Self {
39193919 const payload_top: u32 = @intCast(payload.items.len);
3920 const decls_start = payload_top + (decl_count + decls_per_u32 - 1) / decls_per_u32;
3921 const field_bits_start = decls_start + decl_count * max_decl_size;
3920 const field_bits_start = payload_top + decl_count;
39223921 const fields_start = field_bits_start + if (bits_per_field > 0) blk: {
39233922 const fields_per_u32 = 32 / bits_per_field;
39243923 break :blk (field_count + fields_per_u32 - 1) / fields_per_u32;
39253924 } else 0;
39263925 const payload_end = fields_start + field_count * max_field_size;
39273926 try payload.resize(gpa, payload_end);
3928 return Self{
3927 return .{
39293928 .payload = payload,
39303929 .payload_top = payload_top,
3931 .decls_start = decls_start,
39323930 .field_bits_start = field_bits_start,
39333931 .fields_start = fields_start,
3934 .decls_end = decls_start,
39353932 .fields_end = fields_start,
39363933 };
39373934 }
39383935
3939 fn nextDecl(self: *Self, is_pub: bool, is_export: bool, has_align: bool, has_section_or_addrspace: bool) void {
3940 const index = self.payload_top + self.decl_index / decls_per_u32;
3941 assert(index < self.decls_start);
3942 const bit_bag: u32 = if (self.decl_index % decls_per_u32 == 0) 0 else self.payload.items[index];
3943 self.payload.items[index] = (bit_bag >> bits_per_decl) |
3944 (@as(u32, @intFromBool(is_pub)) << 28) |
3945 (@as(u32, @intFromBool(is_export)) << 29) |
3946 (@as(u32, @intFromBool(has_align)) << 30) |
3947 (@as(u32, @intFromBool(has_section_or_addrspace)) << 31);
3936 fn nextDecl(self: *Self, decl_inst: Zir.Inst.Index) void {
3937 self.payload.items[self.payload_top + self.decl_index] = @intFromEnum(decl_inst);
39483938 self.decl_index += 1;
39493939 }
39503940
......@@ -3962,18 +3952,6 @@ const WipMembers = struct {
39623952 self.field_index += 1;
39633953 }
39643954
3965 fn appendToDecl(self: *Self, data: u32) void {
3966 assert(self.decls_end < self.field_bits_start);
3967 self.payload.items[self.decls_end] = data;
3968 self.decls_end += 1;
3969 }
3970
3971 fn appendToDeclSlice(self: *Self, data: []const u32) void {
3972 assert(self.decls_end + data.len <= self.field_bits_start);
3973 @memcpy(self.payload.items[self.decls_end..][0..data.len], data);
3974 self.decls_end += @intCast(data.len);
3975 }
3976
39773955 fn appendToField(self: *Self, data: u32) void {
39783956 assert(self.fields_end < self.payload.items.len);
39793957 self.payload.items[self.fields_end] = data;
......@@ -3981,11 +3959,6 @@ const WipMembers = struct {
39813959 }
39823960
39833961 fn finishBits(self: *Self, comptime bits_per_field: u32) void {
3984 const empty_decl_slots = decls_per_u32 - (self.decl_index % decls_per_u32);
3985 if (self.decl_index > 0 and empty_decl_slots < decls_per_u32) {
3986 const index = self.payload_top + self.decl_index / decls_per_u32;
3987 self.payload.items[index] >>= @intCast(empty_decl_slots * bits_per_decl);
3988 }
39893962 if (bits_per_field > 0) {
39903963 const fields_per_u32 = 32 / bits_per_field;
39913964 const empty_field_slots = fields_per_u32 - (self.field_index % fields_per_u32);
......@@ -3997,7 +3970,7 @@ const WipMembers = struct {
39973970 }
39983971
39993972 fn declsSlice(self: *Self) []u32 {
4000 return self.payload.items[self.payload_top..self.decls_end];
3973 return self.payload.items[self.payload_top..][0..self.decl_index];
40013974 }
40023975
40033976 fn fieldsSlice(self: *Self) []u32 {
......@@ -4023,11 +3996,10 @@ fn fnDecl(
40233996
40243997 // missing function name already happened in scanDecls()
40253998 const fn_name_token = fn_proto.name_token orelse return error.AnalysisFail;
4026 const fn_name_str_index = try astgen.identAsString(fn_name_token);
40273999
40284000 // We insert this at the beginning so that its instruction index marks the
40294001 // start of the top level declaration.
4030 const block_inst = try gz.makeBlockInst(.block_inline, fn_proto.ast.proto_node);
4002 const decl_inst = try gz.makeBlockInst(.declaration, fn_proto.ast.proto_node);
40314003 astgen.advanceSourceCursorToNode(decl_node);
40324004
40334005 var decl_gz: GenZir = .{
......@@ -4072,8 +4044,7 @@ fn fnDecl(
40724044
40734045 const doc_comment_index = try astgen.docCommentAsString(fn_proto.firstToken());
40744046
4075 // align, linksection, and addrspace is passed in the func instruction in this case.
4076 wip_members.nextDecl(is_pub, is_export, false, false);
4047 wip_members.nextDecl(decl_inst);
40774048
40784049 var noalias_bits: u32 = 0;
40794050 var params_scope = &fn_gz.base;
......@@ -4213,7 +4184,7 @@ fn fnDecl(
42134184 var addrspace_gz = decl_gz.makeSubBlock(params_scope);
42144185 defer addrspace_gz.unstack();
42154186 const addrspace_ref: Zir.Inst.Ref = if (fn_proto.ast.addrspace_expr == 0) .none else inst: {
4216 const inst = try expr(&decl_gz, params_scope, .{ .rl = .{ .coerced_ty = .address_space_type } }, fn_proto.ast.addrspace_expr);
4187 const inst = try expr(&decl_gz, params_scope, addrspace_ri, fn_proto.ast.addrspace_expr);
42174188 if (addrspace_gz.instructionsSlice().len == 0) {
42184189 // In this case we will send a len=0 body which can be encoded more efficiently.
42194190 break :inst inst;
......@@ -4298,7 +4269,7 @@ fn fnDecl(
42984269 .section_gz = &section_gz,
42994270 .addrspace_ref = addrspace_ref,
43004271 .addrspace_gz = &addrspace_gz,
4301 .param_block = block_inst,
4272 .param_block = decl_inst,
43024273 .body_gz = null,
43034274 .lib_name = lib_name,
43044275 .is_var_args = is_var_args,
......@@ -4349,7 +4320,7 @@ fn fnDecl(
43494320 .addrspace_gz = &addrspace_gz,
43504321 .lbrace_line = lbrace_line,
43514322 .lbrace_column = lbrace_column,
4352 .param_block = block_inst,
4323 .param_block = decl_inst,
43534324 .body_gz = &fn_gz,
43544325 .lib_name = lib_name,
43554326 .is_var_args = is_var_args,
......@@ -4363,20 +4334,21 @@ fn fnDecl(
43634334
43644335 // We add this at the end so that its instruction index marks the end range
43654336 // of the top level declaration. addFunc already unstacked fn_gz and ret_gz.
4366 _ = try decl_gz.addBreak(.break_inline, block_inst, func_inst);
4367 try decl_gz.setBlockBody(block_inst);
4368
4369 {
4370 const contents_hash align(@alignOf(u32)) = std.zig.hashSrc(tree.getNodeSource(decl_node));
4371 wip_members.appendToDeclSlice(std.mem.bytesAsSlice(u32, &contents_hash));
4372 }
4373 {
4374 const line_delta = decl_gz.decl_line - gz.decl_line;
4375 wip_members.appendToDecl(line_delta);
4376 }
4377 wip_members.appendToDecl(@intFromEnum(fn_name_str_index));
4378 wip_members.appendToDecl(@intFromEnum(block_inst));
4379 wip_members.appendToDecl(@intFromEnum(doc_comment_index));
4337 _ = try decl_gz.addBreak(.break_inline, decl_inst, func_inst);
4338
4339 try setDeclaration(
4340 decl_inst,
4341 std.zig.hashSrc(tree.getNodeSource(decl_node)),
4342 .{ .named = fn_name_token },
4343 decl_gz.decl_line - gz.decl_line,
4344 is_pub,
4345 is_export,
4346 doc_comment_index,
4347 &decl_gz,
4348 // align, linksection, and addrspace are passed in the func instruction in this case.
4349 // TODO: move them from the function instruction to the declaration instruction?
4350 null,
4351 );
43804352}
43814353
43824354fn globalVarDecl(
......@@ -4393,10 +4365,9 @@ fn globalVarDecl(
43934365 const is_mutable = token_tags[var_decl.ast.mut_token] == .keyword_var;
43944366 // We do this at the beginning so that the instruction index marks the range start
43954367 // of the top level declaration.
4396 const block_inst = try gz.makeBlockInst(.block_inline, node);
4368 const decl_inst = try gz.makeBlockInst(.declaration, node);
43974369
43984370 const name_token = var_decl.ast.mut_token + 1;
4399 const name_str_index = try astgen.identAsString(name_token);
44004371 astgen.advanceSourceCursorToNode(node);
44014372
44024373 var block_scope: GenZir = .{
......@@ -4420,17 +4391,7 @@ fn globalVarDecl(
44204391 const maybe_extern_token = var_decl.extern_export_token orelse break :blk false;
44214392 break :blk token_tags[maybe_extern_token] == .keyword_extern;
44224393 };
4423 const align_inst: Zir.Inst.Ref = if (var_decl.ast.align_node == 0) .none else inst: {
4424 break :inst try expr(&block_scope, &block_scope.base, align_ri, var_decl.ast.align_node);
4425 };
4426 const addrspace_inst: Zir.Inst.Ref = if (var_decl.ast.addrspace_node == 0) .none else inst: {
4427 break :inst try expr(&block_scope, &block_scope.base, .{ .rl = .{ .ty = .address_space_type } }, var_decl.ast.addrspace_node);
4428 };
4429 const section_inst: Zir.Inst.Ref = if (var_decl.ast.section_node == 0) .none else inst: {
4430 break :inst try comptimeExpr(&block_scope, &block_scope.base, .{ .rl = .{ .ty = .slice_const_u8_type } }, var_decl.ast.section_node);
4431 };
4432 const has_section_or_addrspace = section_inst != .none or addrspace_inst != .none;
4433 wip_members.nextDecl(is_pub, is_export, align_inst != .none, has_section_or_addrspace);
4394 wip_members.nextDecl(decl_inst);
44344395
44354396 const is_threadlocal = if (var_decl.threadlocal_token) |tok| blk: {
44364397 if (!is_mutable) {
......@@ -4513,29 +4474,44 @@ fn globalVarDecl(
45134474 } else {
45144475 return astgen.failNode(node, "unable to infer variable type", .{});
45154476 };
4477
45164478 // We do this at the end so that the instruction index marks the end
45174479 // range of a top level declaration.
4518 _ = try block_scope.addBreakWithSrcNode(.break_inline, block_inst, var_inst, node);
4519 try block_scope.setBlockBody(block_inst);
4480 _ = try block_scope.addBreakWithSrcNode(.break_inline, decl_inst, var_inst, node);
45204481
4521 {
4522 const contents_hash align(@alignOf(u32)) = std.zig.hashSrc(tree.getNodeSource(node));
4523 wip_members.appendToDeclSlice(std.mem.bytesAsSlice(u32, &contents_hash));
4482 var align_gz = block_scope.makeSubBlock(scope);
4483 if (var_decl.ast.align_node != 0) {
4484 const align_inst = try expr(&align_gz, &align_gz.base, coerced_align_ri, var_decl.ast.align_node);
4485 _ = try align_gz.addBreakWithSrcNode(.break_inline, decl_inst, align_inst, node);
45244486 }
4525 {
4526 const line_delta = block_scope.decl_line - gz.decl_line;
4527 wip_members.appendToDecl(line_delta);
4528 }
4529 wip_members.appendToDecl(@intFromEnum(name_str_index));
4530 wip_members.appendToDecl(@intFromEnum(block_inst));
4531 wip_members.appendToDecl(@intFromEnum(doc_comment_index)); // doc_comment wip
4532 if (align_inst != .none) {
4533 wip_members.appendToDecl(@intFromEnum(align_inst));
4534 }
4535 if (has_section_or_addrspace) {
4536 wip_members.appendToDecl(@intFromEnum(section_inst));
4537 wip_members.appendToDecl(@intFromEnum(addrspace_inst));
4487
4488 var linksection_gz = align_gz.makeSubBlock(scope);
4489 if (var_decl.ast.section_node != 0) {
4490 const linksection_inst = try expr(&linksection_gz, &linksection_gz.base, coerced_linksection_ri, var_decl.ast.section_node);
4491 _ = try linksection_gz.addBreakWithSrcNode(.break_inline, decl_inst, linksection_inst, node);
45384492 }
4493
4494 var addrspace_gz = linksection_gz.makeSubBlock(scope);
4495 if (var_decl.ast.addrspace_node != 0) {
4496 const addrspace_inst = try expr(&addrspace_gz, &addrspace_gz.base, coerced_addrspace_ri, var_decl.ast.addrspace_node);
4497 _ = try addrspace_gz.addBreakWithSrcNode(.break_inline, decl_inst, addrspace_inst, node);
4498 }
4499
4500 try setDeclaration(
4501 decl_inst,
4502 std.zig.hashSrc(tree.getNodeSource(node)),
4503 .{ .named = name_token },
4504 block_scope.decl_line - gz.decl_line,
4505 is_pub,
4506 is_export,
4507 doc_comment_index,
4508 &block_scope,
4509 .{
4510 .align_gz = &align_gz,
4511 .linksection_gz = &linksection_gz,
4512 .addrspace_gz = &addrspace_gz,
4513 },
4514 );
45394515}
45404516
45414517fn comptimeDecl(
......@@ -4551,8 +4527,8 @@ fn comptimeDecl(
45514527
45524528 // Up top so the ZIR instruction index marks the start range of this
45534529 // top-level declaration.
4554 const block_inst = try gz.makeBlockInst(.block_inline, node);
4555 wip_members.nextDecl(false, false, false, false);
4530 const decl_inst = try gz.makeBlockInst(.declaration, node);
4531 wip_members.nextDecl(decl_inst);
45564532 astgen.advanceSourceCursorToNode(node);
45574533
45584534 var decl_block: GenZir = .{
......@@ -4568,21 +4544,20 @@ fn comptimeDecl(
45684544
45694545 const block_result = try expr(&decl_block, &decl_block.base, .{ .rl = .none }, body_node);
45704546 if (decl_block.isEmpty() or !decl_block.refIsNoReturn(block_result)) {
4571 _ = try decl_block.addBreak(.break_inline, block_inst, .void_value);
4547 _ = try decl_block.addBreak(.break_inline, decl_inst, .void_value);
45724548 }
4573 try decl_block.setBlockBody(block_inst);
45744549
4575 {
4576 const contents_hash align(@alignOf(u32)) = std.zig.hashSrc(tree.getNodeSource(node));
4577 wip_members.appendToDeclSlice(std.mem.bytesAsSlice(u32, &contents_hash));
4578 }
4579 {
4580 const line_delta = decl_block.decl_line - gz.decl_line;
4581 wip_members.appendToDecl(line_delta);
4582 }
4583 wip_members.appendToDecl(0);
4584 wip_members.appendToDecl(@intFromEnum(block_inst));
4585 wip_members.appendToDecl(0); // no doc comments on comptime decls
4550 try setDeclaration(
4551 decl_inst,
4552 std.zig.hashSrc(tree.getNodeSource(node)),
4553 .@"comptime",
4554 decl_block.decl_line - gz.decl_line,
4555 false,
4556 false,
4557 .empty,
4558 &decl_block,
4559 null,
4560 );
45864561}
45874562
45884563fn usingnamespaceDecl(
......@@ -4604,8 +4579,8 @@ fn usingnamespaceDecl(
46044579 };
46054580 // Up top so the ZIR instruction index marks the start range of this
46064581 // top-level declaration.
4607 const block_inst = try gz.makeBlockInst(.block_inline, node);
4608 wip_members.nextDecl(is_pub, true, false, false);
4582 const decl_inst = try gz.makeBlockInst(.declaration, node);
4583 wip_members.nextDecl(decl_inst);
46094584 astgen.advanceSourceCursorToNode(node);
46104585
46114586 var decl_block: GenZir = .{
......@@ -4620,20 +4595,19 @@ fn usingnamespaceDecl(
46204595 defer decl_block.unstack();
46214596
46224597 const namespace_inst = try typeExpr(&decl_block, &decl_block.base, type_expr);
4623 _ = try decl_block.addBreak(.break_inline, block_inst, namespace_inst);
4624 try decl_block.setBlockBody(block_inst);
4625
4626 {
4627 const contents_hash align(@alignOf(u32)) = std.zig.hashSrc(tree.getNodeSource(node));
4628 wip_members.appendToDeclSlice(std.mem.bytesAsSlice(u32, &contents_hash));
4629 }
4630 {
4631 const line_delta = decl_block.decl_line - gz.decl_line;
4632 wip_members.appendToDecl(line_delta);
4633 }
4634 wip_members.appendToDecl(0);
4635 wip_members.appendToDecl(@intFromEnum(block_inst));
4636 wip_members.appendToDecl(0); // no doc comments on usingnamespace decls
4598 _ = try decl_block.addBreak(.break_inline, decl_inst, namespace_inst);
4599
4600 try setDeclaration(
4601 decl_inst,
4602 std.zig.hashSrc(tree.getNodeSource(node)),
4603 .@"usingnamespace",
4604 decl_block.decl_line - gz.decl_line,
4605 is_pub,
4606 false,
4607 .empty,
4608 &decl_block,
4609 null,
4610 );
46374611}
46384612
46394613fn testDecl(
......@@ -4649,9 +4623,9 @@ fn testDecl(
46494623
46504624 // Up top so the ZIR instruction index marks the start range of this
46514625 // top-level declaration.
4652 const block_inst = try gz.makeBlockInst(.block_inline, node);
4626 const decl_inst = try gz.makeBlockInst(.declaration, node);
46534627
4654 wip_members.nextDecl(false, false, false, false);
4628 wip_members.nextDecl(decl_inst);
46554629 astgen.advanceSourceCursorToNode(node);
46564630
46574631 var decl_block: GenZir = .{
......@@ -4669,12 +4643,10 @@ fn testDecl(
46694643 const token_tags = tree.tokens.items(.tag);
46704644 const test_token = main_tokens[node];
46714645 const test_name_token = test_token + 1;
4672 const test_name_token_tag = token_tags[test_name_token];
4673 const is_decltest = test_name_token_tag == .identifier;
4674 const test_name: Zir.NullTerminatedString = blk: {
4675 if (test_name_token_tag == .string_literal) {
4676 break :blk try astgen.testNameString(test_name_token);
4677 } else if (test_name_token_tag == .identifier) {
4646 const test_name: DeclarationName = switch (token_tags[test_name_token]) {
4647 else => .unnamed_test,
4648 .string_literal => .{ .named_test = test_name_token },
4649 .identifier => blk: {
46784650 const ident_name_raw = tree.tokenSlice(test_name_token);
46794651
46804652 if (mem.eql(u8, ident_name_raw, "_")) return astgen.failTok(test_name_token, "'_' used as an identifier without @\"_\" syntax", .{});
......@@ -4744,10 +4716,8 @@ fn testDecl(
47444716 return astgen.failTok(test_name_token, "use of undeclared identifier '{s}'", .{ident_name});
47454717 }
47464718
4747 break :blk name_str_index;
4748 }
4749 // String table index 1 has a special meaning here of test decl with no name.
4750 break :blk .unnamed_test_decl;
4719 break :blk .{ .decltest = name_str_index };
4720 },
47514721 };
47524722
47534723 var fn_block: GenZir = .{
......@@ -4795,7 +4765,7 @@ fn testDecl(
47954765
47964766 .lbrace_line = lbrace_line,
47974767 .lbrace_column = lbrace_column,
4798 .param_block = block_inst,
4768 .param_block = decl_inst,
47994769 .body_gz = &fn_block,
48004770 .lib_name = .empty,
48014771 .is_var_args = false,
......@@ -4806,26 +4776,19 @@ fn testDecl(
48064776 .noalias_bits = 0,
48074777 });
48084778
4809 _ = try decl_block.addBreak(.break_inline, block_inst, func_inst);
4810 try decl_block.setBlockBody(block_inst);
4811
4812 {
4813 const contents_hash align(@alignOf(u32)) = std.zig.hashSrc(tree.getNodeSource(node));
4814 wip_members.appendToDeclSlice(std.mem.bytesAsSlice(u32, &contents_hash));
4815 }
4816 {
4817 const line_delta = decl_block.decl_line - gz.decl_line;
4818 wip_members.appendToDecl(line_delta);
4819 }
4820 if (is_decltest)
4821 wip_members.appendToDecl(2) // 2 here means that it is a decltest, look at doc comment for name
4822 else
4823 wip_members.appendToDecl(@intFromEnum(test_name));
4824 wip_members.appendToDecl(@intFromEnum(block_inst));
4825 if (is_decltest)
4826 wip_members.appendToDecl(@intFromEnum(test_name)) // the doc comment on a decltest represents it's name
4827 else
4828 wip_members.appendToDecl(0); // no doc comments on test decls
4779 _ = try decl_block.addBreak(.break_inline, decl_inst, func_inst);
4780
4781 try setDeclaration(
4782 decl_inst,
4783 std.zig.hashSrc(tree.getNodeSource(node)),
4784 test_name,
4785 decl_block.decl_line - gz.decl_line,
4786 false,
4787 false,
4788 .empty,
4789 &decl_block,
4790 null,
4791 );
48294792}
48304793
48314794fn structDeclInner(
......@@ -13524,3 +13487,106 @@ fn lowerAstErrors(astgen: *AstGen) !void {
1352413487 try tree.renderError(parse_err, msg.writer(gpa));
1352513488 try astgen.appendErrorTokNotesOff(parse_err.token, extra_offset, "{s}", .{msg.items}, notes.items);
1352613489}
13490
13491const DeclarationName = union(enum) {
13492 named: Ast.TokenIndex,
13493 named_test: Ast.TokenIndex,
13494 unnamed_test,
13495 decltest: Zir.NullTerminatedString,
13496 @"comptime",
13497 @"usingnamespace",
13498};
13499
13500/// Sets all extra data for a `declaration` instruction.
13501/// Unstacks `value_gz`, `align_gz`, `linksection_gz`, and `addrspace_gz`.
13502fn setDeclaration(
13503 decl_inst: Zir.Inst.Index,
13504 src_hash: std.zig.SrcHash,
13505 name: DeclarationName,
13506 line_offset: u32,
13507 is_pub: bool,
13508 is_export: bool,
13509 doc_comment: Zir.NullTerminatedString,
13510 value_gz: *GenZir,
13511 /// May be `null` if all these blocks would be empty.
13512 /// If `null`, then `value_gz` must have nothing stacked on it.
13513 extra_gzs: ?struct {
13514 /// Must be stacked on `value_gz`.
13515 align_gz: *GenZir,
13516 /// Must be stacked on `align_gz`.
13517 linksection_gz: *GenZir,
13518 /// Must be stacked on `linksection_gz`, and have nothing stacked on it.
13519 addrspace_gz: *GenZir,
13520 },
13521) !void {
13522 const astgen = value_gz.astgen;
13523 const gpa = astgen.gpa;
13524
13525 const empty_body: []Zir.Inst.Index = &.{};
13526 const value_body, const align_body, const linksection_body, const addrspace_body = if (extra_gzs) |e| .{
13527 value_gz.instructionsSliceUpto(e.align_gz),
13528 e.align_gz.instructionsSliceUpto(e.linksection_gz),
13529 e.linksection_gz.instructionsSliceUpto(e.addrspace_gz),
13530 e.addrspace_gz.instructionsSlice(),
13531 } else .{ value_gz.instructionsSlice(), empty_body, empty_body, empty_body };
13532
13533 const value_len = astgen.countBodyLenAfterFixups(value_body);
13534 const align_len = astgen.countBodyLenAfterFixups(align_body);
13535 const linksection_len = astgen.countBodyLenAfterFixups(linksection_body);
13536 const addrspace_len = astgen.countBodyLenAfterFixups(addrspace_body);
13537
13538 const true_doc_comment: Zir.NullTerminatedString = switch (name) {
13539 .decltest => |test_name| test_name,
13540 else => doc_comment,
13541 };
13542
13543 const src_hash_arr: [4]u32 = @bitCast(src_hash);
13544
13545 const extra: Zir.Inst.Declaration = .{
13546 .src_hash_0 = src_hash_arr[0],
13547 .src_hash_1 = src_hash_arr[1],
13548 .src_hash_2 = src_hash_arr[2],
13549 .src_hash_3 = src_hash_arr[3],
13550 .name = switch (name) {
13551 .named => |tok| @enumFromInt(@intFromEnum(try astgen.identAsString(tok))),
13552 .named_test => |tok| @enumFromInt(@intFromEnum(try astgen.testNameString(tok))),
13553 .unnamed_test => .unnamed_test,
13554 .decltest => .decltest,
13555 .@"comptime" => .@"comptime",
13556 .@"usingnamespace" => .@"usingnamespace",
13557 },
13558 .line_offset = line_offset,
13559 .flags = .{
13560 .value_body_len = @intCast(value_len),
13561 .is_pub = is_pub,
13562 .is_export = is_export,
13563 .has_doc_comment = true_doc_comment != .empty,
13564 .has_align_linksection_addrspace = align_len != 0 or linksection_len != 0 or addrspace_len != 0,
13565 },
13566 };
13567 astgen.instructions.items(.data)[@intFromEnum(decl_inst)].pl_node.payload_index = try astgen.addExtra(extra);
13568 if (extra.flags.has_doc_comment) {
13569 try astgen.extra.append(gpa, @intFromEnum(true_doc_comment));
13570 }
13571 if (extra.flags.has_align_linksection_addrspace) {
13572 try astgen.extra.appendSlice(gpa, &.{
13573 align_len,
13574 linksection_len,
13575 addrspace_len,
13576 });
13577 }
13578 try astgen.extra.ensureUnusedCapacity(gpa, value_len + align_len + linksection_len + addrspace_len);
13579 astgen.appendBodyWithFixups(value_body);
13580 if (extra.flags.has_align_linksection_addrspace) {
13581 astgen.appendBodyWithFixups(align_body);
13582 astgen.appendBodyWithFixups(linksection_body);
13583 astgen.appendBodyWithFixups(addrspace_body);
13584 }
13585
13586 if (extra_gzs) |e| {
13587 e.addrspace_gz.unstack();
13588 e.linksection_gz.unstack();
13589 e.align_gz.unstack();
13590 }
13591 value_gz.unstack();
13592}
src/Autodoc.zig+119-183
......@@ -2846,22 +2846,14 @@ fn walkInstruction(
28462846 return res;
28472847 },
28482848 .block_inline => {
2849 return self.walkRef(
2849 const pl_node = data[@intFromEnum(inst)].pl_node;
2850 const extra = file.zir.extraData(Zir.Inst.Block, pl_node.payload_index);
2851 return self.walkInlineBody(
28502852 file,
28512853 parent_scope,
2854 try self.srcLocInfo(file, pl_node.src_node, parent_src),
28522855 parent_src,
2853 getBlockInlineBreak(file.zir, inst) orelse {
2854 const res = DocData.WalkResult{
2855 .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
2856 .expr = .{ .comptimeExpr = self.comptime_exprs.items.len },
2857 };
2858 const pl_node = data[@intFromEnum(inst)].pl_node;
2859 const block_inline_expr = try self.getBlockSource(file, parent_src, pl_node.src_node);
2860 try self.comptime_exprs.append(self.arena, .{
2861 .code = block_inline_expr,
2862 });
2863 return res;
2864 },
2856 file.zir.bodySlice(extra.end, extra.data.body_len),
28652857 need_type,
28662858 call_ctx,
28672859 );
......@@ -4084,19 +4076,11 @@ fn analyzeAllDecls(
40844076 // First loop to discover decl names
40854077 {
40864078 var it = original_it;
4087 while (it.next()) |d| {
4088 const decl_name_index: Zir.NullTerminatedString = @enumFromInt(file.zir.extra[@intFromEnum(d.sub_index) + 5]);
4089 switch (decl_name_index) {
4090 .empty,
4091 .unnamed_test_decl,
4092 .decltest,
4093 => continue,
4094 _ => if (file.zir.nullTerminatedString(decl_name_index).len == 0) {
4095 continue;
4096 },
4097 }
4098
4099 try scope.insertDeclRef(self.arena, decl_name_index, .Pending);
4079 while (it.next()) |zir_index| {
4080 const declaration, _ = file.zir.getDeclaration(zir_index);
4081 if (declaration.name.isNamedTest(file.zir)) continue;
4082 const decl_name = declaration.name.toString(file.zir) orelse continue;
4083 try scope.insertDeclRef(self.arena, decl_name, .Pending);
41004084 }
41014085 }
41024086
......@@ -4104,147 +4088,114 @@ fn analyzeAllDecls(
41044088 {
41054089 var it = original_it;
41064090 var decl_indexes_slot = first_decl_indexes_slot;
4107 while (it.next()) |d| : (decl_indexes_slot += 1) {
4108 const decl_name_index = file.zir.extra[@intFromEnum(d.sub_index) + 5];
4109 switch (decl_name_index) {
4110 0 => {
4111 const is_exported = @as(u1, @truncate(d.flags >> 1));
4112 switch (is_exported) {
4113 0 => continue, // comptime decl
4114 1 => {
4115 try self.analyzeUsingnamespaceDecl(
4116 file,
4117 scope,
4118 parent_src,
4119 decl_indexes,
4120 priv_decl_indexes,
4121 d,
4122 call_ctx,
4123 );
4124 },
4125 }
4126 },
4127 else => continue,
4128 }
4091 while (it.next()) |zir_index| : (decl_indexes_slot += 1) {
4092 const pl_node = file.zir.instructions.items(.data)[@intFromEnum(zir_index)].pl_node;
4093 const extra = file.zir.extraData(Zir.Inst.Declaration, pl_node.payload_index);
4094 if (extra.data.name != .@"usingnamespace") continue;
4095 try self.analyzeUsingnamespaceDecl(
4096 file,
4097 scope,
4098 try self.srcLocInfo(file, pl_node.src_node, parent_src),
4099 decl_indexes,
4100 priv_decl_indexes,
4101 extra.data,
4102 @intCast(extra.end),
4103 call_ctx,
4104 );
41294105 }
41304106 }
41314107
41324108 // Third loop to analyze all remaining decls
4133 var it = original_it;
4134 while (it.next()) |d| {
4135 const decl_name_index = file.zir.extra[@intFromEnum(d.sub_index) + 5];
4136 switch (decl_name_index) {
4137 0, 1 => continue, // skip over usingnamespace decls
4138 2 => continue, // skip decltests
4139
4140 else => if (file.zir.string_bytes[decl_name_index] == 0) {
4141 continue;
4142 },
4109 {
4110 var it = original_it;
4111 while (it.next()) |zir_index| {
4112 const pl_node = file.zir.instructions.items(.data)[@intFromEnum(zir_index)].pl_node;
4113 const extra = file.zir.extraData(Zir.Inst.Declaration, pl_node.payload_index);
4114 switch (extra.data.name) {
4115 .@"comptime", .@"usingnamespace", .unnamed_test, .decltest => continue,
4116 _ => if (extra.data.name.isNamedTest(file.zir)) continue,
4117 }
4118 try self.analyzeDecl(
4119 file,
4120 scope,
4121 try self.srcLocInfo(file, pl_node.src_node, parent_src),
4122 decl_indexes,
4123 priv_decl_indexes,
4124 zir_index,
4125 extra.data,
4126 @intCast(extra.end),
4127 call_ctx,
4128 );
41434129 }
4144
4145 try self.analyzeDecl(
4146 file,
4147 scope,
4148 parent_src,
4149 decl_indexes,
4150 priv_decl_indexes,
4151 d,
4152 call_ctx,
4153 );
41544130 }
41554131
41564132 // Fourth loop to analyze decltests
4157 it = original_it;
4158 while (it.next()) |d| {
4159 const decl_name_index = file.zir.extra[@intFromEnum(d.sub_index) + 5];
4160 switch (decl_name_index) {
4161 0, 1 => continue, // skip over usingnamespace decls
4162 2 => {},
4163 else => continue, // skip tests and normal decls
4164 }
4165
4133 var it = original_it;
4134 while (it.next()) |zir_index| {
4135 const pl_node = file.zir.instructions.items(.data)[@intFromEnum(zir_index)].pl_node;
4136 const extra = file.zir.extraData(Zir.Inst.Declaration, pl_node.payload_index);
4137 if (extra.data.name != .decltest) continue;
41664138 try self.analyzeDecltest(
41674139 file,
41684140 scope,
4169 parent_src,
4170 d,
4141 try self.srcLocInfo(file, pl_node.src_node, parent_src),
4142 extra.data,
4143 @intCast(extra.end),
41714144 );
41724145 }
41734146
41744147 return it.extra_index;
41754148}
41764149
4150fn walkInlineBody(
4151 autodoc: *Autodoc,
4152 file: *File,
4153 scope: *Scope,
4154 block_src: SrcLocInfo,
4155 parent_src: SrcLocInfo,
4156 body: []const Zir.Inst.Index,
4157 need_type: bool,
4158 call_ctx: ?*const CallContext,
4159) AutodocErrors!DocData.WalkResult {
4160 const tags = file.zir.instructions.items(.tag);
4161 const break_inst = switch (tags[@intFromEnum(body[body.len - 1])]) {
4162 .condbr_inline => {
4163 // Unresolvable.
4164 const res: DocData.WalkResult = .{
4165 .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
4166 .expr = .{ .comptimeExpr = autodoc.comptime_exprs.items.len },
4167 };
4168 const source = (try file.getTree(autodoc.zcu.gpa)).getNodeSource(block_src.src_node);
4169 try autodoc.comptime_exprs.append(autodoc.arena, .{
4170 .code = source,
4171 });
4172 return res;
4173 },
4174 .break_inline => body[body.len - 1],
4175 else => unreachable,
4176 };
4177 const break_data = file.zir.instructions.items(.data)[@intFromEnum(break_inst)].@"break";
4178 return autodoc.walkRef(file, scope, parent_src, break_data.operand, need_type, call_ctx);
4179}
4180
41774181// Asserts the given decl is public
41784182fn analyzeDecl(
41794183 self: *Autodoc,
41804184 file: *File,
41814185 scope: *Scope,
4182 parent_src: SrcLocInfo,
4186 decl_src: SrcLocInfo,
41834187 decl_indexes: *std.ArrayListUnmanaged(usize),
41844188 priv_decl_indexes: *std.ArrayListUnmanaged(usize),
4185 d: Zir.DeclIterator.Item,
4189 decl_inst: Zir.Inst.Index,
4190 declaration: Zir.Inst.Declaration,
4191 extra_index: u32,
41864192 call_ctx: ?*const CallContext,
41874193) AutodocErrors!void {
4188 const data = file.zir.instructions.items(.data);
4189 const is_pub = @as(u1, @truncate(d.flags >> 0)) != 0;
4190 // const is_exported = @truncate(u1, d.flags >> 1) != 0;
4191 const has_align = @as(u1, @truncate(d.flags >> 2)) != 0;
4192 const has_section_or_addrspace = @as(u1, @truncate(d.flags >> 3)) != 0;
4193
4194 var extra_index = @intFromEnum(d.sub_index);
4195 // const hash_u32s = file.zir.extra[extra_index..][0..4];
4196
4197 extra_index += 4;
4198 // const line = file.zir.extra[extra_index];
4199
4200 extra_index += 1;
4201 const decl_name_index: Zir.NullTerminatedString = @enumFromInt(file.zir.extra[extra_index]);
4202
4203 extra_index += 1;
4204 const value_index: Zir.Inst.Index = @enumFromInt(file.zir.extra[extra_index]);
4205
4206 extra_index += 1;
4207 const doc_comment_index: Zir.NullTerminatedString = @enumFromInt(file.zir.extra[extra_index]);
4208
4209 extra_index += 1;
4210 const align_inst: Zir.Inst.Ref = if (!has_align) .none else inst: {
4211 const inst: Zir.Inst.Ref = @enumFromInt(file.zir.extra[extra_index]);
4212 extra_index += 1;
4213 break :inst inst;
4214 };
4215 _ = align_inst;
4216
4217 const section_inst: Zir.Inst.Ref = if (!has_section_or_addrspace) .none else inst: {
4218 const inst: Zir.Inst.Ref = @enumFromInt(file.zir.extra[extra_index]);
4219 extra_index += 1;
4220 break :inst inst;
4221 };
4222 _ = section_inst;
4194 const bodies = declaration.getBodies(extra_index, file.zir);
4195 const name = file.zir.nullTerminatedString(declaration.name.toString(file.zir).?);
42234196
4224 const addrspace_inst: Zir.Inst.Ref = if (!has_section_or_addrspace) .none else inst: {
4225 const inst: Zir.Inst.Ref = @enumFromInt(file.zir.extra[extra_index]);
4226 extra_index += 1;
4227 break :inst inst;
4228 };
4229 _ = addrspace_inst;
4230
4231 // This is known to work because decl values are always block_inlines
4232 const value_pl_node = data[@intFromEnum(value_index)].pl_node;
4233 const decl_src = try self.srcLocInfo(file, value_pl_node.src_node, parent_src);
4234
4235 const name: []const u8 = switch (decl_name_index) {
4236 .empty, .unnamed_test_decl, .decltest => unreachable,
4237 _ => blk: {
4238 if (decl_name_index == .empty) {
4239 // test decl
4240 unreachable;
4241 }
4242 break :blk file.zir.nullTerminatedString(decl_name_index);
4243 },
4244 };
4245
4246 const doc_comment: ?[]const u8 = if (doc_comment_index != .empty)
4247 file.zir.nullTerminatedString(doc_comment_index)
4197 const doc_comment: ?[]const u8 = if (declaration.flags.has_doc_comment)
4198 file.zir.nullTerminatedString(@enumFromInt(file.zir.extra[extra_index]))
42484199 else
42494200 null;
42504201
......@@ -4261,16 +4212,22 @@ fn analyzeDecl(
42614212 break :idx idx;
42624213 };
42634214
4264 const walk_result = try self.walkInstruction(
4215 const walk_result = try self.walkInlineBody(
42654216 file,
42664217 scope,
42674218 decl_src,
4268 value_index,
4219 decl_src,
4220 bodies.value_body,
42694221 true,
42704222 call_ctx,
42714223 );
42724224
4273 const kind: []const u8 = if (try self.declIsVar(file, value_pl_node.src_node, parent_src)) "var" else "const";
4225 const tree = try file.getTree(self.zcu.gpa);
4226 const kind_token = tree.nodes.items(.main_token)[decl_src.src_node];
4227 const kind: []const u8 = switch (tree.tokens.items(.tag)[kind_token]) {
4228 .keyword_var => "var",
4229 else => "const",
4230 };
42744231
42754232 const decls_slot_index = self.decls.items.len;
42764233 try self.decls.append(self.arena, .{
......@@ -4281,13 +4238,13 @@ fn analyzeDecl(
42814238 .parent_container = scope.enclosing_type,
42824239 });
42834240
4284 if (is_pub) {
4241 if (declaration.flags.is_pub) {
42854242 try decl_indexes.append(self.arena, decls_slot_index);
42864243 } else {
42874244 try priv_decl_indexes.append(self.arena, decls_slot_index);
42884245 }
42894246
4290 const decl_status_ptr = scope.resolveDeclName(decl_name_index, file, .none);
4247 const decl_status_ptr = scope.resolveDeclName(declaration.name.toString(file.zir).?, file, .none);
42914248 std.debug.assert(decl_status_ptr.* == .Pending);
42924249 decl_status_ptr.* = .{ .Analyzed = decls_slot_index };
42934250
......@@ -4296,7 +4253,7 @@ fn analyzeDecl(
42964253 for (paths.items) |resume_info| {
42974254 try self.tryResolveRefPath(
42984255 resume_info.file,
4299 value_index,
4256 decl_inst,
43004257 resume_info.ref_path,
43014258 );
43024259 }
......@@ -4312,24 +4269,17 @@ fn analyzeUsingnamespaceDecl(
43124269 self: *Autodoc,
43134270 file: *File,
43144271 scope: *Scope,
4315 parent_src: SrcLocInfo,
4272 decl_src: SrcLocInfo,
43164273 decl_indexes: *std.ArrayListUnmanaged(usize),
43174274 priv_decl_indexes: *std.ArrayListUnmanaged(usize),
4318 d: Zir.DeclIterator.Item,
4275 declaration: Zir.Inst.Declaration,
4276 extra_index: u32,
43194277 call_ctx: ?*const CallContext,
43204278) AutodocErrors!void {
4321 const data = file.zir.instructions.items(.data);
4279 const bodies = declaration.getBodies(extra_index, file.zir);
43224280
4323 const is_pub = @as(u1, @truncate(d.flags)) != 0;
4324 const value_index: Zir.Inst.Index = @enumFromInt(file.zir.extra[@intFromEnum(d.sub_index) + 6]);
4325 const doc_comment_index: Zir.NullTerminatedString = @enumFromInt(file.zir.extra[@intFromEnum(d.sub_index) + 7]);
4326
4327 // This is known to work because decl values are always block_inlines
4328 const value_pl_node = data[@intFromEnum(value_index)].pl_node;
4329 const decl_src = try self.srcLocInfo(file, value_pl_node.src_node, parent_src);
4330
4331 const doc_comment: ?[]const u8 = if (doc_comment_index != .empty)
4332 file.zir.nullTerminatedString(doc_comment_index)
4281 const doc_comment: ?[]const u8 = if (declaration.flags.has_doc_comment)
4282 file.zir.nullTerminatedString(@enumFromInt(file.zir.extra[extra_index]))
43334283 else
43344284 null;
43354285
......@@ -4346,11 +4296,12 @@ fn analyzeUsingnamespaceDecl(
43464296 break :idx idx;
43474297 };
43484298
4349 const walk_result = try self.walkInstruction(
4299 const walk_result = try self.walkInlineBody(
43504300 file,
43514301 scope,
43524302 decl_src,
4353 value_index,
4303 decl_src,
4304 bodies.value_body,
43544305 true,
43554306 call_ctx,
43564307 );
......@@ -4365,7 +4316,7 @@ fn analyzeUsingnamespaceDecl(
43654316 .parent_container = scope.enclosing_type,
43664317 });
43674318
4368 if (is_pub) {
4319 if (declaration.flags.is_pub) {
43694320 try decl_indexes.append(self.arena, decl_slot_index);
43704321 } else {
43714322 try priv_decl_indexes.append(self.arena, decl_slot_index);
......@@ -4376,18 +4327,14 @@ fn analyzeDecltest(
43764327 self: *Autodoc,
43774328 file: *File,
43784329 scope: *Scope,
4379 parent_src: SrcLocInfo,
4380 d: Zir.DeclIterator.Item,
4330 decl_src: SrcLocInfo,
4331 declaration: Zir.Inst.Declaration,
4332 extra_index: u32,
43814333) AutodocErrors!void {
4382 const data = file.zir.instructions.items(.data);
4383
4384 const value_index = file.zir.extra[@intFromEnum(d.sub_index) + 6];
4385 const decl_name_index: Zir.NullTerminatedString = @enumFromInt(file.zir.extra[@intFromEnum(d.sub_index) + 7]);
4386
4387 const value_pl_node = data[value_index].pl_node;
4388 const decl_src = try self.srcLocInfo(file, value_pl_node.src_node, parent_src);
4334 std.debug.assert(declaration.flags.has_doc_comment);
4335 const decl_name_index: Zir.NullTerminatedString = @enumFromInt(file.zir.extra[extra_index]);
43894336
4390 const test_source_code = try self.getBlockSource(file, parent_src, value_pl_node.src_node);
4337 const test_source_code = (try file.getTree(self.zcu.gpa)).getNodeSource(decl_src.src_node);
43914338
43924339 const decl_name: ?[]const u8 = if (decl_name_index != .empty)
43934340 file.zir.nullTerminatedString(decl_name_index)
......@@ -5830,17 +5777,6 @@ fn walkRef(
58305777 }
58315778}
58325779
5833fn getBlockInlineBreak(zir: Zir, inst: Zir.Inst.Index) ?Zir.Inst.Ref {
5834 const tags = zir.instructions.items(.tag);
5835 const data = zir.instructions.items(.data);
5836 const pl_node = data[@intFromEnum(inst)].pl_node;
5837 const extra = zir.extraData(Zir.Inst.Block, pl_node.payload_index);
5838 const break_index = zir.extra[extra.end..][extra.data.body_len - 1];
5839 if (tags[break_index] == .condbr_inline) return null;
5840 std.debug.assert(tags[break_index] == .break_inline);
5841 return data[break_index].@"break".operand;
5842}
5843
58445780fn printWithContext(
58455781 file: *File,
58465782 inst: Zir.Inst.Index,
src/InternPool.zig-2
......@@ -6186,8 +6186,6 @@ fn finishFuncInstance(
61866186 .generation = generation,
61876187 .is_pub = fn_owner_decl.is_pub,
61886188 .is_exported = fn_owner_decl.is_exported,
6189 .has_linksection_or_addrspace = fn_owner_decl.has_linksection_or_addrspace,
6190 .has_align = fn_owner_decl.has_align,
61916189 .alive = true,
61926190 .kind = .anon,
61936191 });
src/Module.zig+216-260
......@@ -386,11 +386,9 @@ pub const Decl = struct {
386386 /// do not need to be loaded into memory in order to compute debug line numbers.
387387 /// This value is absolute.
388388 src_line: u32,
389 /// Index to ZIR `extra` array to the entry in the parent's decl structure
390 /// (the part that says "for every decls_len"). The first item at this index is
391 /// the contents hash, followed by line, name, etc.
392 /// For anonymous decls and also the root Decl for a File, this is `none`.
393 zir_decl_index: Zir.OptionalExtraIndex,
389 /// Index of the ZIR `declaration` instruction from which this `Decl` was created.
390 /// For the root `Decl` of a `File` and legacy anonymous decls, this is `.none`.
391 zir_decl_index: Zir.Inst.OptionalIndex,
394392
395393 /// Represents the "shallow" analysis status. For example, for decls that are functions,
396394 /// the function type is analyzed with this set to `in_progress`, however, the semantic
......@@ -442,10 +440,6 @@ pub const Decl = struct {
442440 is_pub: bool,
443441 /// Whether the corresponding AST decl has a `export` keyword.
444442 is_exported: bool,
445 /// Whether the ZIR code provides an align instruction.
446 has_align: bool,
447 /// Whether the ZIR code provides a linksection and address space instruction.
448 has_linksection_or_addrspace: bool,
449443 /// Flag used by garbage collection to mark and sweep.
450444 /// Decls which correspond to an AST node always have this field set to `true`.
451445 /// Anonymous Decls are initialized with this field set to `false` and then it
......@@ -471,81 +465,19 @@ pub const Decl = struct {
471465 const Index = InternPool.DeclIndex;
472466 const OptionalIndex = InternPool.OptionalDeclIndex;
473467
474 pub const DepsTable = std.AutoArrayHashMapUnmanaged(Decl.Index, DepType);
475
476 /// Later types take priority; e.g. if a dependent decl has both `normal`
477 /// and `function_body` dependencies on another decl, it will be marked as
478 /// having a `function_body` dependency.
479 pub const DepType = enum {
480 /// The dependent references or uses the dependency's value, so must be
481 /// updated whenever it is changed. However, if the dependency is a
482 /// function and its type is unchanged, the dependent does not need to
483 /// be updated.
484 normal,
485 /// The dependent performs an inline or comptime call to the dependency,
486 /// or is a generic instantiation of it. It must therefore be updated
487 /// whenever the dependency is updated, even if the function type
488 /// remained the same.
489 function_body,
490 };
491
492 /// This name is relative to the containing namespace of the decl.
493 /// The memory is owned by the containing File ZIR.
494 pub fn getName(decl: Decl, mod: *Module) ?[:0]const u8 {
495 const zir = decl.getFileScope(mod).zir;
496 return decl.getNameZir(zir);
468 /// Asserts that `zir_decl_index` is not `.none`.
469 fn getDeclaration(decl: Decl, zir: Zir) Zir.Inst.Declaration {
470 const zir_index = decl.zir_decl_index.unwrap().?;
471 const pl_node = zir.instructions.items(.data)[@intFromEnum(zir_index)].pl_node;
472 return zir.extraData(Zir.Inst.Declaration, pl_node.payload_index).data;
497473 }
498474
499 pub fn getNameZir(decl: Decl, zir: Zir) ?[:0]const u8 {
500 assert(decl.zir_decl_index != .none);
501 const name_index = zir.extra[@intFromEnum(decl.zir_decl_index) + 5];
502 if (name_index <= 1) return null;
503 return zir.nullTerminatedString(name_index);
504 }
505
506 pub fn contentsHash(decl: Decl, mod: *Module) std.zig.SrcHash {
507 const zir = decl.getFileScope(mod).zir;
508 return decl.contentsHashZir(zir);
509 }
510
511 pub fn contentsHashZir(decl: Decl, zir: Zir) std.zig.SrcHash {
512 assert(decl.zir_decl_index != .none);
513 const hash_u32s = zir.extra[@intFromEnum(decl.zir_decl_index)..][0..4];
514 const contents_hash = @as(std.zig.SrcHash, @bitCast(hash_u32s.*));
515 return contents_hash;
516 }
517
518 pub fn zirBlockIndex(decl: *const Decl, mod: *Module) Zir.Inst.Index {
519 assert(decl.zir_decl_index != .none);
520 const zir = decl.getFileScope(mod).zir;
521 return @enumFromInt(zir.extra[@intFromEnum(decl.zir_decl_index) + 6]);
522 }
523
524 pub fn zirAlignRef(decl: Decl, mod: *Module) Zir.Inst.Ref {
525 if (!decl.has_align) return .none;
526 assert(decl.zir_decl_index != .none);
527 const zir = decl.getFileScope(mod).zir;
528 return @enumFromInt(zir.extra[@intFromEnum(decl.zir_decl_index) + 8]);
529 }
530
531 pub fn zirLinksectionRef(decl: Decl, mod: *Module) Zir.Inst.Ref {
532 if (!decl.has_linksection_or_addrspace) return .none;
533 assert(decl.zir_decl_index != .none);
534 const zir = decl.getFileScope(mod).zir;
535 const extra_index = @intFromEnum(decl.zir_decl_index) + 8 + @intFromBool(decl.has_align);
536 return @enumFromInt(zir.extra[extra_index]);
537 }
538
539 pub fn zirAddrspaceRef(decl: Decl, mod: *Module) Zir.Inst.Ref {
540 if (!decl.has_linksection_or_addrspace) return .none;
541 assert(decl.zir_decl_index != .none);
542 const zir = decl.getFileScope(mod).zir;
543 const extra_index = @intFromEnum(decl.zir_decl_index) + 8 + @intFromBool(decl.has_align) + 1;
544 return @enumFromInt(zir.extra[extra_index]);
545 }
546
547 pub fn relativeToLine(decl: Decl, offset: u32) u32 {
548 return decl.src_line + offset;
475 pub fn zirBodies(decl: Decl, zcu: *Zcu) Zir.Inst.Declaration.Bodies {
476 const zir = decl.getFileScope(zcu).zir;
477 const zir_index = decl.zir_decl_index.unwrap().?;
478 const pl_node = zir.instructions.items(.data)[@intFromEnum(zir_index)].pl_node;
479 const extra = zir.extraData(Zir.Inst.Declaration, pl_node.payload_index);
480 return extra.data.getBodies(@intCast(extra.end), zir);
549481 }
550482
551483 pub fn relativeToNodeIndex(decl: Decl, offset: i32) Ast.Node.Index {
......@@ -3015,16 +2947,12 @@ fn updateZirRefs(mod: *Module, file: *File, old_zir: Zir) !void {
30152947 // The root decl will be null if the previous ZIR had AST errors.
30162948 const root_decl = file.root_decl.unwrap() orelse return;
30172949
3018 // Maps from old ZIR to new ZIR, struct_decl, enum_decl, etc. Any instruction which
3019 // creates a namespace, gets mapped from old to new here.
2950 // Maps from old ZIR to new ZIR, declaration, struct_decl, enum_decl, etc. Any instruction which
2951 // creates a namespace, and any `declaration` instruction, gets mapped from old to new here.
30202952 var inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{};
30212953 defer inst_map.deinit(gpa);
3022 // Maps from old ZIR to new ZIR, the extra data index for the sub-decl item.
3023 // e.g. the thing that Decl.zir_decl_index points to.
3024 var extra_map: std.AutoHashMapUnmanaged(Zir.ExtraIndex, Zir.ExtraIndex) = .{};
3025 defer extra_map.deinit(gpa);
30262954
3027 try mapOldZirToNew(gpa, old_zir, new_zir, &inst_map, &extra_map);
2955 try mapOldZirToNew(gpa, old_zir, new_zir, &inst_map);
30282956
30292957 // Walk the Decl graph, updating ZIR indexes, strings, and populating
30302958 // the deleted and outdated lists.
......@@ -3050,7 +2978,7 @@ fn updateZirRefs(mod: *Module, file: *File, old_zir: Zir) !void {
30502978 // Anonymous decls should not be marked outdated. They will be re-generated
30512979 // if their owner decl is marked outdated.
30522980 if (decl.zir_decl_index.unwrap()) |old_zir_decl_index| {
3053 const new_zir_decl_index = extra_map.get(old_zir_decl_index) orelse {
2981 const new_zir_decl_index = inst_map.get(old_zir_decl_index) orelse {
30542982 try file.deleted_decls.append(gpa, decl_index);
30552983 continue;
30562984 };
......@@ -3098,9 +3026,9 @@ pub fn mapOldZirToNew(
30983026 old_zir: Zir,
30993027 new_zir: Zir,
31003028 inst_map: *std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index),
3101 extra_map: *std.AutoHashMapUnmanaged(Zir.ExtraIndex, Zir.ExtraIndex),
31023029) Allocator.Error!void {
3103 // Contain ZIR indexes of declaration instructions.
3030 // Contain ZIR indexes of namespace declaration instructions, e.g. struct_decl, union_decl, etc.
3031 // Not `declaration`, as this does not create a namespace.
31043032 const MatchedZirDecl = struct {
31053033 old_inst: Zir.Inst.Index,
31063034 new_inst: Zir.Inst.Index,
......@@ -3108,47 +3036,113 @@ pub fn mapOldZirToNew(
31083036 var match_stack: ArrayListUnmanaged(MatchedZirDecl) = .{};
31093037 defer match_stack.deinit(gpa);
31103038
3111 // Main struct inst is always the same
3039 // Main struct inst is always matched
31123040 try match_stack.append(gpa, .{
31133041 .old_inst = .main_struct_inst,
31143042 .new_inst = .main_struct_inst,
31153043 });
31163044
3045 // Used as temporary buffers for namespace declaration instructions
31173046 var old_decls = std.ArrayList(Zir.Inst.Index).init(gpa);
31183047 defer old_decls.deinit();
31193048 var new_decls = std.ArrayList(Zir.Inst.Index).init(gpa);
31203049 defer new_decls.deinit();
31213050
31223051 while (match_stack.popOrNull()) |match_item| {
3052 // Match the namespace declaration itself
31233053 try inst_map.put(gpa, match_item.old_inst, match_item.new_inst);
31243054
3125 // Maps name to extra index of decl sub item.
3126 var decl_map: std.StringHashMapUnmanaged(Zir.ExtraIndex) = .{};
3127 defer decl_map.deinit(gpa);
3055 // Maps decl name to `declaration` instruction.
3056 var named_decls: std.StringHashMapUnmanaged(Zir.Inst.Index) = .{};
3057 defer named_decls.deinit(gpa);
3058 // Maps test name to `declaration` instruction.
3059 var named_tests: std.StringHashMapUnmanaged(Zir.Inst.Index) = .{};
3060 defer named_tests.deinit(gpa);
3061 // All unnamed tests, in order, for a best-effort match.
3062 var unnamed_tests: std.ArrayListUnmanaged(Zir.Inst.Index) = .{};
3063 defer unnamed_tests.deinit(gpa);
3064 // All comptime declarations, in order, for a best-effort match.
3065 var comptime_decls: std.ArrayListUnmanaged(Zir.Inst.Index) = .{};
3066 defer comptime_decls.deinit(gpa);
3067 // All usingnamespace declarations, in order, for a best-effort match.
3068 var usingnamespace_decls: std.ArrayListUnmanaged(Zir.Inst.Index) = .{};
3069 defer usingnamespace_decls.deinit(gpa);
31283070
31293071 {
31303072 var old_decl_it = old_zir.declIterator(match_item.old_inst);
3131 while (old_decl_it.next()) |old_decl| {
3132 try decl_map.put(gpa, old_decl.name, old_decl.sub_index);
3073 while (old_decl_it.next()) |old_decl_inst| {
3074 const old_decl, _ = old_zir.getDeclaration(old_decl_inst);
3075 switch (old_decl.name) {
3076 .@"comptime" => try comptime_decls.append(gpa, old_decl_inst),
3077 .@"usingnamespace" => try usingnamespace_decls.append(gpa, old_decl_inst),
3078 .unnamed_test, .decltest => try unnamed_tests.append(gpa, old_decl_inst),
3079 _ => {
3080 const name_nts = old_decl.name.toString(old_zir).?;
3081 const name = old_zir.nullTerminatedString(name_nts);
3082 if (old_decl.name.isNamedTest(old_zir)) {
3083 try named_tests.put(gpa, name, old_decl_inst);
3084 } else {
3085 try named_decls.put(gpa, name, old_decl_inst);
3086 }
3087 },
3088 }
31333089 }
31343090 }
31353091
3092 var unnamed_test_idx: u32 = 0;
3093 var comptime_decl_idx: u32 = 0;
3094 var usingnamespace_decl_idx: u32 = 0;
3095
31363096 var new_decl_it = new_zir.declIterator(match_item.new_inst);
3137 while (new_decl_it.next()) |new_decl| {
3138 const old_extra_index = decl_map.get(new_decl.name) orelse continue;
3139 const new_extra_index = new_decl.sub_index;
3140 try extra_map.put(gpa, old_extra_index, new_extra_index);
3141
3142 try old_zir.findDecls(&old_decls, old_extra_index);
3143 try new_zir.findDecls(&new_decls, new_extra_index);
3144 var i: usize = 0;
3145 while (true) : (i += 1) {
3146 if (i >= old_decls.items.len) break;
3147 if (i >= new_decls.items.len) break;
3148 try match_stack.append(gpa, .{
3149 .old_inst = old_decls.items[i],
3150 .new_inst = new_decls.items[i],
3151 });
3097 while (new_decl_it.next()) |new_decl_inst| {
3098 const new_decl, _ = new_zir.getDeclaration(new_decl_inst);
3099 // Attempt to match this to a declaration in the old ZIR:
3100 // * For named declarations (`const`/`var`/`fn`), we match based on name.
3101 // * For named tests (`test "foo"`), we also match based on name.
3102 // * For unnamed tests and decltests, we match based on order.
3103 // * For comptime blocks, we match based on order.
3104 // * For usingnamespace decls, we match based on order.
3105 // If we cannot match this declaration, we can't match anything nested inside of it either, so we just `continue`.
3106 const old_decl_inst = switch (new_decl.name) {
3107 .@"comptime" => inst: {
3108 if (comptime_decl_idx == comptime_decls.items.len) continue;
3109 defer comptime_decl_idx += 1;
3110 break :inst comptime_decls.items[comptime_decl_idx];
3111 },
3112 .@"usingnamespace" => inst: {
3113 if (usingnamespace_decl_idx == usingnamespace_decls.items.len) continue;
3114 defer usingnamespace_decl_idx += 1;
3115 break :inst usingnamespace_decls.items[usingnamespace_decl_idx];
3116 },
3117 .unnamed_test, .decltest => inst: {
3118 if (unnamed_test_idx == unnamed_tests.items.len) continue;
3119 defer unnamed_test_idx += 1;
3120 break :inst unnamed_tests.items[unnamed_test_idx];
3121 },
3122 _ => inst: {
3123 const name_nts = new_decl.name.toString(old_zir).?;
3124 const name = new_zir.nullTerminatedString(name_nts);
3125 if (new_decl.name.isNamedTest(new_zir)) {
3126 break :inst named_tests.get(name) orelse continue;
3127 } else {
3128 break :inst named_decls.get(name) orelse continue;
3129 }
3130 },
3131 };
3132
3133 // Match the `declaration` instruction
3134 try inst_map.put(gpa, old_decl_inst, new_decl_inst);
3135
3136 // Find namespace declarations within this declaration
3137 try old_zir.findDecls(&old_decls, old_decl_inst);
3138 try new_zir.findDecls(&new_decls, new_decl_inst);
3139
3140 // We don't have any smart way of matching up these namespace declarations, so we always
3141 // correlate them based on source order.
3142 const n = @min(old_decls.items.len, new_decls.items.len);
3143 try match_stack.ensureUnusedCapacity(gpa, n);
3144 for (old_decls.items[0..n], new_decls.items[0..n]) |old_inst, new_inst| {
3145 match_stack.appendAssumeCapacity(.{ .old_inst = old_inst, .new_inst = new_inst });
31523146 }
31533147 }
31543148 }
......@@ -3457,8 +3451,6 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
34573451 new_decl.src_line = 0;
34583452 new_decl.is_pub = true;
34593453 new_decl.is_exported = false;
3460 new_decl.has_align = false;
3461 new_decl.has_linksection_or_addrspace = false;
34623454 new_decl.ty = Type.type;
34633455 new_decl.alignment = .none;
34643456 new_decl.@"linksection" = .none;
......@@ -3561,7 +3553,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
35613553
35623554 const gpa = mod.gpa;
35633555 const zir = decl.getFileScope(mod).zir;
3564 const zir_datas = zir.instructions.items(.data);
35653556
35663557 const builtin_type_target_index: InternPool.Index = blk: {
35673558 const std_mod = mod.std_mod;
......@@ -3639,11 +3630,9 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
36393630 };
36403631 defer block_scope.instructions.deinit(gpa);
36413632
3642 const zir_block_index = decl.zirBlockIndex(mod);
3643 const inst_data = zir_datas[@intFromEnum(zir_block_index)].pl_node;
3644 const extra = zir.extraData(Zir.Inst.Block, inst_data.payload_index);
3645 const body = zir.extra[extra.end..][0..extra.data.body_len];
3646 const result_ref = (try sema.analyzeBodyBreak(&block_scope, @ptrCast(body))).?.operand;
3633 const decl_bodies = decl.zirBodies(mod);
3634
3635 const result_ref = (try sema.analyzeBodyBreak(&block_scope, decl_bodies.value_body)).?.operand;
36473636 // We'll do some other bits with the Sema. Clear the type target index just
36483637 // in case they analyze any type.
36493638 sema.builtin_type_target_index = .none;
......@@ -3760,13 +3749,13 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
37603749 decl.ty = decl_tv.ty;
37613750 decl.val = Value.fromInterned((try decl_tv.val.intern(decl_tv.ty, mod)));
37623751 decl.alignment = blk: {
3763 const align_ref = decl.zirAlignRef(mod);
3764 if (align_ref == .none) break :blk .none;
3752 const align_body = decl_bodies.align_body orelse break :blk .none;
3753 const align_ref = (try sema.analyzeBodyBreak(&block_scope, align_body)).?.operand;
37653754 break :blk try sema.resolveAlign(&block_scope, align_src, align_ref);
37663755 };
37673756 decl.@"linksection" = blk: {
3768 const linksection_ref = decl.zirLinksectionRef(mod);
3769 if (linksection_ref == .none) break :blk .none;
3757 const linksection_body = decl_bodies.linksection_body orelse break :blk .none;
3758 const linksection_ref = (try sema.analyzeBodyBreak(&block_scope, linksection_body)).?.operand;
37703759 const bytes = try sema.resolveConstString(&block_scope, section_src, linksection_ref, .{
37713760 .needed_comptime_reason = "linksection must be comptime-known",
37723761 });
......@@ -3786,15 +3775,15 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
37863775 };
37873776
37883777 const target = sema.mod.getTarget();
3789 break :blk switch (decl.zirAddrspaceRef(mod)) {
3790 .none => switch (addrspace_ctx) {
3791 .function => target_util.defaultAddressSpace(target, .function),
3792 .variable => target_util.defaultAddressSpace(target, .global_mutable),
3793 .constant => target_util.defaultAddressSpace(target, .global_constant),
3794 else => unreachable,
3795 },
3796 else => |addrspace_ref| try sema.analyzeAddressSpace(&block_scope, address_space_src, addrspace_ref, addrspace_ctx),
3778
3779 const addrspace_body = decl_bodies.addrspace_body orelse break :blk switch (addrspace_ctx) {
3780 .function => target_util.defaultAddressSpace(target, .function),
3781 .variable => target_util.defaultAddressSpace(target, .global_mutable),
3782 .constant => target_util.defaultAddressSpace(target, .global_constant),
3783 else => unreachable,
37973784 };
3785 const addrspace_ref = (try sema.analyzeBodyBreak(&block_scope, addrspace_body)).?.operand;
3786 break :blk try sema.analyzeAddressSpace(&block_scope, address_space_src, addrspace_ref, addrspace_ctx);
37983787 };
37993788 decl.has_tv = true;
38003789 decl.analysis = .complete;
......@@ -4133,52 +4122,32 @@ fn newEmbedFile(
41334122}
41344123
41354124pub fn scanNamespace(
4136 mod: *Module,
4125 zcu: *Zcu,
41374126 namespace_index: Namespace.Index,
4138 extra_start: usize,
4139 decls_len: u32,
4127 decls: []const Zir.Inst.Index,
41404128 parent_decl: *Decl,
4141) Allocator.Error!usize {
4129) Allocator.Error!void {
41424130 const tracy = trace(@src());
41434131 defer tracy.end();
41444132
4145 const gpa = mod.gpa;
4146 const namespace = mod.namespacePtr(namespace_index);
4147 const zir = namespace.file_scope.zir;
4133 const gpa = zcu.gpa;
4134 const namespace = zcu.namespacePtr(namespace_index);
41484135
4149 try mod.comp.work_queue.ensureUnusedCapacity(decls_len);
4150 try namespace.decls.ensureTotalCapacity(gpa, decls_len);
4136 try zcu.comp.work_queue.ensureUnusedCapacity(decls.len);
4137 try namespace.decls.ensureTotalCapacity(gpa, decls.len);
41514138
4152 const bit_bags_count = std.math.divCeil(usize, decls_len, 8) catch unreachable;
4153 var extra_index = extra_start + bit_bags_count;
4154 var bit_bag_index: usize = extra_start;
4155 var cur_bit_bag: u32 = undefined;
4156 var decl_i: u32 = 0;
41574139 var scan_decl_iter: ScanDeclIter = .{
4158 .module = mod,
4140 .zcu = zcu,
41594141 .namespace_index = namespace_index,
41604142 .parent_decl = parent_decl,
41614143 };
4162 while (decl_i < decls_len) : (decl_i += 1) {
4163 if (decl_i % 8 == 0) {
4164 cur_bit_bag = zir.extra[bit_bag_index];
4165 bit_bag_index += 1;
4166 }
4167 const flags = @as(u4, @truncate(cur_bit_bag));
4168 cur_bit_bag >>= 4;
4169
4170 const decl_sub_index = extra_index;
4171 extra_index += 8; // src_hash(4) + line(1) + name(1) + value(1) + doc_comment(1)
4172 extra_index += @as(u1, @truncate(flags >> 2)); // Align
4173 extra_index += @as(u2, @as(u1, @truncate(flags >> 3))) * 2; // Link section or address space, consists of 2 Refs
4174
4175 try scanDecl(&scan_decl_iter, decl_sub_index, flags);
4144 for (decls) |decl_inst| {
4145 try scanDecl(&scan_decl_iter, decl_inst);
41764146 }
4177 return extra_index;
41784147}
41794148
41804149const ScanDeclIter = struct {
4181 module: *Module,
4150 zcu: *Zcu,
41824151 namespace_index: Namespace.Index,
41834152 parent_decl: *Decl,
41844153 usingnamespace_index: usize = 0,
......@@ -4186,119 +4155,112 @@ const ScanDeclIter = struct {
41864155 unnamed_test_index: usize = 0,
41874156};
41884157
4189fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Error!void {
4158fn scanDecl(iter: *ScanDeclIter, decl_inst: Zir.Inst.Index) Allocator.Error!void {
41904159 const tracy = trace(@src());
41914160 defer tracy.end();
41924161
4193 const mod = iter.module;
4162 const zcu = iter.zcu;
41944163 const namespace_index = iter.namespace_index;
4195 const namespace = mod.namespacePtr(namespace_index);
4196 const gpa = mod.gpa;
4164 const namespace = zcu.namespacePtr(namespace_index);
4165 const gpa = zcu.gpa;
41974166 const zir = namespace.file_scope.zir;
4198 const ip = &mod.intern_pool;
4167 const ip = &zcu.intern_pool;
4168
4169 const pl_node = zir.instructions.items(.data)[@intFromEnum(decl_inst)].pl_node;
4170 const extra = zir.extraData(Zir.Inst.Declaration, pl_node.payload_index);
4171 const declaration = extra.data;
41994172
4200 // zig fmt: off
4201 const is_pub = (flags & 0b0001) != 0;
4202 const export_bit = (flags & 0b0010) != 0;
4203 const has_align = (flags & 0b0100) != 0;
4204 const has_linksection_or_addrspace = (flags & 0b1000) != 0;
4205 // zig fmt: on
4206
4207 const line_off = zir.extra[decl_sub_index + 4];
4208 const line = iter.parent_decl.relativeToLine(line_off);
4209 const decl_name_index: Zir.NullTerminatedString = @enumFromInt(zir.extra[decl_sub_index + 5]);
4210 const decl_doccomment_index = zir.extra[decl_sub_index + 7];
4211 const decl_zir_index = zir.extra[decl_sub_index + 6];
4212 const decl_block_inst_data = zir.instructions.items(.data)[decl_zir_index].pl_node;
4213 const decl_node = iter.parent_decl.relativeToNodeIndex(decl_block_inst_data.src_node);
4173 const line = iter.parent_decl.src_line + declaration.line_offset;
4174 const decl_node = iter.parent_decl.relativeToNodeIndex(pl_node.src_node);
42144175
42154176 // Every Decl needs a name.
4216 var is_named_test = false;
4217 var kind: Decl.Kind = .named;
4218 const decl_name: InternPool.NullTerminatedString = switch (decl_name_index) {
4219 .empty => name: {
4220 if (export_bit) {
4221 const i = iter.usingnamespace_index;
4222 iter.usingnamespace_index += 1;
4223 kind = .@"usingnamespace";
4224 break :name try ip.getOrPutStringFmt(gpa, "usingnamespace_{d}", .{i});
4225 } else {
4226 const i = iter.comptime_index;
4227 iter.comptime_index += 1;
4228 kind = .@"comptime";
4229 break :name try ip.getOrPutStringFmt(gpa, "comptime_{d}", .{i});
4230 }
4177 const decl_name: InternPool.NullTerminatedString, const kind: Decl.Kind, const is_named_test: bool = switch (declaration.name) {
4178 .@"comptime" => info: {
4179 const i = iter.comptime_index;
4180 iter.comptime_index += 1;
4181 break :info .{
4182 try ip.getOrPutStringFmt(gpa, "comptime_{d}", .{i}),
4183 .@"comptime",
4184 false,
4185 };
4186 },
4187 .@"usingnamespace" => info: {
4188 const i = iter.usingnamespace_index;
4189 iter.usingnamespace_index += 1;
4190 break :info .{
4191 try ip.getOrPutStringFmt(gpa, "usingnamespace_{d}", .{i}),
4192 .@"usingnamespace",
4193 false,
4194 };
42314195 },
4232 .unnamed_test_decl => name: {
4196 .unnamed_test => info: {
42334197 const i = iter.unnamed_test_index;
42344198 iter.unnamed_test_index += 1;
4235 kind = .@"test";
4236 break :name try ip.getOrPutStringFmt(gpa, "test_{d}", .{i});
4199 break :info .{
4200 try ip.getOrPutStringFmt(gpa, "test_{d}", .{i}),
4201 .@"test",
4202 false,
4203 };
42374204 },
4238 .decltest => name: {
4239 is_named_test = true;
4240 const test_name = zir.nullTerminatedString(@enumFromInt(decl_doccomment_index));
4241 kind = .@"test";
4242 break :name try ip.getOrPutStringFmt(gpa, "decltest.{s}", .{test_name});
4205 .decltest => info: {
4206 assert(declaration.flags.has_doc_comment);
4207 const name = zir.nullTerminatedString(@enumFromInt(zir.extra[extra.end]));
4208 break :info .{
4209 try ip.getOrPutStringFmt(gpa, "decltest.{s}", .{name}),
4210 .@"test",
4211 true,
4212 };
42434213 },
4244 _ => name: {
4245 const raw_name = zir.nullTerminatedString(decl_name_index);
4246 if (raw_name.len == 0) {
4247 is_named_test = true;
4248 const test_name = zir.nullTerminatedString(@enumFromInt(@intFromEnum(decl_name_index) + 1));
4249 kind = .@"test";
4250 break :name try ip.getOrPutStringFmt(gpa, "test.{s}", .{test_name});
4251 } else {
4252 break :name try ip.getOrPutString(gpa, raw_name);
4253 }
4214 _ => if (declaration.name.isNamedTest(zir)) .{
4215 try ip.getOrPutStringFmt(gpa, "test.{s}", .{zir.nullTerminatedString(declaration.name.toString(zir).?)}),
4216 .@"test",
4217 true,
4218 } else .{
4219 try ip.getOrPutString(gpa, zir.nullTerminatedString(declaration.name.toString(zir).?)),
4220 .named,
4221 false,
42544222 },
42554223 };
42564224
4257 const is_exported = export_bit and decl_name_index != .empty;
42584225 if (kind == .@"usingnamespace") try namespace.usingnamespace_set.ensureUnusedCapacity(gpa, 1);
42594226
42604227 // We create a Decl for it regardless of analysis status.
42614228 const gop = try namespace.decls.getOrPutContextAdapted(
42624229 gpa,
42634230 decl_name,
4264 DeclAdapter{ .mod = mod },
4265 Namespace.DeclContext{ .module = mod },
4231 DeclAdapter{ .mod = zcu },
4232 Namespace.DeclContext{ .module = zcu },
42664233 );
4267 const comp = mod.comp;
4234 const comp = zcu.comp;
42684235 if (!gop.found_existing) {
4269 const new_decl_index = try mod.allocateNewDecl(namespace_index, decl_node, iter.parent_decl.src_scope);
4270 const new_decl = mod.declPtr(new_decl_index);
4236 const new_decl_index = try zcu.allocateNewDecl(namespace_index, decl_node, iter.parent_decl.src_scope);
4237 const new_decl = zcu.declPtr(new_decl_index);
42714238 new_decl.kind = kind;
42724239 new_decl.name = decl_name;
42734240 if (kind == .@"usingnamespace") {
4274 namespace.usingnamespace_set.putAssumeCapacity(new_decl_index, is_pub);
4241 namespace.usingnamespace_set.putAssumeCapacity(new_decl_index, declaration.flags.is_pub);
42754242 }
42764243 new_decl.src_line = line;
42774244 gop.key_ptr.* = new_decl_index;
42784245 // Exported decls, comptime decls, usingnamespace decls, and
42794246 // test decls if in test mode, get analyzed.
42804247 const decl_mod = namespace.file_scope.mod;
4281 const want_analysis = is_exported or switch (decl_name_index) {
4282 .empty => true, // comptime or usingnamespace decl
4283 .unnamed_test_decl => blk: {
4284 // test decl with no name. Skip the part where we check against
4285 // the test name filter.
4286 if (!comp.config.is_test) break :blk false;
4287 if (decl_mod != mod.main_mod) break :blk false;
4288 try mod.test_functions.put(gpa, new_decl_index, {});
4289 break :blk true;
4290 },
4291 else => blk: {
4292 if (!is_named_test) break :blk false;
4293 if (!comp.config.is_test) break :blk false;
4294 if (decl_mod != mod.main_mod) break :blk false;
4295 if (comp.test_filter) |test_filter| {
4296 if (mem.indexOf(u8, ip.stringToSlice(decl_name), test_filter) == null) {
4297 break :blk false;
4248 const want_analysis = declaration.flags.is_export or switch (kind) {
4249 .anon => unreachable,
4250 .@"comptime", .@"usingnamespace" => true,
4251 .named => false,
4252 .@"test" => a: {
4253 if (!comp.config.is_test) break :a false;
4254 if (decl_mod != zcu.main_mod) break :a false;
4255 if (is_named_test) {
4256 if (comp.test_filter) |test_filter| {
4257 if (mem.indexOf(u8, ip.stringToSlice(decl_name), test_filter) == null) {
4258 break :a false;
4259 }
42984260 }
42994261 }
4300 try mod.test_functions.put(gpa, new_decl_index, {});
4301 break :blk true;
4262 try zcu.test_functions.put(gpa, new_decl_index, {});
4263 break :a true;
43024264 },
43034265 };
43044266 if (want_analysis) {
......@@ -4307,46 +4269,42 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err
43074269 });
43084270 comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl_index });
43094271 }
4310 new_decl.is_pub = is_pub;
4311 new_decl.is_exported = is_exported;
4312 new_decl.has_align = has_align;
4313 new_decl.has_linksection_or_addrspace = has_linksection_or_addrspace;
4314 new_decl.zir_decl_index = @enumFromInt(decl_sub_index);
4272 new_decl.is_pub = declaration.flags.is_pub;
4273 new_decl.is_exported = declaration.flags.is_export;
4274 new_decl.zir_decl_index = decl_inst.toOptional();
43154275 new_decl.alive = true; // This Decl corresponds to an AST node and therefore always alive.
43164276 return;
43174277 }
43184278 const decl_index = gop.key_ptr.*;
4319 const decl = mod.declPtr(decl_index);
4279 const decl = zcu.declPtr(decl_index);
43204280 if (kind == .@"test") {
43214281 const src_loc = SrcLoc{
4322 .file_scope = decl.getFileScope(mod),
4282 .file_scope = decl.getFileScope(zcu),
43234283 .parent_decl_node = decl.src_node,
43244284 .lazy = .{ .token_offset = 1 },
43254285 };
43264286 const msg = try ErrorMsg.create(gpa, src_loc, "duplicate test name: {}", .{
4327 decl_name.fmt(&mod.intern_pool),
4287 decl_name.fmt(ip),
43284288 });
43294289 errdefer msg.destroy(gpa);
4330 try mod.failed_decls.putNoClobber(gpa, decl_index, msg);
4290 try zcu.failed_decls.putNoClobber(gpa, decl_index, msg);
43314291 const other_src_loc = SrcLoc{
43324292 .file_scope = namespace.file_scope,
43334293 .parent_decl_node = decl_node,
43344294 .lazy = .{ .token_offset = 1 },
43354295 };
4336 try mod.errNoteNonLazy(other_src_loc, msg, "other test here", .{});
4296 try zcu.errNoteNonLazy(other_src_loc, msg, "other test here", .{});
43374297 }
43384298 // Update the AST node of the decl; even if its contents are unchanged, it may
43394299 // have been re-ordered.
43404300 decl.src_node = decl_node;
43414301 decl.src_line = line;
43424302
4343 decl.is_pub = is_pub;
4344 decl.is_exported = is_exported;
4303 decl.is_pub = declaration.flags.is_pub;
4304 decl.is_exported = declaration.flags.is_export;
43454305 decl.kind = kind;
4346 decl.has_align = has_align;
4347 decl.has_linksection_or_addrspace = has_linksection_or_addrspace;
4348 decl.zir_decl_index = @enumFromInt(decl_sub_index);
4349 if (decl.getOwnedFunction(mod) != null) {
4306 decl.zir_decl_index = decl_inst.toOptional();
4307 if (decl.getOwnedFunction(zcu) != null) {
43504308 // TODO Look into detecting when this would be unnecessary by storing enough state
43514309 // in `Decl` to notice that the line number did not change.
43524310 comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl_index });
......@@ -4730,8 +4688,6 @@ pub fn allocateNewDecl(
47304688 .generation = 0,
47314689 .is_pub = false,
47324690 .is_exported = false,
4733 .has_linksection_or_addrspace = false,
4734 .has_align = false,
47354691 .alive = false,
47364692 .kind = .anon,
47374693 });
src/Sema.zig+20-12
......@@ -1224,6 +1224,10 @@ fn analyzeBodyInner(
12241224 .trap => break sema.zirTrap(block, inst),
12251225 // zig fmt: on
12261226
1227 // This instruction never exists in an analyzed body. It exists only in the declaration
1228 // list for a container type.
1229 .declaration => unreachable,
1230
12271231 .extended => ext: {
12281232 const extended = datas[@intFromEnum(inst)].extended;
12291233 break :ext switch (extended.opcode) {
......@@ -2736,7 +2740,9 @@ pub fn getStructType(
27362740 }
27372741 }
27382742
2739 extra_index = try mod.scanNamespace(namespace, extra_index, decls_len, mod.declPtr(decl));
2743 const decls = sema.code.bodySlice(extra_index, decls_len);
2744 try mod.scanNamespace(namespace, decls, mod.declPtr(decl));
2745 extra_index += decls_len;
27402746
27412747 const ty = try ip.getStructType(gpa, .{
27422748 .decl = decl,
......@@ -2973,7 +2979,9 @@ fn zirEnumDecl(
29732979 const new_namespace = mod.namespacePtr(new_namespace_index);
29742980 errdefer if (!done) mod.destroyNamespace(new_namespace_index);
29752981
2976 extra_index = try mod.scanNamespace(new_namespace_index, extra_index, decls_len, new_decl);
2982 const decls = sema.code.bodySlice(extra_index, decls_len);
2983 try mod.scanNamespace(new_namespace_index, decls, new_decl);
2984 extra_index += decls_len;
29772985
29782986 const body = sema.code.bodySlice(extra_index, body_len);
29792987 extra_index += body.len;
......@@ -3263,7 +3271,8 @@ fn zirUnionDecl(
32633271 new_decl.val = Value.fromInterned(union_ty);
32643272 new_namespace.ty = Type.fromInterned(union_ty);
32653273
3266 _ = try mod.scanNamespace(new_namespace_index, extra_index, decls_len, new_decl);
3274 const decls = sema.code.bodySlice(extra_index, decls_len);
3275 try mod.scanNamespace(new_namespace_index, decls, new_decl);
32673276
32683277 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
32693278 try mod.finalizeAnonDecl(new_decl_index);
......@@ -3326,7 +3335,8 @@ fn zirOpaqueDecl(
33263335 new_decl.val = Value.fromInterned(opaque_ty);
33273336 new_namespace.ty = Type.fromInterned(opaque_ty);
33283337
3329 extra_index = try mod.scanNamespace(new_namespace_index, extra_index, decls_len, new_decl);
3338 const decls = sema.code.bodySlice(extra_index, decls_len);
3339 try mod.scanNamespace(new_namespace_index, decls, new_decl);
33303340
33313341 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
33323342 try mod.finalizeAnonDecl(new_decl_index);
......@@ -36331,9 +36341,7 @@ fn structZirInfo(zir: Zir, zir_index: Zir.Inst.Index) struct {
3633136341 }
3633236342
3633336343 // Skip over decls.
36334 var decls_it = zir.declIteratorInner(extra_index, decls_len);
36335 while (decls_it.next()) |_| {}
36336 extra_index = decls_it.extra_index;
36344 extra_index += decls_len;
3633736345
3633836346 return .{ fields_len, small, extra_index };
3633936347}
......@@ -36802,9 +36810,7 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un
3680236810 } else 0;
3680336811
3680436812 // Skip over decls.
36805 var decls_it = zir.declIteratorInner(extra_index, decls_len);
36806 while (decls_it.next()) |_| {}
36807 extra_index = decls_it.extra_index;
36813 extra_index += decls_len;
3680836814
3680936815 const body = zir.bodySlice(extra_index, body_len);
3681036816 extra_index += body.len;
......@@ -37801,10 +37807,12 @@ pub fn analyzeAddressSpace(
3780137807 ctx: AddressSpaceContext,
3780237808) !std.builtin.AddressSpace {
3780337809 const mod = sema.mod;
37804 const addrspace_tv = try sema.resolveInstConst(block, src, zir_ref, .{
37810 const air_ref = try sema.resolveInst(zir_ref);
37811 const coerced = try sema.coerce(block, Type.fromInterned(.address_space_type), air_ref, src);
37812 const addrspace_val = try sema.resolveConstDefinedValue(block, src, coerced, .{
3780537813 .needed_comptime_reason = "address space must be comptime-known",
3780637814 });
37807 const address_space = mod.toEnum(std.builtin.AddressSpace, addrspace_tv.val);
37815 const address_space = mod.toEnum(std.builtin.AddressSpace, addrspace_val);
3780837816 const target = sema.mod.getTarget();
3780937817 const arch = target.cpu.arch;
3781037818
src/Zir.zig+213-187
......@@ -30,7 +30,7 @@ instructions: std.MultiArrayList(Inst).Slice,
3030/// is referencing the data here whether they want to store both index and length,
3131/// thus allowing null bytes, or store only index, and use null-termination. The
3232/// `string_bytes` array is agnostic to either usage.
33/// Indexes 0 and 1 are reserved for special cases.
33/// Index 0 is reserved for special cases.
3434string_bytes: []u8,
3535/// The meaning of this data is determined by `Inst.Tag` value.
3636/// The first few indexes are reserved. See `ExtraIndex` for the values.
......@@ -60,21 +60,6 @@ pub const ExtraIndex = enum(u32) {
6060 imports,
6161
6262 _,
63
64 pub fn toOptional(i: ExtraIndex) OptionalExtraIndex {
65 return @enumFromInt(@intFromEnum(i));
66 }
67};
68
69pub const OptionalExtraIndex = enum(u32) {
70 compile_errors,
71 imports,
72 none = std.math.maxInt(u32),
73 _,
74
75 pub fn unwrap(oi: OptionalExtraIndex) ?ExtraIndex {
76 return if (oi == .none) null else @enumFromInt(@intFromEnum(oi));
77 }
7863};
7964
8065fn ExtraData(comptime T: type) type {
......@@ -93,6 +78,7 @@ pub fn extraData(code: Zir, comptime T: type, index: usize) ExtraData(T) {
9378
9479 Inst.Ref,
9580 Inst.Index,
81 Inst.Declaration.Name,
9682 NullTerminatedString,
9783 => @enumFromInt(code.extra[i]),
9884
......@@ -102,6 +88,7 @@ pub fn extraData(code: Zir, comptime T: type, index: usize) ExtraData(T) {
10288 Inst.SwitchBlock.Bits,
10389 Inst.SwitchBlockErrUnion.Bits,
10490 Inst.FuncFancy.Bits,
91 Inst.Declaration.Flags,
10592 => @bitCast(code.extra[i]),
10693
10794 else => @compileError("bad field type"),
......@@ -116,8 +103,6 @@ pub fn extraData(code: Zir, comptime T: type, index: usize) ExtraData(T) {
116103
117104pub const NullTerminatedString = enum(u32) {
118105 empty = 0,
119 unnamed_test_decl = 1,
120 decltest = 2,
121106 _,
122107};
123108
......@@ -304,6 +289,12 @@ pub const Inst = struct {
304289 /// a noreturn instruction.
305290 /// Uses the `pl_node` union field. Payload is `Block`.
306291 block_inline,
292 /// This instruction may only ever appear in the list of declarations for a
293 /// namespace type, e.g. within a `struct_decl` instruction. It represents a
294 /// single source declaration (`const`/`var`/`fn`), containing the name,
295 /// attributes, type, and value of the declaration.
296 /// Uses the `pl_node` union field. Payload is `Declaration`.
297 declaration,
307298 /// Implements `suspend {...}`.
308299 /// Uses the `pl_node` union field. Payload is `Block`.
309300 suspend_block,
......@@ -1092,6 +1083,7 @@ pub const Inst = struct {
10921083 .block,
10931084 .block_comptime,
10941085 .block_inline,
1086 .declaration,
10951087 .suspend_block,
10961088 .loop,
10971089 .bool_br_and,
......@@ -1405,6 +1397,7 @@ pub const Inst = struct {
14051397 .block,
14061398 .block_comptime,
14071399 .block_inline,
1400 .declaration,
14081401 .suspend_block,
14091402 .loop,
14101403 .bool_br_and,
......@@ -1639,6 +1632,7 @@ pub const Inst = struct {
16391632 .block = .pl_node,
16401633 .block_comptime = .pl_node,
16411634 .block_inline = .pl_node,
1635 .declaration = .pl_node,
16421636 .suspend_block = .pl_node,
16431637 .bool_not = .un_node,
16441638 .bool_br_and = .bool_br,
......@@ -2508,6 +2502,7 @@ pub const Inst = struct {
25082502 /// If this is 1 it means return_type is a simple Ref
25092503 ret_body_len: u32,
25102504 /// Points to the block that contains the param instructions for this function.
2505 /// If this is a `declaration`, it refers to the declaration's value body.
25112506 param_block: Index,
25122507 body_len: u32,
25132508
......@@ -2565,6 +2560,7 @@ pub const Inst = struct {
25652560 /// 18. src_locs: Func.SrcLocs // if body_len != 0
25662561 pub const FuncFancy = struct {
25672562 /// Points to the block that contains the param instructions for this function.
2563 /// If this is a `declaration`, it refers to the declaration's value body.
25682564 param_block: Index,
25692565 body_len: u32,
25702566 bits: Bits,
......@@ -2632,6 +2628,116 @@ pub const Inst = struct {
26322628 body_len: u32,
26332629 };
26342630
2631 /// Trailing:
2632 /// 0. doc_comment: u32 // if `has_doc_comment`; null-terminated string index
2633 /// 1. align_body_len: u32 // if `has_align_linksection_addrspace`; 0 means no `align`
2634 /// 2. linksection_body_len: u32 // if `has_align_linksection_addrspace`; 0 means no `linksection`
2635 /// 3. addrspace_body_len: u32 // if `has_align_linksection_addrspace`; 0 means no `addrspace`
2636 /// 4. value_body_inst: Zir.Inst.Index
2637 /// - for each `value_body_len`
2638 /// - body to be exited via `break_inline` to this `declaration` instruction
2639 /// 5. align_body_inst: Zir.Inst.Index
2640 /// - for each `align_body_len`
2641 /// - body to be exited via `break_inline` to this `declaration` instruction
2642 /// 6. linksection_body_inst: Zir.Inst.Index
2643 /// - for each `linksection_body_len`
2644 /// - body to be exited via `break_inline` to this `declaration` instruction
2645 /// 7. addrspace_body_inst: Zir.Inst.Index
2646 /// - for each `addrspace_body_len`
2647 /// - body to be exited via `break_inline` to this `declaration` instruction
2648 pub const Declaration = struct {
2649 // These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`.
2650 src_hash_0: u32,
2651 src_hash_1: u32,
2652 src_hash_2: u32,
2653 src_hash_3: u32,
2654 /// The name of this `Decl`. Also indicates whether it is a test, comptime block, etc.
2655 name: Name,
2656 /// This Decl's line number relative to that of its parent.
2657 /// TODO: column must be encoded similarly to respect non-formatted code!
2658 line_offset: u32,
2659 flags: Flags,
2660
2661 pub const Flags = packed struct(u32) {
2662 value_body_len: u28,
2663 is_pub: bool,
2664 is_export: bool,
2665 has_doc_comment: bool,
2666 has_align_linksection_addrspace: bool,
2667 };
2668
2669 pub const Name = enum(u32) {
2670 @"comptime" = std.math.maxInt(u32),
2671 @"usingnamespace" = std.math.maxInt(u32) - 1,
2672 unnamed_test = std.math.maxInt(u32) - 2,
2673 /// In this case, `has_doc_comment` will be true, and the doc
2674 /// comment body is the identifier name.
2675 decltest = std.math.maxInt(u32) - 3,
2676 /// Other values are `NullTerminatedString` values, i.e. index into
2677 /// `string_bytes`. If the byte referenced is 0, the decl is a named
2678 /// test, and the actual name begins at the following byte.
2679 _,
2680
2681 pub fn isNamedTest(name: Name, zir: Zir) bool {
2682 return switch (name) {
2683 .@"comptime", .@"usingnamespace", .unnamed_test, .decltest => false,
2684 _ => zir.string_bytes[@intFromEnum(name)] == 0,
2685 };
2686 }
2687 pub fn toString(name: Name, zir: Zir) ?NullTerminatedString {
2688 switch (name) {
2689 .@"comptime", .@"usingnamespace", .unnamed_test, .decltest => return null,
2690 _ => {},
2691 }
2692 const idx: u32 = @intFromEnum(name);
2693 if (zir.string_bytes[idx] == 0) {
2694 // Named test
2695 return @enumFromInt(idx + 1);
2696 }
2697 return @enumFromInt(idx);
2698 }
2699 };
2700
2701 pub const Bodies = struct {
2702 value_body: []const Index,
2703 align_body: ?[]const Index,
2704 linksection_body: ?[]const Index,
2705 addrspace_body: ?[]const Index,
2706 };
2707
2708 pub fn getBodies(declaration: Declaration, extra_end: u32, zir: Zir) Bodies {
2709 var extra_index: u32 = extra_end;
2710 extra_index += @intFromBool(declaration.flags.has_doc_comment);
2711 const value_body_len = declaration.flags.value_body_len;
2712 const align_body_len, const linksection_body_len, const addrspace_body_len = lens: {
2713 if (!declaration.flags.has_align_linksection_addrspace) {
2714 break :lens .{ 0, 0, 0 };
2715 }
2716 const lens = zir.extra[extra_index..][0..3].*;
2717 extra_index += 3;
2718 break :lens lens;
2719 };
2720 return .{
2721 .value_body = b: {
2722 defer extra_index += value_body_len;
2723 break :b zir.bodySlice(extra_index, value_body_len);
2724 },
2725 .align_body = if (align_body_len == 0) null else b: {
2726 defer extra_index += align_body_len;
2727 break :b zir.bodySlice(extra_index, align_body_len);
2728 },
2729 .linksection_body = if (linksection_body_len == 0) null else b: {
2730 defer extra_index += linksection_body_len;
2731 break :b zir.bodySlice(extra_index, linksection_body_len);
2732 },
2733 .addrspace_body = if (addrspace_body_len == 0) null else b: {
2734 defer extra_index += addrspace_body_len;
2735 break :b zir.bodySlice(extra_index, addrspace_body_len);
2736 },
2737 };
2738 }
2739 };
2740
26352741 /// Stored inside extra, with trailing arguments according to `args_len`.
26362742 /// Implicit 0. arg_0_start: u32, // always same as `args_len`
26372743 /// 1. arg_end: u32, // for each `args_len`
......@@ -2913,37 +3019,14 @@ pub const Inst = struct {
29133019 /// 3. backing_int_body_len: u32, // if has_backing_int
29143020 /// 4. backing_int_ref: Ref, // if has_backing_int and backing_int_body_len is 0
29153021 /// 5. backing_int_body_inst: Inst, // if has_backing_int and backing_int_body_len is > 0
2916 /// 6. decl_bits: u32 // for every 8 decls
2917 /// - sets of 4 bits:
2918 /// 0b000X: whether corresponding decl is pub
2919 /// 0b00X0: whether corresponding decl is exported
2920 /// 0b0X00: whether corresponding decl has an align expression
2921 /// 0bX000: whether corresponding decl has a linksection or an address space expression
2922 /// 7. decl: { // for every decls_len
2923 /// src_hash: [4]u32, // hash of source bytes
2924 /// line: u32, // line number of decl, relative to parent
2925 /// name: NullTerminatedString, // null terminated string index
2926 /// - 0 means comptime or usingnamespace decl.
2927 /// - if name == 0 `is_exported` determines which one: 0=comptime,1=usingnamespace
2928 /// - 1 means test decl with no name.
2929 /// - 2 means that the test is a decltest, doc_comment gives the name of the identifier
2930 /// - if there is a 0 byte at the position `name` indexes, it indicates
2931 /// this is a test decl, and the name starts at `name+1`.
2932 /// value: Index,
2933 /// doc_comment: u32, .empty if no doc comment, if this is a decltest, doc_comment references the decl name in the string table
2934 /// align: Ref, // if corresponding bit is set
2935 /// link_section_or_address_space: { // if corresponding bit is set.
2936 /// link_section: Ref,
2937 /// address_space: Ref,
2938 /// }
2939 /// }
2940 /// 8. flags: u32 // for every 8 fields
3022 /// 6. decl: Index, // for every decls_len; points to a `declaration` instruction
3023 /// 7. flags: u32 // for every 8 fields
29413024 /// - sets of 4 bits:
29423025 /// 0b000X: whether corresponding field has an align expression
29433026 /// 0b00X0: whether corresponding field has a default expression
29443027 /// 0b0X00: whether corresponding field is comptime
29453028 /// 0bX000: whether corresponding field has a type expression
2946 /// 9. fields: { // for every fields_len
3029 /// 8. fields: { // for every fields_len
29473030 /// field_name: u32, // if !is_tuple
29483031 /// doc_comment: NullTerminatedString, // .empty if no doc comment
29493032 /// field_type: Ref, // if corresponding bit is not set. none means anytype.
......@@ -3009,33 +3092,11 @@ pub const Inst = struct {
30093092 /// 2. body_len: u32, // if has_body_len
30103093 /// 3. fields_len: u32, // if has_fields_len
30113094 /// 4. decls_len: u32, // if has_decls_len
3012 /// 5. decl_bits: u32 // for every 8 decls
3013 /// - sets of 4 bits:
3014 /// 0b000X: whether corresponding decl is pub
3015 /// 0b00X0: whether corresponding decl is exported
3016 /// 0b0X00: whether corresponding decl has an align expression
3017 /// 0bX000: whether corresponding decl has a linksection or an address space expression
3018 /// 6. decl: { // for every decls_len
3019 /// src_hash: [4]u32, // hash of source bytes
3020 /// line: u32, // line number of decl, relative to parent
3021 /// name: NullTerminatedString, // null terminated string index
3022 /// - 0 means comptime or usingnamespace decl.
3023 /// - if name == 0 `is_exported` determines which one: 0=comptime,1=usingnamespace
3024 /// - 1 means test decl with no name.
3025 /// - if there is a 0 byte at the position `name` indexes, it indicates
3026 /// this is a test decl, and the name starts at `name+1`.
3027 /// value: Index,
3028 /// doc_comment: u32, // .empty if no doc_comment
3029 /// align: Ref, // if corresponding bit is set
3030 /// link_section_or_address_space: { // if corresponding bit is set.
3031 /// link_section: Ref,
3032 /// address_space: Ref,
3033 /// }
3034 /// }
3035 /// 7. inst: Index // for every body_len
3036 /// 8. has_bits: u32 // for every 32 fields
3095 /// 5. decl: Index, // for every decls_len; points to a `declaration` instruction
3096 /// 6. inst: Index // for every body_len
3097 /// 7. has_bits: u32 // for every 32 fields
30373098 /// - the bit is whether corresponding field has an value expression
3038 /// 9. fields: { // for every fields_len
3099 /// 8. fields: { // for every fields_len
30393100 /// field_name: u32,
30403101 /// doc_comment: u32, // .empty if no doc_comment
30413102 /// value: Ref, // if corresponding bit is set
......@@ -3059,37 +3120,15 @@ pub const Inst = struct {
30593120 /// 2. body_len: u32, // if has_body_len
30603121 /// 3. fields_len: u32, // if has_fields_len
30613122 /// 4. decls_len: u32, // if has_decls_len
3062 /// 5. decl_bits: u32 // for every 8 decls
3063 /// - sets of 4 bits:
3064 /// 0b000X: whether corresponding decl is pub
3065 /// 0b00X0: whether corresponding decl is exported
3066 /// 0b0X00: whether corresponding decl has an align expression
3067 /// 0bX000: whether corresponding decl has a linksection or an address space expression
3068 /// 6. decl: { // for every decls_len
3069 /// src_hash: [4]u32, // hash of source bytes
3070 /// line: u32, // line number of decl, relative to parent
3071 /// name: NullTerminatedString, // null terminated string index
3072 /// - 0 means comptime or usingnamespace decl.
3073 /// - if name == 0 `is_exported` determines which one: 0=comptime,1=usingnamespace
3074 /// - 1 means test decl with no name.
3075 /// - if there is a 0 byte at the position `name` indexes, it indicates
3076 /// this is a test decl, and the name starts at `name+1`.
3077 /// value: Index,
3078 /// doc_comment: NullTerminatedString, // .empty if no doc comment
3079 /// align: Ref, // if corresponding bit is set
3080 /// link_section_or_address_space: { // if corresponding bit is set.
3081 /// link_section: Ref,
3082 /// address_space: Ref,
3083 /// }
3084 /// }
3085 /// 7. inst: Index // for every body_len
3086 /// 8. has_bits: u32 // for every 8 fields
3123 /// 5. decl: Index, // for every decls_len; points to a `declaration` instruction
3124 /// 6. inst: Index // for every body_len
3125 /// 7. has_bits: u32 // for every 8 fields
30873126 /// - sets of 4 bits:
30883127 /// 0b000X: whether corresponding field has a type expression
30893128 /// 0b00X0: whether corresponding field has a align expression
30903129 /// 0b0X00: whether corresponding field has a tag value expression
30913130 /// 0bX000: unused
3092 /// 9. fields: { // for every fields_len
3131 /// 8. fields: { // for every fields_len
30933132 /// field_name: NullTerminatedString, // null terminated string index
30943133 /// doc_comment: NullTerminatedString, // .empty if no doc comment
30953134 /// field_type: Ref, // if corresponding bit is set
......@@ -3121,29 +3160,7 @@ pub const Inst = struct {
31213160 /// Trailing:
31223161 /// 0. src_node: i32, // if has_src_node
31233162 /// 1. decls_len: u32, // if has_decls_len
3124 /// 2. decl_bits: u32 // for every 8 decls
3125 /// - sets of 4 bits:
3126 /// 0b000X: whether corresponding decl is pub
3127 /// 0b00X0: whether corresponding decl is exported
3128 /// 0b0X00: whether corresponding decl has an align expression
3129 /// 0bX000: whether corresponding decl has a linksection or an address space expression
3130 /// 3. decl: { // for every decls_len
3131 /// src_hash: [4]u32, // hash of source bytes
3132 /// line: u32, // line number of decl, relative to parent
3133 /// name: NullTerminatedString, // null terminated string index
3134 /// - 0 means comptime or usingnamespace decl.
3135 /// - if name == 0 `is_exported` determines which one: 0=comptime,1=usingnamespace
3136 /// - 1 means test decl with no name.
3137 /// - if there is a 0 byte at the position `name` indexes, it indicates
3138 /// this is a test decl, and the name starts at `name+1`.
3139 /// value: Index,
3140 /// doc_comment: NullTerminatedString, // .empty if no doc comment,
3141 /// align: Ref, // if corresponding bit is set
3142 /// link_section_or_address_space: { // if corresponding bit is set.
3143 /// link_section: Ref,
3144 /// address_space: Ref,
3145 /// }
3146 /// }
3163 /// 2. decl: Index, // for every decls_len; points to a `declaration` instruction
31473164 pub const OpaqueDecl = struct {
31483165 pub const Small = packed struct {
31493166 has_src_node: bool,
......@@ -3407,44 +3424,17 @@ pub const Inst = struct {
34073424pub const SpecialProng = enum { none, @"else", under };
34083425
34093426pub const DeclIterator = struct {
3410 extra_index: usize,
3411 bit_bag_index: usize,
3412 cur_bit_bag: u32,
3413 decl_i: u32,
3414 decls_len: u32,
3427 extra_index: u32,
3428 decls_remaining: u32,
34153429 zir: Zir,
34163430
3417 pub const Item = struct {
3418 name: [:0]const u8,
3419 sub_index: ExtraIndex,
3420 flags: u4,
3421 };
3422
3423 pub fn next(it: *DeclIterator) ?Item {
3424 if (it.decl_i >= it.decls_len) return null;
3425
3426 if (it.decl_i % 8 == 0) {
3427 it.cur_bit_bag = it.zir.extra[it.bit_bag_index];
3428 it.bit_bag_index += 1;
3429 }
3430 it.decl_i += 1;
3431
3432 const flags: u4 = @truncate(it.cur_bit_bag);
3433 it.cur_bit_bag >>= 4;
3434
3435 const sub_index: ExtraIndex = @enumFromInt(it.extra_index);
3436 it.extra_index += 5; // src_hash(4) + line(1)
3437 const name = it.zir.nullTerminatedString(@enumFromInt(it.zir.extra[it.extra_index]));
3438 it.extra_index += 3; // name(1) + value(1) + doc_comment(1)
3439 it.extra_index += @as(u1, @truncate(flags >> 2)); // align
3440 it.extra_index += @as(u1, @truncate(flags >> 3)); // link_section
3441 it.extra_index += @as(u1, @truncate(flags >> 3)); // address_space
3442
3443 return Item{
3444 .sub_index = sub_index,
3445 .name = name,
3446 .flags = flags,
3447 };
3431 pub fn next(it: *DeclIterator) ?Inst.Index {
3432 if (it.decls_remaining == 0) return null;
3433 const decl_inst: Zir.Inst.Index = @enumFromInt(it.zir.extra[it.extra_index]);
3434 it.extra_index += 1;
3435 it.decls_remaining -= 1;
3436 assert(it.zir.instructions.items(.tag)[@intFromEnum(decl_inst)] == .declaration);
3437 return decl_inst;
34483438 }
34493439};
34503440
......@@ -3454,14 +3444,18 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
34543444 switch (tags[@intFromEnum(decl_inst)]) {
34553445 // Functions are allowed and yield no iterations.
34563446 // There is one case matching this in the extended instruction set below.
3457 .func, .func_inferred, .func_fancy => return declIteratorInner(zir, 0, 0),
3447 .func, .func_inferred, .func_fancy => return .{
3448 .extra_index = undefined,
3449 .decls_remaining = 0,
3450 .zir = zir,
3451 },
34583452
34593453 .extended => {
34603454 const extended = datas[@intFromEnum(decl_inst)].extended;
34613455 switch (extended.opcode) {
34623456 .struct_decl => {
34633457 const small: Inst.StructDecl.Small = @bitCast(extended.small);
3464 var extra_index: usize = extended.operand;
3458 var extra_index: u32 = extended.operand;
34653459 extra_index += @intFromBool(small.has_src_node);
34663460 extra_index += @intFromBool(small.has_fields_len);
34673461 const decls_len = if (small.has_decls_len) decls_len: {
......@@ -3480,11 +3474,15 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
34803474 }
34813475 }
34823476
3483 return declIteratorInner(zir, extra_index, decls_len);
3477 return .{
3478 .extra_index = extra_index,
3479 .decls_remaining = decls_len,
3480 .zir = zir,
3481 };
34843482 },
34853483 .enum_decl => {
34863484 const small: Inst.EnumDecl.Small = @bitCast(extended.small);
3487 var extra_index: usize = extended.operand;
3485 var extra_index: u32 = extended.operand;
34883486 extra_index += @intFromBool(small.has_src_node);
34893487 extra_index += @intFromBool(small.has_tag_type);
34903488 extra_index += @intFromBool(small.has_body_len);
......@@ -3495,11 +3493,15 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
34953493 break :decls_len decls_len;
34963494 } else 0;
34973495
3498 return declIteratorInner(zir, extra_index, decls_len);
3496 return .{
3497 .extra_index = extra_index,
3498 .decls_remaining = decls_len,
3499 .zir = zir,
3500 };
34993501 },
35003502 .union_decl => {
35013503 const small: Inst.UnionDecl.Small = @bitCast(extended.small);
3502 var extra_index: usize = extended.operand;
3504 var extra_index: u32 = extended.operand;
35033505 extra_index += @intFromBool(small.has_src_node);
35043506 extra_index += @intFromBool(small.has_tag_type);
35053507 extra_index += @intFromBool(small.has_body_len);
......@@ -3510,11 +3512,15 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
35103512 break :decls_len decls_len;
35113513 } else 0;
35123514
3513 return declIteratorInner(zir, extra_index, decls_len);
3515 return .{
3516 .extra_index = extra_index,
3517 .decls_remaining = decls_len,
3518 .zir = zir,
3519 };
35143520 },
35153521 .opaque_decl => {
35163522 const small: Inst.OpaqueDecl.Small = @bitCast(extended.small);
3517 var extra_index: usize = extended.operand;
3523 var extra_index: u32 = extended.operand;
35183524 extra_index += @intFromBool(small.has_src_node);
35193525 const decls_len = if (small.has_decls_len) decls_len: {
35203526 const decls_len = zir.extra[extra_index];
......@@ -3522,7 +3528,11 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
35223528 break :decls_len decls_len;
35233529 } else 0;
35243530
3525 return declIteratorInner(zir, extra_index, decls_len);
3531 return .{
3532 .extra_index = extra_index,
3533 .decls_remaining = decls_len,
3534 .zir = zir,
3535 };
35263536 },
35273537 else => unreachable,
35283538 }
......@@ -3531,25 +3541,17 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
35313541 }
35323542}
35333543
3534pub fn declIteratorInner(zir: Zir, extra_index: usize, decls_len: u32) DeclIterator {
3535 const bit_bags_count = std.math.divCeil(usize, decls_len, 8) catch unreachable;
3536 return .{
3537 .zir = zir,
3538 .extra_index = extra_index + bit_bags_count,
3539 .bit_bag_index = extra_index,
3540 .cur_bit_bag = undefined,
3541 .decl_i = 0,
3542 .decls_len = decls_len,
3543 };
3544}
3545
35463544/// The iterator would have to allocate memory anyway to iterate. So here we populate
35473545/// an ArrayList as the result.
3548pub fn findDecls(zir: Zir, list: *std.ArrayList(Inst.Index), decl_sub_index: ExtraIndex) !void {
3549 const block_inst: Zir.Inst.Index = @enumFromInt(zir.extra[@intFromEnum(decl_sub_index) + 6]);
3546pub fn findDecls(zir: Zir, list: *std.ArrayList(Inst.Index), decl_inst: Zir.Inst.Index) !void {
35503547 list.clearRetainingCapacity();
3548 const declaration, const extra_end = zir.getDeclaration(decl_inst);
3549 const bodies = declaration.getBodies(extra_end, zir);
35513550
3552 return zir.findDeclsInner(list, block_inst);
3551 try zir.findDeclsBody(list, bodies.value_body);
3552 if (bodies.align_body) |b| try zir.findDeclsBody(list, b);
3553 if (bodies.linksection_body) |b| try zir.findDeclsBody(list, b);
3554 if (bodies.addrspace_body) |b| try zir.findDeclsBody(list, b);
35533555}
35543556
35553557fn findDeclsInner(
......@@ -3791,8 +3793,17 @@ pub fn getParamBody(zir: Zir, fn_inst: Inst.Index) []const Zir.Inst.Index {
37913793 else => unreachable,
37923794 };
37933795
3794 const param_block = zir.extraData(Inst.Block, datas[@intFromEnum(param_block_index)].pl_node.payload_index);
3795 return zir.bodySlice(param_block.end, param_block.data.body_len);
3796 switch (tags[@intFromEnum(param_block_index)]) {
3797 .block, .block_comptime, .block_inline => {
3798 const param_block = zir.extraData(Inst.Block, datas[@intFromEnum(param_block_index)].pl_node.payload_index);
3799 return zir.bodySlice(param_block.end, param_block.data.body_len);
3800 },
3801 .declaration => {
3802 const decl, const extra_end = zir.getDeclaration(param_block_index);
3803 return decl.getBodies(extra_end, zir).value_body;
3804 },
3805 else => unreachable,
3806 }
37963807}
37973808
37983809pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
......@@ -3888,12 +3899,17 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
38883899 },
38893900 else => unreachable,
38903901 };
3891 switch (tags[@intFromEnum(info.param_block)]) {
3892 .block, .block_comptime, .block_inline => {}, // OK
3893 else => unreachable, // assertion failure
3894 }
3895 const param_block = zir.extraData(Inst.Block, datas[@intFromEnum(info.param_block)].pl_node.payload_index);
3896 const param_body = zir.bodySlice(param_block.end, param_block.data.body_len);
3902 const param_body = switch (tags[@intFromEnum(info.param_block)]) {
3903 .block, .block_comptime, .block_inline => param_body: {
3904 const param_block = zir.extraData(Inst.Block, datas[@intFromEnum(info.param_block)].pl_node.payload_index);
3905 break :param_body zir.bodySlice(param_block.end, param_block.data.body_len);
3906 },
3907 .declaration => param_body: {
3908 const decl, const extra_end = zir.getDeclaration(info.param_block);
3909 break :param_body decl.getBodies(extra_end, zir).value_body;
3910 },
3911 else => unreachable,
3912 };
38973913 var total_params_len: u32 = 0;
38983914 for (param_body) |inst| {
38993915 switch (tags[@intFromEnum(inst)]) {
......@@ -3912,3 +3928,13 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
39123928 .total_params_len = total_params_len,
39133929 };
39143930}
3931
3932pub fn getDeclaration(zir: Zir, inst: Zir.Inst.Index) struct { Inst.Declaration, u32 } {
3933 assert(zir.instructions.items(.tag)[@intFromEnum(inst)] == .declaration);
3934 const pl_node = zir.instructions.items(.data)[@intFromEnum(inst)].pl_node;
3935 const extra = zir.extraData(Inst.Declaration, pl_node.payload_index);
3936 return .{
3937 extra.data,
3938 @intCast(extra.end),
3939 };
3940}
src/main.zig+3-14
......@@ -6856,10 +6856,7 @@ pub fn cmdChangelist(
68566856 var inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{};
68576857 defer inst_map.deinit(gpa);
68586858
6859 var extra_map: std.AutoHashMapUnmanaged(Zir.ExtraIndex, Zir.ExtraIndex) = .{};
6860 defer extra_map.deinit(gpa);
6861
6862 try Module.mapOldZirToNew(gpa, old_zir, file.zir, &inst_map, &extra_map);
6859 try Module.mapOldZirToNew(gpa, old_zir, file.zir, &inst_map);
68636860
68646861 var bw = io.bufferedWriter(io.getStdOut().writer());
68656862 const stdout = bw.writer();
......@@ -6868,16 +6865,8 @@ pub fn cmdChangelist(
68686865 var it = inst_map.iterator();
68696866 while (it.next()) |entry| {
68706867 try stdout.print(" %{d} => %{d}\n", .{
6871 entry.key_ptr.*, entry.value_ptr.*,
6872 });
6873 }
6874 }
6875 {
6876 try stdout.print("Extra mappings:\n", .{});
6877 var it = extra_map.iterator();
6878 while (it.next()) |entry| {
6879 try stdout.print(" {d} => {d}\n", .{
6880 entry.key_ptr.*, entry.value_ptr.*,
6868 @intFromEnum(entry.key_ptr.*),
6869 @intFromEnum(entry.value_ptr.*),
68816870 });
68826871 }
68836872 }
src/print_zir.zig+67-122
......@@ -521,6 +521,8 @@ const Writer = struct {
521521 .@"defer" => try self.writeDefer(stream, inst),
522522 .defer_err_code => try self.writeDeferErrCode(stream, inst),
523523
524 .declaration => try self.writeDeclaration(stream, inst),
525
524526 .extended => try self.writeExtended(stream, inst),
525527 }
526528 }
......@@ -1454,8 +1456,9 @@ const Writer = struct {
14541456
14551457 try stream.writeAll("{\n");
14561458 self.indent += 2;
1457 extra_index = try self.writeDecls(stream, decls_len, extra_index);
1459 try self.writeBody(stream, self.code.bodySlice(extra_index, decls_len));
14581460 self.indent -= 2;
1461 extra_index += decls_len;
14591462 try stream.writeByteNTimes(' ', self.indent);
14601463 try stream.writeAll("}, ");
14611464 }
......@@ -1634,8 +1637,9 @@ const Writer = struct {
16341637
16351638 try stream.writeAll("{\n");
16361639 self.indent += 2;
1637 extra_index = try self.writeDecls(stream, decls_len, extra_index);
1640 try self.writeBody(stream, self.code.bodySlice(extra_index, decls_len));
16381641 self.indent -= 2;
1642 extra_index += decls_len;
16391643 try stream.writeByteNTimes(' ', self.indent);
16401644 try stream.writeAll("}");
16411645 }
......@@ -1727,124 +1731,6 @@ const Writer = struct {
17271731 try self.writeSrcNode(stream, src_node);
17281732 }
17291733
1730 fn writeDecls(self: *Writer, stream: anytype, decls_len: u32, extra_start: usize) !usize {
1731 const parent_decl_node = self.parent_decl_node;
1732 const bit_bags_count = std.math.divCeil(usize, decls_len, 8) catch unreachable;
1733 var extra_index = extra_start + bit_bags_count;
1734 var bit_bag_index: usize = extra_start;
1735 var cur_bit_bag: u32 = undefined;
1736 var decl_i: u32 = 0;
1737 while (decl_i < decls_len) : (decl_i += 1) {
1738 if (decl_i % 8 == 0) {
1739 cur_bit_bag = self.code.extra[bit_bag_index];
1740 bit_bag_index += 1;
1741 }
1742 const is_pub = @as(u1, @truncate(cur_bit_bag)) != 0;
1743 cur_bit_bag >>= 1;
1744 const is_exported = @as(u1, @truncate(cur_bit_bag)) != 0;
1745 cur_bit_bag >>= 1;
1746 const has_align = @as(u1, @truncate(cur_bit_bag)) != 0;
1747 cur_bit_bag >>= 1;
1748 const has_section_or_addrspace = @as(u1, @truncate(cur_bit_bag)) != 0;
1749 cur_bit_bag >>= 1;
1750
1751 const sub_index = extra_index;
1752
1753 const hash_u32s = self.code.extra[extra_index..][0..4];
1754 extra_index += 4;
1755 const line = self.code.extra[extra_index];
1756 extra_index += 1;
1757 const decl_name_index = self.code.extra[extra_index];
1758 extra_index += 1;
1759 const decl_index: Zir.Inst.Index = @enumFromInt(self.code.extra[extra_index]);
1760 extra_index += 1;
1761 const doc_comment_index: Zir.NullTerminatedString = @enumFromInt(self.code.extra[extra_index]);
1762 extra_index += 1;
1763
1764 const align_inst: Zir.Inst.Ref = if (!has_align) .none else inst: {
1765 const inst = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
1766 extra_index += 1;
1767 break :inst inst;
1768 };
1769 const section_inst: Zir.Inst.Ref = if (!has_section_or_addrspace) .none else inst: {
1770 const inst = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
1771 extra_index += 1;
1772 break :inst inst;
1773 };
1774 const addrspace_inst: Zir.Inst.Ref = if (!has_section_or_addrspace) .none else inst: {
1775 const inst = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
1776 extra_index += 1;
1777 break :inst inst;
1778 };
1779
1780 const pub_str = if (is_pub) "pub " else "";
1781 const hash_bytes: [16]u8 = @bitCast(hash_u32s.*);
1782 if (decl_name_index == 0) {
1783 try stream.writeByteNTimes(' ', self.indent);
1784 const name = if (is_exported) "usingnamespace" else "comptime";
1785 try stream.writeAll(pub_str);
1786 try stream.writeAll(name);
1787 } else if (decl_name_index == 1) {
1788 try stream.writeByteNTimes(' ', self.indent);
1789 try stream.writeAll("test");
1790 } else if (decl_name_index == 2) {
1791 try stream.writeByteNTimes(' ', self.indent);
1792 try stream.print("[{d}] decltest {s}", .{ sub_index, self.code.nullTerminatedString(doc_comment_index) });
1793 } else {
1794 const raw_decl_name = self.code.nullTerminatedString(@enumFromInt(decl_name_index));
1795 const decl_name = if (raw_decl_name.len == 0)
1796 self.code.nullTerminatedString(@enumFromInt(decl_name_index + 1))
1797 else
1798 raw_decl_name;
1799 const test_str = if (raw_decl_name.len == 0) "test \"" else "";
1800 const export_str = if (is_exported) "export " else "";
1801
1802 try self.writeDocComment(stream, doc_comment_index);
1803
1804 try stream.writeByteNTimes(' ', self.indent);
1805 const endquote_if_test: []const u8 = if (raw_decl_name.len == 0) "\"" else "";
1806 try stream.print("[{d}] {s}{s}{s}{}{s}", .{
1807 sub_index, pub_str, test_str, export_str, std.zig.fmtId(decl_name), endquote_if_test,
1808 });
1809 if (align_inst != .none) {
1810 try stream.writeAll(" align(");
1811 try self.writeInstRef(stream, align_inst);
1812 try stream.writeAll(")");
1813 }
1814 if (addrspace_inst != .none) {
1815 try stream.writeAll(" addrspace(");
1816 try self.writeInstRef(stream, addrspace_inst);
1817 try stream.writeAll(")");
1818 }
1819 if (section_inst != .none) {
1820 try stream.writeAll(" linksection(");
1821 try self.writeInstRef(stream, section_inst);
1822 try stream.writeAll(")");
1823 }
1824 }
1825
1826 if (self.recurse_decls) {
1827 const tag = self.code.instructions.items(.tag)[@intFromEnum(decl_index)];
1828 try stream.print(" line({d}) hash({}): %{d} = {s}(", .{
1829 line, std.fmt.fmtSliceHexLower(&hash_bytes), @intFromEnum(decl_index), @tagName(tag),
1830 });
1831
1832 const decl_block_inst_data = self.code.instructions.items(.data)[@intFromEnum(decl_index)].pl_node;
1833 const sub_decl_node_off = decl_block_inst_data.src_node;
1834 self.parent_decl_node = self.relativeToNodeIndex(sub_decl_node_off);
1835 try self.writePlNodeBlockWithoutSrc(stream, decl_index);
1836 self.parent_decl_node = parent_decl_node;
1837 try self.writeSrc(stream, decl_block_inst_data.src());
1838 try stream.writeAll("\n");
1839 } else {
1840 try stream.print(" line({d}) hash({}): %{d} = ...\n", .{
1841 line, std.fmt.fmtSliceHexLower(&hash_bytes), @intFromEnum(decl_index),
1842 });
1843 }
1844 }
1845 return extra_index;
1846 }
1847
18481734 fn writeEnumDecl(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
18491735 const small = @as(Zir.Inst.EnumDecl.Small, @bitCast(extended.small));
18501736 var extra_index: usize = extended.operand;
......@@ -1891,8 +1777,9 @@ const Writer = struct {
18911777
18921778 try stream.writeAll("{\n");
18931779 self.indent += 2;
1894 extra_index = try self.writeDecls(stream, decls_len, extra_index);
1780 try self.writeBody(stream, self.code.bodySlice(extra_index, decls_len));
18951781 self.indent -= 2;
1782 extra_index += decls_len;
18961783 try stream.writeByteNTimes(' ', self.indent);
18971784 try stream.writeAll("}, ");
18981785 }
......@@ -1988,7 +1875,7 @@ const Writer = struct {
19881875
19891876 try stream.writeAll("{\n");
19901877 self.indent += 2;
1991 _ = try self.writeDecls(stream, decls_len, extra_index);
1878 try self.writeBody(stream, self.code.bodySlice(extra_index, decls_len));
19921879 self.indent -= 2;
19931880 try stream.writeByteNTimes(' ', self.indent);
19941881 try stream.writeAll("})");
......@@ -2762,6 +2649,64 @@ const Writer = struct {
27622649 try stream.writeByte(')');
27632650 }
27642651
2652 fn writeDeclaration(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
2653 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
2654 const extra = self.code.extraData(Zir.Inst.Declaration, inst_data.payload_index);
2655 const doc_comment: ?Zir.NullTerminatedString = if (extra.data.flags.has_doc_comment) dc: {
2656 break :dc @enumFromInt(self.code.extra[extra.end]);
2657 } else null;
2658 if (extra.data.flags.is_pub) try stream.writeAll("pub ");
2659 if (extra.data.flags.is_export) try stream.writeAll("export ");
2660 switch (extra.data.name) {
2661 .@"comptime" => try stream.writeAll("comptime"),
2662 .@"usingnamespace" => try stream.writeAll("usingnamespace"),
2663 .unnamed_test => try stream.writeAll("test"),
2664 .decltest => try stream.print("decltest '{s}'", .{self.code.nullTerminatedString(doc_comment.?)}),
2665 _ => {
2666 const name = extra.data.name.toString(self.code).?;
2667 const prefix = if (extra.data.name.isNamedTest(self.code)) "test " else "";
2668 try stream.print("{s}'{s}'", .{ prefix, self.code.nullTerminatedString(name) });
2669 },
2670 }
2671 const src_hash_arr: [4]u32 = .{
2672 extra.data.src_hash_0,
2673 extra.data.src_hash_1,
2674 extra.data.src_hash_2,
2675 extra.data.src_hash_3,
2676 };
2677 const src_hash_bytes: [16]u8 = @bitCast(src_hash_arr);
2678 try stream.print(" line(+{d}) hash({})", .{ extra.data.line_offset, std.fmt.fmtSliceHexLower(&src_hash_bytes) });
2679
2680 {
2681 const prev_parent_decl_node = self.parent_decl_node;
2682 defer self.parent_decl_node = prev_parent_decl_node;
2683 self.parent_decl_node = self.relativeToNodeIndex(inst_data.src_node);
2684
2685 const bodies = extra.data.getBodies(@intCast(extra.end), self.code);
2686
2687 try stream.writeAll(" value=");
2688 try self.writeBracedDecl(stream, bodies.value_body);
2689
2690 if (bodies.align_body) |b| {
2691 try stream.writeAll(" align=");
2692 try self.writeBracedDecl(stream, b);
2693 }
2694
2695 if (bodies.linksection_body) |b| {
2696 try stream.writeAll(" linksection=");
2697 try self.writeBracedDecl(stream, b);
2698 }
2699
2700 if (bodies.addrspace_body) |b| {
2701 try stream.writeAll(" addrspace=");
2702 try self.writeBracedDecl(stream, b);
2703 }
2704 }
2705
2706 try stream.writeAll(") ");
2707 try self.writeSrc(stream, inst_data.src());
2708 }
2709
27652710 fn writeInstRef(self: *Writer, stream: anytype, ref: Zir.Inst.Ref) !void {
27662711 if (ref == .none) {
27672712 return stream.writeAll(".none");