| author | |
| committer | |
| log | 7575f212128df84c8b86ee3c89d940313380d902 |
| tree | fc060baccfbfbb24946779a0795c6c29d9d9bf92 |
| parent | 8245d7fac0400d7e9de2a6fd4cfbc3609ad0f201 |
| parent | 9f086f84f53de4eb23d96fe611c071f27405a660 |
| signature |
compiler: allow semantic analysis of files with AstGen errors20 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 | 74 | len: usize, |
| 75 | 75 | capacity: usize, |
| 76 | 76 | |
| 77 | pub const empty: Slice = .{ | |
| 78 | .ptrs = undefined, | |
| 79 | .len = 0, | |
| 80 | .capacity = 0, | |
| 81 | }; | |
| 82 | ||
| 77 | 83 | pub fn items(self: Slice, comptime field: Field) []FieldType(field) { |
| 78 | 84 | const F = FieldType(field); |
| 79 | 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 | 172 | }; |
| 173 | 173 | defer gz_instructions.deinit(gpa); |
| 174 | 174 | |
| 175 | // The AST -> ZIR lowering process assumes an AST that does not have any | |
| 176 | // parse errors. | |
| 177 | if (tree.errors.len == 0) { | |
| 175 | // The AST -> ZIR lowering process assumes an AST that does not have any parse errors. | |
| 176 | // Parse errors, or AstGen errors in the root struct, are considered "fatal", so we emit no ZIR. | |
| 177 | const fatal = if (tree.errors.len == 0) fatal: { | |
| 178 | 178 | if (AstGen.structDeclInner( |
| 179 | 179 | &gen_scope, |
| 180 | 180 | &gen_scope.base, |
| ... | ... | @@ -184,13 +184,15 @@ pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir { |
| 184 | 184 | 0, |
| 185 | 185 | )) |struct_decl_ref| { |
| 186 | 186 | assert(struct_decl_ref.toIndex().? == .main_struct_inst); |
| 187 | break :fatal false; | |
| 187 | 188 | } else |err| switch (err) { |
| 188 | 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 | 193 | try lowerAstErrors(&astgen); |
| 193 | } | |
| 194 | break :fatal true; | |
| 195 | }; | |
| 194 | 196 | |
| 195 | 197 | const err_index = @intFromEnum(Zir.ExtraIndex.compile_errors); |
| 196 | 198 | if (astgen.compile_errors.items.len == 0) { |
| ... | ... | @@ -228,8 +230,8 @@ pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir { |
| 228 | 230 | } |
| 229 | 231 | } |
| 230 | 232 | |
| 231 | return Zir{ | |
| 232 | .instructions = astgen.instructions.toOwnedSlice(), | |
| 233 | return .{ | |
| 234 | .instructions = if (fatal) .empty else astgen.instructions.toOwnedSlice(), | |
| 233 | 235 | .string_bytes = try astgen.string_bytes.toOwnedSlice(gpa), |
| 234 | 236 | .extra = try astgen.extra.toOwnedSlice(gpa), |
| 235 | 237 | }; |
| ... | ... | @@ -2110,7 +2112,7 @@ fn comptimeExprAst( |
| 2110 | 2112 | ) InnerError!Zir.Inst.Ref { |
| 2111 | 2113 | const astgen = gz.astgen; |
| 2112 | 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 | 2117 | const tree = astgen.tree; |
| 2116 | 2118 | const node_datas = tree.nodes.items(.data); |
| ... | ... | @@ -3269,6 +3271,9 @@ fn varDecl( |
| 3269 | 3271 | try astgen.appendErrorTok(comptime_token, "'comptime const' is redundant; instead wrap the initialization expression with 'comptime'", .{}); |
| 3270 | 3272 | } |
| 3271 | 3273 | |
| 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 | 3277 | // Depending on the type of AST the initialization expression is, we may need an lvalue |
| 3273 | 3278 | // or an rvalue as a result location. If it is an rvalue, we can use the instruction as |
| 3274 | 3279 | // the variable, no memory location needed. |
| ... | ... | @@ -3282,7 +3287,7 @@ fn varDecl( |
| 3282 | 3287 | } else .{ .rl = .none, .ctx = .const_init }; |
| 3283 | 3288 | const prev_anon_name_strategy = gz.anon_name_strategy; |
| 3284 | 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 | 3291 | gz.anon_name_strategy = prev_anon_name_strategy; |
| 3287 | 3292 | |
| 3288 | 3293 | try gz.addDbgVar(.dbg_var_val, ident_name, init_inst); |
| ... | ... | @@ -3348,7 +3353,7 @@ fn varDecl( |
| 3348 | 3353 | const prev_anon_name_strategy = gz.anon_name_strategy; |
| 3349 | 3354 | gz.anon_name_strategy = .dbg_var; |
| 3350 | 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); | |
| 3352 | 3357 | |
| 3353 | 3358 | // The const init expression may have modified the error return trace, so signal |
| 3354 | 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 | 3496 | |
| 3492 | 3497 | const full = tree.assignDestructure(node); |
| 3493 | 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 | } |
| 3496 | 3501 | |
| 3497 | 3502 | // If this expression is marked comptime, we must wrap the whole thing in a comptime block. |
| ... | ... | @@ -3550,7 +3555,7 @@ fn assignDestructureMaybeDecls( |
| 3550 | 3555 | |
| 3551 | 3556 | const full = tree.assignDestructure(node); |
| 3552 | 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 | } |
| 3555 | 3560 | |
| 3556 | 3561 | const is_comptime = full.comptime_token != null or gz.is_comptime; |
| ... | ... | @@ -3664,6 +3669,7 @@ fn assignDestructureMaybeDecls( |
| 3664 | 3669 | |
| 3665 | 3670 | if (full.comptime_token != null and !any_non_const_variables) { |
| 3666 | 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 | } |
| 3668 | 3674 | |
| 3669 | 3675 | // If this expression is marked comptime, we must wrap it in a comptime block. |
| ... | ... | @@ -4112,8 +4118,8 @@ fn fnDecl( |
| 4112 | 4118 | // The source slice is added towards the *end* of this function. |
| 4113 | 4119 | astgen.src_hasher.update(std.mem.asBytes(&astgen.source_column)); |
| 4114 | 4120 | |
| 4115 | // missing function name already happened in scanContainer() | |
| 4116 | const fn_name_token = fn_proto.name_token orelse return error.AnalysisFail; | |
| 4121 | // missing function name already checked in scanContainer() | |
| 4122 | const fn_name_token = fn_proto.name_token.?; | |
| 4117 | 4123 | |
| 4118 | 4124 | // We insert this at the beginning so that its instruction index marks the |
| 4119 | 4125 | // start of the top level declaration. |
| ... | ... | @@ -5182,8 +5188,7 @@ fn structDeclInner( |
| 5182 | 5188 | |
| 5183 | 5189 | if (is_comptime) { |
| 5184 | 5190 | switch (layout) { |
| 5185 | .@"packed" => return astgen.failTok(member.comptime_token.?, "packed struct fields cannot be marked comptime", .{}), | |
| 5186 | .@"extern" => return astgen.failTok(member.comptime_token.?, "extern struct fields cannot be marked comptime", .{}), | |
| 5191 | .@"packed", .@"extern" => return astgen.failTok(member.comptime_token.?, "{s} struct fields cannot be marked comptime", .{@tagName(layout)}), | |
| 5187 | 5192 | .auto => any_comptime_fields = true, |
| 5188 | 5193 | } |
| 5189 | 5194 | } else { |
| ... | ... | @@ -5210,7 +5215,7 @@ fn structDeclInner( |
| 5210 | 5215 | |
| 5211 | 5216 | if (have_align) { |
| 5212 | 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 | 5220 | any_aligned_fields = true; |
| 5216 | 5221 | const align_ref = try expr(&block_scope, &namespace.base, coerced_align_ri, member.ast.align_expr); |
| ... | ... | @@ -5304,8 +5309,7 @@ fn tupleDecl( |
| 5304 | 5309 | |
| 5305 | 5310 | switch (layout) { |
| 5306 | 5311 | .auto => {}, |
| 5307 | .@"extern" => return astgen.failNode(node, "extern tuples are not supported", .{}), | |
| 5308 | .@"packed" => return astgen.failNode(node, "packed tuples are not supported", .{}), | |
| 5312 | .@"extern", .@"packed" => return astgen.failNode(node, "{s} tuples are not supported", .{@tagName(layout)}), | |
| 5309 | 5313 | } |
| 5310 | 5314 | |
| 5311 | 5315 | if (backing_int_node != 0) { |
| ... | ... | @@ -5688,7 +5692,7 @@ fn containerDecl( |
| 5688 | 5692 | }; |
| 5689 | 5693 | }; |
| 5690 | 5694 | if (counts.nonexhaustive_node != 0 and container_decl.ast.arg == 0) { |
| 5691 | try astgen.appendErrorNodeNotes( | |
| 5695 | return astgen.failNodeNotes( | |
| 5692 | 5696 | node, |
| 5693 | 5697 | "non-exhaustive enum missing integer tag type", |
| 5694 | 5698 | .{}, |
| ... | ... | @@ -5911,9 +5915,19 @@ fn containerMember( |
| 5911 | 5915 | const full = tree.fullFnProto(&buf, member_node).?; |
| 5912 | 5916 | const body = if (node_tags[member_node] == .fn_decl) node_datas[member_node].rhs else 0; |
| 5913 | 5917 | |
| 5918 | const prev_decl_index = wip_members.decl_index; | |
| 5914 | 5919 | astgen.fnDecl(gz, scope, wip_members, member_node, body, full) catch |err| switch (err) { |
| 5915 | 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 | }, |
| 5919 | 5933 | |
| ... | ... | @@ -5922,28 +5936,77 @@ fn containerMember( |
| 5922 | 5936 | .simple_var_decl, |
| 5923 | 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 | 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 | }, |
| 5930 | 5955 | |
| 5931 | 5956 | .@"comptime" => { |
| 5957 | const prev_decl_index = wip_members.decl_index; | |
| 5932 | 5958 | astgen.comptimeDecl(gz, scope, wip_members, member_node) catch |err| switch (err) { |
| 5933 | 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 | 5972 | .@"usingnamespace" => { |
| 5973 | const prev_decl_index = wip_members.decl_index; | |
| 5938 | 5974 | astgen.usingnamespaceDecl(gz, scope, wip_members, member_node) catch |err| switch (err) { |
| 5939 | 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 | 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 | 5998 | astgen.testDecl(gz, scope, wip_members, member_node) catch |err| switch (err) { |
| 5945 | 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 | 6012 | else => unreachable, |
| ... | ... | @@ -6155,7 +6218,7 @@ fn orelseCatchExpr( |
| 6155 | 6218 | const payload = payload_token orelse break :blk &else_scope.base; |
| 6156 | 6219 | const err_str = tree.tokenSlice(payload); |
| 6157 | 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 | 6223 | const err_name = try astgen.identAsString(payload); |
| 6161 | 6224 | |
| ... | ... | @@ -6614,7 +6677,7 @@ fn whileExpr( |
| 6614 | 6677 | |
| 6615 | 6678 | const is_inline = while_full.inline_token != null; |
| 6616 | 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 | 6682 | const loop_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .loop; |
| 6620 | 6683 | const loop_block = try parent_gz.makeBlockInst(loop_tag, node); |
| ... | ... | @@ -6904,7 +6967,7 @@ fn forExpr( |
| 6904 | 6967 | |
| 6905 | 6968 | const is_inline = for_full.inline_token != null; |
| 6906 | 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 | 6972 | const tree = astgen.tree; |
| 6910 | 6973 | const token_tags = tree.tokens.items(.tag); |
| ... | ... | @@ -6965,7 +7028,7 @@ fn forExpr( |
| 6965 | 7028 | .none; |
| 6966 | 7029 | |
| 6967 | 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 | } |
| 6970 | 7033 | |
| 6971 | 7034 | const start_is_zero = nodeIsTriviallyZero(tree, start_node); |
| ... | ... | @@ -7467,6 +7530,7 @@ fn switchExprErrUnion( |
| 7467 | 7530 | const err_name = blk: { |
| 7468 | 7531 | const err_str = tree.tokenSlice(error_payload); |
| 7469 | 7532 | if (mem.eql(u8, err_str, "_")) { |
| 7533 | // This is fatal because we already know we're switching on the captured error. | |
| 7470 | 7534 | return astgen.failTok(error_payload, "discard of error capture; omit it instead", .{}); |
| 7471 | 7535 | } |
| 7472 | 7536 | const err_name = try astgen.identAsString(error_payload); |
| ... | ... | @@ -7521,7 +7585,7 @@ fn switchExprErrUnion( |
| 7521 | 7585 | |
| 7522 | 7586 | const capture_slice = tree.tokenSlice(capture_token); |
| 7523 | 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 | 7590 | const tag_name = try astgen.identAsString(capture_token); |
| 7527 | 7591 | try astgen.detectLocalShadowing(&case_scope.base, tag_name, capture_token, capture_slice, .capture); |
| ... | ... | @@ -7992,7 +8056,7 @@ fn switchExpr( |
| 7992 | 8056 | break :blk payload_sub_scope; |
| 7993 | 8057 | const tag_slice = tree.tokenSlice(tag_token); |
| 7994 | 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 | 8060 | } else if (case.inline_token == null) { |
| 7997 | 8061 | return astgen.failTok(tag_token, "tag capture on non-inline prong", .{}); |
| 7998 | 8062 | } |
| ... | ... | @@ -13678,6 +13742,8 @@ fn scanContainer( |
| 13678 | 13742 | const main_tokens = tree.nodes.items(.main_token); |
| 13679 | 13743 | const token_tags = tree.tokens.items(.tag); |
| 13680 | 13744 | |
| 13745 | var any_invalid_declarations = false; | |
| 13746 | ||
| 13681 | 13747 | // This type forms a linked list of source tokens declaring the same name. |
| 13682 | 13748 | const NameEntry = struct { |
| 13683 | 13749 | tok: Ast.TokenIndex, |
| ... | ... | @@ -13737,6 +13803,7 @@ fn scanContainer( |
| 13737 | 13803 | const ident = main_tokens[member_node] + 1; |
| 13738 | 13804 | if (token_tags[ident] != .identifier) { |
| 13739 | 13805 | try astgen.appendErrorNode(member_node, "missing function name", .{}); |
| 13806 | any_invalid_declarations = true; | |
| 13740 | 13807 | continue; |
| 13741 | 13808 | } |
| 13742 | 13809 | break :blk .{ .decl, ident }; |
| ... | ... | @@ -13832,6 +13899,7 @@ fn scanContainer( |
| 13832 | 13899 | token_bytes, |
| 13833 | 13900 | }), |
| 13834 | 13901 | }); |
| 13902 | any_invalid_declarations = true; | |
| 13835 | 13903 | continue; |
| 13836 | 13904 | } |
| 13837 | 13905 | |
| ... | ... | @@ -13849,6 +13917,7 @@ fn scanContainer( |
| 13849 | 13917 | .{}, |
| 13850 | 13918 | ), |
| 13851 | 13919 | }); |
| 13920 | any_invalid_declarations = true; | |
| 13852 | 13921 | break; |
| 13853 | 13922 | } |
| 13854 | 13923 | s = local_val.parent; |
| ... | ... | @@ -13865,6 +13934,7 @@ fn scanContainer( |
| 13865 | 13934 | .{}, |
| 13866 | 13935 | ), |
| 13867 | 13936 | }); |
| 13937 | any_invalid_declarations = true; | |
| 13868 | 13938 | break; |
| 13869 | 13939 | } |
| 13870 | 13940 | s = local_ptr.parent; |
| ... | ... | @@ -13876,7 +13946,10 @@ fn scanContainer( |
| 13876 | 13946 | }; |
| 13877 | 13947 | } |
| 13878 | 13948 | |
| 13879 | if (!any_duplicates) return decl_count; | |
| 13949 | if (!any_duplicates) { | |
| 13950 | if (any_invalid_declarations) return error.AnalysisFail; | |
| 13951 | return decl_count; | |
| 13952 | } | |
| 13880 | 13953 | |
| 13881 | 13954 | for (names.keys(), names.values()) |name, first| { |
| 13882 | 13955 | if (first.next == null) continue; |
| ... | ... | @@ -13888,6 +13961,7 @@ fn scanContainer( |
| 13888 | 13961 | try notes.append(astgen.arena, try astgen.errNoteNode(namespace.node, "{s} declared here", .{@tagName(container_kind)})); |
| 13889 | 13962 | const name_duped = try astgen.arena.dupe(u8, mem.span(astgen.nullTerminatedString(name))); |
| 13890 | 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 | } |
| 13892 | 13966 | |
| 13893 | 13967 | for (test_names.keys(), test_names.values()) |name, first| { |
| ... | ... | @@ -13900,6 +13974,7 @@ fn scanContainer( |
| 13900 | 13974 | try notes.append(astgen.arena, try astgen.errNoteNode(namespace.node, "{s} declared here", .{@tagName(container_kind)})); |
| 13901 | 13975 | const name_duped = try astgen.arena.dupe(u8, mem.span(astgen.nullTerminatedString(name))); |
| 13902 | 13976 | try astgen.appendErrorTokNotes(first.tok, "duplicate test name '{s}'", .{name_duped}, notes.items); |
| 13977 | any_invalid_declarations = true; | |
| 13903 | 13978 | } |
| 13904 | 13979 | |
| 13905 | 13980 | for (decltest_names.keys(), decltest_names.values()) |name, first| { |
| ... | ... | @@ -13912,9 +13987,11 @@ fn scanContainer( |
| 13912 | 13987 | try notes.append(astgen.arena, try astgen.errNoteNode(namespace.node, "{s} declared here", .{@tagName(container_kind)})); |
| 13913 | 13988 | const name_duped = try astgen.arena.dupe(u8, mem.span(astgen.nullTerminatedString(name))); |
| 13914 | 13989 | try astgen.appendErrorTokNotes(first.tok, "duplicate decltest '{s}'", .{name_duped}, notes.items); |
| 13990 | any_invalid_declarations = true; | |
| 13915 | 13991 | } |
| 13916 | 13992 | |
| 13917 | return decl_count; | |
| 13993 | assert(any_invalid_declarations); | |
| 13994 | return error.AnalysisFail; | |
| 13918 | 13995 | } |
| 13919 | 13996 | |
| 13920 | 13997 | /// Assumes capacity for body has already been added. Needed capacity taking into |
| ... | ... | @@ -14070,6 +14147,37 @@ const DeclarationName = union(enum) { |
| 14070 | 14147 | @"usingnamespace", |
| 14071 | 14148 | }; |
| 14072 | 14149 | |
| 14150 | fn 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 | 14181 | /// Sets all extra data for a `declaration` instruction. |
| 14074 | 14182 | /// Unstacks `value_gz`, `align_gz`, `linksection_gz`, and `addrspace_gz`. |
| 14075 | 14183 | fn setDeclaration( |
lib/std/zig/Zir.zig+211-177| ... | ... | @@ -120,7 +120,21 @@ pub fn bodySlice(zir: Zir, start: usize, len: usize) []Inst.Index { |
| 120 | 120 | } |
| 121 | 121 | |
| 122 | 122 | pub 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 | ||
| 131 | pub 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 | } |
| 125 | 139 | |
| 126 | 140 | pub fn deinit(code: *Zir, gpa: Allocator) void { |
| ... | ... | @@ -2079,7 +2093,14 @@ pub const Inst = struct { |
| 2079 | 2093 | /// `small` is an `Inst.InplaceOp`. |
| 2080 | 2094 | inplace_arith_result_ty, |
| 2081 | 2095 | /// Marks a statement that can be stepped to but produces no code. |
| 2096 | /// `operand` and `small` are ignored. | |
| 2082 | 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, | |
| 2083 | 2104 | |
| 2084 | 2105 | pub const InstData = struct { |
| 2085 | 2106 | opcode: Extended, |
| ... | ... | @@ -3584,145 +3605,155 @@ pub const DeclIterator = struct { |
| 3584 | 3605 | }; |
| 3585 | 3606 | |
| 3586 | 3607 | pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator { |
| 3587 | const tags = zir.instructions.items(.tag); | |
| 3588 | const datas = zir.instructions.items(.data); | |
| 3589 | switch (tags[@intFromEnum(decl_inst)]) { | |
| 3590 | // Functions are allowed and yield no iterations. | |
| 3591 | // This is because they are returned by `findDecls`. | |
| 3592 | .func, .func_inferred, .func_fancy => return .{ | |
| 3593 | .extra_index = undefined, | |
| 3594 | .decls_remaining = 0, | |
| 3595 | .zir = zir, | |
| 3596 | }, | |
| 3597 | ||
| 3598 | .extended => { | |
| 3599 | const extended = datas[@intFromEnum(decl_inst)].extended; | |
| 3600 | switch (extended.opcode) { | |
| 3601 | // Reifications are allowed and yield no iterations. | |
| 3602 | // This is because they are returned by `findDecls`. | |
| 3603 | .reify => return .{ | |
| 3604 | .extra_index = undefined, | |
| 3605 | .decls_remaining = 0, | |
| 3606 | .zir = zir, | |
| 3607 | }, | |
| 3608 | .struct_decl => { | |
| 3609 | const small: Inst.StructDecl.Small = @bitCast(extended.small); | |
| 3610 | var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.StructDecl).@"struct".fields.len); | |
| 3611 | const captures_len = if (small.has_captures_len) captures_len: { | |
| 3612 | const captures_len = zir.extra[extra_index]; | |
| 3613 | extra_index += 1; | |
| 3614 | break :captures_len captures_len; | |
| 3615 | } else 0; | |
| 3616 | extra_index += @intFromBool(small.has_fields_len); | |
| 3617 | const decls_len = if (small.has_decls_len) decls_len: { | |
| 3618 | const decls_len = zir.extra[extra_index]; | |
| 3619 | extra_index += 1; | |
| 3620 | break :decls_len decls_len; | |
| 3621 | } else 0; | |
| 3622 | ||
| 3623 | extra_index += captures_len; | |
| 3624 | ||
| 3625 | if (small.has_backing_int) { | |
| 3626 | const backing_int_body_len = zir.extra[extra_index]; | |
| 3627 | extra_index += 1; // backing_int_body_len | |
| 3628 | if (backing_int_body_len == 0) { | |
| 3629 | extra_index += 1; // backing_int_ref | |
| 3630 | } else { | |
| 3631 | extra_index += backing_int_body_len; // backing_int_body_inst | |
| 3632 | } | |
| 3633 | } | |
| 3608 | const inst = zir.instructions.get(@intFromEnum(decl_inst)); | |
| 3609 | assert(inst.tag == .extended); | |
| 3610 | const extended = inst.data.extended; | |
| 3611 | switch (extended.opcode) { | |
| 3612 | .struct_decl => { | |
| 3613 | const small: Inst.StructDecl.Small = @bitCast(extended.small); | |
| 3614 | var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.StructDecl).@"struct".fields.len); | |
| 3615 | const captures_len = if (small.has_captures_len) captures_len: { | |
| 3616 | const captures_len = zir.extra[extra_index]; | |
| 3617 | extra_index += 1; | |
| 3618 | break :captures_len captures_len; | |
| 3619 | } else 0; | |
| 3620 | extra_index += @intFromBool(small.has_fields_len); | |
| 3621 | const decls_len = if (small.has_decls_len) decls_len: { | |
| 3622 | const decls_len = zir.extra[extra_index]; | |
| 3623 | extra_index += 1; | |
| 3624 | break :decls_len decls_len; | |
| 3625 | } else 0; | |
| 3626 | ||
| 3627 | extra_index += captures_len; | |
| 3628 | ||
| 3629 | if (small.has_backing_int) { | |
| 3630 | const backing_int_body_len = zir.extra[extra_index]; | |
| 3631 | extra_index += 1; // backing_int_body_len | |
| 3632 | if (backing_int_body_len == 0) { | |
| 3633 | extra_index += 1; // backing_int_ref | |
| 3634 | } else { | |
| 3635 | extra_index += backing_int_body_len; // backing_int_body_inst | |
| 3636 | } | |
| 3637 | } | |
| 3634 | 3638 | |
| 3635 | return .{ | |
| 3636 | .extra_index = extra_index, | |
| 3637 | .decls_remaining = decls_len, | |
| 3638 | .zir = zir, | |
| 3639 | }; | |
| 3640 | }, | |
| 3641 | .enum_decl => { | |
| 3642 | const small: Inst.EnumDecl.Small = @bitCast(extended.small); | |
| 3643 | var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.EnumDecl).@"struct".fields.len); | |
| 3644 | extra_index += @intFromBool(small.has_tag_type); | |
| 3645 | const captures_len = if (small.has_captures_len) captures_len: { | |
| 3646 | const captures_len = zir.extra[extra_index]; | |
| 3647 | extra_index += 1; | |
| 3648 | break :captures_len captures_len; | |
| 3649 | } else 0; | |
| 3650 | extra_index += @intFromBool(small.has_body_len); | |
| 3651 | extra_index += @intFromBool(small.has_fields_len); | |
| 3652 | const decls_len = if (small.has_decls_len) decls_len: { | |
| 3653 | const decls_len = zir.extra[extra_index]; | |
| 3654 | extra_index += 1; | |
| 3655 | break :decls_len decls_len; | |
| 3656 | } else 0; | |
| 3639 | return .{ | |
| 3640 | .extra_index = extra_index, | |
| 3641 | .decls_remaining = decls_len, | |
| 3642 | .zir = zir, | |
| 3643 | }; | |
| 3644 | }, | |
| 3645 | .enum_decl => { | |
| 3646 | const small: Inst.EnumDecl.Small = @bitCast(extended.small); | |
| 3647 | var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.EnumDecl).@"struct".fields.len); | |
| 3648 | extra_index += @intFromBool(small.has_tag_type); | |
| 3649 | const captures_len = if (small.has_captures_len) captures_len: { | |
| 3650 | const captures_len = zir.extra[extra_index]; | |
| 3651 | extra_index += 1; | |
| 3652 | break :captures_len captures_len; | |
| 3653 | } else 0; | |
| 3654 | extra_index += @intFromBool(small.has_body_len); | |
| 3655 | extra_index += @intFromBool(small.has_fields_len); | |
| 3656 | const decls_len = if (small.has_decls_len) decls_len: { | |
| 3657 | const decls_len = zir.extra[extra_index]; | |
| 3658 | extra_index += 1; | |
| 3659 | break :decls_len decls_len; | |
| 3660 | } else 0; | |
| 3657 | 3661 | |
| 3658 | extra_index += captures_len; | |
| 3662 | extra_index += captures_len; | |
| 3659 | 3663 | |
| 3660 | return .{ | |
| 3661 | .extra_index = extra_index, | |
| 3662 | .decls_remaining = decls_len, | |
| 3663 | .zir = zir, | |
| 3664 | }; | |
| 3665 | }, | |
| 3666 | .union_decl => { | |
| 3667 | const small: Inst.UnionDecl.Small = @bitCast(extended.small); | |
| 3668 | var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.UnionDecl).@"struct".fields.len); | |
| 3669 | extra_index += @intFromBool(small.has_tag_type); | |
| 3670 | const captures_len = if (small.has_captures_len) captures_len: { | |
| 3671 | const captures_len = zir.extra[extra_index]; | |
| 3672 | extra_index += 1; | |
| 3673 | break :captures_len captures_len; | |
| 3674 | } else 0; | |
| 3675 | extra_index += @intFromBool(small.has_body_len); | |
| 3676 | extra_index += @intFromBool(small.has_fields_len); | |
| 3677 | const decls_len = if (small.has_decls_len) decls_len: { | |
| 3678 | const decls_len = zir.extra[extra_index]; | |
| 3679 | extra_index += 1; | |
| 3680 | break :decls_len decls_len; | |
| 3681 | } else 0; | |
| 3664 | return .{ | |
| 3665 | .extra_index = extra_index, | |
| 3666 | .decls_remaining = decls_len, | |
| 3667 | .zir = zir, | |
| 3668 | }; | |
| 3669 | }, | |
| 3670 | .union_decl => { | |
| 3671 | const small: Inst.UnionDecl.Small = @bitCast(extended.small); | |
| 3672 | var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.UnionDecl).@"struct".fields.len); | |
| 3673 | extra_index += @intFromBool(small.has_tag_type); | |
| 3674 | const captures_len = if (small.has_captures_len) captures_len: { | |
| 3675 | const captures_len = zir.extra[extra_index]; | |
| 3676 | extra_index += 1; | |
| 3677 | break :captures_len captures_len; | |
| 3678 | } else 0; | |
| 3679 | extra_index += @intFromBool(small.has_body_len); | |
| 3680 | extra_index += @intFromBool(small.has_fields_len); | |
| 3681 | const decls_len = if (small.has_decls_len) decls_len: { | |
| 3682 | const decls_len = zir.extra[extra_index]; | |
| 3683 | extra_index += 1; | |
| 3684 | break :decls_len decls_len; | |
| 3685 | } else 0; | |
| 3682 | 3686 | |
| 3683 | extra_index += captures_len; | |
| 3687 | extra_index += captures_len; | |
| 3684 | 3688 | |
| 3685 | return .{ | |
| 3686 | .extra_index = extra_index, | |
| 3687 | .decls_remaining = decls_len, | |
| 3688 | .zir = zir, | |
| 3689 | }; | |
| 3690 | }, | |
| 3691 | .opaque_decl => { | |
| 3692 | const small: Inst.OpaqueDecl.Small = @bitCast(extended.small); | |
| 3693 | var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.OpaqueDecl).@"struct".fields.len); | |
| 3694 | const decls_len = if (small.has_decls_len) decls_len: { | |
| 3695 | const decls_len = zir.extra[extra_index]; | |
| 3696 | extra_index += 1; | |
| 3697 | break :decls_len decls_len; | |
| 3698 | } else 0; | |
| 3699 | const captures_len = if (small.has_captures_len) captures_len: { | |
| 3700 | const captures_len = zir.extra[extra_index]; | |
| 3701 | extra_index += 1; | |
| 3702 | break :captures_len captures_len; | |
| 3703 | } else 0; | |
| 3689 | return .{ | |
| 3690 | .extra_index = extra_index, | |
| 3691 | .decls_remaining = decls_len, | |
| 3692 | .zir = zir, | |
| 3693 | }; | |
| 3694 | }, | |
| 3695 | .opaque_decl => { | |
| 3696 | const small: Inst.OpaqueDecl.Small = @bitCast(extended.small); | |
| 3697 | var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.OpaqueDecl).@"struct".fields.len); | |
| 3698 | const decls_len = if (small.has_decls_len) decls_len: { | |
| 3699 | const decls_len = zir.extra[extra_index]; | |
| 3700 | extra_index += 1; | |
| 3701 | break :decls_len decls_len; | |
| 3702 | } else 0; | |
| 3703 | const captures_len = if (small.has_captures_len) captures_len: { | |
| 3704 | const captures_len = zir.extra[extra_index]; | |
| 3705 | extra_index += 1; | |
| 3706 | break :captures_len captures_len; | |
| 3707 | } else 0; | |
| 3704 | 3708 | |
| 3705 | extra_index += captures_len; | |
| 3709 | extra_index += captures_len; | |
| 3706 | 3710 | |
| 3707 | return .{ | |
| 3708 | .extra_index = extra_index, | |
| 3709 | .decls_remaining = decls_len, | |
| 3710 | .zir = zir, | |
| 3711 | }; | |
| 3712 | }, | |
| 3713 | else => unreachable, | |
| 3714 | } | |
| 3711 | return .{ | |
| 3712 | .extra_index = extra_index, | |
| 3713 | .decls_remaining = decls_len, | |
| 3714 | .zir = zir, | |
| 3715 | }; | |
| 3715 | 3716 | }, |
| 3716 | 3717 | else => unreachable, |
| 3717 | 3718 | } |
| 3718 | 3719 | } |
| 3719 | 3720 | |
| 3720 | /// Find all type declarations, recursively, within a `declaration` instruction. Does not recurse through | |
| 3721 | /// said type declarations' declarations; to find all declarations, call this function on the declarations | |
| 3722 | /// of the discovered types recursively. | |
| 3723 | /// The iterator would have to allocate memory anyway to iterate, so an `ArrayList` is populated as the result. | |
| 3724 | pub fn findDecls(zir: Zir, gpa: Allocator, list: *std.ArrayListUnmanaged(Inst.Index), decl_inst: Zir.Inst.Index) !void { | |
| 3725 | list.clearRetainingCapacity(); | |
| 3721 | /// `DeclContents` contains all "interesting" instructions found within a declaration by `findTrackable`. | |
| 3722 | /// These instructions are partitioned into a few different sets, since this makes ZIR instruction mapping | |
| 3723 | /// more effective. | |
| 3724 | pub const DeclContents = struct { | |
| 3725 | /// This is a simple optional because ZIR guarantees that a `func`/`func_inferred`/`func_fancy` instruction | |
| 3726 | /// can only occur once per `declaration`. | |
| 3727 | func_decl: ?Inst.Index, | |
| 3728 | explicit_types: std.ArrayListUnmanaged(Inst.Index), | |
| 3729 | other: std.ArrayListUnmanaged(Inst.Index), | |
| 3730 | ||
| 3731 | pub const init: DeclContents = .{ | |
| 3732 | .func_decl = null, | |
| 3733 | .explicit_types = .empty, | |
| 3734 | .other = .empty, | |
| 3735 | }; | |
| 3736 | ||
| 3737 | pub fn clear(contents: *DeclContents) void { | |
| 3738 | contents.func_decl = null; | |
| 3739 | contents.explicit_types.clearRetainingCapacity(); | |
| 3740 | contents.other.clearRetainingCapacity(); | |
| 3741 | } | |
| 3742 | ||
| 3743 | pub fn deinit(contents: *DeclContents, gpa: Allocator) void { | |
| 3744 | contents.explicit_types.deinit(gpa); | |
| 3745 | contents.other.deinit(gpa); | |
| 3746 | } | |
| 3747 | }; | |
| 3748 | ||
| 3749 | /// Find all tracked ZIR instructions, recursively, within a `declaration` instruction. Does not recurse through | |
| 3750 | /// nested declarations; to find all declarations, call this function recursively on the type declarations discovered | |
| 3751 | /// in `contents.explicit_types`. | |
| 3752 | /// | |
| 3753 | /// This populates an `ArrayListUnmanaged` because an iterator would need to allocate memory anyway. | |
| 3754 | pub fn findTrackable(zir: Zir, gpa: Allocator, contents: *DeclContents, decl_inst: Zir.Inst.Index) !void { | |
| 3755 | contents.clear(); | |
| 3756 | ||
| 3726 | 3757 | const declaration, const extra_end = zir.getDeclaration(decl_inst); |
| 3727 | 3758 | const bodies = declaration.getBodies(extra_end, zir); |
| 3728 | 3759 | |
| ... | ... | @@ -3731,27 +3762,27 @@ pub fn findDecls(zir: Zir, gpa: Allocator, list: *std.ArrayListUnmanaged(Inst.In |
| 3731 | 3762 | var found_defers: std.AutoHashMapUnmanaged(u32, void) = .empty; |
| 3732 | 3763 | defer found_defers.deinit(gpa); |
| 3733 | 3764 | |
| 3734 | try zir.findDeclsBody(gpa, list, &found_defers, bodies.value_body); | |
| 3735 | if (bodies.align_body) |b| try zir.findDeclsBody(gpa, list, &found_defers, b); | |
| 3736 | if (bodies.linksection_body) |b| try zir.findDeclsBody(gpa, list, &found_defers, b); | |
| 3737 | if (bodies.addrspace_body) |b| try zir.findDeclsBody(gpa, list, &found_defers, b); | |
| 3765 | try zir.findTrackableBody(gpa, contents, &found_defers, bodies.value_body); | |
| 3766 | if (bodies.align_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b); | |
| 3767 | if (bodies.linksection_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b); | |
| 3768 | if (bodies.addrspace_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b); | |
| 3738 | 3769 | } |
| 3739 | 3770 | |
| 3740 | /// Like `findDecls`, but only considers the `main_struct_inst` instruction. This may return more than | |
| 3771 | /// Like `findTrackable`, but only considers the `main_struct_inst` instruction. This may return more than | |
| 3741 | 3772 | /// just that instruction because it will also traverse fields. |
| 3742 | pub fn findDeclsRoot(zir: Zir, gpa: Allocator, list: *std.ArrayListUnmanaged(Inst.Index)) !void { | |
| 3743 | list.clearRetainingCapacity(); | |
| 3773 | pub fn findTrackableRoot(zir: Zir, gpa: Allocator, contents: *DeclContents) !void { | |
| 3774 | contents.clear(); | |
| 3744 | 3775 | |
| 3745 | 3776 | var found_defers: std.AutoHashMapUnmanaged(u32, void) = .empty; |
| 3746 | 3777 | defer found_defers.deinit(gpa); |
| 3747 | 3778 | |
| 3748 | try zir.findDeclsInner(gpa, list, &found_defers, .main_struct_inst); | |
| 3779 | try zir.findTrackableInner(gpa, contents, &found_defers, .main_struct_inst); | |
| 3749 | 3780 | } |
| 3750 | 3781 | |
| 3751 | fn findDeclsInner( | |
| 3782 | fn findTrackableInner( | |
| 3752 | 3783 | zir: Zir, |
| 3753 | 3784 | gpa: Allocator, |
| 3754 | list: *std.ArrayListUnmanaged(Inst.Index), | |
| 3785 | contents: *DeclContents, | |
| 3755 | 3786 | defers: *std.AutoHashMapUnmanaged(u32, void), |
| 3756 | 3787 | inst: Inst.Index, |
| 3757 | 3788 | ) Allocator.Error!void { |
| ... | ... | @@ -3995,7 +4026,7 @@ fn findDeclsInner( |
| 3995 | 4026 | .struct_init, |
| 3996 | 4027 | .struct_init_ref, |
| 3997 | 4028 | .struct_init_anon, |
| 3998 | => return list.append(gpa, inst), | |
| 4029 | => return contents.other.append(gpa, inst), | |
| 3999 | 4030 | |
| 4000 | 4031 | .extended => { |
| 4001 | 4032 | const extended = datas[@intFromEnum(inst)].extended; |
| ... | ... | @@ -4055,21 +4086,22 @@ fn findDeclsInner( |
| 4055 | 4086 | .inplace_arith_result_ty, |
| 4056 | 4087 | .tuple_decl, |
| 4057 | 4088 | .dbg_empty_stmt, |
| 4089 | .astgen_error, | |
| 4058 | 4090 | => return, |
| 4059 | 4091 | |
| 4060 | 4092 | // `@TypeOf` has a body. |
| 4061 | 4093 | .typeof_peer => { |
| 4062 | 4094 | const extra = zir.extraData(Zir.Inst.TypeOfPeer, extended.operand); |
| 4063 | 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 | }, |
| 4066 | 4098 | |
| 4067 | 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), | |
| 4069 | 4101 | |
| 4070 | 4102 | // Struct declarations need tracking and have bodies. |
| 4071 | 4103 | .struct_decl => { |
| 4072 | try list.append(gpa, inst); | |
| 4104 | try contents.explicit_types.append(gpa, inst); | |
| 4073 | 4105 | |
| 4074 | 4106 | const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small); |
| 4075 | 4107 | const extra = zir.extraData(Zir.Inst.StructDecl, extended.operand); |
| ... | ... | @@ -4098,7 +4130,7 @@ fn findDeclsInner( |
| 4098 | 4130 | } else { |
| 4099 | 4131 | const body = zir.bodySlice(extra_index, backing_int_body_len); |
| 4100 | 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 | 4136 | extra_index += decls_len; |
| ... | ... | @@ -4154,12 +4186,12 @@ fn findDeclsInner( |
| 4154 | 4186 | |
| 4155 | 4187 | // Now, `fields_extra_index` points to `bodies`. Let's treat this as one big body. |
| 4156 | 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 | }, |
| 4159 | 4191 | |
| 4160 | 4192 | // Union declarations need tracking and have a body. |
| 4161 | 4193 | .union_decl => { |
| 4162 | try list.append(gpa, inst); | |
| 4194 | try contents.explicit_types.append(gpa, inst); | |
| 4163 | 4195 | |
| 4164 | 4196 | const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small); |
| 4165 | 4197 | const extra = zir.extraData(Zir.Inst.UnionDecl, extended.operand); |
| ... | ... | @@ -4184,12 +4216,12 @@ fn findDeclsInner( |
| 4184 | 4216 | extra_index += captures_len; |
| 4185 | 4217 | extra_index += decls_len; |
| 4186 | 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 | }, |
| 4189 | 4221 | |
| 4190 | 4222 | // Enum declarations need tracking and have a body. |
| 4191 | 4223 | .enum_decl => { |
| 4192 | try list.append(gpa, inst); | |
| 4224 | try contents.explicit_types.append(gpa, inst); | |
| 4193 | 4225 | |
| 4194 | 4226 | const small: Zir.Inst.EnumDecl.Small = @bitCast(extended.small); |
| 4195 | 4227 | const extra = zir.extraData(Zir.Inst.EnumDecl, extended.operand); |
| ... | ... | @@ -4214,7 +4246,7 @@ fn findDeclsInner( |
| 4214 | 4246 | extra_index += captures_len; |
| 4215 | 4247 | extra_index += decls_len; |
| 4216 | 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 | 4255 | .func, |
| 4224 | 4256 | .func_inferred, |
| 4225 | 4257 | => { |
| 4226 | try list.append(gpa, inst); | |
| 4258 | assert(contents.func_decl == null); | |
| 4259 | contents.func_decl = inst; | |
| 4227 | 4260 | |
| 4228 | 4261 | const inst_data = datas[@intFromEnum(inst)].pl_node; |
| 4229 | 4262 | const extra = zir.extraData(Inst.Func, inst_data.payload_index); |
| ... | ... | @@ -4234,14 +4267,15 @@ fn findDeclsInner( |
| 4234 | 4267 | else => { |
| 4235 | 4268 | const body = zir.bodySlice(extra_index, extra.data.ret_body_len); |
| 4236 | 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 | 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 | 4276 | .func_fancy => { |
| 4244 | try list.append(gpa, inst); | |
| 4277 | assert(contents.func_decl == null); | |
| 4278 | contents.func_decl = inst; | |
| 4245 | 4279 | |
| 4246 | 4280 | const inst_data = datas[@intFromEnum(inst)].pl_node; |
| 4247 | 4281 | const extra = zir.extraData(Inst.FuncFancy, inst_data.payload_index); |
| ... | ... | @@ -4252,7 +4286,7 @@ fn findDeclsInner( |
| 4252 | 4286 | const body_len = zir.extra[extra_index]; |
| 4253 | 4287 | extra_index += 1; |
| 4254 | 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 | 4290 | extra_index += body.len; |
| 4257 | 4291 | } else if (extra.data.bits.has_align_ref) { |
| 4258 | 4292 | extra_index += 1; |
| ... | ... | @@ -4262,7 +4296,7 @@ fn findDeclsInner( |
| 4262 | 4296 | const body_len = zir.extra[extra_index]; |
| 4263 | 4297 | extra_index += 1; |
| 4264 | 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 | 4300 | extra_index += body.len; |
| 4267 | 4301 | } else if (extra.data.bits.has_addrspace_ref) { |
| 4268 | 4302 | extra_index += 1; |
| ... | ... | @@ -4272,7 +4306,7 @@ fn findDeclsInner( |
| 4272 | 4306 | const body_len = zir.extra[extra_index]; |
| 4273 | 4307 | extra_index += 1; |
| 4274 | 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 | 4310 | extra_index += body.len; |
| 4277 | 4311 | } else if (extra.data.bits.has_section_ref) { |
| 4278 | 4312 | extra_index += 1; |
| ... | ... | @@ -4282,7 +4316,7 @@ fn findDeclsInner( |
| 4282 | 4316 | const body_len = zir.extra[extra_index]; |
| 4283 | 4317 | extra_index += 1; |
| 4284 | 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 | 4320 | extra_index += body.len; |
| 4287 | 4321 | } else if (extra.data.bits.has_cc_ref) { |
| 4288 | 4322 | extra_index += 1; |
| ... | ... | @@ -4292,7 +4326,7 @@ fn findDeclsInner( |
| 4292 | 4326 | const body_len = zir.extra[extra_index]; |
| 4293 | 4327 | extra_index += 1; |
| 4294 | 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 | 4330 | extra_index += body.len; |
| 4297 | 4331 | } else if (extra.data.bits.has_ret_ty_ref) { |
| 4298 | 4332 | extra_index += 1; |
| ... | ... | @@ -4301,7 +4335,7 @@ fn findDeclsInner( |
| 4301 | 4335 | extra_index += @intFromBool(extra.data.bits.has_any_noalias); |
| 4302 | 4336 | |
| 4303 | 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 | }, |
| 4306 | 4340 | |
| 4307 | 4341 | // Block instructions, recurse over the bodies. |
| ... | ... | @@ -4316,24 +4350,24 @@ fn findDeclsInner( |
| 4316 | 4350 | const inst_data = datas[@intFromEnum(inst)].pl_node; |
| 4317 | 4351 | const extra = zir.extraData(Inst.Block, inst_data.payload_index); |
| 4318 | 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 | 4355 | .condbr, .condbr_inline => { |
| 4322 | 4356 | const inst_data = datas[@intFromEnum(inst)].pl_node; |
| 4323 | 4357 | const extra = zir.extraData(Inst.CondBr, inst_data.payload_index); |
| 4324 | 4358 | const then_body = zir.bodySlice(extra.end, extra.data.then_body_len); |
| 4325 | 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); | |
| 4327 | try zir.findDeclsBody(gpa, list, defers, else_body); | |
| 4360 | try zir.findTrackableBody(gpa, contents, defers, then_body); | |
| 4361 | try zir.findTrackableBody(gpa, contents, defers, else_body); | |
| 4328 | 4362 | }, |
| 4329 | 4363 | .@"try", .try_ptr => { |
| 4330 | 4364 | const inst_data = datas[@intFromEnum(inst)].pl_node; |
| 4331 | 4365 | const extra = zir.extraData(Inst.Try, inst_data.payload_index); |
| 4332 | 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), | |
| 4336 | .switch_block_err_union => return zir.findDeclsSwitch(gpa, list, defers, inst, .err_union), | |
| 4369 | .switch_block, .switch_block_ref => return zir.findTrackableSwitch(gpa, contents, defers, inst, .normal), | |
| 4370 | .switch_block_err_union => return zir.findTrackableSwitch(gpa, contents, defers, inst, .err_union), | |
| 4337 | 4371 | |
| 4338 | 4372 | .suspend_block => @panic("TODO iterate suspend block"), |
| 4339 | 4373 | |
| ... | ... | @@ -4341,7 +4375,7 @@ fn findDeclsInner( |
| 4341 | 4375 | const inst_data = datas[@intFromEnum(inst)].pl_tok; |
| 4342 | 4376 | const extra = zir.extraData(Inst.Param, inst_data.payload_index); |
| 4343 | 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 | }, |
| 4346 | 4380 | |
| 4347 | 4381 | inline .call, .field_call => |tag| { |
| ... | ... | @@ -4357,7 +4391,7 @@ fn findDeclsInner( |
| 4357 | 4391 | const first_arg_start_off = args_len; |
| 4358 | 4392 | const final_arg_end_off = zir.extra[extra.end + args_len - 1]; |
| 4359 | 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 | 4397 | .@"defer" => { |
| ... | ... | @@ -4365,7 +4399,7 @@ fn findDeclsInner( |
| 4365 | 4399 | const gop = try defers.getOrPut(gpa, inst_data.index); |
| 4366 | 4400 | if (!gop.found_existing) { |
| 4367 | 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 | 4405 | .defer_err_code => { |
| ... | ... | @@ -4374,16 +4408,16 @@ fn findDeclsInner( |
| 4374 | 4408 | const gop = try defers.getOrPut(gpa, extra.index); |
| 4375 | 4409 | if (!gop.found_existing) { |
| 4376 | 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 | } |
| 4382 | 4416 | |
| 4383 | fn findDeclsSwitch( | |
| 4417 | fn findTrackableSwitch( | |
| 4384 | 4418 | zir: Zir, |
| 4385 | 4419 | gpa: Allocator, |
| 4386 | list: *std.ArrayListUnmanaged(Inst.Index), | |
| 4420 | contents: *DeclContents, | |
| 4387 | 4421 | defers: *std.AutoHashMapUnmanaged(u32, void), |
| 4388 | 4422 | inst: Inst.Index, |
| 4389 | 4423 | /// Distinguishes between `switch_block[_ref]` and `switch_block_err_union`. |
| ... | ... | @@ -4419,7 +4453,7 @@ fn findDeclsSwitch( |
| 4419 | 4453 | const body = zir.bodySlice(extra_index, prong_info.body_len); |
| 4420 | 4454 | extra_index += body.len; |
| 4421 | 4455 | |
| 4422 | try zir.findDeclsBody(gpa, list, defers, body); | |
| 4456 | try zir.findTrackableBody(gpa, contents, defers, body); | |
| 4423 | 4457 | |
| 4424 | 4458 | break :has_special extra.data.bits.has_else; |
| 4425 | 4459 | }, |
| ... | ... | @@ -4431,7 +4465,7 @@ fn findDeclsSwitch( |
| 4431 | 4465 | const body = zir.bodySlice(extra_index, prong_info.body_len); |
| 4432 | 4466 | extra_index += body.len; |
| 4433 | 4467 | |
| 4434 | try zir.findDeclsBody(gpa, list, defers, body); | |
| 4468 | try zir.findTrackableBody(gpa, contents, defers, body); | |
| 4435 | 4469 | } |
| 4436 | 4470 | |
| 4437 | 4471 | { |
| ... | ... | @@ -4443,7 +4477,7 @@ fn findDeclsSwitch( |
| 4443 | 4477 | const body = zir.bodySlice(extra_index, prong_info.body_len); |
| 4444 | 4478 | extra_index += body.len; |
| 4445 | 4479 | |
| 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 | 4494 | const body = zir.bodySlice(extra_index, prong_info.body_len); |
| 4461 | 4495 | extra_index += body.len; |
| 4462 | 4496 | |
| 4463 | try zir.findDeclsBody(gpa, list, defers, body); | |
| 4497 | try zir.findTrackableBody(gpa, contents, defers, body); | |
| 4464 | 4498 | } |
| 4465 | 4499 | } |
| 4466 | 4500 | } |
| 4467 | 4501 | |
| 4468 | fn findDeclsBody( | |
| 4502 | fn findTrackableBody( | |
| 4469 | 4503 | zir: Zir, |
| 4470 | 4504 | gpa: Allocator, |
| 4471 | list: *std.ArrayListUnmanaged(Inst.Index), | |
| 4505 | contents: *DeclContents, | |
| 4472 | 4506 | defers: *std.AutoHashMapUnmanaged(u32, void), |
| 4473 | 4507 | body: []const Inst.Index, |
| 4474 | 4508 | ) Allocator.Error!void { |
| 4475 | 4509 | for (body) |member| { |
| 4476 | try zir.findDeclsInner(gpa, list, defers, member); | |
| 4510 | try zir.findTrackableInner(gpa, contents, defers, member); | |
| 4477 | 4511 | } |
| 4478 | 4512 | } |
| 4479 | 4513 |
src/Compilation.zig+21-9| ... | ... | @@ -3223,17 +3223,29 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { |
| 3223 | 3223 | } |
| 3224 | 3224 | } |
| 3225 | 3225 | |
| 3226 | if (comp.zcu) |zcu| { | |
| 3227 | if (comp.incremental and bundle.root_list.items.len == 0) { | |
| 3228 | const should_have_error = for (zcu.transitive_failed_analysis.keys()) |failed_unit| { | |
| 3229 | const refs = try zcu.resolveReferences(); | |
| 3230 | if (refs.contains(failed_unit)) break true; | |
| 3231 | } else false; | |
| 3232 | if (should_have_error) { | |
| 3233 | @panic("referenced transitive analysis errors, but none actually emitted"); | |
| 3226 | // TODO: eventually, this should be behind `std.debug.runtime_safety`. But right now, this is a | |
| 3227 | // very common way for incremental compilation bugs to manifest, so let's always check it. | |
| 3228 | if (comp.zcu) |zcu| if (comp.incremental and bundle.root_list.items.len == 0) { | |
| 3229 | for (zcu.transitive_failed_analysis.keys()) |failed_unit| { | |
| 3230 | const refs = try zcu.resolveReferences(); | |
| 3231 | var ref = refs.get(failed_unit) orelse continue; | |
| 3232 | // This AU is referenced and has a transitive compile error, meaning it referenced something with a compile error. | |
| 3233 | // However, we haven't reported any such error. | |
| 3234 | // This is a compiler bug. | |
| 3235 | const stderr = std.io.getStdErr().writer(); | |
| 3236 | try stderr.writeAll("referenced transitive analysis errors, but none actually emitted\n"); | |
| 3237 | try stderr.print("{} [transitive failure]\n", .{zcu.fmtAnalUnit(failed_unit)}); | |
| 3238 | while (ref) |r| { | |
| 3239 | try stderr.print("referenced by: {}{s}\n", .{ | |
| 3240 | zcu.fmtAnalUnit(r.referencer), | |
| 3241 | if (zcu.transitive_failed_analysis.contains(r.referencer)) " [transitive failure]" else "", | |
| 3242 | }); | |
| 3243 | ref = refs.get(r.referencer).?; | |
| 3234 | 3244 | } |
| 3245 | ||
| 3246 | @panic("referenced transitive analysis errors, but none actually emitted"); | |
| 3235 | 3247 | } |
| 3236 | } | |
| 3248 | }; | |
| 3237 | 3249 | |
| 3238 | 3250 | const compile_log_text = if (comp.zcu) |m| m.compile_log_text.items else ""; |
| 3239 | 3251 | return bundle.toOwnedBundle(compile_log_text); |
src/InternPool.zig+20| ... | ... | @@ -8616,6 +8616,16 @@ pub fn getFuncDecl( |
| 8616 | 8616 | defer gop.deinit(); |
| 8617 | 8617 | if (gop == .existing) { |
| 8618 | 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 | 8629 | return gop.existing; |
| 8620 | 8630 | } |
| 8621 | 8631 | |
| ... | ... | @@ -8762,6 +8772,16 @@ pub fn getFuncDeclIes( |
| 8762 | 8772 | // An existing function type was found; undo the additions to our two arrays. |
| 8763 | 8773 | items.mutate.len -= 4; |
| 8764 | 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 | 8785 | return func_gop.existing; |
| 8766 | 8786 | } |
| 8767 | 8787 | func_gop.putTentative(func_index); |
src/Sema.zig+1| ... | ... | @@ -1361,6 +1361,7 @@ fn analyzeBodyInner( |
| 1361 | 1361 | i += 1; |
| 1362 | 1362 | continue; |
| 1363 | 1363 | }, |
| 1364 | .astgen_error => return error.AnalysisFail, | |
| 1364 | 1365 | }; |
| 1365 | 1366 | }, |
| 1366 | 1367 |
src/Zcu.zig+61-21| ... | ... | @@ -2593,26 +2593,44 @@ pub fn mapOldZirToNew( |
| 2593 | 2593 | defer match_stack.deinit(gpa); |
| 2594 | 2594 | |
| 2595 | 2595 | // Used as temporary buffers for namespace declaration instructions |
| 2596 | var old_decls: std.ArrayListUnmanaged(Zir.Inst.Index) = .empty; | |
| 2597 | defer old_decls.deinit(gpa); | |
| 2598 | var new_decls: std.ArrayListUnmanaged(Zir.Inst.Index) = .empty; | |
| 2599 | defer new_decls.deinit(gpa); | |
| 2596 | var old_contents: Zir.DeclContents = .init; | |
| 2597 | defer old_contents.deinit(gpa); | |
| 2598 | var new_contents: Zir.DeclContents = .init; | |
| 2599 | defer new_contents.deinit(gpa); | |
| 2600 | 2600 | |
| 2601 | 2601 | // Map the main struct inst (and anything in its fields) |
| 2602 | 2602 | { |
| 2603 | try old_zir.findDeclsRoot(gpa, &old_decls); | |
| 2604 | try new_zir.findDeclsRoot(gpa, &new_decls); | |
| 2603 | try old_zir.findTrackableRoot(gpa, &old_contents); | |
| 2604 | try new_zir.findTrackableRoot(gpa, &new_contents); | |
| 2605 | 2605 | |
| 2606 | assert(old_decls.items[0] == .main_struct_inst); | |
| 2607 | assert(new_decls.items[0] == .main_struct_inst); | |
| 2606 | assert(old_contents.explicit_types.items[0] == .main_struct_inst); | |
| 2607 | assert(new_contents.explicit_types.items[0] == .main_struct_inst); | |
| 2608 | 2608 | |
| 2609 | // We don't have any smart way of matching up these type declarations, so we always | |
| 2610 | // correlate them based on source order. | |
| 2611 | const n = @min(old_decls.items.len, new_decls.items.len); | |
| 2612 | try match_stack.ensureUnusedCapacity(gpa, n); | |
| 2613 | for (old_decls.items[0..n], new_decls.items[0..n]) |old_inst, new_inst| { | |
| 2609 | assert(old_contents.func_decl == null); | |
| 2610 | assert(new_contents.func_decl == null); | |
| 2611 | ||
| 2612 | // We don't have any smart way of matching up these instructions, so we correlate them based on source order | |
| 2613 | // in their respective arrays. | |
| 2614 | ||
| 2615 | const num_explicit_types = @min(old_contents.explicit_types.items.len, new_contents.explicit_types.items.len); | |
| 2616 | try match_stack.ensureUnusedCapacity(gpa, @intCast(num_explicit_types)); | |
| 2617 | for ( | |
| 2618 | old_contents.explicit_types.items[0..num_explicit_types], | |
| 2619 | new_contents.explicit_types.items[0..num_explicit_types], | |
| 2620 | ) |old_inst, new_inst| { | |
| 2621 | // Here we use `match_stack`, so that we will recursively consider declarations on these types. | |
| 2614 | 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 | } |
| 2617 | 2635 | |
| 2618 | 2636 | while (match_stack.popOrNull()) |match_item| { |
| ... | ... | @@ -2700,17 +2718,39 @@ pub fn mapOldZirToNew( |
| 2700 | 2718 | // Match the `declaration` instruction |
| 2701 | 2719 | try inst_map.put(gpa, old_decl_inst, new_decl_inst); |
| 2702 | 2720 | |
| 2703 | // Find container type declarations within this declaration | |
| 2704 | try old_zir.findDecls(gpa, &old_decls, old_decl_inst); | |
| 2705 | try new_zir.findDecls(gpa, &new_decls, new_decl_inst); | |
| 2721 | // Find trackable instructions within this declaration | |
| 2722 | try old_zir.findTrackable(gpa, &old_contents, old_decl_inst); | |
| 2723 | try new_zir.findTrackable(gpa, &new_contents, new_decl_inst); | |
| 2724 | ||
| 2725 | // We don't have any smart way of matching up these instructions, so we correlate them based on source order | |
| 2726 | // in their respective arrays. | |
| 2706 | 2727 | |
| 2707 | // We don't have any smart way of matching up these type declarations, so we always | |
| 2708 | // correlate them based on source order. | |
| 2709 | const n = @min(old_decls.items.len, new_decls.items.len); | |
| 2710 | try match_stack.ensureUnusedCapacity(gpa, n); | |
| 2711 | for (old_decls.items[0..n], new_decls.items[0..n]) |old_inst, new_inst| { | |
| 2728 | const num_explicit_types = @min(old_contents.explicit_types.items.len, new_contents.explicit_types.items.len); | |
| 2729 | try match_stack.ensureUnusedCapacity(gpa, @intCast(num_explicit_types)); | |
| 2730 | for ( | |
| 2731 | old_contents.explicit_types.items[0..num_explicit_types], | |
| 2732 | new_contents.explicit_types.items[0..num_explicit_types], | |
| 2733 | ) |old_inst, new_inst| { | |
| 2734 | // Here we use `match_stack`, so that we will recursively consider declarations on these types. | |
| 2712 | 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 | 185 | log.debug("AstGen cached success: {s}", .{file.sub_file_path}); |
| 186 | 186 | |
| 187 | 187 | if (file.zir.hasCompileErrors()) { |
| 188 | { | |
| 189 | comp.mutex.lock(); | |
| 190 | defer comp.mutex.unlock(); | |
| 191 | try zcu.failed_files.putNoClobber(gpa, file, null); | |
| 192 | } | |
| 188 | comp.mutex.lock(); | |
| 189 | defer comp.mutex.unlock(); | |
| 190 | try zcu.failed_files.putNoClobber(gpa, file, null); | |
| 191 | } | |
| 192 | if (file.zir.loweringFailed()) { | |
| 193 | 193 | file.status = .astgen_failure; |
| 194 | 194 | return error.AnalysisFail; |
| 195 | 195 | } |
| ... | ... | @@ -226,7 +226,7 @@ pub fn astGenFile( |
| 226 | 226 | // single-threaded context, so we need to keep both versions around |
| 227 | 227 | // until that point in the pipeline. Previous ZIR data is freed after |
| 228 | 228 | // that. |
| 229 | if (file.zir_loaded and !file.zir.hasCompileErrors()) { | |
| 229 | if (file.zir_loaded and !file.zir.loweringFailed()) { | |
| 230 | 230 | assert(file.prev_zir == null); |
| 231 | 231 | const prev_zir_ptr = try gpa.create(Zir); |
| 232 | 232 | file.prev_zir = prev_zir_ptr; |
| ... | ... | @@ -321,11 +321,11 @@ pub fn astGenFile( |
| 321 | 321 | }; |
| 322 | 322 | |
| 323 | 323 | if (file.zir.hasCompileErrors()) { |
| 324 | { | |
| 325 | comp.mutex.lock(); | |
| 326 | defer comp.mutex.unlock(); | |
| 327 | try zcu.failed_files.putNoClobber(gpa, file, null); | |
| 328 | } | |
| 324 | comp.mutex.lock(); | |
| 325 | defer comp.mutex.unlock(); | |
| 326 | try zcu.failed_files.putNoClobber(gpa, file, null); | |
| 327 | } | |
| 328 | if (file.zir.loweringFailed()) { | |
| 329 | 329 | file.status = .astgen_failure; |
| 330 | 330 | return error.AnalysisFail; |
| 331 | 331 | } |
| ... | ... | @@ -363,7 +363,7 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void { |
| 363 | 363 | .file = file, |
| 364 | 364 | .inst_map = .{}, |
| 365 | 365 | }; |
| 366 | if (!new_zir.hasCompileErrors()) { | |
| 366 | if (!new_zir.loweringFailed()) { | |
| 367 | 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 | 379 | |
| 380 | 380 | const file = updated_file.file; |
| 381 | 381 | |
| 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 | 382 | const old_inst = tracked_inst.inst.unwrap() orelse continue; // we can't continue tracking lost insts |
| 389 | 383 | const tracked_inst_index = (InternPool.TrackedInst.Index.Unwrapped{ |
| 390 | 384 | .tid = @enumFromInt(tid), |
| 391 | 385 | .index = @intCast(tracked_inst_unwrapped_index), |
| 392 | 386 | }).wrap(ip); |
| 393 | 387 | const new_inst = updated_file.inst_map.get(old_inst) orelse { |
| 394 | // Tracking failed for this instruction. Invalidate associated `src_hash` deps. | |
| 395 | log.debug("tracking failed for %{d}", .{old_inst}); | |
| 388 | // Tracking failed for this instruction. | |
| 389 | // This may be due to changes in the ZIR, or AstGen might have failed due to a very broken file. | |
| 390 | // Either way, invalidate associated `src_hash` deps. | |
| 391 | log.debug("tracking failed for %{d}{s}", .{ | |
| 392 | old_inst, | |
| 393 | if (file.zir.loweringFailed()) " due to AstGen failure" else "", | |
| 394 | }); | |
| 396 | 395 | tracked_inst.inst = .lost; |
| 397 | 396 | try zcu.markDependeeOutdated(.not_marked_po, .{ .src_hash = tracked_inst_index }); |
| 398 | 397 | continue; |
| ... | ... | @@ -494,8 +493,8 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void { |
| 494 | 493 | |
| 495 | 494 | for (updated_files.keys(), updated_files.values()) |file_index, updated_file| { |
| 496 | 495 | const file = updated_file.file; |
| 497 | if (file.zir.hasCompileErrors()) { | |
| 498 | // Keep `prev_zir` around: it's the last non-error ZIR. | |
| 496 | if (file.zir.loweringFailed()) { | |
| 497 | // Keep `prev_zir` around: it's the last usable ZIR. | |
| 499 | 498 | // Don't update the namespace, as we have no new data to update *to*. |
| 500 | 499 | } else { |
| 501 | 500 | const prev_zir = file.prev_zir.?; |
| ... | ... | @@ -539,7 +538,7 @@ pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu |
| 539 | 538 | const anal_unit = AnalUnit.wrap(.{ .cau = cau_index }); |
| 540 | 539 | const cau = ip.getCau(cau_index); |
| 541 | 540 | |
| 542 | log.debug("ensureCauAnalyzed {d}", .{@intFromEnum(cau_index)}); | |
| 541 | log.debug("ensureCauAnalyzed {}", .{zcu.fmtAnalUnit(anal_unit)}); | |
| 543 | 542 | |
| 544 | 543 | assert(!zcu.analysis_in_progress.contains(anal_unit)); |
| 545 | 544 | |
| ... | ... | @@ -577,13 +576,19 @@ pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu |
| 577 | 576 | } |
| 578 | 577 | |
| 579 | 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 | 585 | else |err| switch (err) { |
| 582 | 586 | error.AnalysisFail => res: { |
| 583 | 587 | if (!zcu.failed_analysis.contains(anal_unit)) { |
| 584 | 588 | // If this `Cau` caused the error, it would have an entry in `failed_analysis`. |
| 585 | 589 | // Since it does not, this must be a transitive failure. |
| 586 | 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 | 593 | // We consider this `Cau` to be outdated if: |
| 589 | 594 | // * 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 | 713 | |
| 709 | 714 | // We only care about the uncoerced function. |
| 710 | 715 | const func_index = ip.unwrapCoercedFunc(maybe_coerced_func_index); |
| 716 | const anal_unit = AnalUnit.wrap(.{ .func = func_index }); | |
| 711 | 717 | |
| 712 | const func = zcu.funcInfo(maybe_coerced_func_index); | |
| 718 | log.debug("ensureFuncBodyAnalyzed {}", .{zcu.fmtAnalUnit(anal_unit)}); | |
| 713 | 719 | |
| 714 | log.debug("ensureFuncBodyAnalyzed {d}", .{@intFromEnum(func_index)}); | |
| 720 | const func = zcu.funcInfo(maybe_coerced_func_index); | |
| 715 | 721 | |
| 716 | const anal_unit = AnalUnit.wrap(.{ .func = func_index }); | |
| 717 | 722 | const func_outdated = zcu.outdated.swapRemove(anal_unit) or |
| 718 | 723 | zcu.potentially_outdated.swapRemove(anal_unit); |
| 719 | 724 | |
| ... | ... | @@ -741,6 +746,7 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter |
| 741 | 746 | // If this function caused the error, it would have an entry in `failed_analysis`. |
| 742 | 747 | // Since it does not, this must be a transitive failure. |
| 743 | 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 | 751 | // We consider the IES to be outdated if the function previously succeeded analysis; in this case, |
| 746 | 752 | // 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 | 758 | |
| 753 | 759 | if (func_outdated) { |
| 754 | 760 | if (ies_outdated) { |
| 755 | log.debug("func IES invalidated ('{d}')", .{@intFromEnum(func_index)}); | |
| 756 | 761 | try zcu.markDependeeOutdated(.marked_po, .{ .interned = func_index }); |
| 757 | 762 | } else { |
| 758 | log.debug("func IES up-to-date ('{d}')", .{@intFromEnum(func_index)}); | |
| 759 | 763 | try zcu.markPoDependeeUpToDate(.{ .interned = func_index }); |
| 760 | 764 | } |
| 761 | 765 | } |
| ... | ... | @@ -780,6 +784,7 @@ fn ensureFuncBodyAnalyzedInner( |
| 780 | 784 | // results in the worst case. |
| 781 | 785 | |
| 782 | 786 | if (func.generic_owner == .none) { |
| 787 | // Among another things, this ensures that the function's `zir_body_inst` is correct. | |
| 783 | 788 | try pt.ensureCauAnalyzed(ip.getNav(func.owner_nav).analysis_owner.unwrap().?); |
| 784 | 789 | if (ip.getNav(func.owner_nav).status.resolved.val != func_index) { |
| 785 | 790 | // This function is no longer referenced! There's no point in re-analyzing it. |
| ... | ... | @@ -788,6 +793,7 @@ fn ensureFuncBodyAnalyzedInner( |
| 788 | 793 | } |
| 789 | 794 | } else { |
| 790 | 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 | 797 | try pt.ensureCauAnalyzed(ip.getNav(go_nav).analysis_owner.unwrap().?); |
| 792 | 798 | if (ip.getNav(go_nav).status.resolved.val != func.generic_owner) { |
| 793 | 799 | // The generic owner is no longer referenced, so this function is also unreferenced. |
| ... | ... | @@ -825,8 +831,8 @@ fn ensureFuncBodyAnalyzedInner( |
| 825 | 831 | } |
| 826 | 832 | } |
| 827 | 833 | |
| 828 | log.debug("analyze and generate fn body '{d}'; reason='{s}'", .{ | |
| 829 | @intFromEnum(func_index), | |
| 834 | log.debug("analyze and generate fn body {}; reason='{s}'", .{ | |
| 835 | zcu.fmtAnalUnit(anal_unit), | |
| 830 | 836 | if (func_outdated) "outdated" else "never analyzed", |
| 831 | 837 | }); |
| 832 | 838 | |
| ... | ... | @@ -1165,7 +1171,7 @@ fn semaCau(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) !SemaCauResult { |
| 1165 | 1171 | .none, .type => false, |
| 1166 | 1172 | }; |
| 1167 | 1173 | |
| 1168 | log.debug("semaCau '{d}'", .{@intFromEnum(cau_index)}); | |
| 1174 | log.debug("semaCau {}", .{zcu.fmtAnalUnit(anal_unit)}); | |
| 1169 | 1175 | |
| 1170 | 1176 | try zcu.analysis_in_progress.put(gpa, anal_unit, {}); |
| 1171 | 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 | 2314 | return pt.getErrorValue(try pt.zcu.intern_pool.getOrPutString(pt.zcu.gpa, name)); |
| 2309 | 2315 | } |
| 2310 | 2316 | |
| 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. | |
| 2311 | 2319 | fn lockAndClearFileCompileError(pt: Zcu.PerThread, file: *Zcu.File) void { |
| 2312 | switch (file.status) { | |
| 2313 | .success_zir, .retryable_failure => {}, | |
| 2314 | .never_loaded, .parse_failure, .astgen_failure => { | |
| 2315 | pt.zcu.comp.mutex.lock(); | |
| 2316 | defer pt.zcu.comp.mutex.unlock(); | |
| 2317 | if (pt.zcu.failed_files.fetchSwapRemove(file)) |kv| { | |
| 2318 | if (kv.value) |msg| msg.destroy(pt.zcu.gpa); // Delete previous error message. | |
| 2319 | } | |
| 2320 | }, | |
| 2320 | if (!file.zir_loaded or !file.zir.hasCompileErrors()) return; | |
| 2321 | pt.zcu.comp.mutex.lock(); | |
| 2322 | defer pt.zcu.comp.mutex.unlock(); | |
| 2323 | if (pt.zcu.failed_files.fetchSwapRemove(file)) |kv| { | |
| 2324 | if (kv.value) |msg| msg.destroy(pt.zcu.gpa); // Delete previous error message. | |
| 2321 | 2325 | } |
| 2322 | 2326 | } |
| 2323 | 2327 | |
| ... | ... | @@ -2507,6 +2511,19 @@ pub fn populateTestFunctions( |
| 2507 | 2511 | |
| 2508 | 2512 | for (test_fn_vals, zcu.test_functions.keys()) |*test_fn_val, test_nav_index| { |
| 2509 | 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 | 2527 | const test_nav_name = test_nav.fqn; |
| 2511 | 2528 | const test_nav_name_len = test_nav_name.length(ip); |
| 2512 | 2529 | const test_name_anon_decl: InternPool.Key.Ptr.BaseAddr.Uav = n: { |
src/main.zig+18-5| ... | ... | @@ -6097,11 +6097,18 @@ fn cmdAstCheck( |
| 6097 | 6097 | var error_bundle = try wip_errors.toOwnedBundle(""); |
| 6098 | 6098 | defer error_bundle.deinit(gpa); |
| 6099 | 6099 | error_bundle.renderToStdErr(color.renderOptions()); |
| 6100 | process.exit(1); | |
| 6100 | ||
| 6101 | if (file.zir.loweringFailed()) { | |
| 6102 | process.exit(1); | |
| 6103 | } | |
| 6101 | 6104 | } |
| 6102 | 6105 | |
| 6103 | 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 | 6113 | if (!build_options.enable_debug_extensions) { |
| 6107 | 6114 | fatal("-t option only available in builds of zig with debug extensions", .{}); |
| ... | ... | @@ -6145,7 +6152,13 @@ fn cmdAstCheck( |
| 6145 | 6152 | // zig fmt: on |
| 6146 | 6153 | } |
| 6147 | 6154 | |
| 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 | } |
| 6150 | 6163 | |
| 6151 | 6164 | fn cmdDetectCpu( |
| ... | ... | @@ -6458,7 +6471,7 @@ fn cmdChangelist( |
| 6458 | 6471 | file.zir_loaded = true; |
| 6459 | 6472 | defer file.zir.deinit(gpa); |
| 6460 | 6473 | |
| 6461 | if (file.zir.hasCompileErrors()) { | |
| 6474 | if (file.zir.loweringFailed()) { | |
| 6462 | 6475 | var wip_errors: std.zig.ErrorBundle.Wip = undefined; |
| 6463 | 6476 | try wip_errors.init(gpa); |
| 6464 | 6477 | defer wip_errors.deinit(); |
| ... | ... | @@ -6493,7 +6506,7 @@ fn cmdChangelist( |
| 6493 | 6506 | file.zir = try AstGen.generate(gpa, new_tree); |
| 6494 | 6507 | file.zir_loaded = true; |
| 6495 | 6508 | |
| 6496 | if (file.zir.hasCompileErrors()) { | |
| 6509 | if (file.zir.loweringFailed()) { | |
| 6497 | 6510 | var wip_errors: std.zig.ErrorBundle.Wip = undefined; |
| 6498 | 6511 | try wip_errors.init(gpa); |
| 6499 | 6512 | defer wip_errors.deinit(); |
src/print_zir.zig+1| ... | ... | @@ -623,6 +623,7 @@ const Writer = struct { |
| 623 | 623 | .inplace_arith_result_ty => try self.writeInplaceArithResultTy(stream, extended), |
| 624 | 624 | |
| 625 | 625 | .dbg_empty_stmt => try stream.writeAll("))"), |
| 626 | .astgen_error => try stream.writeAll("))"), | |
| 626 | 627 | } |
| 627 | 628 | } |
| 628 | 629 |
test/cases/compile_errors/access_invalid_typeInfo_decl.zig+3-6| ... | ... | @@ -1,11 +1,8 @@ |
| 1 | const A = B; | |
| 2 | test "Crash" { | |
| 1 | pub const A = B; | |
| 2 | export fn foo() void { | |
| 3 | 3 | _ = @typeInfo(@This()).@"struct".decls[0]; |
| 4 | 4 | } |
| 5 | 5 | |
| 6 | 6 | // 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 @@ |
| 1 | const a = bogus; // astgen error (undeclared identifier) | |
| 2 | const b: u32 = "hi"; // sema error (type mismatch) | |
| 3 | ||
| 4 | comptime { | |
| 5 | _ = b; | |
| 6 | @compileError("not hit because 'b' failed"); | |
| 7 | } | |
| 8 | ||
| 9 | comptime { | |
| 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 | fn func() bogus {} | |
| 2 | fn func() bogus {} | |
| 3 | export fn entry() usize { | |
| 4 | return @sizeOf(@TypeOf(func)); | |
| 5 | } | |
| 1 | fn func() void {} | |
| 2 | fn func() void {} | |
| 6 | 3 | |
| 7 | 4 | // error |
| 8 | 5 | // |
| 9 | 6 | // :1:4: error: duplicate struct member name 'func' |
| 10 | 7 | // :2:4: note: duplicate name here |
| 11 | 8 | // :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 | 19 | // |
| 20 | 20 | // :4:5: error: unreachable code |
| 21 | 21 | // :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 | 1 | comptime { |
| 2 | 2 | const a = "foo"; |
| 3 | if (a == "foo") unreachable; | |
| 3 | if (a != "foo") unreachable; | |
| 4 | 4 | } |
| 5 | 5 | comptime { |
| 6 | 6 | const a = "foo"; |
| 7 | if (a == ("foo")) unreachable; // intentionally allow | |
| 7 | if (a == "foo") {} else unreachable; | |
| 8 | } | |
| 9 | comptime { | |
| 10 | const a = "foo"; | |
| 11 | if (a != ("foo")) {} // intentionally allow | |
| 12 | if (a == ("foo")) {} // intentionally allow | |
| 8 | 13 | } |
| 9 | 14 | comptime { |
| 10 | 15 | const a = "foo"; |
| 11 | 16 | switch (a) { |
| 12 | "foo" => unreachable, | |
| 13 | else => {}, | |
| 17 | "foo" => {}, | |
| 18 | else => unreachable, | |
| 14 | 19 | } |
| 15 | 20 | } |
| 16 | 21 | comptime { |
| 17 | 22 | const a = "foo"; |
| 18 | 23 | switch (a) { |
| 19 | ("foo") => unreachable, // intentionally allow | |
| 24 | ("foo") => {}, // intentionally allow | |
| 20 | 25 | else => {}, |
| 21 | 26 | } |
| 22 | 27 | } |
| ... | ... | @@ -25,5 +30,6 @@ comptime { |
| 25 | 30 | // backend=stage2 |
| 26 | 31 | // target=native |
| 27 | 32 | // |
| 28 | // :3:11: error: cannot compare strings with == | |
| 29 | // :12:9: error: cannot switch on strings | |
| 33 | // :3:11: error: cannot compare strings with != | |
| 34 | // :7:11: error: cannot compare strings with == | |
| 35 | // :17:9: error: cannot switch on strings |
test/cases/compile_errors/invalid_decltest.zig+1-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | export fn foo() void { |
| 2 | 2 | const a = 1; |
| 3 | struct { | |
| 3 | _ = struct { | |
| 4 | 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 | 28 | _ = jd; |
| 29 | 29 | } |
| 30 | 30 | |
| 31 | export fn entry() usize { | |
| 32 | return @sizeOf(@TypeOf(foo)); | |
| 33 | } | |
| 34 | ||
| 35 | 31 | // error |
| 36 | 32 | // backend=stage2 |
| 37 | 33 | // target=native |
test/cases/compile_errors/noreturn_builtins_divert_control_flow.zig+2-1| ... | ... | @@ -7,7 +7,7 @@ export fn entry2() void { |
| 7 | 7 | @panic(""); |
| 8 | 8 | } |
| 9 | 9 | export fn entry3() void { |
| 10 | @compileError(""); | |
| 10 | @compileError("expect to hit this"); | |
| 11 | 11 | @compileError(""); |
| 12 | 12 | } |
| 13 | 13 | |
| ... | ... | @@ -21,3 +21,4 @@ export fn entry3() void { |
| 21 | 21 | // :6:5: note: control flow is diverted here |
| 22 | 22 | // :11:5: error: unreachable code |
| 23 | 23 | // :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 | 2 | fn entry() void {} |
| 3 | 3 | fn entry() void {} |
| 4 | 4 | |
| 5 | fn foo() void { | |
| 6 | var foo = 1234; | |
| 7 | } | |
| 8 | ||
| 9 | 5 | // error |
| 10 | 6 | // |
| 11 | 7 | // :2:4: error: duplicate struct member name 'entry' |
| 12 | 8 | // :3:4: note: duplicate name here |
| 13 | 9 | // :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 | 1 | pub fn main() void { |
| 2 | 2 | const x = 1; |
| 3 | const y, var z = .{ 2, 3 }; | |
| 3 | const y, var z: u32 = .{ 2, 3 }; | |
| 4 | 4 | } |
| 5 | 5 | |
| 6 | 6 | // error |