authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-12-09 18:32:23-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-12-09 18:32:23-05:00
log7575f212128df84c8b86ee3c89d940313380d902
treefc060baccfbfbb24946779a0795c6c29d9d9bf92
parent8245d7fac0400d7e9de2a6fd4cfbc3609ad0f201
parent9f086f84f53de4eb23d96fe611c071f27405a660
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #22157 from mlugg/astgen-error-lazy

compiler: allow semantic analysis of files with AstGen errors

20 files changed, 581 insertions(+), 321 deletions(-)

lib/std/multi_array_list.zig+6
......@@ -74,6 +74,12 @@ pub fn MultiArrayList(comptime T: type) type {
7474 len: usize,
7575 capacity: usize,
7676
77 pub const empty: Slice = .{
78 .ptrs = undefined,
79 .len = 0,
80 .capacity = 0,
81 };
82
7783 pub fn items(self: Slice, comptime field: Field) []FieldType(field) {
7884 const F = FieldType(field);
7985 if (self.capacity == 0) {
lib/std/zig/AstGen.zig+143-35
......@@ -172,9 +172,9 @@ pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir {
172172 };
173173 defer gz_instructions.deinit(gpa);
174174
175 // The AST -> ZIR lowering process assumes an AST that does not have any
176 // parse errors.
177 if (tree.errors.len == 0) {
175 // The AST -> ZIR lowering process assumes an AST that does not have any parse errors.
176 // Parse errors, or AstGen errors in the root struct, are considered "fatal", so we emit no ZIR.
177 const fatal = if (tree.errors.len == 0) fatal: {
178178 if (AstGen.structDeclInner(
179179 &gen_scope,
180180 &gen_scope.base,
......@@ -184,13 +184,15 @@ pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir {
184184 0,
185185 )) |struct_decl_ref| {
186186 assert(struct_decl_ref.toIndex().? == .main_struct_inst);
187 break :fatal false;
187188 } else |err| switch (err) {
188189 error.OutOfMemory => return error.OutOfMemory,
189 error.AnalysisFail => {}, // Handled via compile_errors below.
190 error.AnalysisFail => break :fatal true, // Handled via compile_errors below.
190191 }
191 } else {
192 } else fatal: {
192193 try lowerAstErrors(&astgen);
193 }
194 break :fatal true;
195 };
194196
195197 const err_index = @intFromEnum(Zir.ExtraIndex.compile_errors);
196198 if (astgen.compile_errors.items.len == 0) {
......@@ -228,8 +230,8 @@ pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir {
228230 }
229231 }
230232
231 return Zir{
232 .instructions = astgen.instructions.toOwnedSlice(),
233 return .{
234 .instructions = if (fatal) .empty else astgen.instructions.toOwnedSlice(),
233235 .string_bytes = try astgen.string_bytes.toOwnedSlice(gpa),
234236 .extra = try astgen.extra.toOwnedSlice(gpa),
235237 };
......@@ -2110,7 +2112,7 @@ fn comptimeExprAst(
21102112) InnerError!Zir.Inst.Ref {
21112113 const astgen = gz.astgen;
21122114 if (gz.is_comptime) {
2113 return astgen.failNode(node, "redundant comptime keyword in already comptime scope", .{});
2115 try astgen.appendErrorNode(node, "redundant comptime keyword in already comptime scope", .{});
21142116 }
21152117 const tree = astgen.tree;
21162118 const node_datas = tree.nodes.items(.data);
......@@ -3269,6 +3271,9 @@ fn varDecl(
32693271 try astgen.appendErrorTok(comptime_token, "'comptime const' is redundant; instead wrap the initialization expression with 'comptime'", .{});
32703272 }
32713273
3274 // `comptime const` is a non-fatal error; treat it like the init was marked `comptime`.
3275 const force_comptime = var_decl.comptime_token != null;
3276
32723277 // Depending on the type of AST the initialization expression is, we may need an lvalue
32733278 // or an rvalue as a result location. If it is an rvalue, we can use the instruction as
32743279 // the variable, no memory location needed.
......@@ -3282,7 +3287,7 @@ fn varDecl(
32823287 } else .{ .rl = .none, .ctx = .const_init };
32833288 const prev_anon_name_strategy = gz.anon_name_strategy;
32843289 gz.anon_name_strategy = .dbg_var;
3285 const init_inst = try reachableExpr(gz, scope, result_info, var_decl.ast.init_node, node);
3290 const init_inst = try reachableExprComptime(gz, scope, result_info, var_decl.ast.init_node, node, force_comptime);
32863291 gz.anon_name_strategy = prev_anon_name_strategy;
32873292
32883293 try gz.addDbgVar(.dbg_var_val, ident_name, init_inst);
......@@ -3348,7 +3353,7 @@ fn varDecl(
33483353 const prev_anon_name_strategy = gz.anon_name_strategy;
33493354 gz.anon_name_strategy = .dbg_var;
33503355 defer gz.anon_name_strategy = prev_anon_name_strategy;
3351 const init_inst = try reachableExpr(gz, scope, init_result_info, var_decl.ast.init_node, node);
3356 const init_inst = try reachableExprComptime(gz, scope, init_result_info, var_decl.ast.init_node, node, force_comptime);
33523357
33533358 // The const init expression may have modified the error return trace, so signal
33543359 // to Sema that it should save the new index for restoring later.
......@@ -3491,7 +3496,7 @@ fn assignDestructure(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerErro
34913496
34923497 const full = tree.assignDestructure(node);
34933498 if (full.comptime_token != null and gz.is_comptime) {
3494 return astgen.failNode(node, "redundant comptime keyword in already comptime scope", .{});
3499 return astgen.appendErrorNode(node, "redundant comptime keyword in already comptime scope", .{});
34953500 }
34963501
34973502 // If this expression is marked comptime, we must wrap the whole thing in a comptime block.
......@@ -3550,7 +3555,7 @@ fn assignDestructureMaybeDecls(
35503555
35513556 const full = tree.assignDestructure(node);
35523557 if (full.comptime_token != null and gz.is_comptime) {
3553 return astgen.failNode(node, "redundant comptime keyword in already comptime scope", .{});
3558 try astgen.appendErrorNode(node, "redundant comptime keyword in already comptime scope", .{});
35543559 }
35553560
35563561 const is_comptime = full.comptime_token != null or gz.is_comptime;
......@@ -3664,6 +3669,7 @@ fn assignDestructureMaybeDecls(
36643669
36653670 if (full.comptime_token != null and !any_non_const_variables) {
36663671 try astgen.appendErrorTok(full.comptime_token.?, "'comptime const' is redundant; instead wrap the initialization expression with 'comptime'", .{});
3672 // Note that this is non-fatal; we will still evaluate at comptime.
36673673 }
36683674
36693675 // If this expression is marked comptime, we must wrap it in a comptime block.
......@@ -4112,8 +4118,8 @@ fn fnDecl(
41124118 // The source slice is added towards the *end* of this function.
41134119 astgen.src_hasher.update(std.mem.asBytes(&astgen.source_column));
41144120
4115 // missing function name already happened in scanContainer()
4116 const fn_name_token = fn_proto.name_token orelse return error.AnalysisFail;
4121 // missing function name already checked in scanContainer()
4122 const fn_name_token = fn_proto.name_token.?;
41174123
41184124 // We insert this at the beginning so that its instruction index marks the
41194125 // start of the top level declaration.
......@@ -5182,8 +5188,7 @@ fn structDeclInner(
51825188
51835189 if (is_comptime) {
51845190 switch (layout) {
5185 .@"packed" => return astgen.failTok(member.comptime_token.?, "packed struct fields cannot be marked comptime", .{}),
5186 .@"extern" => return astgen.failTok(member.comptime_token.?, "extern struct fields cannot be marked comptime", .{}),
5191 .@"packed", .@"extern" => return astgen.failTok(member.comptime_token.?, "{s} struct fields cannot be marked comptime", .{@tagName(layout)}),
51875192 .auto => any_comptime_fields = true,
51885193 }
51895194 } else {
......@@ -5210,7 +5215,7 @@ fn structDeclInner(
52105215
52115216 if (have_align) {
52125217 if (layout == .@"packed") {
5213 try astgen.appendErrorNode(member.ast.align_expr, "unable to override alignment of packed struct fields", .{});
5218 return astgen.failNode(member.ast.align_expr, "unable to override alignment of packed struct fields", .{});
52145219 }
52155220 any_aligned_fields = true;
52165221 const align_ref = try expr(&block_scope, &namespace.base, coerced_align_ri, member.ast.align_expr);
......@@ -5304,8 +5309,7 @@ fn tupleDecl(
53045309
53055310 switch (layout) {
53065311 .auto => {},
5307 .@"extern" => return astgen.failNode(node, "extern tuples are not supported", .{}),
5308 .@"packed" => return astgen.failNode(node, "packed tuples are not supported", .{}),
5312 .@"extern", .@"packed" => return astgen.failNode(node, "{s} tuples are not supported", .{@tagName(layout)}),
53095313 }
53105314
53115315 if (backing_int_node != 0) {
......@@ -5688,7 +5692,7 @@ fn containerDecl(
56885692 };
56895693 };
56905694 if (counts.nonexhaustive_node != 0 and container_decl.ast.arg == 0) {
5691 try astgen.appendErrorNodeNotes(
5695 return astgen.failNodeNotes(
56925696 node,
56935697 "non-exhaustive enum missing integer tag type",
56945698 .{},
......@@ -5911,9 +5915,19 @@ fn containerMember(
59115915 const full = tree.fullFnProto(&buf, member_node).?;
59125916 const body = if (node_tags[member_node] == .fn_decl) node_datas[member_node].rhs else 0;
59135917
5918 const prev_decl_index = wip_members.decl_index;
59145919 astgen.fnDecl(gz, scope, wip_members, member_node, body, full) catch |err| switch (err) {
59155920 error.OutOfMemory => return error.OutOfMemory,
5916 error.AnalysisFail => {},
5921 error.AnalysisFail => {
5922 wip_members.decl_index = prev_decl_index;
5923 try addFailedDeclaration(
5924 wip_members,
5925 gz,
5926 .{ .named = full.name_token.? },
5927 full.ast.proto_node,
5928 full.visib_token != null,
5929 );
5930 },
59175931 };
59185932 },
59195933
......@@ -5922,28 +5936,77 @@ fn containerMember(
59225936 .simple_var_decl,
59235937 .aligned_var_decl,
59245938 => {
5925 astgen.globalVarDecl(gz, scope, wip_members, member_node, tree.fullVarDecl(member_node).?) catch |err| switch (err) {
5939 const full = tree.fullVarDecl(member_node).?;
5940 const prev_decl_index = wip_members.decl_index;
5941 astgen.globalVarDecl(gz, scope, wip_members, member_node, full) catch |err| switch (err) {
59265942 error.OutOfMemory => return error.OutOfMemory,
5927 error.AnalysisFail => {},
5943 error.AnalysisFail => {
5944 wip_members.decl_index = prev_decl_index;
5945 try addFailedDeclaration(
5946 wip_members,
5947 gz,
5948 .{ .named = full.ast.mut_token + 1 },
5949 member_node,
5950 full.visib_token != null,
5951 );
5952 },
59285953 };
59295954 },
59305955
59315956 .@"comptime" => {
5957 const prev_decl_index = wip_members.decl_index;
59325958 astgen.comptimeDecl(gz, scope, wip_members, member_node) catch |err| switch (err) {
59335959 error.OutOfMemory => return error.OutOfMemory,
5934 error.AnalysisFail => {},
5960 error.AnalysisFail => {
5961 wip_members.decl_index = prev_decl_index;
5962 try addFailedDeclaration(
5963 wip_members,
5964 gz,
5965 .@"comptime",
5966 member_node,
5967 false,
5968 );
5969 },
59355970 };
59365971 },
59375972 .@"usingnamespace" => {
5973 const prev_decl_index = wip_members.decl_index;
59385974 astgen.usingnamespaceDecl(gz, scope, wip_members, member_node) catch |err| switch (err) {
59395975 error.OutOfMemory => return error.OutOfMemory,
5940 error.AnalysisFail => {},
5976 error.AnalysisFail => {
5977 wip_members.decl_index = prev_decl_index;
5978 try addFailedDeclaration(
5979 wip_members,
5980 gz,
5981 .@"usingnamespace",
5982 member_node,
5983 is_pub: {
5984 const main_tokens = tree.nodes.items(.main_token);
5985 const token_tags = tree.tokens.items(.tag);
5986 const main_token = main_tokens[member_node];
5987 break :is_pub main_token > 0 and token_tags[main_token - 1] == .keyword_pub;
5988 },
5989 );
5990 },
59415991 };
59425992 },
59435993 .test_decl => {
5994 const prev_decl_index = wip_members.decl_index;
5995 // We need to have *some* decl here so that the decl count matches what's expected.
5996 // Since it doesn't strictly matter *what* this is, let's save ourselves the trouble
5997 // of duplicating the test name logic, and just assume this is an unnamed test.
59445998 astgen.testDecl(gz, scope, wip_members, member_node) catch |err| switch (err) {
59455999 error.OutOfMemory => return error.OutOfMemory,
5946 error.AnalysisFail => {},
6000 error.AnalysisFail => {
6001 wip_members.decl_index = prev_decl_index;
6002 try addFailedDeclaration(
6003 wip_members,
6004 gz,
6005 .unnamed_test,
6006 member_node,
6007 false,
6008 );
6009 },
59476010 };
59486011 },
59496012 else => unreachable,
......@@ -6155,7 +6218,7 @@ fn orelseCatchExpr(
61556218 const payload = payload_token orelse break :blk &else_scope.base;
61566219 const err_str = tree.tokenSlice(payload);
61576220 if (mem.eql(u8, err_str, "_")) {
6158 return astgen.failTok(payload, "discard of error capture; omit it instead", .{});
6221 try astgen.appendErrorTok(payload, "discard of error capture; omit it instead", .{});
61596222 }
61606223 const err_name = try astgen.identAsString(payload);
61616224
......@@ -6614,7 +6677,7 @@ fn whileExpr(
66146677
66156678 const is_inline = while_full.inline_token != null;
66166679 if (parent_gz.is_comptime and is_inline) {
6617 return astgen.failTok(while_full.inline_token.?, "redundant inline keyword in comptime scope", .{});
6680 try astgen.appendErrorTok(while_full.inline_token.?, "redundant inline keyword in comptime scope", .{});
66186681 }
66196682 const loop_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .loop;
66206683 const loop_block = try parent_gz.makeBlockInst(loop_tag, node);
......@@ -6904,7 +6967,7 @@ fn forExpr(
69046967
69056968 const is_inline = for_full.inline_token != null;
69066969 if (parent_gz.is_comptime and is_inline) {
6907 return astgen.failTok(for_full.inline_token.?, "redundant inline keyword in comptime scope", .{});
6970 try astgen.appendErrorTok(for_full.inline_token.?, "redundant inline keyword in comptime scope", .{});
69086971 }
69096972 const tree = astgen.tree;
69106973 const token_tags = tree.tokens.items(.tag);
......@@ -6965,7 +7028,7 @@ fn forExpr(
69657028 .none;
69667029
69677030 if (end_val == .none and is_discard) {
6968 return astgen.failTok(ident_tok, "discard of unbounded counter", .{});
7031 try astgen.appendErrorTok(ident_tok, "discard of unbounded counter", .{});
69697032 }
69707033
69717034 const start_is_zero = nodeIsTriviallyZero(tree, start_node);
......@@ -7467,6 +7530,7 @@ fn switchExprErrUnion(
74677530 const err_name = blk: {
74687531 const err_str = tree.tokenSlice(error_payload);
74697532 if (mem.eql(u8, err_str, "_")) {
7533 // This is fatal because we already know we're switching on the captured error.
74707534 return astgen.failTok(error_payload, "discard of error capture; omit it instead", .{});
74717535 }
74727536 const err_name = try astgen.identAsString(error_payload);
......@@ -7521,7 +7585,7 @@ fn switchExprErrUnion(
75217585
75227586 const capture_slice = tree.tokenSlice(capture_token);
75237587 if (mem.eql(u8, capture_slice, "_")) {
7524 return astgen.failTok(capture_token, "discard of error capture; omit it instead", .{});
7588 try astgen.appendErrorTok(capture_token, "discard of error capture; omit it instead", .{});
75257589 }
75267590 const tag_name = try astgen.identAsString(capture_token);
75277591 try astgen.detectLocalShadowing(&case_scope.base, tag_name, capture_token, capture_slice, .capture);
......@@ -7992,7 +8056,7 @@ fn switchExpr(
79928056 break :blk payload_sub_scope;
79938057 const tag_slice = tree.tokenSlice(tag_token);
79948058 if (mem.eql(u8, tag_slice, "_")) {
7995 return astgen.failTok(tag_token, "discard of tag capture; omit it instead", .{});
8059 try astgen.appendErrorTok(tag_token, "discard of tag capture; omit it instead", .{});
79968060 } else if (case.inline_token == null) {
79978061 return astgen.failTok(tag_token, "tag capture on non-inline prong", .{});
79988062 }
......@@ -13678,6 +13742,8 @@ fn scanContainer(
1367813742 const main_tokens = tree.nodes.items(.main_token);
1367913743 const token_tags = tree.tokens.items(.tag);
1368013744
13745 var any_invalid_declarations = false;
13746
1368113747 // This type forms a linked list of source tokens declaring the same name.
1368213748 const NameEntry = struct {
1368313749 tok: Ast.TokenIndex,
......@@ -13737,6 +13803,7 @@ fn scanContainer(
1373713803 const ident = main_tokens[member_node] + 1;
1373813804 if (token_tags[ident] != .identifier) {
1373913805 try astgen.appendErrorNode(member_node, "missing function name", .{});
13806 any_invalid_declarations = true;
1374013807 continue;
1374113808 }
1374213809 break :blk .{ .decl, ident };
......@@ -13832,6 +13899,7 @@ fn scanContainer(
1383213899 token_bytes,
1383313900 }),
1383413901 });
13902 any_invalid_declarations = true;
1383513903 continue;
1383613904 }
1383713905
......@@ -13849,6 +13917,7 @@ fn scanContainer(
1384913917 .{},
1385013918 ),
1385113919 });
13920 any_invalid_declarations = true;
1385213921 break;
1385313922 }
1385413923 s = local_val.parent;
......@@ -13865,6 +13934,7 @@ fn scanContainer(
1386513934 .{},
1386613935 ),
1386713936 });
13937 any_invalid_declarations = true;
1386813938 break;
1386913939 }
1387013940 s = local_ptr.parent;
......@@ -13876,7 +13946,10 @@ fn scanContainer(
1387613946 };
1387713947 }
1387813948
13879 if (!any_duplicates) return decl_count;
13949 if (!any_duplicates) {
13950 if (any_invalid_declarations) return error.AnalysisFail;
13951 return decl_count;
13952 }
1388013953
1388113954 for (names.keys(), names.values()) |name, first| {
1388213955 if (first.next == null) continue;
......@@ -13888,6 +13961,7 @@ fn scanContainer(
1388813961 try notes.append(astgen.arena, try astgen.errNoteNode(namespace.node, "{s} declared here", .{@tagName(container_kind)}));
1388913962 const name_duped = try astgen.arena.dupe(u8, mem.span(astgen.nullTerminatedString(name)));
1389013963 try astgen.appendErrorTokNotes(first.tok, "duplicate {s} member name '{s}'", .{ @tagName(container_kind), name_duped }, notes.items);
13964 any_invalid_declarations = true;
1389113965 }
1389213966
1389313967 for (test_names.keys(), test_names.values()) |name, first| {
......@@ -13900,6 +13974,7 @@ fn scanContainer(
1390013974 try notes.append(astgen.arena, try astgen.errNoteNode(namespace.node, "{s} declared here", .{@tagName(container_kind)}));
1390113975 const name_duped = try astgen.arena.dupe(u8, mem.span(astgen.nullTerminatedString(name)));
1390213976 try astgen.appendErrorTokNotes(first.tok, "duplicate test name '{s}'", .{name_duped}, notes.items);
13977 any_invalid_declarations = true;
1390313978 }
1390413979
1390513980 for (decltest_names.keys(), decltest_names.values()) |name, first| {
......@@ -13912,9 +13987,11 @@ fn scanContainer(
1391213987 try notes.append(astgen.arena, try astgen.errNoteNode(namespace.node, "{s} declared here", .{@tagName(container_kind)}));
1391313988 const name_duped = try astgen.arena.dupe(u8, mem.span(astgen.nullTerminatedString(name)));
1391413989 try astgen.appendErrorTokNotes(first.tok, "duplicate decltest '{s}'", .{name_duped}, notes.items);
13990 any_invalid_declarations = true;
1391513991 }
1391613992
13917 return decl_count;
13993 assert(any_invalid_declarations);
13994 return error.AnalysisFail;
1391813995}
1391913996
1392013997/// Assumes capacity for body has already been added. Needed capacity taking into
......@@ -14070,6 +14147,37 @@ const DeclarationName = union(enum) {
1407014147 @"usingnamespace",
1407114148};
1407214149
14150fn addFailedDeclaration(
14151 wip_members: *WipMembers,
14152 gz: *GenZir,
14153 name: DeclarationName,
14154 src_node: Ast.Node.Index,
14155 is_pub: bool,
14156) !void {
14157 const decl_inst = try gz.makeDeclaration(src_node);
14158 wip_members.nextDecl(decl_inst);
14159 var decl_gz = gz.makeSubBlock(&gz.base); // scope doesn't matter here
14160 _ = try decl_gz.add(.{
14161 .tag = .extended,
14162 .data = .{ .extended = .{
14163 .opcode = .astgen_error,
14164 .small = undefined,
14165 .operand = undefined,
14166 } },
14167 });
14168 try setDeclaration(
14169 decl_inst,
14170 @splat(0), // use a fixed hash to represent an AstGen failure; we don't care about source changes if AstGen still failed!
14171 name,
14172 gz.astgen.source_line,
14173 is_pub,
14174 false, // we don't care about exports since semantic analysis will fail
14175 .empty,
14176 &decl_gz,
14177 null,
14178 );
14179}
14180
1407314181/// Sets all extra data for a `declaration` instruction.
1407414182/// Unstacks `value_gz`, `align_gz`, `linksection_gz`, and `addrspace_gz`.
1407514183fn setDeclaration(
lib/std/zig/Zir.zig+211-177
......@@ -120,7 +120,21 @@ pub fn bodySlice(zir: Zir, start: usize, len: usize) []Inst.Index {
120120}
121121
122122pub fn hasCompileErrors(code: Zir) bool {
123 return code.extra[@intFromEnum(ExtraIndex.compile_errors)] != 0;
123 if (code.extra[@intFromEnum(ExtraIndex.compile_errors)] != 0) {
124 return true;
125 } else {
126 assert(code.instructions.len != 0); // i.e. lowering did not fail
127 return false;
128 }
129}
130
131pub fn loweringFailed(code: Zir) bool {
132 if (code.instructions.len == 0) {
133 assert(code.hasCompileErrors());
134 return true;
135 } else {
136 return false;
137 }
124138}
125139
126140pub fn deinit(code: *Zir, gpa: Allocator) void {
......@@ -2079,7 +2093,14 @@ pub const Inst = struct {
20792093 /// `small` is an `Inst.InplaceOp`.
20802094 inplace_arith_result_ty,
20812095 /// Marks a statement that can be stepped to but produces no code.
2096 /// `operand` and `small` are ignored.
20822097 dbg_empty_stmt,
2098 /// At this point, AstGen encountered a fatal error which terminated ZIR lowering for this body.
2099 /// A file-level error has been reported. Sema should terminate semantic analysis.
2100 /// `operand` and `small` are ignored.
2101 /// This instruction is always `noreturn`, however, it is not considered as such by ZIR-level queries. This allows AstGen to assume that
2102 /// any code may have gone here, avoiding false-positive "unreachable code" errors.
2103 astgen_error,
20832104
20842105 pub const InstData = struct {
20852106 opcode: Extended,
......@@ -3584,145 +3605,155 @@ pub const DeclIterator = struct {
35843605};
35853606
35863607pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
3587 const tags = zir.instructions.items(.tag);
3588 const datas = zir.instructions.items(.data);
3589 switch (tags[@intFromEnum(decl_inst)]) {
3590 // Functions are allowed and yield no iterations.
3591 // This is because they are returned by `findDecls`.
3592 .func, .func_inferred, .func_fancy => return .{
3593 .extra_index = undefined,
3594 .decls_remaining = 0,
3595 .zir = zir,
3596 },
3597
3598 .extended => {
3599 const extended = datas[@intFromEnum(decl_inst)].extended;
3600 switch (extended.opcode) {
3601 // Reifications are allowed and yield no iterations.
3602 // This is because they are returned by `findDecls`.
3603 .reify => return .{
3604 .extra_index = undefined,
3605 .decls_remaining = 0,
3606 .zir = zir,
3607 },
3608 .struct_decl => {
3609 const small: Inst.StructDecl.Small = @bitCast(extended.small);
3610 var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.StructDecl).@"struct".fields.len);
3611 const captures_len = if (small.has_captures_len) captures_len: {
3612 const captures_len = zir.extra[extra_index];
3613 extra_index += 1;
3614 break :captures_len captures_len;
3615 } else 0;
3616 extra_index += @intFromBool(small.has_fields_len);
3617 const decls_len = if (small.has_decls_len) decls_len: {
3618 const decls_len = zir.extra[extra_index];
3619 extra_index += 1;
3620 break :decls_len decls_len;
3621 } else 0;
3622
3623 extra_index += captures_len;
3624
3625 if (small.has_backing_int) {
3626 const backing_int_body_len = zir.extra[extra_index];
3627 extra_index += 1; // backing_int_body_len
3628 if (backing_int_body_len == 0) {
3629 extra_index += 1; // backing_int_ref
3630 } else {
3631 extra_index += backing_int_body_len; // backing_int_body_inst
3632 }
3633 }
3608 const inst = zir.instructions.get(@intFromEnum(decl_inst));
3609 assert(inst.tag == .extended);
3610 const extended = inst.data.extended;
3611 switch (extended.opcode) {
3612 .struct_decl => {
3613 const small: Inst.StructDecl.Small = @bitCast(extended.small);
3614 var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.StructDecl).@"struct".fields.len);
3615 const captures_len = if (small.has_captures_len) captures_len: {
3616 const captures_len = zir.extra[extra_index];
3617 extra_index += 1;
3618 break :captures_len captures_len;
3619 } else 0;
3620 extra_index += @intFromBool(small.has_fields_len);
3621 const decls_len = if (small.has_decls_len) decls_len: {
3622 const decls_len = zir.extra[extra_index];
3623 extra_index += 1;
3624 break :decls_len decls_len;
3625 } else 0;
3626
3627 extra_index += captures_len;
3628
3629 if (small.has_backing_int) {
3630 const backing_int_body_len = zir.extra[extra_index];
3631 extra_index += 1; // backing_int_body_len
3632 if (backing_int_body_len == 0) {
3633 extra_index += 1; // backing_int_ref
3634 } else {
3635 extra_index += backing_int_body_len; // backing_int_body_inst
3636 }
3637 }
36343638
3635 return .{
3636 .extra_index = extra_index,
3637 .decls_remaining = decls_len,
3638 .zir = zir,
3639 };
3640 },
3641 .enum_decl => {
3642 const small: Inst.EnumDecl.Small = @bitCast(extended.small);
3643 var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.EnumDecl).@"struct".fields.len);
3644 extra_index += @intFromBool(small.has_tag_type);
3645 const captures_len = if (small.has_captures_len) captures_len: {
3646 const captures_len = zir.extra[extra_index];
3647 extra_index += 1;
3648 break :captures_len captures_len;
3649 } else 0;
3650 extra_index += @intFromBool(small.has_body_len);
3651 extra_index += @intFromBool(small.has_fields_len);
3652 const decls_len = if (small.has_decls_len) decls_len: {
3653 const decls_len = zir.extra[extra_index];
3654 extra_index += 1;
3655 break :decls_len decls_len;
3656 } else 0;
3639 return .{
3640 .extra_index = extra_index,
3641 .decls_remaining = decls_len,
3642 .zir = zir,
3643 };
3644 },
3645 .enum_decl => {
3646 const small: Inst.EnumDecl.Small = @bitCast(extended.small);
3647 var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.EnumDecl).@"struct".fields.len);
3648 extra_index += @intFromBool(small.has_tag_type);
3649 const captures_len = if (small.has_captures_len) captures_len: {
3650 const captures_len = zir.extra[extra_index];
3651 extra_index += 1;
3652 break :captures_len captures_len;
3653 } else 0;
3654 extra_index += @intFromBool(small.has_body_len);
3655 extra_index += @intFromBool(small.has_fields_len);
3656 const decls_len = if (small.has_decls_len) decls_len: {
3657 const decls_len = zir.extra[extra_index];
3658 extra_index += 1;
3659 break :decls_len decls_len;
3660 } else 0;
36573661
3658 extra_index += captures_len;
3662 extra_index += captures_len;
36593663
3660 return .{
3661 .extra_index = extra_index,
3662 .decls_remaining = decls_len,
3663 .zir = zir,
3664 };
3665 },
3666 .union_decl => {
3667 const small: Inst.UnionDecl.Small = @bitCast(extended.small);
3668 var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.UnionDecl).@"struct".fields.len);
3669 extra_index += @intFromBool(small.has_tag_type);
3670 const captures_len = if (small.has_captures_len) captures_len: {
3671 const captures_len = zir.extra[extra_index];
3672 extra_index += 1;
3673 break :captures_len captures_len;
3674 } else 0;
3675 extra_index += @intFromBool(small.has_body_len);
3676 extra_index += @intFromBool(small.has_fields_len);
3677 const decls_len = if (small.has_decls_len) decls_len: {
3678 const decls_len = zir.extra[extra_index];
3679 extra_index += 1;
3680 break :decls_len decls_len;
3681 } else 0;
3664 return .{
3665 .extra_index = extra_index,
3666 .decls_remaining = decls_len,
3667 .zir = zir,
3668 };
3669 },
3670 .union_decl => {
3671 const small: Inst.UnionDecl.Small = @bitCast(extended.small);
3672 var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.UnionDecl).@"struct".fields.len);
3673 extra_index += @intFromBool(small.has_tag_type);
3674 const captures_len = if (small.has_captures_len) captures_len: {
3675 const captures_len = zir.extra[extra_index];
3676 extra_index += 1;
3677 break :captures_len captures_len;
3678 } else 0;
3679 extra_index += @intFromBool(small.has_body_len);
3680 extra_index += @intFromBool(small.has_fields_len);
3681 const decls_len = if (small.has_decls_len) decls_len: {
3682 const decls_len = zir.extra[extra_index];
3683 extra_index += 1;
3684 break :decls_len decls_len;
3685 } else 0;
36823686
3683 extra_index += captures_len;
3687 extra_index += captures_len;
36843688
3685 return .{
3686 .extra_index = extra_index,
3687 .decls_remaining = decls_len,
3688 .zir = zir,
3689 };
3690 },
3691 .opaque_decl => {
3692 const small: Inst.OpaqueDecl.Small = @bitCast(extended.small);
3693 var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.OpaqueDecl).@"struct".fields.len);
3694 const decls_len = if (small.has_decls_len) decls_len: {
3695 const decls_len = zir.extra[extra_index];
3696 extra_index += 1;
3697 break :decls_len decls_len;
3698 } else 0;
3699 const captures_len = if (small.has_captures_len) captures_len: {
3700 const captures_len = zir.extra[extra_index];
3701 extra_index += 1;
3702 break :captures_len captures_len;
3703 } else 0;
3689 return .{
3690 .extra_index = extra_index,
3691 .decls_remaining = decls_len,
3692 .zir = zir,
3693 };
3694 },
3695 .opaque_decl => {
3696 const small: Inst.OpaqueDecl.Small = @bitCast(extended.small);
3697 var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.OpaqueDecl).@"struct".fields.len);
3698 const decls_len = if (small.has_decls_len) decls_len: {
3699 const decls_len = zir.extra[extra_index];
3700 extra_index += 1;
3701 break :decls_len decls_len;
3702 } else 0;
3703 const captures_len = if (small.has_captures_len) captures_len: {
3704 const captures_len = zir.extra[extra_index];
3705 extra_index += 1;
3706 break :captures_len captures_len;
3707 } else 0;
37043708
3705 extra_index += captures_len;
3709 extra_index += captures_len;
37063710
3707 return .{
3708 .extra_index = extra_index,
3709 .decls_remaining = decls_len,
3710 .zir = zir,
3711 };
3712 },
3713 else => unreachable,
3714 }
3711 return .{
3712 .extra_index = extra_index,
3713 .decls_remaining = decls_len,
3714 .zir = zir,
3715 };
37153716 },
37163717 else => unreachable,
37173718 }
37183719}
37193720
3720/// Find all type declarations, recursively, within a `declaration` instruction. Does not recurse through
3721/// said type declarations' declarations; to find all declarations, call this function on the declarations
3722/// of the discovered types recursively.
3723/// The iterator would have to allocate memory anyway to iterate, so an `ArrayList` is populated as the result.
3724pub fn findDecls(zir: Zir, gpa: Allocator, list: *std.ArrayListUnmanaged(Inst.Index), decl_inst: Zir.Inst.Index) !void {
3725 list.clearRetainingCapacity();
3721/// `DeclContents` contains all "interesting" instructions found within a declaration by `findTrackable`.
3722/// These instructions are partitioned into a few different sets, since this makes ZIR instruction mapping
3723/// more effective.
3724pub const DeclContents = struct {
3725 /// This is a simple optional because ZIR guarantees that a `func`/`func_inferred`/`func_fancy` instruction
3726 /// can only occur once per `declaration`.
3727 func_decl: ?Inst.Index,
3728 explicit_types: std.ArrayListUnmanaged(Inst.Index),
3729 other: std.ArrayListUnmanaged(Inst.Index),
3730
3731 pub const init: DeclContents = .{
3732 .func_decl = null,
3733 .explicit_types = .empty,
3734 .other = .empty,
3735 };
3736
3737 pub fn clear(contents: *DeclContents) void {
3738 contents.func_decl = null;
3739 contents.explicit_types.clearRetainingCapacity();
3740 contents.other.clearRetainingCapacity();
3741 }
3742
3743 pub fn deinit(contents: *DeclContents, gpa: Allocator) void {
3744 contents.explicit_types.deinit(gpa);
3745 contents.other.deinit(gpa);
3746 }
3747};
3748
3749/// Find all tracked ZIR instructions, recursively, within a `declaration` instruction. Does not recurse through
3750/// nested declarations; to find all declarations, call this function recursively on the type declarations discovered
3751/// in `contents.explicit_types`.
3752///
3753/// This populates an `ArrayListUnmanaged` because an iterator would need to allocate memory anyway.
3754pub fn findTrackable(zir: Zir, gpa: Allocator, contents: *DeclContents, decl_inst: Zir.Inst.Index) !void {
3755 contents.clear();
3756
37263757 const declaration, const extra_end = zir.getDeclaration(decl_inst);
37273758 const bodies = declaration.getBodies(extra_end, zir);
37283759
......@@ -3731,27 +3762,27 @@ pub fn findDecls(zir: Zir, gpa: Allocator, list: *std.ArrayListUnmanaged(Inst.In
37313762 var found_defers: std.AutoHashMapUnmanaged(u32, void) = .empty;
37323763 defer found_defers.deinit(gpa);
37333764
3734 try zir.findDeclsBody(gpa, list, &found_defers, bodies.value_body);
3735 if (bodies.align_body) |b| try zir.findDeclsBody(gpa, list, &found_defers, b);
3736 if (bodies.linksection_body) |b| try zir.findDeclsBody(gpa, list, &found_defers, b);
3737 if (bodies.addrspace_body) |b| try zir.findDeclsBody(gpa, list, &found_defers, b);
3765 try zir.findTrackableBody(gpa, contents, &found_defers, bodies.value_body);
3766 if (bodies.align_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b);
3767 if (bodies.linksection_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b);
3768 if (bodies.addrspace_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b);
37383769}
37393770
3740/// Like `findDecls`, but only considers the `main_struct_inst` instruction. This may return more than
3771/// Like `findTrackable`, but only considers the `main_struct_inst` instruction. This may return more than
37413772/// just that instruction because it will also traverse fields.
3742pub fn findDeclsRoot(zir: Zir, gpa: Allocator, list: *std.ArrayListUnmanaged(Inst.Index)) !void {
3743 list.clearRetainingCapacity();
3773pub fn findTrackableRoot(zir: Zir, gpa: Allocator, contents: *DeclContents) !void {
3774 contents.clear();
37443775
37453776 var found_defers: std.AutoHashMapUnmanaged(u32, void) = .empty;
37463777 defer found_defers.deinit(gpa);
37473778
3748 try zir.findDeclsInner(gpa, list, &found_defers, .main_struct_inst);
3779 try zir.findTrackableInner(gpa, contents, &found_defers, .main_struct_inst);
37493780}
37503781
3751fn findDeclsInner(
3782fn findTrackableInner(
37523783 zir: Zir,
37533784 gpa: Allocator,
3754 list: *std.ArrayListUnmanaged(Inst.Index),
3785 contents: *DeclContents,
37553786 defers: *std.AutoHashMapUnmanaged(u32, void),
37563787 inst: Inst.Index,
37573788) Allocator.Error!void {
......@@ -3995,7 +4026,7 @@ fn findDeclsInner(
39954026 .struct_init,
39964027 .struct_init_ref,
39974028 .struct_init_anon,
3998 => return list.append(gpa, inst),
4029 => return contents.other.append(gpa, inst),
39994030
40004031 .extended => {
40014032 const extended = datas[@intFromEnum(inst)].extended;
......@@ -4055,21 +4086,22 @@ fn findDeclsInner(
40554086 .inplace_arith_result_ty,
40564087 .tuple_decl,
40574088 .dbg_empty_stmt,
4089 .astgen_error,
40584090 => return,
40594091
40604092 // `@TypeOf` has a body.
40614093 .typeof_peer => {
40624094 const extra = zir.extraData(Zir.Inst.TypeOfPeer, extended.operand);
40634095 const body = zir.bodySlice(extra.data.body_index, extra.data.body_len);
4064 try zir.findDeclsBody(gpa, list, defers, body);
4096 try zir.findTrackableBody(gpa, contents, defers, body);
40654097 },
40664098
40674099 // Reifications and opaque declarations need tracking, but have no body.
4068 .reify, .opaque_decl => return list.append(gpa, inst),
4100 .reify, .opaque_decl => return contents.other.append(gpa, inst),
40694101
40704102 // Struct declarations need tracking and have bodies.
40714103 .struct_decl => {
4072 try list.append(gpa, inst);
4104 try contents.explicit_types.append(gpa, inst);
40734105
40744106 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
40754107 const extra = zir.extraData(Zir.Inst.StructDecl, extended.operand);
......@@ -4098,7 +4130,7 @@ fn findDeclsInner(
40984130 } else {
40994131 const body = zir.bodySlice(extra_index, backing_int_body_len);
41004132 extra_index += backing_int_body_len;
4101 try zir.findDeclsBody(gpa, list, defers, body);
4133 try zir.findTrackableBody(gpa, contents, defers, body);
41024134 }
41034135 }
41044136 extra_index += decls_len;
......@@ -4154,12 +4186,12 @@ fn findDeclsInner(
41544186
41554187 // Now, `fields_extra_index` points to `bodies`. Let's treat this as one big body.
41564188 const merged_bodies = zir.bodySlice(fields_extra_index, total_bodies_len);
4157 try zir.findDeclsBody(gpa, list, defers, merged_bodies);
4189 try zir.findTrackableBody(gpa, contents, defers, merged_bodies);
41584190 },
41594191
41604192 // Union declarations need tracking and have a body.
41614193 .union_decl => {
4162 try list.append(gpa, inst);
4194 try contents.explicit_types.append(gpa, inst);
41634195
41644196 const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);
41654197 const extra = zir.extraData(Zir.Inst.UnionDecl, extended.operand);
......@@ -4184,12 +4216,12 @@ fn findDeclsInner(
41844216 extra_index += captures_len;
41854217 extra_index += decls_len;
41864218 const body = zir.bodySlice(extra_index, body_len);
4187 try zir.findDeclsBody(gpa, list, defers, body);
4219 try zir.findTrackableBody(gpa, contents, defers, body);
41884220 },
41894221
41904222 // Enum declarations need tracking and have a body.
41914223 .enum_decl => {
4192 try list.append(gpa, inst);
4224 try contents.explicit_types.append(gpa, inst);
41934225
41944226 const small: Zir.Inst.EnumDecl.Small = @bitCast(extended.small);
41954227 const extra = zir.extraData(Zir.Inst.EnumDecl, extended.operand);
......@@ -4214,7 +4246,7 @@ fn findDeclsInner(
42144246 extra_index += captures_len;
42154247 extra_index += decls_len;
42164248 const body = zir.bodySlice(extra_index, body_len);
4217 try zir.findDeclsBody(gpa, list, defers, body);
4249 try zir.findTrackableBody(gpa, contents, defers, body);
42184250 },
42194251 }
42204252 },
......@@ -4223,7 +4255,8 @@ fn findDeclsInner(
42234255 .func,
42244256 .func_inferred,
42254257 => {
4226 try list.append(gpa, inst);
4258 assert(contents.func_decl == null);
4259 contents.func_decl = inst;
42274260
42284261 const inst_data = datas[@intFromEnum(inst)].pl_node;
42294262 const extra = zir.extraData(Inst.Func, inst_data.payload_index);
......@@ -4234,14 +4267,15 @@ fn findDeclsInner(
42344267 else => {
42354268 const body = zir.bodySlice(extra_index, extra.data.ret_body_len);
42364269 extra_index += body.len;
4237 try zir.findDeclsBody(gpa, list, defers, body);
4270 try zir.findTrackableBody(gpa, contents, defers, body);
42384271 },
42394272 }
42404273 const body = zir.bodySlice(extra_index, extra.data.body_len);
4241 return zir.findDeclsBody(gpa, list, defers, body);
4274 return zir.findTrackableBody(gpa, contents, defers, body);
42424275 },
42434276 .func_fancy => {
4244 try list.append(gpa, inst);
4277 assert(contents.func_decl == null);
4278 contents.func_decl = inst;
42454279
42464280 const inst_data = datas[@intFromEnum(inst)].pl_node;
42474281 const extra = zir.extraData(Inst.FuncFancy, inst_data.payload_index);
......@@ -4252,7 +4286,7 @@ fn findDeclsInner(
42524286 const body_len = zir.extra[extra_index];
42534287 extra_index += 1;
42544288 const body = zir.bodySlice(extra_index, body_len);
4255 try zir.findDeclsBody(gpa, list, defers, body);
4289 try zir.findTrackableBody(gpa, contents, defers, body);
42564290 extra_index += body.len;
42574291 } else if (extra.data.bits.has_align_ref) {
42584292 extra_index += 1;
......@@ -4262,7 +4296,7 @@ fn findDeclsInner(
42624296 const body_len = zir.extra[extra_index];
42634297 extra_index += 1;
42644298 const body = zir.bodySlice(extra_index, body_len);
4265 try zir.findDeclsBody(gpa, list, defers, body);
4299 try zir.findTrackableBody(gpa, contents, defers, body);
42664300 extra_index += body.len;
42674301 } else if (extra.data.bits.has_addrspace_ref) {
42684302 extra_index += 1;
......@@ -4272,7 +4306,7 @@ fn findDeclsInner(
42724306 const body_len = zir.extra[extra_index];
42734307 extra_index += 1;
42744308 const body = zir.bodySlice(extra_index, body_len);
4275 try zir.findDeclsBody(gpa, list, defers, body);
4309 try zir.findTrackableBody(gpa, contents, defers, body);
42764310 extra_index += body.len;
42774311 } else if (extra.data.bits.has_section_ref) {
42784312 extra_index += 1;
......@@ -4282,7 +4316,7 @@ fn findDeclsInner(
42824316 const body_len = zir.extra[extra_index];
42834317 extra_index += 1;
42844318 const body = zir.bodySlice(extra_index, body_len);
4285 try zir.findDeclsBody(gpa, list, defers, body);
4319 try zir.findTrackableBody(gpa, contents, defers, body);
42864320 extra_index += body.len;
42874321 } else if (extra.data.bits.has_cc_ref) {
42884322 extra_index += 1;
......@@ -4292,7 +4326,7 @@ fn findDeclsInner(
42924326 const body_len = zir.extra[extra_index];
42934327 extra_index += 1;
42944328 const body = zir.bodySlice(extra_index, body_len);
4295 try zir.findDeclsBody(gpa, list, defers, body);
4329 try zir.findTrackableBody(gpa, contents, defers, body);
42964330 extra_index += body.len;
42974331 } else if (extra.data.bits.has_ret_ty_ref) {
42984332 extra_index += 1;
......@@ -4301,7 +4335,7 @@ fn findDeclsInner(
43014335 extra_index += @intFromBool(extra.data.bits.has_any_noalias);
43024336
43034337 const body = zir.bodySlice(extra_index, extra.data.body_len);
4304 return zir.findDeclsBody(gpa, list, defers, body);
4338 return zir.findTrackableBody(gpa, contents, defers, body);
43054339 },
43064340
43074341 // Block instructions, recurse over the bodies.
......@@ -4316,24 +4350,24 @@ fn findDeclsInner(
43164350 const inst_data = datas[@intFromEnum(inst)].pl_node;
43174351 const extra = zir.extraData(Inst.Block, inst_data.payload_index);
43184352 const body = zir.bodySlice(extra.end, extra.data.body_len);
4319 return zir.findDeclsBody(gpa, list, defers, body);
4353 return zir.findTrackableBody(gpa, contents, defers, body);
43204354 },
43214355 .condbr, .condbr_inline => {
43224356 const inst_data = datas[@intFromEnum(inst)].pl_node;
43234357 const extra = zir.extraData(Inst.CondBr, inst_data.payload_index);
43244358 const then_body = zir.bodySlice(extra.end, extra.data.then_body_len);
43254359 const else_body = zir.bodySlice(extra.end + then_body.len, extra.data.else_body_len);
4326 try zir.findDeclsBody(gpa, list, defers, then_body);
4327 try zir.findDeclsBody(gpa, list, defers, else_body);
4360 try zir.findTrackableBody(gpa, contents, defers, then_body);
4361 try zir.findTrackableBody(gpa, contents, defers, else_body);
43284362 },
43294363 .@"try", .try_ptr => {
43304364 const inst_data = datas[@intFromEnum(inst)].pl_node;
43314365 const extra = zir.extraData(Inst.Try, inst_data.payload_index);
43324366 const body = zir.bodySlice(extra.end, extra.data.body_len);
4333 try zir.findDeclsBody(gpa, list, defers, body);
4367 try zir.findTrackableBody(gpa, contents, defers, body);
43344368 },
4335 .switch_block, .switch_block_ref => return zir.findDeclsSwitch(gpa, list, defers, inst, .normal),
4336 .switch_block_err_union => return zir.findDeclsSwitch(gpa, list, defers, inst, .err_union),
4369 .switch_block, .switch_block_ref => return zir.findTrackableSwitch(gpa, contents, defers, inst, .normal),
4370 .switch_block_err_union => return zir.findTrackableSwitch(gpa, contents, defers, inst, .err_union),
43374371
43384372 .suspend_block => @panic("TODO iterate suspend block"),
43394373
......@@ -4341,7 +4375,7 @@ fn findDeclsInner(
43414375 const inst_data = datas[@intFromEnum(inst)].pl_tok;
43424376 const extra = zir.extraData(Inst.Param, inst_data.payload_index);
43434377 const body = zir.bodySlice(extra.end, extra.data.body_len);
4344 try zir.findDeclsBody(gpa, list, defers, body);
4378 try zir.findTrackableBody(gpa, contents, defers, body);
43454379 },
43464380
43474381 inline .call, .field_call => |tag| {
......@@ -4357,7 +4391,7 @@ fn findDeclsInner(
43574391 const first_arg_start_off = args_len;
43584392 const final_arg_end_off = zir.extra[extra.end + args_len - 1];
43594393 const args_body = zir.bodySlice(extra.end + first_arg_start_off, final_arg_end_off - first_arg_start_off);
4360 try zir.findDeclsBody(gpa, list, defers, args_body);
4394 try zir.findTrackableBody(gpa, contents, defers, args_body);
43614395 }
43624396 },
43634397 .@"defer" => {
......@@ -4365,7 +4399,7 @@ fn findDeclsInner(
43654399 const gop = try defers.getOrPut(gpa, inst_data.index);
43664400 if (!gop.found_existing) {
43674401 const body = zir.bodySlice(inst_data.index, inst_data.len);
4368 try zir.findDeclsBody(gpa, list, defers, body);
4402 try zir.findTrackableBody(gpa, contents, defers, body);
43694403 }
43704404 },
43714405 .defer_err_code => {
......@@ -4374,16 +4408,16 @@ fn findDeclsInner(
43744408 const gop = try defers.getOrPut(gpa, extra.index);
43754409 if (!gop.found_existing) {
43764410 const body = zir.bodySlice(extra.index, extra.len);
4377 try zir.findDeclsBody(gpa, list, defers, body);
4411 try zir.findTrackableBody(gpa, contents, defers, body);
43784412 }
43794413 },
43804414 }
43814415}
43824416
4383fn findDeclsSwitch(
4417fn findTrackableSwitch(
43844418 zir: Zir,
43854419 gpa: Allocator,
4386 list: *std.ArrayListUnmanaged(Inst.Index),
4420 contents: *DeclContents,
43874421 defers: *std.AutoHashMapUnmanaged(u32, void),
43884422 inst: Inst.Index,
43894423 /// Distinguishes between `switch_block[_ref]` and `switch_block_err_union`.
......@@ -4419,7 +4453,7 @@ fn findDeclsSwitch(
44194453 const body = zir.bodySlice(extra_index, prong_info.body_len);
44204454 extra_index += body.len;
44214455
4422 try zir.findDeclsBody(gpa, list, defers, body);
4456 try zir.findTrackableBody(gpa, contents, defers, body);
44234457
44244458 break :has_special extra.data.bits.has_else;
44254459 },
......@@ -4431,7 +4465,7 @@ fn findDeclsSwitch(
44314465 const body = zir.bodySlice(extra_index, prong_info.body_len);
44324466 extra_index += body.len;
44334467
4434 try zir.findDeclsBody(gpa, list, defers, body);
4468 try zir.findTrackableBody(gpa, contents, defers, body);
44354469 }
44364470
44374471 {
......@@ -4443,7 +4477,7 @@ fn findDeclsSwitch(
44434477 const body = zir.bodySlice(extra_index, prong_info.body_len);
44444478 extra_index += body.len;
44454479
4446 try zir.findDeclsBody(gpa, list, defers, body);
4480 try zir.findTrackableBody(gpa, contents, defers, body);
44474481 }
44484482 }
44494483 {
......@@ -4460,20 +4494,20 @@ fn findDeclsSwitch(
44604494 const body = zir.bodySlice(extra_index, prong_info.body_len);
44614495 extra_index += body.len;
44624496
4463 try zir.findDeclsBody(gpa, list, defers, body);
4497 try zir.findTrackableBody(gpa, contents, defers, body);
44644498 }
44654499 }
44664500}
44674501
4468fn findDeclsBody(
4502fn findTrackableBody(
44694503 zir: Zir,
44704504 gpa: Allocator,
4471 list: *std.ArrayListUnmanaged(Inst.Index),
4505 contents: *DeclContents,
44724506 defers: *std.AutoHashMapUnmanaged(u32, void),
44734507 body: []const Inst.Index,
44744508) Allocator.Error!void {
44754509 for (body) |member| {
4476 try zir.findDeclsInner(gpa, list, defers, member);
4510 try zir.findTrackableInner(gpa, contents, defers, member);
44774511 }
44784512}
44794513
src/Compilation.zig+21-9
......@@ -3223,17 +3223,29 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
32233223 }
32243224 }
32253225
3226 if (comp.zcu) |zcu| {
3227 if (comp.incremental and bundle.root_list.items.len == 0) {
3228 const should_have_error = for (zcu.transitive_failed_analysis.keys()) |failed_unit| {
3229 const refs = try zcu.resolveReferences();
3230 if (refs.contains(failed_unit)) break true;
3231 } else false;
3232 if (should_have_error) {
3233 @panic("referenced transitive analysis errors, but none actually emitted");
3226 // TODO: eventually, this should be behind `std.debug.runtime_safety`. But right now, this is a
3227 // very common way for incremental compilation bugs to manifest, so let's always check it.
3228 if (comp.zcu) |zcu| if (comp.incremental and bundle.root_list.items.len == 0) {
3229 for (zcu.transitive_failed_analysis.keys()) |failed_unit| {
3230 const refs = try zcu.resolveReferences();
3231 var ref = refs.get(failed_unit) orelse continue;
3232 // This AU is referenced and has a transitive compile error, meaning it referenced something with a compile error.
3233 // However, we haven't reported any such error.
3234 // This is a compiler bug.
3235 const stderr = std.io.getStdErr().writer();
3236 try stderr.writeAll("referenced transitive analysis errors, but none actually emitted\n");
3237 try stderr.print("{} [transitive failure]\n", .{zcu.fmtAnalUnit(failed_unit)});
3238 while (ref) |r| {
3239 try stderr.print("referenced by: {}{s}\n", .{
3240 zcu.fmtAnalUnit(r.referencer),
3241 if (zcu.transitive_failed_analysis.contains(r.referencer)) " [transitive failure]" else "",
3242 });
3243 ref = refs.get(r.referencer).?;
32343244 }
3245
3246 @panic("referenced transitive analysis errors, but none actually emitted");
32353247 }
3236 }
3248 };
32373249
32383250 const compile_log_text = if (comp.zcu) |m| m.compile_log_text.items else "";
32393251 return bundle.toOwnedBundle(compile_log_text);
src/InternPool.zig+20
......@@ -8616,6 +8616,16 @@ pub fn getFuncDecl(
86168616 defer gop.deinit();
86178617 if (gop == .existing) {
86188618 extra.mutate.len = prev_extra_len;
8619
8620 const zir_body_inst_ptr = ip.funcDeclInfo(gop.existing).zirBodyInstPtr(ip);
8621 if (zir_body_inst_ptr.* != key.zir_body_inst) {
8622 // Since this function's `owner_nav` matches `key`, this *is* the function we're talking
8623 // about. The only way it could have a different ZIR `func` instruction is if the old
8624 // instruction has been lost and replaced with a new `TrackedInst.Index`.
8625 assert(zir_body_inst_ptr.resolve(ip) == null);
8626 zir_body_inst_ptr.* = key.zir_body_inst;
8627 }
8628
86198629 return gop.existing;
86208630 }
86218631
......@@ -8762,6 +8772,16 @@ pub fn getFuncDeclIes(
87628772 // An existing function type was found; undo the additions to our two arrays.
87638773 items.mutate.len -= 4;
87648774 extra.mutate.len = prev_extra_len;
8775
8776 const zir_body_inst_ptr = ip.funcDeclInfo(func_gop.existing).zirBodyInstPtr(ip);
8777 if (zir_body_inst_ptr.* != key.zir_body_inst) {
8778 // Since this function's `owner_nav` matches `key`, this *is* the function we're talking
8779 // about. The only way it could have a different ZIR `func` instruction is if the old
8780 // instruction has been lost and replaced with a new `TrackedInst.Index`.
8781 assert(zir_body_inst_ptr.resolve(ip) == null);
8782 zir_body_inst_ptr.* = key.zir_body_inst;
8783 }
8784
87658785 return func_gop.existing;
87668786 }
87678787 func_gop.putTentative(func_index);
src/Sema.zig+1
......@@ -1361,6 +1361,7 @@ fn analyzeBodyInner(
13611361 i += 1;
13621362 continue;
13631363 },
1364 .astgen_error => return error.AnalysisFail,
13641365 };
13651366 },
13661367
src/Zcu.zig+61-21
......@@ -2593,26 +2593,44 @@ pub fn mapOldZirToNew(
25932593 defer match_stack.deinit(gpa);
25942594
25952595 // Used as temporary buffers for namespace declaration instructions
2596 var old_decls: std.ArrayListUnmanaged(Zir.Inst.Index) = .empty;
2597 defer old_decls.deinit(gpa);
2598 var new_decls: std.ArrayListUnmanaged(Zir.Inst.Index) = .empty;
2599 defer new_decls.deinit(gpa);
2596 var old_contents: Zir.DeclContents = .init;
2597 defer old_contents.deinit(gpa);
2598 var new_contents: Zir.DeclContents = .init;
2599 defer new_contents.deinit(gpa);
26002600
26012601 // Map the main struct inst (and anything in its fields)
26022602 {
2603 try old_zir.findDeclsRoot(gpa, &old_decls);
2604 try new_zir.findDeclsRoot(gpa, &new_decls);
2603 try old_zir.findTrackableRoot(gpa, &old_contents);
2604 try new_zir.findTrackableRoot(gpa, &new_contents);
26052605
2606 assert(old_decls.items[0] == .main_struct_inst);
2607 assert(new_decls.items[0] == .main_struct_inst);
2606 assert(old_contents.explicit_types.items[0] == .main_struct_inst);
2607 assert(new_contents.explicit_types.items[0] == .main_struct_inst);
26082608
2609 // We don't have any smart way of matching up these type declarations, so we always
2610 // correlate them based on source order.
2611 const n = @min(old_decls.items.len, new_decls.items.len);
2612 try match_stack.ensureUnusedCapacity(gpa, n);
2613 for (old_decls.items[0..n], new_decls.items[0..n]) |old_inst, new_inst| {
2609 assert(old_contents.func_decl == null);
2610 assert(new_contents.func_decl == null);
2611
2612 // We don't have any smart way of matching up these instructions, so we correlate them based on source order
2613 // in their respective arrays.
2614
2615 const num_explicit_types = @min(old_contents.explicit_types.items.len, new_contents.explicit_types.items.len);
2616 try match_stack.ensureUnusedCapacity(gpa, @intCast(num_explicit_types));
2617 for (
2618 old_contents.explicit_types.items[0..num_explicit_types],
2619 new_contents.explicit_types.items[0..num_explicit_types],
2620 ) |old_inst, new_inst| {
2621 // Here we use `match_stack`, so that we will recursively consider declarations on these types.
26142622 match_stack.appendAssumeCapacity(.{ .old_inst = old_inst, .new_inst = new_inst });
26152623 }
2624
2625 const num_other = @min(old_contents.other.items.len, new_contents.other.items.len);
2626 try inst_map.ensureUnusedCapacity(gpa, @intCast(num_other));
2627 for (
2628 old_contents.other.items[0..num_other],
2629 new_contents.other.items[0..num_other],
2630 ) |old_inst, new_inst| {
2631 // These instructions don't have declarations, so we just modify `inst_map` directly.
2632 inst_map.putAssumeCapacity(old_inst, new_inst);
2633 }
26162634 }
26172635
26182636 while (match_stack.popOrNull()) |match_item| {
......@@ -2700,17 +2718,39 @@ pub fn mapOldZirToNew(
27002718 // Match the `declaration` instruction
27012719 try inst_map.put(gpa, old_decl_inst, new_decl_inst);
27022720
2703 // Find container type declarations within this declaration
2704 try old_zir.findDecls(gpa, &old_decls, old_decl_inst);
2705 try new_zir.findDecls(gpa, &new_decls, new_decl_inst);
2721 // Find trackable instructions within this declaration
2722 try old_zir.findTrackable(gpa, &old_contents, old_decl_inst);
2723 try new_zir.findTrackable(gpa, &new_contents, new_decl_inst);
2724
2725 // We don't have any smart way of matching up these instructions, so we correlate them based on source order
2726 // in their respective arrays.
27062727
2707 // We don't have any smart way of matching up these type declarations, so we always
2708 // correlate them based on source order.
2709 const n = @min(old_decls.items.len, new_decls.items.len);
2710 try match_stack.ensureUnusedCapacity(gpa, n);
2711 for (old_decls.items[0..n], new_decls.items[0..n]) |old_inst, new_inst| {
2728 const num_explicit_types = @min(old_contents.explicit_types.items.len, new_contents.explicit_types.items.len);
2729 try match_stack.ensureUnusedCapacity(gpa, @intCast(num_explicit_types));
2730 for (
2731 old_contents.explicit_types.items[0..num_explicit_types],
2732 new_contents.explicit_types.items[0..num_explicit_types],
2733 ) |old_inst, new_inst| {
2734 // Here we use `match_stack`, so that we will recursively consider declarations on these types.
27122735 match_stack.appendAssumeCapacity(.{ .old_inst = old_inst, .new_inst = new_inst });
27132736 }
2737
2738 const num_other = @min(old_contents.other.items.len, new_contents.other.items.len);
2739 try inst_map.ensureUnusedCapacity(gpa, @intCast(num_other));
2740 for (
2741 old_contents.other.items[0..num_other],
2742 new_contents.other.items[0..num_other],
2743 ) |old_inst, new_inst| {
2744 // These instructions don't have declarations, so we just modify `inst_map` directly.
2745 inst_map.putAssumeCapacity(old_inst, new_inst);
2746 }
2747
2748 if (old_contents.func_decl) |old_func_inst| {
2749 if (new_contents.func_decl) |new_func_inst| {
2750 // There are no declarations on a function either, so again, we just directly add it to `inst_map`.
2751 try inst_map.put(gpa, old_func_inst, new_func_inst);
2752 }
2753 }
27142754 }
27152755 }
27162756}
src/Zcu/PerThread.zig+58-41
......@@ -185,11 +185,11 @@ pub fn astGenFile(
185185 log.debug("AstGen cached success: {s}", .{file.sub_file_path});
186186
187187 if (file.zir.hasCompileErrors()) {
188 {
189 comp.mutex.lock();
190 defer comp.mutex.unlock();
191 try zcu.failed_files.putNoClobber(gpa, file, null);
192 }
188 comp.mutex.lock();
189 defer comp.mutex.unlock();
190 try zcu.failed_files.putNoClobber(gpa, file, null);
191 }
192 if (file.zir.loweringFailed()) {
193193 file.status = .astgen_failure;
194194 return error.AnalysisFail;
195195 }
......@@ -226,7 +226,7 @@ pub fn astGenFile(
226226 // single-threaded context, so we need to keep both versions around
227227 // until that point in the pipeline. Previous ZIR data is freed after
228228 // that.
229 if (file.zir_loaded and !file.zir.hasCompileErrors()) {
229 if (file.zir_loaded and !file.zir.loweringFailed()) {
230230 assert(file.prev_zir == null);
231231 const prev_zir_ptr = try gpa.create(Zir);
232232 file.prev_zir = prev_zir_ptr;
......@@ -321,11 +321,11 @@ pub fn astGenFile(
321321 };
322322
323323 if (file.zir.hasCompileErrors()) {
324 {
325 comp.mutex.lock();
326 defer comp.mutex.unlock();
327 try zcu.failed_files.putNoClobber(gpa, file, null);
328 }
324 comp.mutex.lock();
325 defer comp.mutex.unlock();
326 try zcu.failed_files.putNoClobber(gpa, file, null);
327 }
328 if (file.zir.loweringFailed()) {
329329 file.status = .astgen_failure;
330330 return error.AnalysisFail;
331331 }
......@@ -363,7 +363,7 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
363363 .file = file,
364364 .inst_map = .{},
365365 };
366 if (!new_zir.hasCompileErrors()) {
366 if (!new_zir.loweringFailed()) {
367367 try Zcu.mapOldZirToNew(gpa, old_zir.*, file.zir, &gop.value_ptr.inst_map);
368368 }
369369 }
......@@ -379,20 +379,19 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
379379
380380 const file = updated_file.file;
381381
382 if (file.zir.hasCompileErrors()) {
383 // If we mark this as outdated now, users of this inst will just get a transitive analysis failure.
384 // Ultimately, they would end up throwing out potentially useful analysis results.
385 // So, do nothing. We already have the file failure -- that's sufficient for now!
386 continue;
387 }
388382 const old_inst = tracked_inst.inst.unwrap() orelse continue; // we can't continue tracking lost insts
389383 const tracked_inst_index = (InternPool.TrackedInst.Index.Unwrapped{
390384 .tid = @enumFromInt(tid),
391385 .index = @intCast(tracked_inst_unwrapped_index),
392386 }).wrap(ip);
393387 const new_inst = updated_file.inst_map.get(old_inst) orelse {
394 // Tracking failed for this instruction. Invalidate associated `src_hash` deps.
395 log.debug("tracking failed for %{d}", .{old_inst});
388 // Tracking failed for this instruction.
389 // This may be due to changes in the ZIR, or AstGen might have failed due to a very broken file.
390 // Either way, invalidate associated `src_hash` deps.
391 log.debug("tracking failed for %{d}{s}", .{
392 old_inst,
393 if (file.zir.loweringFailed()) " due to AstGen failure" else "",
394 });
396395 tracked_inst.inst = .lost;
397396 try zcu.markDependeeOutdated(.not_marked_po, .{ .src_hash = tracked_inst_index });
398397 continue;
......@@ -494,8 +493,8 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
494493
495494 for (updated_files.keys(), updated_files.values()) |file_index, updated_file| {
496495 const file = updated_file.file;
497 if (file.zir.hasCompileErrors()) {
498 // Keep `prev_zir` around: it's the last non-error ZIR.
496 if (file.zir.loweringFailed()) {
497 // Keep `prev_zir` around: it's the last usable ZIR.
499498 // Don't update the namespace, as we have no new data to update *to*.
500499 } else {
501500 const prev_zir = file.prev_zir.?;
......@@ -539,7 +538,7 @@ pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu
539538 const anal_unit = AnalUnit.wrap(.{ .cau = cau_index });
540539 const cau = ip.getCau(cau_index);
541540
542 log.debug("ensureCauAnalyzed {d}", .{@intFromEnum(cau_index)});
541 log.debug("ensureCauAnalyzed {}", .{zcu.fmtAnalUnit(anal_unit)});
543542
544543 assert(!zcu.analysis_in_progress.contains(anal_unit));
545544
......@@ -577,13 +576,19 @@ pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu
577576 }
578577
579578 const sema_result: SemaCauResult, const analysis_fail = if (pt.ensureCauAnalyzedInner(cau_index, cau_outdated)) |result|
580 .{ result, false }
579 // This `Cau` has gone from failed to success, so even if the value of the owner `Nav` didn't actually
580 // change, we need to invalidate the dependencies anyway.
581 .{ .{
582 .invalidate_decl_val = result.invalidate_decl_val or prev_failed,
583 .invalidate_decl_ref = result.invalidate_decl_ref or prev_failed,
584 }, false }
581585 else |err| switch (err) {
582586 error.AnalysisFail => res: {
583587 if (!zcu.failed_analysis.contains(anal_unit)) {
584588 // If this `Cau` caused the error, it would have an entry in `failed_analysis`.
585589 // Since it does not, this must be a transitive failure.
586590 try zcu.transitive_failed_analysis.put(gpa, anal_unit, {});
591 log.debug("mark transitive analysis failure for {}", .{zcu.fmtAnalUnit(anal_unit)});
587592 }
588593 // We consider this `Cau` to be outdated if:
589594 // * Previous analysis succeeded; in this case, we need to re-analyze dependants to ensure
......@@ -708,12 +713,12 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter
708713
709714 // We only care about the uncoerced function.
710715 const func_index = ip.unwrapCoercedFunc(maybe_coerced_func_index);
716 const anal_unit = AnalUnit.wrap(.{ .func = func_index });
711717
712 const func = zcu.funcInfo(maybe_coerced_func_index);
718 log.debug("ensureFuncBodyAnalyzed {}", .{zcu.fmtAnalUnit(anal_unit)});
713719
714 log.debug("ensureFuncBodyAnalyzed {d}", .{@intFromEnum(func_index)});
720 const func = zcu.funcInfo(maybe_coerced_func_index);
715721
716 const anal_unit = AnalUnit.wrap(.{ .func = func_index });
717722 const func_outdated = zcu.outdated.swapRemove(anal_unit) or
718723 zcu.potentially_outdated.swapRemove(anal_unit);
719724
......@@ -741,6 +746,7 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter
741746 // If this function caused the error, it would have an entry in `failed_analysis`.
742747 // Since it does not, this must be a transitive failure.
743748 try zcu.transitive_failed_analysis.put(gpa, anal_unit, {});
749 log.debug("mark transitive analysis failure for {}", .{zcu.fmtAnalUnit(anal_unit)});
744750 }
745751 // We consider the IES to be outdated if the function previously succeeded analysis; in this case,
746752 // we need to re-analyze dependants to ensure they hit a transitive error here, rather than reporting
......@@ -752,10 +758,8 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter
752758
753759 if (func_outdated) {
754760 if (ies_outdated) {
755 log.debug("func IES invalidated ('{d}')", .{@intFromEnum(func_index)});
756761 try zcu.markDependeeOutdated(.marked_po, .{ .interned = func_index });
757762 } else {
758 log.debug("func IES up-to-date ('{d}')", .{@intFromEnum(func_index)});
759763 try zcu.markPoDependeeUpToDate(.{ .interned = func_index });
760764 }
761765 }
......@@ -780,6 +784,7 @@ fn ensureFuncBodyAnalyzedInner(
780784 // results in the worst case.
781785
782786 if (func.generic_owner == .none) {
787 // Among another things, this ensures that the function's `zir_body_inst` is correct.
783788 try pt.ensureCauAnalyzed(ip.getNav(func.owner_nav).analysis_owner.unwrap().?);
784789 if (ip.getNav(func.owner_nav).status.resolved.val != func_index) {
785790 // This function is no longer referenced! There's no point in re-analyzing it.
......@@ -788,6 +793,7 @@ fn ensureFuncBodyAnalyzedInner(
788793 }
789794 } else {
790795 const go_nav = zcu.funcInfo(func.generic_owner).owner_nav;
796 // Among another things, this ensures that the function's `zir_body_inst` is correct.
791797 try pt.ensureCauAnalyzed(ip.getNav(go_nav).analysis_owner.unwrap().?);
792798 if (ip.getNav(go_nav).status.resolved.val != func.generic_owner) {
793799 // The generic owner is no longer referenced, so this function is also unreferenced.
......@@ -825,8 +831,8 @@ fn ensureFuncBodyAnalyzedInner(
825831 }
826832 }
827833
828 log.debug("analyze and generate fn body '{d}'; reason='{s}'", .{
829 @intFromEnum(func_index),
834 log.debug("analyze and generate fn body {}; reason='{s}'", .{
835 zcu.fmtAnalUnit(anal_unit),
830836 if (func_outdated) "outdated" else "never analyzed",
831837 });
832838
......@@ -1165,7 +1171,7 @@ fn semaCau(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) !SemaCauResult {
11651171 .none, .type => false,
11661172 };
11671173
1168 log.debug("semaCau '{d}'", .{@intFromEnum(cau_index)});
1174 log.debug("semaCau {}", .{zcu.fmtAnalUnit(anal_unit)});
11691175
11701176 try zcu.analysis_in_progress.put(gpa, anal_unit, {});
11711177 errdefer _ = zcu.analysis_in_progress.swapRemove(anal_unit);
......@@ -2308,16 +2314,14 @@ pub fn getErrorValueFromSlice(pt: Zcu.PerThread, name: []const u8) Allocator.Err
23082314 return pt.getErrorValue(try pt.zcu.intern_pool.getOrPutString(pt.zcu.gpa, name));
23092315}
23102316
2317/// Removes any entry from `Zcu.failed_files` associated with `file`. Acquires `Compilation.mutex` as needed.
2318/// `file.zir` must be unchanged from the last update, as it is used to determine if there is such an entry.
23112319fn lockAndClearFileCompileError(pt: Zcu.PerThread, file: *Zcu.File) void {
2312 switch (file.status) {
2313 .success_zir, .retryable_failure => {},
2314 .never_loaded, .parse_failure, .astgen_failure => {
2315 pt.zcu.comp.mutex.lock();
2316 defer pt.zcu.comp.mutex.unlock();
2317 if (pt.zcu.failed_files.fetchSwapRemove(file)) |kv| {
2318 if (kv.value) |msg| msg.destroy(pt.zcu.gpa); // Delete previous error message.
2319 }
2320 },
2320 if (!file.zir_loaded or !file.zir.hasCompileErrors()) return;
2321 pt.zcu.comp.mutex.lock();
2322 defer pt.zcu.comp.mutex.unlock();
2323 if (pt.zcu.failed_files.fetchSwapRemove(file)) |kv| {
2324 if (kv.value) |msg| msg.destroy(pt.zcu.gpa); // Delete previous error message.
23212325 }
23222326}
23232327
......@@ -2507,6 +2511,19 @@ pub fn populateTestFunctions(
25072511
25082512 for (test_fn_vals, zcu.test_functions.keys()) |*test_fn_val, test_nav_index| {
25092513 const test_nav = ip.getNav(test_nav_index);
2514
2515 {
2516 // The test declaration might have failed; if that's the case, just return, as we'll
2517 // be emitting a compile error anyway.
2518 const cau = test_nav.analysis_owner.unwrap().?;
2519 const anal_unit: AnalUnit = .wrap(.{ .cau = cau });
2520 if (zcu.failed_analysis.contains(anal_unit) or
2521 zcu.transitive_failed_analysis.contains(anal_unit))
2522 {
2523 return;
2524 }
2525 }
2526
25102527 const test_nav_name = test_nav.fqn;
25112528 const test_nav_name_len = test_nav_name.length(ip);
25122529 const test_name_anon_decl: InternPool.Key.Ptr.BaseAddr.Uav = n: {
src/main.zig+18-5
......@@ -6097,11 +6097,18 @@ fn cmdAstCheck(
60976097 var error_bundle = try wip_errors.toOwnedBundle("");
60986098 defer error_bundle.deinit(gpa);
60996099 error_bundle.renderToStdErr(color.renderOptions());
6100 process.exit(1);
6100
6101 if (file.zir.loweringFailed()) {
6102 process.exit(1);
6103 }
61016104 }
61026105
61036106 if (!want_output_text) {
6104 return cleanExit();
6107 if (file.zir.hasCompileErrors()) {
6108 process.exit(1);
6109 } else {
6110 return cleanExit();
6111 }
61056112 }
61066113 if (!build_options.enable_debug_extensions) {
61076114 fatal("-t option only available in builds of zig with debug extensions", .{});
......@@ -6145,7 +6152,13 @@ fn cmdAstCheck(
61456152 // zig fmt: on
61466153 }
61476154
6148 return @import("print_zir.zig").renderAsTextToFile(gpa, &file, io.getStdOut());
6155 try @import("print_zir.zig").renderAsTextToFile(gpa, &file, io.getStdOut());
6156
6157 if (file.zir.hasCompileErrors()) {
6158 process.exit(1);
6159 } else {
6160 return cleanExit();
6161 }
61496162}
61506163
61516164fn cmdDetectCpu(
......@@ -6458,7 +6471,7 @@ fn cmdChangelist(
64586471 file.zir_loaded = true;
64596472 defer file.zir.deinit(gpa);
64606473
6461 if (file.zir.hasCompileErrors()) {
6474 if (file.zir.loweringFailed()) {
64626475 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
64636476 try wip_errors.init(gpa);
64646477 defer wip_errors.deinit();
......@@ -6493,7 +6506,7 @@ fn cmdChangelist(
64936506 file.zir = try AstGen.generate(gpa, new_tree);
64946507 file.zir_loaded = true;
64956508
6496 if (file.zir.hasCompileErrors()) {
6509 if (file.zir.loweringFailed()) {
64976510 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
64986511 try wip_errors.init(gpa);
64996512 defer wip_errors.deinit();
src/print_zir.zig+1
......@@ -623,6 +623,7 @@ const Writer = struct {
623623 .inplace_arith_result_ty => try self.writeInplaceArithResultTy(stream, extended),
624624
625625 .dbg_empty_stmt => try stream.writeAll("))"),
626 .astgen_error => try stream.writeAll("))"),
626627 }
627628 }
628629
test/cases/compile_errors/access_invalid_typeInfo_decl.zig+3-6
......@@ -1,11 +1,8 @@
1const A = B;
2test "Crash" {
1pub const A = B;
2export fn foo() void {
33 _ = @typeInfo(@This()).@"struct".decls[0];
44}
55
66// error
7// backend=stage2
8// target=native
9// is_test=true
107//
11// :1:11: error: use of undeclared identifier 'B'
8// :1:15: error: use of undeclared identifier 'B'
test/cases/compile_errors/astgen_sema_errors_combined.zig created+17
......@@ -0,0 +1,17 @@
1const a = bogus; // astgen error (undeclared identifier)
2const b: u32 = "hi"; // sema error (type mismatch)
3
4comptime {
5 _ = b;
6 @compileError("not hit because 'b' failed");
7}
8
9comptime {
10 @compileError("this should be hit");
11}
12
13// error
14//
15// :1:11: error: use of undeclared identifier 'bogus'
16// :2:16: error: expected type 'u32', found '*const [2:0]u8'
17// :10:5: error: this should be hit
test/cases/compile_errors/colliding_invalid_top_level_functions.zig+2-7
......@@ -1,13 +1,8 @@
1fn func() bogus {}
2fn func() bogus {}
3export fn entry() usize {
4 return @sizeOf(@TypeOf(func));
5}
1fn func() void {}
2fn func() void {}
63
74// error
85//
96// :1:4: error: duplicate struct member name 'func'
107// :2:4: note: duplicate name here
118// :1:1: note: struct declared here
12// :1:11: error: use of undeclared identifier 'bogus'
13// :2:11: error: use of undeclared identifier 'bogus'
test/cases/compile_errors/constant_inside_comptime_function_has_compile_error.zig+2
......@@ -19,3 +19,5 @@ export fn entry() void {
1919//
2020// :4:5: error: unreachable code
2121// :4:25: note: control flow is diverted here
22// :4:25: error: aoeu
23// :1:36: note: called from here
test/cases/compile_errors/invalid_compare_string.zig+13-7
......@@ -1,22 +1,27 @@
11comptime {
22 const a = "foo";
3 if (a == "foo") unreachable;
3 if (a != "foo") unreachable;
44}
55comptime {
66 const a = "foo";
7 if (a == ("foo")) unreachable; // intentionally allow
7 if (a == "foo") {} else unreachable;
8}
9comptime {
10 const a = "foo";
11 if (a != ("foo")) {} // intentionally allow
12 if (a == ("foo")) {} // intentionally allow
813}
914comptime {
1015 const a = "foo";
1116 switch (a) {
12 "foo" => unreachable,
13 else => {},
17 "foo" => {},
18 else => unreachable,
1419 }
1520}
1621comptime {
1722 const a = "foo";
1823 switch (a) {
19 ("foo") => unreachable, // intentionally allow
24 ("foo") => {}, // intentionally allow
2025 else => {},
2126 }
2227}
......@@ -25,5 +30,6 @@ comptime {
2530// backend=stage2
2631// target=native
2732//
28// :3:11: error: cannot compare strings with ==
29// :12:9: error: cannot switch on strings
33// :3:11: error: cannot compare strings with !=
34// :7:11: error: cannot compare strings with ==
35// :17:9: error: cannot switch on strings
test/cases/compile_errors/invalid_decltest.zig+1-1
......@@ -1,6 +1,6 @@
11export fn foo() void {
22 const a = 1;
3 struct {
3 _ = struct {
44 test a {}
55 };
66}
test/cases/compile_errors/misspelled_type_with_pointer_only_reference.zig-4
......@@ -28,10 +28,6 @@ fn foo() void {
2828 _ = jd;
2929}
3030
31export fn entry() usize {
32 return @sizeOf(@TypeOf(foo));
33}
34
3531// error
3632// backend=stage2
3733// target=native
test/cases/compile_errors/noreturn_builtins_divert_control_flow.zig+2-1
......@@ -7,7 +7,7 @@ export fn entry2() void {
77 @panic("");
88}
99export fn entry3() void {
10 @compileError("");
10 @compileError("expect to hit this");
1111 @compileError("");
1212}
1313
......@@ -21,3 +21,4 @@ export fn entry3() void {
2121// :6:5: note: control flow is diverted here
2222// :11:5: error: unreachable code
2323// :10:5: note: control flow is diverted here
24// :10:5: error: expect to hit this
test/cases/function_redeclaration.zig-6
......@@ -2,14 +2,8 @@
22fn entry() void {}
33fn entry() void {}
44
5fn foo() void {
6 var foo = 1234;
7}
8
95// error
106//
117// :2:4: error: duplicate struct member name 'entry'
128// :3:4: note: duplicate name here
139// :2:1: note: struct declared here
14// :6:9: error: local variable shadows declaration of 'foo'
15// :5:1: note: declared here
test/cases/unused_vars.zig+1-1
......@@ -1,6 +1,6 @@
11pub fn main() void {
22 const x = 1;
3 const y, var z = .{ 2, 3 };
3 const y, var z: u32 = .{ 2, 3 };
44}
55
66// error