authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-10-11 01:15:30-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-10-11 10:36:19-07:00
log13fb68c064900cee67583e603d8c2acf41770663
tree537e524b28610d80f2553d1b124f67b4656fb80a
parent5e53203e82bdeb0273160db156050164c5c69267

link: consolidate diagnostics

By organizing linker diagnostics into this struct, it becomes possible to share more code between linker backends, and more importantly it becomes possible to pass only the Diag struct to some functions, rather than passing the entire linker state object in. This makes data dependencies more obvious, making it easier to rearrange code and to multithread. Also fix MachO code abusing an atomic variable. Not only was it using the wrong atomic operation, it is unnecessary additional state since the state is already being protected by a mutex.

15 files changed, 513 insertions(+), 440 deletions(-)

src/Compilation.zig+11-81
...@@ -106,10 +106,7 @@ win32_resource_table: if (dev.env.supports(.win32_resource)) std.AutoArrayHashMa...@@ -106,10 +106,7 @@ win32_resource_table: if (dev.env.supports(.win32_resource)) std.AutoArrayHashMa
106 pub fn deinit(_: @This(), _: Allocator) void {}106 pub fn deinit(_: @This(), _: Allocator) void {}
107} = .{},107} = .{},
108108
109link_errors: std.ArrayListUnmanaged(link.File.ErrorMsg) = .empty,109link_diags: link.Diags,
110link_errors_mutex: std.Thread.Mutex = .{},
111link_error_flags: link.File.ErrorFlags = .{},
112lld_errors: std.ArrayListUnmanaged(LldError) = .empty,
113110
114work_queues: [111work_queues: [
115 len: {112 len: {
...@@ -842,21 +839,6 @@ pub const MiscError = struct {...@@ -842,21 +839,6 @@ pub const MiscError = struct {
842 }839 }
843};840};
844841
845pub const LldError = struct {
846 /// Allocated with gpa.
847 msg: []const u8,
848 context_lines: []const []const u8 = &.{},
849
850 pub fn deinit(self: *LldError, gpa: Allocator) void {
851 for (self.context_lines) |line| {
852 gpa.free(line);
853 }
854
855 gpa.free(self.context_lines);
856 gpa.free(self.msg);
857 }
858};
859
860pub const EmitLoc = struct {842pub const EmitLoc = struct {
861 /// If this is `null` it means the file will be output to the cache directory.843 /// If this is `null` it means the file will be output to the cache directory.
862 /// When provided, both the open file handle and the path name must outlive the `Compilation`.844 /// When provided, both the open file handle and the path name must outlive the `Compilation`.
...@@ -1558,6 +1540,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -1558,6 +1540,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
1558 .global_cc_argv = options.global_cc_argv,1540 .global_cc_argv = options.global_cc_argv,
1559 .file_system_inputs = options.file_system_inputs,1541 .file_system_inputs = options.file_system_inputs,
1560 .parent_whole_cache = options.parent_whole_cache,1542 .parent_whole_cache = options.parent_whole_cache,
1543 .link_diags = .init(gpa),
1561 };1544 };
15621545
1563 // Prevent some footguns by making the "any" fields of config reflect1546 // Prevent some footguns by making the "any" fields of config reflect
...@@ -1999,13 +1982,7 @@ pub fn destroy(comp: *Compilation) void {...@@ -1999,13 +1982,7 @@ pub fn destroy(comp: *Compilation) void {
1999 }1982 }
2000 comp.failed_win32_resources.deinit(gpa);1983 comp.failed_win32_resources.deinit(gpa);
20011984
2002 for (comp.link_errors.items) |*item| item.deinit(gpa);1985 comp.link_diags.deinit();
2003 comp.link_errors.deinit(gpa);
2004
2005 for (comp.lld_errors.items) |*lld_error| {
2006 lld_error.deinit(gpa);
2007 }
2008 comp.lld_errors.deinit(gpa);
20091986
2010 comp.clearMiscFailures();1987 comp.clearMiscFailures();
20111988
...@@ -2304,7 +2281,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {...@@ -2304,7 +2281,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
23042281
2305 if (anyErrors(comp)) {2282 if (anyErrors(comp)) {
2306 // Skip flushing and keep source files loaded for error reporting.2283 // Skip flushing and keep source files loaded for error reporting.
2307 comp.link_error_flags = .{};2284 comp.link_diags.flags = .{};
2308 return;2285 return;
2309 }2286 }
23102287
...@@ -2451,7 +2428,7 @@ fn flush(...@@ -2451,7 +2428,7 @@ fn flush(
2451 if (comp.bin_file) |lf| {2428 if (comp.bin_file) |lf| {
2452 // This is needed before reading the error flags.2429 // This is needed before reading the error flags.
2453 lf.flush(arena, tid, prog_node) catch |err| switch (err) {2430 lf.flush(arena, tid, prog_node) catch |err| switch (err) {
2454 error.FlushFailure, error.LinkFailure => {}, // error reported through link_error_flags2431 error.FlushFailure, error.LinkFailure => {}, // error reported through link_diags.flags
2455 error.LLDReportedFailure => {}, // error reported via lockAndParseLldStderr2432 error.LLDReportedFailure => {}, // error reported via lockAndParseLldStderr
2456 else => |e| return e,2433 else => |e| return e,
2457 };2434 };
...@@ -3070,7 +3047,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {...@@ -3070,7 +3047,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
3070 try bundle.addBundleAsRoots(error_bundle);3047 try bundle.addBundleAsRoots(error_bundle);
3071 }3048 }
30723049
3073 for (comp.lld_errors.items) |lld_error| {3050 for (comp.link_diags.lld.items) |lld_error| {
3074 const notes_len = @as(u32, @intCast(lld_error.context_lines.len));3051 const notes_len = @as(u32, @intCast(lld_error.context_lines.len));
30753052
3076 try bundle.addRootErrorMessage(.{3053 try bundle.addRootErrorMessage(.{
...@@ -3091,7 +3068,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {...@@ -3091,7 +3068,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
3091 });3068 });
3092 if (value.children) |b| try bundle.addBundleAsNotes(b);3069 if (value.children) |b| try bundle.addBundleAsNotes(b);
3093 }3070 }
3094 if (comp.alloc_failure_occurred) {3071 if (comp.alloc_failure_occurred or comp.link_diags.flags.alloc_failure_occurred) {
3095 try bundle.addRootErrorMessage(.{3072 try bundle.addRootErrorMessage(.{
3096 .msg = try bundle.addString("memory allocation failure"),3073 .msg = try bundle.addString("memory allocation failure"),
3097 });3074 });
...@@ -3220,14 +3197,14 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {...@@ -3220,14 +3197,14 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
3220 }3197 }
32213198
3222 if (bundle.root_list.items.len == 0) {3199 if (bundle.root_list.items.len == 0) {
3223 if (comp.link_error_flags.no_entry_point_found) {3200 if (comp.link_diags.flags.no_entry_point_found) {
3224 try bundle.addRootErrorMessage(.{3201 try bundle.addRootErrorMessage(.{
3225 .msg = try bundle.addString("no entry point found"),3202 .msg = try bundle.addString("no entry point found"),
3226 });3203 });
3227 }3204 }
3228 }3205 }
32293206
3230 if (comp.link_error_flags.missing_libc) {3207 if (comp.link_diags.flags.missing_libc) {
3231 try bundle.addRootErrorMessage(.{3208 try bundle.addRootErrorMessage(.{
3232 .msg = try bundle.addString("libc not available"),3209 .msg = try bundle.addString("libc not available"),
3233 .notes_len = 2,3210 .notes_len = 2,
...@@ -3241,7 +3218,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {...@@ -3241,7 +3218,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
3241 }));3218 }));
3242 }3219 }
32433220
3244 for (comp.link_errors.items) |link_err| {3221 for (comp.link_diags.msgs.items) |link_err| {
3245 try bundle.addRootErrorMessage(.{3222 try bundle.addRootErrorMessage(.{
3246 .msg = try bundle.addString(link_err.msg),3223 .msg = try bundle.addString(link_err.msg),
3247 .notes_len = @intCast(link_err.notes.len),3224 .notes_len = @intCast(link_err.notes.len),
...@@ -6161,6 +6138,7 @@ fn wantBuildLibUnwindFromSource(comp: *Compilation) bool {...@@ -6161,6 +6138,7 @@ fn wantBuildLibUnwindFromSource(comp: *Compilation) bool {
6161}6138}
61626139
6163fn setAllocFailure(comp: *Compilation) void {6140fn setAllocFailure(comp: *Compilation) void {
6141 @branchHint(.cold);
6164 log.debug("memory allocation failure", .{});6142 log.debug("memory allocation failure", .{});
6165 comp.alloc_failure_occurred = true;6143 comp.alloc_failure_occurred = true;
6166}6144}
...@@ -6195,54 +6173,6 @@ pub fn lockAndSetMiscFailure(...@@ -6195,54 +6173,6 @@ pub fn lockAndSetMiscFailure(
6195 return setMiscFailure(comp, tag, format, args);6173 return setMiscFailure(comp, tag, format, args);
6196}6174}
61976175
6198fn parseLldStderr(comp: *Compilation, prefix: []const u8, stderr: []const u8) Allocator.Error!void {
6199 var context_lines = std.ArrayList([]const u8).init(comp.gpa);
6200 defer context_lines.deinit();
6201
6202 var current_err: ?*LldError = null;
6203 var lines = mem.splitSequence(u8, stderr, if (builtin.os.tag == .windows) "\r\n" else "\n");
6204 while (lines.next()) |line| {
6205 if (line.len > prefix.len + ":".len and
6206 mem.eql(u8, line[0..prefix.len], prefix) and line[prefix.len] == ':')
6207 {
6208 if (current_err) |err| {
6209 err.context_lines = try context_lines.toOwnedSlice();
6210 }
6211
6212 var split = mem.splitSequence(u8, line, "error: ");
6213 _ = split.first();
6214
6215 const duped_msg = try std.fmt.allocPrint(comp.gpa, "{s}: {s}", .{ prefix, split.rest() });
6216 errdefer comp.gpa.free(duped_msg);
6217
6218 current_err = try comp.lld_errors.addOne(comp.gpa);
6219 current_err.?.* = .{ .msg = duped_msg };
6220 } else if (current_err != null) {
6221 const context_prefix = ">>> ";
6222 var trimmed = mem.trimRight(u8, line, &std.ascii.whitespace);
6223 if (mem.startsWith(u8, trimmed, context_prefix)) {
6224 trimmed = trimmed[context_prefix.len..];
6225 }
6226
6227 if (trimmed.len > 0) {
6228 const duped_line = try comp.gpa.dupe(u8, trimmed);
6229 try context_lines.append(duped_line);
6230 }
6231 }
6232 }
6233
6234 if (current_err) |err| {
6235 err.context_lines = try context_lines.toOwnedSlice();
6236 }
6237}
6238
6239pub fn lockAndParseLldStderr(comp: *Compilation, prefix: []const u8, stderr: []const u8) void {
6240 comp.mutex.lock();
6241 defer comp.mutex.unlock();
6242
6243 comp.parseLldStderr(prefix, stderr) catch comp.setAllocFailure();
6244}
6245
6246pub fn dump_argv(argv: []const []const u8) void {6176pub fn dump_argv(argv: []const []const u8) void {
6247 std.debug.lockStdErr();6177 std.debug.lockStdErr();
6248 defer std.debug.unlockStdErr();6178 defer std.debug.unlockStdErr();
src/link.zig+249-84
...@@ -37,6 +37,252 @@ pub const SystemLib = struct {...@@ -37,6 +37,252 @@ pub const SystemLib = struct {
37 path: ?Path,37 path: ?Path,
38};38};
3939
40pub const Diags = struct {
41 /// Stored here so that function definitions can distinguish between
42 /// needing an allocator for things besides error reporting.
43 gpa: Allocator,
44 mutex: std.Thread.Mutex,
45 msgs: std.ArrayListUnmanaged(Msg),
46 flags: Flags,
47 lld: std.ArrayListUnmanaged(Lld),
48
49 pub const Flags = packed struct {
50 no_entry_point_found: bool = false,
51 missing_libc: bool = false,
52 alloc_failure_occurred: bool = false,
53
54 const Int = blk: {
55 const bits = @typeInfo(@This()).@"struct".fields.len;
56 break :blk @Type(.{ .int = .{
57 .signedness = .unsigned,
58 .bits = bits,
59 } });
60 };
61
62 pub fn anySet(ef: Flags) bool {
63 return @as(Int, @bitCast(ef)) > 0;
64 }
65 };
66
67 pub const Lld = struct {
68 /// Allocated with gpa.
69 msg: []const u8,
70 context_lines: []const []const u8 = &.{},
71
72 pub fn deinit(self: *Lld, gpa: Allocator) void {
73 for (self.context_lines) |line| gpa.free(line);
74 gpa.free(self.context_lines);
75 gpa.free(self.msg);
76 self.* = undefined;
77 }
78 };
79
80 pub const Msg = struct {
81 msg: []const u8,
82 notes: []Msg = &.{},
83
84 pub fn deinit(self: *Msg, gpa: Allocator) void {
85 for (self.notes) |*note| note.deinit(gpa);
86 gpa.free(self.notes);
87 gpa.free(self.msg);
88 }
89 };
90
91 pub const ErrorWithNotes = struct {
92 diags: *Diags,
93 /// Allocated index in diags.msgs array.
94 index: usize,
95 /// Next available note slot.
96 note_slot: usize = 0,
97
98 pub fn addMsg(
99 err: ErrorWithNotes,
100 comptime format: []const u8,
101 args: anytype,
102 ) error{OutOfMemory}!void {
103 const gpa = err.diags.gpa;
104 const err_msg = &err.diags.msgs.items[err.index];
105 err_msg.msg = try std.fmt.allocPrint(gpa, format, args);
106 }
107
108 pub fn addNote(
109 err: *ErrorWithNotes,
110 comptime format: []const u8,
111 args: anytype,
112 ) error{OutOfMemory}!void {
113 const gpa = err.diags.gpa;
114 const err_msg = &err.diags.msgs.items[err.index];
115 assert(err.note_slot < err_msg.notes.len);
116 err_msg.notes[err.note_slot] = .{ .msg = try std.fmt.allocPrint(gpa, format, args) };
117 err.note_slot += 1;
118 }
119 };
120
121 pub fn init(gpa: Allocator) Diags {
122 return .{
123 .gpa = gpa,
124 .mutex = .{},
125 .msgs = .empty,
126 .flags = .{},
127 .lld = .empty,
128 };
129 }
130
131 pub fn deinit(diags: *Diags) void {
132 const gpa = diags.gpa;
133
134 for (diags.msgs.items) |*item| item.deinit(gpa);
135 diags.msgs.deinit(gpa);
136
137 for (diags.lld.items) |*item| item.deinit(gpa);
138 diags.lld.deinit(gpa);
139
140 diags.* = undefined;
141 }
142
143 pub fn hasErrors(diags: *Diags) bool {
144 return diags.msgs.items.len > 0 or diags.flags.anySet();
145 }
146
147 pub fn lockAndParseLldStderr(diags: *Diags, prefix: []const u8, stderr: []const u8) void {
148 diags.mutex.lock();
149 defer diags.mutex.unlock();
150
151 diags.parseLldStderr(prefix, stderr) catch diags.setAllocFailure();
152 }
153
154 fn parseLldStderr(
155 diags: *Diags,
156 prefix: []const u8,
157 stderr: []const u8,
158 ) Allocator.Error!void {
159 const gpa = diags.gpa;
160
161 var context_lines = std.ArrayList([]const u8).init(gpa);
162 defer context_lines.deinit();
163
164 var current_err: ?*Lld = null;
165 var lines = mem.splitSequence(u8, stderr, if (builtin.os.tag == .windows) "\r\n" else "\n");
166 while (lines.next()) |line| {
167 if (line.len > prefix.len + ":".len and
168 mem.eql(u8, line[0..prefix.len], prefix) and line[prefix.len] == ':')
169 {
170 if (current_err) |err| {
171 err.context_lines = try context_lines.toOwnedSlice();
172 }
173
174 var split = mem.splitSequence(u8, line, "error: ");
175 _ = split.first();
176
177 const duped_msg = try std.fmt.allocPrint(gpa, "{s}: {s}", .{ prefix, split.rest() });
178 errdefer gpa.free(duped_msg);
179
180 current_err = try diags.lld.addOne(gpa);
181 current_err.?.* = .{ .msg = duped_msg };
182 } else if (current_err != null) {
183 const context_prefix = ">>> ";
184 var trimmed = mem.trimRight(u8, line, &std.ascii.whitespace);
185 if (mem.startsWith(u8, trimmed, context_prefix)) {
186 trimmed = trimmed[context_prefix.len..];
187 }
188
189 if (trimmed.len > 0) {
190 const duped_line = try gpa.dupe(u8, trimmed);
191 try context_lines.append(duped_line);
192 }
193 }
194 }
195
196 if (current_err) |err| {
197 err.context_lines = try context_lines.toOwnedSlice();
198 }
199 }
200
201 pub fn fail(diags: *Diags, comptime format: []const u8, args: anytype) error{LinkFailure} {
202 @branchHint(.cold);
203 addError(diags, format, args);
204 return error.LinkFailure;
205 }
206
207 pub fn addError(diags: *Diags, comptime format: []const u8, args: anytype) void {
208 @branchHint(.cold);
209 const gpa = diags.gpa;
210 diags.mutex.lock();
211 defer diags.mutex.unlock();
212 diags.msgs.ensureUnusedCapacity(gpa, 1) catch |err| switch (err) {
213 error.OutOfMemory => {
214 diags.flags.alloc_failure_occurred = true;
215 return;
216 },
217 };
218 const err_msg: Msg = .{
219 .msg = std.fmt.allocPrint(gpa, format, args) catch |err| switch (err) {
220 error.OutOfMemory => {
221 diags.flags.alloc_failure_occurred = true;
222 return;
223 },
224 },
225 };
226 diags.msgs.appendAssumeCapacity(err_msg);
227 }
228
229 pub fn addErrorWithNotes(diags: *Diags, note_count: usize) error{OutOfMemory}!ErrorWithNotes {
230 @branchHint(.cold);
231 const gpa = diags.gpa;
232 diags.mutex.lock();
233 defer diags.mutex.unlock();
234 try diags.msgs.ensureUnusedCapacity(gpa, 1);
235 return addErrorWithNotesAssumeCapacity(diags, note_count);
236 }
237
238 pub fn addErrorWithNotesAssumeCapacity(diags: *Diags, note_count: usize) error{OutOfMemory}!ErrorWithNotes {
239 @branchHint(.cold);
240 const gpa = diags.gpa;
241 const index = diags.msgs.items.len;
242 const err = diags.msgs.addOneAssumeCapacity();
243 err.* = .{
244 .msg = undefined,
245 .notes = try gpa.alloc(Diags.Msg, note_count),
246 };
247 return .{
248 .diags = diags,
249 .index = index,
250 };
251 }
252
253 pub fn reportMissingLibraryError(
254 diags: *Diags,
255 checked_paths: []const []const u8,
256 comptime format: []const u8,
257 args: anytype,
258 ) error{OutOfMemory}!void {
259 @branchHint(.cold);
260 var err = try diags.addErrorWithNotes(checked_paths.len);
261 try err.addMsg(format, args);
262 for (checked_paths) |path| {
263 try err.addNote("tried {s}", .{path});
264 }
265 }
266
267 pub fn reportParseError(
268 diags: *Diags,
269 path: Path,
270 comptime format: []const u8,
271 args: anytype,
272 ) error{OutOfMemory}!void {
273 @branchHint(.cold);
274 var err = try diags.addErrorWithNotes(1);
275 try err.addMsg(format, args);
276 try err.addNote("while parsing {}", .{path});
277 }
278
279 pub fn setAllocFailure(diags: *Diags) void {
280 @branchHint(.cold);
281 log.debug("memory allocation failure", .{});
282 diags.flags.alloc_failure_occurred = true;
283 }
284};
285
40pub fn hashAddSystemLibs(286pub fn hashAddSystemLibs(
41 man: *Cache.Manifest,287 man: *Cache.Manifest,
42 hm: std.StringArrayHashMapUnmanaged(SystemLib),288 hm: std.StringArrayHashMapUnmanaged(SystemLib),
...@@ -446,58 +692,6 @@ pub const File = struct {...@@ -446,58 +692,6 @@ pub const File = struct {
446 }692 }
447 }693 }
448694
449 pub const ErrorWithNotes = struct {
450 base: *const File,
451
452 /// Allocated index in base.errors array.
453 index: usize,
454
455 /// Next available note slot.
456 note_slot: usize = 0,
457
458 pub fn addMsg(
459 err: ErrorWithNotes,
460 comptime format: []const u8,
461 args: anytype,
462 ) error{OutOfMemory}!void {
463 const gpa = err.base.comp.gpa;
464 const err_msg = &err.base.comp.link_errors.items[err.index];
465 err_msg.msg = try std.fmt.allocPrint(gpa, format, args);
466 }
467
468 pub fn addNote(
469 err: *ErrorWithNotes,
470 comptime format: []const u8,
471 args: anytype,
472 ) error{OutOfMemory}!void {
473 const gpa = err.base.comp.gpa;
474 const err_msg = &err.base.comp.link_errors.items[err.index];
475 assert(err.note_slot < err_msg.notes.len);
476 err_msg.notes[err.note_slot] = .{ .msg = try std.fmt.allocPrint(gpa, format, args) };
477 err.note_slot += 1;
478 }
479 };
480
481 pub fn addErrorWithNotes(base: *const File, note_count: usize) error{OutOfMemory}!ErrorWithNotes {
482 base.comp.link_errors_mutex.lock();
483 defer base.comp.link_errors_mutex.unlock();
484 const gpa = base.comp.gpa;
485 try base.comp.link_errors.ensureUnusedCapacity(gpa, 1);
486 return base.addErrorWithNotesAssumeCapacity(note_count);
487 }
488
489 pub fn addErrorWithNotesAssumeCapacity(base: *const File, note_count: usize) error{OutOfMemory}!ErrorWithNotes {
490 const gpa = base.comp.gpa;
491 const index = base.comp.link_errors.items.len;
492 const err = base.comp.link_errors.addOneAssumeCapacity();
493 err.* = .{ .msg = undefined, .notes = try gpa.alloc(ErrorMsg, note_count) };
494 return .{ .base = base, .index = index };
495 }
496
497 pub fn hasErrors(base: *const File) bool {
498 return base.comp.link_errors.items.len > 0 or base.comp.link_error_flags.isSet();
499 }
500
501 pub fn releaseLock(self: *File) void {695 pub fn releaseLock(self: *File) void {
502 if (self.lock) |*lock| {696 if (self.lock) |*lock| {
503 lock.release();697 lock.release();
...@@ -523,7 +717,7 @@ pub const File = struct {...@@ -523,7 +717,7 @@ pub const File = struct {
523 }717 }
524718
525 /// TODO audit this error set. most of these should be collapsed into one error,719 /// TODO audit this error set. most of these should be collapsed into one error,
526 /// and ErrorFlags should be updated to convey the meaning to the user.720 /// and Diags.Flags should be updated to convey the meaning to the user.
527 pub const FlushError = error{721 pub const FlushError = error{
528 CacheUnavailable,722 CacheUnavailable,
529 CurrentWorkingDirectoryUnlinked,723 CurrentWorkingDirectoryUnlinked,
...@@ -939,36 +1133,6 @@ pub const File = struct {...@@ -939,36 +1133,6 @@ pub const File = struct {
939 }1133 }
940 };1134 };
9411135
942 pub const ErrorFlags = packed struct {
943 no_entry_point_found: bool = false,
944 missing_libc: bool = false,
945
946 const Int = blk: {
947 const bits = @typeInfo(@This()).@"struct".fields.len;
948 break :blk @Type(.{ .int = .{
949 .signedness = .unsigned,
950 .bits = bits,
951 } });
952 };
953
954 fn isSet(ef: ErrorFlags) bool {
955 return @as(Int, @bitCast(ef)) > 0;
956 }
957 };
958
959 pub const ErrorMsg = struct {
960 msg: []const u8,
961 notes: []ErrorMsg = &.{},
962
963 pub fn deinit(self: *ErrorMsg, gpa: Allocator) void {
964 for (self.notes) |*note| {
965 note.deinit(gpa);
966 }
967 gpa.free(self.notes);
968 gpa.free(self.msg);
969 }
970 };
971
972 pub const LazySymbol = struct {1136 pub const LazySymbol = struct {
973 pub const Kind = enum { code, const_data };1137 pub const Kind = enum { code, const_data };
9741138
...@@ -1154,7 +1318,8 @@ pub fn spawnLld(...@@ -1154,7 +1318,8 @@ pub fn spawnLld(
1154 switch (term) {1318 switch (term) {
1155 .Exited => |code| if (code != 0) {1319 .Exited => |code| if (code != 0) {
1156 if (comp.clang_passthrough_mode) std.process.exit(code);1320 if (comp.clang_passthrough_mode) std.process.exit(code);
1157 comp.lockAndParseLldStderr(argv[1], stderr);1321 const diags = &comp.link_diags;
1322 diags.lockAndParseLldStderr(argv[1], stderr);
1158 return error.LLDReportedFailure;1323 return error.LLDReportedFailure;
1159 },1324 },
1160 else => {1325 else => {
src/link/Coff.zig+3-2
...@@ -1679,6 +1679,7 @@ pub fn flushModule(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no...@@ -1679,6 +1679,7 @@ pub fn flushModule(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
16791679
1680 const comp = self.base.comp;1680 const comp = self.base.comp;
1681 const gpa = comp.gpa;1681 const gpa = comp.gpa;
1682 const diags = &comp.link_diags;
16821683
1683 if (self.llvm_object) |llvm_object| {1684 if (self.llvm_object) |llvm_object| {
1684 try self.base.emitLlvmObject(arena, llvm_object, prog_node);1685 try self.base.emitLlvmObject(arena, llvm_object, prog_node);
...@@ -1796,10 +1797,10 @@ pub fn flushModule(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no...@@ -1796,10 +1797,10 @@ pub fn flushModule(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
17961797
1797 if (self.entry_addr == null and comp.config.output_mode == .Exe) {1798 if (self.entry_addr == null and comp.config.output_mode == .Exe) {
1798 log.debug("flushing. no_entry_point_found = true\n", .{});1799 log.debug("flushing. no_entry_point_found = true\n", .{});
1799 comp.link_error_flags.no_entry_point_found = true;1800 diags.flags.no_entry_point_found = true;
1800 } else {1801 } else {
1801 log.debug("flushing. no_entry_point_found = false\n", .{});1802 log.debug("flushing. no_entry_point_found = false\n", .{});
1802 comp.link_error_flags.no_entry_point_found = false;1803 diags.flags.no_entry_point_found = false;
1803 try self.writeHeader();1804 try self.writeHeader();
1804 }1805 }
18051806
src/link/Elf.zig+32-33
...@@ -769,6 +769,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod...@@ -769,6 +769,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
769769
770 const comp = self.base.comp;770 const comp = self.base.comp;
771 const gpa = comp.gpa;771 const gpa = comp.gpa;
772 const diags = &comp.link_diags;
772773
773 if (self.llvm_object) |llvm_object| {774 if (self.llvm_object) |llvm_object| {
774 try self.base.emitLlvmObject(arena, llvm_object, prog_node);775 try self.base.emitLlvmObject(arena, llvm_object, prog_node);
...@@ -848,7 +849,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod...@@ -848,7 +849,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
848 }849 }
849850
850 // libc dep851 // libc dep
851 comp.link_error_flags.missing_libc = false;852 diags.flags.missing_libc = false;
852 if (comp.config.link_libc) {853 if (comp.config.link_libc) {
853 if (comp.libc_installation) |lc| {854 if (comp.libc_installation) |lc| {
854 const flags = target_util.libcFullLinkFlags(target);855 const flags = target_util.libcFullLinkFlags(target);
...@@ -868,7 +869,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod...@@ -868,7 +869,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
868 if (try self.accessLibPath(arena, &test_path, &checked_paths, lc.crt_dir.?, lib_name, .static))869 if (try self.accessLibPath(arena, &test_path, &checked_paths, lc.crt_dir.?, lib_name, .static))
869 break :success;870 break :success;
870871
871 try self.reportMissingLibraryError(872 try diags.reportMissingLibraryError(
872 checked_paths.items,873 checked_paths.items,
873 "missing system library: '{s}' was not found",874 "missing system library: '{s}' was not found",
874 .{lib_name},875 .{lib_name},
...@@ -901,7 +902,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod...@@ -901,7 +902,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
901 });902 });
902 try self.parseLibraryReportingFailure(.{ .path = path }, false);903 try self.parseLibraryReportingFailure(.{ .path = path }, false);
903 } else {904 } else {
904 comp.link_error_flags.missing_libc = true;905 diags.flags.missing_libc = true;
905 }906 }
906 }907 }
907908
...@@ -920,7 +921,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod...@@ -920,7 +921,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
920 if (csu.crtend) |path| try parseObjectReportingFailure(self, path);921 if (csu.crtend) |path| try parseObjectReportingFailure(self, path);
921 if (csu.crtn) |path| try parseObjectReportingFailure(self, path);922 if (csu.crtn) |path| try parseObjectReportingFailure(self, path);
922923
923 if (self.base.hasErrors()) return error.FlushFailure;924 if (diags.hasErrors()) return error.FlushFailure;
924925
925 // Dedup shared objects926 // Dedup shared objects
926 {927 {
...@@ -1078,14 +1079,14 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod...@@ -1078,14 +1079,14 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
10781079
1079 if (self.base.isExe() and self.linkerDefinedPtr().?.entry_index == null) {1080 if (self.base.isExe() and self.linkerDefinedPtr().?.entry_index == null) {
1080 log.debug("flushing. no_entry_point_found = true", .{});1081 log.debug("flushing. no_entry_point_found = true", .{});
1081 comp.link_error_flags.no_entry_point_found = true;1082 diags.flags.no_entry_point_found = true;
1082 } else {1083 } else {
1083 log.debug("flushing. no_entry_point_found = false", .{});1084 log.debug("flushing. no_entry_point_found = false", .{});
1084 comp.link_error_flags.no_entry_point_found = false;1085 diags.flags.no_entry_point_found = false;
1085 try self.writeElfHeader();1086 try self.writeElfHeader();
1086 }1087 }
10871088
1088 if (self.base.hasErrors()) return error.FlushFailure;1089 if (diags.hasErrors()) return error.FlushFailure;
1089}1090}
10901091
1091/// --verbose-link output1092/// --verbose-link output
...@@ -1358,7 +1359,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {...@@ -1358,7 +1359,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
1358}1359}
13591360
1360pub const ParseError = error{1361pub const ParseError = error{
1361 /// Indicates the error is already reported on `Compilation.link_errors`.1362 /// Indicates the error is already reported on `Compilation.link_diags`.
1362 LinkFailure,1363 LinkFailure,
13631364
1364 OutOfMemory,1365 OutOfMemory,
...@@ -1484,7 +1485,10 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {...@@ -1484,7 +1485,10 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {
1484 const tracy = trace(@src());1485 const tracy = trace(@src());
1485 defer tracy.end();1486 defer tracy.end();
14861487
1487 const gpa = self.base.comp.gpa;1488 const comp = self.base.comp;
1489 const gpa = comp.gpa;
1490 const diags = &comp.link_diags;
1491
1488 const in_file = try lib.path.root_dir.handle.openFile(lib.path.sub_path, .{});1492 const in_file = try lib.path.root_dir.handle.openFile(lib.path.sub_path, .{});
1489 defer in_file.close();1493 defer in_file.close();
1490 const data = try in_file.readToEndAlloc(gpa, std.math.maxInt(u32));1494 const data = try in_file.readToEndAlloc(gpa, std.math.maxInt(u32));
...@@ -1533,7 +1537,7 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {...@@ -1533,7 +1537,7 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {
1533 }1537 }
1534 }1538 }
15351539
1536 try self.reportMissingLibraryError(1540 try diags.reportMissingLibraryError(
1537 checked_paths.items,1541 checked_paths.items,
1538 "missing library dependency: GNU ld script '{}' requires '{s}', but file not found",1542 "missing library dependency: GNU ld script '{}' requires '{s}', but file not found",
1539 .{ @as(Path, lib.path), script_arg.path },1543 .{ @as(Path, lib.path), script_arg.path },
...@@ -1856,6 +1860,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s...@@ -1856,6 +1860,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
18561860
1857 const comp = self.base.comp;1861 const comp = self.base.comp;
1858 const gpa = comp.gpa;1862 const gpa = comp.gpa;
1863 const diags = &comp.link_diags;
18591864
1860 const directory = self.base.emit.root_dir; // Just an alias to make it shorter to type.1865 const directory = self.base.emit.root_dir; // Just an alias to make it shorter to type.
1861 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});1866 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});
...@@ -2376,7 +2381,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s...@@ -2376,7 +2381,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
2376 }2381 }
23772382
2378 // libc dep2383 // libc dep
2379 comp.link_error_flags.missing_libc = false;2384 diags.flags.missing_libc = false;
2380 if (comp.config.link_libc) {2385 if (comp.config.link_libc) {
2381 if (comp.libc_installation != null) {2386 if (comp.libc_installation != null) {
2382 const needs_grouping = link_mode == .static;2387 const needs_grouping = link_mode == .static;
...@@ -2401,7 +2406,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s...@@ -2401,7 +2406,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
2401 .dynamic => "libc.so",2406 .dynamic => "libc.so",
2402 }));2407 }));
2403 } else {2408 } else {
2404 comp.link_error_flags.missing_libc = true;2409 diags.flags.missing_libc = true;
2405 }2410 }
2406 }2411 }
2407 }2412 }
...@@ -2546,7 +2551,8 @@ fn writePhdrTable(self: *Elf) !void {...@@ -2546,7 +2551,8 @@ fn writePhdrTable(self: *Elf) !void {
2546}2551}
25472552
2548pub fn writeElfHeader(self: *Elf) !void {2553pub fn writeElfHeader(self: *Elf) !void {
2549 if (self.base.hasErrors()) return; // We had errors, so skip flushing to render the output unusable2554 const diags = &self.base.comp.link_diags;
2555 if (diags.hasErrors()) return; // We had errors, so skip flushing to render the output unusable
25502556
2551 const comp = self.base.comp;2557 const comp = self.base.comp;
2552 var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 = undefined;2558 var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 = undefined;
...@@ -3700,6 +3706,7 @@ fn addLoadPhdrs(self: *Elf) error{OutOfMemory}!void {...@@ -3700,6 +3706,7 @@ fn addLoadPhdrs(self: *Elf) error{OutOfMemory}!void {
37003706
3701/// Allocates PHDR table in virtual memory and in file.3707/// Allocates PHDR table in virtual memory and in file.
3702fn allocatePhdrTable(self: *Elf) error{OutOfMemory}!void {3708fn allocatePhdrTable(self: *Elf) error{OutOfMemory}!void {
3709 const diags = &self.base.comp.link_diags;
3703 const phdr_table = &self.phdrs.items[self.phdr_indexes.table.int().?];3710 const phdr_table = &self.phdrs.items[self.phdr_indexes.table.int().?];
3704 const phdr_table_load = &self.phdrs.items[self.phdr_indexes.table_load.int().?];3711 const phdr_table_load = &self.phdrs.items[self.phdr_indexes.table_load.int().?];
37053712
...@@ -3720,7 +3727,7 @@ fn allocatePhdrTable(self: *Elf) error{OutOfMemory}!void {...@@ -3720,7 +3727,7 @@ fn allocatePhdrTable(self: *Elf) error{OutOfMemory}!void {
3720 // (revisit getMaxNumberOfPhdrs())3727 // (revisit getMaxNumberOfPhdrs())
3721 // 2. shift everything in file to free more space for EHDR + PHDR table3728 // 2. shift everything in file to free more space for EHDR + PHDR table
3722 // TODO verify `getMaxNumberOfPhdrs()` is accurate and convert this into no-op3729 // TODO verify `getMaxNumberOfPhdrs()` is accurate and convert this into no-op
3723 var err = try self.base.addErrorWithNotes(1);3730 var err = try diags.addErrorWithNotes(1);
3724 try err.addMsg("fatal linker error: not enough space reserved for EHDR and PHDR table", .{});3731 try err.addMsg("fatal linker error: not enough space reserved for EHDR and PHDR table", .{});
3725 try err.addNote("required 0x{x}, available 0x{x}", .{ needed_size, available_space });3732 try err.addNote("required 0x{x}, available 0x{x}", .{ needed_size, available_space });
3726 }3733 }
...@@ -4855,16 +4862,17 @@ pub fn insertDynString(self: *Elf, name: []const u8) error{OutOfMemory}!u32 {...@@ -4855,16 +4862,17 @@ pub fn insertDynString(self: *Elf, name: []const u8) error{OutOfMemory}!u32 {
48554862
4856fn reportUndefinedSymbols(self: *Elf, undefs: anytype) !void {4863fn reportUndefinedSymbols(self: *Elf, undefs: anytype) !void {
4857 const gpa = self.base.comp.gpa;4864 const gpa = self.base.comp.gpa;
4865 const diags = &self.base.comp.link_diags;
4858 const max_notes = 4;4866 const max_notes = 4;
48594867
4860 try self.base.comp.link_errors.ensureUnusedCapacity(gpa, undefs.count());4868 try diags.msgs.ensureUnusedCapacity(gpa, undefs.count());
48614869
4862 for (undefs.keys(), undefs.values()) |key, refs| {4870 for (undefs.keys(), undefs.values()) |key, refs| {
4863 const undef_sym = self.resolver.keys.items[key - 1];4871 const undef_sym = self.resolver.keys.items[key - 1];
4864 const nrefs = @min(refs.items.len, max_notes);4872 const nrefs = @min(refs.items.len, max_notes);
4865 const nnotes = nrefs + @intFromBool(refs.items.len > max_notes);4873 const nnotes = nrefs + @intFromBool(refs.items.len > max_notes);
48664874
4867 var err = try self.base.addErrorWithNotesAssumeCapacity(nnotes);4875 var err = try diags.addErrorWithNotesAssumeCapacity(nnotes);
4868 try err.addMsg("undefined symbol: {s}", .{undef_sym.name(self)});4876 try err.addMsg("undefined symbol: {s}", .{undef_sym.name(self)});
48694877
4870 for (refs.items[0..nrefs]) |ref| {4878 for (refs.items[0..nrefs]) |ref| {
...@@ -4882,6 +4890,7 @@ fn reportUndefinedSymbols(self: *Elf, undefs: anytype) !void {...@@ -4882,6 +4890,7 @@ fn reportUndefinedSymbols(self: *Elf, undefs: anytype) !void {
48824890
4883fn reportDuplicates(self: *Elf, dupes: anytype) error{ HasDuplicates, OutOfMemory }!void {4891fn reportDuplicates(self: *Elf, dupes: anytype) error{ HasDuplicates, OutOfMemory }!void {
4884 if (dupes.keys().len == 0) return; // Nothing to do4892 if (dupes.keys().len == 0) return; // Nothing to do
4893 const diags = &self.base.comp.link_diags;
48854894
4886 const max_notes = 3;4895 const max_notes = 3;
48874896
...@@ -4889,7 +4898,7 @@ fn reportDuplicates(self: *Elf, dupes: anytype) error{ HasDuplicates, OutOfMemor...@@ -4889,7 +4898,7 @@ fn reportDuplicates(self: *Elf, dupes: anytype) error{ HasDuplicates, OutOfMemor
4889 const sym = self.resolver.keys.items[key - 1];4898 const sym = self.resolver.keys.items[key - 1];
4890 const nnotes = @min(notes.items.len, max_notes) + @intFromBool(notes.items.len > max_notes);4899 const nnotes = @min(notes.items.len, max_notes) + @intFromBool(notes.items.len > max_notes);
48914900
4892 var err = try self.base.addErrorWithNotes(nnotes + 1);4901 var err = try diags.addErrorWithNotes(nnotes + 1);
4893 try err.addMsg("duplicate symbol definition: {s}", .{sym.name(self)});4902 try err.addMsg("duplicate symbol definition: {s}", .{sym.name(self)});
4894 try err.addNote("defined by {}", .{sym.file(self).?.fmtPath()});4903 try err.addNote("defined by {}", .{sym.file(self).?.fmtPath()});
48954904
...@@ -4908,21 +4917,9 @@ fn reportDuplicates(self: *Elf, dupes: anytype) error{ HasDuplicates, OutOfMemor...@@ -4908,21 +4917,9 @@ fn reportDuplicates(self: *Elf, dupes: anytype) error{ HasDuplicates, OutOfMemor
4908 return error.HasDuplicates;4917 return error.HasDuplicates;
4909}4918}
49104919
4911fn reportMissingLibraryError(
4912 self: *Elf,
4913 checked_paths: []const []const u8,
4914 comptime format: []const u8,
4915 args: anytype,
4916) error{OutOfMemory}!void {
4917 var err = try self.base.addErrorWithNotes(checked_paths.len);
4918 try err.addMsg(format, args);
4919 for (checked_paths) |path| {
4920 try err.addNote("tried {s}", .{path});
4921 }
4922}
4923
4924fn reportUnsupportedCpuArch(self: *Elf) error{OutOfMemory}!void {4920fn reportUnsupportedCpuArch(self: *Elf) error{OutOfMemory}!void {
4925 var err = try self.base.addErrorWithNotes(0);4921 const diags = &self.base.comp.link_diags;
4922 var err = try diags.addErrorWithNotes(0);
4926 try err.addMsg("fatal linker error: unsupported CPU architecture {s}", .{4923 try err.addMsg("fatal linker error: unsupported CPU architecture {s}", .{
4927 @tagName(self.getTarget().cpu.arch),4924 @tagName(self.getTarget().cpu.arch),
4928 });4925 });
...@@ -4934,7 +4931,8 @@ pub fn addParseError(...@@ -4934,7 +4931,8 @@ pub fn addParseError(
4934 comptime format: []const u8,4931 comptime format: []const u8,
4935 args: anytype,4932 args: anytype,
4936) error{OutOfMemory}!void {4933) error{OutOfMemory}!void {
4937 var err = try self.base.addErrorWithNotes(1);4934 const diags = &self.base.comp.link_diags;
4935 var err = try diags.addErrorWithNotes(1);
4938 try err.addMsg(format, args);4936 try err.addMsg(format, args);
4939 try err.addNote("while parsing {}", .{path});4937 try err.addNote("while parsing {}", .{path});
4940}4938}
...@@ -4945,7 +4943,8 @@ pub fn addFileError(...@@ -4945,7 +4943,8 @@ pub fn addFileError(
4945 comptime format: []const u8,4943 comptime format: []const u8,
4946 args: anytype,4944 args: anytype,
4947) error{OutOfMemory}!void {4945) error{OutOfMemory}!void {
4948 var err = try self.base.addErrorWithNotes(1);4946 const diags = &self.base.comp.link_diags;
4947 var err = try diags.addErrorWithNotes(1);
4949 try err.addMsg(format, args);4948 try err.addMsg(format, args);
4950 try err.addNote("while parsing {}", .{self.file(file_index).?.fmtPath()});4949 try err.addNote("while parsing {}", .{self.file(file_index).?.fmtPath()});
4951}4950}
src/link/Elf/Atom.zig+20-10
...@@ -519,7 +519,8 @@ fn dataType(symbol: *const Symbol, elf_file: *Elf) u2 {...@@ -519,7 +519,8 @@ fn dataType(symbol: *const Symbol, elf_file: *Elf) u2 {
519}519}
520520
521fn reportUnhandledRelocError(self: Atom, rel: elf.Elf64_Rela, elf_file: *Elf) RelocError!void {521fn reportUnhandledRelocError(self: Atom, rel: elf.Elf64_Rela, elf_file: *Elf) RelocError!void {
522 var err = try elf_file.base.addErrorWithNotes(1);522 const diags = &elf_file.base.comp.link_diags;
523 var err = try diags.addErrorWithNotes(1);
523 try err.addMsg("fatal linker error: unhandled relocation type {} at offset 0x{x}", .{524 try err.addMsg("fatal linker error: unhandled relocation type {} at offset 0x{x}", .{
524 relocation.fmtRelocType(rel.r_type(), elf_file.getTarget().cpu.arch),525 relocation.fmtRelocType(rel.r_type(), elf_file.getTarget().cpu.arch),
525 rel.r_offset,526 rel.r_offset,
...@@ -534,7 +535,8 @@ fn reportTextRelocError(...@@ -534,7 +535,8 @@ fn reportTextRelocError(
534 rel: elf.Elf64_Rela,535 rel: elf.Elf64_Rela,
535 elf_file: *Elf,536 elf_file: *Elf,
536) RelocError!void {537) RelocError!void {
537 var err = try elf_file.base.addErrorWithNotes(1);538 const diags = &elf_file.base.comp.link_diags;
539 var err = try diags.addErrorWithNotes(1);
538 try err.addMsg("relocation at offset 0x{x} against symbol '{s}' cannot be used", .{540 try err.addMsg("relocation at offset 0x{x} against symbol '{s}' cannot be used", .{
539 rel.r_offset,541 rel.r_offset,
540 symbol.name(elf_file),542 symbol.name(elf_file),
...@@ -549,7 +551,8 @@ fn reportPicError(...@@ -549,7 +551,8 @@ fn reportPicError(
549 rel: elf.Elf64_Rela,551 rel: elf.Elf64_Rela,
550 elf_file: *Elf,552 elf_file: *Elf,
551) RelocError!void {553) RelocError!void {
552 var err = try elf_file.base.addErrorWithNotes(2);554 const diags = &elf_file.base.comp.link_diags;
555 var err = try diags.addErrorWithNotes(2);
553 try err.addMsg("relocation at offset 0x{x} against symbol '{s}' cannot be used", .{556 try err.addMsg("relocation at offset 0x{x} against symbol '{s}' cannot be used", .{
554 rel.r_offset,557 rel.r_offset,
555 symbol.name(elf_file),558 symbol.name(elf_file),
...@@ -565,7 +568,8 @@ fn reportNoPicError(...@@ -565,7 +568,8 @@ fn reportNoPicError(
565 rel: elf.Elf64_Rela,568 rel: elf.Elf64_Rela,
566 elf_file: *Elf,569 elf_file: *Elf,
567) RelocError!void {570) RelocError!void {
568 var err = try elf_file.base.addErrorWithNotes(2);571 const diags = &elf_file.base.comp.link_diags;
572 var err = try diags.addErrorWithNotes(2);
569 try err.addMsg("relocation at offset 0x{x} against symbol '{s}' cannot be used", .{573 try err.addMsg("relocation at offset 0x{x} against symbol '{s}' cannot be used", .{
570 rel.r_offset,574 rel.r_offset,
571 symbol.name(elf_file),575 symbol.name(elf_file),
...@@ -1082,6 +1086,7 @@ const x86_64 = struct {...@@ -1082,6 +1086,7 @@ const x86_64 = struct {
1082 stream: anytype,1086 stream: anytype,
1083 ) (error{ InvalidInstruction, CannotEncode } || RelocError)!void {1087 ) (error{ InvalidInstruction, CannotEncode } || RelocError)!void {
1084 dev.check(.x86_64_backend);1088 dev.check(.x86_64_backend);
1089 const diags = &elf_file.base.comp.link_diags;
1085 const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type());1090 const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type());
1086 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;1091 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
10871092
...@@ -1176,7 +1181,7 @@ const x86_64 = struct {...@@ -1176,7 +1181,7 @@ const x86_64 = struct {
1176 try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);1181 try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);
1177 } else {1182 } else {
1178 x86_64.relaxGotPcTlsDesc(code[r_offset - 3 ..]) catch {1183 x86_64.relaxGotPcTlsDesc(code[r_offset - 3 ..]) catch {
1179 var err = try elf_file.base.addErrorWithNotes(1);1184 var err = try diags.addErrorWithNotes(1);
1180 try err.addMsg("could not relax {s}", .{@tagName(r_type)});1185 try err.addMsg("could not relax {s}", .{@tagName(r_type)});
1181 try err.addNote("in {}:{s} at offset 0x{x}", .{1186 try err.addNote("in {}:{s} at offset 0x{x}", .{
1182 atom.file(elf_file).?.fmtPath(),1187 atom.file(elf_file).?.fmtPath(),
...@@ -1301,6 +1306,7 @@ const x86_64 = struct {...@@ -1301,6 +1306,7 @@ const x86_64 = struct {
1301 ) !void {1306 ) !void {
1302 dev.check(.x86_64_backend);1307 dev.check(.x86_64_backend);
1303 assert(rels.len == 2);1308 assert(rels.len == 2);
1309 const diags = &elf_file.base.comp.link_diags;
1304 const writer = stream.writer();1310 const writer = stream.writer();
1305 const rel: elf.R_X86_64 = @enumFromInt(rels[1].r_type());1311 const rel: elf.R_X86_64 = @enumFromInt(rels[1].r_type());
1306 switch (rel) {1312 switch (rel) {
...@@ -1317,7 +1323,7 @@ const x86_64 = struct {...@@ -1317,7 +1323,7 @@ const x86_64 = struct {
1317 },1323 },
13181324
1319 else => {1325 else => {
1320 var err = try elf_file.base.addErrorWithNotes(1);1326 var err = try diags.addErrorWithNotes(1);
1321 try err.addMsg("TODO: rewrite {} when followed by {}", .{1327 try err.addMsg("TODO: rewrite {} when followed by {}", .{
1322 relocation.fmtRelocType(rels[0].r_type(), .x86_64),1328 relocation.fmtRelocType(rels[0].r_type(), .x86_64),
1323 relocation.fmtRelocType(rels[1].r_type(), .x86_64),1329 relocation.fmtRelocType(rels[1].r_type(), .x86_64),
...@@ -1341,6 +1347,7 @@ const x86_64 = struct {...@@ -1341,6 +1347,7 @@ const x86_64 = struct {
1341 ) !void {1347 ) !void {
1342 dev.check(.x86_64_backend);1348 dev.check(.x86_64_backend);
1343 assert(rels.len == 2);1349 assert(rels.len == 2);
1350 const diags = &elf_file.base.comp.link_diags;
1344 const writer = stream.writer();1351 const writer = stream.writer();
1345 const rel: elf.R_X86_64 = @enumFromInt(rels[1].r_type());1352 const rel: elf.R_X86_64 = @enumFromInt(rels[1].r_type());
1346 switch (rel) {1353 switch (rel) {
...@@ -1372,7 +1379,7 @@ const x86_64 = struct {...@@ -1372,7 +1379,7 @@ const x86_64 = struct {
1372 },1379 },
13731380
1374 else => {1381 else => {
1375 var err = try elf_file.base.addErrorWithNotes(1);1382 var err = try diags.addErrorWithNotes(1);
1376 try err.addMsg("TODO: rewrite {} when followed by {}", .{1383 try err.addMsg("TODO: rewrite {} when followed by {}", .{
1377 relocation.fmtRelocType(rels[0].r_type(), .x86_64),1384 relocation.fmtRelocType(rels[0].r_type(), .x86_64),
1378 relocation.fmtRelocType(rels[1].r_type(), .x86_64),1385 relocation.fmtRelocType(rels[1].r_type(), .x86_64),
...@@ -1446,6 +1453,7 @@ const x86_64 = struct {...@@ -1446,6 +1453,7 @@ const x86_64 = struct {
1446 ) !void {1453 ) !void {
1447 dev.check(.x86_64_backend);1454 dev.check(.x86_64_backend);
1448 assert(rels.len == 2);1455 assert(rels.len == 2);
1456 const diags = &elf_file.base.comp.link_diags;
1449 const writer = stream.writer();1457 const writer = stream.writer();
1450 const rel: elf.R_X86_64 = @enumFromInt(rels[1].r_type());1458 const rel: elf.R_X86_64 = @enumFromInt(rels[1].r_type());
1451 switch (rel) {1459 switch (rel) {
...@@ -1468,7 +1476,7 @@ const x86_64 = struct {...@@ -1468,7 +1476,7 @@ const x86_64 = struct {
1468 },1476 },
14691477
1470 else => {1478 else => {
1471 var err = try elf_file.base.addErrorWithNotes(1);1479 var err = try diags.addErrorWithNotes(1);
1472 try err.addMsg("fatal linker error: rewrite {} when followed by {}", .{1480 try err.addMsg("fatal linker error: rewrite {} when followed by {}", .{
1473 relocation.fmtRelocType(rels[0].r_type(), .x86_64),1481 relocation.fmtRelocType(rels[0].r_type(), .x86_64),
1474 relocation.fmtRelocType(rels[1].r_type(), .x86_64),1482 relocation.fmtRelocType(rels[1].r_type(), .x86_64),
...@@ -1603,6 +1611,7 @@ const aarch64 = struct {...@@ -1603,6 +1611,7 @@ const aarch64 = struct {
1603 ) (error{ UnexpectedRemainder, DivisionByZero } || RelocError)!void {1611 ) (error{ UnexpectedRemainder, DivisionByZero } || RelocError)!void {
1604 _ = it;1612 _ = it;
16051613
1614 const diags = &elf_file.base.comp.link_diags;
1606 const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type());1615 const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type());
1607 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;1616 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
1608 const cwriter = stream.writer();1617 const cwriter = stream.writer();
...@@ -1657,7 +1666,7 @@ const aarch64 = struct {...@@ -1657,7 +1666,7 @@ const aarch64 = struct {
1657 aarch64_util.writeAdrpInst(pages, code);1666 aarch64_util.writeAdrpInst(pages, code);
1658 } else {1667 } else {
1659 // TODO: relax1668 // TODO: relax
1660 var err = try elf_file.base.addErrorWithNotes(1);1669 var err = try diags.addErrorWithNotes(1);
1661 try err.addMsg("TODO: relax ADR_GOT_PAGE", .{});1670 try err.addMsg("TODO: relax ADR_GOT_PAGE", .{});
1662 try err.addNote("in {}:{s} at offset 0x{x}", .{1671 try err.addNote("in {}:{s} at offset 0x{x}", .{
1663 atom.file(elf_file).?.fmtPath(),1672 atom.file(elf_file).?.fmtPath(),
...@@ -1882,6 +1891,7 @@ const riscv = struct {...@@ -1882,6 +1891,7 @@ const riscv = struct {
1882 code: []u8,1891 code: []u8,
1883 stream: anytype,1892 stream: anytype,
1884 ) !void {1893 ) !void {
1894 const diags = &elf_file.base.comp.link_diags;
1885 const r_type: elf.R_RISCV = @enumFromInt(rel.r_type());1895 const r_type: elf.R_RISCV = @enumFromInt(rel.r_type());
1886 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;1896 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
1887 const cwriter = stream.writer();1897 const cwriter = stream.writer();
...@@ -1943,7 +1953,7 @@ const riscv = struct {...@@ -1943,7 +1953,7 @@ const riscv = struct {
1943 if (S == atom_addr + @as(i64, @intCast(pair.r_offset))) break pair;1953 if (S == atom_addr + @as(i64, @intCast(pair.r_offset))) break pair;
1944 } else {1954 } else {
1945 // TODO: implement searching forward1955 // TODO: implement searching forward
1946 var err = try elf_file.base.addErrorWithNotes(1);1956 var err = try diags.addErrorWithNotes(1);
1947 try err.addMsg("TODO: find HI20 paired reloc scanning forward", .{});1957 try err.addMsg("TODO: find HI20 paired reloc scanning forward", .{});
1948 try err.addNote("in {}:{s} at offset 0x{x}", .{1958 try err.addNote("in {}:{s} at offset 0x{x}", .{
1949 atom.file(elf_file).?.fmtPath(),1959 atom.file(elf_file).?.fmtPath(),
src/link/Elf/Object.zig+6-4
...@@ -644,6 +644,7 @@ pub fn checkDuplicates(self: *Object, dupes: anytype, elf_file: *Elf) error{OutO...@@ -644,6 +644,7 @@ pub fn checkDuplicates(self: *Object, dupes: anytype, elf_file: *Elf) error{OutO
644644
645pub fn initInputMergeSections(self: *Object, elf_file: *Elf) !void {645pub fn initInputMergeSections(self: *Object, elf_file: *Elf) !void {
646 const gpa = elf_file.base.comp.gpa;646 const gpa = elf_file.base.comp.gpa;
647 const diags = &elf_file.base.comp.link_diags;
647648
648 try self.input_merge_sections.ensureUnusedCapacity(gpa, self.shdrs.items.len);649 try self.input_merge_sections.ensureUnusedCapacity(gpa, self.shdrs.items.len);
649 try self.input_merge_sections_indexes.resize(gpa, self.shdrs.items.len);650 try self.input_merge_sections_indexes.resize(gpa, self.shdrs.items.len);
...@@ -685,7 +686,7 @@ pub fn initInputMergeSections(self: *Object, elf_file: *Elf) !void {...@@ -685,7 +686,7 @@ pub fn initInputMergeSections(self: *Object, elf_file: *Elf) !void {
685 var end = start;686 var end = start;
686 while (end < data.len - sh_entsize and !isNull(data[end .. end + sh_entsize])) : (end += sh_entsize) {}687 while (end < data.len - sh_entsize and !isNull(data[end .. end + sh_entsize])) : (end += sh_entsize) {}
687 if (!isNull(data[end .. end + sh_entsize])) {688 if (!isNull(data[end .. end + sh_entsize])) {
688 var err = try elf_file.base.addErrorWithNotes(1);689 var err = try diags.addErrorWithNotes(1);
689 try err.addMsg("string not null terminated", .{});690 try err.addMsg("string not null terminated", .{});
690 try err.addNote("in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) });691 try err.addNote("in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) });
691 return error.LinkFailure;692 return error.LinkFailure;
...@@ -700,7 +701,7 @@ pub fn initInputMergeSections(self: *Object, elf_file: *Elf) !void {...@@ -700,7 +701,7 @@ pub fn initInputMergeSections(self: *Object, elf_file: *Elf) !void {
700 const sh_entsize: u32 = @intCast(shdr.sh_entsize);701 const sh_entsize: u32 = @intCast(shdr.sh_entsize);
701 if (sh_entsize == 0) continue; // Malformed, don't split but don't error out702 if (sh_entsize == 0) continue; // Malformed, don't split but don't error out
702 if (shdr.sh_size % sh_entsize != 0) {703 if (shdr.sh_size % sh_entsize != 0) {
703 var err = try elf_file.base.addErrorWithNotes(1);704 var err = try diags.addErrorWithNotes(1);
704 try err.addMsg("size not a multiple of sh_entsize", .{});705 try err.addMsg("size not a multiple of sh_entsize", .{});
705 try err.addNote("in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) });706 try err.addNote("in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) });
706 return error.LinkFailure;707 return error.LinkFailure;
...@@ -738,6 +739,7 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) error{...@@ -738,6 +739,7 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) error{
738 Overflow,739 Overflow,
739}!void {740}!void {
740 const gpa = elf_file.base.comp.gpa;741 const gpa = elf_file.base.comp.gpa;
742 const diags = &elf_file.base.comp.link_diags;
741743
742 for (self.input_merge_sections_indexes.items) |index| {744 for (self.input_merge_sections_indexes.items) |index| {
743 const imsec = self.inputMergeSection(index) orelse continue;745 const imsec = self.inputMergeSection(index) orelse continue;
...@@ -776,7 +778,7 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) error{...@@ -776,7 +778,7 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) error{
776 const imsec = self.inputMergeSection(imsec_index) orelse continue;778 const imsec = self.inputMergeSection(imsec_index) orelse continue;
777 if (imsec.offsets.items.len == 0) continue;779 if (imsec.offsets.items.len == 0) continue;
778 const res = imsec.findSubsection(@intCast(esym.st_value)) orelse {780 const res = imsec.findSubsection(@intCast(esym.st_value)) orelse {
779 var err = try elf_file.base.addErrorWithNotes(2);781 var err = try diags.addErrorWithNotes(2);
780 try err.addMsg("invalid symbol value: {x}", .{esym.st_value});782 try err.addMsg("invalid symbol value: {x}", .{esym.st_value});
781 try err.addNote("for symbol {s}", .{sym.name(elf_file)});783 try err.addNote("for symbol {s}", .{sym.name(elf_file)});
782 try err.addNote("in {}", .{self.fmtPath()});784 try err.addNote("in {}", .{self.fmtPath()});
...@@ -802,7 +804,7 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) error{...@@ -802,7 +804,7 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) error{
802 if (imsec.offsets.items.len == 0) continue;804 if (imsec.offsets.items.len == 0) continue;
803 const msec = elf_file.mergeSection(imsec.merge_section_index);805 const msec = elf_file.mergeSection(imsec.merge_section_index);
804 const res = imsec.findSubsection(@intCast(@as(i64, @intCast(esym.st_value)) + rel.r_addend)) orelse {806 const res = imsec.findSubsection(@intCast(@as(i64, @intCast(esym.st_value)) + rel.r_addend)) orelse {
805 var err = try elf_file.base.addErrorWithNotes(1);807 var err = try diags.addErrorWithNotes(1);
806 try err.addMsg("invalid relocation at offset 0x{x}", .{rel.r_offset});808 try err.addMsg("invalid relocation at offset 0x{x}", .{rel.r_offset});
807 try err.addNote("in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) });809 try err.addNote("in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) });
808 return error.LinkFailure;810 return error.LinkFailure;
src/link/Elf/eh_frame.zig+2-1
...@@ -611,7 +611,8 @@ const riscv = struct {...@@ -611,7 +611,8 @@ const riscv = struct {
611};611};
612612
613fn reportInvalidReloc(rec: anytype, elf_file: *Elf, rel: elf.Elf64_Rela) !void {613fn reportInvalidReloc(rec: anytype, elf_file: *Elf, rel: elf.Elf64_Rela) !void {
614 var err = try elf_file.base.addErrorWithNotes(1);614 const diags = &elf_file.base.comp.link_diags;
615 var err = try diags.addErrorWithNotes(1);
615 try err.addMsg("invalid relocation type {} at offset 0x{x}", .{616 try err.addMsg("invalid relocation type {} at offset 0x{x}", .{
616 relocation.fmtRelocType(rel.r_type(), elf_file.getTarget().cpu.arch),617 relocation.fmtRelocType(rel.r_type(), elf_file.getTarget().cpu.arch),
617 rel.r_offset,618 rel.r_offset,
src/link/Elf/relocatable.zig+7-4
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?Path) link.File.FlushError!void {1pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?Path) link.File.FlushError!void {
2 const gpa = comp.gpa;2 const gpa = comp.gpa;
3 const diags = &comp.link_diags;
34
4 for (comp.objects) |obj| {5 for (comp.objects) |obj| {
5 switch (Compilation.classifyFileExt(obj.path.sub_path)) {6 switch (Compilation.classifyFileExt(obj.path.sub_path)) {
...@@ -21,7 +22,7 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?Path...@@ -21,7 +22,7 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?Path
21 try parseObjectStaticLibReportingFailure(elf_file, comp.compiler_rt_obj.?.full_object_path);22 try parseObjectStaticLibReportingFailure(elf_file, comp.compiler_rt_obj.?.full_object_path);
22 }23 }
2324
24 if (elf_file.base.hasErrors()) return error.FlushFailure;25 if (diags.hasErrors()) return error.FlushFailure;
2526
26 // First, we flush relocatable object file generated with our backends.27 // First, we flush relocatable object file generated with our backends.
27 if (elf_file.zigObjectPtr()) |zig_object| {28 if (elf_file.zigObjectPtr()) |zig_object| {
...@@ -146,10 +147,12 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?Path...@@ -146,10 +147,12 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?Path
146 try elf_file.base.file.?.setEndPos(total_size);147 try elf_file.base.file.?.setEndPos(total_size);
147 try elf_file.base.file.?.pwriteAll(buffer.items, 0);148 try elf_file.base.file.?.pwriteAll(buffer.items, 0);
148149
149 if (elf_file.base.hasErrors()) return error.FlushFailure;150 if (diags.hasErrors()) return error.FlushFailure;
150}151}
151152
152pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?Path) link.File.FlushError!void {153pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?Path) link.File.FlushError!void {
154 const diags = &comp.link_diags;
155
153 for (comp.objects) |obj| {156 for (comp.objects) |obj| {
154 if (obj.isObject()) {157 if (obj.isObject()) {
155 try elf_file.parseObjectReportingFailure(obj.path);158 try elf_file.parseObjectReportingFailure(obj.path);
...@@ -167,7 +170,7 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?Path) l...@@ -167,7 +170,7 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?Path) l
167170
168 if (module_obj_path) |path| try elf_file.parseObjectReportingFailure(path);171 if (module_obj_path) |path| try elf_file.parseObjectReportingFailure(path);
169172
170 if (elf_file.base.hasErrors()) return error.FlushFailure;173 if (diags.hasErrors()) return error.FlushFailure;
171174
172 // Now, we are ready to resolve the symbols across all input files.175 // Now, we are ready to resolve the symbols across all input files.
173 // We will first resolve the files in the ZigObject, next in the parsed176 // We will first resolve the files in the ZigObject, next in the parsed
...@@ -213,7 +216,7 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?Path) l...@@ -213,7 +216,7 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?Path) l
213 try elf_file.writeShdrTable();216 try elf_file.writeShdrTable();
214 try elf_file.writeElfHeader();217 try elf_file.writeElfHeader();
215218
216 if (elf_file.base.hasErrors()) return error.FlushFailure;219 if (diags.hasErrors()) return error.FlushFailure;
217}220}
218221
219fn parseObjectStaticLibReportingFailure(elf_file: *Elf, path: Path) error{OutOfMemory}!void {222fn parseObjectStaticLibReportingFailure(elf_file: *Elf, path: Path) error{OutOfMemory}!void {
src/link/MachO.zig+80-119
...@@ -100,7 +100,6 @@ debug_rnglists_sect_index: ?u8 = null,...@@ -100,7 +100,6 @@ debug_rnglists_sect_index: ?u8 = null,
100has_tlv: AtomicBool = AtomicBool.init(false),100has_tlv: AtomicBool = AtomicBool.init(false),
101binds_to_weak: AtomicBool = AtomicBool.init(false),101binds_to_weak: AtomicBool = AtomicBool.init(false),
102weak_defines: AtomicBool = AtomicBool.init(false),102weak_defines: AtomicBool = AtomicBool.init(false),
103has_errors: AtomicBool = AtomicBool.init(false),
104103
105/// Options104/// Options
106/// SDK layout105/// SDK layout
...@@ -347,6 +346,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n...@@ -347,6 +346,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
347346
348 const comp = self.base.comp;347 const comp = self.base.comp;
349 const gpa = comp.gpa;348 const gpa = comp.gpa;
349 const diags = &self.base.comp.link_diags;
350350
351 if (self.llvm_object) |llvm_object| {351 if (self.llvm_object) |llvm_object| {
352 try self.base.emitLlvmObject(arena, llvm_object, prog_node);352 try self.base.emitLlvmObject(arena, llvm_object, prog_node);
...@@ -397,8 +397,8 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n...@@ -397,8 +397,8 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
397397
398 for (positionals.items) |obj| {398 for (positionals.items) |obj| {
399 self.classifyInputFile(obj.path, .{ .path = obj.path }, obj.must_link) catch |err| switch (err) {399 self.classifyInputFile(obj.path, .{ .path = obj.path }, obj.must_link) catch |err| switch (err) {
400 error.UnknownFileType => try self.reportParseError(obj.path, "unknown file type for an input file", .{}),400 error.UnknownFileType => try diags.reportParseError(obj.path, "unknown file type for an input file", .{}),
401 else => |e| try self.reportParseError(401 else => |e| try diags.reportParseError(
402 obj.path,402 obj.path,
403 "unexpected error: reading input file failed with error {s}",403 "unexpected error: reading input file failed with error {s}",
404 .{@errorName(e)},404 .{@errorName(e)},
...@@ -444,8 +444,8 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n...@@ -444,8 +444,8 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
444444
445 for (system_libs.items) |lib| {445 for (system_libs.items) |lib| {
446 self.classifyInputFile(lib.path, lib, false) catch |err| switch (err) {446 self.classifyInputFile(lib.path, lib, false) catch |err| switch (err) {
447 error.UnknownFileType => try self.reportParseError(lib.path, "unknown file type for an input file", .{}),447 error.UnknownFileType => try diags.reportParseError(lib.path, "unknown file type for an input file", .{}),
448 else => |e| try self.reportParseError(448 else => |e| try diags.reportParseError(
449 lib.path,449 lib.path,
450 "unexpected error: parsing input file failed with error {s}",450 "unexpected error: parsing input file failed with error {s}",
451 .{@errorName(e)},451 .{@errorName(e)},
...@@ -461,8 +461,8 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n...@@ -461,8 +461,8 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
461 };461 };
462 if (compiler_rt_path) |path| {462 if (compiler_rt_path) |path| {
463 self.classifyInputFile(path, .{ .path = path }, false) catch |err| switch (err) {463 self.classifyInputFile(path, .{ .path = path }, false) catch |err| switch (err) {
464 error.UnknownFileType => try self.reportParseError(path, "unknown file type for an input file", .{}),464 error.UnknownFileType => try diags.reportParseError(path, "unknown file type for an input file", .{}),
465 else => |e| try self.reportParseError(465 else => |e| try diags.reportParseError(
466 path,466 path,
467 "unexpected error: parsing input file failed with error {s}",467 "unexpected error: parsing input file failed with error {s}",
468 .{@errorName(e)},468 .{@errorName(e)},
...@@ -474,14 +474,11 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n...@@ -474,14 +474,11 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
474 self.parseDependentDylibs() catch |err| {474 self.parseDependentDylibs() catch |err| {
475 switch (err) {475 switch (err) {
476 error.MissingLibraryDependencies => {},476 error.MissingLibraryDependencies => {},
477 else => |e| try self.reportUnexpectedError(477 else => |e| return diags.fail("failed to parse dependent libraries: {s}", .{@errorName(e)}),
478 "unexpected error while parsing dependent libraries: {s}",
479 .{@errorName(e)},
480 ),
481 }478 }
482 };479 };
483480
484 if (self.base.hasErrors()) return error.FlushFailure;481 if (diags.hasErrors()) return error.FlushFailure;
485482
486 {483 {
487 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));484 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
...@@ -502,10 +499,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n...@@ -502,10 +499,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
502499
503 self.checkDuplicates() catch |err| switch (err) {500 self.checkDuplicates() catch |err| switch (err) {
504 error.HasDuplicates => return error.FlushFailure,501 error.HasDuplicates => return error.FlushFailure,
505 else => |e| {502 else => |e| return diags.fail("failed to check for duplicate symbol definitions: {s}", .{@errorName(e)}),
506 try self.reportUnexpectedError("unexpected error while checking for duplicate symbol definitions", .{});
507 return e;
508 },
509 };503 };
510504
511 self.markImportsAndExports();505 self.markImportsAndExports();
...@@ -520,10 +514,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n...@@ -520,10 +514,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
520514
521 self.scanRelocs() catch |err| switch (err) {515 self.scanRelocs() catch |err| switch (err) {
522 error.HasUndefinedSymbols => return error.FlushFailure,516 error.HasUndefinedSymbols => return error.FlushFailure,
523 else => |e| {517 else => |e| return diags.fail("failed to scan relocations: {s}", .{@errorName(e)}),
524 try self.reportUnexpectedError("unexpected error while scanning relocations", .{});
525 return e;
526 },
527 };518 };
528519
529 try self.initOutputSections();520 try self.initOutputSections();
...@@ -784,6 +775,8 @@ pub fn resolveLibSystem(...@@ -784,6 +775,8 @@ pub fn resolveLibSystem(
784 comp: *Compilation,775 comp: *Compilation,
785 out_libs: anytype,776 out_libs: anytype,
786) !void {777) !void {
778 const diags = &self.base.comp.link_diags;
779
787 var test_path = std.ArrayList(u8).init(arena);780 var test_path = std.ArrayList(u8).init(arena);
788 var checked_paths = std.ArrayList([]const u8).init(arena);781 var checked_paths = std.ArrayList([]const u8).init(arena);
789782
...@@ -803,7 +796,7 @@ pub fn resolveLibSystem(...@@ -803,7 +796,7 @@ pub fn resolveLibSystem(
803 if (try accessLibPath(arena, &test_path, &checked_paths, dir, "System")) break :success;796 if (try accessLibPath(arena, &test_path, &checked_paths, dir, "System")) break :success;
804 }797 }
805798
806 try self.reportMissingLibraryError(checked_paths.items, "unable to find libSystem system library", .{});799 try diags.reportMissingLibraryError(checked_paths.items, "unable to find libSystem system library", .{});
807 return error.MissingLibSystem;800 return error.MissingLibSystem;
808 }801 }
809802
...@@ -845,6 +838,7 @@ pub fn classifyInputFile(self: *MachO, path: Path, lib: SystemLib, must_link: bo...@@ -845,6 +838,7 @@ pub fn classifyInputFile(self: *MachO, path: Path, lib: SystemLib, must_link: bo
845}838}
846839
847fn parseFatFile(self: *MachO, file: std.fs.File, path: Path) !?fat.Arch {840fn parseFatFile(self: *MachO, file: std.fs.File, path: Path) !?fat.Arch {
841 const diags = &self.base.comp.link_diags;
848 const fat_h = fat.readFatHeader(file) catch return null;842 const fat_h = fat.readFatHeader(file) catch return null;
849 if (fat_h.magic != macho.FAT_MAGIC and fat_h.magic != macho.FAT_MAGIC_64) return null;843 if (fat_h.magic != macho.FAT_MAGIC and fat_h.magic != macho.FAT_MAGIC_64) return null;
850 var fat_archs_buffer: [2]fat.Arch = undefined;844 var fat_archs_buffer: [2]fat.Arch = undefined;
...@@ -853,7 +847,7 @@ fn parseFatFile(self: *MachO, file: std.fs.File, path: Path) !?fat.Arch {...@@ -853,7 +847,7 @@ fn parseFatFile(self: *MachO, file: std.fs.File, path: Path) !?fat.Arch {
853 for (fat_archs) |arch| {847 for (fat_archs) |arch| {
854 if (arch.tag == cpu_arch) return arch;848 if (arch.tag == cpu_arch) return arch;
855 }849 }
856 try self.reportParseError(path, "missing arch in universal file: expected {s}", .{850 try diags.reportParseError(path, "missing arch in universal file: expected {s}", .{
857 @tagName(cpu_arch),851 @tagName(cpu_arch),
858 });852 });
859 return error.MissingCpuArch;853 return error.MissingCpuArch;
...@@ -901,6 +895,7 @@ pub fn parseInputFiles(self: *MachO) !void {...@@ -901,6 +895,7 @@ pub fn parseInputFiles(self: *MachO) !void {
901 const tracy = trace(@src());895 const tracy = trace(@src());
902 defer tracy.end();896 defer tracy.end();
903897
898 const diags = &self.base.comp.link_diags;
904 const tp = self.base.comp.thread_pool;899 const tp = self.base.comp.thread_pool;
905 var wg: WaitGroup = .{};900 var wg: WaitGroup = .{};
906901
...@@ -916,7 +911,7 @@ pub fn parseInputFiles(self: *MachO) !void {...@@ -916,7 +911,7 @@ pub fn parseInputFiles(self: *MachO) !void {
916 }911 }
917 }912 }
918913
919 if (self.has_errors.swap(false, .seq_cst)) return error.FlushFailure;914 if (diags.hasErrors()) return error.LinkFailure;
920}915}
921916
922fn parseInputFileWorker(self: *MachO, file: File) void {917fn parseInputFileWorker(self: *MachO, file: File) void {
...@@ -928,9 +923,9 @@ fn parseInputFileWorker(self: *MachO, file: File) void {...@@ -928,9 +923,9 @@ fn parseInputFileWorker(self: *MachO, file: File) void {
928 error.InvalidMachineType,923 error.InvalidMachineType,
929 error.InvalidTarget,924 error.InvalidTarget,
930 => {}, // already reported925 => {}, // already reported
926
931 else => |e| self.reportParseError2(file.getIndex(), "unexpected error: parsing input file failed with error {s}", .{@errorName(e)}) catch {},927 else => |e| self.reportParseError2(file.getIndex(), "unexpected error: parsing input file failed with error {s}", .{@errorName(e)}) catch {},
932 }928 }
933 _ = self.has_errors.swap(true, .seq_cst);
934 };929 };
935}930}
936931
...@@ -1296,6 +1291,7 @@ fn markLive(self: *MachO) void {...@@ -1296,6 +1291,7 @@ fn markLive(self: *MachO) void {
12961291
1297fn convertTentativeDefsAndResolveSpecialSymbols(self: *MachO) !void {1292fn convertTentativeDefsAndResolveSpecialSymbols(self: *MachO) !void {
1298 const tp = self.base.comp.thread_pool;1293 const tp = self.base.comp.thread_pool;
1294 const diags = &self.base.comp.link_diags;
1299 var wg: WaitGroup = .{};1295 var wg: WaitGroup = .{};
1300 {1296 {
1301 wg.reset();1297 wg.reset();
...@@ -1307,7 +1303,7 @@ fn convertTentativeDefsAndResolveSpecialSymbols(self: *MachO) !void {...@@ -1307,7 +1303,7 @@ fn convertTentativeDefsAndResolveSpecialSymbols(self: *MachO) !void {
1307 tp.spawnWg(&wg, resolveSpecialSymbolsWorker, .{ self, obj });1303 tp.spawnWg(&wg, resolveSpecialSymbolsWorker, .{ self, obj });
1308 }1304 }
1309 }1305 }
1310 if (self.has_errors.swap(false, .seq_cst)) return error.FlushFailure;1306 if (diags.hasErrors()) return error.LinkFailure;
1311}1307}
13121308
1313fn convertTentativeDefinitionsWorker(self: *MachO, object: *Object) void {1309fn convertTentativeDefinitionsWorker(self: *MachO, object: *Object) void {
...@@ -1319,26 +1315,19 @@ fn convertTentativeDefinitionsWorker(self: *MachO, object: *Object) void {...@@ -1319,26 +1315,19 @@ fn convertTentativeDefinitionsWorker(self: *MachO, object: *Object) void {
1319 "unexpected error occurred while converting tentative symbols into defined symbols: {s}",1315 "unexpected error occurred while converting tentative symbols into defined symbols: {s}",
1320 .{@errorName(err)},1316 .{@errorName(err)},
1321 ) catch {};1317 ) catch {};
1322 _ = self.has_errors.swap(true, .seq_cst);
1323 };1318 };
1324}1319}
13251320
1326fn resolveSpecialSymbolsWorker(self: *MachO, obj: *InternalObject) void {1321fn resolveSpecialSymbolsWorker(self: *MachO, obj: *InternalObject) void {
1327 const tracy = trace(@src());1322 const tracy = trace(@src());
1328 defer tracy.end();1323 defer tracy.end();
1329 obj.resolveBoundarySymbols(self) catch |err| {1324
1330 self.reportUnexpectedError("unexpected error occurred while resolving boundary symbols: {s}", .{1325 const diags = &self.base.comp.link_diags;
1331 @errorName(err),1326
1332 }) catch {};1327 obj.resolveBoundarySymbols(self) catch |err|
1333 _ = self.has_errors.swap(true, .seq_cst);1328 return diags.addError("failed to resolve boundary symbols: {s}", .{@errorName(err)});
1334 return;1329 obj.resolveObjcMsgSendSymbols(self) catch |err|
1335 };1330 return diags.addError("failed to resolve ObjC msgsend stubs: {s}", .{@errorName(err)});
1336 obj.resolveObjcMsgSendSymbols(self) catch |err| {
1337 self.reportUnexpectedError("unexpected error occurred while resolving ObjC msgsend stubs: {s}", .{
1338 @errorName(err),
1339 }) catch {};
1340 _ = self.has_errors.swap(true, .seq_cst);
1341 };
1342}1331}
13431332
1344pub fn dedupLiterals(self: *MachO) !void {1333pub fn dedupLiterals(self: *MachO) !void {
...@@ -1390,6 +1379,8 @@ fn checkDuplicates(self: *MachO) !void {...@@ -1390,6 +1379,8 @@ fn checkDuplicates(self: *MachO) !void {
1390 defer tracy.end();1379 defer tracy.end();
13911380
1392 const tp = self.base.comp.thread_pool;1381 const tp = self.base.comp.thread_pool;
1382 const diags = &self.base.comp.link_diags;
1383
1393 var wg: WaitGroup = .{};1384 var wg: WaitGroup = .{};
1394 {1385 {
1395 wg.reset();1386 wg.reset();
...@@ -1405,7 +1396,7 @@ fn checkDuplicates(self: *MachO) !void {...@@ -1405,7 +1396,7 @@ fn checkDuplicates(self: *MachO) !void {
1405 }1396 }
1406 }1397 }
14071398
1408 if (self.has_errors.swap(false, .seq_cst)) return error.FlushFailure;1399 if (diags.hasErrors()) return error.LinkFailure;
14091400
1410 try self.reportDuplicates();1401 try self.reportDuplicates();
1411}1402}
...@@ -1417,7 +1408,6 @@ fn checkDuplicatesWorker(self: *MachO, file: File) void {...@@ -1417,7 +1408,6 @@ fn checkDuplicatesWorker(self: *MachO, file: File) void {
1417 self.reportParseError2(file.getIndex(), "failed to check for duplicate definitions: {s}", .{1408 self.reportParseError2(file.getIndex(), "failed to check for duplicate definitions: {s}", .{
1418 @errorName(err),1409 @errorName(err),
1419 }) catch {};1410 }) catch {};
1420 _ = self.has_errors.swap(true, .seq_cst);
1421 };1411 };
1422}1412}
14231413
...@@ -1460,6 +1450,8 @@ fn scanRelocs(self: *MachO) !void {...@@ -1460,6 +1450,8 @@ fn scanRelocs(self: *MachO) !void {
1460 defer tracy.end();1450 defer tracy.end();
14611451
1462 const tp = self.base.comp.thread_pool;1452 const tp = self.base.comp.thread_pool;
1453 const diags = &self.base.comp.link_diags;
1454
1463 var wg: WaitGroup = .{};1455 var wg: WaitGroup = .{};
14641456
1465 {1457 {
...@@ -1477,7 +1469,7 @@ fn scanRelocs(self: *MachO) !void {...@@ -1477,7 +1469,7 @@ fn scanRelocs(self: *MachO) !void {
1477 }1469 }
1478 }1470 }
14791471
1480 if (self.has_errors.swap(false, .seq_cst)) return error.FlushFailure;1472 if (diags.hasErrors()) return error.LinkFailure;
14811473
1482 if (self.getInternalObject()) |obj| {1474 if (self.getInternalObject()) |obj| {
1483 try obj.checkUndefs(self);1475 try obj.checkUndefs(self);
...@@ -1503,7 +1495,6 @@ fn scanRelocsWorker(self: *MachO, file: File) void {...@@ -1503,7 +1495,6 @@ fn scanRelocsWorker(self: *MachO, file: File) void {
1503 self.reportParseError2(file.getIndex(), "failed to scan relocations: {s}", .{1495 self.reportParseError2(file.getIndex(), "failed to scan relocations: {s}", .{
1504 @errorName(err),1496 @errorName(err),
1505 }) catch {};1497 }) catch {};
1506 _ = self.has_errors.swap(true, .seq_cst);
1507 };1498 };
1508}1499}
15091500
...@@ -1527,6 +1518,7 @@ fn reportUndefs(self: *MachO) !void {...@@ -1527,6 +1518,7 @@ fn reportUndefs(self: *MachO) !void {
1527 if (self.undefs.keys().len == 0) return; // Nothing to do1518 if (self.undefs.keys().len == 0) return; // Nothing to do
15281519
1529 const gpa = self.base.comp.gpa;1520 const gpa = self.base.comp.gpa;
1521 const diags = &self.base.comp.link_diags;
1530 const max_notes = 4;1522 const max_notes = 4;
15311523
1532 // We will sort by name, and then by file to ensure deterministic output.1524 // We will sort by name, and then by file to ensure deterministic output.
...@@ -1558,7 +1550,7 @@ fn reportUndefs(self: *MachO) !void {...@@ -1558,7 +1550,7 @@ fn reportUndefs(self: *MachO) !void {
1558 break :nnotes @min(nnotes, max_notes) + @intFromBool(nnotes > max_notes);1550 break :nnotes @min(nnotes, max_notes) + @intFromBool(nnotes > max_notes);
1559 };1551 };
15601552
1561 var err = try self.base.addErrorWithNotes(nnotes);1553 var err = try diags.addErrorWithNotes(nnotes);
1562 try err.addMsg("undefined symbol: {s}", .{undef_sym.getName(self)});1554 try err.addMsg("undefined symbol: {s}", .{undef_sym.getName(self)});
15631555
1564 switch (notes) {1556 switch (notes) {
...@@ -1908,6 +1900,7 @@ fn calcSectionSizes(self: *MachO) !void {...@@ -1908,6 +1900,7 @@ fn calcSectionSizes(self: *MachO) !void {
1908 const tracy = trace(@src());1900 const tracy = trace(@src());
1909 defer tracy.end();1901 defer tracy.end();
19101902
1903 const diags = &self.base.comp.link_diags;
1911 const cpu_arch = self.getTarget().cpu.arch;1904 const cpu_arch = self.getTarget().cpu.arch;
19121905
1913 if (self.data_sect_index) |idx| {1906 if (self.data_sect_index) |idx| {
...@@ -1951,7 +1944,7 @@ fn calcSectionSizes(self: *MachO) !void {...@@ -1951,7 +1944,7 @@ fn calcSectionSizes(self: *MachO) !void {
1951 }1944 }
1952 }1945 }
19531946
1954 if (self.has_errors.swap(false, .seq_cst)) return error.FlushFailure;1947 if (diags.hasErrors()) return error.LinkFailure;
19551948
1956 try self.calcSymtabSize();1949 try self.calcSymtabSize();
19571950
...@@ -2003,6 +1996,9 @@ fn calcSectionSizes(self: *MachO) !void {...@@ -2003,6 +1996,9 @@ fn calcSectionSizes(self: *MachO) !void {
2003fn calcSectionSizeWorker(self: *MachO, sect_id: u8) void {1996fn calcSectionSizeWorker(self: *MachO, sect_id: u8) void {
2004 const tracy = trace(@src());1997 const tracy = trace(@src());
2005 defer tracy.end();1998 defer tracy.end();
1999
2000 const diags = &self.base.comp.link_diags;
2001
2006 const doWork = struct {2002 const doWork = struct {
2007 fn doWork(macho_file: *MachO, header: *macho.section_64, atoms: []const Ref) !void {2003 fn doWork(macho_file: *MachO, header: *macho.section_64, atoms: []const Ref) !void {
2008 for (atoms) |ref| {2004 for (atoms) |ref| {
...@@ -2020,26 +2016,21 @@ fn calcSectionSizeWorker(self: *MachO, sect_id: u8) void {...@@ -2020,26 +2016,21 @@ fn calcSectionSizeWorker(self: *MachO, sect_id: u8) void {
2020 const header = &slice.items(.header)[sect_id];2016 const header = &slice.items(.header)[sect_id];
2021 const atoms = slice.items(.atoms)[sect_id].items;2017 const atoms = slice.items(.atoms)[sect_id].items;
2022 doWork(self, header, atoms) catch |err| {2018 doWork(self, header, atoms) catch |err| {
2023 self.reportUnexpectedError("failed to calculate size of section '{s},{s}': {s}", .{2019 try diags.addError("failed to calculate size of section '{s},{s}': {s}", .{
2024 header.segName(),2020 header.segName(), header.sectName(), @errorName(err),
2025 header.sectName(),2021 });
2026 @errorName(err),
2027 }) catch {};
2028 _ = self.has_errors.swap(true, .seq_cst);
2029 };2022 };
2030}2023}
20312024
2032fn createThunksWorker(self: *MachO, sect_id: u8) void {2025fn createThunksWorker(self: *MachO, sect_id: u8) void {
2033 const tracy = trace(@src());2026 const tracy = trace(@src());
2034 defer tracy.end();2027 defer tracy.end();
2028 const diags = &self.base.comp.link_diags;
2035 self.createThunks(sect_id) catch |err| {2029 self.createThunks(sect_id) catch |err| {
2036 const header = self.sections.items(.header)[sect_id];2030 const header = self.sections.items(.header)[sect_id];
2037 self.reportUnexpectedError("failed to create thunks and calculate size of section '{s},{s}': {s}", .{2031 diags.addError("failed to create thunks and calculate size of section '{s},{s}': {s}", .{
2038 header.segName(),2032 header.segName(), header.sectName(), @errorName(err),
2039 header.sectName(),2033 });
2040 @errorName(err),
2041 }) catch {};
2042 _ = self.has_errors.swap(true, .seq_cst);
2043 };2034 };
2044}2035}
20452036
...@@ -2047,6 +2038,8 @@ fn generateUnwindInfo(self: *MachO) !void {...@@ -2047,6 +2038,8 @@ fn generateUnwindInfo(self: *MachO) !void {
2047 const tracy = trace(@src());2038 const tracy = trace(@src());
2048 defer tracy.end();2039 defer tracy.end();
20492040
2041 const diags = &self.base.comp.link_diags;
2042
2050 if (self.eh_frame_sect_index) |index| {2043 if (self.eh_frame_sect_index) |index| {
2051 const sect = &self.sections.items(.header)[index];2044 const sect = &self.sections.items(.header)[index];
2052 sect.size = try eh_frame.calcSize(self);2045 sect.size = try eh_frame.calcSize(self);
...@@ -2055,10 +2048,7 @@ fn generateUnwindInfo(self: *MachO) !void {...@@ -2055,10 +2048,7 @@ fn generateUnwindInfo(self: *MachO) !void {
2055 if (self.unwind_info_sect_index) |index| {2048 if (self.unwind_info_sect_index) |index| {
2056 const sect = &self.sections.items(.header)[index];2049 const sect = &self.sections.items(.header)[index];
2057 self.unwind_info.generate(self) catch |err| switch (err) {2050 self.unwind_info.generate(self) catch |err| switch (err) {
2058 error.TooManyPersonalities => return self.reportUnexpectedError(2051 error.TooManyPersonalities => return diags.fail("too many personalities in unwind info", .{}),
2059 "too many personalities in unwind info",
2060 .{},
2061 ),
2062 else => |e| return e,2052 else => |e| return e,
2063 };2053 };
2064 sect.size = self.unwind_info.calcSize();2054 sect.size = self.unwind_info.calcSize();
...@@ -2427,6 +2417,7 @@ fn writeSectionsAndUpdateLinkeditSizes(self: *MachO) !void {...@@ -2427,6 +2417,7 @@ fn writeSectionsAndUpdateLinkeditSizes(self: *MachO) !void {
2427 defer tracy.end();2417 defer tracy.end();
24282418
2429 const gpa = self.base.comp.gpa;2419 const gpa = self.base.comp.gpa;
2420 const diags = &self.base.comp.link_diags;
24302421
2431 const cmd = self.symtab_cmd;2422 const cmd = self.symtab_cmd;
2432 try self.symtab.resize(gpa, cmd.nsyms);2423 try self.symtab.resize(gpa, cmd.nsyms);
...@@ -2495,7 +2486,7 @@ fn writeSectionsAndUpdateLinkeditSizes(self: *MachO) !void {...@@ -2495,7 +2486,7 @@ fn writeSectionsAndUpdateLinkeditSizes(self: *MachO) !void {
2495 };2486 };
2496 }2487 }
24972488
2498 if (self.has_errors.swap(false, .seq_cst)) return error.FlushFailure;2489 if (diags.hasErrors()) return error.LinkFailure;
2499}2490}
25002491
2501fn writeAtomsWorker(self: *MachO, file: File) void {2492fn writeAtomsWorker(self: *MachO, file: File) void {
...@@ -2505,13 +2496,15 @@ fn writeAtomsWorker(self: *MachO, file: File) void {...@@ -2505,13 +2496,15 @@ fn writeAtomsWorker(self: *MachO, file: File) void {
2505 self.reportParseError2(file.getIndex(), "failed to resolve relocations and write atoms: {s}", .{2496 self.reportParseError2(file.getIndex(), "failed to resolve relocations and write atoms: {s}", .{
2506 @errorName(err),2497 @errorName(err),
2507 }) catch {};2498 }) catch {};
2508 _ = self.has_errors.swap(true, .seq_cst);
2509 };2499 };
2510}2500}
25112501
2512fn writeThunkWorker(self: *MachO, thunk: Thunk) void {2502fn writeThunkWorker(self: *MachO, thunk: Thunk) void {
2513 const tracy = trace(@src());2503 const tracy = trace(@src());
2514 defer tracy.end();2504 defer tracy.end();
2505
2506 const diags = &self.base.comp.link_diags;
2507
2515 const doWork = struct {2508 const doWork = struct {
2516 fn doWork(th: Thunk, buffer: []u8, macho_file: *MachO) !void {2509 fn doWork(th: Thunk, buffer: []u8, macho_file: *MachO) !void {
2517 const off = math.cast(usize, th.value) orelse return error.Overflow;2510 const off = math.cast(usize, th.value) orelse return error.Overflow;
...@@ -2522,8 +2515,7 @@ fn writeThunkWorker(self: *MachO, thunk: Thunk) void {...@@ -2522,8 +2515,7 @@ fn writeThunkWorker(self: *MachO, thunk: Thunk) void {
2522 }.doWork;2515 }.doWork;
2523 const out = self.sections.items(.out)[thunk.out_n_sect].items;2516 const out = self.sections.items(.out)[thunk.out_n_sect].items;
2524 doWork(thunk, out, self) catch |err| {2517 doWork(thunk, out, self) catch |err| {
2525 self.reportUnexpectedError("failed to write contents of thunk: {s}", .{@errorName(err)}) catch {};2518 diags.addError("failed to write contents of thunk: {s}", .{@errorName(err)});
2526 _ = self.has_errors.swap(true, .seq_cst);
2527 };2519 };
2528}2520}
25292521
...@@ -2531,6 +2523,8 @@ fn writeSyntheticSectionWorker(self: *MachO, sect_id: u8, out: []u8) void {...@@ -2531,6 +2523,8 @@ fn writeSyntheticSectionWorker(self: *MachO, sect_id: u8, out: []u8) void {
2531 const tracy = trace(@src());2523 const tracy = trace(@src());
2532 defer tracy.end();2524 defer tracy.end();
25332525
2526 const diags = &self.base.comp.link_diags;
2527
2534 const Tag = enum {2528 const Tag = enum {
2535 eh_frame,2529 eh_frame,
2536 unwind_info,2530 unwind_info,
...@@ -2575,18 +2569,18 @@ fn writeSyntheticSectionWorker(self: *MachO, sect_id: u8, out: []u8) void {...@@ -2575,18 +2569,18 @@ fn writeSyntheticSectionWorker(self: *MachO, sect_id: u8, out: []u8) void {
2575 unreachable;2569 unreachable;
2576 };2570 };
2577 doWork(self, tag, out) catch |err| {2571 doWork(self, tag, out) catch |err| {
2578 self.reportUnexpectedError("could not write section '{s},{s}': {s}", .{2572 diags.addError("could not write section '{s},{s}': {s}", .{
2579 header.segName(),2573 header.segName(), header.sectName(), @errorName(err),
2580 header.sectName(),2574 });
2581 @errorName(err),
2582 }) catch {};
2583 _ = self.has_errors.swap(true, .seq_cst);
2584 };2575 };
2585}2576}
25862577
2587fn updateLazyBindSizeWorker(self: *MachO) void {2578fn updateLazyBindSizeWorker(self: *MachO) void {
2588 const tracy = trace(@src());2579 const tracy = trace(@src());
2589 defer tracy.end();2580 defer tracy.end();
2581
2582 const diags = &self.base.comp.link_diags;
2583
2590 const doWork = struct {2584 const doWork = struct {
2591 fn doWork(macho_file: *MachO) !void {2585 fn doWork(macho_file: *MachO) !void {
2592 try macho_file.lazy_bind_section.updateSize(macho_file);2586 try macho_file.lazy_bind_section.updateSize(macho_file);
...@@ -2596,12 +2590,8 @@ fn updateLazyBindSizeWorker(self: *MachO) void {...@@ -2596,12 +2590,8 @@ fn updateLazyBindSizeWorker(self: *MachO) void {
2596 try macho_file.stubs_helper.write(macho_file, stream.writer());2590 try macho_file.stubs_helper.write(macho_file, stream.writer());
2597 }2591 }
2598 }.doWork;2592 }.doWork;
2599 doWork(self) catch |err| {2593 doWork(self) catch |err|
2600 self.reportUnexpectedError("could not calculate size of lazy binding section: {s}", .{2594 diags.addError("could not calculate size of lazy binding section: {s}", .{@errorName(err)});
2601 @errorName(err),
2602 }) catch {};
2603 _ = self.has_errors.swap(true, .seq_cst);
2604 };
2605}2595}
26062596
2607pub fn updateLinkeditSizeWorker(self: *MachO, tag: enum {2597pub fn updateLinkeditSizeWorker(self: *MachO, tag: enum {
...@@ -2611,6 +2601,7 @@ pub fn updateLinkeditSizeWorker(self: *MachO, tag: enum {...@@ -2611,6 +2601,7 @@ pub fn updateLinkeditSizeWorker(self: *MachO, tag: enum {
2611 export_trie,2601 export_trie,
2612 data_in_code,2602 data_in_code,
2613}) void {2603}) void {
2604 const diags = &self.base.comp.link_diags;
2614 const res = switch (tag) {2605 const res = switch (tag) {
2615 .rebase => self.rebase_section.updateSize(self),2606 .rebase => self.rebase_section.updateSize(self),
2616 .bind => self.bind_section.updateSize(self),2607 .bind => self.bind_section.updateSize(self),
...@@ -2618,13 +2609,8 @@ pub fn updateLinkeditSizeWorker(self: *MachO, tag: enum {...@@ -2618,13 +2609,8 @@ pub fn updateLinkeditSizeWorker(self: *MachO, tag: enum {
2618 .export_trie => self.export_trie.updateSize(self),2609 .export_trie => self.export_trie.updateSize(self),
2619 .data_in_code => self.data_in_code.updateSize(self),2610 .data_in_code => self.data_in_code.updateSize(self),
2620 };2611 };
2621 res catch |err| {2612 res catch |err|
2622 self.reportUnexpectedError("could not calculate size of {s} section: {s}", .{2613 diags.addError("could not calculate size of {s} section: {s}", .{ @tagName(tag), @errorName(err) });
2623 @tagName(tag),
2624 @errorName(err),
2625 }) catch {};
2626 _ = self.has_errors.swap(true, .seq_cst);
2627 };
2628}2614}
26292615
2630fn writeSectionsToFile(self: *MachO) !void {2616fn writeSectionsToFile(self: *MachO) !void {
...@@ -3432,6 +3418,7 @@ pub fn growSection(self: *MachO, sect_index: u8, needed_size: u64) !void {...@@ -3432,6 +3418,7 @@ pub fn growSection(self: *MachO, sect_index: u8, needed_size: u64) !void {
3432}3418}
34333419
3434fn growSectionNonRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !void {3420fn growSectionNonRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !void {
3421 const diags = &self.base.comp.link_diags;
3435 const sect = &self.sections.items(.header)[sect_index];3422 const sect = &self.sections.items(.header)[sect_index];
34363423
3437 const seg_id = self.sections.items(.segment_id)[sect_index];3424 const seg_id = self.sections.items(.segment_id)[sect_index];
...@@ -3467,7 +3454,7 @@ fn growSectionNonRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !vo...@@ -3467,7 +3454,7 @@ fn growSectionNonRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !vo
34673454
3468 const mem_capacity = self.allocatedSizeVirtual(seg.vmaddr);3455 const mem_capacity = self.allocatedSizeVirtual(seg.vmaddr);
3469 if (needed_size > mem_capacity) {3456 if (needed_size > mem_capacity) {
3470 var err = try self.base.addErrorWithNotes(2);3457 var err = try diags.addErrorWithNotes(2);
3471 try err.addMsg("fatal linker error: cannot expand segment seg({d})({s}) in virtual memory", .{3458 try err.addMsg("fatal linker error: cannot expand segment seg({d})({s}) in virtual memory", .{
3472 seg_id,3459 seg_id,
3473 seg.segName(),3460 seg.segName(),
...@@ -3766,41 +3753,18 @@ pub fn eatPrefix(path: []const u8, prefix: []const u8) ?[]const u8 {...@@ -3766,41 +3753,18 @@ pub fn eatPrefix(path: []const u8, prefix: []const u8) ?[]const u8 {
3766 return null;3753 return null;
3767}3754}
37683755
3769pub fn reportParseError(
3770 self: *MachO,
3771 path: Path,
3772 comptime format: []const u8,
3773 args: anytype,
3774) error{OutOfMemory}!void {
3775 var err = try self.base.addErrorWithNotes(1);
3776 try err.addMsg(format, args);
3777 try err.addNote("while parsing {}", .{path});
3778}
3779
3780pub fn reportParseError2(3756pub fn reportParseError2(
3781 self: *MachO,3757 self: *MachO,
3782 file_index: File.Index,3758 file_index: File.Index,
3783 comptime format: []const u8,3759 comptime format: []const u8,
3784 args: anytype,3760 args: anytype,
3785) error{OutOfMemory}!void {3761) error{OutOfMemory}!void {
3786 var err = try self.base.addErrorWithNotes(1);3762 const diags = &self.base.comp.link_diags;
3763 var err = try diags.addErrorWithNotes(1);
3787 try err.addMsg(format, args);3764 try err.addMsg(format, args);
3788 try err.addNote("while parsing {}", .{self.getFile(file_index).?.fmtPath()});3765 try err.addNote("while parsing {}", .{self.getFile(file_index).?.fmtPath()});
3789}3766}
37903767
3791fn reportMissingLibraryError(
3792 self: *MachO,
3793 checked_paths: []const []const u8,
3794 comptime format: []const u8,
3795 args: anytype,
3796) error{OutOfMemory}!void {
3797 var err = try self.base.addErrorWithNotes(checked_paths.len);
3798 try err.addMsg(format, args);
3799 for (checked_paths) |path| {
3800 try err.addNote("tried {s}", .{path});
3801 }
3802}
3803
3804fn reportMissingDependencyError(3768fn reportMissingDependencyError(
3805 self: *MachO,3769 self: *MachO,
3806 parent: File.Index,3770 parent: File.Index,
...@@ -3809,7 +3773,8 @@ fn reportMissingDependencyError(...@@ -3809,7 +3773,8 @@ fn reportMissingDependencyError(
3809 comptime format: []const u8,3773 comptime format: []const u8,
3810 args: anytype,3774 args: anytype,
3811) error{OutOfMemory}!void {3775) error{OutOfMemory}!void {
3812 var err = try self.base.addErrorWithNotes(2 + checked_paths.len);3776 const diags = &self.base.comp.link_diags;
3777 var err = try diags.addErrorWithNotes(2 + checked_paths.len);
3813 try err.addMsg(format, args);3778 try err.addMsg(format, args);
3814 try err.addNote("while resolving {s}", .{path});3779 try err.addNote("while resolving {s}", .{path});
3815 try err.addNote("a dependency of {}", .{self.getFile(parent).?.fmtPath()});3780 try err.addNote("a dependency of {}", .{self.getFile(parent).?.fmtPath()});
...@@ -3825,18 +3790,13 @@ fn reportDependencyError(...@@ -3825,18 +3790,13 @@ fn reportDependencyError(
3825 comptime format: []const u8,3790 comptime format: []const u8,
3826 args: anytype,3791 args: anytype,
3827) error{OutOfMemory}!void {3792) error{OutOfMemory}!void {
3828 var err = try self.base.addErrorWithNotes(2);3793 const diags = &self.base.comp.link_diags;
3794 var err = try diags.addErrorWithNotes(2);
3829 try err.addMsg(format, args);3795 try err.addMsg(format, args);
3830 try err.addNote("while parsing {s}", .{path});3796 try err.addNote("while parsing {s}", .{path});
3831 try err.addNote("a dependency of {}", .{self.getFile(parent).?.fmtPath()});3797 try err.addNote("a dependency of {}", .{self.getFile(parent).?.fmtPath()});
3832}3798}
38333799
3834pub fn reportUnexpectedError(self: *MachO, comptime format: []const u8, args: anytype) error{OutOfMemory}!void {
3835 var err = try self.base.addErrorWithNotes(1);
3836 try err.addMsg(format, args);
3837 try err.addNote("please report this as a linker bug on https://github.com/ziglang/zig/issues/new/choose", .{});
3838}
3839
3840fn reportDuplicates(self: *MachO) error{ HasDuplicates, OutOfMemory }!void {3800fn reportDuplicates(self: *MachO) error{ HasDuplicates, OutOfMemory }!void {
3841 const tracy = trace(@src());3801 const tracy = trace(@src());
3842 defer tracy.end();3802 defer tracy.end();
...@@ -3844,6 +3804,7 @@ fn reportDuplicates(self: *MachO) error{ HasDuplicates, OutOfMemory }!void {...@@ -3844,6 +3804,7 @@ fn reportDuplicates(self: *MachO) error{ HasDuplicates, OutOfMemory }!void {
3844 if (self.dupes.keys().len == 0) return; // Nothing to do3804 if (self.dupes.keys().len == 0) return; // Nothing to do
38453805
3846 const gpa = self.base.comp.gpa;3806 const gpa = self.base.comp.gpa;
3807 const diags = &self.base.comp.link_diags;
3847 const max_notes = 3;3808 const max_notes = 3;
38483809
3849 // We will sort by name, and then by file to ensure deterministic output.3810 // We will sort by name, and then by file to ensure deterministic output.
...@@ -3861,7 +3822,7 @@ fn reportDuplicates(self: *MachO) error{ HasDuplicates, OutOfMemory }!void {...@@ -3861,7 +3822,7 @@ fn reportDuplicates(self: *MachO) error{ HasDuplicates, OutOfMemory }!void {
3861 const notes = self.dupes.get(key).?;3822 const notes = self.dupes.get(key).?;
3862 const nnotes = @min(notes.items.len, max_notes) + @intFromBool(notes.items.len > max_notes);3823 const nnotes = @min(notes.items.len, max_notes) + @intFromBool(notes.items.len > max_notes);
38633824
3864 var err = try self.base.addErrorWithNotes(nnotes + 1);3825 var err = try diags.addErrorWithNotes(nnotes + 1);
3865 try err.addMsg("duplicate symbol definition: {s}", .{sym.getName(self)});3826 try err.addMsg("duplicate symbol definition: {s}", .{sym.getName(self)});
3866 try err.addNote("defined by {}", .{sym.getFile(self).?.fmtPath()});3827 try err.addNote("defined by {}", .{sym.getFile(self).?.fmtPath()});
38673828
src/link/MachO/Archive.zig+2-1
...@@ -6,6 +6,7 @@ pub fn deinit(self: *Archive, allocator: Allocator) void {...@@ -6,6 +6,7 @@ pub fn deinit(self: *Archive, allocator: Allocator) void {
66
7pub fn unpack(self: *Archive, macho_file: *MachO, path: Path, handle_index: File.HandleIndex, fat_arch: ?fat.Arch) !void {7pub fn unpack(self: *Archive, macho_file: *MachO, path: Path, handle_index: File.HandleIndex, fat_arch: ?fat.Arch) !void {
8 const gpa = macho_file.base.comp.gpa;8 const gpa = macho_file.base.comp.gpa;
9 const diags = &macho_file.base.comp.link_diags;
910
10 var arena = std.heap.ArenaAllocator.init(gpa);11 var arena = std.heap.ArenaAllocator.init(gpa);
11 defer arena.deinit();12 defer arena.deinit();
...@@ -28,7 +29,7 @@ pub fn unpack(self: *Archive, macho_file: *MachO, path: Path, handle_index: File...@@ -28,7 +29,7 @@ pub fn unpack(self: *Archive, macho_file: *MachO, path: Path, handle_index: File
28 pos += @sizeOf(ar_hdr);29 pos += @sizeOf(ar_hdr);
2930
30 if (!mem.eql(u8, &hdr.ar_fmag, ARFMAG)) {31 if (!mem.eql(u8, &hdr.ar_fmag, ARFMAG)) {
31 try macho_file.reportParseError(path, "invalid header delimiter: expected '{s}', found '{s}'", .{32 try diags.reportParseError(path, "invalid header delimiter: expected '{s}', found '{s}'", .{
32 std.fmt.fmtSliceEscapeLower(ARFMAG), std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag),33 std.fmt.fmtSliceEscapeLower(ARFMAG), std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag),
33 });34 });
34 return error.MalformedArchive;35 return error.MalformedArchive;
src/link/MachO/Atom.zig+2-1
...@@ -893,6 +893,7 @@ fn resolveRelocInner(...@@ -893,6 +893,7 @@ fn resolveRelocInner(
893const x86_64 = struct {893const x86_64 = struct {
894 fn relaxGotLoad(self: Atom, code: []u8, rel: Relocation, macho_file: *MachO) ResolveError!void {894 fn relaxGotLoad(self: Atom, code: []u8, rel: Relocation, macho_file: *MachO) ResolveError!void {
895 dev.check(.x86_64_backend);895 dev.check(.x86_64_backend);
896 const diags = &macho_file.base.comp.link_diags;
896 const old_inst = disassemble(code) orelse return error.RelaxFail;897 const old_inst = disassemble(code) orelse return error.RelaxFail;
897 switch (old_inst.encoding.mnemonic) {898 switch (old_inst.encoding.mnemonic) {
898 .mov => {899 .mov => {
...@@ -901,7 +902,7 @@ const x86_64 = struct {...@@ -901,7 +902,7 @@ const x86_64 = struct {
901 encode(&.{inst}, code) catch return error.RelaxFail;902 encode(&.{inst}, code) catch return error.RelaxFail;
902 },903 },
903 else => |x| {904 else => |x| {
904 var err = try macho_file.base.addErrorWithNotes(2);905 var err = try diags.addErrorWithNotes(2);
905 try err.addMsg("{s}: 0x{x}: 0x{x}: failed to relax relocation of type {}", .{906 try err.addMsg("{s}: 0x{x}: 0x{x}: failed to relax relocation of type {}", .{
906 self.getName(macho_file),907 self.getName(macho_file),
907 self.getAddress(macho_file),908 self.getAddress(macho_file),
src/link/MachO/ZigObject.zig+12-29
...@@ -364,6 +364,8 @@ pub fn scanRelocs(self: *ZigObject, macho_file: *MachO) !void {...@@ -364,6 +364,8 @@ pub fn scanRelocs(self: *ZigObject, macho_file: *MachO) !void {
364364
365pub fn resolveRelocs(self: *ZigObject, macho_file: *MachO) !void {365pub fn resolveRelocs(self: *ZigObject, macho_file: *MachO) !void {
366 const gpa = macho_file.base.comp.gpa;366 const gpa = macho_file.base.comp.gpa;
367 const diags = &macho_file.base.comp.link_diags;
368
367 var has_error = false;369 var has_error = false;
368 for (self.getAtoms()) |atom_index| {370 for (self.getAtoms()) |atom_index| {
369 const atom = self.getAtom(atom_index) orelse continue;371 const atom = self.getAtom(atom_index) orelse continue;
...@@ -379,17 +381,12 @@ pub fn resolveRelocs(self: *ZigObject, macho_file: *MachO) !void {...@@ -379,17 +381,12 @@ pub fn resolveRelocs(self: *ZigObject, macho_file: *MachO) !void {
379 defer gpa.free(code);381 defer gpa.free(code);
380 self.getAtomData(macho_file, atom.*, code) catch |err| {382 self.getAtomData(macho_file, atom.*, code) catch |err| {
381 switch (err) {383 switch (err) {
382 error.InputOutput => {384 error.InputOutput => return diags.fail("fetching code for '{s}' failed", .{
383 try macho_file.reportUnexpectedError("fetching code for '{s}' failed", .{385 atom.getName(macho_file),
384 atom.getName(macho_file),386 }),
385 });387 else => |e| return diags.fail("failed to fetch code for '{s}': {s}", .{
386 },388 atom.getName(macho_file), @errorName(e),
387 else => |e| {389 }),
388 try macho_file.reportUnexpectedError("unexpected error while fetching code for '{s}': {s}", .{
389 atom.getName(macho_file),
390 @errorName(e),
391 });
392 },
393 }390 }
394 has_error = true;391 has_error = true;
395 continue;392 continue;
...@@ -398,9 +395,7 @@ pub fn resolveRelocs(self: *ZigObject, macho_file: *MachO) !void {...@@ -398,9 +395,7 @@ pub fn resolveRelocs(self: *ZigObject, macho_file: *MachO) !void {
398 atom.resolveRelocs(macho_file, code) catch |err| {395 atom.resolveRelocs(macho_file, code) catch |err| {
399 switch (err) {396 switch (err) {
400 error.ResolveFailed => {},397 error.ResolveFailed => {},
401 else => |e| {398 else => |e| return diags.fail("failed to resolve relocations: {s}", .{@errorName(e)}),
402 try macho_file.reportUnexpectedError("unexpected error while resolving relocations: {s}", .{@errorName(e)});
403 },
404 }399 }
405 has_error = true;400 has_error = true;
406 continue;401 continue;
...@@ -426,6 +421,7 @@ pub fn calcNumRelocs(self: *ZigObject, macho_file: *MachO) void {...@@ -426,6 +421,7 @@ pub fn calcNumRelocs(self: *ZigObject, macho_file: *MachO) void {
426421
427pub fn writeRelocs(self: *ZigObject, macho_file: *MachO) !void {422pub fn writeRelocs(self: *ZigObject, macho_file: *MachO) !void {
428 const gpa = macho_file.base.comp.gpa;423 const gpa = macho_file.base.comp.gpa;
424 const diags = &macho_file.base.comp.link_diags;
429425
430 for (self.getAtoms()) |atom_index| {426 for (self.getAtoms()) |atom_index| {
431 const atom = self.getAtom(atom_index) orelse continue;427 const atom = self.getAtom(atom_index) orelse continue;
...@@ -439,21 +435,8 @@ pub fn writeRelocs(self: *ZigObject, macho_file: *MachO) !void {...@@ -439,21 +435,8 @@ pub fn writeRelocs(self: *ZigObject, macho_file: *MachO) !void {
439 const atom_size = std.math.cast(usize, atom.size) orelse return error.Overflow;435 const atom_size = std.math.cast(usize, atom.size) orelse return error.Overflow;
440 const code = try gpa.alloc(u8, atom_size);436 const code = try gpa.alloc(u8, atom_size);
441 defer gpa.free(code);437 defer gpa.free(code);
442 self.getAtomData(macho_file, atom.*, code) catch |err| switch (err) {438 self.getAtomData(macho_file, atom.*, code) catch |err|
443 error.InputOutput => {439 return diags.fail("failed to fetch code for '{s}': {s}", .{ atom.getName(macho_file), @errorName(err) });
444 try macho_file.reportUnexpectedError("fetching code for '{s}' failed", .{
445 atom.getName(macho_file),
446 });
447 return error.FlushFailure;
448 },
449 else => |e| {
450 try macho_file.reportUnexpectedError("unexpected error while fetching code for '{s}': {s}", .{
451 atom.getName(macho_file),
452 @errorName(e),
453 });
454 return error.FlushFailure;
455 },
456 };
457 const file_offset = header.offset + atom.value;440 const file_offset = header.offset + atom.value;
458 try atom.writeRelocs(macho_file, code, relocs[extra.rel_out_index..][0..extra.rel_out_count]);441 try atom.writeRelocs(macho_file, code, relocs[extra.rel_out_index..][0..extra.rel_out_count]);
459 try macho_file.base.file.?.pwriteAll(code, file_offset);442 try macho_file.base.file.?.pwriteAll(code, file_offset);
src/link/MachO/relocatable.zig+28-30
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Path) link.File.FlushError!void {1pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Path) link.File.FlushError!void {
2 const gpa = macho_file.base.comp.gpa;2 const gpa = macho_file.base.comp.gpa;
3 const diags = &macho_file.base.comp.link_diags;
34
4 // TODO: "positional arguments" is a CLI concept, not a linker concept. Delete this unnecessary array list.5 // TODO: "positional arguments" is a CLI concept, not a linker concept. Delete this unnecessary array list.
5 var positionals = std.ArrayList(Compilation.LinkObject).init(gpa);6 var positionals = std.ArrayList(Compilation.LinkObject).init(gpa);
...@@ -29,8 +30,8 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat...@@ -29,8 +30,8 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat
2930
30 for (positionals.items) |obj| {31 for (positionals.items) |obj| {
31 macho_file.classifyInputFile(obj.path, .{ .path = obj.path }, obj.must_link) catch |err| switch (err) {32 macho_file.classifyInputFile(obj.path, .{ .path = obj.path }, obj.must_link) catch |err| switch (err) {
32 error.UnknownFileType => try macho_file.reportParseError(obj.path, "unknown file type for an input file", .{}),33 error.UnknownFileType => try diags.reportParseError(obj.path, "unknown file type for an input file", .{}),
33 else => |e| try macho_file.reportParseError(34 else => |e| try diags.reportParseError(
34 obj.path,35 obj.path,
35 "unexpected error: reading input file failed with error {s}",36 "unexpected error: reading input file failed with error {s}",
36 .{@errorName(e)},37 .{@errorName(e)},
...@@ -38,11 +39,11 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat...@@ -38,11 +39,11 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat
38 };39 };
39 }40 }
4041
41 if (macho_file.base.hasErrors()) return error.FlushFailure;42 if (diags.hasErrors()) return error.FlushFailure;
4243
43 try macho_file.parseInputFiles();44 try macho_file.parseInputFiles();
4445
45 if (macho_file.base.hasErrors()) return error.FlushFailure;46 if (diags.hasErrors()) return error.FlushFailure;
4647
47 try macho_file.resolveSymbols();48 try macho_file.resolveSymbols();
48 try macho_file.dedupLiterals();49 try macho_file.dedupLiterals();
...@@ -75,6 +76,7 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat...@@ -75,6 +76,7 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat
7576
76pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Path) link.File.FlushError!void {77pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Path) link.File.FlushError!void {
77 const gpa = comp.gpa;78 const gpa = comp.gpa;
79 const diags = &macho_file.base.comp.link_diags;
7880
79 var positionals = std.ArrayList(Compilation.LinkObject).init(gpa);81 var positionals = std.ArrayList(Compilation.LinkObject).init(gpa);
80 defer positionals.deinit();82 defer positionals.deinit();
...@@ -94,8 +96,8 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?...@@ -94,8 +96,8 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
9496
95 for (positionals.items) |obj| {97 for (positionals.items) |obj| {
96 macho_file.classifyInputFile(obj.path, .{ .path = obj.path }, obj.must_link) catch |err| switch (err) {98 macho_file.classifyInputFile(obj.path, .{ .path = obj.path }, obj.must_link) catch |err| switch (err) {
97 error.UnknownFileType => try macho_file.reportParseError(obj.path, "unknown file type for an input file", .{}),99 error.UnknownFileType => try diags.reportParseError(obj.path, "unknown file type for an input file", .{}),
98 else => |e| try macho_file.reportParseError(100 else => |e| try diags.reportParseError(
99 obj.path,101 obj.path,
100 "unexpected error: reading input file failed with error {s}",102 "unexpected error: reading input file failed with error {s}",
101 .{@errorName(e)},103 .{@errorName(e)},
...@@ -103,11 +105,11 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?...@@ -103,11 +105,11 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
103 };105 };
104 }106 }
105107
106 if (macho_file.base.hasErrors()) return error.FlushFailure;108 if (diags.hasErrors()) return error.FlushFailure;
107109
108 try parseInputFilesAr(macho_file);110 try parseInputFilesAr(macho_file);
109111
110 if (macho_file.base.hasErrors()) return error.FlushFailure;112 if (diags.hasErrors()) return error.FlushFailure;
111113
112 // First, we flush relocatable object file generated with our backends.114 // First, we flush relocatable object file generated with our backends.
113 if (macho_file.getZigObject()) |zo| {115 if (macho_file.getZigObject()) |zo| {
...@@ -228,7 +230,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?...@@ -228,7 +230,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
228 try macho_file.base.file.?.setEndPos(total_size);230 try macho_file.base.file.?.setEndPos(total_size);
229 try macho_file.base.file.?.pwriteAll(buffer.items, 0);231 try macho_file.base.file.?.pwriteAll(buffer.items, 0);
230232
231 if (macho_file.base.hasErrors()) return error.FlushFailure;233 if (diags.hasErrors()) return error.FlushFailure;
232}234}
233235
234fn parseInputFilesAr(macho_file: *MachO) !void {236fn parseInputFilesAr(macho_file: *MachO) !void {
...@@ -293,6 +295,8 @@ fn calcSectionSizes(macho_file: *MachO) !void {...@@ -293,6 +295,8 @@ fn calcSectionSizes(macho_file: *MachO) !void {
293 const tracy = trace(@src());295 const tracy = trace(@src());
294 defer tracy.end();296 defer tracy.end();
295297
298 const diags = &macho_file.base.comp.link_diags;
299
296 if (macho_file.getZigObject()) |zo| {300 if (macho_file.getZigObject()) |zo| {
297 // TODO this will create a race as we need to track merging of debug sections which we currently don't301 // TODO this will create a race as we need to track merging of debug sections which we currently don't
298 zo.calcNumRelocs(macho_file);302 zo.calcNumRelocs(macho_file);
...@@ -337,7 +341,7 @@ fn calcSectionSizes(macho_file: *MachO) !void {...@@ -337,7 +341,7 @@ fn calcSectionSizes(macho_file: *MachO) !void {
337 }341 }
338 try calcSymtabSize(macho_file);342 try calcSymtabSize(macho_file);
339343
340 if (macho_file.has_errors.swap(false, .seq_cst)) return error.FlushFailure;344 if (diags.hasErrors()) return error.LinkFailure;
341}345}
342346
343fn calcSectionSizeWorker(macho_file: *MachO, sect_id: u8) void {347fn calcSectionSizeWorker(macho_file: *MachO, sect_id: u8) void {
...@@ -365,6 +369,8 @@ fn calcEhFrameSizeWorker(macho_file: *MachO) void {...@@ -365,6 +369,8 @@ fn calcEhFrameSizeWorker(macho_file: *MachO) void {
365 const tracy = trace(@src());369 const tracy = trace(@src());
366 defer tracy.end();370 defer tracy.end();
367371
372 const diags = &macho_file.base.comp.link_diags;
373
368 const doWork = struct {374 const doWork = struct {
369 fn doWork(mfile: *MachO, header: *macho.section_64) !void {375 fn doWork(mfile: *MachO, header: *macho.section_64) !void {
370 header.size = try eh_frame.calcSize(mfile);376 header.size = try eh_frame.calcSize(mfile);
...@@ -374,12 +380,8 @@ fn calcEhFrameSizeWorker(macho_file: *MachO) void {...@@ -374,12 +380,8 @@ fn calcEhFrameSizeWorker(macho_file: *MachO) void {
374 }.doWork;380 }.doWork;
375381
376 const header = &macho_file.sections.items(.header)[macho_file.eh_frame_sect_index.?];382 const header = &macho_file.sections.items(.header)[macho_file.eh_frame_sect_index.?];
377 doWork(macho_file, header) catch |err| {383 doWork(macho_file, header) catch |err|
378 macho_file.reportUnexpectedError("failed to calculate size of section '__TEXT,__eh_frame': {s}", .{384 diags.addError("failed to calculate size of section '__TEXT,__eh_frame': {s}", .{@errorName(err)});
379 @errorName(err),
380 }) catch {};
381 _ = macho_file.has_errors.swap(true, .seq_cst);
382 };
383}385}
384386
385fn calcCompactUnwindSize(macho_file: *MachO) void {387fn calcCompactUnwindSize(macho_file: *MachO) void {
...@@ -592,6 +594,7 @@ fn writeSections(macho_file: *MachO) !void {...@@ -592,6 +594,7 @@ fn writeSections(macho_file: *MachO) !void {
592 defer tracy.end();594 defer tracy.end();
593595
594 const gpa = macho_file.base.comp.gpa;596 const gpa = macho_file.base.comp.gpa;
597 const diags = &macho_file.base.comp.link_diags;
595 const cpu_arch = macho_file.getTarget().cpu.arch;598 const cpu_arch = macho_file.getTarget().cpu.arch;
596 const slice = macho_file.sections.slice();599 const slice = macho_file.sections.slice();
597 for (slice.items(.header), slice.items(.out), slice.items(.relocs), 0..) |header, *out, *relocs, n_sect| {600 for (slice.items(.header), slice.items(.out), slice.items(.relocs), 0..) |header, *out, *relocs, n_sect| {
...@@ -637,7 +640,7 @@ fn writeSections(macho_file: *MachO) !void {...@@ -637,7 +640,7 @@ fn writeSections(macho_file: *MachO) !void {
637 }640 }
638 }641 }
639642
640 if (macho_file.has_errors.swap(false, .seq_cst)) return error.FlushFailure;643 if (diags.hasErrors()) return error.LinkFailure;
641644
642 if (macho_file.getZigObject()) |zo| {645 if (macho_file.getZigObject()) |zo| {
643 try zo.writeRelocs(macho_file);646 try zo.writeRelocs(macho_file);
...@@ -651,33 +654,28 @@ fn writeAtomsWorker(macho_file: *MachO, file: File) void {...@@ -651,33 +654,28 @@ fn writeAtomsWorker(macho_file: *MachO, file: File) void {
651 macho_file.reportParseError2(file.getIndex(), "failed to write atoms: {s}", .{654 macho_file.reportParseError2(file.getIndex(), "failed to write atoms: {s}", .{
652 @errorName(err),655 @errorName(err),
653 }) catch {};656 }) catch {};
654 _ = macho_file.has_errors.swap(true, .seq_cst);
655 };657 };
656}658}
657659
658fn writeEhFrameWorker(macho_file: *MachO) void {660fn writeEhFrameWorker(macho_file: *MachO) void {
659 const tracy = trace(@src());661 const tracy = trace(@src());
660 defer tracy.end();662 defer tracy.end();
663
664 const diags = &macho_file.base.comp.link_diags;
661 const sect_index = macho_file.eh_frame_sect_index.?;665 const sect_index = macho_file.eh_frame_sect_index.?;
662 const buffer = macho_file.sections.items(.out)[sect_index];666 const buffer = macho_file.sections.items(.out)[sect_index];
663 const relocs = macho_file.sections.items(.relocs)[sect_index];667 const relocs = macho_file.sections.items(.relocs)[sect_index];
664 eh_frame.writeRelocs(macho_file, buffer.items, relocs.items) catch |err| {668 eh_frame.writeRelocs(macho_file, buffer.items, relocs.items) catch |err|
665 macho_file.reportUnexpectedError("failed to write '__LD,__eh_frame' section: {s}", .{669 diags.addError("failed to write '__LD,__eh_frame' section: {s}", .{@errorName(err)});
666 @errorName(err),
667 }) catch {};
668 _ = macho_file.has_errors.swap(true, .seq_cst);
669 };
670}670}
671671
672fn writeCompactUnwindWorker(macho_file: *MachO, object: *Object) void {672fn writeCompactUnwindWorker(macho_file: *MachO, object: *Object) void {
673 const tracy = trace(@src());673 const tracy = trace(@src());
674 defer tracy.end();674 defer tracy.end();
675 object.writeCompactUnwindRelocatable(macho_file) catch |err| {675
676 macho_file.reportUnexpectedError("failed to write '__LD,__eh_frame' section: {s}", .{676 const diags = &macho_file.base.comp.link_diags;
677 @errorName(err),677 object.writeCompactUnwindRelocatable(macho_file) catch |err|
678 }) catch {};678 diags.addError("failed to write '__LD,__eh_frame' section: {s}", .{@errorName(err)});
679 _ = macho_file.has_errors.swap(true, .seq_cst);
680 };
681}679}
682680
683fn writeSectionsToFile(macho_file: *MachO) !void {681fn writeSectionsToFile(macho_file: *MachO) !void {
src/link/Wasm.zig+51-36
...@@ -649,6 +649,8 @@ fn parseInputFiles(wasm: *Wasm, files: []const []const u8) !void {...@@ -649,6 +649,8 @@ fn parseInputFiles(wasm: *Wasm, files: []const []const u8) !void {
649/// file and parsed successfully. Returns false when file is not an object file.649/// file and parsed successfully. Returns false when file is not an object file.
650/// May return an error instead when parsing failed.650/// May return an error instead when parsing failed.
651fn parseObjectFile(wasm: *Wasm, path: []const u8) !bool {651fn parseObjectFile(wasm: *Wasm, path: []const u8) !bool {
652 const diags = &wasm.base.comp.link_diags;
653
652 const obj_file = try fs.cwd().openFile(path, .{});654 const obj_file = try fs.cwd().openFile(path, .{});
653 errdefer obj_file.close();655 errdefer obj_file.close();
654656
...@@ -656,7 +658,7 @@ fn parseObjectFile(wasm: *Wasm, path: []const u8) !bool {...@@ -656,7 +658,7 @@ fn parseObjectFile(wasm: *Wasm, path: []const u8) !bool {
656 var object = Object.create(wasm, obj_file, path, null) catch |err| switch (err) {658 var object = Object.create(wasm, obj_file, path, null) catch |err| switch (err) {
657 error.InvalidMagicByte, error.NotObjectFile => return false,659 error.InvalidMagicByte, error.NotObjectFile => return false,
658 else => |e| {660 else => |e| {
659 var err_note = try wasm.base.addErrorWithNotes(1);661 var err_note = try diags.addErrorWithNotes(1);
660 try err_note.addMsg("Failed parsing object file: {s}", .{@errorName(e)});662 try err_note.addMsg("Failed parsing object file: {s}", .{@errorName(e)});
661 try err_note.addNote("while parsing '{s}'", .{path});663 try err_note.addNote("while parsing '{s}'", .{path});
662 return error.FlushFailure;664 return error.FlushFailure;
...@@ -698,6 +700,7 @@ pub inline fn getAtomPtr(wasm: *Wasm, index: Atom.Index) *Atom {...@@ -698,6 +700,7 @@ pub inline fn getAtomPtr(wasm: *Wasm, index: Atom.Index) *Atom {
698/// are referenced by other object files or Zig code.700/// are referenced by other object files or Zig code.
699fn parseArchive(wasm: *Wasm, path: []const u8, force_load: bool) !bool {701fn parseArchive(wasm: *Wasm, path: []const u8, force_load: bool) !bool {
700 const gpa = wasm.base.comp.gpa;702 const gpa = wasm.base.comp.gpa;
703 const diags = &wasm.base.comp.link_diags;
701704
702 const archive_file = try fs.cwd().openFile(path, .{});705 const archive_file = try fs.cwd().openFile(path, .{});
703 errdefer archive_file.close();706 errdefer archive_file.close();
...@@ -712,7 +715,7 @@ fn parseArchive(wasm: *Wasm, path: []const u8, force_load: bool) !bool {...@@ -712,7 +715,7 @@ fn parseArchive(wasm: *Wasm, path: []const u8, force_load: bool) !bool {
712 return false;715 return false;
713 },716 },
714 else => |e| {717 else => |e| {
715 var err_note = try wasm.base.addErrorWithNotes(1);718 var err_note = try diags.addErrorWithNotes(1);
716 try err_note.addMsg("Failed parsing archive: {s}", .{@errorName(e)});719 try err_note.addMsg("Failed parsing archive: {s}", .{@errorName(e)});
717 try err_note.addNote("while parsing archive {s}", .{path});720 try err_note.addNote("while parsing archive {s}", .{path});
718 return error.FlushFailure;721 return error.FlushFailure;
...@@ -739,7 +742,7 @@ fn parseArchive(wasm: *Wasm, path: []const u8, force_load: bool) !bool {...@@ -739,7 +742,7 @@ fn parseArchive(wasm: *Wasm, path: []const u8, force_load: bool) !bool {
739742
740 for (offsets.keys()) |file_offset| {743 for (offsets.keys()) |file_offset| {
741 var object = archive.parseObject(wasm, file_offset) catch |e| {744 var object = archive.parseObject(wasm, file_offset) catch |e| {
742 var err_note = try wasm.base.addErrorWithNotes(1);745 var err_note = try diags.addErrorWithNotes(1);
743 try err_note.addMsg("Failed parsing object: {s}", .{@errorName(e)});746 try err_note.addMsg("Failed parsing object: {s}", .{@errorName(e)});
744 try err_note.addNote("while parsing object in archive {s}", .{path});747 try err_note.addNote("while parsing object in archive {s}", .{path});
745 return error.FlushFailure;748 return error.FlushFailure;
...@@ -763,6 +766,7 @@ fn requiresTLSReloc(wasm: *const Wasm) bool {...@@ -763,6 +766,7 @@ fn requiresTLSReloc(wasm: *const Wasm) bool {
763766
764fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {767fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {
765 const gpa = wasm.base.comp.gpa;768 const gpa = wasm.base.comp.gpa;
769 const diags = &wasm.base.comp.link_diags;
766 const obj_file = wasm.file(file_index).?;770 const obj_file = wasm.file(file_index).?;
767 log.debug("Resolving symbols in object: '{s}'", .{obj_file.path()});771 log.debug("Resolving symbols in object: '{s}'", .{obj_file.path()});
768772
...@@ -777,7 +781,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {...@@ -777,7 +781,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {
777781
778 if (symbol.isLocal()) {782 if (symbol.isLocal()) {
779 if (symbol.isUndefined()) {783 if (symbol.isUndefined()) {
780 var err = try wasm.base.addErrorWithNotes(1);784 var err = try diags.addErrorWithNotes(1);
781 try err.addMsg("Local symbols are not allowed to reference imports", .{});785 try err.addMsg("Local symbols are not allowed to reference imports", .{});
782 try err.addNote("symbol '{s}' defined in '{s}'", .{ sym_name, obj_file.path() });786 try err.addNote("symbol '{s}' defined in '{s}'", .{ sym_name, obj_file.path() });
783 }787 }
...@@ -814,7 +818,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {...@@ -814,7 +818,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {
814 break :outer; // existing is weak, while new one isn't. Replace it.818 break :outer; // existing is weak, while new one isn't. Replace it.
815 }819 }
816 // both are defined and weak, we have a symbol collision.820 // both are defined and weak, we have a symbol collision.
817 var err = try wasm.base.addErrorWithNotes(2);821 var err = try diags.addErrorWithNotes(2);
818 try err.addMsg("symbol '{s}' defined multiple times", .{sym_name});822 try err.addMsg("symbol '{s}' defined multiple times", .{sym_name});
819 try err.addNote("first definition in '{s}'", .{existing_file_path});823 try err.addNote("first definition in '{s}'", .{existing_file_path});
820 try err.addNote("next definition in '{s}'", .{obj_file.path()});824 try err.addNote("next definition in '{s}'", .{obj_file.path()});
...@@ -825,7 +829,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {...@@ -825,7 +829,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {
825 }829 }
826830
827 if (symbol.tag != existing_sym.tag) {831 if (symbol.tag != existing_sym.tag) {
828 var err = try wasm.base.addErrorWithNotes(2);832 var err = try diags.addErrorWithNotes(2);
829 try err.addMsg("symbol '{s}' mismatching types '{s}' and '{s}'", .{ sym_name, @tagName(symbol.tag), @tagName(existing_sym.tag) });833 try err.addMsg("symbol '{s}' mismatching types '{s}' and '{s}'", .{ sym_name, @tagName(symbol.tag), @tagName(existing_sym.tag) });
830 try err.addNote("first definition in '{s}'", .{existing_file_path});834 try err.addNote("first definition in '{s}'", .{existing_file_path});
831 try err.addNote("next definition in '{s}'", .{obj_file.path()});835 try err.addNote("next definition in '{s}'", .{obj_file.path()});
...@@ -845,7 +849,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {...@@ -845,7 +849,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {
845 const imp = obj_file.import(sym_index);849 const imp = obj_file.import(sym_index);
846 const module_name = obj_file.string(imp.module_name);850 const module_name = obj_file.string(imp.module_name);
847 if (!mem.eql(u8, existing_name, module_name)) {851 if (!mem.eql(u8, existing_name, module_name)) {
848 var err = try wasm.base.addErrorWithNotes(2);852 var err = try diags.addErrorWithNotes(2);
849 try err.addMsg("symbol '{s}' module name mismatch. Expected '{s}', but found '{s}'", .{853 try err.addMsg("symbol '{s}' module name mismatch. Expected '{s}', but found '{s}'", .{
850 sym_name,854 sym_name,
851 existing_name,855 existing_name,
...@@ -865,7 +869,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {...@@ -865,7 +869,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {
865 const existing_ty = wasm.getGlobalType(existing_loc);869 const existing_ty = wasm.getGlobalType(existing_loc);
866 const new_ty = wasm.getGlobalType(location);870 const new_ty = wasm.getGlobalType(location);
867 if (existing_ty.mutable != new_ty.mutable or existing_ty.valtype != new_ty.valtype) {871 if (existing_ty.mutable != new_ty.mutable or existing_ty.valtype != new_ty.valtype) {
868 var err = try wasm.base.addErrorWithNotes(2);872 var err = try diags.addErrorWithNotes(2);
869 try err.addMsg("symbol '{s}' mismatching global types", .{sym_name});873 try err.addMsg("symbol '{s}' mismatching global types", .{sym_name});
870 try err.addNote("first definition in '{s}'", .{existing_file_path});874 try err.addNote("first definition in '{s}'", .{existing_file_path});
871 try err.addNote("next definition in '{s}'", .{obj_file.path()});875 try err.addNote("next definition in '{s}'", .{obj_file.path()});
...@@ -876,7 +880,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {...@@ -876,7 +880,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {
876 const existing_ty = wasm.getFunctionSignature(existing_loc);880 const existing_ty = wasm.getFunctionSignature(existing_loc);
877 const new_ty = wasm.getFunctionSignature(location);881 const new_ty = wasm.getFunctionSignature(location);
878 if (!existing_ty.eql(new_ty)) {882 if (!existing_ty.eql(new_ty)) {
879 var err = try wasm.base.addErrorWithNotes(3);883 var err = try diags.addErrorWithNotes(3);
880 try err.addMsg("symbol '{s}' mismatching function signatures.", .{sym_name});884 try err.addMsg("symbol '{s}' mismatching function signatures.", .{sym_name});
881 try err.addNote("expected signature {}, but found signature {}", .{ existing_ty, new_ty });885 try err.addNote("expected signature {}, but found signature {}", .{ existing_ty, new_ty });
882 try err.addNote("first definition in '{s}'", .{existing_file_path});886 try err.addNote("first definition in '{s}'", .{existing_file_path});
...@@ -909,6 +913,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {...@@ -909,6 +913,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {
909913
910fn resolveSymbolsInArchives(wasm: *Wasm) !void {914fn resolveSymbolsInArchives(wasm: *Wasm) !void {
911 const gpa = wasm.base.comp.gpa;915 const gpa = wasm.base.comp.gpa;
916 const diags = &wasm.base.comp.link_diags;
912 if (wasm.archives.items.len == 0) return;917 if (wasm.archives.items.len == 0) return;
913918
914 log.debug("Resolving symbols in archives", .{});919 log.debug("Resolving symbols in archives", .{});
...@@ -928,7 +933,7 @@ fn resolveSymbolsInArchives(wasm: *Wasm) !void {...@@ -928,7 +933,7 @@ fn resolveSymbolsInArchives(wasm: *Wasm) !void {
928 // Parse object and and resolve symbols again before we check remaining933 // Parse object and and resolve symbols again before we check remaining
929 // undefined symbols.934 // undefined symbols.
930 var object = archive.parseObject(wasm, offset.items[0]) catch |e| {935 var object = archive.parseObject(wasm, offset.items[0]) catch |e| {
931 var err_note = try wasm.base.addErrorWithNotes(1);936 var err_note = try diags.addErrorWithNotes(1);
932 try err_note.addMsg("Failed parsing object: {s}", .{@errorName(e)});937 try err_note.addMsg("Failed parsing object: {s}", .{@errorName(e)});
933 try err_note.addNote("while parsing object in archive {s}", .{archive.name});938 try err_note.addNote("while parsing object in archive {s}", .{archive.name});
934 return error.FlushFailure;939 return error.FlushFailure;
...@@ -1172,6 +1177,7 @@ fn validateFeatures(...@@ -1172,6 +1177,7 @@ fn validateFeatures(
1172 emit_features_count: *u32,1177 emit_features_count: *u32,
1173) !void {1178) !void {
1174 const comp = wasm.base.comp;1179 const comp = wasm.base.comp;
1180 const diags = &wasm.base.comp.link_diags;
1175 const target = comp.root_mod.resolved_target.result;1181 const target = comp.root_mod.resolved_target.result;
1176 const shared_memory = comp.config.shared_memory;1182 const shared_memory = comp.config.shared_memory;
1177 const cpu_features = target.cpu.features;1183 const cpu_features = target.cpu.features;
...@@ -1235,7 +1241,7 @@ fn validateFeatures(...@@ -1235,7 +1241,7 @@ fn validateFeatures(
1235 allowed[used_index] = is_enabled;1241 allowed[used_index] = is_enabled;
1236 emit_features_count.* += @intFromBool(is_enabled);1242 emit_features_count.* += @intFromBool(is_enabled);
1237 } else if (is_enabled and !allowed[used_index]) {1243 } else if (is_enabled and !allowed[used_index]) {
1238 var err = try wasm.base.addErrorWithNotes(1);1244 var err = try diags.addErrorWithNotes(1);
1239 try err.addMsg("feature '{}' not allowed, but used by linked object", .{@as(types.Feature.Tag, @enumFromInt(used_index))});1245 try err.addMsg("feature '{}' not allowed, but used by linked object", .{@as(types.Feature.Tag, @enumFromInt(used_index))});
1240 try err.addNote("defined in '{s}'", .{wasm.files.items(.data)[used_set >> 1].object.path});1246 try err.addNote("defined in '{s}'", .{wasm.files.items(.data)[used_set >> 1].object.path});
1241 valid_feature_set = false;1247 valid_feature_set = false;
...@@ -1249,7 +1255,7 @@ fn validateFeatures(...@@ -1249,7 +1255,7 @@ fn validateFeatures(
1249 if (shared_memory) {1255 if (shared_memory) {
1250 const disallowed_feature = disallowed[@intFromEnum(types.Feature.Tag.shared_mem)];1256 const disallowed_feature = disallowed[@intFromEnum(types.Feature.Tag.shared_mem)];
1251 if (@as(u1, @truncate(disallowed_feature)) != 0) {1257 if (@as(u1, @truncate(disallowed_feature)) != 0) {
1252 var err = try wasm.base.addErrorWithNotes(0);1258 var err = try diags.addErrorWithNotes(0);
1253 try err.addMsg(1259 try err.addMsg(
1254 "shared-memory is disallowed by '{s}' because it wasn't compiled with 'atomics' and 'bulk-memory' features enabled",1260 "shared-memory is disallowed by '{s}' because it wasn't compiled with 'atomics' and 'bulk-memory' features enabled",
1255 .{wasm.files.items(.data)[disallowed_feature >> 1].object.path},1261 .{wasm.files.items(.data)[disallowed_feature >> 1].object.path},
...@@ -1259,7 +1265,7 @@ fn validateFeatures(...@@ -1259,7 +1265,7 @@ fn validateFeatures(
12591265
1260 for ([_]types.Feature.Tag{ .atomics, .bulk_memory }) |feature| {1266 for ([_]types.Feature.Tag{ .atomics, .bulk_memory }) |feature| {
1261 if (!allowed[@intFromEnum(feature)]) {1267 if (!allowed[@intFromEnum(feature)]) {
1262 var err = try wasm.base.addErrorWithNotes(0);1268 var err = try diags.addErrorWithNotes(0);
1263 try err.addMsg("feature '{}' is not used but is required for shared-memory", .{feature});1269 try err.addMsg("feature '{}' is not used but is required for shared-memory", .{feature});
1264 }1270 }
1265 }1271 }
...@@ -1268,7 +1274,7 @@ fn validateFeatures(...@@ -1268,7 +1274,7 @@ fn validateFeatures(
1268 if (has_tls) {1274 if (has_tls) {
1269 for ([_]types.Feature.Tag{ .atomics, .bulk_memory }) |feature| {1275 for ([_]types.Feature.Tag{ .atomics, .bulk_memory }) |feature| {
1270 if (!allowed[@intFromEnum(feature)]) {1276 if (!allowed[@intFromEnum(feature)]) {
1271 var err = try wasm.base.addErrorWithNotes(0);1277 var err = try diags.addErrorWithNotes(0);
1272 try err.addMsg("feature '{}' is not used but is required for thread-local storage", .{feature});1278 try err.addMsg("feature '{}' is not used but is required for thread-local storage", .{feature});
1273 }1279 }
1274 }1280 }
...@@ -1282,7 +1288,7 @@ fn validateFeatures(...@@ -1282,7 +1288,7 @@ fn validateFeatures(
1282 // from here a feature is always used1288 // from here a feature is always used
1283 const disallowed_feature = disallowed[@intFromEnum(feature.tag)];1289 const disallowed_feature = disallowed[@intFromEnum(feature.tag)];
1284 if (@as(u1, @truncate(disallowed_feature)) != 0) {1290 if (@as(u1, @truncate(disallowed_feature)) != 0) {
1285 var err = try wasm.base.addErrorWithNotes(2);1291 var err = try diags.addErrorWithNotes(2);
1286 try err.addMsg("feature '{}' is disallowed, but used by linked object", .{feature.tag});1292 try err.addMsg("feature '{}' is disallowed, but used by linked object", .{feature.tag});
1287 try err.addNote("disallowed by '{s}'", .{wasm.files.items(.data)[disallowed_feature >> 1].object.path});1293 try err.addNote("disallowed by '{s}'", .{wasm.files.items(.data)[disallowed_feature >> 1].object.path});
1288 try err.addNote("used in '{s}'", .{object.path});1294 try err.addNote("used in '{s}'", .{object.path});
...@@ -1296,7 +1302,7 @@ fn validateFeatures(...@@ -1296,7 +1302,7 @@ fn validateFeatures(
1296 for (required, 0..) |required_feature, feature_index| {1302 for (required, 0..) |required_feature, feature_index| {
1297 const is_required = @as(u1, @truncate(required_feature)) != 0;1303 const is_required = @as(u1, @truncate(required_feature)) != 0;
1298 if (is_required and !object_used_features[feature_index]) {1304 if (is_required and !object_used_features[feature_index]) {
1299 var err = try wasm.base.addErrorWithNotes(2);1305 var err = try diags.addErrorWithNotes(2);
1300 try err.addMsg("feature '{}' is required but not used in linked object", .{@as(types.Feature.Tag, @enumFromInt(feature_index))});1306 try err.addMsg("feature '{}' is required but not used in linked object", .{@as(types.Feature.Tag, @enumFromInt(feature_index))});
1301 try err.addNote("required by '{s}'", .{wasm.files.items(.data)[required_feature >> 1].object.path});1307 try err.addNote("required by '{s}'", .{wasm.files.items(.data)[required_feature >> 1].object.path});
1302 try err.addNote("missing in '{s}'", .{object.path});1308 try err.addNote("missing in '{s}'", .{object.path});
...@@ -1364,6 +1370,7 @@ pub fn findGlobalSymbol(wasm: *Wasm, name: []const u8) ?SymbolLoc {...@@ -1364,6 +1370,7 @@ pub fn findGlobalSymbol(wasm: *Wasm, name: []const u8) ?SymbolLoc {
13641370
1365fn checkUndefinedSymbols(wasm: *const Wasm) !void {1371fn checkUndefinedSymbols(wasm: *const Wasm) !void {
1366 const comp = wasm.base.comp;1372 const comp = wasm.base.comp;
1373 const diags = &wasm.base.comp.link_diags;
1367 if (comp.config.output_mode == .Obj) return;1374 if (comp.config.output_mode == .Obj) return;
1368 if (wasm.import_symbols) return;1375 if (wasm.import_symbols) return;
13691376
...@@ -1377,7 +1384,7 @@ fn checkUndefinedSymbols(wasm: *const Wasm) !void {...@@ -1377,7 +1384,7 @@ fn checkUndefinedSymbols(wasm: *const Wasm) !void {
1377 else1384 else
1378 wasm.name;1385 wasm.name;
1379 const symbol_name = undef.getName(wasm);1386 const symbol_name = undef.getName(wasm);
1380 var err = try wasm.base.addErrorWithNotes(1);1387 var err = try diags.addErrorWithNotes(1);
1381 try err.addMsg("could not resolve undefined symbol '{s}'", .{symbol_name});1388 try err.addMsg("could not resolve undefined symbol '{s}'", .{symbol_name});
1382 try err.addNote("defined in '{s}'", .{file_name});1389 try err.addNote("defined in '{s}'", .{file_name});
1383 }1390 }
...@@ -1736,6 +1743,7 @@ fn sortDataSegments(wasm: *Wasm) !void {...@@ -1736,6 +1743,7 @@ fn sortDataSegments(wasm: *Wasm) !void {
1736/// contain any parameters.1743/// contain any parameters.
1737fn setupInitFunctions(wasm: *Wasm) !void {1744fn setupInitFunctions(wasm: *Wasm) !void {
1738 const gpa = wasm.base.comp.gpa;1745 const gpa = wasm.base.comp.gpa;
1746 const diags = &wasm.base.comp.link_diags;
1739 // There's no constructors for Zig so we can simply search through linked object files only.1747 // There's no constructors for Zig so we can simply search through linked object files only.
1740 for (wasm.objects.items) |file_index| {1748 for (wasm.objects.items) |file_index| {
1741 const object: Object = wasm.files.items(.data)[@intFromEnum(file_index)].object;1749 const object: Object = wasm.files.items(.data)[@intFromEnum(file_index)].object;
...@@ -1751,7 +1759,7 @@ fn setupInitFunctions(wasm: *Wasm) !void {...@@ -1751,7 +1759,7 @@ fn setupInitFunctions(wasm: *Wasm) !void {
1751 break :ty object.func_types[func.type_index];1759 break :ty object.func_types[func.type_index];
1752 };1760 };
1753 if (ty.params.len != 0) {1761 if (ty.params.len != 0) {
1754 var err = try wasm.base.addErrorWithNotes(0);1762 var err = try diags.addErrorWithNotes(0);
1755 try err.addMsg("constructor functions cannot take arguments: '{s}'", .{object.string_table.get(symbol.name)});1763 try err.addMsg("constructor functions cannot take arguments: '{s}'", .{object.string_table.get(symbol.name)});
1756 }1764 }
1757 log.debug("appended init func '{s}'\n", .{object.string_table.get(symbol.name)});1765 log.debug("appended init func '{s}'\n", .{object.string_table.get(symbol.name)});
...@@ -2130,12 +2138,13 @@ fn mergeTypes(wasm: *Wasm) !void {...@@ -2130,12 +2138,13 @@ fn mergeTypes(wasm: *Wasm) !void {
21302138
2131fn checkExportNames(wasm: *Wasm) !void {2139fn checkExportNames(wasm: *Wasm) !void {
2132 const force_exp_names = wasm.export_symbol_names;2140 const force_exp_names = wasm.export_symbol_names;
2141 const diags = &wasm.base.comp.link_diags;
2133 if (force_exp_names.len > 0) {2142 if (force_exp_names.len > 0) {
2134 var failed_exports = false;2143 var failed_exports = false;
21352144
2136 for (force_exp_names) |exp_name| {2145 for (force_exp_names) |exp_name| {
2137 const loc = wasm.findGlobalSymbol(exp_name) orelse {2146 const loc = wasm.findGlobalSymbol(exp_name) orelse {
2138 var err = try wasm.base.addErrorWithNotes(0);2147 var err = try diags.addErrorWithNotes(0);
2139 try err.addMsg("could not export '{s}', symbol not found", .{exp_name});2148 try err.addMsg("could not export '{s}', symbol not found", .{exp_name});
2140 failed_exports = true;2149 failed_exports = true;
2141 continue;2150 continue;
...@@ -2195,18 +2204,19 @@ fn setupExports(wasm: *Wasm) !void {...@@ -2195,18 +2204,19 @@ fn setupExports(wasm: *Wasm) !void {
21952204
2196fn setupStart(wasm: *Wasm) !void {2205fn setupStart(wasm: *Wasm) !void {
2197 const comp = wasm.base.comp;2206 const comp = wasm.base.comp;
2207 const diags = &wasm.base.comp.link_diags;
2198 // do not export entry point if user set none or no default was set.2208 // do not export entry point if user set none or no default was set.
2199 const entry_name = wasm.entry_name orelse return;2209 const entry_name = wasm.entry_name orelse return;
22002210
2201 const symbol_loc = wasm.findGlobalSymbol(entry_name) orelse {2211 const symbol_loc = wasm.findGlobalSymbol(entry_name) orelse {
2202 var err = try wasm.base.addErrorWithNotes(0);2212 var err = try diags.addErrorWithNotes(0);
2203 try err.addMsg("Entry symbol '{s}' missing, use '-fno-entry' to suppress", .{entry_name});2213 try err.addMsg("Entry symbol '{s}' missing, use '-fno-entry' to suppress", .{entry_name});
2204 return error.FlushFailure;2214 return error.FlushFailure;
2205 };2215 };
22062216
2207 const symbol = symbol_loc.getSymbol(wasm);2217 const symbol = symbol_loc.getSymbol(wasm);
2208 if (symbol.tag != .function) {2218 if (symbol.tag != .function) {
2209 var err = try wasm.base.addErrorWithNotes(0);2219 var err = try diags.addErrorWithNotes(0);
2210 try err.addMsg("Entry symbol '{s}' is not a function", .{entry_name});2220 try err.addMsg("Entry symbol '{s}' is not a function", .{entry_name});
2211 return error.FlushFailure;2221 return error.FlushFailure;
2212 }2222 }
...@@ -2220,6 +2230,7 @@ fn setupStart(wasm: *Wasm) !void {...@@ -2220,6 +2230,7 @@ fn setupStart(wasm: *Wasm) !void {
2220/// Sets up the memory section of the wasm module, as well as the stack.2230/// Sets up the memory section of the wasm module, as well as the stack.
2221fn setupMemory(wasm: *Wasm) !void {2231fn setupMemory(wasm: *Wasm) !void {
2222 const comp = wasm.base.comp;2232 const comp = wasm.base.comp;
2233 const diags = &wasm.base.comp.link_diags;
2223 const shared_memory = comp.config.shared_memory;2234 const shared_memory = comp.config.shared_memory;
2224 log.debug("Setting up memory layout", .{});2235 log.debug("Setting up memory layout", .{});
2225 const page_size = std.wasm.page_size; // 64kb2236 const page_size = std.wasm.page_size; // 64kb
...@@ -2312,15 +2323,15 @@ fn setupMemory(wasm: *Wasm) !void {...@@ -2312,15 +2323,15 @@ fn setupMemory(wasm: *Wasm) !void {
23122323
2313 if (wasm.initial_memory) |initial_memory| {2324 if (wasm.initial_memory) |initial_memory| {
2314 if (!std.mem.isAlignedGeneric(u64, initial_memory, page_size)) {2325 if (!std.mem.isAlignedGeneric(u64, initial_memory, page_size)) {
2315 var err = try wasm.base.addErrorWithNotes(0);2326 var err = try diags.addErrorWithNotes(0);
2316 try err.addMsg("Initial memory must be {d}-byte aligned", .{page_size});2327 try err.addMsg("Initial memory must be {d}-byte aligned", .{page_size});
2317 }2328 }
2318 if (memory_ptr > initial_memory) {2329 if (memory_ptr > initial_memory) {
2319 var err = try wasm.base.addErrorWithNotes(0);2330 var err = try diags.addErrorWithNotes(0);
2320 try err.addMsg("Initial memory too small, must be at least {d} bytes", .{memory_ptr});2331 try err.addMsg("Initial memory too small, must be at least {d} bytes", .{memory_ptr});
2321 }2332 }
2322 if (initial_memory > max_memory_allowed) {2333 if (initial_memory > max_memory_allowed) {
2323 var err = try wasm.base.addErrorWithNotes(0);2334 var err = try diags.addErrorWithNotes(0);
2324 try err.addMsg("Initial memory exceeds maximum memory {d}", .{max_memory_allowed});2335 try err.addMsg("Initial memory exceeds maximum memory {d}", .{max_memory_allowed});
2325 }2336 }
2326 memory_ptr = initial_memory;2337 memory_ptr = initial_memory;
...@@ -2338,15 +2349,15 @@ fn setupMemory(wasm: *Wasm) !void {...@@ -2338,15 +2349,15 @@ fn setupMemory(wasm: *Wasm) !void {
23382349
2339 if (wasm.max_memory) |max_memory| {2350 if (wasm.max_memory) |max_memory| {
2340 if (!std.mem.isAlignedGeneric(u64, max_memory, page_size)) {2351 if (!std.mem.isAlignedGeneric(u64, max_memory, page_size)) {
2341 var err = try wasm.base.addErrorWithNotes(0);2352 var err = try diags.addErrorWithNotes(0);
2342 try err.addMsg("Maximum memory must be {d}-byte aligned", .{page_size});2353 try err.addMsg("Maximum memory must be {d}-byte aligned", .{page_size});
2343 }2354 }
2344 if (memory_ptr > max_memory) {2355 if (memory_ptr > max_memory) {
2345 var err = try wasm.base.addErrorWithNotes(0);2356 var err = try diags.addErrorWithNotes(0);
2346 try err.addMsg("Maximum memory too small, must be at least {d} bytes", .{memory_ptr});2357 try err.addMsg("Maximum memory too small, must be at least {d} bytes", .{memory_ptr});
2347 }2358 }
2348 if (max_memory > max_memory_allowed) {2359 if (max_memory > max_memory_allowed) {
2349 var err = try wasm.base.addErrorWithNotes(0);2360 var err = try diags.addErrorWithNotes(0);
2350 try err.addMsg("Maximum memory exceeds maximum amount {d}", .{max_memory_allowed});2361 try err.addMsg("Maximum memory exceeds maximum amount {d}", .{max_memory_allowed});
2351 }2362 }
2352 wasm.memories.limits.max = @as(u32, @intCast(max_memory / page_size));2363 wasm.memories.limits.max = @as(u32, @intCast(max_memory / page_size));
...@@ -2364,6 +2375,7 @@ fn setupMemory(wasm: *Wasm) !void {...@@ -2364,6 +2375,7 @@ fn setupMemory(wasm: *Wasm) !void {
2364pub fn getMatchingSegment(wasm: *Wasm, file_index: File.Index, symbol_index: Symbol.Index) !u32 {2375pub fn getMatchingSegment(wasm: *Wasm, file_index: File.Index, symbol_index: Symbol.Index) !u32 {
2365 const comp = wasm.base.comp;2376 const comp = wasm.base.comp;
2366 const gpa = comp.gpa;2377 const gpa = comp.gpa;
2378 const diags = &wasm.base.comp.link_diags;
2367 const obj_file = wasm.file(file_index).?;2379 const obj_file = wasm.file(file_index).?;
2368 const symbol = obj_file.symbols()[@intFromEnum(symbol_index)];2380 const symbol = obj_file.symbols()[@intFromEnum(symbol_index)];
2369 const index: u32 = @intCast(wasm.segments.items.len);2381 const index: u32 = @intCast(wasm.segments.items.len);
...@@ -2450,7 +2462,7 @@ pub fn getMatchingSegment(wasm: *Wasm, file_index: File.Index, symbol_index: Sym...@@ -2450,7 +2462,7 @@ pub fn getMatchingSegment(wasm: *Wasm, file_index: File.Index, symbol_index: Sym
2450 break :blk index;2462 break :blk index;
2451 };2463 };
2452 } else {2464 } else {
2453 var err = try wasm.base.addErrorWithNotes(1);2465 var err = try diags.addErrorWithNotes(1);
2454 try err.addMsg("found unknown section '{s}'", .{section_name});2466 try err.addMsg("found unknown section '{s}'", .{section_name});
2455 try err.addNote("defined in '{s}'", .{obj_file.path()});2467 try err.addNote("defined in '{s}'", .{obj_file.path()});
2456 return error.UnexpectedValue;2468 return error.UnexpectedValue;
...@@ -2487,6 +2499,7 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_no...@@ -2487,6 +2499,7 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
2487 defer tracy.end();2499 defer tracy.end();
24882500
2489 const comp = wasm.base.comp;2501 const comp = wasm.base.comp;
2502 const diags = &comp.link_diags;
2490 if (wasm.llvm_object) |llvm_object| {2503 if (wasm.llvm_object) |llvm_object| {
2491 try wasm.base.emitLlvmObject(arena, llvm_object, prog_node);2504 try wasm.base.emitLlvmObject(arena, llvm_object, prog_node);
2492 const use_lld = build_options.have_llvm and comp.config.use_lld;2505 const use_lld = build_options.have_llvm and comp.config.use_lld;
...@@ -2569,23 +2582,23 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_no...@@ -2569,23 +2582,23 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
2569 if (wasm.zig_object_index != .null) {2582 if (wasm.zig_object_index != .null) {
2570 try wasm.resolveSymbolsInObject(wasm.zig_object_index);2583 try wasm.resolveSymbolsInObject(wasm.zig_object_index);
2571 }2584 }
2572 if (wasm.base.hasErrors()) return error.FlushFailure;2585 if (diags.hasErrors()) return error.FlushFailure;
2573 for (wasm.objects.items) |object_index| {2586 for (wasm.objects.items) |object_index| {
2574 try wasm.resolveSymbolsInObject(object_index);2587 try wasm.resolveSymbolsInObject(object_index);
2575 }2588 }
2576 if (wasm.base.hasErrors()) return error.FlushFailure;2589 if (diags.hasErrors()) return error.FlushFailure;
25772590
2578 var emit_features_count: u32 = 0;2591 var emit_features_count: u32 = 0;
2579 var enabled_features: [@typeInfo(types.Feature.Tag).@"enum".fields.len]bool = undefined;2592 var enabled_features: [@typeInfo(types.Feature.Tag).@"enum".fields.len]bool = undefined;
2580 try wasm.validateFeatures(&enabled_features, &emit_features_count);2593 try wasm.validateFeatures(&enabled_features, &emit_features_count);
2581 try wasm.resolveSymbolsInArchives();2594 try wasm.resolveSymbolsInArchives();
2582 if (wasm.base.hasErrors()) return error.FlushFailure;2595 if (diags.hasErrors()) return error.FlushFailure;
2583 try wasm.resolveLazySymbols();2596 try wasm.resolveLazySymbols();
2584 try wasm.checkUndefinedSymbols();2597 try wasm.checkUndefinedSymbols();
2585 try wasm.checkExportNames();2598 try wasm.checkExportNames();
25862599
2587 try wasm.setupInitFunctions();2600 try wasm.setupInitFunctions();
2588 if (wasm.base.hasErrors()) return error.FlushFailure;2601 if (diags.hasErrors()) return error.FlushFailure;
2589 try wasm.setupStart();2602 try wasm.setupStart();
25902603
2591 try wasm.markReferences();2604 try wasm.markReferences();
...@@ -2594,7 +2607,7 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_no...@@ -2594,7 +2607,7 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
2594 try wasm.mergeTypes();2607 try wasm.mergeTypes();
2595 try wasm.allocateAtoms();2608 try wasm.allocateAtoms();
2596 try wasm.setupMemory();2609 try wasm.setupMemory();
2597 if (wasm.base.hasErrors()) return error.FlushFailure;2610 if (diags.hasErrors()) return error.FlushFailure;
2598 wasm.allocateVirtualAddresses();2611 wasm.allocateVirtualAddresses();
2599 wasm.mapFunctionTable();2612 wasm.mapFunctionTable();
2600 try wasm.initializeCallCtorsFunction();2613 try wasm.initializeCallCtorsFunction();
...@@ -2604,7 +2617,7 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_no...@@ -2604,7 +2617,7 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
2604 try wasm.setupStartSection();2617 try wasm.setupStartSection();
2605 try wasm.setupExports();2618 try wasm.setupExports();
2606 try wasm.writeToFile(enabled_features, emit_features_count, arena);2619 try wasm.writeToFile(enabled_features, emit_features_count, arena);
2607 if (wasm.base.hasErrors()) return error.FlushFailure;2620 if (diags.hasErrors()) return error.FlushFailure;
2608}2621}
26092622
2610/// Writes the WebAssembly in-memory module to the file2623/// Writes the WebAssembly in-memory module to the file
...@@ -2615,6 +2628,7 @@ fn writeToFile(...@@ -2615,6 +2628,7 @@ fn writeToFile(
2615 arena: Allocator,2628 arena: Allocator,
2616) !void {2629) !void {
2617 const comp = wasm.base.comp;2630 const comp = wasm.base.comp;
2631 const diags = &comp.link_diags;
2618 const gpa = comp.gpa;2632 const gpa = comp.gpa;
2619 const use_llvm = comp.config.use_llvm;2633 const use_llvm = comp.config.use_llvm;
2620 const use_lld = build_options.have_llvm and comp.config.use_lld;2634 const use_lld = build_options.have_llvm and comp.config.use_lld;
...@@ -3003,7 +3017,7 @@ fn writeToFile(...@@ -3003,7 +3017,7 @@ fn writeToFile(
3003 try emitBuildIdSection(&binary_bytes, str);3017 try emitBuildIdSection(&binary_bytes, str);
3004 },3018 },
3005 else => |mode| {3019 else => |mode| {
3006 var err = try wasm.base.addErrorWithNotes(0);3020 var err = try diags.addErrorWithNotes(0);
3007 try err.addMsg("build-id '{s}' is not supported for WebAssembly", .{@tagName(mode)});3021 try err.addMsg("build-id '{s}' is not supported for WebAssembly", .{@tagName(mode)});
3008 },3022 },
3009 }3023 }
...@@ -3684,7 +3698,8 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:...@@ -3684,7 +3698,8 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
3684 switch (term) {3698 switch (term) {
3685 .Exited => |code| {3699 .Exited => |code| {
3686 if (code != 0) {3700 if (code != 0) {
3687 comp.lockAndParseLldStderr(linker_command, stderr);3701 const diags = &comp.link_diags;
3702 diags.lockAndParseLldStderr(linker_command, stderr);
3688 return error.LLDReportedFailure;3703 return error.LLDReportedFailure;
3689 }3704 }
3690 },3705 },
src/link/Wasm/Object.zig+8-5
...@@ -226,6 +226,8 @@ pub fn findImport(object: *const Object, sym: Symbol) types.Import {...@@ -226,6 +226,8 @@ pub fn findImport(object: *const Object, sym: Symbol) types.Import {
226///226///
227/// When the object file is *NOT* MVP, we return `null`.227/// When the object file is *NOT* MVP, we return `null`.
228fn checkLegacyIndirectFunctionTable(object: *Object, wasm_file: *const Wasm) !?Symbol {228fn checkLegacyIndirectFunctionTable(object: *Object, wasm_file: *const Wasm) !?Symbol {
229 const diags = &wasm_file.base.comp.link_diags;
230
229 var table_count: usize = 0;231 var table_count: usize = 0;
230 for (object.symtable) |sym| {232 for (object.symtable) |sym| {
231 if (sym.tag == .table) table_count += 1;233 if (sym.tag == .table) table_count += 1;
...@@ -235,7 +237,7 @@ fn checkLegacyIndirectFunctionTable(object: *Object, wasm_file: *const Wasm) !?S...@@ -235,7 +237,7 @@ fn checkLegacyIndirectFunctionTable(object: *Object, wasm_file: *const Wasm) !?S
235 if (object.imported_tables_count == table_count) return null;237 if (object.imported_tables_count == table_count) return null;
236238
237 if (table_count != 0) {239 if (table_count != 0) {
238 var err = try wasm_file.base.addErrorWithNotes(1);240 var err = try diags.addErrorWithNotes(1);
239 try err.addMsg("Expected a table entry symbol for each of the {d} table(s), but instead got {d} symbols.", .{241 try err.addMsg("Expected a table entry symbol for each of the {d} table(s), but instead got {d} symbols.", .{
240 object.imported_tables_count,242 object.imported_tables_count,
241 table_count,243 table_count,
...@@ -246,14 +248,14 @@ fn checkLegacyIndirectFunctionTable(object: *Object, wasm_file: *const Wasm) !?S...@@ -246,14 +248,14 @@ fn checkLegacyIndirectFunctionTable(object: *Object, wasm_file: *const Wasm) !?S
246248
247 // MVP object files cannot have any table definitions, only imports (for the indirect function table).249 // MVP object files cannot have any table definitions, only imports (for the indirect function table).
248 if (object.tables.len > 0) {250 if (object.tables.len > 0) {
249 var err = try wasm_file.base.addErrorWithNotes(1);251 var err = try diags.addErrorWithNotes(1);
250 try err.addMsg("Unexpected table definition without representing table symbols.", .{});252 try err.addMsg("Unexpected table definition without representing table symbols.", .{});
251 try err.addNote("defined in '{s}'", .{object.path});253 try err.addNote("defined in '{s}'", .{object.path});
252 return error.UnexpectedTable;254 return error.UnexpectedTable;
253 }255 }
254256
255 if (object.imported_tables_count != 1) {257 if (object.imported_tables_count != 1) {
256 var err = try wasm_file.base.addErrorWithNotes(1);258 var err = try diags.addErrorWithNotes(1);
257 try err.addMsg("Found more than one table import, but no representing table symbols", .{});259 try err.addMsg("Found more than one table import, but no representing table symbols", .{});
258 try err.addNote("defined in '{s}'", .{object.path});260 try err.addNote("defined in '{s}'", .{object.path});
259 return error.MissingTableSymbols;261 return error.MissingTableSymbols;
...@@ -266,7 +268,7 @@ fn checkLegacyIndirectFunctionTable(object: *Object, wasm_file: *const Wasm) !?S...@@ -266,7 +268,7 @@ fn checkLegacyIndirectFunctionTable(object: *Object, wasm_file: *const Wasm) !?S
266 } else unreachable;268 } else unreachable;
267269
268 if (!std.mem.eql(u8, object.string_table.get(table_import.name), "__indirect_function_table")) {270 if (!std.mem.eql(u8, object.string_table.get(table_import.name), "__indirect_function_table")) {
269 var err = try wasm_file.base.addErrorWithNotes(1);271 var err = try diags.addErrorWithNotes(1);
270 try err.addMsg("Non-indirect function table import '{s}' is missing a corresponding symbol", .{object.string_table.get(table_import.name)});272 try err.addMsg("Non-indirect function table import '{s}' is missing a corresponding symbol", .{object.string_table.get(table_import.name)});
271 try err.addNote("defined in '{s}'", .{object.path});273 try err.addNote("defined in '{s}'", .{object.path});
272 return error.MissingTableSymbols;274 return error.MissingTableSymbols;
...@@ -587,6 +589,7 @@ fn Parser(comptime ReaderType: type) type {...@@ -587,6 +589,7 @@ fn Parser(comptime ReaderType: type) type {
587 /// to be able to link.589 /// to be able to link.
588 /// Logs an info message when an undefined feature is detected.590 /// Logs an info message when an undefined feature is detected.
589 fn parseFeatures(parser: *ObjectParser, gpa: Allocator) !void {591 fn parseFeatures(parser: *ObjectParser, gpa: Allocator) !void {
592 const diags = &parser.wasm_file.base.comp.link_diags;
590 const reader = parser.reader.reader();593 const reader = parser.reader.reader();
591 for (try readVec(&parser.object.features, reader, gpa)) |*feature| {594 for (try readVec(&parser.object.features, reader, gpa)) |*feature| {
592 const prefix = try readEnum(types.Feature.Prefix, reader);595 const prefix = try readEnum(types.Feature.Prefix, reader);
...@@ -596,7 +599,7 @@ fn Parser(comptime ReaderType: type) type {...@@ -596,7 +599,7 @@ fn Parser(comptime ReaderType: type) type {
596 try reader.readNoEof(name);599 try reader.readNoEof(name);
597600
598 const tag = types.known_features.get(name) orelse {601 const tag = types.known_features.get(name) orelse {
599 var err = try parser.wasm_file.base.addErrorWithNotes(1);602 var err = try diags.addErrorWithNotes(1);
600 try err.addMsg("Object file contains unknown feature: {s}", .{name});603 try err.addMsg("Object file contains unknown feature: {s}", .{name});
601 try err.addNote("defined in '{s}'", .{parser.object.path});604 try err.addNote("defined in '{s}'", .{parser.object.path});
602 return error.UnknownFeature;605 return error.UnknownFeature;