| ... | @@ -51,6 +51,7 @@ whole_cache_manifest: ?*Cache.Manifest = null, | ... | @@ -51,6 +51,7 @@ whole_cache_manifest: ?*Cache.Manifest = null, |
| 51 | whole_cache_manifest_mutex: std.Thread.Mutex = .{}, | 51 | whole_cache_manifest_mutex: std.Thread.Mutex = .{}, |
| 52 | | 52 | |
| 53 | link_error_flags: link.File.ErrorFlags = .{}, | 53 | link_error_flags: link.File.ErrorFlags = .{}, |
| | 54 | lld_errors: std.ArrayListUnmanaged(LldError) = .{}, |
| 54 | | 55 | |
| 55 | work_queue: std.fifo.LinearFifo(Job, .Dynamic), | 56 | work_queue: std.fifo.LinearFifo(Job, .Dynamic), |
| 56 | anon_work_queue: std.fifo.LinearFifo(Job, .Dynamic), | 57 | anon_work_queue: std.fifo.LinearFifo(Job, .Dynamic), |
| ... | @@ -335,6 +336,21 @@ pub const MiscError = struct { | ... | @@ -335,6 +336,21 @@ pub const MiscError = struct { |
| 335 | } | 336 | } |
| 336 | }; | 337 | }; |
| 337 | | 338 | |
| | 339 | pub const LldError = struct { |
| | 340 | /// Allocated with gpa. |
| | 341 | msg: []const u8, |
| | 342 | context_lines: []const []const u8 = &.{}, |
| | 343 | |
| | 344 | pub fn deinit(self: *LldError, gpa: Allocator) void { |
| | 345 | for (self.context_lines) |line| { |
| | 346 | gpa.free(line); |
| | 347 | } |
| | 348 | |
| | 349 | gpa.free(self.context_lines); |
| | 350 | gpa.free(self.msg); |
| | 351 | } |
| | 352 | }; |
| | 353 | |
| 338 | /// To support incremental compilation, errors are stored in various places | 354 | /// To support incremental compilation, errors are stored in various places |
| 339 | /// so that they can be created and destroyed appropriately. This structure | 355 | /// so that they can be created and destroyed appropriately. This structure |
| 340 | /// is used to collect all the errors from the various places into one | 356 | /// is used to collect all the errors from the various places into one |
| ... | @@ -498,7 +514,7 @@ pub const AllErrors = struct { | ... | @@ -498,7 +514,7 @@ pub const AllErrors = struct { |
| 498 | } | 514 | } |
| 499 | ttyconf.setColor(stderr, .Reset); | 515 | ttyconf.setColor(stderr, .Reset); |
| 500 | for (plain.notes) |note| { | 516 | for (plain.notes) |note| { |
| 501 | try note.renderToWriter(ttyconf, stderr, "error", .Red, indent + 4); | 517 | try note.renderToWriter(ttyconf, stderr, "note", .Cyan, indent + 4); |
| 502 | } | 518 | } |
| 503 | }, | 519 | }, |
| 504 | } | 520 | } |
| ... | @@ -2166,6 +2182,11 @@ pub fn destroy(self: *Compilation) void { | ... | @@ -2166,6 +2182,11 @@ pub fn destroy(self: *Compilation) void { |
| 2166 | } | 2182 | } |
| 2167 | self.failed_c_objects.deinit(gpa); | 2183 | self.failed_c_objects.deinit(gpa); |
| 2168 | | 2184 | |
| | 2185 | for (self.lld_errors.items) |*lld_error| { |
| | 2186 | lld_error.deinit(gpa); |
| | 2187 | } |
| | 2188 | self.lld_errors.deinit(gpa); |
| | 2189 | |
| 2169 | self.clearMiscFailures(); | 2190 | self.clearMiscFailures(); |
| 2170 | | 2191 | |
| 2171 | self.cache_parent.manifest_dir.close(); | 2192 | self.cache_parent.manifest_dir.close(); |
| ... | @@ -2465,6 +2486,10 @@ pub fn update(comp: *Compilation) !void { | ... | @@ -2465,6 +2486,10 @@ pub fn update(comp: *Compilation) !void { |
| 2465 | try comp.flush(main_progress_node); | 2486 | try comp.flush(main_progress_node); |
| 2466 | } | 2487 | } |
| 2467 | | 2488 | |
| | 2489 | if (comp.totalErrorCount() != 0) { |
| | 2490 | return; |
| | 2491 | } |
| | 2492 | |
| 2468 | // Failure here only means an unnecessary cache miss. | 2493 | // Failure here only means an unnecessary cache miss. |
| 2469 | man.writeManifest() catch |err| { | 2494 | man.writeManifest() catch |err| { |
| 2470 | log.warn("failed to write cache manifest: {s}", .{@errorName(err)}); | 2495 | log.warn("failed to write cache manifest: {s}", .{@errorName(err)}); |
| ... | @@ -2494,7 +2519,7 @@ fn flush(comp: *Compilation, prog_node: *std.Progress.Node) !void { | ... | @@ -2494,7 +2519,7 @@ fn flush(comp: *Compilation, prog_node: *std.Progress.Node) !void { |
| 2494 | // This is needed before reading the error flags. | 2519 | // This is needed before reading the error flags. |
| 2495 | comp.bin_file.flush(comp, prog_node) catch |err| switch (err) { | 2520 | comp.bin_file.flush(comp, prog_node) catch |err| switch (err) { |
| 2496 | error.FlushFailure => {}, // error reported through link_error_flags | 2521 | error.FlushFailure => {}, // error reported through link_error_flags |
| 2497 | error.LLDReportedFailure => {}, // error reported through log.err | 2522 | error.LLDReportedFailure => {}, // error reported via lockAndParseLldStderr |
| 2498 | else => |e| return e, | 2523 | else => |e| return e, |
| 2499 | }; | 2524 | }; |
| 2500 | comp.link_error_flags = comp.bin_file.errorFlags(); | 2525 | comp.link_error_flags = comp.bin_file.errorFlags(); |
| ... | @@ -2727,7 +2752,7 @@ pub fn makeBinFileWritable(self: *Compilation) !void { | ... | @@ -2727,7 +2752,7 @@ pub fn makeBinFileWritable(self: *Compilation) !void { |
| 2727 | /// This function is temporally single-threaded. | 2752 | /// This function is temporally single-threaded. |
| 2728 | pub fn totalErrorCount(self: *Compilation) usize { | 2753 | pub fn totalErrorCount(self: *Compilation) usize { |
| 2729 | var total: usize = self.failed_c_objects.count() + self.misc_failures.count() + | 2754 | var total: usize = self.failed_c_objects.count() + self.misc_failures.count() + |
| 2730 | @boolToInt(self.alloc_failure_occurred); | 2755 | @boolToInt(self.alloc_failure_occurred) + self.lld_errors.items.len; |
| 2731 | | 2756 | |
| 2732 | if (self.bin_file.options.module) |module| { | 2757 | if (self.bin_file.options.module) |module| { |
| 2733 | total += module.failed_exports.count(); | 2758 | total += module.failed_exports.count(); |
| ... | @@ -2815,6 +2840,21 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors { | ... | @@ -2815,6 +2840,21 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors { |
| 2815 | }); | 2840 | }); |
| 2816 | } | 2841 | } |
| 2817 | } | 2842 | } |
| | 2843 | for (self.lld_errors.items) |lld_error| { |
| | 2844 | const notes = try arena_allocator.alloc(AllErrors.Message, lld_error.context_lines.len); |
| | 2845 | for (lld_error.context_lines) |context_line, i| { |
| | 2846 | notes[i] = .{ .plain = .{ |
| | 2847 | .msg = try arena_allocator.dupe(u8, context_line), |
| | 2848 | } }; |
| | 2849 | } |
| | 2850 | |
| | 2851 | try errors.append(.{ |
| | 2852 | .plain = .{ |
| | 2853 | .msg = try arena_allocator.dupe(u8, lld_error.msg), |
| | 2854 | .notes = notes, |
| | 2855 | }, |
| | 2856 | }); |
| | 2857 | } |
| 2818 | for (self.misc_failures.values()) |*value| { | 2858 | for (self.misc_failures.values()) |*value| { |
| 2819 | try AllErrors.addPlainWithChildren(&arena, &errors, value.msg, value.children); | 2859 | try AllErrors.addPlainWithChildren(&arena, &errors, value.msg, value.children); |
| 2820 | } | 2860 | } |
| ... | @@ -4989,6 +5029,52 @@ pub fn lockAndSetMiscFailure( | ... | @@ -4989,6 +5029,52 @@ pub fn lockAndSetMiscFailure( |
| 4989 | return setMiscFailure(comp, tag, format, args); | 5029 | return setMiscFailure(comp, tag, format, args); |
| 4990 | } | 5030 | } |
| 4991 | | 5031 | |
| | 5032 | fn parseLldStderr(comp: *Compilation, comptime prefix: []const u8, stderr: []const u8) Allocator.Error!void { |
| | 5033 | var context_lines = std.ArrayList([]const u8).init(comp.gpa); |
| | 5034 | defer context_lines.deinit(); |
| | 5035 | |
| | 5036 | var current_err: ?*LldError = null; |
| | 5037 | var lines = mem.split(u8, stderr, std.cstr.line_sep); |
| | 5038 | while (lines.next()) |line| { |
| | 5039 | if (mem.startsWith(u8, line, prefix ++ ":")) { |
| | 5040 | if (current_err) |err| { |
| | 5041 | err.context_lines = context_lines.toOwnedSlice(); |
| | 5042 | } |
| | 5043 | |
| | 5044 | var split = std.mem.split(u8, line, "error: "); |
| | 5045 | _ = split.first(); |
| | 5046 | |
| | 5047 | const duped_msg = try std.fmt.allocPrint(comp.gpa, "{s}: {s}", .{ prefix, split.rest() }); |
| | 5048 | errdefer comp.gpa.free(duped_msg); |
| | 5049 | |
| | 5050 | current_err = try comp.lld_errors.addOne(comp.gpa); |
| | 5051 | current_err.?.* = .{ .msg = duped_msg }; |
| | 5052 | } else if (current_err != null) { |
| | 5053 | const context_prefix = ">>> "; |
| | 5054 | var trimmed = mem.trimRight(u8, line, &std.ascii.whitespace); |
| | 5055 | if (mem.startsWith(u8, trimmed, context_prefix)) { |
| | 5056 | trimmed = trimmed[context_prefix.len..]; |
| | 5057 | } |
| | 5058 | |
| | 5059 | if (trimmed.len > 0) { |
| | 5060 | const duped_line = try comp.gpa.dupe(u8, trimmed); |
| | 5061 | try context_lines.append(duped_line); |
| | 5062 | } |
| | 5063 | } |
| | 5064 | } |
| | 5065 | |
| | 5066 | if (current_err) |err| { |
| | 5067 | err.context_lines = context_lines.toOwnedSlice(); |
| | 5068 | } |
| | 5069 | } |
| | 5070 | |
| | 5071 | pub fn lockAndParseLldStderr(comp: *Compilation, comptime prefix: []const u8, stderr: []const u8) void { |
| | 5072 | comp.mutex.lock(); |
| | 5073 | defer comp.mutex.unlock(); |
| | 5074 | |
| | 5075 | comp.parseLldStderr(prefix, stderr) catch comp.setAllocFailure(); |
| | 5076 | } |
| | 5077 | |
| 4992 | pub fn dump_argv(argv: []const []const u8) void { | 5078 | pub fn dump_argv(argv: []const []const u8) void { |
| 4993 | for (argv[0 .. argv.len - 1]) |arg| { | 5079 | for (argv[0 .. argv.len - 1]) |arg| { |
| 4994 | std.debug.print("{s} ", .{arg}); | 5080 | std.debug.print("{s} ", .{arg}); |