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 {...@@ -74,6 +74,12 @@ pub fn MultiArrayList(comptime T: type) type {
74 len: usize,74 len: usize,
75 capacity: usize,75 capacity: usize,
7676
77 pub const empty: Slice = .{
78 .ptrs = undefined,
79 .len = 0,
80 .capacity = 0,
81 };
82
77 pub fn items(self: Slice, comptime field: Field) []FieldType(field) {83 pub fn items(self: Slice, comptime field: Field) []FieldType(field) {
78 const F = FieldType(field);84 const F = FieldType(field);
79 if (self.capacity == 0) {85 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 {...@@ -172,9 +172,9 @@ pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir {
172 };172 };
173 defer gz_instructions.deinit(gpa);173 defer gz_instructions.deinit(gpa);
174174
175 // The AST -> ZIR lowering process assumes an AST that does not have any175 // The AST -> ZIR lowering process assumes an AST that does not have any parse errors.
176 // parse errors.176 // Parse errors, or AstGen errors in the root struct, are considered "fatal", so we emit no ZIR.
177 if (tree.errors.len == 0) {177 const fatal = if (tree.errors.len == 0) fatal: {
178 if (AstGen.structDeclInner(178 if (AstGen.structDeclInner(
179 &gen_scope,179 &gen_scope,
180 &gen_scope.base,180 &gen_scope.base,
...@@ -184,13 +184,15 @@ pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir {...@@ -184,13 +184,15 @@ pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir {
184 0,184 0,
185 )) |struct_decl_ref| {185 )) |struct_decl_ref| {
186 assert(struct_decl_ref.toIndex().? == .main_struct_inst);186 assert(struct_decl_ref.toIndex().? == .main_struct_inst);
187 break :fatal false;
187 } else |err| switch (err) {188 } else |err| switch (err) {
188 error.OutOfMemory => return error.OutOfMemory,189 error.OutOfMemory => return error.OutOfMemory,
189 error.AnalysisFail => {}, // Handled via compile_errors below.190 error.AnalysisFail => break :fatal true, // Handled via compile_errors below.
190 }191 }
191 } else {192 } else fatal: {
192 try lowerAstErrors(&astgen);193 try lowerAstErrors(&astgen);
193 }194 break :fatal true;
195 };
194196
195 const err_index = @intFromEnum(Zir.ExtraIndex.compile_errors);197 const err_index = @intFromEnum(Zir.ExtraIndex.compile_errors);
196 if (astgen.compile_errors.items.len == 0) {198 if (astgen.compile_errors.items.len == 0) {
...@@ -228,8 +230,8 @@ pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir {...@@ -228,8 +230,8 @@ pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir {
228 }230 }
229 }231 }
230232
231 return Zir{233 return .{
232 .instructions = astgen.instructions.toOwnedSlice(),234 .instructions = if (fatal) .empty else astgen.instructions.toOwnedSlice(),
233 .string_bytes = try astgen.string_bytes.toOwnedSlice(gpa),235 .string_bytes = try astgen.string_bytes.toOwnedSlice(gpa),
234 .extra = try astgen.extra.toOwnedSlice(gpa),236 .extra = try astgen.extra.toOwnedSlice(gpa),
235 };237 };
...@@ -2110,7 +2112,7 @@ fn comptimeExprAst(...@@ -2110,7 +2112,7 @@ fn comptimeExprAst(
2110) InnerError!Zir.Inst.Ref {2112) InnerError!Zir.Inst.Ref {
2111 const astgen = gz.astgen;2113 const astgen = gz.astgen;
2112 if (gz.is_comptime) {2114 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", .{});
2114 }2116 }
2115 const tree = astgen.tree;2117 const tree = astgen.tree;
2116 const node_datas = tree.nodes.items(.data);2118 const node_datas = tree.nodes.items(.data);
...@@ -3269,6 +3271,9 @@ fn varDecl(...@@ -3269,6 +3271,9 @@ fn varDecl(
3269 try astgen.appendErrorTok(comptime_token, "'comptime const' is redundant; instead wrap the initialization expression with 'comptime'", .{});3271 try astgen.appendErrorTok(comptime_token, "'comptime const' is redundant; instead wrap the initialization expression with 'comptime'", .{});
3270 }3272 }
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
3272 // Depending on the type of AST the initialization expression is, we may need an lvalue3277 // Depending on the type of AST the initialization expression is, we may need an lvalue
3273 // or an rvalue as a result location. If it is an rvalue, we can use the instruction as3278 // or an rvalue as a result location. If it is an rvalue, we can use the instruction as
3274 // the variable, no memory location needed.3279 // the variable, no memory location needed.
...@@ -3282,7 +3287,7 @@ fn varDecl(...@@ -3282,7 +3287,7 @@ fn varDecl(
3282 } else .{ .rl = .none, .ctx = .const_init };3287 } else .{ .rl = .none, .ctx = .const_init };
3283 const prev_anon_name_strategy = gz.anon_name_strategy;3288 const prev_anon_name_strategy = gz.anon_name_strategy;
3284 gz.anon_name_strategy = .dbg_var;3289 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);
3286 gz.anon_name_strategy = prev_anon_name_strategy;3291 gz.anon_name_strategy = prev_anon_name_strategy;
32873292
3288 try gz.addDbgVar(.dbg_var_val, ident_name, init_inst);3293 try gz.addDbgVar(.dbg_var_val, ident_name, init_inst);
...@@ -3348,7 +3353,7 @@ fn varDecl(...@@ -3348,7 +3353,7 @@ fn varDecl(
3348 const prev_anon_name_strategy = gz.anon_name_strategy;3353 const prev_anon_name_strategy = gz.anon_name_strategy;
3349 gz.anon_name_strategy = .dbg_var;3354 gz.anon_name_strategy = .dbg_var;
3350 defer gz.anon_name_strategy = prev_anon_name_strategy;3355 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
3353 // The const init expression may have modified the error return trace, so signal3358 // The const init expression may have modified the error return trace, so signal
3354 // to Sema that it should save the new index for restoring later.3359 // 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...@@ -3491,7 +3496,7 @@ fn assignDestructure(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerErro
34913496
3492 const full = tree.assignDestructure(node);3497 const full = tree.assignDestructure(node);
3493 if (full.comptime_token != null and gz.is_comptime) {3498 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", .{});
3495 }3500 }
34963501
3497 // If this expression is marked comptime, we must wrap the whole thing in a comptime block.3502 // If this expression is marked comptime, we must wrap the whole thing in a comptime block.
...@@ -3550,7 +3555,7 @@ fn assignDestructureMaybeDecls(...@@ -3550,7 +3555,7 @@ fn assignDestructureMaybeDecls(
35503555
3551 const full = tree.assignDestructure(node);3556 const full = tree.assignDestructure(node);
3552 if (full.comptime_token != null and gz.is_comptime) {3557 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", .{});
3554 }3559 }
35553560
3556 const is_comptime = full.comptime_token != null or gz.is_comptime;3561 const is_comptime = full.comptime_token != null or gz.is_comptime;
...@@ -3664,6 +3669,7 @@ fn assignDestructureMaybeDecls(...@@ -3664,6 +3669,7 @@ fn assignDestructureMaybeDecls(
36643669
3665 if (full.comptime_token != null and !any_non_const_variables) {3670 if (full.comptime_token != null and !any_non_const_variables) {
3666 try astgen.appendErrorTok(full.comptime_token.?, "'comptime const' is redundant; instead wrap the initialization expression with 'comptime'", .{});3671 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.
3667 }3673 }
36683674
3669 // If this expression is marked comptime, we must wrap it in a comptime block.3675 // If this expression is marked comptime, we must wrap it in a comptime block.
...@@ -4112,8 +4118,8 @@ fn fnDecl(...@@ -4112,8 +4118,8 @@ fn fnDecl(
4112 // The source slice is added towards the *end* of this function.4118 // The source slice is added towards the *end* of this function.
4113 astgen.src_hasher.update(std.mem.asBytes(&astgen.source_column));4119 astgen.src_hasher.update(std.mem.asBytes(&astgen.source_column));
41144120
4115 // missing function name already happened in scanContainer()4121 // missing function name already checked in scanContainer()
4116 const fn_name_token = fn_proto.name_token orelse return error.AnalysisFail;4122 const fn_name_token = fn_proto.name_token.?;
41174123
4118 // We insert this at the beginning so that its instruction index marks the4124 // We insert this at the beginning so that its instruction index marks the
4119 // start of the top level declaration.4125 // start of the top level declaration.
...@@ -5182,8 +5188,7 @@ fn structDeclInner(...@@ -5182,8 +5188,7 @@ fn structDeclInner(
51825188
5183 if (is_comptime) {5189 if (is_comptime) {
5184 switch (layout) {5190 switch (layout) {
5185 .@"packed" => return astgen.failTok(member.comptime_token.?, "packed struct fields cannot be marked comptime", .{}),5191 .@"packed", .@"extern" => return astgen.failTok(member.comptime_token.?, "{s} struct fields cannot be marked comptime", .{@tagName(layout)}),
5186 .@"extern" => return astgen.failTok(member.comptime_token.?, "extern struct fields cannot be marked comptime", .{}),
5187 .auto => any_comptime_fields = true,5192 .auto => any_comptime_fields = true,
5188 }5193 }
5189 } else {5194 } else {
...@@ -5210,7 +5215,7 @@ fn structDeclInner(...@@ -5210,7 +5215,7 @@ fn structDeclInner(
52105215
5211 if (have_align) {5216 if (have_align) {
5212 if (layout == .@"packed") {5217 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", .{});
5214 }5219 }
5215 any_aligned_fields = true;5220 any_aligned_fields = true;
5216 const align_ref = try expr(&block_scope, &namespace.base, coerced_align_ri, member.ast.align_expr);5221 const align_ref = try expr(&block_scope, &namespace.base, coerced_align_ri, member.ast.align_expr);
...@@ -5304,8 +5309,7 @@ fn tupleDecl(...@@ -5304,8 +5309,7 @@ fn tupleDecl(
53045309
5305 switch (layout) {5310 switch (layout) {
5306 .auto => {},5311 .auto => {},
5307 .@"extern" => return astgen.failNode(node, "extern tuples are not supported", .{}),5312 .@"extern", .@"packed" => return astgen.failNode(node, "{s} tuples are not supported", .{@tagName(layout)}),
5308 .@"packed" => return astgen.failNode(node, "packed tuples are not supported", .{}),
5309 }5313 }
53105314
5311 if (backing_int_node != 0) {5315 if (backing_int_node != 0) {
...@@ -5688,7 +5692,7 @@ fn containerDecl(...@@ -5688,7 +5692,7 @@ fn containerDecl(
5688 };5692 };
5689 };5693 };
5690 if (counts.nonexhaustive_node != 0 and container_decl.ast.arg == 0) {5694 if (counts.nonexhaustive_node != 0 and container_decl.ast.arg == 0) {
5691 try astgen.appendErrorNodeNotes(5695 return astgen.failNodeNotes(
5692 node,5696 node,
5693 "non-exhaustive enum missing integer tag type",5697 "non-exhaustive enum missing integer tag type",
5694 .{},5698 .{},
...@@ -5911,9 +5915,19 @@ fn containerMember(...@@ -5911,9 +5915,19 @@ fn containerMember(
5911 const full = tree.fullFnProto(&buf, member_node).?;5915 const full = tree.fullFnProto(&buf, member_node).?;
5912 const body = if (node_tags[member_node] == .fn_decl) node_datas[member_node].rhs else 0;5916 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;
5914 astgen.fnDecl(gz, scope, wip_members, member_node, body, full) catch |err| switch (err) {5919 astgen.fnDecl(gz, scope, wip_members, member_node, body, full) catch |err| switch (err) {
5915 error.OutOfMemory => return error.OutOfMemory,5920 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 },
5917 };5931 };
5918 },5932 },
59195933
...@@ -5922,28 +5936,77 @@ fn containerMember(...@@ -5922,28 +5936,77 @@ fn containerMember(
5922 .simple_var_decl,5936 .simple_var_decl,
5923 .aligned_var_decl,5937 .aligned_var_decl,
5924 => {5938 => {
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) {
5926 error.OutOfMemory => return error.OutOfMemory,5942 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 },
5928 };5953 };
5929 },5954 },
59305955
5931 .@"comptime" => {5956 .@"comptime" => {
5957 const prev_decl_index = wip_members.decl_index;
5932 astgen.comptimeDecl(gz, scope, wip_members, member_node) catch |err| switch (err) {5958 astgen.comptimeDecl(gz, scope, wip_members, member_node) catch |err| switch (err) {
5933 error.OutOfMemory => return error.OutOfMemory,5959 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 },
5935 };5970 };
5936 },5971 },
5937 .@"usingnamespace" => {5972 .@"usingnamespace" => {
5973 const prev_decl_index = wip_members.decl_index;
5938 astgen.usingnamespaceDecl(gz, scope, wip_members, member_node) catch |err| switch (err) {5974 astgen.usingnamespaceDecl(gz, scope, wip_members, member_node) catch |err| switch (err) {
5939 error.OutOfMemory => return error.OutOfMemory,5975 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 },
5941 };5991 };
5942 },5992 },
5943 .test_decl => {5993 .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.
5944 astgen.testDecl(gz, scope, wip_members, member_node) catch |err| switch (err) {5998 astgen.testDecl(gz, scope, wip_members, member_node) catch |err| switch (err) {
5945 error.OutOfMemory => return error.OutOfMemory,5999 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 },
5947 };6010 };
5948 },6011 },
5949 else => unreachable,6012 else => unreachable,
...@@ -6155,7 +6218,7 @@ fn orelseCatchExpr(...@@ -6155,7 +6218,7 @@ fn orelseCatchExpr(
6155 const payload = payload_token orelse break :blk &else_scope.base;6218 const payload = payload_token orelse break :blk &else_scope.base;
6156 const err_str = tree.tokenSlice(payload);6219 const err_str = tree.tokenSlice(payload);
6157 if (mem.eql(u8, err_str, "_")) {6220 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", .{});
6159 }6222 }
6160 const err_name = try astgen.identAsString(payload);6223 const err_name = try astgen.identAsString(payload);
61616224
...@@ -6614,7 +6677,7 @@ fn whileExpr(...@@ -6614,7 +6677,7 @@ fn whileExpr(
66146677
6615 const is_inline = while_full.inline_token != null;6678 const is_inline = while_full.inline_token != null;
6616 if (parent_gz.is_comptime and is_inline) {6679 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", .{});
6618 }6681 }
6619 const loop_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .loop;6682 const loop_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .loop;
6620 const loop_block = try parent_gz.makeBlockInst(loop_tag, node);6683 const loop_block = try parent_gz.makeBlockInst(loop_tag, node);
...@@ -6904,7 +6967,7 @@ fn forExpr(...@@ -6904,7 +6967,7 @@ fn forExpr(
69046967
6905 const is_inline = for_full.inline_token != null;6968 const is_inline = for_full.inline_token != null;
6906 if (parent_gz.is_comptime and is_inline) {6969 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", .{});
6908 }6971 }
6909 const tree = astgen.tree;6972 const tree = astgen.tree;
6910 const token_tags = tree.tokens.items(.tag);6973 const token_tags = tree.tokens.items(.tag);
...@@ -6965,7 +7028,7 @@ fn forExpr(...@@ -6965,7 +7028,7 @@ fn forExpr(
6965 .none;7028 .none;
69667029
6967 if (end_val == .none and is_discard) {7030 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", .{});
6969 }7032 }
69707033
6971 const start_is_zero = nodeIsTriviallyZero(tree, start_node);7034 const start_is_zero = nodeIsTriviallyZero(tree, start_node);
...@@ -7467,6 +7530,7 @@ fn switchExprErrUnion(...@@ -7467,6 +7530,7 @@ fn switchExprErrUnion(
7467 const err_name = blk: {7530 const err_name = blk: {
7468 const err_str = tree.tokenSlice(error_payload);7531 const err_str = tree.tokenSlice(error_payload);
7469 if (mem.eql(u8, err_str, "_")) {7532 if (mem.eql(u8, err_str, "_")) {
7533 // This is fatal because we already know we're switching on the captured error.
7470 return astgen.failTok(error_payload, "discard of error capture; omit it instead", .{});7534 return astgen.failTok(error_payload, "discard of error capture; omit it instead", .{});
7471 }7535 }
7472 const err_name = try astgen.identAsString(error_payload);7536 const err_name = try astgen.identAsString(error_payload);
...@@ -7521,7 +7585,7 @@ fn switchExprErrUnion(...@@ -7521,7 +7585,7 @@ fn switchExprErrUnion(
75217585
7522 const capture_slice = tree.tokenSlice(capture_token);7586 const capture_slice = tree.tokenSlice(capture_token);
7523 if (mem.eql(u8, capture_slice, "_")) {7587 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", .{});
7525 }7589 }
7526 const tag_name = try astgen.identAsString(capture_token);7590 const tag_name = try astgen.identAsString(capture_token);
7527 try astgen.detectLocalShadowing(&case_scope.base, tag_name, capture_token, capture_slice, .capture);7591 try astgen.detectLocalShadowing(&case_scope.base, tag_name, capture_token, capture_slice, .capture);
...@@ -7992,7 +8056,7 @@ fn switchExpr(...@@ -7992,7 +8056,7 @@ fn switchExpr(
7992 break :blk payload_sub_scope;8056 break :blk payload_sub_scope;
7993 const tag_slice = tree.tokenSlice(tag_token);8057 const tag_slice = tree.tokenSlice(tag_token);
7994 if (mem.eql(u8, tag_slice, "_")) {8058 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", .{});
7996 } else if (case.inline_token == null) {8060 } else if (case.inline_token == null) {
7997 return astgen.failTok(tag_token, "tag capture on non-inline prong", .{});8061 return astgen.failTok(tag_token, "tag capture on non-inline prong", .{});
7998 }8062 }
...@@ -13678,6 +13742,8 @@ fn scanContainer(...@@ -13678,6 +13742,8 @@ fn scanContainer(
13678 const main_tokens = tree.nodes.items(.main_token);13742 const main_tokens = tree.nodes.items(.main_token);
13679 const token_tags = tree.tokens.items(.tag);13743 const token_tags = tree.tokens.items(.tag);
1368013744
13745 var any_invalid_declarations = false;
13746
13681 // This type forms a linked list of source tokens declaring the same name.13747 // This type forms a linked list of source tokens declaring the same name.
13682 const NameEntry = struct {13748 const NameEntry = struct {
13683 tok: Ast.TokenIndex,13749 tok: Ast.TokenIndex,
...@@ -13737,6 +13803,7 @@ fn scanContainer(...@@ -13737,6 +13803,7 @@ fn scanContainer(
13737 const ident = main_tokens[member_node] + 1;13803 const ident = main_tokens[member_node] + 1;
13738 if (token_tags[ident] != .identifier) {13804 if (token_tags[ident] != .identifier) {
13739 try astgen.appendErrorNode(member_node, "missing function name", .{});13805 try astgen.appendErrorNode(member_node, "missing function name", .{});
13806 any_invalid_declarations = true;
13740 continue;13807 continue;
13741 }13808 }
13742 break :blk .{ .decl, ident };13809 break :blk .{ .decl, ident };
...@@ -13832,6 +13899,7 @@ fn scanContainer(...@@ -13832,6 +13899,7 @@ fn scanContainer(
13832 token_bytes,13899 token_bytes,
13833 }),13900 }),
13834 });13901 });
13902 any_invalid_declarations = true;
13835 continue;13903 continue;
13836 }13904 }
1383713905
...@@ -13849,6 +13917,7 @@ fn scanContainer(...@@ -13849,6 +13917,7 @@ fn scanContainer(
13849 .{},13917 .{},
13850 ),13918 ),
13851 });13919 });
13920 any_invalid_declarations = true;
13852 break;13921 break;
13853 }13922 }
13854 s = local_val.parent;13923 s = local_val.parent;
...@@ -13865,6 +13934,7 @@ fn scanContainer(...@@ -13865,6 +13934,7 @@ fn scanContainer(
13865 .{},13934 .{},
13866 ),13935 ),
13867 });13936 });
13937 any_invalid_declarations = true;
13868 break;13938 break;
13869 }13939 }
13870 s = local_ptr.parent;13940 s = local_ptr.parent;
...@@ -13876,7 +13946,10 @@ fn scanContainer(...@@ -13876,7 +13946,10 @@ fn scanContainer(
13876 };13946 };
13877 }13947 }
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
13881 for (names.keys(), names.values()) |name, first| {13954 for (names.keys(), names.values()) |name, first| {
13882 if (first.next == null) continue;13955 if (first.next == null) continue;
...@@ -13888,6 +13961,7 @@ fn scanContainer(...@@ -13888,6 +13961,7 @@ fn scanContainer(
13888 try notes.append(astgen.arena, try astgen.errNoteNode(namespace.node, "{s} declared here", .{@tagName(container_kind)}));13961 try notes.append(astgen.arena, try astgen.errNoteNode(namespace.node, "{s} declared here", .{@tagName(container_kind)}));
13889 const name_duped = try astgen.arena.dupe(u8, mem.span(astgen.nullTerminatedString(name)));13962 const name_duped = try astgen.arena.dupe(u8, mem.span(astgen.nullTerminatedString(name)));
13890 try astgen.appendErrorTokNotes(first.tok, "duplicate {s} member name '{s}'", .{ @tagName(container_kind), name_duped }, notes.items);13963 try astgen.appendErrorTokNotes(first.tok, "duplicate {s} member name '{s}'", .{ @tagName(container_kind), name_duped }, notes.items);
13964 any_invalid_declarations = true;
13891 }13965 }
1389213966
13893 for (test_names.keys(), test_names.values()) |name, first| {13967 for (test_names.keys(), test_names.values()) |name, first| {
...@@ -13900,6 +13974,7 @@ fn scanContainer(...@@ -13900,6 +13974,7 @@ fn scanContainer(
13900 try notes.append(astgen.arena, try astgen.errNoteNode(namespace.node, "{s} declared here", .{@tagName(container_kind)}));13974 try notes.append(astgen.arena, try astgen.errNoteNode(namespace.node, "{s} declared here", .{@tagName(container_kind)}));
13901 const name_duped = try astgen.arena.dupe(u8, mem.span(astgen.nullTerminatedString(name)));13975 const name_duped = try astgen.arena.dupe(u8, mem.span(astgen.nullTerminatedString(name)));
13902 try astgen.appendErrorTokNotes(first.tok, "duplicate test name '{s}'", .{name_duped}, notes.items);13976 try astgen.appendErrorTokNotes(first.tok, "duplicate test name '{s}'", .{name_duped}, notes.items);
13977 any_invalid_declarations = true;
13903 }13978 }
1390413979
13905 for (decltest_names.keys(), decltest_names.values()) |name, first| {13980 for (decltest_names.keys(), decltest_names.values()) |name, first| {
...@@ -13912,9 +13987,11 @@ fn scanContainer(...@@ -13912,9 +13987,11 @@ fn scanContainer(
13912 try notes.append(astgen.arena, try astgen.errNoteNode(namespace.node, "{s} declared here", .{@tagName(container_kind)}));13987 try notes.append(astgen.arena, try astgen.errNoteNode(namespace.node, "{s} declared here", .{@tagName(container_kind)}));
13913 const name_duped = try astgen.arena.dupe(u8, mem.span(astgen.nullTerminatedString(name)));13988 const name_duped = try astgen.arena.dupe(u8, mem.span(astgen.nullTerminatedString(name)));
13914 try astgen.appendErrorTokNotes(first.tok, "duplicate decltest '{s}'", .{name_duped}, notes.items);13989 try astgen.appendErrorTokNotes(first.tok, "duplicate decltest '{s}'", .{name_duped}, notes.items);
13990 any_invalid_declarations = true;
13915 }13991 }
1391613992
13917 return decl_count;13993 assert(any_invalid_declarations);
13994 return error.AnalysisFail;
13918}13995}
1391913996
13920/// Assumes capacity for body has already been added. Needed capacity taking into13997/// Assumes capacity for body has already been added. Needed capacity taking into
...@@ -14070,6 +14147,37 @@ const DeclarationName = union(enum) {...@@ -14070,6 +14147,37 @@ const DeclarationName = union(enum) {
14070 @"usingnamespace",14147 @"usingnamespace",
14071};14148};
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
14073/// Sets all extra data for a `declaration` instruction.14181/// Sets all extra data for a `declaration` instruction.
14074/// Unstacks `value_gz`, `align_gz`, `linksection_gz`, and `addrspace_gz`.14182/// Unstacks `value_gz`, `align_gz`, `linksection_gz`, and `addrspace_gz`.
14075fn setDeclaration(14183fn setDeclaration(
lib/std/zig/Zir.zig+211-177
...@@ -120,7 +120,21 @@ pub fn bodySlice(zir: Zir, start: usize, len: usize) []Inst.Index {...@@ -120,7 +120,21 @@ pub fn bodySlice(zir: Zir, start: usize, len: usize) []Inst.Index {
120}120}
121121
122pub fn hasCompileErrors(code: Zir) bool {122pub 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 }
124}138}
125139
126pub fn deinit(code: *Zir, gpa: Allocator) void {140pub fn deinit(code: *Zir, gpa: Allocator) void {
...@@ -2079,7 +2093,14 @@ pub const Inst = struct {...@@ -2079,7 +2093,14 @@ pub const Inst = struct {
2079 /// `small` is an `Inst.InplaceOp`.2093 /// `small` is an `Inst.InplaceOp`.
2080 inplace_arith_result_ty,2094 inplace_arith_result_ty,
2081 /// Marks a statement that can be stepped to but produces no code.2095 /// Marks a statement that can be stepped to but produces no code.
2096 /// `operand` and `small` are ignored.
2082 dbg_empty_stmt,2097 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
2084 pub const InstData = struct {2105 pub const InstData = struct {
2085 opcode: Extended,2106 opcode: Extended,
...@@ -3584,145 +3605,155 @@ pub const DeclIterator = struct {...@@ -3584,145 +3605,155 @@ pub const DeclIterator = struct {
3584};3605};
35853606
3586pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {3607pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
3587 const tags = zir.instructions.items(.tag);3608 const inst = zir.instructions.get(@intFromEnum(decl_inst));
3588 const datas = zir.instructions.items(.data);3609 assert(inst.tag == .extended);
3589 switch (tags[@intFromEnum(decl_inst)]) {3610 const extended = inst.data.extended;
3590 // Functions are allowed and yield no iterations.3611 switch (extended.opcode) {
3591 // This is because they are returned by `findDecls`.3612 .struct_decl => {
3592 .func, .func_inferred, .func_fancy => return .{3613 const small: Inst.StructDecl.Small = @bitCast(extended.small);
3593 .extra_index = undefined,3614 var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.StructDecl).@"struct".fields.len);
3594 .decls_remaining = 0,3615 const captures_len = if (small.has_captures_len) captures_len: {
3595 .zir = zir,3616 const captures_len = zir.extra[extra_index];
3596 },3617 extra_index += 1;
35973618 break :captures_len captures_len;
3598 .extended => {3619 } else 0;
3599 const extended = datas[@intFromEnum(decl_inst)].extended;3620 extra_index += @intFromBool(small.has_fields_len);
3600 switch (extended.opcode) {3621 const decls_len = if (small.has_decls_len) decls_len: {
3601 // Reifications are allowed and yield no iterations.3622 const decls_len = zir.extra[extra_index];
3602 // This is because they are returned by `findDecls`.3623 extra_index += 1;
3603 .reify => return .{3624 break :decls_len decls_len;
3604 .extra_index = undefined,3625 } else 0;
3605 .decls_remaining = 0,3626
3606 .zir = zir,3627 extra_index += captures_len;
3607 },3628
3608 .struct_decl => {3629 if (small.has_backing_int) {
3609 const small: Inst.StructDecl.Small = @bitCast(extended.small);3630 const backing_int_body_len = zir.extra[extra_index];
3610 var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.StructDecl).@"struct".fields.len);3631 extra_index += 1; // backing_int_body_len
3611 const captures_len = if (small.has_captures_len) captures_len: {3632 if (backing_int_body_len == 0) {
3612 const captures_len = zir.extra[extra_index];3633 extra_index += 1; // backing_int_ref
3613 extra_index += 1;3634 } else {
3614 break :captures_len captures_len;3635 extra_index += backing_int_body_len; // backing_int_body_inst
3615 } else 0;3636 }
3616 extra_index += @intFromBool(small.has_fields_len);3637 }
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 }
36343638
3635 return .{3639 return .{
3636 .extra_index = extra_index,3640 .extra_index = extra_index,
3637 .decls_remaining = decls_len,3641 .decls_remaining = decls_len,
3638 .zir = zir,3642 .zir = zir,
3639 };3643 };
3640 },3644 },
3641 .enum_decl => {3645 .enum_decl => {
3642 const small: Inst.EnumDecl.Small = @bitCast(extended.small);3646 const small: Inst.EnumDecl.Small = @bitCast(extended.small);
3643 var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.EnumDecl).@"struct".fields.len);3647 var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.EnumDecl).@"struct".fields.len);
3644 extra_index += @intFromBool(small.has_tag_type);3648 extra_index += @intFromBool(small.has_tag_type);
3645 const captures_len = if (small.has_captures_len) captures_len: {3649 const captures_len = if (small.has_captures_len) captures_len: {
3646 const captures_len = zir.extra[extra_index];3650 const captures_len = zir.extra[extra_index];
3647 extra_index += 1;3651 extra_index += 1;
3648 break :captures_len captures_len;3652 break :captures_len captures_len;
3649 } else 0;3653 } else 0;
3650 extra_index += @intFromBool(small.has_body_len);3654 extra_index += @intFromBool(small.has_body_len);
3651 extra_index += @intFromBool(small.has_fields_len);3655 extra_index += @intFromBool(small.has_fields_len);
3652 const decls_len = if (small.has_decls_len) decls_len: {3656 const decls_len = if (small.has_decls_len) decls_len: {
3653 const decls_len = zir.extra[extra_index];3657 const decls_len = zir.extra[extra_index];
3654 extra_index += 1;3658 extra_index += 1;
3655 break :decls_len decls_len;3659 break :decls_len decls_len;
3656 } else 0;3660 } else 0;
36573661
3658 extra_index += captures_len;3662 extra_index += captures_len;
36593663
3660 return .{3664 return .{
3661 .extra_index = extra_index,3665 .extra_index = extra_index,
3662 .decls_remaining = decls_len,3666 .decls_remaining = decls_len,
3663 .zir = zir,3667 .zir = zir,
3664 };3668 };
3665 },3669 },
3666 .union_decl => {3670 .union_decl => {
3667 const small: Inst.UnionDecl.Small = @bitCast(extended.small);3671 const small: Inst.UnionDecl.Small = @bitCast(extended.small);
3668 var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.UnionDecl).@"struct".fields.len);3672 var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.UnionDecl).@"struct".fields.len);
3669 extra_index += @intFromBool(small.has_tag_type);3673 extra_index += @intFromBool(small.has_tag_type);
3670 const captures_len = if (small.has_captures_len) captures_len: {3674 const captures_len = if (small.has_captures_len) captures_len: {
3671 const captures_len = zir.extra[extra_index];3675 const captures_len = zir.extra[extra_index];
3672 extra_index += 1;3676 extra_index += 1;
3673 break :captures_len captures_len;3677 break :captures_len captures_len;
3674 } else 0;3678 } else 0;
3675 extra_index += @intFromBool(small.has_body_len);3679 extra_index += @intFromBool(small.has_body_len);
3676 extra_index += @intFromBool(small.has_fields_len);3680 extra_index += @intFromBool(small.has_fields_len);
3677 const decls_len = if (small.has_decls_len) decls_len: {3681 const decls_len = if (small.has_decls_len) decls_len: {
3678 const decls_len = zir.extra[extra_index];3682 const decls_len = zir.extra[extra_index];
3679 extra_index += 1;3683 extra_index += 1;
3680 break :decls_len decls_len;3684 break :decls_len decls_len;
3681 } else 0;3685 } else 0;
36823686
3683 extra_index += captures_len;3687 extra_index += captures_len;
36843688
3685 return .{3689 return .{
3686 .extra_index = extra_index,3690 .extra_index = extra_index,
3687 .decls_remaining = decls_len,3691 .decls_remaining = decls_len,
3688 .zir = zir,3692 .zir = zir,
3689 };3693 };
3690 },3694 },
3691 .opaque_decl => {3695 .opaque_decl => {
3692 const small: Inst.OpaqueDecl.Small = @bitCast(extended.small);3696 const small: Inst.OpaqueDecl.Small = @bitCast(extended.small);
3693 var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.OpaqueDecl).@"struct".fields.len);3697 var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.OpaqueDecl).@"struct".fields.len);
3694 const decls_len = if (small.has_decls_len) decls_len: {3698 const decls_len = if (small.has_decls_len) decls_len: {
3695 const decls_len = zir.extra[extra_index];3699 const decls_len = zir.extra[extra_index];
3696 extra_index += 1;3700 extra_index += 1;
3697 break :decls_len decls_len;3701 break :decls_len decls_len;
3698 } else 0;3702 } else 0;
3699 const captures_len = if (small.has_captures_len) captures_len: {3703 const captures_len = if (small.has_captures_len) captures_len: {
3700 const captures_len = zir.extra[extra_index];3704 const captures_len = zir.extra[extra_index];
3701 extra_index += 1;3705 extra_index += 1;
3702 break :captures_len captures_len;3706 break :captures_len captures_len;
3703 } else 0;3707 } else 0;
37043708
3705 extra_index += captures_len;3709 extra_index += captures_len;
37063710
3707 return .{3711 return .{
3708 .extra_index = extra_index,3712 .extra_index = extra_index,
3709 .decls_remaining = decls_len,3713 .decls_remaining = decls_len,
3710 .zir = zir,3714 .zir = zir,
3711 };3715 };
3712 },
3713 else => unreachable,
3714 }
3715 },3716 },
3716 else => unreachable,3717 else => unreachable,
3717 }3718 }
3718}3719}
37193720
3720/// Find all type declarations, recursively, within a `declaration` instruction. Does not recurse through3721/// `DeclContents` contains all "interesting" instructions found within a declaration by `findTrackable`.
3721/// said type declarations' declarations; to find all declarations, call this function on the declarations3722/// These instructions are partitioned into a few different sets, since this makes ZIR instruction mapping
3722/// of the discovered types recursively.3723/// more effective.
3723/// The iterator would have to allocate memory anyway to iterate, so an `ArrayList` is populated as the result.3724pub const DeclContents = struct {
3724pub fn findDecls(zir: Zir, gpa: Allocator, list: *std.ArrayListUnmanaged(Inst.Index), decl_inst: Zir.Inst.Index) !void {3725 /// This is a simple optional because ZIR guarantees that a `func`/`func_inferred`/`func_fancy` instruction
3725 list.clearRetainingCapacity();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
3726 const declaration, const extra_end = zir.getDeclaration(decl_inst);3757 const declaration, const extra_end = zir.getDeclaration(decl_inst);
3727 const bodies = declaration.getBodies(extra_end, zir);3758 const bodies = declaration.getBodies(extra_end, zir);
37283759
...@@ -3731,27 +3762,27 @@ pub fn findDecls(zir: Zir, gpa: Allocator, list: *std.ArrayListUnmanaged(Inst.In...@@ -3731,27 +3762,27 @@ pub fn findDecls(zir: Zir, gpa: Allocator, list: *std.ArrayListUnmanaged(Inst.In
3731 var found_defers: std.AutoHashMapUnmanaged(u32, void) = .empty;3762 var found_defers: std.AutoHashMapUnmanaged(u32, void) = .empty;
3732 defer found_defers.deinit(gpa);3763 defer found_defers.deinit(gpa);
37333764
3734 try zir.findDeclsBody(gpa, list, &found_defers, bodies.value_body);3765 try zir.findTrackableBody(gpa, contents, &found_defers, bodies.value_body);
3735 if (bodies.align_body) |b| try zir.findDeclsBody(gpa, list, &found_defers, b);3766 if (bodies.align_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b);
3736 if (bodies.linksection_body) |b| try zir.findDeclsBody(gpa, list, &found_defers, b);3767 if (bodies.linksection_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b);
3737 if (bodies.addrspace_body) |b| try zir.findDeclsBody(gpa, list, &found_defers, b);3768 if (bodies.addrspace_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b);
3738}3769}
37393770
3740/// Like `findDecls`, but only considers the `main_struct_inst` instruction. This may return more than3771/// Like `findTrackable`, but only considers the `main_struct_inst` instruction. This may return more than
3741/// just that instruction because it will also traverse fields.3772/// just that instruction because it will also traverse fields.
3742pub fn findDeclsRoot(zir: Zir, gpa: Allocator, list: *std.ArrayListUnmanaged(Inst.Index)) !void {3773pub fn findTrackableRoot(zir: Zir, gpa: Allocator, contents: *DeclContents) !void {
3743 list.clearRetainingCapacity();3774 contents.clear();
37443775
3745 var found_defers: std.AutoHashMapUnmanaged(u32, void) = .empty;3776 var found_defers: std.AutoHashMapUnmanaged(u32, void) = .empty;
3746 defer found_defers.deinit(gpa);3777 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);
3749}3780}
37503781
3751fn findDeclsInner(3782fn findTrackableInner(
3752 zir: Zir,3783 zir: Zir,
3753 gpa: Allocator,3784 gpa: Allocator,
3754 list: *std.ArrayListUnmanaged(Inst.Index),3785 contents: *DeclContents,
3755 defers: *std.AutoHashMapUnmanaged(u32, void),3786 defers: *std.AutoHashMapUnmanaged(u32, void),
3756 inst: Inst.Index,3787 inst: Inst.Index,
3757) Allocator.Error!void {3788) Allocator.Error!void {
...@@ -3995,7 +4026,7 @@ fn findDeclsInner(...@@ -3995,7 +4026,7 @@ fn findDeclsInner(
3995 .struct_init,4026 .struct_init,
3996 .struct_init_ref,4027 .struct_init_ref,
3997 .struct_init_anon,4028 .struct_init_anon,
3998 => return list.append(gpa, inst),4029 => return contents.other.append(gpa, inst),
39994030
4000 .extended => {4031 .extended => {
4001 const extended = datas[@intFromEnum(inst)].extended;4032 const extended = datas[@intFromEnum(inst)].extended;
...@@ -4055,21 +4086,22 @@ fn findDeclsInner(...@@ -4055,21 +4086,22 @@ fn findDeclsInner(
4055 .inplace_arith_result_ty,4086 .inplace_arith_result_ty,
4056 .tuple_decl,4087 .tuple_decl,
4057 .dbg_empty_stmt,4088 .dbg_empty_stmt,
4089 .astgen_error,
4058 => return,4090 => return,
40594091
4060 // `@TypeOf` has a body.4092 // `@TypeOf` has a body.
4061 .typeof_peer => {4093 .typeof_peer => {
4062 const extra = zir.extraData(Zir.Inst.TypeOfPeer, extended.operand);4094 const extra = zir.extraData(Zir.Inst.TypeOfPeer, extended.operand);
4063 const body = zir.bodySlice(extra.data.body_index, extra.data.body_len);4095 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);
4065 },4097 },
40664098
4067 // Reifications and opaque declarations need tracking, but have no body.4099 // 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
4070 // Struct declarations need tracking and have bodies.4102 // Struct declarations need tracking and have bodies.
4071 .struct_decl => {4103 .struct_decl => {
4072 try list.append(gpa, inst);4104 try contents.explicit_types.append(gpa, inst);
40734105
4074 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);4106 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
4075 const extra = zir.extraData(Zir.Inst.StructDecl, extended.operand);4107 const extra = zir.extraData(Zir.Inst.StructDecl, extended.operand);
...@@ -4098,7 +4130,7 @@ fn findDeclsInner(...@@ -4098,7 +4130,7 @@ fn findDeclsInner(
4098 } else {4130 } else {
4099 const body = zir.bodySlice(extra_index, backing_int_body_len);4131 const body = zir.bodySlice(extra_index, backing_int_body_len);
4100 extra_index += backing_int_body_len;4132 extra_index += backing_int_body_len;
4101 try zir.findDeclsBody(gpa, list, defers, body);4133 try zir.findTrackableBody(gpa, contents, defers, body);
4102 }4134 }
4103 }4135 }
4104 extra_index += decls_len;4136 extra_index += decls_len;
...@@ -4154,12 +4186,12 @@ fn findDeclsInner(...@@ -4154,12 +4186,12 @@ fn findDeclsInner(
41544186
4155 // Now, `fields_extra_index` points to `bodies`. Let's treat this as one big body.4187 // Now, `fields_extra_index` points to `bodies`. Let's treat this as one big body.
4156 const merged_bodies = zir.bodySlice(fields_extra_index, total_bodies_len);4188 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);
4158 },4190 },
41594191
4160 // Union declarations need tracking and have a body.4192 // Union declarations need tracking and have a body.
4161 .union_decl => {4193 .union_decl => {
4162 try list.append(gpa, inst);4194 try contents.explicit_types.append(gpa, inst);
41634195
4164 const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);4196 const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);
4165 const extra = zir.extraData(Zir.Inst.UnionDecl, extended.operand);4197 const extra = zir.extraData(Zir.Inst.UnionDecl, extended.operand);
...@@ -4184,12 +4216,12 @@ fn findDeclsInner(...@@ -4184,12 +4216,12 @@ fn findDeclsInner(
4184 extra_index += captures_len;4216 extra_index += captures_len;
4185 extra_index += decls_len;4217 extra_index += decls_len;
4186 const body = zir.bodySlice(extra_index, body_len);4218 const body = zir.bodySlice(extra_index, body_len);
4187 try zir.findDeclsBody(gpa, list, defers, body);4219 try zir.findTrackableBody(gpa, contents, defers, body);
4188 },4220 },
41894221
4190 // Enum declarations need tracking and have a body.4222 // Enum declarations need tracking and have a body.
4191 .enum_decl => {4223 .enum_decl => {
4192 try list.append(gpa, inst);4224 try contents.explicit_types.append(gpa, inst);
41934225
4194 const small: Zir.Inst.EnumDecl.Small = @bitCast(extended.small);4226 const small: Zir.Inst.EnumDecl.Small = @bitCast(extended.small);
4195 const extra = zir.extraData(Zir.Inst.EnumDecl, extended.operand);4227 const extra = zir.extraData(Zir.Inst.EnumDecl, extended.operand);
...@@ -4214,7 +4246,7 @@ fn findDeclsInner(...@@ -4214,7 +4246,7 @@ fn findDeclsInner(
4214 extra_index += captures_len;4246 extra_index += captures_len;
4215 extra_index += decls_len;4247 extra_index += decls_len;
4216 const body = zir.bodySlice(extra_index, body_len);4248 const body = zir.bodySlice(extra_index, body_len);
4217 try zir.findDeclsBody(gpa, list, defers, body);4249 try zir.findTrackableBody(gpa, contents, defers, body);
4218 },4250 },
4219 }4251 }
4220 },4252 },
...@@ -4223,7 +4255,8 @@ fn findDeclsInner(...@@ -4223,7 +4255,8 @@ fn findDeclsInner(
4223 .func,4255 .func,
4224 .func_inferred,4256 .func_inferred,
4225 => {4257 => {
4226 try list.append(gpa, inst);4258 assert(contents.func_decl == null);
4259 contents.func_decl = inst;
42274260
4228 const inst_data = datas[@intFromEnum(inst)].pl_node;4261 const inst_data = datas[@intFromEnum(inst)].pl_node;
4229 const extra = zir.extraData(Inst.Func, inst_data.payload_index);4262 const extra = zir.extraData(Inst.Func, inst_data.payload_index);
...@@ -4234,14 +4267,15 @@ fn findDeclsInner(...@@ -4234,14 +4267,15 @@ fn findDeclsInner(
4234 else => {4267 else => {
4235 const body = zir.bodySlice(extra_index, extra.data.ret_body_len);4268 const body = zir.bodySlice(extra_index, extra.data.ret_body_len);
4236 extra_index += body.len;4269 extra_index += body.len;
4237 try zir.findDeclsBody(gpa, list, defers, body);4270 try zir.findTrackableBody(gpa, contents, defers, body);
4238 },4271 },
4239 }4272 }
4240 const body = zir.bodySlice(extra_index, extra.data.body_len);4273 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);
4242 },4275 },
4243 .func_fancy => {4276 .func_fancy => {
4244 try list.append(gpa, inst);4277 assert(contents.func_decl == null);
4278 contents.func_decl = inst;
42454279
4246 const inst_data = datas[@intFromEnum(inst)].pl_node;4280 const inst_data = datas[@intFromEnum(inst)].pl_node;
4247 const extra = zir.extraData(Inst.FuncFancy, inst_data.payload_index);4281 const extra = zir.extraData(Inst.FuncFancy, inst_data.payload_index);
...@@ -4252,7 +4286,7 @@ fn findDeclsInner(...@@ -4252,7 +4286,7 @@ fn findDeclsInner(
4252 const body_len = zir.extra[extra_index];4286 const body_len = zir.extra[extra_index];
4253 extra_index += 1;4287 extra_index += 1;
4254 const body = zir.bodySlice(extra_index, body_len);4288 const body = zir.bodySlice(extra_index, body_len);
4255 try zir.findDeclsBody(gpa, list, defers, body);4289 try zir.findTrackableBody(gpa, contents, defers, body);
4256 extra_index += body.len;4290 extra_index += body.len;
4257 } else if (extra.data.bits.has_align_ref) {4291 } else if (extra.data.bits.has_align_ref) {
4258 extra_index += 1;4292 extra_index += 1;
...@@ -4262,7 +4296,7 @@ fn findDeclsInner(...@@ -4262,7 +4296,7 @@ fn findDeclsInner(
4262 const body_len = zir.extra[extra_index];4296 const body_len = zir.extra[extra_index];
4263 extra_index += 1;4297 extra_index += 1;
4264 const body = zir.bodySlice(extra_index, body_len);4298 const body = zir.bodySlice(extra_index, body_len);
4265 try zir.findDeclsBody(gpa, list, defers, body);4299 try zir.findTrackableBody(gpa, contents, defers, body);
4266 extra_index += body.len;4300 extra_index += body.len;
4267 } else if (extra.data.bits.has_addrspace_ref) {4301 } else if (extra.data.bits.has_addrspace_ref) {
4268 extra_index += 1;4302 extra_index += 1;
...@@ -4272,7 +4306,7 @@ fn findDeclsInner(...@@ -4272,7 +4306,7 @@ fn findDeclsInner(
4272 const body_len = zir.extra[extra_index];4306 const body_len = zir.extra[extra_index];
4273 extra_index += 1;4307 extra_index += 1;
4274 const body = zir.bodySlice(extra_index, body_len);4308 const body = zir.bodySlice(extra_index, body_len);
4275 try zir.findDeclsBody(gpa, list, defers, body);4309 try zir.findTrackableBody(gpa, contents, defers, body);
4276 extra_index += body.len;4310 extra_index += body.len;
4277 } else if (extra.data.bits.has_section_ref) {4311 } else if (extra.data.bits.has_section_ref) {
4278 extra_index += 1;4312 extra_index += 1;
...@@ -4282,7 +4316,7 @@ fn findDeclsInner(...@@ -4282,7 +4316,7 @@ fn findDeclsInner(
4282 const body_len = zir.extra[extra_index];4316 const body_len = zir.extra[extra_index];
4283 extra_index += 1;4317 extra_index += 1;
4284 const body = zir.bodySlice(extra_index, body_len);4318 const body = zir.bodySlice(extra_index, body_len);
4285 try zir.findDeclsBody(gpa, list, defers, body);4319 try zir.findTrackableBody(gpa, contents, defers, body);
4286 extra_index += body.len;4320 extra_index += body.len;
4287 } else if (extra.data.bits.has_cc_ref) {4321 } else if (extra.data.bits.has_cc_ref) {
4288 extra_index += 1;4322 extra_index += 1;
...@@ -4292,7 +4326,7 @@ fn findDeclsInner(...@@ -4292,7 +4326,7 @@ fn findDeclsInner(
4292 const body_len = zir.extra[extra_index];4326 const body_len = zir.extra[extra_index];
4293 extra_index += 1;4327 extra_index += 1;
4294 const body = zir.bodySlice(extra_index, body_len);4328 const body = zir.bodySlice(extra_index, body_len);
4295 try zir.findDeclsBody(gpa, list, defers, body);4329 try zir.findTrackableBody(gpa, contents, defers, body);
4296 extra_index += body.len;4330 extra_index += body.len;
4297 } else if (extra.data.bits.has_ret_ty_ref) {4331 } else if (extra.data.bits.has_ret_ty_ref) {
4298 extra_index += 1;4332 extra_index += 1;
...@@ -4301,7 +4335,7 @@ fn findDeclsInner(...@@ -4301,7 +4335,7 @@ fn findDeclsInner(
4301 extra_index += @intFromBool(extra.data.bits.has_any_noalias);4335 extra_index += @intFromBool(extra.data.bits.has_any_noalias);
43024336
4303 const body = zir.bodySlice(extra_index, extra.data.body_len);4337 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);
4305 },4339 },
43064340
4307 // Block instructions, recurse over the bodies.4341 // Block instructions, recurse over the bodies.
...@@ -4316,24 +4350,24 @@ fn findDeclsInner(...@@ -4316,24 +4350,24 @@ fn findDeclsInner(
4316 const inst_data = datas[@intFromEnum(inst)].pl_node;4350 const inst_data = datas[@intFromEnum(inst)].pl_node;
4317 const extra = zir.extraData(Inst.Block, inst_data.payload_index);4351 const extra = zir.extraData(Inst.Block, inst_data.payload_index);
4318 const body = zir.bodySlice(extra.end, extra.data.body_len);4352 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);
4320 },4354 },
4321 .condbr, .condbr_inline => {4355 .condbr, .condbr_inline => {
4322 const inst_data = datas[@intFromEnum(inst)].pl_node;4356 const inst_data = datas[@intFromEnum(inst)].pl_node;
4323 const extra = zir.extraData(Inst.CondBr, inst_data.payload_index);4357 const extra = zir.extraData(Inst.CondBr, inst_data.payload_index);
4324 const then_body = zir.bodySlice(extra.end, extra.data.then_body_len);4358 const then_body = zir.bodySlice(extra.end, extra.data.then_body_len);
4325 const else_body = zir.bodySlice(extra.end + then_body.len, extra.data.else_body_len);4359 const else_body = zir.bodySlice(extra.end + then_body.len, extra.data.else_body_len);
4326 try zir.findDeclsBody(gpa, list, defers, then_body);4360 try zir.findTrackableBody(gpa, contents, defers, then_body);
4327 try zir.findDeclsBody(gpa, list, defers, else_body);4361 try zir.findTrackableBody(gpa, contents, defers, else_body);
4328 },4362 },
4329 .@"try", .try_ptr => {4363 .@"try", .try_ptr => {
4330 const inst_data = datas[@intFromEnum(inst)].pl_node;4364 const inst_data = datas[@intFromEnum(inst)].pl_node;
4331 const extra = zir.extraData(Inst.Try, inst_data.payload_index);4365 const extra = zir.extraData(Inst.Try, inst_data.payload_index);
4332 const body = zir.bodySlice(extra.end, extra.data.body_len);4366 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);
4334 },4368 },
4335 .switch_block, .switch_block_ref => return zir.findDeclsSwitch(gpa, list, defers, inst, .normal),4369 .switch_block, .switch_block_ref => return zir.findTrackableSwitch(gpa, contents, defers, inst, .normal),
4336 .switch_block_err_union => return zir.findDeclsSwitch(gpa, list, defers, inst, .err_union),4370 .switch_block_err_union => return zir.findTrackableSwitch(gpa, contents, defers, inst, .err_union),
43374371
4338 .suspend_block => @panic("TODO iterate suspend block"),4372 .suspend_block => @panic("TODO iterate suspend block"),
43394373
...@@ -4341,7 +4375,7 @@ fn findDeclsInner(...@@ -4341,7 +4375,7 @@ fn findDeclsInner(
4341 const inst_data = datas[@intFromEnum(inst)].pl_tok;4375 const inst_data = datas[@intFromEnum(inst)].pl_tok;
4342 const extra = zir.extraData(Inst.Param, inst_data.payload_index);4376 const extra = zir.extraData(Inst.Param, inst_data.payload_index);
4343 const body = zir.bodySlice(extra.end, extra.data.body_len);4377 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);
4345 },4379 },
43464380
4347 inline .call, .field_call => |tag| {4381 inline .call, .field_call => |tag| {
...@@ -4357,7 +4391,7 @@ fn findDeclsInner(...@@ -4357,7 +4391,7 @@ fn findDeclsInner(
4357 const first_arg_start_off = args_len;4391 const first_arg_start_off = args_len;
4358 const final_arg_end_off = zir.extra[extra.end + args_len - 1];4392 const final_arg_end_off = zir.extra[extra.end + args_len - 1];
4359 const args_body = zir.bodySlice(extra.end + first_arg_start_off, final_arg_end_off - first_arg_start_off);4393 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);
4361 }4395 }
4362 },4396 },
4363 .@"defer" => {4397 .@"defer" => {
...@@ -4365,7 +4399,7 @@ fn findDeclsInner(...@@ -4365,7 +4399,7 @@ fn findDeclsInner(
4365 const gop = try defers.getOrPut(gpa, inst_data.index);4399 const gop = try defers.getOrPut(gpa, inst_data.index);
4366 if (!gop.found_existing) {4400 if (!gop.found_existing) {
4367 const body = zir.bodySlice(inst_data.index, inst_data.len);4401 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);
4369 }4403 }
4370 },4404 },
4371 .defer_err_code => {4405 .defer_err_code => {
...@@ -4374,16 +4408,16 @@ fn findDeclsInner(...@@ -4374,16 +4408,16 @@ fn findDeclsInner(
4374 const gop = try defers.getOrPut(gpa, extra.index);4408 const gop = try defers.getOrPut(gpa, extra.index);
4375 if (!gop.found_existing) {4409 if (!gop.found_existing) {
4376 const body = zir.bodySlice(extra.index, extra.len);4410 const body = zir.bodySlice(extra.index, extra.len);
4377 try zir.findDeclsBody(gpa, list, defers, body);4411 try zir.findTrackableBody(gpa, contents, defers, body);
4378 }4412 }
4379 },4413 },
4380 }4414 }
4381}4415}
43824416
4383fn findDeclsSwitch(4417fn findTrackableSwitch(
4384 zir: Zir,4418 zir: Zir,
4385 gpa: Allocator,4419 gpa: Allocator,
4386 list: *std.ArrayListUnmanaged(Inst.Index),4420 contents: *DeclContents,
4387 defers: *std.AutoHashMapUnmanaged(u32, void),4421 defers: *std.AutoHashMapUnmanaged(u32, void),
4388 inst: Inst.Index,4422 inst: Inst.Index,
4389 /// Distinguishes between `switch_block[_ref]` and `switch_block_err_union`.4423 /// Distinguishes between `switch_block[_ref]` and `switch_block_err_union`.
...@@ -4419,7 +4453,7 @@ fn findDeclsSwitch(...@@ -4419,7 +4453,7 @@ fn findDeclsSwitch(
4419 const body = zir.bodySlice(extra_index, prong_info.body_len);4453 const body = zir.bodySlice(extra_index, prong_info.body_len);
4420 extra_index += body.len;4454 extra_index += body.len;
44214455
4422 try zir.findDeclsBody(gpa, list, defers, body);4456 try zir.findTrackableBody(gpa, contents, defers, body);
44234457
4424 break :has_special extra.data.bits.has_else;4458 break :has_special extra.data.bits.has_else;
4425 },4459 },
...@@ -4431,7 +4465,7 @@ fn findDeclsSwitch(...@@ -4431,7 +4465,7 @@ fn findDeclsSwitch(
4431 const body = zir.bodySlice(extra_index, prong_info.body_len);4465 const body = zir.bodySlice(extra_index, prong_info.body_len);
4432 extra_index += body.len;4466 extra_index += body.len;
44334467
4434 try zir.findDeclsBody(gpa, list, defers, body);4468 try zir.findTrackableBody(gpa, contents, defers, body);
4435 }4469 }
44364470
4437 {4471 {
...@@ -4443,7 +4477,7 @@ fn findDeclsSwitch(...@@ -4443,7 +4477,7 @@ fn findDeclsSwitch(
4443 const body = zir.bodySlice(extra_index, prong_info.body_len);4477 const body = zir.bodySlice(extra_index, prong_info.body_len);
4444 extra_index += body.len;4478 extra_index += body.len;
44454479
4446 try zir.findDeclsBody(gpa, list, defers, body);4480 try zir.findTrackableBody(gpa, contents, defers, body);
4447 }4481 }
4448 }4482 }
4449 {4483 {
...@@ -4460,20 +4494,20 @@ fn findDeclsSwitch(...@@ -4460,20 +4494,20 @@ fn findDeclsSwitch(
4460 const body = zir.bodySlice(extra_index, prong_info.body_len);4494 const body = zir.bodySlice(extra_index, prong_info.body_len);
4461 extra_index += body.len;4495 extra_index += body.len;
44624496
4463 try zir.findDeclsBody(gpa, list, defers, body);4497 try zir.findTrackableBody(gpa, contents, defers, body);
4464 }4498 }
4465 }4499 }
4466}4500}
44674501
4468fn findDeclsBody(4502fn findTrackableBody(
4469 zir: Zir,4503 zir: Zir,
4470 gpa: Allocator,4504 gpa: Allocator,
4471 list: *std.ArrayListUnmanaged(Inst.Index),4505 contents: *DeclContents,
4472 defers: *std.AutoHashMapUnmanaged(u32, void),4506 defers: *std.AutoHashMapUnmanaged(u32, void),
4473 body: []const Inst.Index,4507 body: []const Inst.Index,
4474) Allocator.Error!void {4508) Allocator.Error!void {
4475 for (body) |member| {4509 for (body) |member| {
4476 try zir.findDeclsInner(gpa, list, defers, member);4510 try zir.findTrackableInner(gpa, contents, defers, member);
4477 }4511 }
4478}4512}
44794513
src/Compilation.zig+21-9
...@@ -3223,17 +3223,29 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {...@@ -3223,17 +3223,29 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
3223 }3223 }
3224 }3224 }
32253225
3226 if (comp.zcu) |zcu| {3226 // TODO: eventually, this should be behind `std.debug.runtime_safety`. But right now, this is a
3227 if (comp.incremental and bundle.root_list.items.len == 0) {3227 // very common way for incremental compilation bugs to manifest, so let's always check it.
3228 const should_have_error = for (zcu.transitive_failed_analysis.keys()) |failed_unit| {3228 if (comp.zcu) |zcu| if (comp.incremental and bundle.root_list.items.len == 0) {
3229 const refs = try zcu.resolveReferences();3229 for (zcu.transitive_failed_analysis.keys()) |failed_unit| {
3230 if (refs.contains(failed_unit)) break true;3230 const refs = try zcu.resolveReferences();
3231 } else false;3231 var ref = refs.get(failed_unit) orelse continue;
3232 if (should_have_error) {3232 // This AU is referenced and has a transitive compile error, meaning it referenced something with a compile error.
3233 @panic("referenced transitive analysis errors, but none actually emitted");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).?;
3234 }3244 }
3245
3246 @panic("referenced transitive analysis errors, but none actually emitted");
3235 }3247 }
3236 }3248 };
32373249
3238 const compile_log_text = if (comp.zcu) |m| m.compile_log_text.items else "";3250 const compile_log_text = if (comp.zcu) |m| m.compile_log_text.items else "";
3239 return bundle.toOwnedBundle(compile_log_text);3251 return bundle.toOwnedBundle(compile_log_text);
src/InternPool.zig+20
...@@ -8616,6 +8616,16 @@ pub fn getFuncDecl(...@@ -8616,6 +8616,16 @@ pub fn getFuncDecl(
8616 defer gop.deinit();8616 defer gop.deinit();
8617 if (gop == .existing) {8617 if (gop == .existing) {
8618 extra.mutate.len = prev_extra_len;8618 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
8619 return gop.existing;8629 return gop.existing;
8620 }8630 }
86218631
...@@ -8762,6 +8772,16 @@ pub fn getFuncDeclIes(...@@ -8762,6 +8772,16 @@ pub fn getFuncDeclIes(
8762 // An existing function type was found; undo the additions to our two arrays.8772 // An existing function type was found; undo the additions to our two arrays.
8763 items.mutate.len -= 4;8773 items.mutate.len -= 4;
8764 extra.mutate.len = prev_extra_len;8774 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
8765 return func_gop.existing;8785 return func_gop.existing;
8766 }8786 }
8767 func_gop.putTentative(func_index);8787 func_gop.putTentative(func_index);
src/Sema.zig+1
...@@ -1361,6 +1361,7 @@ fn analyzeBodyInner(...@@ -1361,6 +1361,7 @@ fn analyzeBodyInner(
1361 i += 1;1361 i += 1;
1362 continue;1362 continue;
1363 },1363 },
1364 .astgen_error => return error.AnalysisFail,
1364 };1365 };
1365 },1366 },
13661367
src/Zcu.zig+61-21
...@@ -2593,26 +2593,44 @@ pub fn mapOldZirToNew(...@@ -2593,26 +2593,44 @@ pub fn mapOldZirToNew(
2593 defer match_stack.deinit(gpa);2593 defer match_stack.deinit(gpa);
25942594
2595 // Used as temporary buffers for namespace declaration instructions2595 // Used as temporary buffers for namespace declaration instructions
2596 var old_decls: std.ArrayListUnmanaged(Zir.Inst.Index) = .empty;2596 var old_contents: Zir.DeclContents = .init;
2597 defer old_decls.deinit(gpa);2597 defer old_contents.deinit(gpa);
2598 var new_decls: std.ArrayListUnmanaged(Zir.Inst.Index) = .empty;2598 var new_contents: Zir.DeclContents = .init;
2599 defer new_decls.deinit(gpa);2599 defer new_contents.deinit(gpa);
26002600
2601 // Map the main struct inst (and anything in its fields)2601 // Map the main struct inst (and anything in its fields)
2602 {2602 {
2603 try old_zir.findDeclsRoot(gpa, &old_decls);2603 try old_zir.findTrackableRoot(gpa, &old_contents);
2604 try new_zir.findDeclsRoot(gpa, &new_decls);2604 try new_zir.findTrackableRoot(gpa, &new_contents);
26052605
2606 assert(old_decls.items[0] == .main_struct_inst);2606 assert(old_contents.explicit_types.items[0] == .main_struct_inst);
2607 assert(new_decls.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 always2609 assert(old_contents.func_decl == null);
2610 // correlate them based on source order.2610 assert(new_contents.func_decl == null);
2611 const n = @min(old_decls.items.len, new_decls.items.len);2611
2612 try match_stack.ensureUnusedCapacity(gpa, n);2612 // We don't have any smart way of matching up these instructions, so we correlate them based on source order
2613 for (old_decls.items[0..n], new_decls.items[0..n]) |old_inst, new_inst| {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.
2614 match_stack.appendAssumeCapacity(.{ .old_inst = old_inst, .new_inst = new_inst });2622 match_stack.appendAssumeCapacity(.{ .old_inst = old_inst, .new_inst = new_inst });
2615 }2623 }
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 }
2616 }2634 }
26172635
2618 while (match_stack.popOrNull()) |match_item| {2636 while (match_stack.popOrNull()) |match_item| {
...@@ -2700,17 +2718,39 @@ pub fn mapOldZirToNew(...@@ -2700,17 +2718,39 @@ pub fn mapOldZirToNew(
2700 // Match the `declaration` instruction2718 // Match the `declaration` instruction
2701 try inst_map.put(gpa, old_decl_inst, new_decl_inst);2719 try inst_map.put(gpa, old_decl_inst, new_decl_inst);
27022720
2703 // Find container type declarations within this declaration2721 // Find trackable instructions within this declaration
2704 try old_zir.findDecls(gpa, &old_decls, old_decl_inst);2722 try old_zir.findTrackable(gpa, &old_contents, old_decl_inst);
2705 try new_zir.findDecls(gpa, &new_decls, new_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 always2728 const num_explicit_types = @min(old_contents.explicit_types.items.len, new_contents.explicit_types.items.len);
2708 // correlate them based on source order.2729 try match_stack.ensureUnusedCapacity(gpa, @intCast(num_explicit_types));
2709 const n = @min(old_decls.items.len, new_decls.items.len);2730 for (
2710 try match_stack.ensureUnusedCapacity(gpa, n);2731 old_contents.explicit_types.items[0..num_explicit_types],
2711 for (old_decls.items[0..n], new_decls.items[0..n]) |old_inst, new_inst| {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.
2712 match_stack.appendAssumeCapacity(.{ .old_inst = old_inst, .new_inst = new_inst });2735 match_stack.appendAssumeCapacity(.{ .old_inst = old_inst, .new_inst = new_inst });
2713 }2736 }
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 }
2714 }2754 }
2715 }2755 }
2716}2756}
src/Zcu/PerThread.zig+58-41
...@@ -185,11 +185,11 @@ pub fn astGenFile(...@@ -185,11 +185,11 @@ pub fn astGenFile(
185 log.debug("AstGen cached success: {s}", .{file.sub_file_path});185 log.debug("AstGen cached success: {s}", .{file.sub_file_path});
186186
187 if (file.zir.hasCompileErrors()) {187 if (file.zir.hasCompileErrors()) {
188 {188 comp.mutex.lock();
189 comp.mutex.lock();189 defer comp.mutex.unlock();
190 defer comp.mutex.unlock();190 try zcu.failed_files.putNoClobber(gpa, file, null);
191 try zcu.failed_files.putNoClobber(gpa, file, null);191 }
192 }192 if (file.zir.loweringFailed()) {
193 file.status = .astgen_failure;193 file.status = .astgen_failure;
194 return error.AnalysisFail;194 return error.AnalysisFail;
195 }195 }
...@@ -226,7 +226,7 @@ pub fn astGenFile(...@@ -226,7 +226,7 @@ pub fn astGenFile(
226 // single-threaded context, so we need to keep both versions around226 // single-threaded context, so we need to keep both versions around
227 // until that point in the pipeline. Previous ZIR data is freed after227 // until that point in the pipeline. Previous ZIR data is freed after
228 // that.228 // that.
229 if (file.zir_loaded and !file.zir.hasCompileErrors()) {229 if (file.zir_loaded and !file.zir.loweringFailed()) {
230 assert(file.prev_zir == null);230 assert(file.prev_zir == null);
231 const prev_zir_ptr = try gpa.create(Zir);231 const prev_zir_ptr = try gpa.create(Zir);
232 file.prev_zir = prev_zir_ptr;232 file.prev_zir = prev_zir_ptr;
...@@ -321,11 +321,11 @@ pub fn astGenFile(...@@ -321,11 +321,11 @@ pub fn astGenFile(
321 };321 };
322322
323 if (file.zir.hasCompileErrors()) {323 if (file.zir.hasCompileErrors()) {
324 {324 comp.mutex.lock();
325 comp.mutex.lock();325 defer comp.mutex.unlock();
326 defer comp.mutex.unlock();326 try zcu.failed_files.putNoClobber(gpa, file, null);
327 try zcu.failed_files.putNoClobber(gpa, file, null);327 }
328 }328 if (file.zir.loweringFailed()) {
329 file.status = .astgen_failure;329 file.status = .astgen_failure;
330 return error.AnalysisFail;330 return error.AnalysisFail;
331 }331 }
...@@ -363,7 +363,7 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {...@@ -363,7 +363,7 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
363 .file = file,363 .file = file,
364 .inst_map = .{},364 .inst_map = .{},
365 };365 };
366 if (!new_zir.hasCompileErrors()) {366 if (!new_zir.loweringFailed()) {
367 try Zcu.mapOldZirToNew(gpa, old_zir.*, file.zir, &gop.value_ptr.inst_map);367 try Zcu.mapOldZirToNew(gpa, old_zir.*, file.zir, &gop.value_ptr.inst_map);
368 }368 }
369 }369 }
...@@ -379,20 +379,19 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {...@@ -379,20 +379,19 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
379379
380 const file = updated_file.file;380 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 }
388 const old_inst = tracked_inst.inst.unwrap() orelse continue; // we can't continue tracking lost insts382 const old_inst = tracked_inst.inst.unwrap() orelse continue; // we can't continue tracking lost insts
389 const tracked_inst_index = (InternPool.TrackedInst.Index.Unwrapped{383 const tracked_inst_index = (InternPool.TrackedInst.Index.Unwrapped{
390 .tid = @enumFromInt(tid),384 .tid = @enumFromInt(tid),
391 .index = @intCast(tracked_inst_unwrapped_index),385 .index = @intCast(tracked_inst_unwrapped_index),
392 }).wrap(ip);386 }).wrap(ip);
393 const new_inst = updated_file.inst_map.get(old_inst) orelse {387 const new_inst = updated_file.inst_map.get(old_inst) orelse {
394 // Tracking failed for this instruction. Invalidate associated `src_hash` deps.388 // Tracking failed for this instruction.
395 log.debug("tracking failed for %{d}", .{old_inst});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 });
396 tracked_inst.inst = .lost;395 tracked_inst.inst = .lost;
397 try zcu.markDependeeOutdated(.not_marked_po, .{ .src_hash = tracked_inst_index });396 try zcu.markDependeeOutdated(.not_marked_po, .{ .src_hash = tracked_inst_index });
398 continue;397 continue;
...@@ -494,8 +493,8 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {...@@ -494,8 +493,8 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
494493
495 for (updated_files.keys(), updated_files.values()) |file_index, updated_file| {494 for (updated_files.keys(), updated_files.values()) |file_index, updated_file| {
496 const file = updated_file.file;495 const file = updated_file.file;
497 if (file.zir.hasCompileErrors()) {496 if (file.zir.loweringFailed()) {
498 // Keep `prev_zir` around: it's the last non-error ZIR.497 // Keep `prev_zir` around: it's the last usable ZIR.
499 // Don't update the namespace, as we have no new data to update *to*.498 // Don't update the namespace, as we have no new data to update *to*.
500 } else {499 } else {
501 const prev_zir = file.prev_zir.?;500 const prev_zir = file.prev_zir.?;
...@@ -539,7 +538,7 @@ pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu...@@ -539,7 +538,7 @@ pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu
539 const anal_unit = AnalUnit.wrap(.{ .cau = cau_index });538 const anal_unit = AnalUnit.wrap(.{ .cau = cau_index });
540 const cau = ip.getCau(cau_index);539 const cau = ip.getCau(cau_index);
541540
542 log.debug("ensureCauAnalyzed {d}", .{@intFromEnum(cau_index)});541 log.debug("ensureCauAnalyzed {}", .{zcu.fmtAnalUnit(anal_unit)});
543542
544 assert(!zcu.analysis_in_progress.contains(anal_unit));543 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...@@ -577,13 +576,19 @@ pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu
577 }576 }
578577
579 const sema_result: SemaCauResult, const analysis_fail = if (pt.ensureCauAnalyzedInner(cau_index, cau_outdated)) |result|578 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 }
581 else |err| switch (err) {585 else |err| switch (err) {
582 error.AnalysisFail => res: {586 error.AnalysisFail => res: {
583 if (!zcu.failed_analysis.contains(anal_unit)) {587 if (!zcu.failed_analysis.contains(anal_unit)) {
584 // If this `Cau` caused the error, it would have an entry in `failed_analysis`.588 // If this `Cau` caused the error, it would have an entry in `failed_analysis`.
585 // Since it does not, this must be a transitive failure.589 // Since it does not, this must be a transitive failure.
586 try zcu.transitive_failed_analysis.put(gpa, anal_unit, {});590 try zcu.transitive_failed_analysis.put(gpa, anal_unit, {});
591 log.debug("mark transitive analysis failure for {}", .{zcu.fmtAnalUnit(anal_unit)});
587 }592 }
588 // We consider this `Cau` to be outdated if:593 // We consider this `Cau` to be outdated if:
589 // * Previous analysis succeeded; in this case, we need to re-analyze dependants to ensure594 // * 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...@@ -708,12 +713,12 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter
708713
709 // We only care about the uncoerced function.714 // We only care about the uncoerced function.
710 const func_index = ip.unwrapCoercedFunc(maybe_coerced_func_index);715 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 });
717 const func_outdated = zcu.outdated.swapRemove(anal_unit) or722 const func_outdated = zcu.outdated.swapRemove(anal_unit) or
718 zcu.potentially_outdated.swapRemove(anal_unit);723 zcu.potentially_outdated.swapRemove(anal_unit);
719724
...@@ -741,6 +746,7 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter...@@ -741,6 +746,7 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter
741 // If this function caused the error, it would have an entry in `failed_analysis`.746 // If this function caused the error, it would have an entry in `failed_analysis`.
742 // Since it does not, this must be a transitive failure.747 // Since it does not, this must be a transitive failure.
743 try zcu.transitive_failed_analysis.put(gpa, anal_unit, {});748 try zcu.transitive_failed_analysis.put(gpa, anal_unit, {});
749 log.debug("mark transitive analysis failure for {}", .{zcu.fmtAnalUnit(anal_unit)});
744 }750 }
745 // We consider the IES to be outdated if the function previously succeeded analysis; in this case,751 // We consider the IES to be outdated if the function previously succeeded analysis; in this case,
746 // we need to re-analyze dependants to ensure they hit a transitive error here, rather than reporting752 // 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...@@ -752,10 +758,8 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter
752758
753 if (func_outdated) {759 if (func_outdated) {
754 if (ies_outdated) {760 if (ies_outdated) {
755 log.debug("func IES invalidated ('{d}')", .{@intFromEnum(func_index)});
756 try zcu.markDependeeOutdated(.marked_po, .{ .interned = func_index });761 try zcu.markDependeeOutdated(.marked_po, .{ .interned = func_index });
757 } else {762 } else {
758 log.debug("func IES up-to-date ('{d}')", .{@intFromEnum(func_index)});
759 try zcu.markPoDependeeUpToDate(.{ .interned = func_index });763 try zcu.markPoDependeeUpToDate(.{ .interned = func_index });
760 }764 }
761 }765 }
...@@ -780,6 +784,7 @@ fn ensureFuncBodyAnalyzedInner(...@@ -780,6 +784,7 @@ fn ensureFuncBodyAnalyzedInner(
780 // results in the worst case.784 // results in the worst case.
781785
782 if (func.generic_owner == .none) {786 if (func.generic_owner == .none) {
787 // Among another things, this ensures that the function's `zir_body_inst` is correct.
783 try pt.ensureCauAnalyzed(ip.getNav(func.owner_nav).analysis_owner.unwrap().?);788 try pt.ensureCauAnalyzed(ip.getNav(func.owner_nav).analysis_owner.unwrap().?);
784 if (ip.getNav(func.owner_nav).status.resolved.val != func_index) {789 if (ip.getNav(func.owner_nav).status.resolved.val != func_index) {
785 // This function is no longer referenced! There's no point in re-analyzing it.790 // This function is no longer referenced! There's no point in re-analyzing it.
...@@ -788,6 +793,7 @@ fn ensureFuncBodyAnalyzedInner(...@@ -788,6 +793,7 @@ fn ensureFuncBodyAnalyzedInner(
788 }793 }
789 } else {794 } else {
790 const go_nav = zcu.funcInfo(func.generic_owner).owner_nav;795 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.
791 try pt.ensureCauAnalyzed(ip.getNav(go_nav).analysis_owner.unwrap().?);797 try pt.ensureCauAnalyzed(ip.getNav(go_nav).analysis_owner.unwrap().?);
792 if (ip.getNav(go_nav).status.resolved.val != func.generic_owner) {798 if (ip.getNav(go_nav).status.resolved.val != func.generic_owner) {
793 // The generic owner is no longer referenced, so this function is also unreferenced.799 // The generic owner is no longer referenced, so this function is also unreferenced.
...@@ -825,8 +831,8 @@ fn ensureFuncBodyAnalyzedInner(...@@ -825,8 +831,8 @@ fn ensureFuncBodyAnalyzedInner(
825 }831 }
826 }832 }
827833
828 log.debug("analyze and generate fn body '{d}'; reason='{s}'", .{834 log.debug("analyze and generate fn body {}; reason='{s}'", .{
829 @intFromEnum(func_index),835 zcu.fmtAnalUnit(anal_unit),
830 if (func_outdated) "outdated" else "never analyzed",836 if (func_outdated) "outdated" else "never analyzed",
831 });837 });
832838
...@@ -1165,7 +1171,7 @@ fn semaCau(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) !SemaCauResult {...@@ -1165,7 +1171,7 @@ fn semaCau(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) !SemaCauResult {
1165 .none, .type => false,1171 .none, .type => false,
1166 };1172 };
11671173
1168 log.debug("semaCau '{d}'", .{@intFromEnum(cau_index)});1174 log.debug("semaCau {}", .{zcu.fmtAnalUnit(anal_unit)});
11691175
1170 try zcu.analysis_in_progress.put(gpa, anal_unit, {});1176 try zcu.analysis_in_progress.put(gpa, anal_unit, {});
1171 errdefer _ = zcu.analysis_in_progress.swapRemove(anal_unit);1177 errdefer _ = zcu.analysis_in_progress.swapRemove(anal_unit);
...@@ -2308,16 +2314,14 @@ pub fn getErrorValueFromSlice(pt: Zcu.PerThread, name: []const u8) Allocator.Err...@@ -2308,16 +2314,14 @@ pub fn getErrorValueFromSlice(pt: Zcu.PerThread, name: []const u8) Allocator.Err
2308 return pt.getErrorValue(try pt.zcu.intern_pool.getOrPutString(pt.zcu.gpa, name));2314 return pt.getErrorValue(try pt.zcu.intern_pool.getOrPutString(pt.zcu.gpa, name));
2309}2315}
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.
2311fn lockAndClearFileCompileError(pt: Zcu.PerThread, file: *Zcu.File) void {2319fn lockAndClearFileCompileError(pt: Zcu.PerThread, file: *Zcu.File) void {
2312 switch (file.status) {2320 if (!file.zir_loaded or !file.zir.hasCompileErrors()) return;
2313 .success_zir, .retryable_failure => {},2321 pt.zcu.comp.mutex.lock();
2314 .never_loaded, .parse_failure, .astgen_failure => {2322 defer pt.zcu.comp.mutex.unlock();
2315 pt.zcu.comp.mutex.lock();2323 if (pt.zcu.failed_files.fetchSwapRemove(file)) |kv| {
2316 defer pt.zcu.comp.mutex.unlock();2324 if (kv.value) |msg| msg.destroy(pt.zcu.gpa); // Delete previous error message.
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 },
2321 }2325 }
2322}2326}
23232327
...@@ -2507,6 +2511,19 @@ pub fn populateTestFunctions(...@@ -2507,6 +2511,19 @@ pub fn populateTestFunctions(
25072511
2508 for (test_fn_vals, zcu.test_functions.keys()) |*test_fn_val, test_nav_index| {2512 for (test_fn_vals, zcu.test_functions.keys()) |*test_fn_val, test_nav_index| {
2509 const test_nav = ip.getNav(test_nav_index);2513 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
2510 const test_nav_name = test_nav.fqn;2527 const test_nav_name = test_nav.fqn;
2511 const test_nav_name_len = test_nav_name.length(ip);2528 const test_nav_name_len = test_nav_name.length(ip);
2512 const test_name_anon_decl: InternPool.Key.Ptr.BaseAddr.Uav = n: {2529 const test_name_anon_decl: InternPool.Key.Ptr.BaseAddr.Uav = n: {
src/main.zig+18-5
...@@ -6097,11 +6097,18 @@ fn cmdAstCheck(...@@ -6097,11 +6097,18 @@ fn cmdAstCheck(
6097 var error_bundle = try wip_errors.toOwnedBundle("");6097 var error_bundle = try wip_errors.toOwnedBundle("");
6098 defer error_bundle.deinit(gpa);6098 defer error_bundle.deinit(gpa);
6099 error_bundle.renderToStdErr(color.renderOptions());6099 error_bundle.renderToStdErr(color.renderOptions());
6100 process.exit(1);6100
6101 if (file.zir.loweringFailed()) {
6102 process.exit(1);
6103 }
6101 }6104 }
61026105
6103 if (!want_output_text) {6106 if (!want_output_text) {
6104 return cleanExit();6107 if (file.zir.hasCompileErrors()) {
6108 process.exit(1);
6109 } else {
6110 return cleanExit();
6111 }
6105 }6112 }
6106 if (!build_options.enable_debug_extensions) {6113 if (!build_options.enable_debug_extensions) {
6107 fatal("-t option only available in builds of zig with debug extensions", .{});6114 fatal("-t option only available in builds of zig with debug extensions", .{});
...@@ -6145,7 +6152,13 @@ fn cmdAstCheck(...@@ -6145,7 +6152,13 @@ fn cmdAstCheck(
6145 // zig fmt: on6152 // zig fmt: on
6146 }6153 }
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 }
6149}6162}
61506163
6151fn cmdDetectCpu(6164fn cmdDetectCpu(
...@@ -6458,7 +6471,7 @@ fn cmdChangelist(...@@ -6458,7 +6471,7 @@ fn cmdChangelist(
6458 file.zir_loaded = true;6471 file.zir_loaded = true;
6459 defer file.zir.deinit(gpa);6472 defer file.zir.deinit(gpa);
64606473
6461 if (file.zir.hasCompileErrors()) {6474 if (file.zir.loweringFailed()) {
6462 var wip_errors: std.zig.ErrorBundle.Wip = undefined;6475 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
6463 try wip_errors.init(gpa);6476 try wip_errors.init(gpa);
6464 defer wip_errors.deinit();6477 defer wip_errors.deinit();
...@@ -6493,7 +6506,7 @@ fn cmdChangelist(...@@ -6493,7 +6506,7 @@ fn cmdChangelist(
6493 file.zir = try AstGen.generate(gpa, new_tree);6506 file.zir = try AstGen.generate(gpa, new_tree);
6494 file.zir_loaded = true;6507 file.zir_loaded = true;
64956508
6496 if (file.zir.hasCompileErrors()) {6509 if (file.zir.loweringFailed()) {
6497 var wip_errors: std.zig.ErrorBundle.Wip = undefined;6510 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
6498 try wip_errors.init(gpa);6511 try wip_errors.init(gpa);
6499 defer wip_errors.deinit();6512 defer wip_errors.deinit();
src/print_zir.zig+1
...@@ -623,6 +623,7 @@ const Writer = struct {...@@ -623,6 +623,7 @@ const Writer = struct {
623 .inplace_arith_result_ty => try self.writeInplaceArithResultTy(stream, extended),623 .inplace_arith_result_ty => try self.writeInplaceArithResultTy(stream, extended),
624624
625 .dbg_empty_stmt => try stream.writeAll("))"),625 .dbg_empty_stmt => try stream.writeAll("))"),
626 .astgen_error => try stream.writeAll("))"),
626 }627 }
627 }628 }
628629
test/cases/compile_errors/access_invalid_typeInfo_decl.zig+3-6
...@@ -1,11 +1,8 @@...@@ -1,11 +1,8 @@
1const A = B;1pub const A = B;
2test "Crash" {2export fn foo() void {
3 _ = @typeInfo(@This()).@"struct".decls[0];3 _ = @typeInfo(@This()).@"struct".decls[0];
4}4}
55
6// error6// error
7// backend=stage2
8// target=native
9// is_test=true
10//7//
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 @@...@@ -1,13 +1,8 @@
1fn func() bogus {}1fn func() void {}
2fn func() bogus {}2fn func() void {}
3export fn entry() usize {
4 return @sizeOf(@TypeOf(func));
5}
63
7// error4// error
8//5//
9// :1:4: error: duplicate struct member name 'func'6// :1:4: error: duplicate struct member name 'func'
10// :2:4: note: duplicate name here7// :2:4: note: duplicate name here
11// :1:1: note: struct declared here8// :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 {...@@ -19,3 +19,5 @@ export fn entry() void {
19//19//
20// :4:5: error: unreachable code20// :4:5: error: unreachable code
21// :4:25: note: control flow is diverted here21// :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 @@...@@ -1,22 +1,27 @@
1comptime {1comptime {
2 const a = "foo";2 const a = "foo";
3 if (a == "foo") unreachable;3 if (a != "foo") unreachable;
4}4}
5comptime {5comptime {
6 const a = "foo";6 const a = "foo";
7 if (a == ("foo")) unreachable; // intentionally allow7 if (a == "foo") {} else unreachable;
8}
9comptime {
10 const a = "foo";
11 if (a != ("foo")) {} // intentionally allow
12 if (a == ("foo")) {} // intentionally allow
8}13}
9comptime {14comptime {
10 const a = "foo";15 const a = "foo";
11 switch (a) {16 switch (a) {
12 "foo" => unreachable,17 "foo" => {},
13 else => {},18 else => unreachable,
14 }19 }
15}20}
16comptime {21comptime {
17 const a = "foo";22 const a = "foo";
18 switch (a) {23 switch (a) {
19 ("foo") => unreachable, // intentionally allow24 ("foo") => {}, // intentionally allow
20 else => {},25 else => {},
21 }26 }
22}27}
...@@ -25,5 +30,6 @@ comptime {...@@ -25,5 +30,6 @@ comptime {
25// backend=stage230// backend=stage2
26// target=native31// target=native
27//32//
28// :3:11: error: cannot compare strings with ==33// :3:11: error: cannot compare strings with !=
29// :12:9: error: cannot switch on strings34// :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 @@...@@ -1,6 +1,6 @@
1export fn foo() void {1export fn foo() void {
2 const a = 1;2 const a = 1;
3 struct {3 _ = struct {
4 test a {}4 test a {}
5 };5 };
6}6}
test/cases/compile_errors/misspelled_type_with_pointer_only_reference.zig-4
...@@ -28,10 +28,6 @@ fn foo() void {...@@ -28,10 +28,6 @@ fn foo() void {
28 _ = jd;28 _ = jd;
29}29}
3030
31export fn entry() usize {
32 return @sizeOf(@TypeOf(foo));
33}
34
35// error31// error
36// backend=stage232// backend=stage2
37// target=native33// target=native
test/cases/compile_errors/noreturn_builtins_divert_control_flow.zig+2-1
...@@ -7,7 +7,7 @@ export fn entry2() void {...@@ -7,7 +7,7 @@ export fn entry2() void {
7 @panic("");7 @panic("");
8}8}
9export fn entry3() void {9export fn entry3() void {
10 @compileError("");10 @compileError("expect to hit this");
11 @compileError("");11 @compileError("");
12}12}
1313
...@@ -21,3 +21,4 @@ export fn entry3() void {...@@ -21,3 +21,4 @@ export fn entry3() void {
21// :6:5: note: control flow is diverted here21// :6:5: note: control flow is diverted here
22// :11:5: error: unreachable code22// :11:5: error: unreachable code
23// :10:5: note: control flow is diverted here23// :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 @@...@@ -2,14 +2,8 @@
2fn entry() void {}2fn entry() void {}
3fn entry() void {}3fn entry() void {}
44
5fn foo() void {
6 var foo = 1234;
7}
8
9// error5// error
10//6//
11// :2:4: error: duplicate struct member name 'entry'7// :2:4: error: duplicate struct member name 'entry'
12// :3:4: note: duplicate name here8// :3:4: note: duplicate name here
13// :2:1: note: struct declared here9// :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 @@...@@ -1,6 +1,6 @@
1pub fn main() void {1pub fn main() void {
2 const x = 1;2 const x = 1;
3 const y, var z = .{ 2, 3 };3 const y, var z: u32 = .{ 2, 3 };
4}4}
55
6// error6// error