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 {...@@ -86,6 +86,7 @@ fn setExtra(astgen: *AstGen, index: usize, extra: anytype) void {
8686
87 Zir.Inst.Ref,87 Zir.Inst.Ref,
88 Zir.Inst.Index,88 Zir.Inst.Index,
89 Zir.Inst.Declaration.Name,
89 Zir.NullTerminatedString,90 Zir.NullTerminatedString,
90 => @intFromEnum(@field(extra, field.name)),91 => @intFromEnum(@field(extra, field.name)),
9192
...@@ -95,6 +96,7 @@ fn setExtra(astgen: *AstGen, index: usize, extra: anytype) void {...@@ -95,6 +96,7 @@ fn setExtra(astgen: *AstGen, index: usize, extra: anytype) void {
95 Zir.Inst.SwitchBlock.Bits,96 Zir.Inst.SwitchBlock.Bits,
96 Zir.Inst.SwitchBlockErrUnion.Bits,97 Zir.Inst.SwitchBlockErrUnion.Bits,
97 Zir.Inst.FuncFancy.Bits,98 Zir.Inst.FuncFancy.Bits,
99 Zir.Inst.Declaration.Flags,
98 => @bitCast(@field(extra, field.name)),100 => @bitCast(@field(extra, field.name)),
99101
100 else => @compileError("bad field type"),102 else => @compileError("bad field type"),
...@@ -132,8 +134,8 @@ pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir {...@@ -132,8 +134,8 @@ pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir {
132 };134 };
133 defer astgen.deinit(gpa);135 defer astgen.deinit(gpa);
134136
135 // String table indexes 0, 1, 2 are reserved for special meaning.137 // String table index 0 is reserved for `NullTerminatedString.empty`.
136 try astgen.string_bytes.appendSlice(gpa, &[_]u8{ 0, 0, 0 });138 try astgen.string_bytes.append(gpa, 0);
137139
138 // We expect at least as many ZIR instructions and extra data items140 // We expect at least as many ZIR instructions and extra data items
139 // as AST nodes.141 // as AST nodes.
...@@ -355,8 +357,13 @@ const ResultInfo = struct {...@@ -355,8 +357,13 @@ const ResultInfo = struct {
355 };357 };
356};358};
357359
360/// TODO: modify Sema to remove in favour of `coerced_align_ri`
358const align_ri: ResultInfo = .{ .rl = .{ .ty = .u29_type } };361const align_ri: ResultInfo = .{ .rl = .{ .ty = .u29_type } };
359const coerced_align_ri: ResultInfo = .{ .rl = .{ .coerced_ty = .u29_type } };362const 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 } };
360const bool_ri: ResultInfo = .{ .rl = .{ .ty = .bool_type } };367const bool_ri: ResultInfo = .{ .rl = .{ .ty = .bool_type } };
361const type_ri: ResultInfo = .{ .rl = .{ .ty = .type_type } };368const type_ri: ResultInfo = .{ .rl = .{ .ty = .type_type } };
362const coerced_type_ri: ResultInfo = .{ .rl = .{ .coerced_ty = .type_type } };369const 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...@@ -2592,6 +2599,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
2592 .block,2599 .block,
2593 .block_comptime,2600 .block_comptime,
2594 .block_inline,2601 .block_inline,
2602 .declaration,
2595 .suspend_block,2603 .suspend_block,
2596 .loop,2604 .loop,
2597 .bool_br_and,2605 .bool_br_and,
...@@ -3783,7 +3791,7 @@ fn ptrType(...@@ -3783,7 +3791,7 @@ fn ptrType(
3783 gz.astgen.source_line = source_line;3791 gz.astgen.source_line = source_line;
3784 gz.astgen.source_column = source_column;3792 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);
3787 trailing_count += 1;3795 trailing_count += 1;
3788 }3796 }
3789 if (ptr_info.ast.align_node != 0) {3797 if (ptr_info.ast.align_node != 0) {
...@@ -3899,8 +3907,6 @@ fn arrayTypeSentinel(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node....@@ -3899,8 +3907,6 @@ fn arrayTypeSentinel(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.
3899const WipMembers = struct {3907const WipMembers = struct {
3900 payload: *ArrayListUnmanaged(u32),3908 payload: *ArrayListUnmanaged(u32),
3901 payload_top: usize,3909 payload_top: usize,
3902 decls_start: u32,
3903 decls_end: u32,
3904 field_bits_start: u32,3910 field_bits_start: u32,
3905 fields_start: u32,3911 fields_start: u32,
3906 fields_end: u32,3912 fields_end: u32,
...@@ -3908,43 +3914,27 @@ const WipMembers = struct {...@@ -3908,43 +3914,27 @@ const WipMembers = struct {
3908 field_index: u32 = 0,3914 field_index: u32 = 0,
39093915
3910 const Self = @This();3916 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
3918 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 {3918 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 {
3919 const payload_top: u32 = @intCast(payload.items.len);3919 const payload_top: u32 = @intCast(payload.items.len);
3920 const decls_start = payload_top + (decl_count + decls_per_u32 - 1) / decls_per_u32;3920 const field_bits_start = payload_top + decl_count;
3921 const field_bits_start = decls_start + decl_count * max_decl_size;
3922 const fields_start = field_bits_start + if (bits_per_field > 0) blk: {3921 const fields_start = field_bits_start + if (bits_per_field > 0) blk: {
3923 const fields_per_u32 = 32 / bits_per_field;3922 const fields_per_u32 = 32 / bits_per_field;
3924 break :blk (field_count + fields_per_u32 - 1) / fields_per_u32;3923 break :blk (field_count + fields_per_u32 - 1) / fields_per_u32;
3925 } else 0;3924 } else 0;
3926 const payload_end = fields_start + field_count * max_field_size;3925 const payload_end = fields_start + field_count * max_field_size;
3927 try payload.resize(gpa, payload_end);3926 try payload.resize(gpa, payload_end);
3928 return Self{3927 return .{
3929 .payload = payload,3928 .payload = payload,
3930 .payload_top = payload_top,3929 .payload_top = payload_top,
3931 .decls_start = decls_start,
3932 .field_bits_start = field_bits_start,3930 .field_bits_start = field_bits_start,
3933 .fields_start = fields_start,3931 .fields_start = fields_start,
3934 .decls_end = decls_start,
3935 .fields_end = fields_start,3932 .fields_end = fields_start,
3936 };3933 };
3937 }3934 }
39383935
3939 fn nextDecl(self: *Self, is_pub: bool, is_export: bool, has_align: bool, has_section_or_addrspace: bool) void {3936 fn nextDecl(self: *Self, decl_inst: Zir.Inst.Index) void {
3940 const index = self.payload_top + self.decl_index / decls_per_u32;3937 self.payload.items[self.payload_top + self.decl_index] = @intFromEnum(decl_inst);
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);
3948 self.decl_index += 1;3938 self.decl_index += 1;
3949 }3939 }
39503940
...@@ -3962,18 +3952,6 @@ const WipMembers = struct {...@@ -3962,18 +3952,6 @@ const WipMembers = struct {
3962 self.field_index += 1;3952 self.field_index += 1;
3963 }3953 }
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
3977 fn appendToField(self: *Self, data: u32) void {3955 fn appendToField(self: *Self, data: u32) void {
3978 assert(self.fields_end < self.payload.items.len);3956 assert(self.fields_end < self.payload.items.len);
3979 self.payload.items[self.fields_end] = data;3957 self.payload.items[self.fields_end] = data;
...@@ -3981,11 +3959,6 @@ const WipMembers = struct {...@@ -3981,11 +3959,6 @@ const WipMembers = struct {
3981 }3959 }
39823960
3983 fn finishBits(self: *Self, comptime bits_per_field: u32) void {3961 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 }
3989 if (bits_per_field > 0) {3962 if (bits_per_field > 0) {
3990 const fields_per_u32 = 32 / bits_per_field;3963 const fields_per_u32 = 32 / bits_per_field;
3991 const empty_field_slots = fields_per_u32 - (self.field_index % fields_per_u32);3964 const empty_field_slots = fields_per_u32 - (self.field_index % fields_per_u32);
...@@ -3997,7 +3970,7 @@ const WipMembers = struct {...@@ -3997,7 +3970,7 @@ const WipMembers = struct {
3997 }3970 }
39983971
3999 fn declsSlice(self: *Self) []u32 {3972 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];
4001 }3974 }
40023975
4003 fn fieldsSlice(self: *Self) []u32 {3976 fn fieldsSlice(self: *Self) []u32 {
...@@ -4023,11 +3996,10 @@ fn fnDecl(...@@ -4023,11 +3996,10 @@ fn fnDecl(
40233996
4024 // missing function name already happened in scanDecls()3997 // missing function name already happened in scanDecls()
4025 const fn_name_token = fn_proto.name_token orelse return error.AnalysisFail;3998 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
4028 // We insert this at the beginning so that its instruction index marks the4000 // We insert this at the beginning so that its instruction index marks the
4029 // start of the top level declaration.4001 // 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);
4031 astgen.advanceSourceCursorToNode(decl_node);4003 astgen.advanceSourceCursorToNode(decl_node);
40324004
4033 var decl_gz: GenZir = .{4005 var decl_gz: GenZir = .{
...@@ -4072,8 +4044,7 @@ fn fnDecl(...@@ -4072,8 +4044,7 @@ fn fnDecl(
40724044
4073 const doc_comment_index = try astgen.docCommentAsString(fn_proto.firstToken());4045 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.4047 wip_members.nextDecl(decl_inst);
4076 wip_members.nextDecl(is_pub, is_export, false, false);
40774048
4078 var noalias_bits: u32 = 0;4049 var noalias_bits: u32 = 0;
4079 var params_scope = &fn_gz.base;4050 var params_scope = &fn_gz.base;
...@@ -4213,7 +4184,7 @@ fn fnDecl(...@@ -4213,7 +4184,7 @@ fn fnDecl(
4213 var addrspace_gz = decl_gz.makeSubBlock(params_scope);4184 var addrspace_gz = decl_gz.makeSubBlock(params_scope);
4214 defer addrspace_gz.unstack();4185 defer addrspace_gz.unstack();
4215 const addrspace_ref: Zir.Inst.Ref = if (fn_proto.ast.addrspace_expr == 0) .none else inst: {4186 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);
4217 if (addrspace_gz.instructionsSlice().len == 0) {4188 if (addrspace_gz.instructionsSlice().len == 0) {
4218 // In this case we will send a len=0 body which can be encoded more efficiently.4189 // In this case we will send a len=0 body which can be encoded more efficiently.
4219 break :inst inst;4190 break :inst inst;
...@@ -4298,7 +4269,7 @@ fn fnDecl(...@@ -4298,7 +4269,7 @@ fn fnDecl(
4298 .section_gz = &section_gz,4269 .section_gz = &section_gz,
4299 .addrspace_ref = addrspace_ref,4270 .addrspace_ref = addrspace_ref,
4300 .addrspace_gz = &addrspace_gz,4271 .addrspace_gz = &addrspace_gz,
4301 .param_block = block_inst,4272 .param_block = decl_inst,
4302 .body_gz = null,4273 .body_gz = null,
4303 .lib_name = lib_name,4274 .lib_name = lib_name,
4304 .is_var_args = is_var_args,4275 .is_var_args = is_var_args,
...@@ -4349,7 +4320,7 @@ fn fnDecl(...@@ -4349,7 +4320,7 @@ fn fnDecl(
4349 .addrspace_gz = &addrspace_gz,4320 .addrspace_gz = &addrspace_gz,
4350 .lbrace_line = lbrace_line,4321 .lbrace_line = lbrace_line,
4351 .lbrace_column = lbrace_column,4322 .lbrace_column = lbrace_column,
4352 .param_block = block_inst,4323 .param_block = decl_inst,
4353 .body_gz = &fn_gz,4324 .body_gz = &fn_gz,
4354 .lib_name = lib_name,4325 .lib_name = lib_name,
4355 .is_var_args = is_var_args,4326 .is_var_args = is_var_args,
...@@ -4363,20 +4334,21 @@ fn fnDecl(...@@ -4363,20 +4334,21 @@ fn fnDecl(
43634334
4364 // We add this at the end so that its instruction index marks the end range4335 // We add this at the end so that its instruction index marks the end range
4365 // of the top level declaration. addFunc already unstacked fn_gz and ret_gz.4336 // of the top level declaration. addFunc already unstacked fn_gz and ret_gz.
4366 _ = try decl_gz.addBreak(.break_inline, block_inst, func_inst);4337 _ = try decl_gz.addBreak(.break_inline, decl_inst, func_inst);
4367 try decl_gz.setBlockBody(block_inst);4338
43684339 try setDeclaration(
4369 {4340 decl_inst,
4370 const contents_hash align(@alignOf(u32)) = std.zig.hashSrc(tree.getNodeSource(decl_node));4341 std.zig.hashSrc(tree.getNodeSource(decl_node)),
4371 wip_members.appendToDeclSlice(std.mem.bytesAsSlice(u32, &contents_hash));4342 .{ .named = fn_name_token },
4372 }4343 decl_gz.decl_line - gz.decl_line,
4373 {4344 is_pub,
4374 const line_delta = decl_gz.decl_line - gz.decl_line;4345 is_export,
4375 wip_members.appendToDecl(line_delta);4346 doc_comment_index,
4376 }4347 &decl_gz,
4377 wip_members.appendToDecl(@intFromEnum(fn_name_str_index));4348 // align, linksection, and addrspace are passed in the func instruction in this case.
4378 wip_members.appendToDecl(@intFromEnum(block_inst));4349 // TODO: move them from the function instruction to the declaration instruction?
4379 wip_members.appendToDecl(@intFromEnum(doc_comment_index));4350 null,
4351 );
4380}4352}
43814353
4382fn globalVarDecl(4354fn globalVarDecl(
...@@ -4393,10 +4365,9 @@ fn globalVarDecl(...@@ -4393,10 +4365,9 @@ fn globalVarDecl(
4393 const is_mutable = token_tags[var_decl.ast.mut_token] == .keyword_var;4365 const is_mutable = token_tags[var_decl.ast.mut_token] == .keyword_var;
4394 // We do this at the beginning so that the instruction index marks the range start4366 // We do this at the beginning so that the instruction index marks the range start
4395 // of the top level declaration.4367 // 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
4398 const name_token = var_decl.ast.mut_token + 1;4370 const name_token = var_decl.ast.mut_token + 1;
4399 const name_str_index = try astgen.identAsString(name_token);
4400 astgen.advanceSourceCursorToNode(node);4371 astgen.advanceSourceCursorToNode(node);
44014372
4402 var block_scope: GenZir = .{4373 var block_scope: GenZir = .{
...@@ -4420,17 +4391,7 @@ fn globalVarDecl(...@@ -4420,17 +4391,7 @@ fn globalVarDecl(
4420 const maybe_extern_token = var_decl.extern_export_token orelse break :blk false;4391 const maybe_extern_token = var_decl.extern_export_token orelse break :blk false;
4421 break :blk token_tags[maybe_extern_token] == .keyword_extern;4392 break :blk token_tags[maybe_extern_token] == .keyword_extern;
4422 };4393 };
4423 const align_inst: Zir.Inst.Ref = if (var_decl.ast.align_node == 0) .none else inst: {4394 wip_members.nextDecl(decl_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);
44344395
4435 const is_threadlocal = if (var_decl.threadlocal_token) |tok| blk: {4396 const is_threadlocal = if (var_decl.threadlocal_token) |tok| blk: {
4436 if (!is_mutable) {4397 if (!is_mutable) {
...@@ -4513,29 +4474,44 @@ fn globalVarDecl(...@@ -4513,29 +4474,44 @@ fn globalVarDecl(
4513 } else {4474 } else {
4514 return astgen.failNode(node, "unable to infer variable type", .{});4475 return astgen.failNode(node, "unable to infer variable type", .{});
4515 };4476 };
4477
4516 // We do this at the end so that the instruction index marks the end4478 // We do this at the end so that the instruction index marks the end
4517 // range of a top level declaration.4479 // range of a top level declaration.
4518 _ = try block_scope.addBreakWithSrcNode(.break_inline, block_inst, var_inst, node);4480 _ = try block_scope.addBreakWithSrcNode(.break_inline, decl_inst, var_inst, node);
4519 try block_scope.setBlockBody(block_inst);
45204481
4521 {4482 var align_gz = block_scope.makeSubBlock(scope);
4522 const contents_hash align(@alignOf(u32)) = std.zig.hashSrc(tree.getNodeSource(node));4483 if (var_decl.ast.align_node != 0) {
4523 wip_members.appendToDeclSlice(std.mem.bytesAsSlice(u32, &contents_hash));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);
4524 }4486 }
4525 {4487
4526 const line_delta = block_scope.decl_line - gz.decl_line;4488 var linksection_gz = align_gz.makeSubBlock(scope);
4527 wip_members.appendToDecl(line_delta);4489 if (var_decl.ast.section_node != 0) {
4528 }4490 const linksection_inst = try expr(&linksection_gz, &linksection_gz.base, coerced_linksection_ri, var_decl.ast.section_node);
4529 wip_members.appendToDecl(@intFromEnum(name_str_index));4491 _ = try linksection_gz.addBreakWithSrcNode(.break_inline, decl_inst, linksection_inst, node);
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));
4538 }4492 }
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 );
4539}4515}
45404516
4541fn comptimeDecl(4517fn comptimeDecl(
...@@ -4551,8 +4527,8 @@ fn comptimeDecl(...@@ -4551,8 +4527,8 @@ fn comptimeDecl(
45514527
4552 // Up top so the ZIR instruction index marks the start range of this4528 // Up top so the ZIR instruction index marks the start range of this
4553 // top-level declaration.4529 // top-level declaration.
4554 const block_inst = try gz.makeBlockInst(.block_inline, node);4530 const decl_inst = try gz.makeBlockInst(.declaration, node);
4555 wip_members.nextDecl(false, false, false, false);4531 wip_members.nextDecl(decl_inst);
4556 astgen.advanceSourceCursorToNode(node);4532 astgen.advanceSourceCursorToNode(node);
45574533
4558 var decl_block: GenZir = .{4534 var decl_block: GenZir = .{
...@@ -4568,21 +4544,20 @@ fn comptimeDecl(...@@ -4568,21 +4544,20 @@ fn comptimeDecl(
45684544
4569 const block_result = try expr(&decl_block, &decl_block.base, .{ .rl = .none }, body_node);4545 const block_result = try expr(&decl_block, &decl_block.base, .{ .rl = .none }, body_node);
4570 if (decl_block.isEmpty() or !decl_block.refIsNoReturn(block_result)) {4546 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);
4572 }4548 }
4573 try decl_block.setBlockBody(block_inst);
45744549
4575 {4550 try setDeclaration(
4576 const contents_hash align(@alignOf(u32)) = std.zig.hashSrc(tree.getNodeSource(node));4551 decl_inst,
4577 wip_members.appendToDeclSlice(std.mem.bytesAsSlice(u32, &contents_hash));4552 std.zig.hashSrc(tree.getNodeSource(node)),
4578 }4553 .@"comptime",
4579 {4554 decl_block.decl_line - gz.decl_line,
4580 const line_delta = decl_block.decl_line - gz.decl_line;4555 false,
4581 wip_members.appendToDecl(line_delta);4556 false,
4582 }4557 .empty,
4583 wip_members.appendToDecl(0);4558 &decl_block,
4584 wip_members.appendToDecl(@intFromEnum(block_inst));4559 null,
4585 wip_members.appendToDecl(0); // no doc comments on comptime decls4560 );
4586}4561}
45874562
4588fn usingnamespaceDecl(4563fn usingnamespaceDecl(
...@@ -4604,8 +4579,8 @@ fn usingnamespaceDecl(...@@ -4604,8 +4579,8 @@ fn usingnamespaceDecl(
4604 };4579 };
4605 // Up top so the ZIR instruction index marks the start range of this4580 // Up top so the ZIR instruction index marks the start range of this
4606 // top-level declaration.4581 // top-level declaration.
4607 const block_inst = try gz.makeBlockInst(.block_inline, node);4582 const decl_inst = try gz.makeBlockInst(.declaration, node);
4608 wip_members.nextDecl(is_pub, true, false, false);4583 wip_members.nextDecl(decl_inst);
4609 astgen.advanceSourceCursorToNode(node);4584 astgen.advanceSourceCursorToNode(node);
46104585
4611 var decl_block: GenZir = .{4586 var decl_block: GenZir = .{
...@@ -4620,20 +4595,19 @@ fn usingnamespaceDecl(...@@ -4620,20 +4595,19 @@ fn usingnamespaceDecl(
4620 defer decl_block.unstack();4595 defer decl_block.unstack();
46214596
4622 const namespace_inst = try typeExpr(&decl_block, &decl_block.base, type_expr);4597 const namespace_inst = try typeExpr(&decl_block, &decl_block.base, type_expr);
4623 _ = try decl_block.addBreak(.break_inline, block_inst, namespace_inst);4598 _ = try decl_block.addBreak(.break_inline, decl_inst, namespace_inst);
4624 try decl_block.setBlockBody(block_inst);4599
46254600 try setDeclaration(
4626 {4601 decl_inst,
4627 const contents_hash align(@alignOf(u32)) = std.zig.hashSrc(tree.getNodeSource(node));4602 std.zig.hashSrc(tree.getNodeSource(node)),
4628 wip_members.appendToDeclSlice(std.mem.bytesAsSlice(u32, &contents_hash));4603 .@"usingnamespace",
4629 }4604 decl_block.decl_line - gz.decl_line,
4630 {4605 is_pub,
4631 const line_delta = decl_block.decl_line - gz.decl_line;4606 false,
4632 wip_members.appendToDecl(line_delta);4607 .empty,
4633 }4608 &decl_block,
4634 wip_members.appendToDecl(0);4609 null,
4635 wip_members.appendToDecl(@intFromEnum(block_inst));4610 );
4636 wip_members.appendToDecl(0); // no doc comments on usingnamespace decls
4637}4611}
46384612
4639fn testDecl(4613fn testDecl(
...@@ -4649,9 +4623,9 @@ fn testDecl(...@@ -4649,9 +4623,9 @@ fn testDecl(
46494623
4650 // Up top so the ZIR instruction index marks the start range of this4624 // Up top so the ZIR instruction index marks the start range of this
4651 // top-level declaration.4625 // 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);
4655 astgen.advanceSourceCursorToNode(node);4629 astgen.advanceSourceCursorToNode(node);
46564630
4657 var decl_block: GenZir = .{4631 var decl_block: GenZir = .{
...@@ -4669,12 +4643,10 @@ fn testDecl(...@@ -4669,12 +4643,10 @@ fn testDecl(
4669 const token_tags = tree.tokens.items(.tag);4643 const token_tags = tree.tokens.items(.tag);
4670 const test_token = main_tokens[node];4644 const test_token = main_tokens[node];
4671 const test_name_token = test_token + 1;4645 const test_name_token = test_token + 1;
4672 const test_name_token_tag = token_tags[test_name_token];4646 const test_name: DeclarationName = switch (token_tags[test_name_token]) {
4673 const is_decltest = test_name_token_tag == .identifier;4647 else => .unnamed_test,
4674 const test_name: Zir.NullTerminatedString = blk: {4648 .string_literal => .{ .named_test = test_name_token },
4675 if (test_name_token_tag == .string_literal) {4649 .identifier => blk: {
4676 break :blk try astgen.testNameString(test_name_token);
4677 } else if (test_name_token_tag == .identifier) {
4678 const ident_name_raw = tree.tokenSlice(test_name_token);4650 const ident_name_raw = tree.tokenSlice(test_name_token);
46794651
4680 if (mem.eql(u8, ident_name_raw, "_")) return astgen.failTok(test_name_token, "'_' used as an identifier without @\"_\" syntax", .{});4652 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(...@@ -4744,10 +4716,8 @@ fn testDecl(
4744 return astgen.failTok(test_name_token, "use of undeclared identifier '{s}'", .{ident_name});4716 return astgen.failTok(test_name_token, "use of undeclared identifier '{s}'", .{ident_name});
4745 }4717 }
47464718
4747 break :blk name_str_index;4719 break :blk .{ .decltest = name_str_index };
4748 }4720 },
4749 // String table index 1 has a special meaning here of test decl with no name.
4750 break :blk .unnamed_test_decl;
4751 };4721 };
47524722
4753 var fn_block: GenZir = .{4723 var fn_block: GenZir = .{
...@@ -4795,7 +4765,7 @@ fn testDecl(...@@ -4795,7 +4765,7 @@ fn testDecl(
47954765
4796 .lbrace_line = lbrace_line,4766 .lbrace_line = lbrace_line,
4797 .lbrace_column = lbrace_column,4767 .lbrace_column = lbrace_column,
4798 .param_block = block_inst,4768 .param_block = decl_inst,
4799 .body_gz = &fn_block,4769 .body_gz = &fn_block,
4800 .lib_name = .empty,4770 .lib_name = .empty,
4801 .is_var_args = false,4771 .is_var_args = false,
...@@ -4806,26 +4776,19 @@ fn testDecl(...@@ -4806,26 +4776,19 @@ fn testDecl(
4806 .noalias_bits = 0,4776 .noalias_bits = 0,
4807 });4777 });
48084778
4809 _ = try decl_block.addBreak(.break_inline, block_inst, func_inst);4779 _ = try decl_block.addBreak(.break_inline, decl_inst, func_inst);
4810 try decl_block.setBlockBody(block_inst);4780
48114781 try setDeclaration(
4812 {4782 decl_inst,
4813 const contents_hash align(@alignOf(u32)) = std.zig.hashSrc(tree.getNodeSource(node));4783 std.zig.hashSrc(tree.getNodeSource(node)),
4814 wip_members.appendToDeclSlice(std.mem.bytesAsSlice(u32, &contents_hash));4784 test_name,
4815 }4785 decl_block.decl_line - gz.decl_line,
4816 {4786 false,
4817 const line_delta = decl_block.decl_line - gz.decl_line;4787 false,
4818 wip_members.appendToDecl(line_delta);4788 .empty,
4819 }4789 &decl_block,
4820 if (is_decltest)4790 null,
4821 wip_members.appendToDecl(2) // 2 here means that it is a decltest, look at doc comment for name4791 );
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
4829}4792}
48304793
4831fn structDeclInner(4794fn structDeclInner(
...@@ -13524,3 +13487,106 @@ fn lowerAstErrors(astgen: *AstGen) !void {...@@ -13524,3 +13487,106 @@ fn lowerAstErrors(astgen: *AstGen) !void {
13524 try tree.renderError(parse_err, msg.writer(gpa));13487 try tree.renderError(parse_err, msg.writer(gpa));
13525 try astgen.appendErrorTokNotesOff(parse_err.token, extra_offset, "{s}", .{msg.items}, notes.items);13488 try astgen.appendErrorTokNotesOff(parse_err.token, extra_offset, "{s}", .{msg.items}, notes.items);
13526}13489}
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(...@@ -2846,22 +2846,14 @@ fn walkInstruction(
2846 return res;2846 return res;
2847 },2847 },
2848 .block_inline => {2848 .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(
2850 file,2852 file,
2851 parent_scope,2853 parent_scope,
2854 try self.srcLocInfo(file, pl_node.src_node, parent_src),
2852 parent_src,2855 parent_src,
2853 getBlockInlineBreak(file.zir, inst) orelse {2856 file.zir.bodySlice(extra.end, extra.data.body_len),
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 },
2865 need_type,2857 need_type,
2866 call_ctx,2858 call_ctx,
2867 );2859 );
...@@ -4084,19 +4076,11 @@ fn analyzeAllDecls(...@@ -4084,19 +4076,11 @@ fn analyzeAllDecls(
4084 // First loop to discover decl names4076 // First loop to discover decl names
4085 {4077 {
4086 var it = original_it;4078 var it = original_it;
4087 while (it.next()) |d| {4079 while (it.next()) |zir_index| {
4088 const decl_name_index: Zir.NullTerminatedString = @enumFromInt(file.zir.extra[@intFromEnum(d.sub_index) + 5]);4080 const declaration, _ = file.zir.getDeclaration(zir_index);
4089 switch (decl_name_index) {4081 if (declaration.name.isNamedTest(file.zir)) continue;
4090 .empty,4082 const decl_name = declaration.name.toString(file.zir) orelse continue;
4091 .unnamed_test_decl,4083 try scope.insertDeclRef(self.arena, decl_name, .Pending);
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);
4100 }4084 }
4101 }4085 }
41024086
...@@ -4104,147 +4088,114 @@ fn analyzeAllDecls(...@@ -4104,147 +4088,114 @@ fn analyzeAllDecls(
4104 {4088 {
4105 var it = original_it;4089 var it = original_it;
4106 var decl_indexes_slot = first_decl_indexes_slot;4090 var decl_indexes_slot = first_decl_indexes_slot;
4107 while (it.next()) |d| : (decl_indexes_slot += 1) {4091 while (it.next()) |zir_index| : (decl_indexes_slot += 1) {
4108 const decl_name_index = file.zir.extra[@intFromEnum(d.sub_index) + 5];4092 const pl_node = file.zir.instructions.items(.data)[@intFromEnum(zir_index)].pl_node;
4109 switch (decl_name_index) {4093 const extra = file.zir.extraData(Zir.Inst.Declaration, pl_node.payload_index);
4110 0 => {4094 if (extra.data.name != .@"usingnamespace") continue;
4111 const is_exported = @as(u1, @truncate(d.flags >> 1));4095 try self.analyzeUsingnamespaceDecl(
4112 switch (is_exported) {4096 file,
4113 0 => continue, // comptime decl4097 scope,
4114 1 => {4098 try self.srcLocInfo(file, pl_node.src_node, parent_src),
4115 try self.analyzeUsingnamespaceDecl(4099 decl_indexes,
4116 file,4100 priv_decl_indexes,
4117 scope,4101 extra.data,
4118 parent_src,4102 @intCast(extra.end),
4119 decl_indexes,4103 call_ctx,
4120 priv_decl_indexes,4104 );
4121 d,
4122 call_ctx,
4123 );
4124 },
4125 }
4126 },
4127 else => continue,
4128 }
4129 }4105 }
4130 }4106 }
41314107
4132 // Third loop to analyze all remaining decls4108 // Third loop to analyze all remaining decls
4133 var it = original_it;4109 {
4134 while (it.next()) |d| {4110 var it = original_it;
4135 const decl_name_index = file.zir.extra[@intFromEnum(d.sub_index) + 5];4111 while (it.next()) |zir_index| {
4136 switch (decl_name_index) {4112 const pl_node = file.zir.instructions.items(.data)[@intFromEnum(zir_index)].pl_node;
4137 0, 1 => continue, // skip over usingnamespace decls4113 const extra = file.zir.extraData(Zir.Inst.Declaration, pl_node.payload_index);
4138 2 => continue, // skip decltests4114 switch (extra.data.name) {
41394115 .@"comptime", .@"usingnamespace", .unnamed_test, .decltest => continue,
4140 else => if (file.zir.string_bytes[decl_name_index] == 0) {4116 _ => if (extra.data.name.isNamedTest(file.zir)) continue,
4141 continue;4117 }
4142 },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 );
4143 }4129 }
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 );
4154 }4130 }
41554131
4156 // Fourth loop to analyze decltests4132 // Fourth loop to analyze decltests
4157 it = original_it;4133 var it = original_it;
4158 while (it.next()) |d| {4134 while (it.next()) |zir_index| {
4159 const decl_name_index = file.zir.extra[@intFromEnum(d.sub_index) + 5];4135 const pl_node = file.zir.instructions.items(.data)[@intFromEnum(zir_index)].pl_node;
4160 switch (decl_name_index) {4136 const extra = file.zir.extraData(Zir.Inst.Declaration, pl_node.payload_index);
4161 0, 1 => continue, // skip over usingnamespace decls4137 if (extra.data.name != .decltest) continue;
4162 2 => {},
4163 else => continue, // skip tests and normal decls
4164 }
4165
4166 try self.analyzeDecltest(4138 try self.analyzeDecltest(
4167 file,4139 file,
4168 scope,4140 scope,
4169 parent_src,4141 try self.srcLocInfo(file, pl_node.src_node, parent_src),
4170 d,4142 extra.data,
4143 @intCast(extra.end),
4171 );4144 );
4172 }4145 }
41734146
4174 return it.extra_index;4147 return it.extra_index;
4175}4148}
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
4177// Asserts the given decl is public4181// Asserts the given decl is public
4178fn analyzeDecl(4182fn analyzeDecl(
4179 self: *Autodoc,4183 self: *Autodoc,
4180 file: *File,4184 file: *File,
4181 scope: *Scope,4185 scope: *Scope,
4182 parent_src: SrcLocInfo,4186 decl_src: SrcLocInfo,
4183 decl_indexes: *std.ArrayListUnmanaged(usize),4187 decl_indexes: *std.ArrayListUnmanaged(usize),
4184 priv_decl_indexes: *std.ArrayListUnmanaged(usize),4188 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,
4186 call_ctx: ?*const CallContext,4192 call_ctx: ?*const CallContext,
4187) AutodocErrors!void {4193) AutodocErrors!void {
4188 const data = file.zir.instructions.items(.data);4194 const bodies = declaration.getBodies(extra_index, file.zir);
4189 const is_pub = @as(u1, @truncate(d.flags >> 0)) != 0;4195 const name = file.zir.nullTerminatedString(declaration.name.toString(file.zir).?);
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;
42234196
4224 const addrspace_inst: Zir.Inst.Ref = if (!has_section_or_addrspace) .none else inst: {4197 const doc_comment: ?[]const u8 = if (declaration.flags.has_doc_comment)
4225 const inst: Zir.Inst.Ref = @enumFromInt(file.zir.extra[extra_index]);4198 file.zir.nullTerminatedString(@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)
4248 else4199 else
4249 null;4200 null;
42504201
...@@ -4261,16 +4212,22 @@ fn analyzeDecl(...@@ -4261,16 +4212,22 @@ fn analyzeDecl(
4261 break :idx idx;4212 break :idx idx;
4262 };4213 };
42634214
4264 const walk_result = try self.walkInstruction(4215 const walk_result = try self.walkInlineBody(
4265 file,4216 file,
4266 scope,4217 scope,
4267 decl_src,4218 decl_src,
4268 value_index,4219 decl_src,
4220 bodies.value_body,
4269 true,4221 true,
4270 call_ctx,4222 call_ctx,
4271 );4223 );
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
4275 const decls_slot_index = self.decls.items.len;4232 const decls_slot_index = self.decls.items.len;
4276 try self.decls.append(self.arena, .{4233 try self.decls.append(self.arena, .{
...@@ -4281,13 +4238,13 @@ fn analyzeDecl(...@@ -4281,13 +4238,13 @@ fn analyzeDecl(
4281 .parent_container = scope.enclosing_type,4238 .parent_container = scope.enclosing_type,
4282 });4239 });
42834240
4284 if (is_pub) {4241 if (declaration.flags.is_pub) {
4285 try decl_indexes.append(self.arena, decls_slot_index);4242 try decl_indexes.append(self.arena, decls_slot_index);
4286 } else {4243 } else {
4287 try priv_decl_indexes.append(self.arena, decls_slot_index);4244 try priv_decl_indexes.append(self.arena, decls_slot_index);
4288 }4245 }
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);
4291 std.debug.assert(decl_status_ptr.* == .Pending);4248 std.debug.assert(decl_status_ptr.* == .Pending);
4292 decl_status_ptr.* = .{ .Analyzed = decls_slot_index };4249 decl_status_ptr.* = .{ .Analyzed = decls_slot_index };
42934250
...@@ -4296,7 +4253,7 @@ fn analyzeDecl(...@@ -4296,7 +4253,7 @@ fn analyzeDecl(
4296 for (paths.items) |resume_info| {4253 for (paths.items) |resume_info| {
4297 try self.tryResolveRefPath(4254 try self.tryResolveRefPath(
4298 resume_info.file,4255 resume_info.file,
4299 value_index,4256 decl_inst,
4300 resume_info.ref_path,4257 resume_info.ref_path,
4301 );4258 );
4302 }4259 }
...@@ -4312,24 +4269,17 @@ fn analyzeUsingnamespaceDecl(...@@ -4312,24 +4269,17 @@ fn analyzeUsingnamespaceDecl(
4312 self: *Autodoc,4269 self: *Autodoc,
4313 file: *File,4270 file: *File,
4314 scope: *Scope,4271 scope: *Scope,
4315 parent_src: SrcLocInfo,4272 decl_src: SrcLocInfo,
4316 decl_indexes: *std.ArrayListUnmanaged(usize),4273 decl_indexes: *std.ArrayListUnmanaged(usize),
4317 priv_decl_indexes: *std.ArrayListUnmanaged(usize),4274 priv_decl_indexes: *std.ArrayListUnmanaged(usize),
4318 d: Zir.DeclIterator.Item,4275 declaration: Zir.Inst.Declaration,
4276 extra_index: u32,
4319 call_ctx: ?*const CallContext,4277 call_ctx: ?*const CallContext,
4320) AutodocErrors!void {4278) 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;4281 const doc_comment: ?[]const u8 = if (declaration.flags.has_doc_comment)
4324 const value_index: Zir.Inst.Index = @enumFromInt(file.zir.extra[@intFromEnum(d.sub_index) + 6]);4282 file.zir.nullTerminatedString(@enumFromInt(file.zir.extra[extra_index]))
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)
4333 else4283 else
4334 null;4284 null;
43354285
...@@ -4346,11 +4296,12 @@ fn analyzeUsingnamespaceDecl(...@@ -4346,11 +4296,12 @@ fn analyzeUsingnamespaceDecl(
4346 break :idx idx;4296 break :idx idx;
4347 };4297 };
43484298
4349 const walk_result = try self.walkInstruction(4299 const walk_result = try self.walkInlineBody(
4350 file,4300 file,
4351 scope,4301 scope,
4352 decl_src,4302 decl_src,
4353 value_index,4303 decl_src,
4304 bodies.value_body,
4354 true,4305 true,
4355 call_ctx,4306 call_ctx,
4356 );4307 );
...@@ -4365,7 +4316,7 @@ fn analyzeUsingnamespaceDecl(...@@ -4365,7 +4316,7 @@ fn analyzeUsingnamespaceDecl(
4365 .parent_container = scope.enclosing_type,4316 .parent_container = scope.enclosing_type,
4366 });4317 });
43674318
4368 if (is_pub) {4319 if (declaration.flags.is_pub) {
4369 try decl_indexes.append(self.arena, decl_slot_index);4320 try decl_indexes.append(self.arena, decl_slot_index);
4370 } else {4321 } else {
4371 try priv_decl_indexes.append(self.arena, decl_slot_index);4322 try priv_decl_indexes.append(self.arena, decl_slot_index);
...@@ -4376,18 +4327,14 @@ fn analyzeDecltest(...@@ -4376,18 +4327,14 @@ fn analyzeDecltest(
4376 self: *Autodoc,4327 self: *Autodoc,
4377 file: *File,4328 file: *File,
4378 scope: *Scope,4329 scope: *Scope,
4379 parent_src: SrcLocInfo,4330 decl_src: SrcLocInfo,
4380 d: Zir.DeclIterator.Item,4331 declaration: Zir.Inst.Declaration,
4332 extra_index: u32,
4381) AutodocErrors!void {4333) AutodocErrors!void {
4382 const data = file.zir.instructions.items(.data);4334 std.debug.assert(declaration.flags.has_doc_comment);
43834335 const decl_name_index: Zir.NullTerminatedString = @enumFromInt(file.zir.extra[extra_index]);
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);
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
4392 const decl_name: ?[]const u8 = if (decl_name_index != .empty)4339 const decl_name: ?[]const u8 = if (decl_name_index != .empty)
4393 file.zir.nullTerminatedString(decl_name_index)4340 file.zir.nullTerminatedString(decl_name_index)
...@@ -5830,17 +5777,6 @@ fn walkRef(...@@ -5830,17 +5777,6 @@ fn walkRef(
5830 }5777 }
5831}5778}
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
5844fn printWithContext(5780fn printWithContext(
5845 file: *File,5781 file: *File,
5846 inst: Zir.Inst.Index,5782 inst: Zir.Inst.Index,
src/InternPool.zig-2
...@@ -6186,8 +6186,6 @@ fn finishFuncInstance(...@@ -6186,8 +6186,6 @@ fn finishFuncInstance(
6186 .generation = generation,6186 .generation = generation,
6187 .is_pub = fn_owner_decl.is_pub,6187 .is_pub = fn_owner_decl.is_pub,
6188 .is_exported = fn_owner_decl.is_exported,6188 .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,
6191 .alive = true,6189 .alive = true,
6192 .kind = .anon,6190 .kind = .anon,
6193 });6191 });
src/Module.zig+216-260
...@@ -386,11 +386,9 @@ pub const Decl = struct {...@@ -386,11 +386,9 @@ pub const Decl = struct {
386 /// do not need to be loaded into memory in order to compute debug line numbers.386 /// do not need to be loaded into memory in order to compute debug line numbers.
387 /// This value is absolute.387 /// This value is absolute.
388 src_line: u32,388 src_line: u32,
389 /// Index to ZIR `extra` array to the entry in the parent's decl structure389 /// Index of the ZIR `declaration` instruction from which this `Decl` was created.
390 /// (the part that says "for every decls_len"). The first item at this index is390 /// For the root `Decl` of a `File` and legacy anonymous decls, this is `.none`.
391 /// the contents hash, followed by line, name, etc.391 zir_decl_index: Zir.Inst.OptionalIndex,
392 /// For anonymous decls and also the root Decl for a File, this is `none`.
393 zir_decl_index: Zir.OptionalExtraIndex,
394392
395 /// Represents the "shallow" analysis status. For example, for decls that are functions,393 /// Represents the "shallow" analysis status. For example, for decls that are functions,
396 /// the function type is analyzed with this set to `in_progress`, however, the semantic394 /// the function type is analyzed with this set to `in_progress`, however, the semantic
...@@ -442,10 +440,6 @@ pub const Decl = struct {...@@ -442,10 +440,6 @@ pub const Decl = struct {
442 is_pub: bool,440 is_pub: bool,
443 /// Whether the corresponding AST decl has a `export` keyword.441 /// Whether the corresponding AST decl has a `export` keyword.
444 is_exported: bool,442 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,
449 /// Flag used by garbage collection to mark and sweep.443 /// Flag used by garbage collection to mark and sweep.
450 /// Decls which correspond to an AST node always have this field set to `true`.444 /// Decls which correspond to an AST node always have this field set to `true`.
451 /// Anonymous Decls are initialized with this field set to `false` and then it445 /// Anonymous Decls are initialized with this field set to `false` and then it
...@@ -471,81 +465,19 @@ pub const Decl = struct {...@@ -471,81 +465,19 @@ pub const Decl = struct {
471 const Index = InternPool.DeclIndex;465 const Index = InternPool.DeclIndex;
472 const OptionalIndex = InternPool.OptionalDeclIndex;466 const OptionalIndex = InternPool.OptionalDeclIndex;
473467
474 pub const DepsTable = std.AutoArrayHashMapUnmanaged(Decl.Index, DepType);468 /// Asserts that `zir_decl_index` is not `.none`.
475469 fn getDeclaration(decl: Decl, zir: Zir) Zir.Inst.Declaration {
476 /// Later types take priority; e.g. if a dependent decl has both `normal`470 const zir_index = decl.zir_decl_index.unwrap().?;
477 /// and `function_body` dependencies on another decl, it will be marked as471 const pl_node = zir.instructions.items(.data)[@intFromEnum(zir_index)].pl_node;
478 /// having a `function_body` dependency.472 return zir.extraData(Zir.Inst.Declaration, pl_node.payload_index).data;
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);
497 }473 }
498474
499 pub fn getNameZir(decl: Decl, zir: Zir) ?[:0]const u8 {475 pub fn zirBodies(decl: Decl, zcu: *Zcu) Zir.Inst.Declaration.Bodies {
500 assert(decl.zir_decl_index != .none);476 const zir = decl.getFileScope(zcu).zir;
501 const name_index = zir.extra[@intFromEnum(decl.zir_decl_index) + 5];477 const zir_index = decl.zir_decl_index.unwrap().?;
502 if (name_index <= 1) return null;478 const pl_node = zir.instructions.items(.data)[@intFromEnum(zir_index)].pl_node;
503 return zir.nullTerminatedString(name_index);479 const extra = zir.extraData(Zir.Inst.Declaration, pl_node.payload_index);
504 }480 return extra.data.getBodies(@intCast(extra.end), zir);
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;
549 }481 }
550482
551 pub fn relativeToNodeIndex(decl: Decl, offset: i32) Ast.Node.Index {483 pub fn relativeToNodeIndex(decl: Decl, offset: i32) Ast.Node.Index {
...@@ -3015,16 +2947,12 @@ fn updateZirRefs(mod: *Module, file: *File, old_zir: Zir) !void {...@@ -3015,16 +2947,12 @@ fn updateZirRefs(mod: *Module, file: *File, old_zir: Zir) !void {
3015 // The root decl will be null if the previous ZIR had AST errors.2947 // The root decl will be null if the previous ZIR had AST errors.
3016 const root_decl = file.root_decl.unwrap() orelse return;2948 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 which2950 // Maps from old ZIR to new ZIR, declaration, struct_decl, enum_decl, etc. Any instruction which
3019 // creates a namespace, gets mapped from old to new here.2951 // creates a namespace, and any `declaration` instruction, gets mapped from old to new here.
3020 var inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{};2952 var inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{};
3021 defer inst_map.deinit(gpa);2953 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
3029 // Walk the Decl graph, updating ZIR indexes, strings, and populating2957 // Walk the Decl graph, updating ZIR indexes, strings, and populating
3030 // the deleted and outdated lists.2958 // the deleted and outdated lists.
...@@ -3050,7 +2978,7 @@ fn updateZirRefs(mod: *Module, file: *File, old_zir: Zir) !void {...@@ -3050,7 +2978,7 @@ fn updateZirRefs(mod: *Module, file: *File, old_zir: Zir) !void {
3050 // Anonymous decls should not be marked outdated. They will be re-generated2978 // Anonymous decls should not be marked outdated. They will be re-generated
3051 // if their owner decl is marked outdated.2979 // if their owner decl is marked outdated.
3052 if (decl.zir_decl_index.unwrap()) |old_zir_decl_index| {2980 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 {
3054 try file.deleted_decls.append(gpa, decl_index);2982 try file.deleted_decls.append(gpa, decl_index);
3055 continue;2983 continue;
3056 };2984 };
...@@ -3098,9 +3026,9 @@ pub fn mapOldZirToNew(...@@ -3098,9 +3026,9 @@ pub fn mapOldZirToNew(
3098 old_zir: Zir,3026 old_zir: Zir,
3099 new_zir: Zir,3027 new_zir: Zir,
3100 inst_map: *std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index),3028 inst_map: *std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index),
3101 extra_map: *std.AutoHashMapUnmanaged(Zir.ExtraIndex, Zir.ExtraIndex),
3102) Allocator.Error!void {3029) 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.
3104 const MatchedZirDecl = struct {3032 const MatchedZirDecl = struct {
3105 old_inst: Zir.Inst.Index,3033 old_inst: Zir.Inst.Index,
3106 new_inst: Zir.Inst.Index,3034 new_inst: Zir.Inst.Index,
...@@ -3108,47 +3036,113 @@ pub fn mapOldZirToNew(...@@ -3108,47 +3036,113 @@ pub fn mapOldZirToNew(
3108 var match_stack: ArrayListUnmanaged(MatchedZirDecl) = .{};3036 var match_stack: ArrayListUnmanaged(MatchedZirDecl) = .{};
3109 defer match_stack.deinit(gpa);3037 defer match_stack.deinit(gpa);
31103038
3111 // Main struct inst is always the same3039 // Main struct inst is always matched
3112 try match_stack.append(gpa, .{3040 try match_stack.append(gpa, .{
3113 .old_inst = .main_struct_inst,3041 .old_inst = .main_struct_inst,
3114 .new_inst = .main_struct_inst,3042 .new_inst = .main_struct_inst,
3115 });3043 });
31163044
3045 // Used as temporary buffers for namespace declaration instructions
3117 var old_decls = std.ArrayList(Zir.Inst.Index).init(gpa);3046 var old_decls = std.ArrayList(Zir.Inst.Index).init(gpa);
3118 defer old_decls.deinit();3047 defer old_decls.deinit();
3119 var new_decls = std.ArrayList(Zir.Inst.Index).init(gpa);3048 var new_decls = std.ArrayList(Zir.Inst.Index).init(gpa);
3120 defer new_decls.deinit();3049 defer new_decls.deinit();
31213050
3122 while (match_stack.popOrNull()) |match_item| {3051 while (match_stack.popOrNull()) |match_item| {
3052 // Match the namespace declaration itself
3123 try inst_map.put(gpa, match_item.old_inst, match_item.new_inst);3053 try inst_map.put(gpa, match_item.old_inst, match_item.new_inst);
31243054
3125 // Maps name to extra index of decl sub item.3055 // Maps decl name to `declaration` instruction.
3126 var decl_map: std.StringHashMapUnmanaged(Zir.ExtraIndex) = .{};3056 var named_decls: std.StringHashMapUnmanaged(Zir.Inst.Index) = .{};
3127 defer decl_map.deinit(gpa);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
3129 {3071 {
3130 var old_decl_it = old_zir.declIterator(match_item.old_inst);3072 var old_decl_it = old_zir.declIterator(match_item.old_inst);
3131 while (old_decl_it.next()) |old_decl| {3073 while (old_decl_it.next()) |old_decl_inst| {
3132 try decl_map.put(gpa, old_decl.name, old_decl.sub_index);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 }
3133 }3089 }
3134 }3090 }
31353091
3092 var unnamed_test_idx: u32 = 0;
3093 var comptime_decl_idx: u32 = 0;
3094 var usingnamespace_decl_idx: u32 = 0;
3095
3136 var new_decl_it = new_zir.declIterator(match_item.new_inst);3096 var new_decl_it = new_zir.declIterator(match_item.new_inst);
3137 while (new_decl_it.next()) |new_decl| {3097 while (new_decl_it.next()) |new_decl_inst| {
3138 const old_extra_index = decl_map.get(new_decl.name) orelse continue;3098 const new_decl, _ = new_zir.getDeclaration(new_decl_inst);
3139 const new_extra_index = new_decl.sub_index;3099 // Attempt to match this to a declaration in the old ZIR:
3140 try extra_map.put(gpa, old_extra_index, new_extra_index);3100 // * For named declarations (`const`/`var`/`fn`), we match based on name.
31413101 // * For named tests (`test "foo"`), we also match based on name.
3142 try old_zir.findDecls(&old_decls, old_extra_index);3102 // * For unnamed tests and decltests, we match based on order.
3143 try new_zir.findDecls(&new_decls, new_extra_index);3103 // * For comptime blocks, we match based on order.
3144 var i: usize = 0;3104 // * For usingnamespace decls, we match based on order.
3145 while (true) : (i += 1) {3105 // If we cannot match this declaration, we can't match anything nested inside of it either, so we just `continue`.
3146 if (i >= old_decls.items.len) break;3106 const old_decl_inst = switch (new_decl.name) {
3147 if (i >= new_decls.items.len) break;3107 .@"comptime" => inst: {
3148 try match_stack.append(gpa, .{3108 if (comptime_decl_idx == comptime_decls.items.len) continue;
3149 .old_inst = old_decls.items[i],3109 defer comptime_decl_idx += 1;
3150 .new_inst = new_decls.items[i],3110 break :inst comptime_decls.items[comptime_decl_idx];
3151 });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 });
3152 }3146 }
3153 }3147 }
3154 }3148 }
...@@ -3457,8 +3451,6 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {...@@ -3457,8 +3451,6 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
3457 new_decl.src_line = 0;3451 new_decl.src_line = 0;
3458 new_decl.is_pub = true;3452 new_decl.is_pub = true;
3459 new_decl.is_exported = false;3453 new_decl.is_exported = false;
3460 new_decl.has_align = false;
3461 new_decl.has_linksection_or_addrspace = false;
3462 new_decl.ty = Type.type;3454 new_decl.ty = Type.type;
3463 new_decl.alignment = .none;3455 new_decl.alignment = .none;
3464 new_decl.@"linksection" = .none;3456 new_decl.@"linksection" = .none;
...@@ -3561,7 +3553,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {...@@ -3561,7 +3553,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
35613553
3562 const gpa = mod.gpa;3554 const gpa = mod.gpa;
3563 const zir = decl.getFileScope(mod).zir;3555 const zir = decl.getFileScope(mod).zir;
3564 const zir_datas = zir.instructions.items(.data);
35653556
3566 const builtin_type_target_index: InternPool.Index = blk: {3557 const builtin_type_target_index: InternPool.Index = blk: {
3567 const std_mod = mod.std_mod;3558 const std_mod = mod.std_mod;
...@@ -3639,11 +3630,9 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {...@@ -3639,11 +3630,9 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
3639 };3630 };
3640 defer block_scope.instructions.deinit(gpa);3631 defer block_scope.instructions.deinit(gpa);
36413632
3642 const zir_block_index = decl.zirBlockIndex(mod);3633 const decl_bodies = decl.zirBodies(mod);
3643 const inst_data = zir_datas[@intFromEnum(zir_block_index)].pl_node;3634
3644 const extra = zir.extraData(Zir.Inst.Block, inst_data.payload_index);3635 const result_ref = (try sema.analyzeBodyBreak(&block_scope, decl_bodies.value_body)).?.operand;
3645 const body = zir.extra[extra.end..][0..extra.data.body_len];
3646 const result_ref = (try sema.analyzeBodyBreak(&block_scope, @ptrCast(body))).?.operand;
3647 // We'll do some other bits with the Sema. Clear the type target index just3636 // We'll do some other bits with the Sema. Clear the type target index just
3648 // in case they analyze any type.3637 // in case they analyze any type.
3649 sema.builtin_type_target_index = .none;3638 sema.builtin_type_target_index = .none;
...@@ -3760,13 +3749,13 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {...@@ -3760,13 +3749,13 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
3760 decl.ty = decl_tv.ty;3749 decl.ty = decl_tv.ty;
3761 decl.val = Value.fromInterned((try decl_tv.val.intern(decl_tv.ty, mod)));3750 decl.val = Value.fromInterned((try decl_tv.val.intern(decl_tv.ty, mod)));
3762 decl.alignment = blk: {3751 decl.alignment = blk: {
3763 const align_ref = decl.zirAlignRef(mod);3752 const align_body = decl_bodies.align_body orelse break :blk .none;
3764 if (align_ref == .none) break :blk .none;3753 const align_ref = (try sema.analyzeBodyBreak(&block_scope, align_body)).?.operand;
3765 break :blk try sema.resolveAlign(&block_scope, align_src, align_ref);3754 break :blk try sema.resolveAlign(&block_scope, align_src, align_ref);
3766 };3755 };
3767 decl.@"linksection" = blk: {3756 decl.@"linksection" = blk: {
3768 const linksection_ref = decl.zirLinksectionRef(mod);3757 const linksection_body = decl_bodies.linksection_body orelse break :blk .none;
3769 if (linksection_ref == .none) break :blk .none;3758 const linksection_ref = (try sema.analyzeBodyBreak(&block_scope, linksection_body)).?.operand;
3770 const bytes = try sema.resolveConstString(&block_scope, section_src, linksection_ref, .{3759 const bytes = try sema.resolveConstString(&block_scope, section_src, linksection_ref, .{
3771 .needed_comptime_reason = "linksection must be comptime-known",3760 .needed_comptime_reason = "linksection must be comptime-known",
3772 });3761 });
...@@ -3786,15 +3775,15 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {...@@ -3786,15 +3775,15 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
3786 };3775 };
37873776
3788 const target = sema.mod.getTarget();3777 const target = sema.mod.getTarget();
3789 break :blk switch (decl.zirAddrspaceRef(mod)) {3778
3790 .none => switch (addrspace_ctx) {3779 const addrspace_body = decl_bodies.addrspace_body orelse break :blk switch (addrspace_ctx) {
3791 .function => target_util.defaultAddressSpace(target, .function),3780 .function => target_util.defaultAddressSpace(target, .function),
3792 .variable => target_util.defaultAddressSpace(target, .global_mutable),3781 .variable => target_util.defaultAddressSpace(target, .global_mutable),
3793 .constant => target_util.defaultAddressSpace(target, .global_constant),3782 .constant => target_util.defaultAddressSpace(target, .global_constant),
3794 else => unreachable,3783 else => unreachable,
3795 },
3796 else => |addrspace_ref| try sema.analyzeAddressSpace(&block_scope, address_space_src, addrspace_ref, addrspace_ctx),
3797 };3784 };
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);
3798 };3787 };
3799 decl.has_tv = true;3788 decl.has_tv = true;
3800 decl.analysis = .complete;3789 decl.analysis = .complete;
...@@ -4133,52 +4122,32 @@ fn newEmbedFile(...@@ -4133,52 +4122,32 @@ fn newEmbedFile(
4133}4122}
41344123
4135pub fn scanNamespace(4124pub fn scanNamespace(
4136 mod: *Module,4125 zcu: *Zcu,
4137 namespace_index: Namespace.Index,4126 namespace_index: Namespace.Index,
4138 extra_start: usize,4127 decls: []const Zir.Inst.Index,
4139 decls_len: u32,
4140 parent_decl: *Decl,4128 parent_decl: *Decl,
4141) Allocator.Error!usize {4129) Allocator.Error!void {
4142 const tracy = trace(@src());4130 const tracy = trace(@src());
4143 defer tracy.end();4131 defer tracy.end();
41444132
4145 const gpa = mod.gpa;4133 const gpa = zcu.gpa;
4146 const namespace = mod.namespacePtr(namespace_index);4134 const namespace = zcu.namespacePtr(namespace_index);
4147 const zir = namespace.file_scope.zir;
41484135
4149 try mod.comp.work_queue.ensureUnusedCapacity(decls_len);4136 try zcu.comp.work_queue.ensureUnusedCapacity(decls.len);
4150 try namespace.decls.ensureTotalCapacity(gpa, 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;
4157 var scan_decl_iter: ScanDeclIter = .{4139 var scan_decl_iter: ScanDeclIter = .{
4158 .module = mod,4140 .zcu = zcu,
4159 .namespace_index = namespace_index,4141 .namespace_index = namespace_index,
4160 .parent_decl = parent_decl,4142 .parent_decl = parent_decl,
4161 };4143 };
4162 while (decl_i < decls_len) : (decl_i += 1) {4144 for (decls) |decl_inst| {
4163 if (decl_i % 8 == 0) {4145 try scanDecl(&scan_decl_iter, decl_inst);
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);
4176 }4146 }
4177 return extra_index;
4178}4147}
41794148
4180const ScanDeclIter = struct {4149const ScanDeclIter = struct {
4181 module: *Module,4150 zcu: *Zcu,
4182 namespace_index: Namespace.Index,4151 namespace_index: Namespace.Index,
4183 parent_decl: *Decl,4152 parent_decl: *Decl,
4184 usingnamespace_index: usize = 0,4153 usingnamespace_index: usize = 0,
...@@ -4186,119 +4155,112 @@ const ScanDeclIter = struct {...@@ -4186,119 +4155,112 @@ const ScanDeclIter = struct {
4186 unnamed_test_index: usize = 0,4155 unnamed_test_index: usize = 0,
4187};4156};
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 {
4190 const tracy = trace(@src());4159 const tracy = trace(@src());
4191 defer tracy.end();4160 defer tracy.end();
41924161
4193 const mod = iter.module;4162 const zcu = iter.zcu;
4194 const namespace_index = iter.namespace_index;4163 const namespace_index = iter.namespace_index;
4195 const namespace = mod.namespacePtr(namespace_index);4164 const namespace = zcu.namespacePtr(namespace_index);
4196 const gpa = mod.gpa;4165 const gpa = zcu.gpa;
4197 const zir = namespace.file_scope.zir;4166 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: off4173 const line = iter.parent_decl.src_line + declaration.line_offset;
4201 const is_pub = (flags & 0b0001) != 0;4174 const decl_node = iter.parent_decl.relativeToNodeIndex(pl_node.src_node);
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);
42144175
4215 // Every Decl needs a name.4176 // Every Decl needs a name.
4216 var is_named_test = false;4177 const decl_name: InternPool.NullTerminatedString, const kind: Decl.Kind, const is_named_test: bool = switch (declaration.name) {
4217 var kind: Decl.Kind = .named;4178 .@"comptime" => info: {
4218 const decl_name: InternPool.NullTerminatedString = switch (decl_name_index) {4179 const i = iter.comptime_index;
4219 .empty => name: {4180 iter.comptime_index += 1;
4220 if (export_bit) {4181 break :info .{
4221 const i = iter.usingnamespace_index;4182 try ip.getOrPutStringFmt(gpa, "comptime_{d}", .{i}),
4222 iter.usingnamespace_index += 1;4183 .@"comptime",
4223 kind = .@"usingnamespace";4184 false,
4224 break :name try ip.getOrPutStringFmt(gpa, "usingnamespace_{d}", .{i});4185 };
4225 } else {4186 },
4226 const i = iter.comptime_index;4187 .@"usingnamespace" => info: {
4227 iter.comptime_index += 1;4188 const i = iter.usingnamespace_index;
4228 kind = .@"comptime";4189 iter.usingnamespace_index += 1;
4229 break :name try ip.getOrPutStringFmt(gpa, "comptime_{d}", .{i});4190 break :info .{
4230 }4191 try ip.getOrPutStringFmt(gpa, "usingnamespace_{d}", .{i}),
4192 .@"usingnamespace",
4193 false,
4194 };
4231 },4195 },
4232 .unnamed_test_decl => name: {4196 .unnamed_test => info: {
4233 const i = iter.unnamed_test_index;4197 const i = iter.unnamed_test_index;
4234 iter.unnamed_test_index += 1;4198 iter.unnamed_test_index += 1;
4235 kind = .@"test";4199 break :info .{
4236 break :name try ip.getOrPutStringFmt(gpa, "test_{d}", .{i});4200 try ip.getOrPutStringFmt(gpa, "test_{d}", .{i}),
4201 .@"test",
4202 false,
4203 };
4237 },4204 },
4238 .decltest => name: {4205 .decltest => info: {
4239 is_named_test = true;4206 assert(declaration.flags.has_doc_comment);
4240 const test_name = zir.nullTerminatedString(@enumFromInt(decl_doccomment_index));4207 const name = zir.nullTerminatedString(@enumFromInt(zir.extra[extra.end]));
4241 kind = .@"test";4208 break :info .{
4242 break :name try ip.getOrPutStringFmt(gpa, "decltest.{s}", .{test_name});4209 try ip.getOrPutStringFmt(gpa, "decltest.{s}", .{name}),
4210 .@"test",
4211 true,
4212 };
4243 },4213 },
4244 _ => name: {4214 _ => if (declaration.name.isNamedTest(zir)) .{
4245 const raw_name = zir.nullTerminatedString(decl_name_index);4215 try ip.getOrPutStringFmt(gpa, "test.{s}", .{zir.nullTerminatedString(declaration.name.toString(zir).?)}),
4246 if (raw_name.len == 0) {4216 .@"test",
4247 is_named_test = true;4217 true,
4248 const test_name = zir.nullTerminatedString(@enumFromInt(@intFromEnum(decl_name_index) + 1));4218 } else .{
4249 kind = .@"test";4219 try ip.getOrPutString(gpa, zir.nullTerminatedString(declaration.name.toString(zir).?)),
4250 break :name try ip.getOrPutStringFmt(gpa, "test.{s}", .{test_name});4220 .named,
4251 } else {4221 false,
4252 break :name try ip.getOrPutString(gpa, raw_name);
4253 }
4254 },4222 },
4255 };4223 };
42564224
4257 const is_exported = export_bit and decl_name_index != .empty;
4258 if (kind == .@"usingnamespace") try namespace.usingnamespace_set.ensureUnusedCapacity(gpa, 1);4225 if (kind == .@"usingnamespace") try namespace.usingnamespace_set.ensureUnusedCapacity(gpa, 1);
42594226
4260 // We create a Decl for it regardless of analysis status.4227 // We create a Decl for it regardless of analysis status.
4261 const gop = try namespace.decls.getOrPutContextAdapted(4228 const gop = try namespace.decls.getOrPutContextAdapted(
4262 gpa,4229 gpa,
4263 decl_name,4230 decl_name,
4264 DeclAdapter{ .mod = mod },4231 DeclAdapter{ .mod = zcu },
4265 Namespace.DeclContext{ .module = mod },4232 Namespace.DeclContext{ .module = zcu },
4266 );4233 );
4267 const comp = mod.comp;4234 const comp = zcu.comp;
4268 if (!gop.found_existing) {4235 if (!gop.found_existing) {
4269 const new_decl_index = try mod.allocateNewDecl(namespace_index, decl_node, iter.parent_decl.src_scope);4236 const new_decl_index = try zcu.allocateNewDecl(namespace_index, decl_node, iter.parent_decl.src_scope);
4270 const new_decl = mod.declPtr(new_decl_index);4237 const new_decl = zcu.declPtr(new_decl_index);
4271 new_decl.kind = kind;4238 new_decl.kind = kind;
4272 new_decl.name = decl_name;4239 new_decl.name = decl_name;
4273 if (kind == .@"usingnamespace") {4240 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);
4275 }4242 }
4276 new_decl.src_line = line;4243 new_decl.src_line = line;
4277 gop.key_ptr.* = new_decl_index;4244 gop.key_ptr.* = new_decl_index;
4278 // Exported decls, comptime decls, usingnamespace decls, and4245 // Exported decls, comptime decls, usingnamespace decls, and
4279 // test decls if in test mode, get analyzed.4246 // test decls if in test mode, get analyzed.
4280 const decl_mod = namespace.file_scope.mod;4247 const decl_mod = namespace.file_scope.mod;
4281 const want_analysis = is_exported or switch (decl_name_index) {4248 const want_analysis = declaration.flags.is_export or switch (kind) {
4282 .empty => true, // comptime or usingnamespace decl4249 .anon => unreachable,
4283 .unnamed_test_decl => blk: {4250 .@"comptime", .@"usingnamespace" => true,
4284 // test decl with no name. Skip the part where we check against4251 .named => false,
4285 // the test name filter.4252 .@"test" => a: {
4286 if (!comp.config.is_test) break :blk false;4253 if (!comp.config.is_test) break :a false;
4287 if (decl_mod != mod.main_mod) break :blk false;4254 if (decl_mod != zcu.main_mod) break :a false;
4288 try mod.test_functions.put(gpa, new_decl_index, {});4255 if (is_named_test) {
4289 break :blk true;4256 if (comp.test_filter) |test_filter| {
4290 },4257 if (mem.indexOf(u8, ip.stringToSlice(decl_name), test_filter) == null) {
4291 else => blk: {4258 break :a false;
4292 if (!is_named_test) break :blk false;4259 }
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;
4298 }4260 }
4299 }4261 }
4300 try mod.test_functions.put(gpa, new_decl_index, {});4262 try zcu.test_functions.put(gpa, new_decl_index, {});
4301 break :blk true;4263 break :a true;
4302 },4264 },
4303 };4265 };
4304 if (want_analysis) {4266 if (want_analysis) {
...@@ -4307,46 +4269,42 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err...@@ -4307,46 +4269,42 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err
4307 });4269 });
4308 comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl_index });4270 comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl_index });
4309 }4271 }
4310 new_decl.is_pub = is_pub;4272 new_decl.is_pub = declaration.flags.is_pub;
4311 new_decl.is_exported = is_exported;4273 new_decl.is_exported = declaration.flags.is_export;
4312 new_decl.has_align = has_align;4274 new_decl.zir_decl_index = decl_inst.toOptional();
4313 new_decl.has_linksection_or_addrspace = has_linksection_or_addrspace;
4314 new_decl.zir_decl_index = @enumFromInt(decl_sub_index);
4315 new_decl.alive = true; // This Decl corresponds to an AST node and therefore always alive.4275 new_decl.alive = true; // This Decl corresponds to an AST node and therefore always alive.
4316 return;4276 return;
4317 }4277 }
4318 const decl_index = gop.key_ptr.*;4278 const decl_index = gop.key_ptr.*;
4319 const decl = mod.declPtr(decl_index);4279 const decl = zcu.declPtr(decl_index);
4320 if (kind == .@"test") {4280 if (kind == .@"test") {
4321 const src_loc = SrcLoc{4281 const src_loc = SrcLoc{
4322 .file_scope = decl.getFileScope(mod),4282 .file_scope = decl.getFileScope(zcu),
4323 .parent_decl_node = decl.src_node,4283 .parent_decl_node = decl.src_node,
4324 .lazy = .{ .token_offset = 1 },4284 .lazy = .{ .token_offset = 1 },
4325 };4285 };
4326 const msg = try ErrorMsg.create(gpa, src_loc, "duplicate test name: {}", .{4286 const msg = try ErrorMsg.create(gpa, src_loc, "duplicate test name: {}", .{
4327 decl_name.fmt(&mod.intern_pool),4287 decl_name.fmt(ip),
4328 });4288 });
4329 errdefer msg.destroy(gpa);4289 errdefer msg.destroy(gpa);
4330 try mod.failed_decls.putNoClobber(gpa, decl_index, msg);4290 try zcu.failed_decls.putNoClobber(gpa, decl_index, msg);
4331 const other_src_loc = SrcLoc{4291 const other_src_loc = SrcLoc{
4332 .file_scope = namespace.file_scope,4292 .file_scope = namespace.file_scope,
4333 .parent_decl_node = decl_node,4293 .parent_decl_node = decl_node,
4334 .lazy = .{ .token_offset = 1 },4294 .lazy = .{ .token_offset = 1 },
4335 };4295 };
4336 try mod.errNoteNonLazy(other_src_loc, msg, "other test here", .{});4296 try zcu.errNoteNonLazy(other_src_loc, msg, "other test here", .{});
4337 }4297 }
4338 // Update the AST node of the decl; even if its contents are unchanged, it may4298 // Update the AST node of the decl; even if its contents are unchanged, it may
4339 // have been re-ordered.4299 // have been re-ordered.
4340 decl.src_node = decl_node;4300 decl.src_node = decl_node;
4341 decl.src_line = line;4301 decl.src_line = line;
43424302
4343 decl.is_pub = is_pub;4303 decl.is_pub = declaration.flags.is_pub;
4344 decl.is_exported = is_exported;4304 decl.is_exported = declaration.flags.is_export;
4345 decl.kind = kind;4305 decl.kind = kind;
4346 decl.has_align = has_align;4306 decl.zir_decl_index = decl_inst.toOptional();
4347 decl.has_linksection_or_addrspace = has_linksection_or_addrspace;4307 if (decl.getOwnedFunction(zcu) != null) {
4348 decl.zir_decl_index = @enumFromInt(decl_sub_index);
4349 if (decl.getOwnedFunction(mod) != null) {
4350 // TODO Look into detecting when this would be unnecessary by storing enough state4308 // TODO Look into detecting when this would be unnecessary by storing enough state
4351 // in `Decl` to notice that the line number did not change.4309 // in `Decl` to notice that the line number did not change.
4352 comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl_index });4310 comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl_index });
...@@ -4730,8 +4688,6 @@ pub fn allocateNewDecl(...@@ -4730,8 +4688,6 @@ pub fn allocateNewDecl(
4730 .generation = 0,4688 .generation = 0,
4731 .is_pub = false,4689 .is_pub = false,
4732 .is_exported = false,4690 .is_exported = false,
4733 .has_linksection_or_addrspace = false,
4734 .has_align = false,
4735 .alive = false,4691 .alive = false,
4736 .kind = .anon,4692 .kind = .anon,
4737 });4693 });
src/Sema.zig+20-12
...@@ -1224,6 +1224,10 @@ fn analyzeBodyInner(...@@ -1224,6 +1224,10 @@ fn analyzeBodyInner(
1224 .trap => break sema.zirTrap(block, inst),1224 .trap => break sema.zirTrap(block, inst),
1225 // zig fmt: on1225 // 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
1227 .extended => ext: {1231 .extended => ext: {
1228 const extended = datas[@intFromEnum(inst)].extended;1232 const extended = datas[@intFromEnum(inst)].extended;
1229 break :ext switch (extended.opcode) {1233 break :ext switch (extended.opcode) {
...@@ -2736,7 +2740,9 @@ pub fn getStructType(...@@ -2736,7 +2740,9 @@ pub fn getStructType(
2736 }2740 }
2737 }2741 }
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
2741 const ty = try ip.getStructType(gpa, .{2747 const ty = try ip.getStructType(gpa, .{
2742 .decl = decl,2748 .decl = decl,
...@@ -2973,7 +2979,9 @@ fn zirEnumDecl(...@@ -2973,7 +2979,9 @@ fn zirEnumDecl(
2973 const new_namespace = mod.namespacePtr(new_namespace_index);2979 const new_namespace = mod.namespacePtr(new_namespace_index);
2974 errdefer if (!done) mod.destroyNamespace(new_namespace_index);2980 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
2978 const body = sema.code.bodySlice(extra_index, body_len);2986 const body = sema.code.bodySlice(extra_index, body_len);
2979 extra_index += body.len;2987 extra_index += body.len;
...@@ -3263,7 +3271,8 @@ fn zirUnionDecl(...@@ -3263,7 +3271,8 @@ fn zirUnionDecl(
3263 new_decl.val = Value.fromInterned(union_ty);3271 new_decl.val = Value.fromInterned(union_ty);
3264 new_namespace.ty = Type.fromInterned(union_ty);3272 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
3268 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);3277 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
3269 try mod.finalizeAnonDecl(new_decl_index);3278 try mod.finalizeAnonDecl(new_decl_index);
...@@ -3326,7 +3335,8 @@ fn zirOpaqueDecl(...@@ -3326,7 +3335,8 @@ fn zirOpaqueDecl(
3326 new_decl.val = Value.fromInterned(opaque_ty);3335 new_decl.val = Value.fromInterned(opaque_ty);
3327 new_namespace.ty = Type.fromInterned(opaque_ty);3336 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
3331 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);3341 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
3332 try mod.finalizeAnonDecl(new_decl_index);3342 try mod.finalizeAnonDecl(new_decl_index);
...@@ -36331,9 +36341,7 @@ fn structZirInfo(zir: Zir, zir_index: Zir.Inst.Index) struct {...@@ -36331,9 +36341,7 @@ fn structZirInfo(zir: Zir, zir_index: Zir.Inst.Index) struct {
36331 }36341 }
3633236342
36333 // Skip over decls.36343 // Skip over decls.
36334 var decls_it = zir.declIteratorInner(extra_index, decls_len);36344 extra_index += decls_len;
36335 while (decls_it.next()) |_| {}
36336 extra_index = decls_it.extra_index;
3633736345
36338 return .{ fields_len, small, extra_index };36346 return .{ fields_len, small, extra_index };
36339}36347}
...@@ -36802,9 +36810,7 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un...@@ -36802,9 +36810,7 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un
36802 } else 0;36810 } else 0;
3680336811
36804 // Skip over decls.36812 // Skip over decls.
36805 var decls_it = zir.declIteratorInner(extra_index, decls_len);36813 extra_index += decls_len;
36806 while (decls_it.next()) |_| {}
36807 extra_index = decls_it.extra_index;
3680836814
36809 const body = zir.bodySlice(extra_index, body_len);36815 const body = zir.bodySlice(extra_index, body_len);
36810 extra_index += body.len;36816 extra_index += body.len;
...@@ -37801,10 +37807,12 @@ pub fn analyzeAddressSpace(...@@ -37801,10 +37807,12 @@ pub fn analyzeAddressSpace(
37801 ctx: AddressSpaceContext,37807 ctx: AddressSpaceContext,
37802) !std.builtin.AddressSpace {37808) !std.builtin.AddressSpace {
37803 const mod = sema.mod;37809 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, .{
37805 .needed_comptime_reason = "address space must be comptime-known",37813 .needed_comptime_reason = "address space must be comptime-known",
37806 });37814 });
37807 const address_space = mod.toEnum(std.builtin.AddressSpace, addrspace_tv.val);37815 const address_space = mod.toEnum(std.builtin.AddressSpace, addrspace_val);
37808 const target = sema.mod.getTarget();37816 const target = sema.mod.getTarget();
37809 const arch = target.cpu.arch;37817 const arch = target.cpu.arch;
3781037818
src/Zir.zig+213-187
...@@ -30,7 +30,7 @@ instructions: std.MultiArrayList(Inst).Slice,...@@ -30,7 +30,7 @@ instructions: std.MultiArrayList(Inst).Slice,
30/// is referencing the data here whether they want to store both index and length,30/// is referencing the data here whether they want to store both index and length,
31/// thus allowing null bytes, or store only index, and use null-termination. The31/// thus allowing null bytes, or store only index, and use null-termination. The
32/// `string_bytes` array is agnostic to either usage.32/// `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.
34string_bytes: []u8,34string_bytes: []u8,
35/// The meaning of this data is determined by `Inst.Tag` value.35/// The meaning of this data is determined by `Inst.Tag` value.
36/// The first few indexes are reserved. See `ExtraIndex` for the values.36/// The first few indexes are reserved. See `ExtraIndex` for the values.
...@@ -60,21 +60,6 @@ pub const ExtraIndex = enum(u32) {...@@ -60,21 +60,6 @@ pub const ExtraIndex = enum(u32) {
60 imports,60 imports,
6161
62 _,62 _,
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 }
78};63};
7964
80fn ExtraData(comptime T: type) type {65fn ExtraData(comptime T: type) type {
...@@ -93,6 +78,7 @@ pub fn extraData(code: Zir, comptime T: type, index: usize) ExtraData(T) {...@@ -93,6 +78,7 @@ pub fn extraData(code: Zir, comptime T: type, index: usize) ExtraData(T) {
9378
94 Inst.Ref,79 Inst.Ref,
95 Inst.Index,80 Inst.Index,
81 Inst.Declaration.Name,
96 NullTerminatedString,82 NullTerminatedString,
97 => @enumFromInt(code.extra[i]),83 => @enumFromInt(code.extra[i]),
9884
...@@ -102,6 +88,7 @@ pub fn extraData(code: Zir, comptime T: type, index: usize) ExtraData(T) {...@@ -102,6 +88,7 @@ pub fn extraData(code: Zir, comptime T: type, index: usize) ExtraData(T) {
102 Inst.SwitchBlock.Bits,88 Inst.SwitchBlock.Bits,
103 Inst.SwitchBlockErrUnion.Bits,89 Inst.SwitchBlockErrUnion.Bits,
104 Inst.FuncFancy.Bits,90 Inst.FuncFancy.Bits,
91 Inst.Declaration.Flags,
105 => @bitCast(code.extra[i]),92 => @bitCast(code.extra[i]),
10693
107 else => @compileError("bad field type"),94 else => @compileError("bad field type"),
...@@ -116,8 +103,6 @@ pub fn extraData(code: Zir, comptime T: type, index: usize) ExtraData(T) {...@@ -116,8 +103,6 @@ pub fn extraData(code: Zir, comptime T: type, index: usize) ExtraData(T) {
116103
117pub const NullTerminatedString = enum(u32) {104pub const NullTerminatedString = enum(u32) {
118 empty = 0,105 empty = 0,
119 unnamed_test_decl = 1,
120 decltest = 2,
121 _,106 _,
122};107};
123108
...@@ -304,6 +289,12 @@ pub const Inst = struct {...@@ -304,6 +289,12 @@ pub const Inst = struct {
304 /// a noreturn instruction.289 /// a noreturn instruction.
305 /// Uses the `pl_node` union field. Payload is `Block`.290 /// Uses the `pl_node` union field. Payload is `Block`.
306 block_inline,291 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,
307 /// Implements `suspend {...}`.298 /// Implements `suspend {...}`.
308 /// Uses the `pl_node` union field. Payload is `Block`.299 /// Uses the `pl_node` union field. Payload is `Block`.
309 suspend_block,300 suspend_block,
...@@ -1092,6 +1083,7 @@ pub const Inst = struct {...@@ -1092,6 +1083,7 @@ pub const Inst = struct {
1092 .block,1083 .block,
1093 .block_comptime,1084 .block_comptime,
1094 .block_inline,1085 .block_inline,
1086 .declaration,
1095 .suspend_block,1087 .suspend_block,
1096 .loop,1088 .loop,
1097 .bool_br_and,1089 .bool_br_and,
...@@ -1405,6 +1397,7 @@ pub const Inst = struct {...@@ -1405,6 +1397,7 @@ pub const Inst = struct {
1405 .block,1397 .block,
1406 .block_comptime,1398 .block_comptime,
1407 .block_inline,1399 .block_inline,
1400 .declaration,
1408 .suspend_block,1401 .suspend_block,
1409 .loop,1402 .loop,
1410 .bool_br_and,1403 .bool_br_and,
...@@ -1639,6 +1632,7 @@ pub const Inst = struct {...@@ -1639,6 +1632,7 @@ pub const Inst = struct {
1639 .block = .pl_node,1632 .block = .pl_node,
1640 .block_comptime = .pl_node,1633 .block_comptime = .pl_node,
1641 .block_inline = .pl_node,1634 .block_inline = .pl_node,
1635 .declaration = .pl_node,
1642 .suspend_block = .pl_node,1636 .suspend_block = .pl_node,
1643 .bool_not = .un_node,1637 .bool_not = .un_node,
1644 .bool_br_and = .bool_br,1638 .bool_br_and = .bool_br,
...@@ -2508,6 +2502,7 @@ pub const Inst = struct {...@@ -2508,6 +2502,7 @@ pub const Inst = struct {
2508 /// If this is 1 it means return_type is a simple Ref2502 /// If this is 1 it means return_type is a simple Ref
2509 ret_body_len: u32,2503 ret_body_len: u32,
2510 /// Points to the block that contains the param instructions for this function.2504 /// 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.
2511 param_block: Index,2506 param_block: Index,
2512 body_len: u32,2507 body_len: u32,
25132508
...@@ -2565,6 +2560,7 @@ pub const Inst = struct {...@@ -2565,6 +2560,7 @@ pub const Inst = struct {
2565 /// 18. src_locs: Func.SrcLocs // if body_len != 02560 /// 18. src_locs: Func.SrcLocs // if body_len != 0
2566 pub const FuncFancy = struct {2561 pub const FuncFancy = struct {
2567 /// Points to the block that contains the param instructions for this function.2562 /// 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.
2568 param_block: Index,2564 param_block: Index,
2569 body_len: u32,2565 body_len: u32,
2570 bits: Bits,2566 bits: Bits,
...@@ -2632,6 +2628,116 @@ pub const Inst = struct {...@@ -2632,6 +2628,116 @@ pub const Inst = struct {
2632 body_len: u32,2628 body_len: u32,
2633 };2629 };
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
2635 /// Stored inside extra, with trailing arguments according to `args_len`.2741 /// Stored inside extra, with trailing arguments according to `args_len`.
2636 /// Implicit 0. arg_0_start: u32, // always same as `args_len`2742 /// Implicit 0. arg_0_start: u32, // always same as `args_len`
2637 /// 1. arg_end: u32, // for each `args_len`2743 /// 1. arg_end: u32, // for each `args_len`
...@@ -2913,37 +3019,14 @@ pub const Inst = struct {...@@ -2913,37 +3019,14 @@ pub const Inst = struct {
2913 /// 3. backing_int_body_len: u32, // if has_backing_int3019 /// 3. backing_int_body_len: u32, // if has_backing_int
2914 /// 4. backing_int_ref: Ref, // if has_backing_int and backing_int_body_len is 03020 /// 4. backing_int_ref: Ref, // if has_backing_int and backing_int_body_len is 0
2915 /// 5. backing_int_body_inst: Inst, // if has_backing_int and backing_int_body_len is > 03021 /// 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 decls3022 /// 6. decl: Index, // for every decls_len; points to a `declaration` instruction
2917 /// - sets of 4 bits:3023 /// 7. flags: u32 // for every 8 fields
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
2941 /// - sets of 4 bits:3024 /// - sets of 4 bits:
2942 /// 0b000X: whether corresponding field has an align expression3025 /// 0b000X: whether corresponding field has an align expression
2943 /// 0b00X0: whether corresponding field has a default expression3026 /// 0b00X0: whether corresponding field has a default expression
2944 /// 0b0X00: whether corresponding field is comptime3027 /// 0b0X00: whether corresponding field is comptime
2945 /// 0bX000: whether corresponding field has a type expression3028 /// 0bX000: whether corresponding field has a type expression
2946 /// 9. fields: { // for every fields_len3029 /// 8. fields: { // for every fields_len
2947 /// field_name: u32, // if !is_tuple3030 /// field_name: u32, // if !is_tuple
2948 /// doc_comment: NullTerminatedString, // .empty if no doc comment3031 /// doc_comment: NullTerminatedString, // .empty if no doc comment
2949 /// field_type: Ref, // if corresponding bit is not set. none means anytype.3032 /// field_type: Ref, // if corresponding bit is not set. none means anytype.
...@@ -3009,33 +3092,11 @@ pub const Inst = struct {...@@ -3009,33 +3092,11 @@ pub const Inst = struct {
3009 /// 2. body_len: u32, // if has_body_len3092 /// 2. body_len: u32, // if has_body_len
3010 /// 3. fields_len: u32, // if has_fields_len3093 /// 3. fields_len: u32, // if has_fields_len
3011 /// 4. decls_len: u32, // if has_decls_len3094 /// 4. decls_len: u32, // if has_decls_len
3012 /// 5. decl_bits: u32 // for every 8 decls3095 /// 5. decl: Index, // for every decls_len; points to a `declaration` instruction
3013 /// - sets of 4 bits:3096 /// 6. inst: Index // for every body_len
3014 /// 0b000X: whether corresponding decl is pub3097 /// 7. has_bits: u32 // for every 32 fields
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
3037 /// - the bit is whether corresponding field has an value expression3098 /// - the bit is whether corresponding field has an value expression
3038 /// 9. fields: { // for every fields_len3099 /// 8. fields: { // for every fields_len
3039 /// field_name: u32,3100 /// field_name: u32,
3040 /// doc_comment: u32, // .empty if no doc_comment3101 /// doc_comment: u32, // .empty if no doc_comment
3041 /// value: Ref, // if corresponding bit is set3102 /// value: Ref, // if corresponding bit is set
...@@ -3059,37 +3120,15 @@ pub const Inst = struct {...@@ -3059,37 +3120,15 @@ pub const Inst = struct {
3059 /// 2. body_len: u32, // if has_body_len3120 /// 2. body_len: u32, // if has_body_len
3060 /// 3. fields_len: u32, // if has_fields_len3121 /// 3. fields_len: u32, // if has_fields_len
3061 /// 4. decls_len: u32, // if has_decls_len3122 /// 4. decls_len: u32, // if has_decls_len
3062 /// 5. decl_bits: u32 // for every 8 decls3123 /// 5. decl: Index, // for every decls_len; points to a `declaration` instruction
3063 /// - sets of 4 bits:3124 /// 6. inst: Index // for every body_len
3064 /// 0b000X: whether corresponding decl is pub3125 /// 7. has_bits: u32 // for every 8 fields
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
3087 /// - sets of 4 bits:3126 /// - sets of 4 bits:
3088 /// 0b000X: whether corresponding field has a type expression3127 /// 0b000X: whether corresponding field has a type expression
3089 /// 0b00X0: whether corresponding field has a align expression3128 /// 0b00X0: whether corresponding field has a align expression
3090 /// 0b0X00: whether corresponding field has a tag value expression3129 /// 0b0X00: whether corresponding field has a tag value expression
3091 /// 0bX000: unused3130 /// 0bX000: unused
3092 /// 9. fields: { // for every fields_len3131 /// 8. fields: { // for every fields_len
3093 /// field_name: NullTerminatedString, // null terminated string index3132 /// field_name: NullTerminatedString, // null terminated string index
3094 /// doc_comment: NullTerminatedString, // .empty if no doc comment3133 /// doc_comment: NullTerminatedString, // .empty if no doc comment
3095 /// field_type: Ref, // if corresponding bit is set3134 /// field_type: Ref, // if corresponding bit is set
...@@ -3121,29 +3160,7 @@ pub const Inst = struct {...@@ -3121,29 +3160,7 @@ pub const Inst = struct {
3121 /// Trailing:3160 /// Trailing:
3122 /// 0. src_node: i32, // if has_src_node3161 /// 0. src_node: i32, // if has_src_node
3123 /// 1. decls_len: u32, // if has_decls_len3162 /// 1. decls_len: u32, // if has_decls_len
3124 /// 2. decl_bits: u32 // for every 8 decls3163 /// 2. decl: Index, // for every decls_len; points to a `declaration` instruction
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 /// }
3147 pub const OpaqueDecl = struct {3164 pub const OpaqueDecl = struct {
3148 pub const Small = packed struct {3165 pub const Small = packed struct {
3149 has_src_node: bool,3166 has_src_node: bool,
...@@ -3407,44 +3424,17 @@ pub const Inst = struct {...@@ -3407,44 +3424,17 @@ pub const Inst = struct {
3407pub const SpecialProng = enum { none, @"else", under };3424pub const SpecialProng = enum { none, @"else", under };
34083425
3409pub const DeclIterator = struct {3426pub const DeclIterator = struct {
3410 extra_index: usize,3427 extra_index: u32,
3411 bit_bag_index: usize,3428 decls_remaining: u32,
3412 cur_bit_bag: u32,
3413 decl_i: u32,
3414 decls_len: u32,
3415 zir: Zir,3429 zir: Zir,
34163430
3417 pub const Item = struct {3431 pub fn next(it: *DeclIterator) ?Inst.Index {
3418 name: [:0]const u8,3432 if (it.decls_remaining == 0) return null;
3419 sub_index: ExtraIndex,3433 const decl_inst: Zir.Inst.Index = @enumFromInt(it.zir.extra[it.extra_index]);
3420 flags: u4,3434 it.extra_index += 1;
3421 };3435 it.decls_remaining -= 1;
34223436 assert(it.zir.instructions.items(.tag)[@intFromEnum(decl_inst)] == .declaration);
3423 pub fn next(it: *DeclIterator) ?Item {3437 return decl_inst;
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 };
3448 }3438 }
3449};3439};
34503440
...@@ -3454,14 +3444,18 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {...@@ -3454,14 +3444,18 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
3454 switch (tags[@intFromEnum(decl_inst)]) {3444 switch (tags[@intFromEnum(decl_inst)]) {
3455 // Functions are allowed and yield no iterations.3445 // Functions are allowed and yield no iterations.
3456 // There is one case matching this in the extended instruction set below.3446 // 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
3459 .extended => {3453 .extended => {
3460 const extended = datas[@intFromEnum(decl_inst)].extended;3454 const extended = datas[@intFromEnum(decl_inst)].extended;
3461 switch (extended.opcode) {3455 switch (extended.opcode) {
3462 .struct_decl => {3456 .struct_decl => {
3463 const small: Inst.StructDecl.Small = @bitCast(extended.small);3457 const small: Inst.StructDecl.Small = @bitCast(extended.small);
3464 var extra_index: usize = extended.operand;3458 var extra_index: u32 = extended.operand;
3465 extra_index += @intFromBool(small.has_src_node);3459 extra_index += @intFromBool(small.has_src_node);
3466 extra_index += @intFromBool(small.has_fields_len);3460 extra_index += @intFromBool(small.has_fields_len);
3467 const decls_len = if (small.has_decls_len) decls_len: {3461 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 {...@@ -3480,11 +3474,15 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
3480 }3474 }
3481 }3475 }
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 };
3484 },3482 },
3485 .enum_decl => {3483 .enum_decl => {
3486 const small: Inst.EnumDecl.Small = @bitCast(extended.small);3484 const small: Inst.EnumDecl.Small = @bitCast(extended.small);
3487 var extra_index: usize = extended.operand;3485 var extra_index: u32 = extended.operand;
3488 extra_index += @intFromBool(small.has_src_node);3486 extra_index += @intFromBool(small.has_src_node);
3489 extra_index += @intFromBool(small.has_tag_type);3487 extra_index += @intFromBool(small.has_tag_type);
3490 extra_index += @intFromBool(small.has_body_len);3488 extra_index += @intFromBool(small.has_body_len);
...@@ -3495,11 +3493,15 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {...@@ -3495,11 +3493,15 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
3495 break :decls_len decls_len;3493 break :decls_len decls_len;
3496 } else 0;3494 } 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 };
3499 },3501 },
3500 .union_decl => {3502 .union_decl => {
3501 const small: Inst.UnionDecl.Small = @bitCast(extended.small);3503 const small: Inst.UnionDecl.Small = @bitCast(extended.small);
3502 var extra_index: usize = extended.operand;3504 var extra_index: u32 = extended.operand;
3503 extra_index += @intFromBool(small.has_src_node);3505 extra_index += @intFromBool(small.has_src_node);
3504 extra_index += @intFromBool(small.has_tag_type);3506 extra_index += @intFromBool(small.has_tag_type);
3505 extra_index += @intFromBool(small.has_body_len);3507 extra_index += @intFromBool(small.has_body_len);
...@@ -3510,11 +3512,15 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {...@@ -3510,11 +3512,15 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
3510 break :decls_len decls_len;3512 break :decls_len decls_len;
3511 } else 0;3513 } 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 };
3514 },3520 },
3515 .opaque_decl => {3521 .opaque_decl => {
3516 const small: Inst.OpaqueDecl.Small = @bitCast(extended.small);3522 const small: Inst.OpaqueDecl.Small = @bitCast(extended.small);
3517 var extra_index: usize = extended.operand;3523 var extra_index: u32 = extended.operand;
3518 extra_index += @intFromBool(small.has_src_node);3524 extra_index += @intFromBool(small.has_src_node);
3519 const decls_len = if (small.has_decls_len) decls_len: {3525 const decls_len = if (small.has_decls_len) decls_len: {
3520 const decls_len = zir.extra[extra_index];3526 const decls_len = zir.extra[extra_index];
...@@ -3522,7 +3528,11 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {...@@ -3522,7 +3528,11 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
3522 break :decls_len decls_len;3528 break :decls_len decls_len;
3523 } else 0;3529 } 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 };
3526 },3536 },
3527 else => unreachable,3537 else => unreachable,
3528 }3538 }
...@@ -3531,25 +3541,17 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {...@@ -3531,25 +3541,17 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
3531 }3541 }
3532}3542}
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
3546/// The iterator would have to allocate memory anyway to iterate. So here we populate3544/// The iterator would have to allocate memory anyway to iterate. So here we populate
3547/// an ArrayList as the result.3545/// an ArrayList as the result.
3548pub fn findDecls(zir: Zir, list: *std.ArrayList(Inst.Index), decl_sub_index: ExtraIndex) !void {3546pub fn findDecls(zir: Zir, list: *std.ArrayList(Inst.Index), decl_inst: Zir.Inst.Index) !void {
3549 const block_inst: Zir.Inst.Index = @enumFromInt(zir.extra[@intFromEnum(decl_sub_index) + 6]);
3550 list.clearRetainingCapacity();3547 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);
3553}3555}
35543556
3555fn findDeclsInner(3557fn findDeclsInner(
...@@ -3791,8 +3793,17 @@ pub fn getParamBody(zir: Zir, fn_inst: Inst.Index) []const Zir.Inst.Index {...@@ -3791,8 +3793,17 @@ pub fn getParamBody(zir: Zir, fn_inst: Inst.Index) []const Zir.Inst.Index {
3791 else => unreachable,3793 else => unreachable,
3792 };3794 };
37933795
3794 const param_block = zir.extraData(Inst.Block, datas[@intFromEnum(param_block_index)].pl_node.payload_index);3796 switch (tags[@intFromEnum(param_block_index)]) {
3795 return zir.bodySlice(param_block.end, param_block.data.body_len);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 }
3796}3807}
37973808
3798pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {3809pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
...@@ -3888,12 +3899,17 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {...@@ -3888,12 +3899,17 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
3888 },3899 },
3889 else => unreachable,3900 else => unreachable,
3890 };3901 };
3891 switch (tags[@intFromEnum(info.param_block)]) {3902 const param_body = switch (tags[@intFromEnum(info.param_block)]) {
3892 .block, .block_comptime, .block_inline => {}, // OK3903 .block, .block_comptime, .block_inline => param_body: {
3893 else => unreachable, // assertion failure3904 const param_block = zir.extraData(Inst.Block, datas[@intFromEnum(info.param_block)].pl_node.payload_index);
3894 }3905 break :param_body zir.bodySlice(param_block.end, param_block.data.body_len);
3895 const param_block = zir.extraData(Inst.Block, datas[@intFromEnum(info.param_block)].pl_node.payload_index);3906 },
3896 const param_body = zir.bodySlice(param_block.end, param_block.data.body_len);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 };
3897 var total_params_len: u32 = 0;3913 var total_params_len: u32 = 0;
3898 for (param_body) |inst| {3914 for (param_body) |inst| {
3899 switch (tags[@intFromEnum(inst)]) {3915 switch (tags[@intFromEnum(inst)]) {
...@@ -3912,3 +3928,13 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {...@@ -3912,3 +3928,13 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
3912 .total_params_len = total_params_len,3928 .total_params_len = total_params_len,
3913 };3929 };
3914}3930}
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(...@@ -6856,10 +6856,7 @@ pub fn cmdChangelist(
6856 var inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{};6856 var inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{};
6857 defer inst_map.deinit(gpa);6857 defer inst_map.deinit(gpa);
68586858
6859 var extra_map: std.AutoHashMapUnmanaged(Zir.ExtraIndex, Zir.ExtraIndex) = .{};6859 try Module.mapOldZirToNew(gpa, old_zir, file.zir, &inst_map);
6860 defer extra_map.deinit(gpa);
6861
6862 try Module.mapOldZirToNew(gpa, old_zir, file.zir, &inst_map, &extra_map);
68636860
6864 var bw = io.bufferedWriter(io.getStdOut().writer());6861 var bw = io.bufferedWriter(io.getStdOut().writer());
6865 const stdout = bw.writer();6862 const stdout = bw.writer();
...@@ -6868,16 +6865,8 @@ pub fn cmdChangelist(...@@ -6868,16 +6865,8 @@ pub fn cmdChangelist(
6868 var it = inst_map.iterator();6865 var it = inst_map.iterator();
6869 while (it.next()) |entry| {6866 while (it.next()) |entry| {
6870 try stdout.print(" %{d} => %{d}\n", .{6867 try stdout.print(" %{d} => %{d}\n", .{
6871 entry.key_ptr.*, entry.value_ptr.*,6868 @intFromEnum(entry.key_ptr.*),
6872 });6869 @intFromEnum(entry.value_ptr.*),
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.*,
6881 });6870 });
6882 }6871 }
6883 }6872 }
src/print_zir.zig+67-122
...@@ -521,6 +521,8 @@ const Writer = struct {...@@ -521,6 +521,8 @@ const Writer = struct {
521 .@"defer" => try self.writeDefer(stream, inst),521 .@"defer" => try self.writeDefer(stream, inst),
522 .defer_err_code => try self.writeDeferErrCode(stream, inst),522 .defer_err_code => try self.writeDeferErrCode(stream, inst),
523523
524 .declaration => try self.writeDeclaration(stream, inst),
525
524 .extended => try self.writeExtended(stream, inst),526 .extended => try self.writeExtended(stream, inst),
525 }527 }
526 }528 }
...@@ -1454,8 +1456,9 @@ const Writer = struct {...@@ -1454,8 +1456,9 @@ const Writer = struct {
14541456
1455 try stream.writeAll("{\n");1457 try stream.writeAll("{\n");
1456 self.indent += 2;1458 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));
1458 self.indent -= 2;1460 self.indent -= 2;
1461 extra_index += decls_len;
1459 try stream.writeByteNTimes(' ', self.indent);1462 try stream.writeByteNTimes(' ', self.indent);
1460 try stream.writeAll("}, ");1463 try stream.writeAll("}, ");
1461 }1464 }
...@@ -1634,8 +1637,9 @@ const Writer = struct {...@@ -1634,8 +1637,9 @@ const Writer = struct {
16341637
1635 try stream.writeAll("{\n");1638 try stream.writeAll("{\n");
1636 self.indent += 2;1639 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));
1638 self.indent -= 2;1641 self.indent -= 2;
1642 extra_index += decls_len;
1639 try stream.writeByteNTimes(' ', self.indent);1643 try stream.writeByteNTimes(' ', self.indent);
1640 try stream.writeAll("}");1644 try stream.writeAll("}");
1641 }1645 }
...@@ -1727,124 +1731,6 @@ const Writer = struct {...@@ -1727,124 +1731,6 @@ const Writer = struct {
1727 try self.writeSrcNode(stream, src_node);1731 try self.writeSrcNode(stream, src_node);
1728 }1732 }
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
1848 fn writeEnumDecl(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {1734 fn writeEnumDecl(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
1849 const small = @as(Zir.Inst.EnumDecl.Small, @bitCast(extended.small));1735 const small = @as(Zir.Inst.EnumDecl.Small, @bitCast(extended.small));
1850 var extra_index: usize = extended.operand;1736 var extra_index: usize = extended.operand;
...@@ -1891,8 +1777,9 @@ const Writer = struct {...@@ -1891,8 +1777,9 @@ const Writer = struct {
18911777
1892 try stream.writeAll("{\n");1778 try stream.writeAll("{\n");
1893 self.indent += 2;1779 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));
1895 self.indent -= 2;1781 self.indent -= 2;
1782 extra_index += decls_len;
1896 try stream.writeByteNTimes(' ', self.indent);1783 try stream.writeByteNTimes(' ', self.indent);
1897 try stream.writeAll("}, ");1784 try stream.writeAll("}, ");
1898 }1785 }
...@@ -1988,7 +1875,7 @@ const Writer = struct {...@@ -1988,7 +1875,7 @@ const Writer = struct {
19881875
1989 try stream.writeAll("{\n");1876 try stream.writeAll("{\n");
1990 self.indent += 2;1877 self.indent += 2;
1991 _ = try self.writeDecls(stream, decls_len, extra_index);1878 try self.writeBody(stream, self.code.bodySlice(extra_index, decls_len));
1992 self.indent -= 2;1879 self.indent -= 2;
1993 try stream.writeByteNTimes(' ', self.indent);1880 try stream.writeByteNTimes(' ', self.indent);
1994 try stream.writeAll("})");1881 try stream.writeAll("})");
...@@ -2762,6 +2649,64 @@ const Writer = struct {...@@ -2762,6 +2649,64 @@ const Writer = struct {
2762 try stream.writeByte(')');2649 try stream.writeByte(')');
2763 }2650 }
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
2765 fn writeInstRef(self: *Writer, stream: anytype, ref: Zir.Inst.Ref) !void {2710 fn writeInstRef(self: *Writer, stream: anytype, ref: Zir.Inst.Ref) !void {
2766 if (ref == .none) {2711 if (ref == .none) {
2767 return stream.writeAll(".none");2712 return stream.writeAll(".none");