authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-16 14:44:02-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-16 14:48:10-07:00
log01b4bf34ea4f37d8b778bb2413ac1fc445f8bead
tree6075a5f6e35448ab1899b34a559d5c1ce9e27bd2
parentcf57e8223f06f6b305e7274445cf935b1ed312d2

stage2: AstGen improvements

* AstGen: represent compile errors in ZIR rather than returning `error.AnalysisFail`. * ZIR: remove decl_ref and decl_val instructions. These are replaced by `decl_ref_named` and `decl_val_named`, respectively, which will probably get renamed in the future to the instructions that were just deleted. * AstGen: implement `@This()`, `@fence()`, `@returnAddress()`, and `@src()`. * AstGen: struct_decl improved to support fields_len=0 but have decls. * AstGen: fix missing null bytes after compile error messages. * SrcLoc: no longer depend on `Decl`. Instead have an explicit field `parent_decl_node` which is an absolute AST Node index. * Module: `failed_files` table can have null value, in which case the key, which is a `*Scope.File`, will have ZIR errors in it. * ZIR: implement text rendering of struct decls. * CLI: introduce debug_usage and `zig astgen` command which is enabled when the compiler is built in debug mode.

7 files changed, 457 insertions(+), 263 deletions(-)

BRANCH_TODO+11
......@@ -1,3 +1,14 @@
1 * AstGen decls into blocks so we can evaluate them independently
2 * look for cached zir code
3 * save zir code to cache
4 * store list of imported strings
5 * use list of imported strings to queue up more astgen tasks
6 * keep track of file dependencies/dependants
7 * unload files from memory when a dependency is dropped
8 * implement zir error notes
9
10 * implement the new AstGen compile errors
11
112 * get rid of failed_root_src_file
213 * get rid of Scope.DeclRef
314 * handle decl collision with usingnamespace
src/AstGen.zig+36-24
......@@ -96,14 +96,18 @@ pub fn generate(gpa: *Allocator, file: *Scope.File) InnerError!Zir {
9696 .arg = 0,
9797 },
9898 };
99 const struct_decl_ref = try AstGen.structDeclInner(
99 if (AstGen.structDeclInner(
100100 &gen_scope,
101101 &gen_scope.base,
102102 0,
103103 container_decl,
104104 .struct_decl,
105 );
106 astgen.extra.items[0] = @enumToInt(struct_decl_ref);
105 )) |struct_decl_ref| {
106 astgen.extra.items[0] = @enumToInt(struct_decl_ref);
107 } else |err| switch (err) {
108 error.OutOfMemory => return error.OutOfMemory,
109 error.AnalysisFail => {}, // Handled via compile_errors below.
110 }
107111
108112 if (astgen.compile_errors.items.len == 0) {
109113 astgen.extra.items[1] = 0;
......@@ -1272,8 +1276,6 @@ fn blockExprStmts(
12721276 .cmp_gt,
12731277 .cmp_neq,
12741278 .coerce_result_ptr,
1275 .decl_ref,
1276 .decl_val,
12771279 .decl_ref_named,
12781280 .decl_val_named,
12791281 .load,
......@@ -1381,6 +1383,10 @@ fn blockExprStmts(
13811383 .type_info,
13821384 .size_of,
13831385 .bit_size_of,
1386 .this,
1387 .fence,
1388 .ret_addr,
1389 .builtin_src,
13841390 => break :b false,
13851391
13861392 // ZIR instructions that are always either `noreturn` or `void`.
......@@ -2385,13 +2391,16 @@ fn structDeclInner(
23852391
23862392 const decl_inst = try gz.addBlock(tag, node);
23872393 try gz.instructions.append(gpa, decl_inst);
2388 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
2394 if (field_index != 0) {
2395 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
2396 }
23892397
23902398 try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len +
23912399 @typeInfo(Zir.Inst.StructDecl).Struct.fields.len +
2392 bit_bag.items.len + 1 + fields_data.items.len +
2400 bit_bag.items.len + @boolToInt(field_index != 0) + fields_data.items.len +
23932401 block_scope.instructions.items.len +
2394 wip_decls.bit_bag.items.len + 1 + wip_decls.name_and_value.items.len);
2402 wip_decls.bit_bag.items.len + @boolToInt(wip_decls.decl_index != 0) +
2403 wip_decls.name_and_value.items.len);
23952404 const zir_datas = astgen.instructions.items(.data);
23962405 zir_datas[decl_inst].pl_node.payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.StructDecl{
23972406 .body_len = @intCast(u32, block_scope.instructions.items.len),
......@@ -2401,11 +2410,15 @@ fn structDeclInner(
24012410 astgen.extra.appendSliceAssumeCapacity(block_scope.instructions.items);
24022411
24032412 astgen.extra.appendSliceAssumeCapacity(bit_bag.items); // Likely empty.
2404 astgen.extra.appendAssumeCapacity(cur_bit_bag);
2413 if (field_index != 0) {
2414 astgen.extra.appendAssumeCapacity(cur_bit_bag);
2415 }
24052416 astgen.extra.appendSliceAssumeCapacity(fields_data.items);
24062417
24072418 astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty.
2408 astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag);
2419 if (wip_decls.decl_index != 0) {
2420 astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag);
2421 }
24092422 astgen.extra.appendSliceAssumeCapacity(wip_decls.name_and_value.items);
24102423
24112424 return gz.indexToRef(decl_inst);
......@@ -4750,6 +4763,11 @@ fn builtinCall(
47504763 return rvalue(gz, scope, rl, result, node);
47514764 },
47524765
4766 .This => return rvalue(gz, scope, rl, try gz.addNode(.this, node), node),
4767 .fence => return rvalue(gz, scope, rl, try gz.addNode(.fence, node), node),
4768 .return_address => return rvalue(gz, scope, rl, try gz.addNode(.ret_addr, node), node),
4769 .src => return rvalue(gz, scope, rl, try gz.addNode(.builtin_src, node), node),
4770
47534771 .add_with_overflow,
47544772 .align_cast,
47554773 .align_of,
......@@ -4778,7 +4796,6 @@ fn builtinCall(
47784796 .error_name,
47794797 .error_return_trace,
47804798 .err_set_cast,
4781 .fence,
47824799 .field_parent_ptr,
47834800 .float_to_int,
47844801 .has_field,
......@@ -4794,7 +4811,6 @@ fn builtinCall(
47944811 .pop_count,
47954812 .ptr_cast,
47964813 .rem,
4797 .return_address,
47984814 .set_align_stack,
47994815 .set_cold,
48004816 .set_float_mode,
......@@ -4805,7 +4821,6 @@ fn builtinCall(
48054821 .shuffle,
48064822 .splat,
48074823 .reduce,
4808 .src,
48094824 .sqrt,
48104825 .sin,
48114826 .cos,
......@@ -4821,21 +4836,18 @@ fn builtinCall(
48214836 .round,
48224837 .sub_with_overflow,
48234838 .tag_name,
4824 .This,
48254839 .truncate,
48264840 .Type,
48274841 .type_name,
48284842 .union_init,
4829 => return astgen.failNode(node, "TODO: implement builtin function {s}", .{
4830 builtin_name,
4831 }),
4832
48334843 .async_call,
48344844 .frame,
48354845 .Frame,
48364846 .frame_address,
48374847 .frame_size,
4838 => return astgen.failNode(node, "async and related features are not yet supported", .{}),
4848 => return astgen.failNode(node, "TODO: implement builtin function {s}", .{
4849 builtin_name,
4850 }),
48394851 }
48404852}
48414853
......@@ -5376,7 +5388,7 @@ pub fn failNodeNotes(
53765388 {
53775389 var managed = string_bytes.toManaged(astgen.gpa);
53785390 defer string_bytes.* = managed.toUnmanaged();
5379 try managed.writer().print(format, args);
5391 try managed.writer().print(format ++ "\x00", args);
53805392 }
53815393 const notes_index: u32 = if (notes.len != 0) blk: {
53825394 const notes_start = astgen.extra.items.len;
......@@ -5417,7 +5429,7 @@ pub fn failTokNotes(
54175429 {
54185430 var managed = string_bytes.toManaged(astgen.gpa);
54195431 defer string_bytes.* = managed.toUnmanaged();
5420 try managed.writer().print(format, args);
5432 try managed.writer().print(format ++ "\x00", args);
54215433 }
54225434 const notes_index: u32 = if (notes.len != 0) blk: {
54235435 const notes_start = astgen.extra.items.len;
......@@ -5451,7 +5463,7 @@ pub fn failOff(
54515463 {
54525464 var managed = string_bytes.toManaged(astgen.gpa);
54535465 defer string_bytes.* = managed.toUnmanaged();
5454 try managed.writer().print(format, args);
5466 try managed.writer().print(format ++ "\x00", args);
54555467 }
54565468 try astgen.compile_errors.append(astgen.gpa, .{
54575469 .msg = msg,
......@@ -5475,7 +5487,7 @@ pub fn errNoteTok(
54755487 {
54765488 var managed = string_bytes.toManaged(astgen.gpa);
54775489 defer string_bytes.* = managed.toUnmanaged();
5478 try managed.writer().print(format, args);
5490 try managed.writer().print(format ++ "\x00", args);
54795491 }
54805492 return astgen.addExtra(Zir.Inst.CompileErrors.Item{
54815493 .msg = msg,
......@@ -5498,7 +5510,7 @@ pub fn errNoteNode(
54985510 {
54995511 var managed = string_bytes.toManaged(astgen.gpa);
55005512 defer string_bytes.* = managed.toUnmanaged();
5501 try managed.writer().print(format, args);
5513 try managed.writer().print(format ++ "\x00", args);
55025514 }
55035515 return astgen.addExtra(Zir.Inst.CompileErrors.Item{
55045516 .msg = msg,
src/Compilation.zig+63-6
......@@ -391,10 +391,10 @@ pub const AllErrors = struct {
391391 const notes = try arena.allocator.alloc(Message, module_err_msg.notes.len);
392392 for (notes) |*note, i| {
393393 const module_note = module_err_msg.notes[i];
394 const source = try module_note.src_loc.fileScope().getSource(module.gpa);
394 const source = try module_note.src_loc.file_scope.getSource(module.gpa);
395395 const byte_offset = try module_note.src_loc.byteOffset();
396396 const loc = std.zig.findLineColumn(source, byte_offset);
397 const sub_file_path = module_note.src_loc.fileScope().sub_file_path;
397 const sub_file_path = module_note.src_loc.file_scope.sub_file_path;
398398 note.* = .{
399399 .src = .{
400400 .src_path = try arena.allocator.dupe(u8, sub_file_path),
......@@ -406,10 +406,10 @@ pub const AllErrors = struct {
406406 },
407407 };
408408 }
409 const source = try module_err_msg.src_loc.fileScope().getSource(module.gpa);
409 const source = try module_err_msg.src_loc.file_scope.getSource(module.gpa);
410410 const byte_offset = try module_err_msg.src_loc.byteOffset();
411411 const loc = std.zig.findLineColumn(source, byte_offset);
412 const sub_file_path = module_err_msg.src_loc.fileScope().sub_file_path;
412 const sub_file_path = module_err_msg.src_loc.file_scope.sub_file_path;
413413 try errors.append(.{
414414 .src = .{
415415 .src_path = try arena.allocator.dupe(u8, sub_file_path),
......@@ -423,6 +423,56 @@ pub const AllErrors = struct {
423423 });
424424 }
425425
426 pub fn addZir(
427 arena: *Allocator,
428 errors: *std.ArrayList(Message),
429 file: *Module.Scope.File,
430 source: []const u8,
431 ) !void {
432 assert(file.zir_loaded);
433 assert(file.tree_loaded);
434 const Zir = @import("Zir.zig");
435 const payload_index = file.zir.extra[Zir.compile_error_extra_index];
436 assert(payload_index != 0);
437
438 const header = file.zir.extraData(Zir.Inst.CompileErrors, payload_index);
439 const items_len = header.data.items_len;
440 var extra_index = header.end;
441 var item_i: usize = 0;
442 while (item_i < items_len) : (item_i += 1) {
443 const item = file.zir.extraData(Zir.Inst.CompileErrors.Item, extra_index);
444 extra_index = item.end;
445
446 if (item.data.notes != 0) {
447 @panic("TODO implement AllErrors for Zir notes");
448 }
449
450 const msg = file.zir.nullTerminatedString(item.data.msg);
451 const byte_offset = blk: {
452 const token_starts = file.tree.tokens.items(.start);
453 if (item.data.node != 0) {
454 const main_tokens = file.tree.nodes.items(.main_token);
455 const main_token = main_tokens[item.data.node];
456 break :blk token_starts[main_token];
457 }
458 break :blk token_starts[item.data.token] + item.data.byte_offset;
459 };
460 const loc = std.zig.findLineColumn(source, byte_offset);
461
462 try errors.append(.{
463 .src = .{
464 .src_path = try arena.dupe(u8, file.sub_file_path),
465 .msg = try arena.dupe(u8, msg),
466 .byte_offset = byte_offset,
467 .line = @intCast(u32, loc.line),
468 .column = @intCast(u32, loc.column),
469 .notes = &.{}, // TODO
470 .source_line = try arena.dupe(u8, loc.source_line),
471 },
472 });
473 }
474 }
475
426476 fn addPlain(
427477 arena: *std.heap.ArenaAllocator,
428478 errors: *std.ArrayList(Message),
......@@ -1624,7 +1674,13 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
16241674 }
16251675 if (self.bin_file.options.module) |module| {
16261676 for (module.failed_files.items()) |entry| {
1627 try AllErrors.add(module, &arena, &errors, entry.value.*);
1677 if (entry.value) |msg| {
1678 try AllErrors.add(module, &arena, &errors, msg.*);
1679 } else {
1680 // Must be ZIR errors.
1681 const source = try entry.key.getSource(module.gpa);
1682 try AllErrors.addZir(&arena.allocator, &errors, entry.key, source);
1683 }
16281684 }
16291685 for (module.failed_decls.items()) |entry| {
16301686 if (entry.key.namespace.file_scope.status == .parse_failure) {
......@@ -2276,7 +2332,8 @@ fn reportRetryableAstGenError(
22762332 file.status = .retryable_failure;
22772333
22782334 const err_msg = try Module.ErrorMsg.create(gpa, .{
2279 .container = .{ .file_scope = file },
2335 .file_scope = file,
2336 .parent_decl_node = 0,
22802337 .lazy = .entire_file,
22812338 }, "unable to load {s}: {s}", .{
22822339 file.sub_file_path, @errorName(err),
src/Module.zig+91-129
......@@ -70,7 +70,7 @@ emit_h_failed_decls: std.AutoArrayHashMapUnmanaged(*Decl, *ErrorMsg) = .{},
7070compile_log_decls: std.AutoArrayHashMapUnmanaged(*Decl, SrcLoc) = .{},
7171/// Using a map here for consistency with the other fields here.
7272/// The ErrorMsg memory is owned by the `Scope.File`, using Module's general purpose allocator.
73failed_files: std.AutoArrayHashMapUnmanaged(*Scope.File, *ErrorMsg) = .{},
73failed_files: std.AutoArrayHashMapUnmanaged(*Scope.File, ?*ErrorMsg) = .{},
7474/// Using a map here for consistency with the other fields here.
7575/// The ErrorMsg memory is owned by the `Export`, using Module's general purpose allocator.
7676failed_exports: std.AutoArrayHashMapUnmanaged(*Export, *ErrorMsg) = .{},
......@@ -267,9 +267,10 @@ pub const Decl = struct {
267267 return .{ .node_offset = decl.nodeIndexToRelative(node_index) };
268268 }
269269
270 pub fn srcLoc(decl: *Decl) SrcLoc {
270 pub fn srcLoc(decl: Decl) SrcLoc {
271271 return .{
272 .container = .{ .decl = decl },
272 .file_scope = decl.getFileScope(),
273 .parent_decl_node = decl.src_node,
273274 .lazy = .{ .node_offset = 0 },
274275 };
275276 }
......@@ -367,7 +368,8 @@ pub const ErrorSet = struct {
367368
368369 pub fn srcLoc(self: ErrorSet) SrcLoc {
369370 return .{
370 .container = .{ .decl = self.owner_decl },
371 .file_scope = self.owner_decl.getFileScope(),
372 .parent_decl_node = self.owner_decl.src_node,
371373 .lazy = .{ .node_offset = self.node_offset },
372374 };
373375 }
......@@ -397,7 +399,8 @@ pub const Struct = struct {
397399
398400 pub fn srcLoc(s: Struct) SrcLoc {
399401 return .{
400 .container = .{ .decl = s.owner_decl },
402 .file_scope = s.owner_decl.getFileScope(),
403 .parent_decl_node = s.owner_decl.src_node,
401404 .lazy = .{ .node_offset = s.node_offset },
402405 };
403406 }
......@@ -416,7 +419,8 @@ pub const EnumSimple = struct {
416419
417420 pub fn srcLoc(self: EnumSimple) SrcLoc {
418421 return .{
419 .container = .{ .decl = self.owner_decl },
422 .file_scope = self.owner_decl.getFileScope(),
423 .parent_decl_node = self.owner_decl.src_node,
420424 .lazy = .{ .node_offset = self.node_offset },
421425 };
422426 }
......@@ -444,7 +448,8 @@ pub const EnumFull = struct {
444448
445449 pub fn srcLoc(self: EnumFull) SrcLoc {
446450 return .{
447 .container = .{ .decl = self.owner_decl },
451 .file_scope = self.owner_decl.getFileScope(),
452 .parent_decl_node = self.owner_decl.src_node,
448453 .lazy = .{ .node_offset = self.node_offset },
449454 };
450455 }
......@@ -1710,51 +1715,19 @@ pub const ErrorMsg = struct {
17101715
17111716/// Canonical reference to a position within a source file.
17121717pub const SrcLoc = struct {
1713 /// The active field is determined by tag of `lazy`.
1714 container: union {
1715 /// The containing `Decl` according to the source code.
1716 decl: *Decl,
1717 file_scope: *Scope.File,
1718 },
1719 /// Relative to `decl`.
1718 file_scope: *Scope.File,
1719 /// Might be 0 depending on tag of `lazy`.
1720 parent_decl_node: ast.Node.Index,
1721 /// Relative to `parent_decl_node`.
17201722 lazy: LazySrcLoc,
17211723
1722 pub fn fileScope(src_loc: SrcLoc) *Scope.File {
1723 return switch (src_loc.lazy) {
1724 .unneeded => unreachable,
1725
1726 .byte_abs,
1727 .token_abs,
1728 .node_abs,
1729 .entire_file,
1730 => src_loc.container.file_scope,
1724 pub fn declSrcToken(src_loc: SrcLoc) ast.TokenIndex {
1725 const tree = src_loc.file_scope.tree;
1726 return tree.firstToken(src_loc.parent_decl_node);
1727 }
17311728
1732 .byte_offset,
1733 .token_offset,
1734 .node_offset,
1735 .node_offset_back2tok,
1736 .node_offset_var_decl_ty,
1737 .node_offset_for_cond,
1738 .node_offset_builtin_call_arg0,
1739 .node_offset_builtin_call_arg1,
1740 .node_offset_array_access_index,
1741 .node_offset_slice_sentinel,
1742 .node_offset_call_func,
1743 .node_offset_field_name,
1744 .node_offset_deref_ptr,
1745 .node_offset_asm_source,
1746 .node_offset_asm_ret_ty,
1747 .node_offset_if_cond,
1748 .node_offset_bin_op,
1749 .node_offset_bin_lhs,
1750 .node_offset_bin_rhs,
1751 .node_offset_switch_operand,
1752 .node_offset_switch_special_prong,
1753 .node_offset_switch_range,
1754 .node_offset_fn_type_cc,
1755 .node_offset_fn_type_ret_ty,
1756 => src_loc.container.decl.namespace.file_scope,
1757 };
1729 pub fn declRelativeToNodeIndex(src_loc: SrcLoc, offset: i32) ast.TokenIndex {
1730 return @bitCast(ast.Node.Index, offset + @bitCast(i32, src_loc.parent_decl_node));
17581731 }
17591732
17601733 pub fn byteOffset(src_loc: SrcLoc) !u32 {
......@@ -1765,48 +1738,45 @@ pub const SrcLoc = struct {
17651738 .byte_abs => |byte_index| return byte_index,
17661739
17671740 .token_abs => |tok_index| {
1768 const tree = src_loc.container.file_scope.tree;
1741 const tree = src_loc.file_scope.tree;
17691742 const token_starts = tree.tokens.items(.start);
17701743 return token_starts[tok_index];
17711744 },
17721745 .node_abs => |node| {
1773 const tree = src_loc.container.file_scope.tree;
1746 const tree = src_loc.file_scope.tree;
17741747 const token_starts = tree.tokens.items(.start);
17751748 const tok_index = tree.firstToken(node);
17761749 return token_starts[tok_index];
17771750 },
17781751 .byte_offset => |byte_off| {
1779 const decl = src_loc.container.decl;
1780 return decl.srcByteOffset() + byte_off;
1752 const tree = src_loc.file_scope.tree;
1753 const token_starts = tree.tokens.items(.start);
1754 return token_starts[src_loc.declSrcToken()] + byte_off;
17811755 },
17821756 .token_offset => |tok_off| {
1783 const decl = src_loc.container.decl;
1784 const tok_index = decl.srcToken() + tok_off;
1785 const tree = decl.namespace.file_scope.tree;
1757 const tok_index = src_loc.declSrcToken() + tok_off;
1758 const tree = src_loc.file_scope.tree;
17861759 const token_starts = tree.tokens.items(.start);
17871760 return token_starts[tok_index];
17881761 },
17891762 .node_offset, .node_offset_bin_op => |node_off| {
1790 const decl = src_loc.container.decl;
1791 const node = decl.relativeToNodeIndex(node_off);
1792 const tree = decl.namespace.file_scope.tree;
1763 const node = src_loc.declRelativeToNodeIndex(node_off);
1764 const tree = src_loc.file_scope.tree;
17931765 const main_tokens = tree.nodes.items(.main_token);
17941766 const tok_index = main_tokens[node];
17951767 const token_starts = tree.tokens.items(.start);
17961768 return token_starts[tok_index];
17971769 },
17981770 .node_offset_back2tok => |node_off| {
1799 const decl = src_loc.container.decl;
1800 const node = decl.relativeToNodeIndex(node_off);
1801 const tree = decl.namespace.file_scope.tree;
1771 const node = src_loc.declRelativeToNodeIndex(node_off);
1772 const tree = src_loc.file_scope.tree;
18021773 const tok_index = tree.firstToken(node) - 2;
18031774 const token_starts = tree.tokens.items(.start);
18041775 return token_starts[tok_index];
18051776 },
18061777 .node_offset_var_decl_ty => |node_off| {
1807 const decl = src_loc.container.decl;
1808 const node = decl.relativeToNodeIndex(node_off);
1809 const tree = decl.namespace.file_scope.tree;
1778 const node = src_loc.declRelativeToNodeIndex(node_off);
1779 const tree = src_loc.file_scope.tree;
18101780 const node_tags = tree.nodes.items(.tag);
18111781 const full = switch (node_tags[node]) {
18121782 .global_var_decl => tree.globalVarDecl(node),
......@@ -1825,11 +1795,10 @@ pub const SrcLoc = struct {
18251795 return token_starts[tok_index];
18261796 },
18271797 .node_offset_builtin_call_arg0 => |node_off| {
1828 const decl = src_loc.container.decl;
1829 const tree = decl.namespace.file_scope.tree;
1798 const tree = src_loc.file_scope.tree;
18301799 const node_datas = tree.nodes.items(.data);
18311800 const node_tags = tree.nodes.items(.tag);
1832 const node = decl.relativeToNodeIndex(node_off);
1801 const node = src_loc.declRelativeToNodeIndex(node_off);
18331802 const param = switch (node_tags[node]) {
18341803 .builtin_call_two, .builtin_call_two_comma => node_datas[node].lhs,
18351804 .builtin_call, .builtin_call_comma => tree.extra_data[node_datas[node].lhs],
......@@ -1841,11 +1810,10 @@ pub const SrcLoc = struct {
18411810 return token_starts[tok_index];
18421811 },
18431812 .node_offset_builtin_call_arg1 => |node_off| {
1844 const decl = src_loc.container.decl;
1845 const tree = decl.namespace.file_scope.tree;
1813 const tree = src_loc.file_scope.tree;
18461814 const node_datas = tree.nodes.items(.data);
18471815 const node_tags = tree.nodes.items(.tag);
1848 const node = decl.relativeToNodeIndex(node_off);
1816 const node = src_loc.declRelativeToNodeIndex(node_off);
18491817 const param = switch (node_tags[node]) {
18501818 .builtin_call_two, .builtin_call_two_comma => node_datas[node].rhs,
18511819 .builtin_call, .builtin_call_comma => tree.extra_data[node_datas[node].lhs + 1],
......@@ -1857,22 +1825,20 @@ pub const SrcLoc = struct {
18571825 return token_starts[tok_index];
18581826 },
18591827 .node_offset_array_access_index => |node_off| {
1860 const decl = src_loc.container.decl;
1861 const tree = decl.namespace.file_scope.tree;
1828 const tree = src_loc.file_scope.tree;
18621829 const node_datas = tree.nodes.items(.data);
18631830 const node_tags = tree.nodes.items(.tag);
1864 const node = decl.relativeToNodeIndex(node_off);
1831 const node = src_loc.declRelativeToNodeIndex(node_off);
18651832 const main_tokens = tree.nodes.items(.main_token);
18661833 const tok_index = main_tokens[node_datas[node].rhs];
18671834 const token_starts = tree.tokens.items(.start);
18681835 return token_starts[tok_index];
18691836 },
18701837 .node_offset_slice_sentinel => |node_off| {
1871 const decl = src_loc.container.decl;
1872 const tree = decl.namespace.file_scope.tree;
1838 const tree = src_loc.file_scope.tree;
18731839 const node_datas = tree.nodes.items(.data);
18741840 const node_tags = tree.nodes.items(.tag);
1875 const node = decl.relativeToNodeIndex(node_off);
1841 const node = src_loc.declRelativeToNodeIndex(node_off);
18761842 const full = switch (node_tags[node]) {
18771843 .slice_open => tree.sliceOpen(node),
18781844 .slice => tree.slice(node),
......@@ -1885,11 +1851,10 @@ pub const SrcLoc = struct {
18851851 return token_starts[tok_index];
18861852 },
18871853 .node_offset_call_func => |node_off| {
1888 const decl = src_loc.container.decl;
1889 const tree = decl.namespace.file_scope.tree;
1854 const tree = src_loc.file_scope.tree;
18901855 const node_datas = tree.nodes.items(.data);
18911856 const node_tags = tree.nodes.items(.tag);
1892 const node = decl.relativeToNodeIndex(node_off);
1857 const node = src_loc.declRelativeToNodeIndex(node_off);
18931858 var params: [1]ast.Node.Index = undefined;
18941859 const full = switch (node_tags[node]) {
18951860 .call_one,
......@@ -1912,11 +1877,10 @@ pub const SrcLoc = struct {
19121877 return token_starts[tok_index];
19131878 },
19141879 .node_offset_field_name => |node_off| {
1915 const decl = src_loc.container.decl;
1916 const tree = decl.namespace.file_scope.tree;
1880 const tree = src_loc.file_scope.tree;
19171881 const node_datas = tree.nodes.items(.data);
19181882 const node_tags = tree.nodes.items(.tag);
1919 const node = decl.relativeToNodeIndex(node_off);
1883 const node = src_loc.declRelativeToNodeIndex(node_off);
19201884 const tok_index = switch (node_tags[node]) {
19211885 .field_access => node_datas[node].rhs,
19221886 else => tree.firstToken(node) - 2,
......@@ -1925,21 +1889,19 @@ pub const SrcLoc = struct {
19251889 return token_starts[tok_index];
19261890 },
19271891 .node_offset_deref_ptr => |node_off| {
1928 const decl = src_loc.container.decl;
1929 const tree = decl.namespace.file_scope.tree;
1892 const tree = src_loc.file_scope.tree;
19301893 const node_datas = tree.nodes.items(.data);
19311894 const node_tags = tree.nodes.items(.tag);
1932 const node = decl.relativeToNodeIndex(node_off);
1895 const node = src_loc.declRelativeToNodeIndex(node_off);
19331896 const tok_index = node_datas[node].lhs;
19341897 const token_starts = tree.tokens.items(.start);
19351898 return token_starts[tok_index];
19361899 },
19371900 .node_offset_asm_source => |node_off| {
1938 const decl = src_loc.container.decl;
1939 const tree = decl.namespace.file_scope.tree;
1901 const tree = src_loc.file_scope.tree;
19401902 const node_datas = tree.nodes.items(.data);
19411903 const node_tags = tree.nodes.items(.tag);
1942 const node = decl.relativeToNodeIndex(node_off);
1904 const node = src_loc.declRelativeToNodeIndex(node_off);
19431905 const full = switch (node_tags[node]) {
19441906 .asm_simple => tree.asmSimple(node),
19451907 .@"asm" => tree.asmFull(node),
......@@ -1951,11 +1913,10 @@ pub const SrcLoc = struct {
19511913 return token_starts[tok_index];
19521914 },
19531915 .node_offset_asm_ret_ty => |node_off| {
1954 const decl = src_loc.container.decl;
1955 const tree = decl.namespace.file_scope.tree;
1916 const tree = src_loc.file_scope.tree;
19561917 const node_datas = tree.nodes.items(.data);
19571918 const node_tags = tree.nodes.items(.tag);
1958 const node = decl.relativeToNodeIndex(node_off);
1919 const node = src_loc.declRelativeToNodeIndex(node_off);
19591920 const full = switch (node_tags[node]) {
19601921 .asm_simple => tree.asmSimple(node),
19611922 .@"asm" => tree.asmFull(node),
......@@ -1968,9 +1929,8 @@ pub const SrcLoc = struct {
19681929 },
19691930
19701931 .node_offset_for_cond, .node_offset_if_cond => |node_off| {
1971 const decl = src_loc.container.decl;
1972 const node = decl.relativeToNodeIndex(node_off);
1973 const tree = decl.namespace.file_scope.tree;
1932 const node = src_loc.declRelativeToNodeIndex(node_off);
1933 const tree = src_loc.file_scope.tree;
19741934 const node_tags = tree.nodes.items(.tag);
19751935 const src_node = switch (node_tags[node]) {
19761936 .if_simple => tree.ifSimple(node).ast.cond_expr,
......@@ -1988,9 +1948,8 @@ pub const SrcLoc = struct {
19881948 return token_starts[tok_index];
19891949 },
19901950 .node_offset_bin_lhs => |node_off| {
1991 const decl = src_loc.container.decl;
1992 const node = decl.relativeToNodeIndex(node_off);
1993 const tree = decl.namespace.file_scope.tree;
1951 const node = src_loc.declRelativeToNodeIndex(node_off);
1952 const tree = src_loc.file_scope.tree;
19941953 const node_datas = tree.nodes.items(.data);
19951954 const src_node = node_datas[node].lhs;
19961955 const main_tokens = tree.nodes.items(.main_token);
......@@ -1999,9 +1958,8 @@ pub const SrcLoc = struct {
19991958 return token_starts[tok_index];
20001959 },
20011960 .node_offset_bin_rhs => |node_off| {
2002 const decl = src_loc.container.decl;
2003 const node = decl.relativeToNodeIndex(node_off);
2004 const tree = decl.namespace.file_scope.tree;
1961 const node = src_loc.declRelativeToNodeIndex(node_off);
1962 const tree = src_loc.file_scope.tree;
20051963 const node_datas = tree.nodes.items(.data);
20061964 const src_node = node_datas[node].rhs;
20071965 const main_tokens = tree.nodes.items(.main_token);
......@@ -2011,9 +1969,8 @@ pub const SrcLoc = struct {
20111969 },
20121970
20131971 .node_offset_switch_operand => |node_off| {
2014 const decl = src_loc.container.decl;
2015 const node = decl.relativeToNodeIndex(node_off);
2016 const tree = decl.namespace.file_scope.tree;
1972 const node = src_loc.declRelativeToNodeIndex(node_off);
1973 const tree = src_loc.file_scope.tree;
20171974 const node_datas = tree.nodes.items(.data);
20181975 const src_node = node_datas[node].lhs;
20191976 const main_tokens = tree.nodes.items(.main_token);
......@@ -2023,9 +1980,8 @@ pub const SrcLoc = struct {
20231980 },
20241981
20251982 .node_offset_switch_special_prong => |node_off| {
2026 const decl = src_loc.container.decl;
2027 const switch_node = decl.relativeToNodeIndex(node_off);
2028 const tree = decl.namespace.file_scope.tree;
1983 const switch_node = src_loc.declRelativeToNodeIndex(node_off);
1984 const tree = src_loc.file_scope.tree;
20291985 const node_datas = tree.nodes.items(.data);
20301986 const node_tags = tree.nodes.items(.tag);
20311987 const main_tokens = tree.nodes.items(.main_token);
......@@ -2050,9 +2006,8 @@ pub const SrcLoc = struct {
20502006 },
20512007
20522008 .node_offset_switch_range => |node_off| {
2053 const decl = src_loc.container.decl;
2054 const switch_node = decl.relativeToNodeIndex(node_off);
2055 const tree = decl.namespace.file_scope.tree;
2009 const switch_node = src_loc.declRelativeToNodeIndex(node_off);
2010 const tree = src_loc.file_scope.tree;
20562011 const node_datas = tree.nodes.items(.data);
20572012 const node_tags = tree.nodes.items(.tag);
20582013 const main_tokens = tree.nodes.items(.main_token);
......@@ -2081,11 +2036,10 @@ pub const SrcLoc = struct {
20812036 },
20822037
20832038 .node_offset_fn_type_cc => |node_off| {
2084 const decl = src_loc.container.decl;
2085 const tree = decl.namespace.file_scope.tree;
2039 const tree = src_loc.file_scope.tree;
20862040 const node_datas = tree.nodes.items(.data);
20872041 const node_tags = tree.nodes.items(.tag);
2088 const node = decl.relativeToNodeIndex(node_off);
2042 const node = src_loc.declRelativeToNodeIndex(node_off);
20892043 var params: [1]ast.Node.Index = undefined;
20902044 const full = switch (node_tags[node]) {
20912045 .fn_proto_simple => tree.fnProtoSimple(&params, node),
......@@ -2101,11 +2055,10 @@ pub const SrcLoc = struct {
21012055 },
21022056
21032057 .node_offset_fn_type_ret_ty => |node_off| {
2104 const decl = src_loc.container.decl;
2105 const tree = decl.namespace.file_scope.tree;
2058 const tree = src_loc.file_scope.tree;
21062059 const node_datas = tree.nodes.items(.data);
21072060 const node_tags = tree.nodes.items(.tag);
2108 const node = decl.relativeToNodeIndex(node_off);
2061 const node = src_loc.declRelativeToNodeIndex(node_off);
21092062 var params: [1]ast.Node.Index = undefined;
21102063 const full = switch (node_tags[node]) {
21112064 .fn_proto_simple => tree.fnProtoSimple(&params, node),
......@@ -2288,7 +2241,8 @@ pub const LazySrcLoc = union(enum) {
22882241 .token_abs,
22892242 .node_abs,
22902243 => .{
2291 .container = .{ .file_scope = scope.getFileScope() },
2244 .file_scope = scope.getFileScope(),
2245 .parent_decl_node = 0,
22922246 .lazy = lazy,
22932247 },
22942248
......@@ -2317,7 +2271,8 @@ pub const LazySrcLoc = union(enum) {
23172271 .node_offset_fn_type_cc,
23182272 .node_offset_fn_type_ret_ty,
23192273 => .{
2320 .container = .{ .decl = scope.srcDecl().? },
2274 .file_scope = scope.getFileScope(),
2275 .parent_decl_node = scope.srcDecl().?.src_node,
23212276 .lazy = lazy,
23222277 },
23232278 };
......@@ -2332,7 +2287,8 @@ pub const LazySrcLoc = union(enum) {
23322287 .token_abs,
23332288 .node_abs,
23342289 => .{
2335 .container = .{ .file_scope = decl.getFileScope() },
2290 .file_scope = decl.getFileScope(),
2291 .parent_decl_node = 0,
23362292 .lazy = lazy,
23372293 },
23382294
......@@ -2361,7 +2317,8 @@ pub const LazySrcLoc = union(enum) {
23612317 .node_offset_fn_type_cc,
23622318 .node_offset_fn_type_ret_ty,
23632319 => .{
2364 .container = .{ .decl = decl },
2320 .file_scope = decl.getFileScope(),
2321 .parent_decl_node = decl.src_node,
23652322 .lazy = lazy,
23662323 },
23672324 };
......@@ -2409,7 +2366,7 @@ pub fn deinit(mod: *Module) void {
24092366 mod.emit_h_failed_decls.deinit(gpa);
24102367
24112368 for (mod.failed_files.items()) |entry| {
2412 entry.value.destroy(gpa);
2369 if (entry.value) |msg| msg.destroy(gpa);
24132370 }
24142371 mod.failed_files.deinit(gpa);
24152372
......@@ -2495,7 +2452,7 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node
24952452 const lock = comp.mutex.acquire();
24962453 defer lock.release();
24972454 if (mod.failed_files.swapRemove(file)) |entry| {
2498 entry.value.destroy(gpa); // Delete previous error message.
2455 if (entry.value) |msg| msg.destroy(gpa); // Delete previous error message.
24992456 }
25002457 },
25012458 }
......@@ -2531,7 +2488,8 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node
25312488 const err_msg = try gpa.create(ErrorMsg);
25322489 err_msg.* = .{
25332490 .src_loc = .{
2534 .container = .{ .file_scope = file },
2491 .file_scope = file,
2492 .parent_decl_node = 0,
25352493 .lazy = .{ .byte_abs = token_starts[parse_err.token] },
25362494 },
25372495 .msg = msg.toOwnedSlice(),
......@@ -2550,11 +2508,11 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node
25502508 file.zir = try AstGen.generate(gpa, file);
25512509 file.zir_loaded = true;
25522510
2553 if (file.zir.extra[1] != 0) {
2511 if (file.zir.hasCompileErrors()) {
25542512 {
25552513 const lock = comp.mutex.acquire();
25562514 defer lock.release();
2557 try mod.failed_files.putNoClobber(gpa, file, undefined);
2515 try mod.failed_files.putNoClobber(gpa, file, null);
25582516 }
25592517 file.status = .astgen_failure;
25602518 return error.AnalysisFail;
......@@ -2972,12 +2930,14 @@ fn semaContainerFn(
29722930 if (deleted_decls.swapRemove(decl) == null) {
29732931 decl.analysis = .sema_failure;
29742932 const msg = try ErrorMsg.create(mod.gpa, .{
2975 .container = .{ .file_scope = namespace.file_scope },
2933 .file_scope = namespace.file_scope,
2934 .parent_decl_node = 0,
29762935 .lazy = .{ .token_abs = name_token },
29772936 }, "redeclaration of '{s}'", .{decl.name});
29782937 errdefer msg.destroy(mod.gpa);
29792938 const other_src_loc: SrcLoc = .{
2980 .container = .{ .file_scope = decl.namespace.file_scope },
2939 .file_scope = namespace.file_scope,
2940 .parent_decl_node = 0,
29812941 .lazy = .{ .node_abs = prev_src_node },
29822942 };
29832943 try mod.errNoteNonLazy(other_src_loc, msg, "previously declared here", .{});
......@@ -3040,12 +3000,14 @@ fn semaContainerVar(
30403000 if (deleted_decls.swapRemove(decl) == null) {
30413001 decl.analysis = .sema_failure;
30423002 const msg = try ErrorMsg.create(mod.gpa, .{
3043 .container = .{ .file_scope = namespace.file_scope },
3003 .file_scope = namespace.file_scope,
3004 .parent_decl_node = 0,
30443005 .lazy = .{ .token_abs = name_token },
30453006 }, "redeclaration of '{s}'", .{decl.name});
30463007 errdefer msg.destroy(mod.gpa);
30473008 const other_src_loc: SrcLoc = .{
3048 .container = .{ .file_scope = decl.namespace.file_scope },
3009 .file_scope = decl.namespace.file_scope,
3010 .parent_decl_node = 0,
30493011 .lazy = .{ .node_abs = prev_src_node },
30503012 };
30513013 try mod.errNoteNonLazy(other_src_loc, msg, "previously declared here", .{});
src/Sema.zig+25-16
......@@ -170,9 +170,7 @@ pub fn analyzeBody(
170170 .cmp_lte => try sema.zirCmp(block, inst, .lte),
171171 .cmp_neq => try sema.zirCmp(block, inst, .neq),
172172 .coerce_result_ptr => try sema.zirCoerceResultPtr(block, inst),
173 .decl_ref => try sema.zirDeclRef(block, inst),
174173 .decl_ref_named => try sema.zirDeclRefNamed(block, inst),
175 .decl_val => try sema.zirDeclVal(block, inst),
176174 .decl_val_named => try sema.zirDeclValNamed(block, inst),
177175 .load => try sema.zirLoad(block, inst),
178176 .div => try sema.zirArithmetic(block, inst),
......@@ -266,6 +264,10 @@ pub fn analyzeBody(
266264 .type_info => try sema.zirTypeInfo(block, inst),
267265 .size_of => try sema.zirSizeOf(block, inst),
268266 .bit_size_of => try sema.zirBitSizeOf(block, inst),
267 .this => try sema.zirThis(block, inst),
268 .fence => try sema.zirFence(block, inst),
269 .ret_addr => try sema.zirRetAddr(block, inst),
270 .builtin_src => try sema.zirBuiltinSrc(block, inst),
269271 .typeof => try sema.zirTypeof(block, inst),
270272 .typeof_elem => try sema.zirTypeofElem(block, inst),
271273 .typeof_peer => try sema.zirTypeofPeer(block, inst),
......@@ -1656,20 +1658,6 @@ fn zirDbgStmtNode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerE
16561658 _ = try block.addDbgStmt(src, abs_byte_off);
16571659}
16581660
1659fn zirDeclRef(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
1660 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1661 const src = inst_data.src();
1662 const decl = sema.owner_decl.dependencies.entries.items[inst_data.payload_index].key;
1663 return sema.analyzeDeclRef(block, src, decl);
1664}
1665
1666fn zirDeclVal(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
1667 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1668 const src = inst_data.src();
1669 const decl = sema.owner_decl.dependencies.entries.items[inst_data.payload_index].key;
1670 return sema.analyzeDeclVal(block, src, decl);
1671}
1672
16731661fn zirDeclRefNamed(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
16741662 const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
16751663 const src = inst_data.src();
......@@ -4373,6 +4361,27 @@ fn zirBitSizeOf(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerErr
43734361 return sema.mod.constIntUnsigned(sema.arena, src, Type.initTag(.comptime_int), bit_size);
43744362}
43754363
4364fn zirThis(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
4365 const src_node = sema.code.instructions.items(.data)[inst].node;
4366 const src: LazySrcLoc = .{ .node_offset = src_node };
4367 return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirThis", .{});
4368}
4369fn zirFence(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
4370 const src_node = sema.code.instructions.items(.data)[inst].node;
4371 const src: LazySrcLoc = .{ .node_offset = src_node };
4372 return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirFence", .{});
4373}
4374fn zirRetAddr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
4375 const src_node = sema.code.instructions.items(.data)[inst].node;
4376 const src: LazySrcLoc = .{ .node_offset = src_node };
4377 return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirRetAddr", .{});
4378}
4379fn zirBuiltinSrc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
4380 const src_node = sema.code.instructions.items(.data)[inst].node;
4381 const src: LazySrcLoc = .{ .node_offset = src_node };
4382 return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirBuiltinSrc", .{});
4383}
4384
43764385fn zirTypeInfo(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
43774386 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
43784387 const src = inst_data.src();
src/Zir.zig+138-82
......@@ -42,6 +42,9 @@ string_bytes: []u8,
4242/// payload at this index.
4343extra: []u32,
4444
45pub const main_struct_extra_index = 0;
46pub const compile_error_extra_index = 1;
47
4548/// Returns the requested data, as well as the new index which is at the start of the
4649/// trailers for the object.
4750pub fn extraData(code: Zir, comptime T: type, index: usize) struct { data: T, end: usize } {
......@@ -76,6 +79,10 @@ pub fn refSlice(code: Zir, start: usize, len: usize) []Inst.Ref {
7679 return @bitCast([]Inst.Ref, raw_slice);
7780}
7881
82pub fn hasCompileErrors(code: Zir) bool {
83 return code.extra[compile_error_extra_index] != 0;
84}
85
7986pub fn deinit(code: *Zir, gpa: *Allocator) void {
8087 code.instructions.deinit(gpa);
8188 gpa.free(code.string_bytes);
......@@ -83,13 +90,11 @@ pub fn deinit(code: *Zir, gpa: *Allocator) void {
8390 code.* = undefined;
8491}
8592
86/// For debugging purposes, like dumpFn but for unanalyzed zir blocks
87pub fn dump(
88 code: Zir,
93/// Write human-readable, debug formatted ZIR code to a file.
94pub fn renderAsTextToFile(
8995 gpa: *Allocator,
90 kind: []const u8,
91 scope: *Module.Scope,
92 param_count: usize,
96 scope_file: *Module.Scope.File,
97 fs_file: std.fs.File,
9398) !void {
9499 var arena = std.heap.ArenaAllocator.init(gpa);
95100 defer arena.deinit();
......@@ -97,17 +102,17 @@ pub fn dump(
97102 var writer: Writer = .{
98103 .gpa = gpa,
99104 .arena = &arena.allocator,
100 .scope = scope,
101 .code = code,
105 .file = scope_file,
106 .code = scope_file.zir,
102107 .indent = 0,
103 .param_count = param_count,
108 .parent_decl_node = 0,
109 .param_count = 0,
104110 };
105111
106 const decl_name = scope.srcDecl().?.name;
107 const stderr = std.io.getStdErr().writer();
108 try stderr.print("ZIR {s} {s} %0 ", .{ kind, decl_name });
109 try writer.writeInstToStream(stderr, 0);
110 try stderr.print(" // end ZIR {s} {s}\n\n", .{ kind, decl_name });
112 const main_struct_inst = scope_file.zir.extra[0] - @intCast(u32, Inst.Ref.typed_value_map.len);
113 try fs_file.writer().print("%{d} ", .{main_struct_inst});
114 try writer.writeInstToStream(fs_file.writer(), main_struct_inst);
115 try fs_file.writeAll("\n");
111116}
112117
113118/// These are untyped instructions generated from an Abstract Syntax Tree.
......@@ -291,12 +296,6 @@ pub const Inst = struct {
291296 /// Declares the beginning of a statement. Used for debug info.
292297 /// Uses the `node` union field.
293298 dbg_stmt_node,
294 /// Represents a pointer to a global decl.
295 /// Uses the `pl_node` union field. `payload_index` is into `decls`.
296 decl_ref,
297 /// Equivalent to a decl_ref followed by load.
298 /// Uses the `pl_node` union field. `payload_index` is into `decls`.
299 decl_val,
300299 /// Same as `decl_ref` except instead of indexing into decls, uses
301300 /// a name to identify the Decl. Uses the `str_tok` union field.
302301 decl_ref_named,
......@@ -705,6 +704,14 @@ pub const Inst = struct {
705704 size_of,
706705 /// Implements the `@bitSizeOf` builtin. Uses `un_node`.
707706 bit_size_of,
707 /// Implements the `@This` builtin. Uses `node`.
708 this,
709 /// Implements the `@fence` builtin. Uses `un_node`.
710 fence,
711 /// Implements the `@returnAddress` builtin. Uses `un_node`.
712 ret_addr,
713 /// Implements the `@src` builtin. Uses `un_node`.
714 builtin_src,
708715
709716 /// Returns whether the instruction is one of the control flow "noreturn" types.
710717 /// Function calls do not count.
......@@ -758,8 +765,6 @@ pub const Inst = struct {
758765 .enum_decl_nonexhaustive,
759766 .opaque_decl,
760767 .dbg_stmt_node,
761 .decl_ref,
762 .decl_val,
763768 .decl_ref_named,
764769 .decl_val_named,
765770 .load,
......@@ -873,6 +878,10 @@ pub const Inst = struct {
873878 .type_info,
874879 .size_of,
875880 .bit_size_of,
881 .this,
882 .fence,
883 .ret_addr,
884 .builtin_src,
876885 => false,
877886
878887 .@"break",
......@@ -1647,11 +1656,16 @@ pub const SpecialProng = enum { none, @"else", under };
16471656const Writer = struct {
16481657 gpa: *Allocator,
16491658 arena: *Allocator,
1650 scope: *Module.Scope,
1659 file: *Module.Scope.File,
16511660 code: Zir,
1652 indent: usize,
1661 indent: u32,
1662 parent_decl_node: u32,
16531663 param_count: usize,
16541664
1665 fn relativeToNodeIndex(self: *Writer, offset: i32) ast.Node.Index {
1666 return @bitCast(ast.Node.Index, offset + @bitCast(i32, self.parent_decl_node));
1667 }
1668
16551669 fn writeInstToStream(
16561670 self: *Writer,
16571671 stream: anytype,
......@@ -1832,10 +1846,6 @@ const Writer = struct {
18321846 .typeof_peer,
18331847 => try self.writePlNodeMultiOp(stream, inst),
18341848
1835 .decl_ref,
1836 .decl_val,
1837 => try self.writePlNodeDecl(stream, inst),
1838
18391849 .field_ptr,
18401850 .field_val,
18411851 => try self.writePlNodeField(stream, inst),
......@@ -1851,6 +1861,10 @@ const Writer = struct {
18511861 .repeat_inline,
18521862 .alloc_inferred,
18531863 .alloc_inferred_mut,
1864 .this,
1865 .fence,
1866 .ret_addr,
1867 .builtin_src,
18541868 => try self.writeNode(stream, inst),
18551869
18561870 .error_value,
......@@ -2067,68 +2081,114 @@ const Writer = struct {
20672081 const extra = self.code.extraData(Inst.StructDecl, inst_data.payload_index);
20682082 const body = self.code.extra[extra.end..][0..extra.data.body_len];
20692083 const fields_len = extra.data.fields_len;
2084 const decls_len = extra.data.decls_len;
2085
2086 const prev_parent_decl_node = self.parent_decl_node;
2087 self.parent_decl_node = self.relativeToNodeIndex(inst_data.src_node);
2088
2089 var extra_index: usize = undefined;
20702090
20712091 if (fields_len == 0) {
20722092 assert(body.len == 0);
2073 try stream.writeAll("{}, {}) ");
2074 try self.writeSrc(stream, inst_data.src());
2075 return;
2076 }
2093 try stream.writeAll("{}, {}, {");
2094 extra_index = extra.end;
2095 } else {
2096 try stream.writeAll("{\n");
2097 self.indent += 2;
2098 try self.writeBody(stream, body);
2099
2100 try stream.writeByteNTimes(' ', self.indent - 2);
2101 try stream.writeAll("}, {\n");
2102
2103 const bit_bags_count = std.math.divCeil(usize, fields_len, 16) catch unreachable;
2104 const body_end = extra.end + body.len;
2105 extra_index = body_end + bit_bags_count;
2106 var bit_bag_index: usize = body_end;
2107 var cur_bit_bag: u32 = undefined;
2108 var field_i: u32 = 0;
2109 while (field_i < fields_len) : (field_i += 1) {
2110 if (field_i % 16 == 0) {
2111 cur_bit_bag = self.code.extra[bit_bag_index];
2112 bit_bag_index += 1;
2113 }
2114 const has_align = @truncate(u1, cur_bit_bag) != 0;
2115 cur_bit_bag >>= 1;
2116 const has_default = @truncate(u1, cur_bit_bag) != 0;
2117 cur_bit_bag >>= 1;
20772118
2078 try stream.writeAll("{\n");
2079 self.indent += 2;
2080 try self.writeBody(stream, body);
2119 const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]);
2120 extra_index += 1;
2121 const field_type = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
2122 extra_index += 1;
20812123
2082 try stream.writeByteNTimes(' ', self.indent - 2);
2083 try stream.writeAll("}, {\n");
2124 try stream.writeByteNTimes(' ', self.indent);
2125 try stream.print("{}: ", .{std.zig.fmtId(field_name)});
2126 try self.writeInstRef(stream, field_type);
20842127
2085 const bit_bags_count = std.math.divCeil(usize, fields_len, 16) catch unreachable;
2086 const body_end = extra.end + body.len;
2087 var extra_index: usize = body_end + bit_bags_count;
2088 var bit_bag_index: usize = body_end;
2128 if (has_align) {
2129 const align_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
2130 extra_index += 1;
2131
2132 try stream.writeAll(" align(");
2133 try self.writeInstRef(stream, align_ref);
2134 try stream.writeAll(")");
2135 }
2136 if (has_default) {
2137 const default_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
2138 extra_index += 1;
2139
2140 try stream.writeAll(" = ");
2141 try self.writeInstRef(stream, default_ref);
2142 }
2143 try stream.writeAll(",\n");
2144 }
2145
2146 self.indent -= 2;
2147 try stream.writeByteNTimes(' ', self.indent);
2148 try stream.writeAll("}, {");
2149 }
2150 if (decls_len == 0) {
2151 try stream.writeAll("}) ");
2152 } else {
2153 try stream.writeAll("\n");
2154 self.indent += 2;
2155 try self.writeDecls(stream, decls_len, extra_index);
2156 self.indent -= 2;
2157 try stream.writeByteNTimes(' ', self.indent);
2158 try stream.writeAll("}) ");
2159 }
2160 self.parent_decl_node = prev_parent_decl_node;
2161 try self.writeSrc(stream, inst_data.src());
2162 }
2163
2164 fn writeDecls(self: *Writer, stream: anytype, decls_len: u32, extra_start: usize) !void {
2165 const bit_bags_count = std.math.divCeil(usize, decls_len, 16) catch unreachable;
2166 var extra_index = extra_start + bit_bags_count;
2167 var bit_bag_index: usize = extra_start;
20892168 var cur_bit_bag: u32 = undefined;
2090 var field_i: u32 = 0;
2091 while (field_i < fields_len) : (field_i += 1) {
2092 if (field_i % 16 == 0) {
2169 var decl_i: u32 = 0;
2170 while (decl_i < decls_len) : (decl_i += 1) {
2171 if (decl_i % 16 == 0) {
20932172 cur_bit_bag = self.code.extra[bit_bag_index];
20942173 bit_bag_index += 1;
20952174 }
2096 const has_align = @truncate(u1, cur_bit_bag) != 0;
2175 const is_pub = @truncate(u1, cur_bit_bag) != 0;
20972176 cur_bit_bag >>= 1;
2098 const has_default = @truncate(u1, cur_bit_bag) != 0;
2177 const is_exported = @truncate(u1, cur_bit_bag) != 0;
20992178 cur_bit_bag >>= 1;
21002179
2101 const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]);
2180 const decl_name = self.code.nullTerminatedString(self.code.extra[extra_index]);
21022181 extra_index += 1;
2103 const field_type = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
2182 const decl_value = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
21042183 extra_index += 1;
21052184
2185 const pub_str = if (is_pub) "pub " else "";
2186 const export_str = if (is_exported) "export " else "";
21062187 try stream.writeByteNTimes(' ', self.indent);
2107 try stream.print("{}: ", .{std.zig.fmtId(field_name)});
2108 try self.writeInstRef(stream, field_type);
2109
2110 if (has_align) {
2111 const align_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
2112 extra_index += 1;
2113
2114 try stream.writeAll(" align(");
2115 try self.writeInstRef(stream, align_ref);
2116 try stream.writeAll(")");
2117 }
2118 if (has_default) {
2119 const default_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
2120 extra_index += 1;
2121
2122 try stream.writeAll(" = ");
2123 try self.writeInstRef(stream, default_ref);
2124 }
2125 try stream.writeAll(",\n");
2188 try stream.print("{s}{s}{} = ", .{ pub_str, export_str, std.zig.fmtId(decl_name) });
2189 try self.writeInstRef(stream, decl_value);
2190 try stream.writeAll("\n");
21262191 }
2127
2128 self.indent -= 2;
2129 try stream.writeByteNTimes(' ', self.indent);
2130 try stream.writeAll("}) ");
2131 try self.writeSrc(stream, inst_data.src());
21322192 }
21332193
21342194 fn writeEnumDecl(self: *Writer, stream: anytype, inst: Inst.Index) !void {
......@@ -2374,14 +2434,6 @@ const Writer = struct {
23742434 try self.writeSrc(stream, inst_data.src());
23752435 }
23762436
2377 fn writePlNodeDecl(self: *Writer, stream: anytype, inst: Inst.Index) !void {
2378 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
2379 const owner_decl = self.scope.ownerDecl().?;
2380 const decl = owner_decl.dependencies.entries.items[inst_data.payload_index].key;
2381 try stream.print("{s}) ", .{decl.name});
2382 try self.writeSrc(stream, inst_data.src());
2383 }
2384
23852437 fn writePlNodeField(self: *Writer, stream: anytype, inst: Inst.Index) !void {
23862438 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
23872439 const extra = self.code.extraData(Inst.Field, inst_data.payload_index).data;
......@@ -2593,8 +2645,12 @@ const Writer = struct {
25932645 }
25942646
25952647 fn writeSrc(self: *Writer, stream: anytype, src: LazySrcLoc) !void {
2596 const tree = self.scope.tree();
2597 const src_loc = src.toSrcLoc(self.scope);
2648 const tree = self.file.tree;
2649 const src_loc: Module.SrcLoc = .{
2650 .file_scope = self.file,
2651 .parent_decl_node = self.parent_decl_node,
2652 .lazy = src,
2653 };
25982654 const abs_byte_off = try src_loc.byteOffset();
25992655 const delta_line = std.zig.findLineColumn(tree.source, abs_byte_off);
26002656 try stream.print("{s}:{d}:{d}", .{
src/main.zig+93-6
......@@ -25,7 +25,11 @@ pub fn fatal(comptime format: []const u8, args: anytype) noreturn {
2525 process.exit(1);
2626}
2727
28pub const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB
28/// There are many assumptions in the entire codebase that Zig source files can
29/// be byte-indexed with a u32 integer.
30pub const max_src_size = std.math.maxInt(u32);
31
32pub const debug_extensions_enabled = std.builtin.mode == .Debug;
2933
3034pub const Color = enum {
3135 auto,
......@@ -33,7 +37,7 @@ pub const Color = enum {
3337 on,
3438};
3539
36const usage =
40const normal_usage =
3741 \\Usage: zig [command] [options]
3842 \\
3943 \\Commands:
......@@ -63,6 +67,16 @@ const usage =
6367 \\
6468;
6569
70const debug_usage = normal_usage ++
71 \\
72 \\Debug Commands:
73 \\
74 \\ astgen Print ZIR code for a .zig source file
75 \\
76;
77
78const usage = if (debug_extensions_enabled) debug_usage else normal_usage;
79
6680pub const log_level: std.log.Level = switch (std.builtin.mode) {
6781 .Debug => .debug,
6882 .ReleaseSafe, .ReleaseFast => .info,
......@@ -206,13 +220,15 @@ pub fn mainArgs(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
206220 const stdout = io.getStdOut().writer();
207221 return @import("print_targets.zig").cmdTargets(arena, cmd_args, stdout, info.target);
208222 } else if (mem.eql(u8, cmd, "version")) {
209 try std.io.getStdOut().writeAll(build_options.version ++ "\n");
223 return std.io.getStdOut().writeAll(build_options.version ++ "\n");
210224 } else if (mem.eql(u8, cmd, "env")) {
211 try @import("print_env.zig").cmdEnv(arena, cmd_args, io.getStdOut().writer());
225 return @import("print_env.zig").cmdEnv(arena, cmd_args, io.getStdOut().writer());
212226 } else if (mem.eql(u8, cmd, "zen")) {
213 try io.getStdOut().writeAll(info_zen);
227 return io.getStdOut().writeAll(info_zen);
214228 } else if (mem.eql(u8, cmd, "help") or mem.eql(u8, cmd, "-h") or mem.eql(u8, cmd, "--help")) {
215 try io.getStdOut().writeAll(usage);
229 return io.getStdOut().writeAll(usage);
230 } else if (debug_extensions_enabled and mem.eql(u8, cmd, "astgen")) {
231 return cmdAstgen(gpa, arena, cmd_args);
216232 } else {
217233 std.log.info("{s}", .{usage});
218234 fatal("unknown command: {s}", .{args[1]});
......@@ -3485,3 +3501,74 @@ pub fn cleanExit() void {
34853501 process.exit(0);
34863502 }
34873503}
3504
3505/// This is only enabled for debug builds.
3506pub fn cmdAstgen(
3507 gpa: *Allocator,
3508 arena: *Allocator,
3509 args: []const []const u8,
3510) !void {
3511 const Module = @import("Module.zig");
3512 const AstGen = @import("AstGen.zig");
3513 const Zir = @import("Zir.zig");
3514
3515 const zig_source_file = args[0];
3516
3517 var f = try fs.cwd().openFile(zig_source_file, .{});
3518 defer f.close();
3519
3520 const stat = try f.stat();
3521
3522 if (stat.size > max_src_size)
3523 return error.FileTooBig;
3524
3525 var file: Module.Scope.File = .{
3526 .status = .never_loaded,
3527 .source_loaded = false,
3528 .tree_loaded = false,
3529 .zir_loaded = false,
3530 .sub_file_path = zig_source_file,
3531 .source = undefined,
3532 .stat_size = stat.size,
3533 .stat_inode = stat.inode,
3534 .stat_mtime = stat.mtime,
3535 .tree = undefined,
3536 .zir = undefined,
3537 .pkg = undefined,
3538 .namespace = undefined,
3539 };
3540
3541 const source = try arena.allocSentinel(u8, stat.size, 0);
3542 const amt = try f.readAll(source);
3543 if (amt != stat.size)
3544 return error.UnexpectedEndOfFile;
3545 file.source = source;
3546 file.source_loaded = true;
3547
3548 file.tree = try std.zig.parse(gpa, file.source);
3549 file.tree_loaded = true;
3550 defer file.tree.deinit(gpa);
3551
3552 for (file.tree.errors) |parse_error| {
3553 try printErrMsgToFile(gpa, parse_error, file.tree, zig_source_file, io.getStdErr(), .auto);
3554 }
3555 if (file.tree.errors.len != 0) {
3556 process.exit(1);
3557 }
3558
3559 file.zir = try AstGen.generate(gpa, &file);
3560 file.zir_loaded = true;
3561 defer file.zir.deinit(gpa);
3562
3563 if (file.zir.hasCompileErrors()) {
3564 var errors = std.ArrayList(Compilation.AllErrors.Message).init(arena);
3565 try Compilation.AllErrors.addZir(arena, &errors, &file, source);
3566 const ttyconf = std.debug.detectTTYConfig();
3567 for (errors.items) |full_err_msg| {
3568 full_err_msg.renderToStdErr(ttyconf);
3569 }
3570 process.exit(1);
3571 }
3572
3573 return Zir.renderAsTextToFile(gpa, &file, io.getStdOut());
3574}