@@ -51,6 +51,7 @@ whole_cache_manifest: ?*Cache.Manifest = null,
51
51
whole_cache_manifest_mutex : std.Thread.Mutex = .{},
52
52
53
53
link_error_flags : link.File.ErrorFlags = .{},
54
+ lld_errors : std .ArrayListUnmanaged (LldError ) = .{},
54
55
55
56
work_queue : std .fifo .LinearFifo (Job , .Dynamic ),
56
57
anon_work_queue : std .fifo .LinearFifo (Job , .Dynamic ),
@@ -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
354
/// To support incremental compilation, errors are stored in various places
339
355
/// so that they can be created and destroyed appropriately. This structure
340
356
/// is used to collect all the errors from the various places into one
@@ -2154,6 +2170,11 @@ pub fn destroy(self: *Compilation) void {
2154
2170
}
2155
2171
self .failed_c_objects .deinit (gpa );
2156
2172
2173
+ for (self .lld_errors .items ) | * lld_error | {
2174
+ lld_error .deinit (gpa );
2175
+ }
2176
+ self .lld_errors .deinit (gpa );
2177
+
2157
2178
self .clearMiscFailures ();
2158
2179
2159
2180
self .cache_parent .manifest_dir .close ();
@@ -2453,6 +2474,10 @@ pub fn update(comp: *Compilation) !void {
2453
2474
try comp .flush (main_progress_node );
2454
2475
}
2455
2476
2477
+ if (comp .totalErrorCount () != 0 ) {
2478
+ return ;
2479
+ }
2480
+
2456
2481
// Failure here only means an unnecessary cache miss.
2457
2482
man .writeManifest () catch | err | {
2458
2483
log .warn ("failed to write cache manifest: {s}" , .{@errorName (err )});
@@ -2482,7 +2507,7 @@ fn flush(comp: *Compilation, prog_node: *std.Progress.Node) !void {
2482
2507
// This is needed before reading the error flags.
2483
2508
comp .bin_file .flush (comp , prog_node ) catch | err | switch (err ) {
2484
2509
error .FlushFailure = > {}, // error reported through link_error_flags
2485
- error .LLDReportedFailure = > {}, // error reported through log.err
2510
+ error .LLDReportedFailure = > {}, // error reported via lockAndParseLldStderr
2486
2511
else = > | e | return e ,
2487
2512
};
2488
2513
comp .link_error_flags = comp .bin_file .errorFlags ();
@@ -2715,7 +2740,7 @@ pub fn makeBinFileWritable(self: *Compilation) !void {
2715
2740
/// This function is temporally single-threaded.
2716
2741
pub fn totalErrorCount (self : * Compilation ) usize {
2717
2742
var total : usize = self .failed_c_objects .count () + self .misc_failures .count () +
2718
- @boolToInt (self .alloc_failure_occurred );
2743
+ @boolToInt (self .alloc_failure_occurred ) + self . lld_errors . items . len ;
2719
2744
2720
2745
if (self .bin_file .options .module ) | module | {
2721
2746
total += module .failed_exports .count ();
@@ -2803,6 +2828,21 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
2803
2828
});
2804
2829
}
2805
2830
}
2831
+ for (self .lld_errors .items ) | lld_error | {
2832
+ const notes = try arena_allocator .alloc (AllErrors .Message , lld_error .context_lines .len );
2833
+ for (lld_error .context_lines ) | context_line , i | {
2834
+ notes [i ] = .{ .plain = .{
2835
+ .msg = try arena_allocator .dupe (u8 , context_line ),
2836
+ } };
2837
+ }
2838
+
2839
+ try errors .append (.{
2840
+ .plain = .{
2841
+ .msg = try arena_allocator .dupe (u8 , lld_error .msg ),
2842
+ .notes = notes ,
2843
+ },
2844
+ });
2845
+ }
2806
2846
for (self .misc_failures .values ()) | * value | {
2807
2847
try AllErrors .addPlainWithChildren (& arena , & errors , value .msg , value .children );
2808
2848
}
@@ -4977,6 +5017,49 @@ pub fn lockAndSetMiscFailure(
4977
5017
return setMiscFailure (comp , tag , format , args );
4978
5018
}
4979
5019
5020
+ fn parseLddStderr (comp : * Compilation , comptime prefix : []const u8 , stderr : []const u8 ) Allocator.Error ! void {
5021
+ var context_lines = std .ArrayList ([]const u8 ).init (comp .gpa );
5022
+ defer context_lines .deinit ();
5023
+
5024
+ var current_err : ? * LldError = null ;
5025
+ var lines = mem .split (u8 , stderr , std .cstr .line_sep );
5026
+ while (lines .next ()) | line | {
5027
+ if (mem .startsWith (u8 , line , prefix ++ ":" )) {
5028
+ if (current_err ) | err | {
5029
+ err .context_lines = context_lines .toOwnedSlice ();
5030
+ }
5031
+
5032
+ const duped_msg = try comp .gpa .dupe (u8 , line );
5033
+ errdefer comp .gpa .free (duped_msg );
5034
+
5035
+ current_err = try comp .lld_errors .addOne (comp .gpa );
5036
+ current_err .?.* = .{ .msg = duped_msg };
5037
+ } else if (current_err != null ) {
5038
+ const context_prefix = ">>> " ;
5039
+ var trimmed = mem .trimRight (u8 , line , & std .ascii .whitespace );
5040
+ if (mem .startsWith (u8 , trimmed , context_prefix )) {
5041
+ trimmed = trimmed [context_prefix .len .. ];
5042
+ }
5043
+
5044
+ if (trimmed .len > 0 ) {
5045
+ const duped_line = try comp .gpa .dupe (u8 , trimmed );
5046
+ try context_lines .append (duped_line );
5047
+ }
5048
+ }
5049
+ }
5050
+
5051
+ if (current_err ) | err | {
5052
+ err .context_lines = context_lines .toOwnedSlice ();
5053
+ }
5054
+ }
5055
+
5056
+ pub fn lockAndParseLldStderr (comp : * Compilation , comptime prefix : []const u8 , stderr : []const u8 ) void {
5057
+ comp .mutex .lock ();
5058
+ defer comp .mutex .unlock ();
5059
+
5060
+ comp .parseLddStderr (prefix , stderr ) catch comp .setAllocFailure ();
5061
+ }
5062
+
4980
5063
pub fn dump_argv (argv : []const []const u8 ) void {
4981
5064
for (argv [0 .. argv .len - 1 ]) | arg | {
4982
5065
std .debug .print ("{s} " , .{arg });
0 commit comments