| 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,6 +74,12 @@ pub fn MultiArrayList(comptime T: type) type { |
| 74 | len: usize, | 74 | len: usize, |
| 75 | capacity: usize, | 75 | capacity: usize, |
| 76 | 76 | ||
| 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); |
| 174 | 174 | ||
| 175 | // The AST -> ZIR lowering process assumes an AST that does not have any | 175 | // 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 | }; | ||
| 194 | 196 | ||
| 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 | } |
| 230 | 232 | ||
| 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 | } |
| 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 | // Depending on the type of AST the initialization expression is, we may need an lvalue | 3277 | // 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 as | 3278 | // 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; |
| 3287 | 3292 | ||
| 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); |
| 3352 | 3357 | ||
| 3353 | // The const init expression may have modified the error return trace, so signal | 3358 | // 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 |
| 3491 | 3496 | ||
| 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 | } |
| 3496 | 3501 | ||
| 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( |
| 3550 | 3555 | ||
| 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 | } |
| 3555 | 3560 | ||
| 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( |
| 3664 | 3669 | ||
| 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 | } |
| 3668 | 3674 | ||
| 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)); |
| 4114 | 4120 | ||
| 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.?; |
| 4117 | 4123 | ||
| 4118 | // We insert this at the beginning so that its instruction index marks the | 4124 | // 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( |
| 5182 | 5188 | ||
| 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( |
| 5210 | 5215 | ||
| 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( |
| 5304 | 5309 | ||
| 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 | } |
| 5310 | 5314 | ||
| 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; |
| 5913 | 5917 | ||
| 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 | }, |
| 5919 | 5933 | ||
| ... | @@ -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 | }, |
| 5930 | 5955 | ||
| 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); |
| 6161 | 6224 | ||
| ... | @@ -6614,7 +6677,7 @@ fn whileExpr( | ... | @@ -6614,7 +6677,7 @@ fn whileExpr( |
| 6614 | 6677 | ||
| 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( |
| 6904 | 6967 | ||
| 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; |
| 6966 | 7029 | ||
| 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 | } |
| 6970 | 7033 | ||
| 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( |
| 7521 | 7585 | ||
| 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); |
| 13680 | 13744 | ||
| 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 | } |
| 13837 | 13905 | ||
| ... | @@ -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 | } |
| 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 | 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 | } |
| 13892 | 13966 | ||
| 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 | } |
| 13904 | 13979 | ||
| 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 | } |
| 13916 | 13992 | ||
| 13917 | return decl_count; | 13993 | assert(any_invalid_declarations); |
| 13994 | return error.AnalysisFail; | ||
| 13918 | } | 13995 | } |
| 13919 | 13996 | ||
| 13920 | /// Assumes capacity for body has already been added. Needed capacity taking into | 13997 | /// 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 | }; |
| 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 | /// 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`. |
| 14075 | fn setDeclaration( | 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,7 +120,21 @@ pub fn bodySlice(zir: Zir, start: usize, len: usize) []Inst.Index { |
| 120 | } | 120 | } |
| 121 | 121 | ||
| 122 | pub fn hasCompileErrors(code: Zir) bool { | 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 | pub fn deinit(code: *Zir, gpa: Allocator) void { | 140 | pub 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, | ||
| 2083 | 2104 | ||
| 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 | }; |
| 3585 | 3606 | ||
| 3586 | pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator { | 3607 | pub 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; |
| 3597 | 3618 | 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 | } | ||
| 3634 | 3638 | ||
| 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; |
| 3657 | 3661 | ||
| 3658 | extra_index += captures_len; | 3662 | extra_index += captures_len; |
| 3659 | 3663 | ||
| 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; |
| 3682 | 3686 | ||
| 3683 | extra_index += captures_len; | 3687 | extra_index += captures_len; |
| 3684 | 3688 | ||
| 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; |
| 3704 | 3708 | ||
| 3705 | extra_index += captures_len; | 3709 | extra_index += captures_len; |
| 3706 | 3710 | ||
| 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 | } |
| 3719 | 3720 | ||
| 3720 | /// Find all type declarations, recursively, within a `declaration` instruction. Does not recurse through | 3721 | /// `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 declarations | 3722 | /// 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. | 3724 | pub const DeclContents = struct { |
| 3724 | pub 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. | ||
| 3754 | pub 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); |
| 3728 | 3759 | ||
| ... | @@ -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); |
| 3733 | 3764 | ||
| 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 | } |
| 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 | /// just that instruction because it will also traverse fields. | 3772 | /// just that instruction because it will also traverse fields. |
| 3742 | pub fn findDeclsRoot(zir: Zir, gpa: Allocator, list: *std.ArrayListUnmanaged(Inst.Index)) !void { | 3773 | pub fn findTrackableRoot(zir: Zir, gpa: Allocator, contents: *DeclContents) !void { |
| 3743 | list.clearRetainingCapacity(); | 3774 | contents.clear(); |
| 3744 | 3775 | ||
| 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); |
| 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 | 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), |
| 3999 | 4030 | ||
| 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, |
| 4059 | 4091 | ||
| 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 | }, |
| 4066 | 4098 | ||
| 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), |
| 4069 | 4101 | ||
| 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); |
| 4073 | 4105 | ||
| 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( |
| 4154 | 4186 | ||
| 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 | }, |
| 4159 | 4191 | ||
| 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); |
| 4163 | 4195 | ||
| 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 | }, |
| 4189 | 4221 | ||
| 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); |
| 4193 | 4225 | ||
| 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; | ||
| 4227 | 4260 | ||
| 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; | ||
| 4245 | 4279 | ||
| 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); |
| 4302 | 4336 | ||
| 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 | }, |
| 4306 | 4340 | ||
| 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), |
| 4337 | 4371 | ||
| 4338 | .suspend_block => @panic("TODO iterate suspend block"), | 4372 | .suspend_block => @panic("TODO iterate suspend block"), |
| 4339 | 4373 | ||
| ... | @@ -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 | }, |
| 4346 | 4380 | ||
| 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 | } |
| 4382 | 4416 | ||
| 4383 | fn findDeclsSwitch( | 4417 | fn 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; |
| 4421 | 4455 | ||
| 4422 | try zir.findDeclsBody(gpa, list, defers, body); | 4456 | try zir.findTrackableBody(gpa, contents, defers, body); |
| 4423 | 4457 | ||
| 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; |
| 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,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; |
| 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,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; |
| 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 | 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 | } |
| 4479 | 4513 |
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 | } |
| 3225 | 3225 | ||
| 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 | }; |
| 3237 | 3249 | ||
| 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 | } |
| 8621 | 8631 | ||
| ... | @@ -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 | }, |
| 1366 | 1367 |
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); |
| 2594 | 2594 | ||
| 2595 | // Used as temporary buffers for namespace declaration instructions | 2595 | // 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); |
| 2600 | 2600 | ||
| 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); |
| 2605 | 2605 | ||
| 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); |
| 2608 | 2608 | ||
| 2609 | // We don't have any smart way of matching up these type declarations, so we always | 2609 | 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 | } |
| 2617 | 2635 | ||
| 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` instruction | 2718 | // 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); |
| 2702 | 2720 | ||
| 2703 | // Find container type declarations within this declaration | 2721 | // 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. | ||
| 2706 | 2727 | ||
| 2707 | // We don't have any smart way of matching up these type declarations, so we always | 2728 | 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}); |
| 186 | 186 | ||
| 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 around | 226 | // single-threaded context, so we need to keep both versions around |
| 227 | // until that point in the pipeline. Previous ZIR data is freed after | 227 | // 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 | }; |
| 322 | 322 | ||
| 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 { |
| 379 | 379 | ||
| 380 | const file = updated_file.file; | 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 | const old_inst = tracked_inst.inst.unwrap() orelse continue; // we can't continue tracking lost insts | 382 | 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 { |
| 494 | 493 | ||
| 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); |
| 541 | 540 | ||
| 542 | log.debug("ensureCauAnalyzed {d}", .{@intFromEnum(cau_index)}); | 541 | log.debug("ensureCauAnalyzed {}", .{zcu.fmtAnalUnit(anal_unit)}); |
| 543 | 542 | ||
| 544 | assert(!zcu.analysis_in_progress.contains(anal_unit)); | 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,13 +576,19 @@ pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu |
| 577 | } | 576 | } |
| 578 | 577 | ||
| 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 ensure | 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,12 +713,12 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter |
| 708 | 713 | ||
| 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 }); | ||
| 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 | const func_outdated = zcu.outdated.swapRemove(anal_unit) or | 722 | const func_outdated = zcu.outdated.swapRemove(anal_unit) or |
| 718 | zcu.potentially_outdated.swapRemove(anal_unit); | 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,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 reporting | 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,10 +758,8 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter |
| 752 | 758 | ||
| 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. |
| 781 | 785 | ||
| 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 | } |
| 827 | 833 | ||
| 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 | }); |
| 832 | 838 | ||
| ... | @@ -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 | }; |
| 1167 | 1173 | ||
| 1168 | log.debug("semaCau '{d}'", .{@intFromEnum(cau_index)}); | 1174 | log.debug("semaCau {}", .{zcu.fmtAnalUnit(anal_unit)}); |
| 1169 | 1175 | ||
| 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 | } |
| 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 | fn lockAndClearFileCompileError(pt: Zcu.PerThread, file: *Zcu.File) void { | 2319 | fn 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 | } |
| 2323 | 2327 | ||
| ... | @@ -2507,6 +2511,19 @@ pub fn populateTestFunctions( | ... | @@ -2507,6 +2511,19 @@ pub fn populateTestFunctions( |
| 2507 | 2511 | ||
| 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 | } |
| 6102 | 6105 | ||
| 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: on | 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 | fn cmdDetectCpu( | 6164 | fn 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); |
| 6460 | 6473 | ||
| 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; |
| 6495 | 6508 | ||
| 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), |
| 624 | 624 | ||
| 625 | .dbg_empty_stmt => try stream.writeAll("))"), | 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,11 +1,8 @@ |
| 1 | const A = B; | 1 | pub const A = B; |
| 2 | test "Crash" { | 2 | export fn foo() void { |
| 3 | _ = @typeInfo(@This()).@"struct".decls[0]; | 3 | _ = @typeInfo(@This()).@"struct".decls[0]; |
| 4 | } | 4 | } |
| 5 | 5 | ||
| 6 | // error | 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,13 +1,8 @@ |
| 1 | fn func() bogus {} | 1 | fn func() void {} |
| 2 | fn func() bogus {} | 2 | fn func() void {} |
| 3 | export fn entry() usize { | ||
| 4 | return @sizeOf(@TypeOf(func)); | ||
| 5 | } | ||
| 6 | 3 | ||
| 7 | // error | 4 | // 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 here | 7 | // :2:4: note: duplicate name here |
| 11 | // :1:1: note: struct declared here | 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,3 +19,5 @@ export fn entry() void { |
| 19 | // | 19 | // |
| 20 | // :4:5: error: unreachable code | 20 | // :4:5: error: unreachable code |
| 21 | // :4:25: note: control flow is diverted here | 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,22 +1,27 @@ |
| 1 | comptime { | 1 | comptime { |
| 2 | const a = "foo"; | 2 | const a = "foo"; |
| 3 | if (a == "foo") unreachable; | 3 | if (a != "foo") unreachable; |
| 4 | } | 4 | } |
| 5 | comptime { | 5 | comptime { |
| 6 | const a = "foo"; | 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 | comptime { | 14 | comptime { |
| 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 | } |
| 16 | comptime { | 21 | comptime { |
| 17 | const a = "foo"; | 22 | const a = "foo"; |
| 18 | switch (a) { | 23 | switch (a) { |
| 19 | ("foo") => unreachable, // intentionally allow | 24 | ("foo") => {}, // intentionally allow |
| 20 | else => {}, | 25 | else => {}, |
| 21 | } | 26 | } |
| 22 | } | 27 | } |
| ... | @@ -25,5 +30,6 @@ comptime { | ... | @@ -25,5 +30,6 @@ comptime { |
| 25 | // backend=stage2 | 30 | // backend=stage2 |
| 26 | // target=native | 31 | // 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 strings | 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,6 +1,6 @@ |
| 1 | export fn foo() void { | 1 | export 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 | } |
| 30 | 30 | ||
| 31 | export fn entry() usize { | ||
| 32 | return @sizeOf(@TypeOf(foo)); | ||
| 33 | } | ||
| 34 | |||
| 35 | // error | 31 | // error |
| 36 | // backend=stage2 | 32 | // backend=stage2 |
| 37 | // target=native | 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 +7,7 @@ export fn entry2() void { |
| 7 | @panic(""); | 7 | @panic(""); |
| 8 | } | 8 | } |
| 9 | export fn entry3() void { | 9 | export fn entry3() void { |
| 10 | @compileError(""); | 10 | @compileError("expect to hit this"); |
| 11 | @compileError(""); | 11 | @compileError(""); |
| 12 | } | 12 | } |
| 13 | 13 | ||
| ... | @@ -21,3 +21,4 @@ export fn entry3() void { | ... | @@ -21,3 +21,4 @@ export fn entry3() void { |
| 21 | // :6:5: note: control flow is diverted here | 21 | // :6:5: note: control flow is diverted here |
| 22 | // :11:5: error: unreachable code | 22 | // :11:5: error: unreachable code |
| 23 | // :10:5: note: control flow is diverted here | 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,14 +2,8 @@ |
| 2 | fn entry() void {} | 2 | fn entry() void {} |
| 3 | fn entry() void {} | 3 | fn entry() void {} |
| 4 | 4 | ||
| 5 | fn foo() void { | ||
| 6 | var foo = 1234; | ||
| 7 | } | ||
| 8 | |||
| 9 | // error | 5 | // 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 here | 8 | // :3:4: note: duplicate name here |
| 13 | // :2:1: note: struct declared here | 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,6 +1,6 @@ |
| 1 | pub fn main() void { | 1 | pub 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 | } |
| 5 | 5 | ||
| 6 | // error | 6 | // error |