authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-02-23 16:18:43-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-03-15 10:48:12-07:00
log572cb24d1a4f70c662ddf17df72d27dec44bc4fc
tree15f18b819bd0abd88fa9fe3ef3c0b240c09e10aa
parent4db5bc7b2132d8794d98077a67fc410be9dc98bd

progress towards semantic error serialization

Introduces std.zig.ErrorBundle which is a trivially serializeable set of compilation errors. This is in the standard library so that both the compiler and the build runner can use it. The idea is they will use it to communicate compilation errors over a binary protocol. The binary encoding of ErrorBundle is a bit problematic - I got a little too aggressive with compaction. I need to change it in a follow-up commit to use some indirection in the error message list, otherwise iteration is too unergonomic. In fact it's so problematic right now that the logic getAllErrorsAlloc() actually fails to produce a viable ErrorBundle because it puts SourceLocation data in between the root level ErrorMessage data. This commit has a simplification - redundant logic for rendering AST errors to stderr has been removed in favor of moving the logic for lowering AST errors into AstGen. So even if we get parse errors, the errors will get lowered into ZIR before being reported. I believe this will be useful when working on --autofix. Either way, some redundant brittle logic was happily deleted. In Compilation, updateSubCompilation() is improved to properly perform error reporting when a sub-compilation object fails. It no longer dumps directly to stderr; instead it populates an ErrorBundle object, which gets added to the parent one during getAllErrorsAlloc(). In package fetching code, instead of dumping directly to stderr, it now populates an ErrorBundle object, and gets properly reported at the CLI layer of abstraction.

15 files changed, 1067 insertions(+), 908 deletions(-)

lib/std/zig.zig+1
...@@ -3,6 +3,7 @@ const tokenizer = @import("zig/tokenizer.zig");...@@ -3,6 +3,7 @@ const tokenizer = @import("zig/tokenizer.zig");
3const fmt = @import("zig/fmt.zig");3const fmt = @import("zig/fmt.zig");
4const assert = std.debug.assert;4const assert = std.debug.assert;
55
6pub const ErrorBundle = @import("zig/ErrorBundle.zig");
6pub const Token = tokenizer.Token;7pub const Token = tokenizer.Token;
7pub const Tokenizer = tokenizer.Tokenizer;8pub const Tokenizer = tokenizer.Tokenizer;
8pub const fmtId = fmt.fmtId;9pub const fmtId = fmt.fmtId;
lib/std/zig/ErrorBundle.zig created+419
...@@ -0,0 +1,419 @@
1//! To support incremental compilation, errors are stored in various places
2//! so that they can be created and destroyed appropriately. This structure
3//! is used to collect all the errors from the various places into one
4//! convenient place for API users to consume.
5
6string_bytes: std.ArrayListUnmanaged(u8),
7/// The first thing in this array is a ErrorMessageListIndex.
8extra: std.ArrayListUnmanaged(u32),
9
10// An index into `extra` pointing at an `ErrorMessage`.
11pub const MessageIndex = enum(u32) {
12 _,
13};
14
15/// After the header is:
16/// * string_bytes
17/// * extra (little endian)
18pub const Header = struct {
19 string_bytes_len: u32,
20 extra_len: u32,
21};
22
23/// Trailing: ErrorMessage for each len
24pub const ErrorMessageList = struct {
25 len: u32,
26 start: u32,
27};
28
29/// Trailing:
30/// * ReferenceTrace for each reference_trace_len
31pub const SourceLocation = struct {
32 /// null terminated string index
33 src_path: u32,
34 line: u32,
35 column: u32,
36 /// byte offset of starting token
37 span_start: u32,
38 /// byte offset of main error location
39 span_main: u32,
40 /// byte offset of end of last token
41 span_end: u32,
42 /// null terminated string index, possibly null.
43 /// Does not include the trailing newline.
44 source_line: u32 = 0,
45 reference_trace_len: u32 = 0,
46};
47
48/// Trailing:
49/// * ErrorMessage for each notes_len.
50pub const ErrorMessage = struct {
51 /// null terminated string index
52 msg: u32,
53 /// Usually one, but incremented for redundant messages.
54 count: u32 = 1,
55 /// 0 or the index into extra of a SourceLocation
56 src_loc: u32 = 0,
57 notes_len: u32 = 0,
58};
59
60pub const ReferenceTrace = struct {
61 /// null terminated string index
62 /// Except for the sentinel ReferenceTrace element, in which case:
63 /// * 0 means remaining references hidden
64 /// * >0 means N references hidden
65 decl_name: u32,
66 /// Index into extra of a SourceLocation
67 /// If this is 0, this is the sentinel ReferenceTrace element.
68 src_loc: u32,
69};
70
71pub fn init(eb: *ErrorBundle, gpa: Allocator) !void {
72 eb.* = .{
73 .string_bytes = .{},
74 .extra = .{},
75 };
76
77 // So that 0 can be used to indicate a null string.
78 try eb.string_bytes.append(gpa, 0);
79
80 _ = try addExtra(eb, gpa, ErrorMessageList{
81 .len = 0,
82 .start = 0,
83 });
84}
85
86pub fn deinit(eb: *ErrorBundle, gpa: Allocator) void {
87 eb.string_bytes.deinit(gpa);
88 eb.extra.deinit(gpa);
89 eb.* = undefined;
90}
91
92pub fn addString(eb: *ErrorBundle, gpa: Allocator, s: []const u8) !u32 {
93 const index = @intCast(u32, eb.string_bytes.items.len);
94 try eb.string_bytes.ensureUnusedCapacity(gpa, s.len + 1);
95 eb.string_bytes.appendSliceAssumeCapacity(s);
96 eb.string_bytes.appendAssumeCapacity(0);
97 return index;
98}
99
100pub fn printString(eb: *ErrorBundle, gpa: Allocator, comptime fmt: []const u8, args: anytype) !u32 {
101 const index = @intCast(u32, eb.string_bytes.items.len);
102 try eb.string_bytes.writer(gpa).print(fmt, args);
103 try eb.string_bytes.append(gpa, 0);
104 return index;
105}
106
107pub fn addErrorMessage(eb: *ErrorBundle, gpa: Allocator, em: ErrorMessage) !void {
108 if (eb.errorMessageCount() == 0) {
109 eb.setStartIndex(@intCast(u32, eb.extra.items.len));
110 }
111 _ = try addExtra(eb, gpa, em);
112}
113
114pub fn addSourceLocation(eb: *ErrorBundle, gpa: Allocator, sl: SourceLocation) !u32 {
115 return addExtra(eb, gpa, sl);
116}
117
118pub fn addReferenceTrace(eb: *ErrorBundle, gpa: Allocator, rt: ReferenceTrace) !void {
119 _ = try addExtra(eb, gpa, rt);
120}
121
122pub fn addBundle(eb: *ErrorBundle, gpa: Allocator, other: ErrorBundle) !void {
123 // Skip over the initial ErrorMessageList len field.
124 const root_fields_len = @typeInfo(ErrorMessageList).Struct.fields.len;
125 const other_list = other.extraData(ErrorMessageList, 0).data;
126 const other_extra = other.extra.items[root_fields_len..];
127
128 try eb.string_bytes.ensureUnusedCapacity(gpa, other.string_bytes.items.len);
129 try eb.extra.ensureUnusedCapacity(gpa, other_extra.len);
130
131 const new_string_base = @intCast(u32, eb.string_bytes.items.len);
132 const new_data_base = @intCast(u32, eb.extra.items.len - root_fields_len);
133
134 eb.string_bytes.appendSliceAssumeCapacity(other.string_bytes.items);
135 eb.extra.appendSliceAssumeCapacity(other_extra);
136
137 // Now we must offset the string indexes and extra indexes of the newly
138 // added extra.
139 var index = new_data_base + other_list.start;
140 for (0..other_list.len) |_| {
141 index = try patchMessage(eb, index, new_string_base, new_data_base);
142 }
143}
144
145fn patchMessage(eb: *ErrorBundle, msg_idx: usize, new_string_base: u32, new_data_base: u32) !u32 {
146 var msg = eb.extraData(ErrorMessage, msg_idx);
147 if (msg.data.msg != 0) msg.data.msg += new_string_base;
148 if (msg.data.src_loc != 0) msg.data.src_loc += new_data_base;
149 eb.setExtra(msg_idx, msg.data);
150
151 try patchSrcLoc(eb, msg.data.src_loc, new_string_base, new_data_base);
152
153 var index = @intCast(u32, msg.end);
154 for (0..msg.data.notes_len) |_| {
155 index = try patchMessage(eb, index, new_string_base, new_data_base);
156 }
157 return index;
158}
159
160fn patchSrcLoc(eb: *ErrorBundle, idx: usize, new_string_base: u32, new_data_base: u32) !void {
161 if (idx == 0) return;
162
163 var src_loc = eb.extraData(SourceLocation, idx);
164 if (src_loc.data.src_path != 0) src_loc.data.src_path += new_string_base;
165 if (src_loc.data.source_line != 0) src_loc.data.source_line += new_string_base;
166 eb.setExtra(idx, src_loc.data);
167
168 var index = src_loc.end;
169 for (0..src_loc.data.reference_trace_len) |_| {
170 var ref_trace = eb.extraData(ReferenceTrace, index);
171 if (ref_trace.data.decl_name != 0) ref_trace.data.decl_name += new_string_base;
172 if (ref_trace.data.src_loc != 0) ref_trace.data.src_loc += new_data_base;
173 eb.setExtra(index, ref_trace.data);
174 try patchSrcLoc(eb, ref_trace.data.src_loc, new_string_base, new_data_base);
175 index = ref_trace.end;
176 }
177}
178
179fn addExtra(eb: *ErrorBundle, gpa: Allocator, extra: anytype) Allocator.Error!u32 {
180 const fields = @typeInfo(@TypeOf(extra)).Struct.fields;
181 try eb.extra.ensureUnusedCapacity(gpa, fields.len);
182 return addExtraAssumeCapacity(eb, extra);
183}
184
185fn addExtraAssumeCapacity(eb: *ErrorBundle, extra: anytype) u32 {
186 const fields = @typeInfo(@TypeOf(extra)).Struct.fields;
187 const result = @intCast(u32, eb.extra.items.len);
188 eb.extra.items.len += fields.len;
189 setExtra(eb, result, extra);
190 return result;
191}
192
193fn setExtra(eb: *ErrorBundle, index: usize, extra: anytype) void {
194 const fields = @typeInfo(@TypeOf(extra)).Struct.fields;
195 var i = index;
196 inline for (fields) |field| {
197 eb.extra.items[i] = switch (field.type) {
198 u32 => @field(extra, field.name),
199 else => @compileError("bad field type"),
200 };
201 i += 1;
202 }
203}
204
205pub fn errorMessageCount(eb: ErrorBundle) u32 {
206 return eb.extra.items[0];
207}
208
209pub fn setErrorMessageCount(eb: *ErrorBundle, count: u32) void {
210 eb.extra.items[0] = count;
211}
212
213pub fn incrementCount(eb: *ErrorBundle, delta: u32) void {
214 eb.extra.items[0] += delta;
215}
216
217pub fn getStartIndex(eb: ErrorBundle) u32 {
218 return eb.extra.items[1];
219}
220
221pub fn setStartIndex(eb: *ErrorBundle, index: u32) void {
222 eb.extra.items[1] = index;
223}
224
225pub fn getErrorMessage(eb: ErrorBundle, index: MessageIndex) ErrorMessage {
226 return eb.extraData(ErrorMessage, @enumToInt(index)).data;
227}
228
229pub fn getSourceLocation(eb: ErrorBundle, index: u32) SourceLocation {
230 assert(index != 0);
231 return eb.extraData(SourceLocation, index).data;
232}
233
234/// Returns the requested data, as well as the new index which is at the start of the
235/// trailers for the object.
236fn extraData(eb: ErrorBundle, comptime T: type, index: usize) struct { data: T, end: usize } {
237 const fields = @typeInfo(T).Struct.fields;
238 var i: usize = index;
239 var result: T = undefined;
240 inline for (fields) |field| {
241 @field(result, field.name) = switch (field.type) {
242 u32 => eb.extra.items[i],
243 else => @compileError("bad field type"),
244 };
245 i += 1;
246 }
247 return .{
248 .data = result,
249 .end = i,
250 };
251}
252
253/// Given an index into `string_bytes` returns the null-terminated string found there.
254pub fn nullTerminatedString(eb: ErrorBundle, index: usize) [:0]const u8 {
255 const string_bytes = eb.string_bytes.items;
256 var end: usize = index;
257 while (string_bytes[end] != 0) {
258 end += 1;
259 }
260 return string_bytes[index..end :0];
261}
262
263pub fn renderToStdErr(eb: ErrorBundle, ttyconf: std.debug.TTY.Config) void {
264 std.debug.getStderrMutex().lock();
265 defer std.debug.getStderrMutex().unlock();
266 const stderr = std.io.getStdErr();
267 return renderToWriter(eb, ttyconf, stderr.writer()) catch return;
268}
269
270pub fn renderToWriter(
271 eb: ErrorBundle,
272 ttyconf: std.debug.TTY.Config,
273 writer: anytype,
274) anyerror!void {
275 const list = eb.extraData(ErrorMessageList, 0).data;
276 var index: usize = list.start;
277 for (0..list.len) |_| {
278 const err_msg = eb.extraData(ErrorMessage, index);
279 index = try renderErrorMessageToWriter(eb, err_msg.data, err_msg.end, ttyconf, writer, "error", .Red, 0);
280 }
281}
282
283fn renderErrorMessageToWriter(
284 eb: ErrorBundle,
285 err_msg: ErrorMessage,
286 end_index: usize,
287 ttyconf: std.debug.TTY.Config,
288 stderr: anytype,
289 kind: []const u8,
290 color: std.debug.TTY.Color,
291 indent: usize,
292) anyerror!usize {
293 var counting_writer = std.io.countingWriter(stderr);
294 const counting_stderr = counting_writer.writer();
295 if (err_msg.src_loc != 0) {
296 const src = eb.extraData(SourceLocation, err_msg.src_loc);
297 try counting_stderr.writeByteNTimes(' ', indent);
298 try ttyconf.setColor(stderr, .Bold);
299 try counting_stderr.print("{s}:{d}:{d}: ", .{
300 eb.nullTerminatedString(src.data.src_path),
301 src.data.line + 1,
302 src.data.column + 1,
303 });
304 try ttyconf.setColor(stderr, color);
305 try counting_stderr.writeAll(kind);
306 try counting_stderr.writeAll(": ");
307 // This is the length of the part before the error message:
308 // e.g. "file.zig:4:5: error: "
309 const prefix_len = @intCast(usize, counting_stderr.context.bytes_written);
310 try ttyconf.setColor(stderr, .Reset);
311 try ttyconf.setColor(stderr, .Bold);
312 if (err_msg.count == 1) {
313 try writeMsg(eb, err_msg, stderr, prefix_len);
314 try stderr.writeByte('\n');
315 } else {
316 try writeMsg(eb, err_msg, stderr, prefix_len);
317 try ttyconf.setColor(stderr, .Dim);
318 try stderr.print(" ({d} times)\n", .{err_msg.count});
319 }
320 try ttyconf.setColor(stderr, .Reset);
321 if (src.data.source_line != 0) {
322 const line = eb.nullTerminatedString(src.data.source_line);
323 for (line) |b| switch (b) {
324 '\t' => try stderr.writeByte(' '),
325 else => try stderr.writeByte(b),
326 };
327 try stderr.writeByte('\n');
328 // TODO basic unicode code point monospace width
329 const before_caret = src.data.span_main - src.data.span_start;
330 // -1 since span.main includes the caret
331 const after_caret = src.data.span_end - src.data.span_main -| 1;
332 try stderr.writeByteNTimes(' ', src.data.column - before_caret);
333 try ttyconf.setColor(stderr, .Green);
334 try stderr.writeByteNTimes('~', before_caret);
335 try stderr.writeByte('^');
336 try stderr.writeByteNTimes('~', after_caret);
337 try stderr.writeByte('\n');
338 try ttyconf.setColor(stderr, .Reset);
339 }
340 var index = end_index;
341 for (0..err_msg.notes_len) |_| {
342 const note = eb.extraData(ErrorMessage, index);
343 index = try renderErrorMessageToWriter(eb, note.data, note.end, ttyconf, stderr, "note", .Cyan, indent);
344 }
345 if (src.data.reference_trace_len > 0) {
346 try ttyconf.setColor(stderr, .Reset);
347 try ttyconf.setColor(stderr, .Dim);
348 try stderr.print("referenced by:\n", .{});
349 var ref_index = src.end;
350 for (0..src.data.reference_trace_len) |_| {
351 const ref_trace = eb.extraData(ReferenceTrace, ref_index);
352 ref_index = ref_trace.end;
353 if (ref_trace.data.src_loc != 0) {
354 const ref_src = eb.getSourceLocation(ref_trace.data.src_loc);
355 try stderr.print(" {s}: {s}:{d}:{d}\n", .{
356 eb.nullTerminatedString(ref_trace.data.decl_name),
357 eb.nullTerminatedString(ref_src.src_path),
358 ref_src.line + 1,
359 ref_src.column + 1,
360 });
361 } else if (ref_trace.data.decl_name != 0) {
362 const count = ref_trace.data.decl_name;
363 try stderr.print(
364 " {d} reference(s) hidden; use '-freference-trace={d}' to see all references\n",
365 .{ count, count + src.data.reference_trace_len - 1 },
366 );
367 } else {
368 try stderr.print(
369 " remaining reference traces hidden; use '-freference-trace' to see all reference traces\n",
370 .{},
371 );
372 }
373 }
374 try stderr.writeByte('\n');
375 try ttyconf.setColor(stderr, .Reset);
376 }
377 return index;
378 } else {
379 try ttyconf.setColor(stderr, color);
380 try stderr.writeByteNTimes(' ', indent);
381 try stderr.writeAll(kind);
382 try stderr.writeAll(": ");
383 try ttyconf.setColor(stderr, .Reset);
384 const msg = eb.nullTerminatedString(err_msg.msg);
385 if (err_msg.count == 1) {
386 try stderr.print("{s}\n", .{msg});
387 } else {
388 try stderr.print("{s}", .{msg});
389 try ttyconf.setColor(stderr, .Dim);
390 try stderr.print(" ({d} times)\n", .{err_msg.count});
391 }
392 try ttyconf.setColor(stderr, .Reset);
393 var index = end_index;
394 for (0..err_msg.notes_len) |_| {
395 const note = eb.extraData(ErrorMessage, index);
396 index = try renderErrorMessageToWriter(eb, note.data, note.end, ttyconf, stderr, "note", .Cyan, indent + 4);
397 }
398 return index;
399 }
400}
401
402/// Splits the error message up into lines to properly indent them
403/// to allow for long, good-looking error messages.
404///
405/// This is used to split the message in `@compileError("hello\nworld")` for example.
406fn writeMsg(eb: ErrorBundle, err_msg: ErrorMessage, stderr: anytype, indent: usize) !void {
407 var lines = std.mem.split(u8, eb.nullTerminatedString(err_msg.msg), "\n");
408 while (lines.next()) |line| {
409 try stderr.writeAll(line);
410 if (lines.index == null) break;
411 try stderr.writeByte('\n');
412 try stderr.writeByteNTimes(' ', indent);
413 }
414}
415
416const std = @import("std");
417const ErrorBundle = @This();
418const Allocator = std.mem.Allocator;
419const assert = std.debug.assert;
src/AstGen.zig+70-26
...@@ -133,6 +133,8 @@ pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir {...@@ -133,6 +133,8 @@ pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir {
133 try astgen.extra.ensureTotalCapacity(gpa, tree.nodes.len + reserved_count);133 try astgen.extra.ensureTotalCapacity(gpa, tree.nodes.len + reserved_count);
134 astgen.extra.items.len += reserved_count;134 astgen.extra.items.len += reserved_count;
135135
136 try lowerAstErrors(&astgen);
137
136 var top_scope: Scope.Top = .{};138 var top_scope: Scope.Top = .{};
137139
138 var gz_instructions: std.ArrayListUnmanaged(Zir.Inst.Index) = .{};140 var gz_instructions: std.ArrayListUnmanaged(Zir.Inst.Index) = .{};
...@@ -10401,27 +10403,11 @@ fn appendErrorTokNotes(...@@ -10401,27 +10403,11 @@ fn appendErrorTokNotes(
10401 args: anytype,10403 args: anytype,
10402 notes: []const u32,10404 notes: []const u32,
10403) !void {10405) !void {
10404 @setCold(true);10406 return appendErrorTokNotesOff(astgen, token, 0, format, args, notes);
10405 const string_bytes = &astgen.string_bytes;
10406 const msg = @intCast(u32, string_bytes.items.len);
10407 try string_bytes.writer(astgen.gpa).print(format ++ "\x00", args);
10408 const notes_index: u32 = if (notes.len != 0) blk: {
10409 const notes_start = astgen.extra.items.len;
10410 try astgen.extra.ensureTotalCapacity(astgen.gpa, notes_start + 1 + notes.len);
10411 astgen.extra.appendAssumeCapacity(@intCast(u32, notes.len));
10412 astgen.extra.appendSliceAssumeCapacity(notes);
10413 break :blk @intCast(u32, notes_start);
10414 } else 0;
10415 try astgen.compile_errors.append(astgen.gpa, .{
10416 .msg = msg,
10417 .node = 0,
10418 .token = token,
10419 .byte_offset = 0,
10420 .notes = notes_index,
10421 });
10422}10407}
1042310408
10424/// Same as `fail`, except given an absolute byte offset.10409/// Same as `fail`, except given a token plus an offset from its starting byte
10410/// offset.
10425fn failOff(10411fn failOff(
10426 astgen: *AstGen,10412 astgen: *AstGen,
10427 token: Ast.TokenIndex,10413 token: Ast.TokenIndex,
...@@ -10429,27 +10415,36 @@ fn failOff(...@@ -10429,27 +10415,36 @@ fn failOff(
10429 comptime format: []const u8,10415 comptime format: []const u8,
10430 args: anytype,10416 args: anytype,
10431) InnerError {10417) InnerError {
10432 try appendErrorOff(astgen, token, byte_offset, format, args);10418 try appendErrorTokNotesOff(astgen, token, byte_offset, format, args, &.{});
10433 return error.AnalysisFail;10419 return error.AnalysisFail;
10434}10420}
1043510421
10436fn appendErrorOff(10422fn appendErrorTokNotesOff(
10437 astgen: *AstGen,10423 astgen: *AstGen,
10438 token: Ast.TokenIndex,10424 token: Ast.TokenIndex,
10439 byte_offset: u32,10425 byte_offset: u32,
10440 comptime format: []const u8,10426 comptime format: []const u8,
10441 args: anytype,10427 args: anytype,
10442) Allocator.Error!void {10428 notes: []const u32,
10429) !void {
10443 @setCold(true);10430 @setCold(true);
10431 const gpa = astgen.gpa;
10444 const string_bytes = &astgen.string_bytes;10432 const string_bytes = &astgen.string_bytes;
10445 const msg = @intCast(u32, string_bytes.items.len);10433 const msg = @intCast(u32, string_bytes.items.len);
10446 try string_bytes.writer(astgen.gpa).print(format ++ "\x00", args);10434 try string_bytes.writer(gpa).print(format ++ "\x00", args);
10447 try astgen.compile_errors.append(astgen.gpa, .{10435 const notes_index: u32 = if (notes.len != 0) blk: {
10436 const notes_start = astgen.extra.items.len;
10437 try astgen.extra.ensureTotalCapacity(gpa, notes_start + 1 + notes.len);
10438 astgen.extra.appendAssumeCapacity(@intCast(u32, notes.len));
10439 astgen.extra.appendSliceAssumeCapacity(notes);
10440 break :blk @intCast(u32, notes_start);
10441 } else 0;
10442 try astgen.compile_errors.append(gpa, .{
10448 .msg = msg,10443 .msg = msg,
10449 .node = 0,10444 .node = 0,
10450 .token = token,10445 .token = token,
10451 .byte_offset = byte_offset,10446 .byte_offset = byte_offset,
10452 .notes = 0,10447 .notes = notes_index,
10453 });10448 });
10454}10449}
1045510450
...@@ -10458,6 +10453,16 @@ fn errNoteTok(...@@ -10458,6 +10453,16 @@ fn errNoteTok(
10458 token: Ast.TokenIndex,10453 token: Ast.TokenIndex,
10459 comptime format: []const u8,10454 comptime format: []const u8,
10460 args: anytype,10455 args: anytype,
10456) Allocator.Error!u32 {
10457 return errNoteTokOff(astgen, token, 0, format, args);
10458}
10459
10460fn errNoteTokOff(
10461 astgen: *AstGen,
10462 token: Ast.TokenIndex,
10463 byte_offset: u32,
10464 comptime format: []const u8,
10465 args: anytype,
10461) Allocator.Error!u32 {10466) Allocator.Error!u32 {
10462 @setCold(true);10467 @setCold(true);
10463 const string_bytes = &astgen.string_bytes;10468 const string_bytes = &astgen.string_bytes;
...@@ -10467,7 +10472,7 @@ fn errNoteTok(...@@ -10467,7 +10472,7 @@ fn errNoteTok(
10467 .msg = msg,10472 .msg = msg,
10468 .node = 0,10473 .node = 0,
10469 .token = token,10474 .token = token,
10470 .byte_offset = 0,10475 .byte_offset = byte_offset,
10471 .notes = 0,10476 .notes = 0,
10472 });10477 });
10473}10478}
...@@ -12634,3 +12639,42 @@ fn emitDbgStmt(gz: *GenZir, line: u32, column: u32) !void {...@@ -12634,3 +12639,42 @@ fn emitDbgStmt(gz: *GenZir, line: u32, column: u32) !void {
12634 },12639 },
12635 } });12640 } });
12636}12641}
12642
12643fn lowerAstErrors(astgen: *AstGen) !void {
12644 const tree = astgen.tree;
12645 if (tree.errors.len == 0) return;
12646
12647 const gpa = astgen.gpa;
12648 const parse_err = tree.errors[0];
12649
12650 var msg: std.ArrayListUnmanaged(u8) = .{};
12651 defer msg.deinit(gpa);
12652
12653 const token_starts = tree.tokens.items(.start);
12654 const token_tags = tree.tokens.items(.tag);
12655
12656 var notes: std.ArrayListUnmanaged(u32) = .{};
12657 defer notes.deinit(gpa);
12658
12659 if (token_tags[parse_err.token + @boolToInt(parse_err.token_is_prev)] == .invalid) {
12660 const tok = parse_err.token + @boolToInt(parse_err.token_is_prev);
12661 const bad_off = @intCast(u32, tree.tokenSlice(parse_err.token + @boolToInt(parse_err.token_is_prev)).len);
12662 const byte_abs = token_starts[parse_err.token + @boolToInt(parse_err.token_is_prev)] + bad_off;
12663 try notes.append(gpa, try astgen.errNoteTokOff(tok, bad_off, "invalid byte: '{'}'", .{
12664 std.zig.fmtEscapes(tree.source[byte_abs..][0..1]),
12665 }));
12666 }
12667
12668 for (tree.errors[1..]) |note| {
12669 if (!note.is_note) break;
12670
12671 msg.clearRetainingCapacity();
12672 try tree.renderError(note, msg.writer(gpa));
12673 try notes.append(gpa, try astgen.errNoteTok(note.token, "{s}", .{msg.items}));
12674 }
12675
12676 const extra_offset = tree.errorOffset(parse_err);
12677 msg.clearRetainingCapacity();
12678 try tree.renderError(parse_err, msg.writer(gpa));
12679 try astgen.appendErrorTokNotesOff(parse_err.token, extra_offset, "{s}", .{msg.items}, notes.items);
12680}
src/Compilation.zig+379-566
...@@ -9,6 +9,7 @@ const log = std.log.scoped(.compilation);...@@ -9,6 +9,7 @@ const log = std.log.scoped(.compilation);
9const Target = std.Target;9const Target = std.Target;
10const ThreadPool = std.Thread.Pool;10const ThreadPool = std.Thread.Pool;
11const WaitGroup = std.Thread.WaitGroup;11const WaitGroup = std.Thread.WaitGroup;
12const ErrorBundle = std.zig.ErrorBundle;
1213
13const Value = @import("value.zig").Value;14const Value = @import("value.zig").Value;
14const Type = @import("type.zig").Type;15const Type = @import("type.zig").Type;
...@@ -334,12 +335,41 @@ pub const MiscTask = enum {...@@ -334,12 +335,41 @@ pub const MiscTask = enum {
334 libssp,335 libssp,
335 zig_libc,336 zig_libc,
336 analyze_pkg,337 analyze_pkg,
338
339 @"musl crti.o",
340 @"musl crtn.o",
341 @"musl crt1.o",
342 @"musl rcrt1.o",
343 @"musl Scrt1.o",
344 @"musl libc.a",
345 @"musl libc.so",
346
347 @"wasi crt1-reactor.o",
348 @"wasi crt1-command.o",
349 @"wasi libc.a",
350 @"libwasi-emulated-process-clocks.a",
351 @"libwasi-emulated-getpid.a",
352 @"libwasi-emulated-mman.a",
353 @"libwasi-emulated-signal.a",
354
355 @"glibc crti.o",
356 @"glibc crtn.o",
357 @"glibc Scrt1.o",
358 @"glibc libc_nonshared.a",
359 @"glibc shared object",
360
361 @"mingw-w64 crt2.o",
362 @"mingw-w64 dllcrt2.o",
363 @"mingw-w64 mingw32.lib",
364 @"mingw-w64 msvcrt-os.lib",
365 @"mingw-w64 mingwex.lib",
366 @"mingw-w64 uuid.lib",
337};367};
338368
339pub const MiscError = struct {369pub const MiscError = struct {
340 /// Allocated with gpa.370 /// Allocated with gpa.
341 msg: []u8,371 msg: []u8,
342 children: ?AllErrors = null,372 children: ?ErrorBundle = null,
343373
344 pub fn deinit(misc_err: *MiscError, gpa: Allocator) void {374 pub fn deinit(misc_err: *MiscError, gpa: Allocator) void {
345 gpa.free(misc_err.msg);375 gpa.free(misc_err.msg);
...@@ -365,448 +395,6 @@ pub const LldError = struct {...@@ -365,448 +395,6 @@ pub const LldError = struct {
365 }395 }
366};396};
367397
368/// To support incremental compilation, errors are stored in various places
369/// so that they can be created and destroyed appropriately. This structure
370/// is used to collect all the errors from the various places into one
371/// convenient place for API users to consume. It is allocated into 1 arena
372/// and freed all at once.
373pub const AllErrors = struct {
374 arena: std.heap.ArenaAllocator.State,
375 list: []const Message,
376
377 pub const Message = union(enum) {
378 src: struct {
379 msg: []const u8,
380 src_path: []const u8,
381 line: u32,
382 column: u32,
383 span: Module.SrcLoc.Span,
384 /// Usually one, but incremented for redundant messages.
385 count: u32 = 1,
386 /// Does not include the trailing newline.
387 source_line: ?[]const u8,
388 notes: []const Message = &.{},
389 reference_trace: []Message = &.{},
390
391 /// Splits the error message up into lines to properly indent them
392 /// to allow for long, good-looking error messages.
393 ///
394 /// This is used to split the message in `@compileError("hello\nworld")` for example.
395 fn writeMsg(src: @This(), stderr: anytype, indent: usize) !void {
396 var lines = mem.split(u8, src.msg, "\n");
397 while (lines.next()) |line| {
398 try stderr.writeAll(line);
399 if (lines.index == null) break;
400 try stderr.writeByte('\n');
401 try stderr.writeByteNTimes(' ', indent);
402 }
403 }
404 },
405 plain: struct {
406 msg: []const u8,
407 notes: []Message = &.{},
408 /// Usually one, but incremented for redundant messages.
409 count: u32 = 1,
410 },
411
412 pub fn incrementCount(msg: *Message) void {
413 switch (msg.*) {
414 .src => |*src| {
415 src.count += 1;
416 },
417 .plain => |*plain| {
418 plain.count += 1;
419 },
420 }
421 }
422
423 pub fn renderToStdErr(msg: Message, ttyconf: std.debug.TTY.Config) void {
424 std.debug.getStderrMutex().lock();
425 defer std.debug.getStderrMutex().unlock();
426 const stderr = std.io.getStdErr();
427 return msg.renderToWriter(ttyconf, stderr.writer(), "error", .Red, 0) catch return;
428 }
429
430 pub fn renderToWriter(
431 msg: Message,
432 ttyconf: std.debug.TTY.Config,
433 stderr: anytype,
434 kind: []const u8,
435 color: std.debug.TTY.Color,
436 indent: usize,
437 ) anyerror!void {
438 var counting_writer = std.io.countingWriter(stderr);
439 const counting_stderr = counting_writer.writer();
440 switch (msg) {
441 .src => |src| {
442 try counting_stderr.writeByteNTimes(' ', indent);
443 try ttyconf.setColor(stderr, .Bold);
444 try counting_stderr.print("{s}:{d}:{d}: ", .{
445 src.src_path,
446 src.line + 1,
447 src.column + 1,
448 });
449 try ttyconf.setColor(stderr, color);
450 try counting_stderr.writeAll(kind);
451 try counting_stderr.writeAll(": ");
452 // This is the length of the part before the error message:
453 // e.g. "file.zig:4:5: error: "
454 const prefix_len = @intCast(usize, counting_stderr.context.bytes_written);
455 try ttyconf.setColor(stderr, .Reset);
456 try ttyconf.setColor(stderr, .Bold);
457 if (src.count == 1) {
458 try src.writeMsg(stderr, prefix_len);
459 try stderr.writeByte('\n');
460 } else {
461 try src.writeMsg(stderr, prefix_len);
462 try ttyconf.setColor(stderr, .Dim);
463 try stderr.print(" ({d} times)\n", .{src.count});
464 }
465 try ttyconf.setColor(stderr, .Reset);
466 if (src.source_line) |line| {
467 for (line) |b| switch (b) {
468 '\t' => try stderr.writeByte(' '),
469 else => try stderr.writeByte(b),
470 };
471 try stderr.writeByte('\n');
472 // TODO basic unicode code point monospace width
473 const before_caret = src.span.main - src.span.start;
474 // -1 since span.main includes the caret
475 const after_caret = src.span.end - src.span.main -| 1;
476 try stderr.writeByteNTimes(' ', src.column - before_caret);
477 try ttyconf.setColor(stderr, .Green);
478 try stderr.writeByteNTimes('~', before_caret);
479 try stderr.writeByte('^');
480 try stderr.writeByteNTimes('~', after_caret);
481 try stderr.writeByte('\n');
482 try ttyconf.setColor(stderr, .Reset);
483 }
484 for (src.notes) |note| {
485 try note.renderToWriter(ttyconf, stderr, "note", .Cyan, indent);
486 }
487 if (src.reference_trace.len != 0) {
488 try ttyconf.setColor(stderr, .Reset);
489 try ttyconf.setColor(stderr, .Dim);
490 try stderr.print("referenced by:\n", .{});
491 for (src.reference_trace) |reference| {
492 switch (reference) {
493 .src => |ref_src| try stderr.print(" {s}: {s}:{d}:{d}\n", .{
494 ref_src.msg,
495 ref_src.src_path,
496 ref_src.line + 1,
497 ref_src.column + 1,
498 }),
499 .plain => |plain| if (plain.count != 0) {
500 try stderr.print(
501 " {d} reference(s) hidden; use '-freference-trace={d}' to see all references\n",
502 .{ plain.count, plain.count + src.reference_trace.len - 1 },
503 );
504 } else {
505 try stderr.print(
506 " remaining reference traces hidden; use '-freference-trace' to see all reference traces\n",
507 .{},
508 );
509 },
510 }
511 }
512 try stderr.writeByte('\n');
513 try ttyconf.setColor(stderr, .Reset);
514 }
515 },
516 .plain => |plain| {
517 try ttyconf.setColor(stderr, color);
518 try stderr.writeByteNTimes(' ', indent);
519 try stderr.writeAll(kind);
520 try stderr.writeAll(": ");
521 try ttyconf.setColor(stderr, .Reset);
522 if (plain.count == 1) {
523 try stderr.print("{s}\n", .{plain.msg});
524 } else {
525 try stderr.print("{s}", .{plain.msg});
526 try ttyconf.setColor(stderr, .Dim);
527 try stderr.print(" ({d} times)\n", .{plain.count});
528 }
529 try ttyconf.setColor(stderr, .Reset);
530 for (plain.notes) |note| {
531 try note.renderToWriter(ttyconf, stderr, "note", .Cyan, indent + 4);
532 }
533 },
534 }
535 }
536
537 pub const HashContext = struct {
538 pub fn hash(ctx: HashContext, key: *Message) u64 {
539 _ = ctx;
540 var hasher = std.hash.Wyhash.init(0);
541
542 switch (key.*) {
543 .src => |src| {
544 hasher.update(src.msg);
545 hasher.update(src.src_path);
546 std.hash.autoHash(&hasher, src.line);
547 std.hash.autoHash(&hasher, src.column);
548 std.hash.autoHash(&hasher, src.span.main);
549 },
550 .plain => |plain| {
551 hasher.update(plain.msg);
552 },
553 }
554
555 return hasher.final();
556 }
557
558 pub fn eql(ctx: HashContext, a: *Message, b: *Message) bool {
559 _ = ctx;
560 switch (a.*) {
561 .src => |a_src| switch (b.*) {
562 .src => |b_src| {
563 return mem.eql(u8, a_src.msg, b_src.msg) and
564 mem.eql(u8, a_src.src_path, b_src.src_path) and
565 a_src.line == b_src.line and
566 a_src.column == b_src.column and
567 a_src.span.main == b_src.span.main;
568 },
569 .plain => return false,
570 },
571 .plain => |a_plain| switch (b.*) {
572 .src => return false,
573 .plain => |b_plain| {
574 return mem.eql(u8, a_plain.msg, b_plain.msg);
575 },
576 },
577 }
578 }
579 };
580 };
581
582 pub fn deinit(self: *AllErrors, gpa: Allocator) void {
583 self.arena.promote(gpa).deinit();
584 }
585
586 pub fn add(
587 module: *Module,
588 arena: *std.heap.ArenaAllocator,
589 errors: *std.ArrayList(Message),
590 module_err_msg: Module.ErrorMsg,
591 ) !void {
592 const allocator = arena.allocator();
593
594 const notes_buf = try allocator.alloc(Message, module_err_msg.notes.len);
595 var note_i: usize = 0;
596
597 // De-duplicate error notes. The main use case in mind for this is
598 // too many "note: called from here" notes when eval branch quota is reached.
599 var seen_notes = std.HashMap(
600 *Message,
601 void,
602 Message.HashContext,
603 std.hash_map.default_max_load_percentage,
604 ).init(allocator);
605 const err_source = module_err_msg.src_loc.file_scope.getSource(module.gpa) catch |err| {
606 const file_path = try module_err_msg.src_loc.file_scope.fullPath(allocator);
607 try errors.append(.{
608 .plain = .{
609 .msg = try std.fmt.allocPrint(allocator, "unable to load '{s}': {s}", .{
610 file_path, @errorName(err),
611 }),
612 },
613 });
614 return;
615 };
616 const err_span = try module_err_msg.src_loc.span(module.gpa);
617 const err_loc = std.zig.findLineColumn(err_source.bytes, err_span.main);
618
619 for (module_err_msg.notes) |module_note| {
620 const source = try module_note.src_loc.file_scope.getSource(module.gpa);
621 const span = try module_note.src_loc.span(module.gpa);
622 const loc = std.zig.findLineColumn(source.bytes, span.main);
623 const file_path = try module_note.src_loc.file_scope.fullPath(allocator);
624 const note = &notes_buf[note_i];
625 note.* = .{
626 .src = .{
627 .src_path = file_path,
628 .msg = try allocator.dupe(u8, module_note.msg),
629 .span = span,
630 .line = @intCast(u32, loc.line),
631 .column = @intCast(u32, loc.column),
632 .source_line = if (err_loc.eql(loc)) null else try allocator.dupe(u8, loc.source_line),
633 },
634 };
635 const gop = try seen_notes.getOrPut(note);
636 if (gop.found_existing) {
637 gop.key_ptr.*.incrementCount();
638 } else {
639 note_i += 1;
640 }
641 }
642
643 const reference_trace = try allocator.alloc(Message, module_err_msg.reference_trace.len);
644 for (reference_trace, 0..) |*reference, i| {
645 const module_reference = module_err_msg.reference_trace[i];
646 if (module_reference.hidden != 0) {
647 reference.* = .{ .plain = .{ .msg = undefined, .count = module_reference.hidden } };
648 break;
649 } else if (module_reference.decl == null) {
650 reference.* = .{ .plain = .{ .msg = undefined, .count = 0 } };
651 break;
652 }
653 const source = try module_reference.src_loc.file_scope.getSource(module.gpa);
654 const span = try module_reference.src_loc.span(module.gpa);
655 const loc = std.zig.findLineColumn(source.bytes, span.main);
656 const file_path = try module_reference.src_loc.file_scope.fullPath(allocator);
657 reference.* = .{
658 .src = .{
659 .src_path = file_path,
660 .msg = try allocator.dupe(u8, std.mem.sliceTo(module_reference.decl.?, 0)),
661 .span = span,
662 .line = @intCast(u32, loc.line),
663 .column = @intCast(u32, loc.column),
664 .source_line = null,
665 },
666 };
667 }
668 const file_path = try module_err_msg.src_loc.file_scope.fullPath(allocator);
669 try errors.append(.{
670 .src = .{
671 .src_path = file_path,
672 .msg = try allocator.dupe(u8, module_err_msg.msg),
673 .span = err_span,
674 .line = @intCast(u32, err_loc.line),
675 .column = @intCast(u32, err_loc.column),
676 .notes = notes_buf[0..note_i],
677 .reference_trace = reference_trace,
678 .source_line = if (module_err_msg.src_loc.lazy == .entire_file) null else try allocator.dupe(u8, err_loc.source_line),
679 },
680 });
681 }
682
683 pub fn addZir(
684 arena: Allocator,
685 errors: *std.ArrayList(Message),
686 file: *Module.File,
687 ) !void {
688 assert(file.zir_loaded);
689 assert(file.tree_loaded);
690 assert(file.source_loaded);
691 const payload_index = file.zir.extra[@enumToInt(Zir.ExtraIndex.compile_errors)];
692 assert(payload_index != 0);
693
694 const header = file.zir.extraData(Zir.Inst.CompileErrors, payload_index);
695 const items_len = header.data.items_len;
696 var extra_index = header.end;
697 var item_i: usize = 0;
698 while (item_i < items_len) : (item_i += 1) {
699 const item = file.zir.extraData(Zir.Inst.CompileErrors.Item, extra_index);
700 extra_index = item.end;
701 const err_span = blk: {
702 if (item.data.node != 0) {
703 break :blk Module.SrcLoc.nodeToSpan(&file.tree, item.data.node);
704 }
705 const token_starts = file.tree.tokens.items(.start);
706 const start = token_starts[item.data.token] + item.data.byte_offset;
707 const end = start + @intCast(u32, file.tree.tokenSlice(item.data.token).len) - item.data.byte_offset;
708 break :blk Module.SrcLoc.Span{ .start = start, .end = end, .main = start };
709 };
710 const err_loc = std.zig.findLineColumn(file.source, err_span.main);
711
712 var notes: []Message = &[0]Message{};
713 if (item.data.notes != 0) {
714 const block = file.zir.extraData(Zir.Inst.Block, item.data.notes);
715 const body = file.zir.extra[block.end..][0..block.data.body_len];
716 notes = try arena.alloc(Message, body.len);
717 for (notes, 0..) |*note, i| {
718 const note_item = file.zir.extraData(Zir.Inst.CompileErrors.Item, body[i]);
719 const msg = file.zir.nullTerminatedString(note_item.data.msg);
720 const span = blk: {
721 if (note_item.data.node != 0) {
722 break :blk Module.SrcLoc.nodeToSpan(&file.tree, note_item.data.node);
723 }
724 const token_starts = file.tree.tokens.items(.start);
725 const start = token_starts[note_item.data.token] + note_item.data.byte_offset;
726 const end = start + @intCast(u32, file.tree.tokenSlice(note_item.data.token).len) - item.data.byte_offset;
727 break :blk Module.SrcLoc.Span{ .start = start, .end = end, .main = start };
728 };
729 const loc = std.zig.findLineColumn(file.source, span.main);
730
731 note.* = .{
732 .src = .{
733 .src_path = try file.fullPath(arena),
734 .msg = try arena.dupe(u8, msg),
735 .span = span,
736 .line = @intCast(u32, loc.line),
737 .column = @intCast(u32, loc.column),
738 .notes = &.{}, // TODO rework this function to be recursive
739 .source_line = if (loc.eql(err_loc)) null else try arena.dupe(u8, loc.source_line),
740 },
741 };
742 }
743 }
744
745 const msg = file.zir.nullTerminatedString(item.data.msg);
746 try errors.append(.{
747 .src = .{
748 .src_path = try file.fullPath(arena),
749 .msg = try arena.dupe(u8, msg),
750 .span = err_span,
751 .line = @intCast(u32, err_loc.line),
752 .column = @intCast(u32, err_loc.column),
753 .notes = notes,
754 .source_line = try arena.dupe(u8, err_loc.source_line),
755 },
756 });
757 }
758 }
759
760 fn addPlain(
761 arena: *std.heap.ArenaAllocator,
762 errors: *std.ArrayList(Message),
763 msg: []const u8,
764 ) !void {
765 _ = arena;
766 try errors.append(.{ .plain = .{ .msg = msg } });
767 }
768
769 fn addPlainWithChildren(
770 arena: *std.heap.ArenaAllocator,
771 errors: *std.ArrayList(Message),
772 msg: []const u8,
773 optional_children: ?AllErrors,
774 ) !void {
775 const allocator = arena.allocator();
776 const duped_msg = try allocator.dupe(u8, msg);
777 if (optional_children) |*children| {
778 try errors.append(.{ .plain = .{
779 .msg = duped_msg,
780 .notes = try dupeList(children.list, allocator),
781 } });
782 } else {
783 try errors.append(.{ .plain = .{ .msg = duped_msg } });
784 }
785 }
786
787 fn dupeList(list: []const Message, arena: Allocator) Allocator.Error![]Message {
788 const duped_list = try arena.alloc(Message, list.len);
789 for (list, 0..) |item, i| {
790 duped_list[i] = switch (item) {
791 .src => |src| .{ .src = .{
792 .msg = try arena.dupe(u8, src.msg),
793 .src_path = try arena.dupe(u8, src.src_path),
794 .line = src.line,
795 .column = src.column,
796 .span = src.span,
797 .source_line = if (src.source_line) |s| try arena.dupe(u8, s) else null,
798 .notes = try dupeList(src.notes, arena),
799 } },
800 .plain => |plain| .{ .plain = .{
801 .msg = try arena.dupe(u8, plain.msg),
802 .notes = try dupeList(plain.notes, arena),
803 } },
804 };
805 }
806 return duped_list;
807 }
808};
809
810pub const Directory = Cache.Directory;398pub const Directory = Cache.Directory;
811399
812pub const EmitLoc = struct {400pub const EmitLoc = struct {
...@@ -2891,7 +2479,7 @@ pub fn makeBinFileWritable(self: *Compilation) !void {...@@ -2891,7 +2479,7 @@ pub fn makeBinFileWritable(self: *Compilation) !void {
2891}2479}
28922480
2893/// This function is temporally single-threaded.2481/// This function is temporally single-threaded.
2894pub fn totalErrorCount(self: *Compilation) usize {2482pub fn totalErrorCount(self: *Compilation) u32 {
2895 var total: usize = self.failed_c_objects.count() + self.misc_failures.count() +2483 var total: usize = self.failed_c_objects.count() + self.misc_failures.count() +
2896 @boolToInt(self.alloc_failure_occurred) + self.lld_errors.items.len;2484 @boolToInt(self.alloc_failure_occurred) + self.lld_errors.items.len;
28972485
...@@ -2951,17 +2539,16 @@ pub fn totalErrorCount(self: *Compilation) usize {...@@ -2951,17 +2539,16 @@ pub fn totalErrorCount(self: *Compilation) usize {
2951 }2539 }
2952 }2540 }
29532541
2954 return total;2542 return @intCast(u32, total);
2955}2543}
29562544
2957/// This function is temporally single-threaded.2545/// This function is temporally single-threaded.
2958pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {2546pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle {
2959 var arena = std.heap.ArenaAllocator.init(self.gpa);2547 const gpa = self.gpa;
2960 errdefer arena.deinit();
2961 const arena_allocator = arena.allocator();
29622548
2963 var errors = std.ArrayList(AllErrors.Message).init(self.gpa);2549 var bundle: ErrorBundle = undefined;
2964 defer errors.deinit();2550 try bundle.init(gpa);
2551 errdefer bundle.deinit(gpa);
29652552
2966 {2553 {
2967 var it = self.failed_c_objects.iterator();2554 var it = self.failed_c_objects.iterator();
...@@ -2970,53 +2557,63 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {...@@ -2970,53 +2557,63 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
2970 const err_msg = entry.value_ptr.*;2557 const err_msg = entry.value_ptr.*;
2971 // TODO these fields will need to be adjusted when we have proper2558 // TODO these fields will need to be adjusted when we have proper
2972 // C error reporting bubbling up.2559 // C error reporting bubbling up.
2973 try errors.append(.{2560 try bundle.addErrorMessage(gpa, .{
2974 .src = .{2561 .msg = try bundle.printString(gpa, "unable to build C object: {s}", .{
2975 .src_path = try arena_allocator.dupe(u8, c_object.src.src_path),2562 err_msg.msg,
2976 .msg = try std.fmt.allocPrint(arena_allocator, "unable to build C object: {s}", .{2563 }),
2977 err_msg.msg,2564 .src_loc = try bundle.addSourceLocation(gpa, .{
2978 }),2565 .src_path = try bundle.addString(gpa, c_object.src.src_path),
2979 .span = .{ .start = 0, .end = 1, .main = 0 },2566 .span_start = 0,
2567 .span_main = 0,
2568 .span_end = 1,
2980 .line = err_msg.line,2569 .line = err_msg.line,
2981 .column = err_msg.column,2570 .column = err_msg.column,
2982 .source_line = null, // TODO2571 .source_line = 0, // TODO
2983 },2572 }),
2984 });2573 });
2574 bundle.incrementCount(1);
2985 }2575 }
2986 }2576 }
2987 for (self.lld_errors.items) |lld_error| {
2988 const notes = try arena_allocator.alloc(AllErrors.Message, lld_error.context_lines.len);
2989 for (lld_error.context_lines, 0..) |context_line, i| {
2990 notes[i] = .{ .plain = .{
2991 .msg = try arena_allocator.dupe(u8, context_line),
2992 } };
2993 }
29942577
2995 try errors.append(.{2578 for (self.lld_errors.items) |lld_error| {
2996 .plain = .{2579 try bundle.addErrorMessage(gpa, .{
2997 .msg = try arena_allocator.dupe(u8, lld_error.msg),2580 .msg = try bundle.addString(gpa, lld_error.msg),
2998 .notes = notes,2581 .notes_len = @intCast(u32, lld_error.context_lines.len),
2999 },
3000 });2582 });
2583 bundle.incrementCount(1);
2584
2585 for (lld_error.context_lines) |context_line| {
2586 try bundle.addErrorMessage(gpa, .{
2587 .msg = try bundle.addString(gpa, context_line),
2588 });
2589 }
3001 }2590 }
3002 for (self.misc_failures.values()) |*value| {2591 for (self.misc_failures.values()) |*value| {
3003 try AllErrors.addPlainWithChildren(&arena, &errors, value.msg, value.children);2592 try bundle.addErrorMessage(gpa, .{
2593 .msg = try bundle.addString(gpa, value.msg),
2594 .notes_len = if (value.children) |b| b.errorMessageCount() else 0,
2595 });
2596 if (value.children) |b| try bundle.addBundle(gpa, b);
2597 bundle.incrementCount(1);
3004 }2598 }
3005 if (self.alloc_failure_occurred) {2599 if (self.alloc_failure_occurred) {
3006 try AllErrors.addPlain(&arena, &errors, "memory allocation failure");2600 try bundle.addErrorMessage(gpa, .{
2601 .msg = try bundle.addString(gpa, "memory allocation failure"),
2602 });
2603 bundle.incrementCount(1);
3007 }2604 }
3008 if (self.bin_file.options.module) |module| {2605 if (self.bin_file.options.module) |module| {
3009 {2606 {
3010 var it = module.failed_files.iterator();2607 var it = module.failed_files.iterator();
3011 while (it.next()) |entry| {2608 while (it.next()) |entry| {
3012 if (entry.value_ptr.*) |msg| {2609 if (entry.value_ptr.*) |msg| {
3013 try AllErrors.add(module, &arena, &errors, msg.*);2610 try addModuleErrorMsg(gpa, &bundle, msg.*);
3014 } else {2611 } else {
3015 // Must be ZIR errors. In order for ZIR errors to exist, the parsing2612 // Must be ZIR errors. In order for ZIR errors to exist, the parsing
3016 // must have completed successfully.2613 // must have completed successfully.
3017 const tree = try entry.key_ptr.*.getTree(module.gpa);2614 const tree = try entry.key_ptr.*.getTree(module.gpa);
3018 assert(tree.errors.len == 0);2615 assert(tree.errors.len == 0);
3019 try AllErrors.addZir(arena_allocator, &errors, entry.key_ptr.*);2616 try addZirErrorMessages(gpa, &bundle, entry.key_ptr.*);
3020 }2617 }
3021 }2618 }
3022 }2619 }
...@@ -3024,7 +2621,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {...@@ -3024,7 +2621,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
3024 var it = module.failed_embed_files.iterator();2621 var it = module.failed_embed_files.iterator();
3025 while (it.next()) |entry| {2622 while (it.next()) |entry| {
3026 const msg = entry.value_ptr.*;2623 const msg = entry.value_ptr.*;
3027 try AllErrors.add(module, &arena, &errors, msg.*);2624 try addModuleErrorMsg(gpa, &bundle, msg.*);
3028 }2625 }
3029 }2626 }
3030 {2627 {
...@@ -3034,23 +2631,21 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {...@@ -3034,23 +2631,21 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
3034 // Skip errors for Decls within files that had a parse failure.2631 // Skip errors for Decls within files that had a parse failure.
3035 // We'll try again once parsing succeeds.2632 // We'll try again once parsing succeeds.
3036 if (decl.getFileScope().okToReportErrors()) {2633 if (decl.getFileScope().okToReportErrors()) {
3037 try AllErrors.add(module, &arena, &errors, entry.value_ptr.*.*);2634 try addModuleErrorMsg(gpa, &bundle, entry.value_ptr.*.*);
3038 if (module.cimport_errors.get(entry.key_ptr.*)) |cimport_errors| for (cimport_errors) |c_error| {2635 if (module.cimport_errors.get(entry.key_ptr.*)) |cimport_errors| for (cimport_errors) |c_error| {
3039 if (c_error.path) |some|2636 try bundle.addErrorMessage(gpa, .{
3040 try errors.append(.{2637 .msg = try bundle.addString(gpa, std.mem.span(c_error.msg)),
3041 .src = .{2638 .src_loc = if (c_error.path) |some| try bundle.addSourceLocation(gpa, .{
3042 .src_path = try arena_allocator.dupe(u8, std.mem.span(some)),2639 .src_path = try bundle.addString(gpa, std.mem.span(some)),
3043 .span = .{ .start = c_error.offset, .end = c_error.offset + 1, .main = c_error.offset },2640 .span_start = c_error.offset,
3044 .msg = try arena_allocator.dupe(u8, std.mem.span(c_error.msg)),2641 .span_main = c_error.offset,
3045 .line = c_error.line,2642 .span_end = c_error.offset + 1,
3046 .column = c_error.column,2643 .line = c_error.line,
3047 .source_line = if (c_error.source_line) |line| try arena_allocator.dupe(u8, std.mem.span(line)) else null,2644 .column = c_error.column,
3048 },2645 .source_line = if (c_error.source_line) |line| try bundle.addString(gpa, std.mem.span(line)) else 0,
3049 })2646 }) else 0,
3050 else2647 });
3051 try errors.append(.{2648 bundle.incrementCount(1);
3052 .plain = .{ .msg = try arena_allocator.dupe(u8, std.mem.span(c_error.msg)) },
3053 });
3054 };2649 };
3055 }2650 }
3056 }2651 }
...@@ -3062,45 +2657,40 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {...@@ -3062,45 +2657,40 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
3062 // Skip errors for Decls within files that had a parse failure.2657 // Skip errors for Decls within files that had a parse failure.
3063 // We'll try again once parsing succeeds.2658 // We'll try again once parsing succeeds.
3064 if (decl.getFileScope().okToReportErrors()) {2659 if (decl.getFileScope().okToReportErrors()) {
3065 try AllErrors.add(module, &arena, &errors, entry.value_ptr.*.*);2660 try addModuleErrorMsg(gpa, &bundle, entry.value_ptr.*.*);
3066 }2661 }
3067 }2662 }
3068 }2663 }
3069 for (module.failed_exports.values()) |value| {2664 for (module.failed_exports.values()) |value| {
3070 try AllErrors.add(module, &arena, &errors, value.*);2665 try addModuleErrorMsg(gpa, &bundle, value.*);
3071 }2666 }
3072 }2667 }
30732668
3074 if (errors.items.len == 0) {2669 if (bundle.errorMessageCount() == 0) {
3075 if (self.link_error_flags.no_entry_point_found) {2670 if (self.link_error_flags.no_entry_point_found) {
3076 try errors.append(.{2671 try bundle.addErrorMessage(gpa, .{
3077 .plain = .{2672 .msg = try bundle.addString(gpa, "no entry point found"),
3078 .msg = try std.fmt.allocPrint(arena_allocator, "no entry point found", .{}),
3079 },
3080 });2673 });
2674 bundle.incrementCount(1);
3081 }2675 }
3082 }2676 }
30832677
3084 if (self.link_error_flags.missing_libc) {2678 if (self.link_error_flags.missing_libc) {
3085 const notes = try arena_allocator.create([2]AllErrors.Message);2679 try bundle.addErrorMessage(gpa, .{
3086 notes.* = .{2680 .msg = try bundle.addString(gpa, "libc not available"),
3087 .{ .plain = .{2681 .notes_len = 2,
3088 .msg = try arena_allocator.dupe(u8, "run 'zig libc -h' to learn about libc installations"),2682 });
3089 } },2683 try bundle.addErrorMessage(gpa, .{
3090 .{ .plain = .{2684 .msg = try bundle.addString(gpa, "run 'zig libc -h' to learn about libc installations"),
3091 .msg = try arena_allocator.dupe(u8, "run 'zig targets' to see the targets for which zig can always provide libc"),
3092 } },
3093 };
3094 try errors.append(.{
3095 .plain = .{
3096 .msg = try std.fmt.allocPrint(arena_allocator, "libc not available", .{}),
3097 .notes = notes,
3098 },
3099 });2685 });
2686 try bundle.addErrorMessage(gpa, .{
2687 .msg = try bundle.addString(gpa, "run 'zig targets' to see the targets for which zig can always provide libc"),
2688 });
2689 bundle.incrementCount(1);
3100 }2690 }
31012691
3102 if (self.bin_file.options.module) |module| {2692 if (self.bin_file.options.module) |module| {
3103 if (errors.items.len == 0 and module.compile_log_decls.count() != 0) {2693 if (bundle.errorMessageCount() == 0 and module.compile_log_decls.count() != 0) {
3104 const keys = module.compile_log_decls.keys();2694 const keys = module.compile_log_decls.keys();
3105 const values = module.compile_log_decls.values();2695 const values = module.compile_log_decls.values();
3106 // First one will be the error; subsequent ones will be notes.2696 // First one will be the error; subsequent ones will be notes.
...@@ -3121,16 +2711,259 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {...@@ -3121,16 +2711,259 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
3121 };2711 };
3122 }2712 }
31232713
3124 try AllErrors.add(module, &arena, &errors, err_msg);2714 try addModuleErrorMsg(gpa, &bundle, err_msg);
3125 }2715 }
3126 }2716 }
31272717
3128 assert(errors.items.len == self.totalErrorCount());2718 assert(self.totalErrorCount() == bundle.errorMessageCount());
2719
2720 return bundle;
2721}
2722
2723pub const ErrorNoteHashContext = struct {
2724 eb: *const ErrorBundle,
2725
2726 pub fn hash(ctx: ErrorNoteHashContext, key: ErrorBundle.ErrorMessage) u32 {
2727 var hasher = std.hash.Wyhash.init(0);
31292728
3130 return AllErrors{2729 hasher.update(ctx.eb.nullTerminatedString(key.msg));
3131 .list = try arena_allocator.dupe(AllErrors.Message, errors.items),2730 if (key.src_loc != 0) {
3132 .arena = arena.state,2731 const src = ctx.eb.getSourceLocation(key.src_loc);
2732 hasher.update(ctx.eb.nullTerminatedString(src.src_path));
2733 std.hash.autoHash(&hasher, src.line);
2734 std.hash.autoHash(&hasher, src.column);
2735 std.hash.autoHash(&hasher, src.span_main);
2736 }
2737
2738 return @truncate(u32, hasher.final());
2739 }
2740
2741 pub fn eql(
2742 ctx: ErrorNoteHashContext,
2743 a: ErrorBundle.ErrorMessage,
2744 b: ErrorBundle.ErrorMessage,
2745 b_index: usize,
2746 ) bool {
2747 _ = b_index;
2748 const msg_a = ctx.eb.nullTerminatedString(a.msg);
2749 const msg_b = ctx.eb.nullTerminatedString(b.msg);
2750 if (!std.mem.eql(u8, msg_a, msg_b)) return false;
2751
2752 if (a.src_loc == 0 and b.src_loc == 0) return true;
2753 if (a.src_loc == 0 or b.src_loc == 0) return false;
2754 const src_a = ctx.eb.getSourceLocation(a.src_loc);
2755 const src_b = ctx.eb.getSourceLocation(b.src_loc);
2756
2757 const src_path_a = ctx.eb.nullTerminatedString(src_a.src_path);
2758 const src_path_b = ctx.eb.nullTerminatedString(src_b.src_path);
2759
2760 return std.mem.eql(u8, src_path_a, src_path_b) and
2761 src_a.line == src_b.line and
2762 src_a.column == src_b.column and
2763 src_a.span_main == src_b.span_main;
2764 }
2765};
2766
2767pub fn addModuleErrorMsg(gpa: Allocator, eb: *ErrorBundle, module_err_msg: Module.ErrorMsg) !void {
2768 const err_source = module_err_msg.src_loc.file_scope.getSource(gpa) catch |err| {
2769 const file_path = try module_err_msg.src_loc.file_scope.fullPath(gpa);
2770 defer gpa.free(file_path);
2771 try eb.addErrorMessage(gpa, .{
2772 .msg = try eb.printString(gpa, "unable to load '{s}': {s}", .{
2773 file_path, @errorName(err),
2774 }),
2775 });
2776 eb.incrementCount(1);
2777 return;
3133 };2778 };
2779 const err_span = try module_err_msg.src_loc.span(gpa);
2780 const err_loc = std.zig.findLineColumn(err_source.bytes, err_span.main);
2781 const file_path = try module_err_msg.src_loc.file_scope.fullPath(gpa);
2782 defer gpa.free(file_path);
2783
2784 var ref_traces: std.ArrayListUnmanaged(ErrorBundle.ReferenceTrace) = .{};
2785 defer ref_traces.deinit(gpa);
2786
2787 for (module_err_msg.reference_trace) |module_reference| {
2788 if (module_reference.hidden != 0) {
2789 try ref_traces.append(gpa, .{
2790 .decl_name = module_reference.hidden,
2791 .src_loc = 0,
2792 });
2793 break;
2794 } else if (module_reference.decl == null) {
2795 try ref_traces.append(gpa, .{
2796 .decl_name = 0,
2797 .src_loc = 0,
2798 });
2799 break;
2800 }
2801 const source = try module_reference.src_loc.file_scope.getSource(gpa);
2802 const span = try module_reference.src_loc.span(gpa);
2803 const loc = std.zig.findLineColumn(source.bytes, span.main);
2804 const rt_file_path = try module_reference.src_loc.file_scope.fullPath(gpa);
2805 defer gpa.free(rt_file_path);
2806 try ref_traces.append(gpa, .{
2807 .decl_name = try eb.addString(gpa, std.mem.sliceTo(module_reference.decl.?, 0)),
2808 .src_loc = try eb.addSourceLocation(gpa, .{
2809 .src_path = try eb.addString(gpa, rt_file_path),
2810 .span_start = span.start,
2811 .span_main = span.main,
2812 .span_end = span.end,
2813 .line = @intCast(u32, loc.line),
2814 .column = @intCast(u32, loc.column),
2815 .source_line = 0,
2816 }),
2817 });
2818 }
2819
2820 const src_loc = try eb.addSourceLocation(gpa, .{
2821 .src_path = try eb.addString(gpa, file_path),
2822 .span_start = err_span.start,
2823 .span_main = err_span.main,
2824 .span_end = err_span.end,
2825 .line = @intCast(u32, err_loc.line),
2826 .column = @intCast(u32, err_loc.column),
2827 .source_line = if (module_err_msg.src_loc.lazy == .entire_file)
2828 0
2829 else
2830 try eb.addString(gpa, err_loc.source_line),
2831 .reference_trace_len = @intCast(u32, ref_traces.items.len),
2832 });
2833
2834 for (ref_traces.items) |rt| {
2835 try eb.addReferenceTrace(gpa, rt);
2836 }
2837
2838 // De-duplicate error notes. The main use case in mind for this is
2839 // too many "note: called from here" notes when eval branch quota is reached.
2840 var notes: std.ArrayHashMapUnmanaged(ErrorBundle.ErrorMessage, void, ErrorNoteHashContext, true) = .{};
2841 defer notes.deinit(gpa);
2842
2843 for (module_err_msg.notes) |module_note| {
2844 const source = try module_note.src_loc.file_scope.getSource(gpa);
2845 const span = try module_note.src_loc.span(gpa);
2846 const loc = std.zig.findLineColumn(source.bytes, span.main);
2847 const note_file_path = try module_note.src_loc.file_scope.fullPath(gpa);
2848 defer gpa.free(note_file_path);
2849
2850 const gop = try notes.getOrPutContext(gpa, .{
2851 .msg = try eb.addString(gpa, module_note.msg),
2852 .src_loc = try eb.addSourceLocation(gpa, .{
2853 .src_path = try eb.addString(gpa, note_file_path),
2854 .span_start = span.start,
2855 .span_main = span.main,
2856 .span_end = span.end,
2857 .line = @intCast(u32, loc.line),
2858 .column = @intCast(u32, loc.column),
2859 .source_line = if (err_loc.eql(loc)) 0 else try eb.addString(gpa, loc.source_line),
2860 }),
2861 }, .{ .eb = eb });
2862 if (gop.found_existing) {
2863 gop.key_ptr.count += 1;
2864 }
2865 }
2866
2867 try eb.addErrorMessage(gpa, .{
2868 .msg = try eb.addString(gpa, module_err_msg.msg),
2869 .src_loc = src_loc,
2870 .notes_len = @intCast(u32, notes.entries.len),
2871 });
2872 eb.incrementCount(1);
2873
2874 for (notes.keys()) |note| {
2875 try eb.addErrorMessage(gpa, note);
2876 }
2877}
2878
2879pub fn addZirErrorMessages(gpa: Allocator, eb: *ErrorBundle, file: *Module.File) !void {
2880 assert(file.zir_loaded);
2881 assert(file.tree_loaded);
2882 assert(file.source_loaded);
2883 const payload_index = file.zir.extra[@enumToInt(Zir.ExtraIndex.compile_errors)];
2884 assert(payload_index != 0);
2885
2886 const header = file.zir.extraData(Zir.Inst.CompileErrors, payload_index);
2887 const items_len = header.data.items_len;
2888 var extra_index = header.end;
2889 for (0..items_len) |_| {
2890 const item = file.zir.extraData(Zir.Inst.CompileErrors.Item, extra_index);
2891 extra_index = item.end;
2892 const err_span = blk: {
2893 if (item.data.node != 0) {
2894 break :blk Module.SrcLoc.nodeToSpan(&file.tree, item.data.node);
2895 }
2896 const token_starts = file.tree.tokens.items(.start);
2897 const start = token_starts[item.data.token] + item.data.byte_offset;
2898 const end = start + @intCast(u32, file.tree.tokenSlice(item.data.token).len) - item.data.byte_offset;
2899 break :blk Module.SrcLoc.Span{ .start = start, .end = end, .main = start };
2900 };
2901 const err_loc = std.zig.findLineColumn(file.source, err_span.main);
2902
2903 var notes: []ErrorBundle.ErrorMessage = &.{};
2904 defer gpa.free(notes);
2905
2906 if (item.data.notes != 0) {
2907 const block = file.zir.extraData(Zir.Inst.Block, item.data.notes);
2908 const body = file.zir.extra[block.end..][0..block.data.body_len];
2909 notes = try gpa.alloc(ErrorBundle.ErrorMessage, body.len);
2910 for (notes, body) |*note, body_elem| {
2911 const note_item = file.zir.extraData(Zir.Inst.CompileErrors.Item, body_elem);
2912 const msg = file.zir.nullTerminatedString(note_item.data.msg);
2913 const span = blk: {
2914 if (note_item.data.node != 0) {
2915 break :blk Module.SrcLoc.nodeToSpan(&file.tree, note_item.data.node);
2916 }
2917 const token_starts = file.tree.tokens.items(.start);
2918 const start = token_starts[note_item.data.token] + note_item.data.byte_offset;
2919 const end = start + @intCast(u32, file.tree.tokenSlice(note_item.data.token).len) - item.data.byte_offset;
2920 break :blk Module.SrcLoc.Span{ .start = start, .end = end, .main = start };
2921 };
2922 const loc = std.zig.findLineColumn(file.source, span.main);
2923 const src_path = try file.fullPath(gpa);
2924 defer gpa.free(src_path);
2925
2926 note.* = .{
2927 .msg = try eb.addString(gpa, msg),
2928 .src_loc = try eb.addSourceLocation(gpa, .{
2929 .src_path = try eb.addString(gpa, src_path),
2930 .span_start = span.start,
2931 .span_main = span.main,
2932 .span_end = span.end,
2933 .line = @intCast(u32, loc.line),
2934 .column = @intCast(u32, loc.column),
2935 .source_line = if (loc.eql(err_loc))
2936 0
2937 else
2938 try eb.addString(gpa, loc.source_line),
2939 }),
2940 .notes_len = 0, // TODO rework this function to be recursive
2941 };
2942 }
2943 }
2944
2945 const msg = file.zir.nullTerminatedString(item.data.msg);
2946 const src_path = try file.fullPath(gpa);
2947 defer gpa.free(src_path);
2948 try eb.addErrorMessage(gpa, .{
2949 .msg = try eb.addString(gpa, msg),
2950 .src_loc = try eb.addSourceLocation(gpa, .{
2951 .src_path = try eb.addString(gpa, src_path),
2952 .span_start = err_span.start,
2953 .span_main = err_span.main,
2954 .span_end = err_span.end,
2955 .line = @intCast(u32, err_loc.line),
2956 .column = @intCast(u32, err_loc.column),
2957 .source_line = try eb.addString(gpa, err_loc.source_line),
2958 }),
2959 .notes_len = @intCast(u32, notes.len),
2960 });
2961
2962 for (notes) |note| {
2963 try eb.addErrorMessage(gpa, note);
2964 }
2965 }
2966 eb.incrementCount(items_len);
3134}2967}
31352968
3136pub fn getCompileLogOutput(self: *Compilation) []const u8 {2969pub fn getCompileLogOutput(self: *Compilation) []const u8 {
...@@ -5417,34 +5250,29 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca...@@ -5417,34 +5250,29 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca
5417 return buffer.toOwnedSliceSentinel(0);5250 return buffer.toOwnedSliceSentinel(0);
5418}5251}
54195252
5420pub fn updateSubCompilation(sub_compilation: *Compilation) !void {5253pub fn updateSubCompilation(
5421 try sub_compilation.update();5254 parent_comp: *Compilation,
54225255 sub_comp: *Compilation,
5423 // Look for compilation errors in this sub_compilation5256 misc_task: MiscTask,
5424 // TODO instead of logging these errors, handle them in the callsites5257) !void {
5425 // of updateSubCompilation and attach them as sub-errors, properly5258 try sub_comp.update();
5426 // surfacing the errors. You can see an example of this already5259
5427 // done inside buildOutputFromZig.5260 // Look for compilation errors in this sub compilation
5428 var errors = try sub_compilation.getAllErrorsAlloc();5261 const gpa = parent_comp.gpa;
5429 defer errors.deinit(sub_compilation.gpa);5262 var keep_errors = false;
54305263 var errors = try sub_comp.getAllErrorsAlloc();
5431 if (errors.list.len != 0) {5264 defer if (!keep_errors) errors.deinit(gpa);
5432 for (errors.list) |full_err_msg| {5265
5433 switch (full_err_msg) {5266 if (errors.errorMessageCount() > 0) {
5434 .src => |src| {5267 try parent_comp.misc_failures.ensureUnusedCapacity(gpa, 1);
5435 log.err("{s}:{d}:{d}: {s}", .{5268 parent_comp.misc_failures.putAssumeCapacityNoClobber(misc_task, .{
5436 src.src_path,5269 .msg = try std.fmt.allocPrint(gpa, "sub-compilation of {s} failed", .{
5437 src.line + 1,5270 @tagName(misc_task),
5438 src.column + 1,5271 }),
5439 src.msg,5272 .children = errors,
5440 });5273 });
5441 },5274 keep_errors = true;
5442 .plain => |plain| {5275 return error.SubCompilationFailed;
5443 log.err("{s}", .{plain.msg});
5444 },
5445 }
5446 }
5447 return error.BuildingLibCObjectFailed;
5448 }5276 }
5449}5277}
54505278
...@@ -5520,23 +5348,7 @@ fn buildOutputFromZig(...@@ -5520,23 +5348,7 @@ fn buildOutputFromZig(
5520 });5348 });
5521 defer sub_compilation.destroy();5349 defer sub_compilation.destroy();
55225350
5523 try sub_compilation.update();5351 try comp.updateSubCompilation(sub_compilation, misc_task_tag);
5524 // Look for compilation errors in this sub_compilation.
5525 var keep_errors = false;
5526 var errors = try sub_compilation.getAllErrorsAlloc();
5527 defer if (!keep_errors) errors.deinit(sub_compilation.gpa);
5528
5529 if (errors.list.len != 0) {
5530 try comp.misc_failures.ensureUnusedCapacity(comp.gpa, 1);
5531 comp.misc_failures.putAssumeCapacityNoClobber(misc_task_tag, .{
5532 .msg = try std.fmt.allocPrint(comp.gpa, "sub-compilation of {s} failed", .{
5533 @tagName(misc_task_tag),
5534 }),
5535 .children = errors,
5536 });
5537 keep_errors = true;
5538 return error.SubCompilationFailed;
5539 }
55405352
5541 assert(out.* == null);5353 assert(out.* == null);
5542 out.* = Compilation.CRTFile{5354 out.* = Compilation.CRTFile{
...@@ -5551,6 +5363,7 @@ pub fn build_crt_file(...@@ -5551,6 +5363,7 @@ pub fn build_crt_file(
5551 comp: *Compilation,5363 comp: *Compilation,
5552 root_name: []const u8,5364 root_name: []const u8,
5553 output_mode: std.builtin.OutputMode,5365 output_mode: std.builtin.OutputMode,
5366 misc_task_tag: MiscTask,
5554 c_source_files: []const Compilation.CSourceFile,5367 c_source_files: []const Compilation.CSourceFile,
5555) !void {5368) !void {
5556 const tracy_trace = trace(@src());5369 const tracy_trace = trace(@src());
...@@ -5611,7 +5424,7 @@ pub fn build_crt_file(...@@ -5611,7 +5424,7 @@ pub fn build_crt_file(
5611 });5424 });
5612 defer sub_compilation.destroy();5425 defer sub_compilation.destroy();
56135426
5614 try sub_compilation.updateSubCompilation();5427 try comp.updateSubCompilation(sub_compilation, misc_task_tag);
56155428
5616 try comp.crt_files.ensureUnusedCapacity(comp.gpa, 1);5429 try comp.crt_files.ensureUnusedCapacity(comp.gpa, 1);
56175430
src/Module.zig+1-59
...@@ -3756,67 +3756,9 @@ pub fn astGenFile(mod: *Module, file: *File) !void {...@@ -3756,67 +3756,9 @@ pub fn astGenFile(mod: *Module, file: *File) !void {
3756 file.source_loaded = true;3756 file.source_loaded = true;
37573757
3758 file.tree = try Ast.parse(gpa, source, .zig);3758 file.tree = try Ast.parse(gpa, source, .zig);
3759 defer if (!file.tree_loaded) file.tree.deinit(gpa);
3760
3761 if (file.tree.errors.len != 0) {
3762 const parse_err = file.tree.errors[0];
3763
3764 var msg = std.ArrayList(u8).init(gpa);
3765 defer msg.deinit();
3766
3767 const token_starts = file.tree.tokens.items(.start);
3768 const token_tags = file.tree.tokens.items(.tag);
3769
3770 const extra_offset = file.tree.errorOffset(parse_err);
3771 try file.tree.renderError(parse_err, msg.writer());
3772 const err_msg = try gpa.create(ErrorMsg);
3773 err_msg.* = .{
3774 .src_loc = .{
3775 .file_scope = file,
3776 .parent_decl_node = 0,
3777 .lazy = if (extra_offset == 0) .{
3778 .token_abs = parse_err.token,
3779 } else .{
3780 .byte_abs = token_starts[parse_err.token] + extra_offset,
3781 },
3782 },
3783 .msg = try msg.toOwnedSlice(),
3784 };
3785 if (token_tags[parse_err.token + @boolToInt(parse_err.token_is_prev)] == .invalid) {
3786 const bad_off = @intCast(u32, file.tree.tokenSlice(parse_err.token + @boolToInt(parse_err.token_is_prev)).len);
3787 const byte_abs = token_starts[parse_err.token + @boolToInt(parse_err.token_is_prev)] + bad_off;
3788 try mod.errNoteNonLazy(.{
3789 .file_scope = file,
3790 .parent_decl_node = 0,
3791 .lazy = .{ .byte_abs = byte_abs },
3792 }, err_msg, "invalid byte: '{'}'", .{std.zig.fmtEscapes(source[byte_abs..][0..1])});
3793 }
3794
3795 for (file.tree.errors[1..]) |note| {
3796 if (!note.is_note) break;
3797
3798 try file.tree.renderError(note, msg.writer());
3799 err_msg.notes = try mod.gpa.realloc(err_msg.notes, err_msg.notes.len + 1);
3800 err_msg.notes[err_msg.notes.len - 1] = .{
3801 .src_loc = .{
3802 .file_scope = file,
3803 .parent_decl_node = 0,
3804 .lazy = .{ .token_abs = note.token },
3805 },
3806 .msg = try msg.toOwnedSlice(),
3807 };
3808 }
3809
3810 {
3811 comp.mutex.lock();
3812 defer comp.mutex.unlock();
3813 try mod.failed_files.putNoClobber(gpa, file, err_msg);
3814 }
3815 file.status = .parse_failure;
3816 return error.AnalysisFail;
3817 }
3818 file.tree_loaded = true;3759 file.tree_loaded = true;
38193760
3761 // Any potential AST errors are converted to ZIR errors here.
3820 file.zir = try AstGen.generate(gpa, file.tree);3762 file.zir = try AstGen.generate(gpa, file.tree);
3821 file.zir_loaded = true;3763 file.zir_loaded = true;
3822 file.status = .success_zir;3764 file.status = .success_zir;
src/Package.zig+53-55
...@@ -225,7 +225,7 @@ pub fn fetchAndAddDependencies(...@@ -225,7 +225,7 @@ pub fn fetchAndAddDependencies(
225 dependencies_source: *std.ArrayList(u8),225 dependencies_source: *std.ArrayList(u8),
226 build_roots_source: *std.ArrayList(u8),226 build_roots_source: *std.ArrayList(u8),
227 name_prefix: []const u8,227 name_prefix: []const u8,
228 color: main.Color,228 error_bundle: *std.zig.ErrorBundle,
229 all_modules: *AllModules,229 all_modules: *AllModules,
230) !void {230) !void {
231 const max_bytes = 10 * 1024 * 1024;231 const max_bytes = 10 * 1024 * 1024;
...@@ -250,7 +250,7 @@ pub fn fetchAndAddDependencies(...@@ -250,7 +250,7 @@ pub fn fetchAndAddDependencies(
250250
251 if (ast.errors.len > 0) {251 if (ast.errors.len > 0) {
252 const file_path = try directory.join(arena, &.{Manifest.basename});252 const file_path = try directory.join(arena, &.{Manifest.basename});
253 try main.printErrsMsgToStdErr(gpa, arena, ast, file_path, color);253 try main.putAstErrorsIntoBundle(gpa, ast, file_path, error_bundle);
254 return error.PackageFetchFailed;254 return error.PackageFetchFailed;
255 }255 }
256256
...@@ -258,23 +258,18 @@ pub fn fetchAndAddDependencies(...@@ -258,23 +258,18 @@ pub fn fetchAndAddDependencies(
258 defer manifest.deinit(gpa);258 defer manifest.deinit(gpa);
259259
260 if (manifest.errors.len > 0) {260 if (manifest.errors.len > 0) {
261 const ttyconf: std.debug.TTY.Config = switch (color) {
262 .auto => std.debug.detectTTYConfig(std.io.getStdErr()),
263 .on => .escape_codes,
264 .off => .no_color,
265 };
266 const file_path = try directory.join(arena, &.{Manifest.basename});261 const file_path = try directory.join(arena, &.{Manifest.basename});
267 for (manifest.errors) |msg| {262 for (manifest.errors) |msg| {
268 Report.renderErrorMessage(ast, file_path, ttyconf, msg, &.{});263 try Report.addErrorMessage(gpa, ast, file_path, error_bundle, 0, msg);
269 }264 }
270 return error.PackageFetchFailed;265 return error.PackageFetchFailed;
271 }266 }
272267
273 const report: Report = .{268 const report: Report = .{
269 .gpa = gpa,
274 .ast = &ast,270 .ast = &ast,
275 .directory = directory,271 .directory = directory,
276 .color = color,272 .error_bundle = error_bundle,
277 .arena = arena,
278 };273 };
279274
280 var any_error = false;275 var any_error = false;
...@@ -307,7 +302,7 @@ pub fn fetchAndAddDependencies(...@@ -307,7 +302,7 @@ pub fn fetchAndAddDependencies(
307 dependencies_source,302 dependencies_source,
308 build_roots_source,303 build_roots_source,
309 sub_prefix,304 sub_prefix,
310 color,305 error_bundle,
311 all_modules,306 all_modules,
312 );307 );
313308
...@@ -348,10 +343,10 @@ pub fn createFilePkg(...@@ -348,10 +343,10 @@ pub fn createFilePkg(
348}343}
349344
350const Report = struct {345const Report = struct {
346 gpa: Allocator,
351 ast: *const std.zig.Ast,347 ast: *const std.zig.Ast,
352 directory: Compilation.Directory,348 directory: Compilation.Directory,
353 color: main.Color,349 error_bundle: *std.zig.ErrorBundle,
354 arena: Allocator,
355350
356 fn fail(351 fn fail(
357 report: Report,352 report: Report,
...@@ -359,52 +354,48 @@ const Report = struct {...@@ -359,52 +354,48 @@ const Report = struct {
359 comptime fmt_string: []const u8,354 comptime fmt_string: []const u8,
360 fmt_args: anytype,355 fmt_args: anytype,
361 ) error{ PackageFetchFailed, OutOfMemory } {356 ) error{ PackageFetchFailed, OutOfMemory } {
362 return failWithNotes(report, &.{}, tok, fmt_string, fmt_args);357 const gpa = report.gpa;
363 }
364358
365 fn failWithNotes(359 const file_path = try report.directory.join(gpa, &.{Manifest.basename});
366 report: Report,360 defer gpa.free(file_path);
367 notes: []const Compilation.AllErrors.Message,361
368 tok: std.zig.Ast.TokenIndex,362 const msg = try std.fmt.allocPrint(gpa, fmt_string, fmt_args);
369 comptime fmt_string: []const u8,363 defer gpa.free(msg);
370 fmt_args: anytype,364
371 ) error{ PackageFetchFailed, OutOfMemory } {365 try addErrorMessage(report.gpa, report.ast.*, file_path, report.error_bundle, 0, .{
372 const ttyconf: std.debug.TTY.Config = switch (report.color) {
373 .auto => std.debug.detectTTYConfig(std.io.getStdErr()),
374 .on => .escape_codes,
375 .off => .no_color,
376 };
377 const file_path = try report.directory.join(report.arena, &.{Manifest.basename});
378 renderErrorMessage(report.ast.*, file_path, ttyconf, .{
379 .tok = tok,366 .tok = tok,
380 .off = 0,367 .off = 0,
381 .msg = try std.fmt.allocPrint(report.arena, fmt_string, fmt_args),368 .msg = msg,
382 }, notes);369 });
370
383 return error.PackageFetchFailed;371 return error.PackageFetchFailed;
384 }372 }
385373
386 fn renderErrorMessage(374 fn addErrorMessage(
375 gpa: Allocator,
387 ast: std.zig.Ast,376 ast: std.zig.Ast,
388 file_path: []const u8,377 file_path: []const u8,
389 ttyconf: std.debug.TTY.Config,378 eb: *std.zig.ErrorBundle,
379 notes_len: u32,
390 msg: Manifest.ErrorMessage,380 msg: Manifest.ErrorMessage,
391 notes: []const Compilation.AllErrors.Message,381 ) error{OutOfMemory}!void {
392 ) void {
393 const token_starts = ast.tokens.items(.start);382 const token_starts = ast.tokens.items(.start);
394 const start_loc = ast.tokenLocation(0, msg.tok);383 const start_loc = ast.tokenLocation(0, msg.tok);
395 Compilation.AllErrors.Message.renderToStdErr(.{ .src = .{384
396 .msg = msg.msg,385 try eb.addErrorMessage(gpa, .{
397 .src_path = file_path,386 .msg = try eb.addString(gpa, msg.msg),
398 .line = @intCast(u32, start_loc.line),387 .src_loc = try eb.addSourceLocation(gpa, .{
399 .column = @intCast(u32, start_loc.column),388 .src_path = try eb.addString(gpa, file_path),
400 .span = .{389 .span_start = token_starts[msg.tok],
401 .start = token_starts[msg.tok],390 .span_end = @intCast(u32, token_starts[msg.tok] + ast.tokenSlice(msg.tok).len),
402 .end = @intCast(u32, token_starts[msg.tok] + ast.tokenSlice(msg.tok).len),391 .span_main = token_starts[msg.tok] + msg.off,
403 .main = token_starts[msg.tok] + msg.off,392 .line = @intCast(u32, start_loc.line),
404 },393 .column = @intCast(u32, start_loc.column),
405 .source_line = ast.source[start_loc.line_start..start_loc.line_end],394 .source_line = try eb.addString(gpa, ast.source[start_loc.line_start..start_loc.line_end]),
406 .notes = notes,395 }),
407 } }, ttyconf);396 .notes_len = notes_len,
397 });
398 eb.incrementCount(1);
408 }399 }
409};400};
410401
...@@ -504,9 +495,7 @@ fn fetchAndUnpack(...@@ -504,9 +495,7 @@ fn fetchAndUnpack(
504 // by default, so the same logic applies for buffering the reader as for gzip.495 // by default, so the same logic applies for buffering the reader as for gzip.
505 try unpackTarball(gpa, &req, tmp_directory.handle, std.compress.xz);496 try unpackTarball(gpa, &req, tmp_directory.handle, std.compress.xz);
506 } else {497 } else {
507 return report.fail(dep.url_tok, "unknown file extension for path '{s}'", .{498 return report.fail(dep.url_tok, "unknown file extension for path '{s}'", .{uri.path});
508 uri.path,
509 });
510 }499 }
511500
512 // TODO: delete files not included in the package prior to computing the package hash.501 // TODO: delete files not included in the package prior to computing the package hash.
...@@ -533,10 +522,19 @@ fn fetchAndUnpack(...@@ -533,10 +522,19 @@ fn fetchAndUnpack(
533 });522 });
534 }523 }
535 } else {524 } else {
536 const notes: [1]Compilation.AllErrors.Message = .{.{ .plain = .{525 const file_path = try report.directory.join(gpa, &.{Manifest.basename});
537 .msg = try std.fmt.allocPrint(report.arena, "expected .hash = \"{s}\",", .{&actual_hex}),526 defer gpa.free(file_path);
538 } }};527
539 return report.failWithNotes(&notes, dep.url_tok, "url field is missing corresponding hash field", .{});528 const eb = report.error_bundle;
529 try Report.addErrorMessage(gpa, report.ast.*, file_path, eb, 1, .{
530 .tok = dep.url_tok,
531 .off = 0,
532 .msg = "url field is missing corresponding hash field",
533 });
534 try eb.addErrorMessage(gpa, .{
535 .msg = try eb.printString(gpa, "expected .hash = \"{s}\",", .{&actual_hex}),
536 });
537 return error.PackageFetchFailed;
540 }538 }
541539
542 const build_root = try global_cache_directory.join(gpa, &.{pkg_dir_sub_path});540 const build_root = try global_cache_directory.join(gpa, &.{pkg_dir_sub_path});
src/Sema.zig+11-14
...@@ -2211,29 +2211,26 @@ pub fn fail(...@@ -2211,29 +2211,26 @@ pub fn fail(
22112211
2212fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError {2212fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError {
2213 @setCold(true);2213 @setCold(true);
2214 const gpa = sema.gpa;
22142215
2215 if (crash_report.is_enabled and sema.mod.comp.debug_compile_errors) {2216 if (crash_report.is_enabled and sema.mod.comp.debug_compile_errors) {
2216 if (err_msg.src_loc.lazy == .unneeded) return error.NeededSourceLocation;2217 if (err_msg.src_loc.lazy == .unneeded) return error.NeededSourceLocation;
2217 var arena = std.heap.ArenaAllocator.init(sema.gpa);2218 var errors: std.zig.ErrorBundle = undefined;
2218 errdefer arena.deinit();2219 errors.init(gpa) catch unreachable;
2219 var errors = std.ArrayList(Compilation.AllErrors.Message).init(sema.gpa);2220 Compilation.addModuleErrorMsg(gpa, &errors, err_msg.*) catch unreachable;
2220 defer errors.deinit();
2221
2222 Compilation.AllErrors.add(sema.mod, &arena, &errors, err_msg.*) catch unreachable;
2223
2224 std.debug.print("compile error during Sema:\n", .{});2221 std.debug.print("compile error during Sema:\n", .{});
2225 Compilation.AllErrors.Message.renderToStdErr(errors.items[0], .no_color);2222 errors.renderToStdErr(.no_color);
2226 crash_report.compilerPanic("unexpected compile error occurred", null, null);2223 crash_report.compilerPanic("unexpected compile error occurred", null, null);
2227 }2224 }
22282225
2229 const mod = sema.mod;2226 const mod = sema.mod;
2230 ref: {2227 ref: {
2231 errdefer err_msg.destroy(mod.gpa);2228 errdefer err_msg.destroy(gpa);
2232 if (err_msg.src_loc.lazy == .unneeded) {2229 if (err_msg.src_loc.lazy == .unneeded) {
2233 return error.NeededSourceLocation;2230 return error.NeededSourceLocation;
2234 }2231 }
2235 try mod.failed_decls.ensureUnusedCapacity(mod.gpa, 1);2232 try mod.failed_decls.ensureUnusedCapacity(gpa, 1);
2236 try mod.failed_files.ensureUnusedCapacity(mod.gpa, 1);2233 try mod.failed_files.ensureUnusedCapacity(gpa, 1);
22372234
2238 const max_references = blk: {2235 const max_references = blk: {
2239 if (sema.mod.comp.reference_trace) |num| break :blk num;2236 if (sema.mod.comp.reference_trace) |num| break :blk num;
...@@ -2243,11 +2240,11 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError {...@@ -2243,11 +2240,11 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError {
2243 };2240 };
22442241
2245 var referenced_by = if (sema.func) |some| some.owner_decl else sema.owner_decl_index;2242 var referenced_by = if (sema.func) |some| some.owner_decl else sema.owner_decl_index;
2246 var reference_stack = std.ArrayList(Module.ErrorMsg.Trace).init(sema.gpa);2243 var reference_stack = std.ArrayList(Module.ErrorMsg.Trace).init(gpa);
2247 defer reference_stack.deinit();2244 defer reference_stack.deinit();
22482245
2249 // Avoid infinite loops.2246 // Avoid infinite loops.
2250 var seen = std.AutoHashMap(Module.Decl.Index, void).init(sema.gpa);2247 var seen = std.AutoHashMap(Module.Decl.Index, void).init(gpa);
2251 defer seen.deinit();2248 defer seen.deinit();
22522249
2253 var cur_reference_trace: u32 = 0;2250 var cur_reference_trace: u32 = 0;
...@@ -2288,7 +2285,7 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError {...@@ -2288,7 +2285,7 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError {
2288 if (gop.found_existing) {2285 if (gop.found_existing) {
2289 // If there are multiple errors for the same Decl, prefer the first one added.2286 // If there are multiple errors for the same Decl, prefer the first one added.
2290 sema.err = null;2287 sema.err = null;
2291 err_msg.destroy(mod.gpa);2288 err_msg.destroy(gpa);
2292 } else {2289 } else {
2293 sema.err = err_msg;2290 sema.err = err_msg;
2294 gop.value_ptr.* = err_msg;2291 gop.value_ptr.* = err_msg;
src/glibc.zig+5-5
...@@ -196,7 +196,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -196,7 +196,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
196 "-DASSEMBLER",196 "-DASSEMBLER",
197 "-Wa,--noexecstack",197 "-Wa,--noexecstack",
198 });198 });
199 return comp.build_crt_file("crti", .Obj, &[1]Compilation.CSourceFile{199 return comp.build_crt_file("crti", .Obj, .@"glibc crti.o", &[1]Compilation.CSourceFile{
200 .{200 .{
201 .src_path = try start_asm_path(comp, arena, "crti.S"),201 .src_path = try start_asm_path(comp, arena, "crti.S"),
202 .cache_exempt_flags = args.items,202 .cache_exempt_flags = args.items,
...@@ -215,7 +215,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -215,7 +215,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
215 "-DASSEMBLER",215 "-DASSEMBLER",
216 "-Wa,--noexecstack",216 "-Wa,--noexecstack",
217 });217 });
218 return comp.build_crt_file("crtn", .Obj, &[1]Compilation.CSourceFile{218 return comp.build_crt_file("crtn", .Obj, .@"glibc crtn.o", &[1]Compilation.CSourceFile{
219 .{219 .{
220 .src_path = try start_asm_path(comp, arena, "crtn.S"),220 .src_path = try start_asm_path(comp, arena, "crtn.S"),
221 .cache_exempt_flags = args.items,221 .cache_exempt_flags = args.items,
...@@ -265,7 +265,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -265,7 +265,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
265 .cache_exempt_flags = args.items,265 .cache_exempt_flags = args.items,
266 };266 };
267 };267 };
268 return comp.build_crt_file("Scrt1", .Obj, &[_]Compilation.CSourceFile{ start_o, abi_note_o });268 return comp.build_crt_file("Scrt1", .Obj, .@"glibc Scrt1.o", &[_]Compilation.CSourceFile{ start_o, abi_note_o });
269 },269 },
270 .libc_nonshared_a => {270 .libc_nonshared_a => {
271 const s = path.sep_str;271 const s = path.sep_str;
...@@ -366,7 +366,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -366,7 +366,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
366 files_index += 1;366 files_index += 1;
367 }367 }
368 const files = files_buf[0..files_index];368 const files = files_buf[0..files_index];
369 return comp.build_crt_file("c_nonshared", .Lib, files);369 return comp.build_crt_file("c_nonshared", .Lib, .@"glibc libc_nonshared.a", files);
370 },370 },
371 }371 }
372}372}
...@@ -1105,7 +1105,7 @@ fn buildSharedLib(...@@ -1105,7 +1105,7 @@ fn buildSharedLib(
1105 });1105 });
1106 defer sub_compilation.destroy();1106 defer sub_compilation.destroy();
11071107
1108 try sub_compilation.updateSubCompilation();1108 try comp.updateSubCompilation(sub_compilation, .@"glibc shared object");
1109}1109}
11101110
1111// Return true if glibc has crti/crtn sources for that architecture.1111// Return true if glibc has crti/crtn sources for that architecture.
src/libcxx.zig+2-2
...@@ -258,7 +258,7 @@ pub fn buildLibCXX(comp: *Compilation) !void {...@@ -258,7 +258,7 @@ pub fn buildLibCXX(comp: *Compilation) !void {
258 });258 });
259 defer sub_compilation.destroy();259 defer sub_compilation.destroy();
260260
261 try sub_compilation.updateSubCompilation();261 try comp.updateSubCompilation(sub_compilation, .libcxx);
262262
263 assert(comp.libcxx_static_lib == null);263 assert(comp.libcxx_static_lib == null);
264 comp.libcxx_static_lib = Compilation.CRTFile{264 comp.libcxx_static_lib = Compilation.CRTFile{
...@@ -418,7 +418,7 @@ pub fn buildLibCXXABI(comp: *Compilation) !void {...@@ -418,7 +418,7 @@ pub fn buildLibCXXABI(comp: *Compilation) !void {
418 });418 });
419 defer sub_compilation.destroy();419 defer sub_compilation.destroy();
420420
421 try sub_compilation.updateSubCompilation();421 try comp.updateSubCompilation(sub_compilation, .libcxxabi);
422422
423 assert(comp.libcxxabi_static_lib == null);423 assert(comp.libcxxabi_static_lib == null);
424 comp.libcxxabi_static_lib = Compilation.CRTFile{424 comp.libcxxabi_static_lib = Compilation.CRTFile{
src/libtsan.zig+1-1
...@@ -235,7 +235,7 @@ pub fn buildTsan(comp: *Compilation) !void {...@@ -235,7 +235,7 @@ pub fn buildTsan(comp: *Compilation) !void {
235 });235 });
236 defer sub_compilation.destroy();236 defer sub_compilation.destroy();
237237
238 try sub_compilation.updateSubCompilation();238 try comp.updateSubCompilation(sub_compilation, .libtsan);
239239
240 assert(comp.tsan_static_lib == null);240 assert(comp.tsan_static_lib == null);
241 comp.tsan_static_lib = Compilation.CRTFile{241 comp.tsan_static_lib = Compilation.CRTFile{
src/libunwind.zig+1-1
...@@ -130,7 +130,7 @@ pub fn buildStaticLib(comp: *Compilation) !void {...@@ -130,7 +130,7 @@ pub fn buildStaticLib(comp: *Compilation) !void {
130 });130 });
131 defer sub_compilation.destroy();131 defer sub_compilation.destroy();
132132
133 try sub_compilation.updateSubCompilation();133 try comp.updateSubCompilation(sub_compilation, .libunwind);
134134
135 assert(comp.libunwind_static_lib == null);135 assert(comp.libunwind_static_lib == null);
136136
src/main.zig+104-159
...@@ -24,6 +24,8 @@ const clang = @import("clang.zig");...@@ -24,6 +24,8 @@ const clang = @import("clang.zig");
24const Cache = std.Build.Cache;24const Cache = std.Build.Cache;
25const target_util = @import("target.zig");25const target_util = @import("target.zig");
26const crash_report = @import("crash_report.zig");26const crash_report = @import("crash_report.zig");
27const Module = @import("Module.zig");
28const AstGen = @import("AstGen.zig");
2729
28pub const std_options = struct {30pub const std_options = struct {
29 pub const wasiCwd = wasi_cwd;31 pub const wasiCwd = wasi_cwd;
...@@ -3446,15 +3448,13 @@ fn buildOutputType(...@@ -3446,15 +3448,13 @@ fn buildOutputType(
3446 var errors = try comp.getAllErrorsAlloc();3448 var errors = try comp.getAllErrorsAlloc();
3447 defer errors.deinit(comp.gpa);3449 defer errors.deinit(comp.gpa);
34483450
3449 if (errors.list.len != 0) {3451 if (errors.errorMessageCount() > 0) {
3450 const ttyconf: std.debug.TTY.Config = switch (comp.color) {3452 const ttyconf: std.debug.TTY.Config = switch (comp.color) {
3451 .auto => std.debug.detectTTYConfig(std.io.getStdErr()),3453 .auto => std.debug.detectTTYConfig(std.io.getStdErr()),
3452 .on => .escape_codes,3454 .on => .escape_codes,
3453 .off => .no_color,3455 .off => .no_color,
3454 };3456 };
3455 for (errors.list) |full_err_msg| {3457 try errors.renderToWriter(ttyconf, conn.stream.writer());
3456 try full_err_msg.renderToWriter(ttyconf, conn.stream.writer(), "error:", .Red, 0);
3457 }
3458 continue;3458 continue;
3459 }3459 }
3460 } else {3460 } else {
...@@ -3830,15 +3830,13 @@ fn updateModule(gpa: Allocator, comp: *Compilation, hook: AfterUpdateHook) !void...@@ -3830,15 +3830,13 @@ fn updateModule(gpa: Allocator, comp: *Compilation, hook: AfterUpdateHook) !void
3830 var errors = try comp.getAllErrorsAlloc();3830 var errors = try comp.getAllErrorsAlloc();
3831 defer errors.deinit(comp.gpa);3831 defer errors.deinit(comp.gpa);
38323832
3833 if (errors.list.len != 0) {3833 if (errors.errorMessageCount() > 0) {
3834 const ttyconf: std.debug.TTY.Config = switch (comp.color) {3834 const ttyconf: std.debug.TTY.Config = switch (comp.color) {
3835 .auto => std.debug.detectTTYConfig(std.io.getStdErr()),3835 .auto => std.debug.detectTTYConfig(std.io.getStdErr()),
3836 .on => .escape_codes,3836 .on => .escape_codes,
3837 .off => .no_color,3837 .off => .no_color,
3838 };3838 };
3839 for (errors.list) |full_err_msg| {3839 errors.renderToStdErr(ttyconf);
3840 full_err_msg.renderToStdErr(ttyconf);
3841 }
3842 const log_text = comp.getCompileLogOutput();3840 const log_text = comp.getCompileLogOutput();
3843 if (log_text.len != 0) {3841 if (log_text.len != 0) {
3844 std.debug.print("\nCompile Log Output:\n{s}", .{log_text});3842 std.debug.print("\nCompile Log Output:\n{s}", .{log_text});
...@@ -4438,9 +4436,13 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi...@@ -4438,9 +4436,13 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
4438 var all_modules: Package.AllModules = .{};4436 var all_modules: Package.AllModules = .{};
4439 defer all_modules.deinit(gpa);4437 defer all_modules.deinit(gpa);
44404438
4439 var errors: std.zig.ErrorBundle = undefined;
4440 try errors.init(gpa);
4441 defer errors.deinit(gpa);
4442
4441 // Here we borrow main package's table and will replace it with a fresh4443 // Here we borrow main package's table and will replace it with a fresh
4442 // one after this process completes.4444 // one after this process completes.
4443 build_pkg.fetchAndAddDependencies(4445 const fetch_result = build_pkg.fetchAndAddDependencies(
4444 &main_pkg,4446 &main_pkg,
4445 arena,4447 arena,
4446 &thread_pool,4448 &thread_pool,
...@@ -4451,12 +4453,19 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi...@@ -4451,12 +4453,19 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
4451 &dependencies_source,4453 &dependencies_source,
4452 &build_roots_source,4454 &build_roots_source,
4453 "",4455 "",
4454 color,4456 &errors,
4455 &all_modules,4457 &all_modules,
4456 ) catch |err| switch (err) {4458 );
4457 error.PackageFetchFailed => process.exit(1),4459 if (errors.errorMessageCount() > 0) {
4458 else => |e| return e,4460 const ttyconf: std.debug.TTY.Config = switch (color) {
4459 };4461 .auto => std.debug.detectTTYConfig(std.io.getStdErr()),
4462 .on => .escape_codes,
4463 .off => .no_color,
4464 };
4465 errors.renderToStdErr(ttyconf);
4466 process.exit(1);
4467 }
4468 try fetch_result;
44604469
4461 try dependencies_source.appendSlice("};\npub const build_root = struct {\n");4470 try dependencies_source.appendSlice("};\npub const build_root = struct {\n");
4462 try dependencies_source.appendSlice(build_roots_source.items);4471 try dependencies_source.appendSlice(build_roots_source.items);
...@@ -4543,7 +4552,7 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi...@@ -4543,7 +4552,7 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
4543}4552}
45444553
4545fn readSourceFileToEndAlloc(4554fn readSourceFileToEndAlloc(
4546 allocator: mem.Allocator,4555 allocator: Allocator,
4547 input: *const fs.File,4556 input: *const fs.File,
4548 size_hint: ?usize,4557 size_hint: ?usize,
4549) ![:0]u8 {4558) ![:0]u8 {
...@@ -4687,12 +4696,9 @@ pub fn cmdFmt(gpa: Allocator, arena: Allocator, args: []const []const u8) !void...@@ -4687,12 +4696,9 @@ pub fn cmdFmt(gpa: Allocator, arena: Allocator, args: []const []const u8) !void
4687 };4696 };
4688 defer tree.deinit(gpa);4697 defer tree.deinit(gpa);
46894698
4690 try printErrsMsgToStdErr(gpa, arena, tree, "<stdin>", color);4699 try printAstErrorsToStderr(gpa, tree, "<stdin>", color);
4691 var has_ast_error = false;4700 var has_ast_error = false;
4692 if (check_ast_flag) {4701 if (check_ast_flag) {
4693 const Module = @import("Module.zig");
4694 const AstGen = @import("AstGen.zig");
4695
4696 var file: Module.File = .{4702 var file: Module.File = .{
4697 .status = .never_loaded,4703 .status = .never_loaded,
4698 .source_loaded = true,4704 .source_loaded = true,
...@@ -4715,20 +4721,16 @@ pub fn cmdFmt(gpa: Allocator, arena: Allocator, args: []const []const u8) !void...@@ -4715,20 +4721,16 @@ pub fn cmdFmt(gpa: Allocator, arena: Allocator, args: []const []const u8) !void
4715 defer file.zir.deinit(gpa);4721 defer file.zir.deinit(gpa);
47164722
4717 if (file.zir.hasCompileErrors()) {4723 if (file.zir.hasCompileErrors()) {
4718 var arena_instance = std.heap.ArenaAllocator.init(gpa);4724 var errors: std.zig.ErrorBundle = undefined;
4719 defer arena_instance.deinit();4725 try errors.init(gpa);
4720 var errors = std.ArrayList(Compilation.AllErrors.Message).init(gpa);4726 defer errors.deinit(gpa);
4721 defer errors.deinit();4727 try Compilation.addZirErrorMessages(gpa, &errors, &file);
4722
4723 try Compilation.AllErrors.addZir(arena_instance.allocator(), &errors, &file);
4724 const ttyconf: std.debug.TTY.Config = switch (color) {4728 const ttyconf: std.debug.TTY.Config = switch (color) {
4725 .auto => std.debug.detectTTYConfig(std.io.getStdErr()),4729 .auto => std.debug.detectTTYConfig(std.io.getStdErr()),
4726 .on => .escape_codes,4730 .on => .escape_codes,
4727 .off => .no_color,4731 .off => .no_color,
4728 };4732 };
4729 for (errors.items) |full_err_msg| {4733 errors.renderToStdErr(ttyconf);
4730 full_err_msg.renderToStdErr(ttyconf);
4731 }
4732 has_ast_error = true;4734 has_ast_error = true;
4733 }4735 }
4734 }4736 }
...@@ -4875,12 +4877,13 @@ fn fmtPathFile(...@@ -4875,12 +4877,13 @@ fn fmtPathFile(
4875 if (stat.kind == .Directory)4877 if (stat.kind == .Directory)
4876 return error.IsDir;4878 return error.IsDir;
48774879
4880 const gpa = fmt.gpa;
4878 const source_code = try readSourceFileToEndAlloc(4881 const source_code = try readSourceFileToEndAlloc(
4879 fmt.gpa,4882 gpa,
4880 &source_file,4883 &source_file,
4881 std.math.cast(usize, stat.size) orelse return error.FileTooBig,4884 std.math.cast(usize, stat.size) orelse return error.FileTooBig,
4882 );4885 );
4883 defer fmt.gpa.free(source_code);4886 defer gpa.free(source_code);
48844887
4885 source_file.close();4888 source_file.close();
4886 file_closed = true;4889 file_closed = true;
...@@ -4888,19 +4891,16 @@ fn fmtPathFile(...@@ -4888,19 +4891,16 @@ fn fmtPathFile(
4888 // Add to set after no longer possible to get error.IsDir.4891 // Add to set after no longer possible to get error.IsDir.
4889 if (try fmt.seen.fetchPut(stat.inode, {})) |_| return;4892 if (try fmt.seen.fetchPut(stat.inode, {})) |_| return;
48904893
4891 var tree = try Ast.parse(fmt.gpa, source_code, .zig);4894 var tree = try Ast.parse(gpa, source_code, .zig);
4892 defer tree.deinit(fmt.gpa);4895 defer tree.deinit(gpa);
48934896
4894 try printErrsMsgToStdErr(fmt.gpa, fmt.arena, tree, file_path, fmt.color);4897 try printAstErrorsToStderr(gpa, tree, file_path, fmt.color);
4895 if (tree.errors.len != 0) {4898 if (tree.errors.len != 0) {
4896 fmt.any_error = true;4899 fmt.any_error = true;
4897 return;4900 return;
4898 }4901 }
48994902
4900 if (fmt.check_ast) {4903 if (fmt.check_ast) {
4901 const Module = @import("Module.zig");
4902 const AstGen = @import("AstGen.zig");
4903
4904 var file: Module.File = .{4904 var file: Module.File = .{
4905 .status = .never_loaded,4905 .status = .never_loaded,
4906 .source_loaded = true,4906 .source_loaded = true,
...@@ -4919,31 +4919,27 @@ fn fmtPathFile(...@@ -4919,31 +4919,27 @@ fn fmtPathFile(
4919 .root_decl = .none,4919 .root_decl = .none,
4920 };4920 };
49214921
4922 file.pkg = try Package.create(fmt.gpa, null, file.sub_file_path);4922 file.pkg = try Package.create(gpa, null, file.sub_file_path);
4923 defer file.pkg.destroy(fmt.gpa);4923 defer file.pkg.destroy(gpa);
49244924
4925 if (stat.size > max_src_size)4925 if (stat.size > max_src_size)
4926 return error.FileTooBig;4926 return error.FileTooBig;
49274927
4928 file.zir = try AstGen.generate(fmt.gpa, file.tree);4928 file.zir = try AstGen.generate(gpa, file.tree);
4929 file.zir_loaded = true;4929 file.zir_loaded = true;
4930 defer file.zir.deinit(fmt.gpa);4930 defer file.zir.deinit(gpa);
49314931
4932 if (file.zir.hasCompileErrors()) {4932 if (file.zir.hasCompileErrors()) {
4933 var arena_instance = std.heap.ArenaAllocator.init(fmt.gpa);4933 var errors: std.zig.ErrorBundle = undefined;
4934 defer arena_instance.deinit();4934 try errors.init(gpa);
4935 var errors = std.ArrayList(Compilation.AllErrors.Message).init(fmt.gpa);4935 defer errors.deinit(gpa);
4936 defer errors.deinit();4936 try Compilation.addZirErrorMessages(gpa, &errors, &file);
4937
4938 try Compilation.AllErrors.addZir(arena_instance.allocator(), &errors, &file);
4939 const ttyconf: std.debug.TTY.Config = switch (fmt.color) {4937 const ttyconf: std.debug.TTY.Config = switch (fmt.color) {
4940 .auto => std.debug.detectTTYConfig(std.io.getStdErr()),4938 .auto => std.debug.detectTTYConfig(std.io.getStdErr()),
4941 .on => .escape_codes,4939 .on => .escape_codes,
4942 .off => .no_color,4940 .off => .no_color,
4943 };4941 };
4944 for (errors.items) |full_err_msg| {4942 errors.renderToStdErr(ttyconf);
4945 full_err_msg.renderToStdErr(ttyconf);
4946 }
4947 fmt.any_error = true;4943 fmt.any_error = true;
4948 }4944 }
4949 }4945 }
...@@ -4971,100 +4967,53 @@ fn fmtPathFile(...@@ -4971,100 +4967,53 @@ fn fmtPathFile(
4971 }4967 }
4972}4968}
49734969
4974pub fn printErrsMsgToStdErr(4970fn printAstErrorsToStderr(gpa: Allocator, tree: Ast, path: []const u8, color: Color) !void {
4975 gpa: mem.Allocator,4971 var error_bundle: std.zig.ErrorBundle = undefined;
4976 arena: mem.Allocator,4972 try error_bundle.init(gpa);
4973 defer error_bundle.deinit(gpa);
4974
4975 try putAstErrorsIntoBundle(gpa, tree, path, &error_bundle);
4976
4977 const ttyconf: std.debug.TTY.Config = switch (color) {
4978 .auto => std.debug.detectTTYConfig(std.io.getStdErr()),
4979 .on => .escape_codes,
4980 .off => .no_color,
4981 };
4982 error_bundle.renderToStdErr(ttyconf);
4983}
4984
4985pub fn putAstErrorsIntoBundle(
4986 gpa: Allocator,
4977 tree: Ast,4987 tree: Ast,
4978 path: []const u8,4988 path: []const u8,
4979 color: Color,4989 error_bundle: *std.zig.ErrorBundle,
4980) !void {4990) !void {
4981 const parse_errors: []const Ast.Error = tree.errors;4991 var file: Module.File = .{
4982 var i: usize = 0;4992 .status = .never_loaded,
4983 while (i < parse_errors.len) : (i += 1) {4993 .source_loaded = true,
4984 const parse_error = parse_errors[i];4994 .zir_loaded = false,
4985 const lok_token = parse_error.token;4995 .sub_file_path = path,
4986 const token_tags = tree.tokens.items(.tag);4996 .source = tree.source,
4987 const start_loc = tree.tokenLocation(0, lok_token);4997 .stat = .{
4988 const source_line = tree.source[start_loc.line_start..start_loc.line_end];4998 .size = 0,
49894999 .inode = 0,
4990 var text_buf = std.ArrayList(u8).init(gpa);5000 .mtime = 0,
4991 defer text_buf.deinit();5001 },
4992 const writer = text_buf.writer();5002 .tree = tree,
4993 try tree.renderError(parse_error, writer);5003 .tree_loaded = true,
4994 const text = try arena.dupe(u8, text_buf.items);5004 .zir = undefined,
49955005 .pkg = undefined,
4996 var notes_buffer: [2]Compilation.AllErrors.Message = undefined;5006 .root_decl = .none,
4997 var notes_len: usize = 0;5007 };
4998
4999 if (token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)] == .invalid) {
5000 const bad_off = @intCast(u32, tree.tokenSlice(parse_error.token + @boolToInt(parse_error.token_is_prev)).len);
5001 const byte_offset = @intCast(u32, start_loc.line_start) + @intCast(u32, start_loc.column) + bad_off;
5002 notes_buffer[notes_len] = .{
5003 .src = .{
5004 .src_path = path,
5005 .msg = try std.fmt.allocPrint(arena, "invalid byte: '{'}'", .{
5006 std.zig.fmtEscapes(tree.source[byte_offset..][0..1]),
5007 }),
5008 .span = .{ .start = byte_offset, .end = byte_offset + 1, .main = byte_offset },
5009 .line = @intCast(u32, start_loc.line),
5010 .column = @intCast(u32, start_loc.column) + bad_off,
5011 .source_line = source_line,
5012 },
5013 };
5014 notes_len += 1;
5015 }
5016
5017 for (parse_errors[i + 1 ..]) |note| {
5018 if (!note.is_note) break;
5019
5020 text_buf.items.len = 0;
5021 try tree.renderError(note, writer);
5022 const note_loc = tree.tokenLocation(0, note.token);
5023 const byte_offset = @intCast(u32, note_loc.line_start);
5024 notes_buffer[notes_len] = .{
5025 .src = .{
5026 .src_path = path,
5027 .msg = try arena.dupe(u8, text_buf.items),
5028 .span = .{
5029 .start = byte_offset,
5030 .end = byte_offset + @intCast(u32, tree.tokenSlice(note.token).len),
5031 .main = byte_offset,
5032 },
5033 .line = @intCast(u32, note_loc.line),
5034 .column = @intCast(u32, note_loc.column),
5035 .source_line = tree.source[note_loc.line_start..note_loc.line_end],
5036 },
5037 };
5038 i += 1;
5039 notes_len += 1;
5040 }
50415008
5042 const extra_offset = tree.errorOffset(parse_error);5009 file.pkg = try Package.create(gpa, null, path);
5043 const byte_offset = @intCast(u32, start_loc.line_start) + extra_offset;5010 defer file.pkg.destroy(gpa);
5044 const message: Compilation.AllErrors.Message = .{
5045 .src = .{
5046 .src_path = path,
5047 .msg = text,
5048 .span = .{
5049 .start = byte_offset,
5050 .end = byte_offset + @intCast(u32, tree.tokenSlice(lok_token).len),
5051 .main = byte_offset,
5052 },
5053 .line = @intCast(u32, start_loc.line),
5054 .column = @intCast(u32, start_loc.column) + extra_offset,
5055 .source_line = source_line,
5056 .notes = notes_buffer[0..notes_len],
5057 },
5058 };
50595011
5060 const ttyconf: std.debug.TTY.Config = switch (color) {5012 file.zir = try AstGen.generate(gpa, file.tree);
5061 .auto => std.debug.detectTTYConfig(std.io.getStdErr()),5013 file.zir_loaded = true;
5062 .on => .escape_codes,5014 defer file.zir.deinit(gpa);
5063 .off => .no_color,
5064 };
50655015
5066 message.renderToStdErr(ttyconf);5016 try Compilation.addZirErrorMessages(gpa, error_bundle, &file);
5067 }
5068}5017}
50695018
5070pub const info_zen =5019pub const info_zen =
...@@ -5547,8 +5496,6 @@ pub fn cmdAstCheck(...@@ -5547,8 +5496,6 @@ pub fn cmdAstCheck(
5547 arena: Allocator,5496 arena: Allocator,
5548 args: []const []const u8,5497 args: []const []const u8,
5549) !void {5498) !void {
5550 const Module = @import("Module.zig");
5551 const AstGen = @import("AstGen.zig");
5552 const Zir = @import("Zir.zig");5499 const Zir = @import("Zir.zig");
55535500
5554 var color: Color = .auto;5501 var color: Color = .auto;
...@@ -5638,7 +5585,7 @@ pub fn cmdAstCheck(...@@ -5638,7 +5585,7 @@ pub fn cmdAstCheck(
5638 file.tree_loaded = true;5585 file.tree_loaded = true;
5639 defer file.tree.deinit(gpa);5586 defer file.tree.deinit(gpa);
56405587
5641 try printErrsMsgToStdErr(gpa, arena, file.tree, file.sub_file_path, color);5588 try printAstErrorsToStderr(gpa, file.tree, file.sub_file_path, color);
5642 if (file.tree.errors.len != 0) {5589 if (file.tree.errors.len != 0) {
5643 process.exit(1);5590 process.exit(1);
5644 }5591 }
...@@ -5648,16 +5595,16 @@ pub fn cmdAstCheck(...@@ -5648,16 +5595,16 @@ pub fn cmdAstCheck(
5648 defer file.zir.deinit(gpa);5595 defer file.zir.deinit(gpa);
56495596
5650 if (file.zir.hasCompileErrors()) {5597 if (file.zir.hasCompileErrors()) {
5651 var errors = std.ArrayList(Compilation.AllErrors.Message).init(arena);5598 var errors: std.zig.ErrorBundle = undefined;
5652 try Compilation.AllErrors.addZir(arena, &errors, &file);5599 try errors.init(gpa);
5600 defer errors.deinit(gpa);
5601 try Compilation.addZirErrorMessages(gpa, &errors, &file);
5653 const ttyconf: std.debug.TTY.Config = switch (color) {5602 const ttyconf: std.debug.TTY.Config = switch (color) {
5654 .auto => std.debug.detectTTYConfig(std.io.getStdErr()),5603 .auto => std.debug.detectTTYConfig(std.io.getStdErr()),
5655 .on => .escape_codes,5604 .on => .escape_codes,
5656 .off => .no_color,5605 .off => .no_color,
5657 };5606 };
5658 for (errors.items) |full_err_msg| {5607 errors.renderToStdErr(ttyconf);
5659 full_err_msg.renderToStdErr(ttyconf);
5660 }
5661 process.exit(1);5608 process.exit(1);
5662 }5609 }
56635610
...@@ -5715,8 +5662,6 @@ pub fn cmdChangelist(...@@ -5715,8 +5662,6 @@ pub fn cmdChangelist(
5715 arena: Allocator,5662 arena: Allocator,
5716 args: []const []const u8,5663 args: []const []const u8,
5717) !void {5664) !void {
5718 const Module = @import("Module.zig");
5719 const AstGen = @import("AstGen.zig");
5720 const Zir = @import("Zir.zig");5665 const Zir = @import("Zir.zig");
57215666
5722 const old_source_file = args[0];5667 const old_source_file = args[0];
...@@ -5764,7 +5709,7 @@ pub fn cmdChangelist(...@@ -5764,7 +5709,7 @@ pub fn cmdChangelist(
5764 file.tree_loaded = true;5709 file.tree_loaded = true;
5765 defer file.tree.deinit(gpa);5710 defer file.tree.deinit(gpa);
57665711
5767 try printErrsMsgToStdErr(gpa, arena, file.tree, old_source_file, .auto);5712 try printAstErrorsToStderr(gpa, file.tree, old_source_file, .auto);
5768 if (file.tree.errors.len != 0) {5713 if (file.tree.errors.len != 0) {
5769 process.exit(1);5714 process.exit(1);
5770 }5715 }
...@@ -5774,12 +5719,12 @@ pub fn cmdChangelist(...@@ -5774,12 +5719,12 @@ pub fn cmdChangelist(
5774 defer file.zir.deinit(gpa);5719 defer file.zir.deinit(gpa);
57755720
5776 if (file.zir.hasCompileErrors()) {5721 if (file.zir.hasCompileErrors()) {
5777 var errors = std.ArrayList(Compilation.AllErrors.Message).init(arena);5722 var errors: std.zig.ErrorBundle = undefined;
5778 try Compilation.AllErrors.addZir(arena, &errors, &file);5723 try errors.init(gpa);
5724 defer errors.deinit(gpa);
5725 try Compilation.addZirErrorMessages(gpa, &errors, &file);
5779 const ttyconf = std.debug.detectTTYConfig(std.io.getStdErr());5726 const ttyconf = std.debug.detectTTYConfig(std.io.getStdErr());
5780 for (errors.items) |full_err_msg| {5727 errors.renderToStdErr(ttyconf);
5781 full_err_msg.renderToStdErr(ttyconf);
5782 }
5783 process.exit(1);5728 process.exit(1);
5784 }5729 }
57855730
...@@ -5801,7 +5746,7 @@ pub fn cmdChangelist(...@@ -5801,7 +5746,7 @@ pub fn cmdChangelist(
5801 var new_tree = try Ast.parse(gpa, new_source, .zig);5746 var new_tree = try Ast.parse(gpa, new_source, .zig);
5802 defer new_tree.deinit(gpa);5747 defer new_tree.deinit(gpa);
58035748
5804 try printErrsMsgToStdErr(gpa, arena, new_tree, new_source_file, .auto);5749 try printAstErrorsToStderr(gpa, new_tree, new_source_file, .auto);
5805 if (new_tree.errors.len != 0) {5750 if (new_tree.errors.len != 0) {
5806 process.exit(1);5751 process.exit(1);
5807 }5752 }
...@@ -5813,12 +5758,12 @@ pub fn cmdChangelist(...@@ -5813,12 +5758,12 @@ pub fn cmdChangelist(
5813 file.zir_loaded = true;5758 file.zir_loaded = true;
58145759
5815 if (file.zir.hasCompileErrors()) {5760 if (file.zir.hasCompileErrors()) {
5816 var errors = std.ArrayList(Compilation.AllErrors.Message).init(arena);5761 var errors: std.zig.ErrorBundle = undefined;
5817 try Compilation.AllErrors.addZir(arena, &errors, &file);5762 try errors.init(gpa);
5763 defer errors.deinit(gpa);
5764 try Compilation.addZirErrorMessages(gpa, &errors, &file);
5818 const ttyconf = std.debug.detectTTYConfig(std.io.getStdErr());5765 const ttyconf = std.debug.detectTTYConfig(std.io.getStdErr());
5819 for (errors.items) |full_err_msg| {5766 errors.renderToStdErr(ttyconf);
5820 full_err_msg.renderToStdErr(ttyconf);
5821 }
5822 process.exit(1);5767 process.exit(1);
5823 }5768 }
58245769
src/mingw.zig+6-6
...@@ -41,7 +41,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -41,7 +41,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
41 //"-D_UNICODE",41 //"-D_UNICODE",
42 //"-DWPRFLAG=1",42 //"-DWPRFLAG=1",
43 });43 });
44 return comp.build_crt_file("crt2", .Obj, &[1]Compilation.CSourceFile{44 return comp.build_crt_file("crt2", .Obj, .@"mingw-w64 crt2.o", &[1]Compilation.CSourceFile{
45 .{45 .{
46 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{46 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
47 "libc", "mingw", "crt", "crtexe.c",47 "libc", "mingw", "crt", "crtexe.c",
...@@ -60,7 +60,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -60,7 +60,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
60 "-U__CRTDLL__",60 "-U__CRTDLL__",
61 "-D__MSVCRT__",61 "-D__MSVCRT__",
62 });62 });
63 return comp.build_crt_file("dllcrt2", .Obj, &[1]Compilation.CSourceFile{63 return comp.build_crt_file("dllcrt2", .Obj, .@"mingw-w64 dllcrt2.o", &[1]Compilation.CSourceFile{
64 .{64 .{
65 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{65 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
66 "libc", "mingw", "crt", "crtdll.c",66 "libc", "mingw", "crt", "crtdll.c",
...@@ -100,7 +100,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -100,7 +100,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
100 .extra_flags = args.items,100 .extra_flags = args.items,
101 };101 };
102 }102 }
103 return comp.build_crt_file("mingw32", .Lib, &c_source_files);103 return comp.build_crt_file("mingw32", .Lib, .@"mingw-w64 mingw32.lib", &c_source_files);
104 },104 },
105105
106 .msvcrt_os_lib => {106 .msvcrt_os_lib => {
...@@ -148,7 +148,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -148,7 +148,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
148 };148 };
149 }149 }
150 }150 }
151 return comp.build_crt_file("msvcrt-os", .Lib, c_source_files.items);151 return comp.build_crt_file("msvcrt-os", .Lib, .@"mingw-w64 msvcrt-os.lib", c_source_files.items);
152 },152 },
153153
154 .mingwex_lib => {154 .mingwex_lib => {
...@@ -211,7 +211,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -211,7 +211,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
211 } else {211 } else {
212 @panic("unsupported arch");212 @panic("unsupported arch");
213 }213 }
214 return comp.build_crt_file("mingwex", .Lib, c_source_files.items);214 return comp.build_crt_file("mingwex", .Lib, .@"mingw-w64 mingwex.lib", c_source_files.items);
215 },215 },
216216
217 .uuid_lib => {217 .uuid_lib => {
...@@ -244,7 +244,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -244,7 +244,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
244 .extra_flags = extra_flags,244 .extra_flags = extra_flags,
245 };245 };
246 }246 }
247 return comp.build_crt_file("uuid", .Lib, &c_source_files);247 return comp.build_crt_file("uuid", .Lib, .@"mingw-w64 uuid.lib", &c_source_files);
248 },248 },
249 }249 }
250}250}
src/musl.zig+7-7
...@@ -33,7 +33,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -33,7 +33,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
33 try args.appendSlice(&[_][]const u8{33 try args.appendSlice(&[_][]const u8{
34 "-Qunused-arguments",34 "-Qunused-arguments",
35 });35 });
36 return comp.build_crt_file("crti", .Obj, &[1]Compilation.CSourceFile{36 return comp.build_crt_file("crti", .Obj, .@"musl crti.o", &[1]Compilation.CSourceFile{
37 .{37 .{
38 .src_path = try start_asm_path(comp, arena, "crti.s"),38 .src_path = try start_asm_path(comp, arena, "crti.s"),
39 .extra_flags = args.items,39 .extra_flags = args.items,
...@@ -46,7 +46,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -46,7 +46,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
46 try args.appendSlice(&[_][]const u8{46 try args.appendSlice(&[_][]const u8{
47 "-Qunused-arguments",47 "-Qunused-arguments",
48 });48 });
49 return comp.build_crt_file("crtn", .Obj, &[1]Compilation.CSourceFile{49 return comp.build_crt_file("crtn", .Obj, .@"musl crtn.o", &[1]Compilation.CSourceFile{
50 .{50 .{
51 .src_path = try start_asm_path(comp, arena, "crtn.s"),51 .src_path = try start_asm_path(comp, arena, "crtn.s"),
52 .extra_flags = args.items,52 .extra_flags = args.items,
...@@ -60,7 +60,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -60,7 +60,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
60 "-fno-stack-protector",60 "-fno-stack-protector",
61 "-DCRT",61 "-DCRT",
62 });62 });
63 return comp.build_crt_file("crt1", .Obj, &[1]Compilation.CSourceFile{63 return comp.build_crt_file("crt1", .Obj, .@"musl crt1.o", &[1]Compilation.CSourceFile{
64 .{64 .{
65 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{65 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
66 "libc", "musl", "crt", "crt1.c",66 "libc", "musl", "crt", "crt1.c",
...@@ -77,7 +77,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -77,7 +77,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
77 "-fno-stack-protector",77 "-fno-stack-protector",
78 "-DCRT",78 "-DCRT",
79 });79 });
80 return comp.build_crt_file("rcrt1", .Obj, &[1]Compilation.CSourceFile{80 return comp.build_crt_file("rcrt1", .Obj, .@"musl rcrt1.o", &[1]Compilation.CSourceFile{
81 .{81 .{
82 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{82 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
83 "libc", "musl", "crt", "rcrt1.c",83 "libc", "musl", "crt", "rcrt1.c",
...@@ -94,7 +94,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -94,7 +94,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
94 "-fno-stack-protector",94 "-fno-stack-protector",
95 "-DCRT",95 "-DCRT",
96 });96 });
97 return comp.build_crt_file("Scrt1", .Obj, &[1]Compilation.CSourceFile{97 return comp.build_crt_file("Scrt1", .Obj, .@"musl Scrt1.o", &[1]Compilation.CSourceFile{
98 .{98 .{
99 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{99 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
100 "libc", "musl", "crt", "Scrt1.c",100 "libc", "musl", "crt", "Scrt1.c",
...@@ -187,7 +187,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -187,7 +187,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
187 .extra_flags = args.items,187 .extra_flags = args.items,
188 };188 };
189 }189 }
190 return comp.build_crt_file("c", .Lib, c_source_files.items);190 return comp.build_crt_file("c", .Lib, .@"musl libc.a", c_source_files.items);
191 },191 },
192 .libc_so => {192 .libc_so => {
193 const target = comp.getTarget();193 const target = comp.getTarget();
...@@ -241,7 +241,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -241,7 +241,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
241 });241 });
242 defer sub_compilation.destroy();242 defer sub_compilation.destroy();
243243
244 try sub_compilation.updateSubCompilation();244 try comp.updateSubCompilation(sub_compilation, .@"musl libc.so");
245245
246 try comp.crt_files.ensureUnusedCapacity(comp.gpa, 1);246 try comp.crt_files.ensureUnusedCapacity(comp.gpa, 1);
247247
src/wasi_libc.zig+7-7
...@@ -74,7 +74,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -74,7 +74,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
74 var args = std.ArrayList([]const u8).init(arena);74 var args = std.ArrayList([]const u8).init(arena);
75 try addCCArgs(comp, arena, &args, false);75 try addCCArgs(comp, arena, &args, false);
76 try addLibcBottomHalfIncludes(comp, arena, &args);76 try addLibcBottomHalfIncludes(comp, arena, &args);
77 return comp.build_crt_file("crt1-reactor", .Obj, &[1]Compilation.CSourceFile{77 return comp.build_crt_file("crt1-reactor", .Obj, .@"wasi crt1-reactor.o", &[1]Compilation.CSourceFile{
78 .{78 .{
79 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{79 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
80 "libc", try sanitize(arena, crt1_reactor_src_file),80 "libc", try sanitize(arena, crt1_reactor_src_file),
...@@ -87,7 +87,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -87,7 +87,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
87 var args = std.ArrayList([]const u8).init(arena);87 var args = std.ArrayList([]const u8).init(arena);
88 try addCCArgs(comp, arena, &args, false);88 try addCCArgs(comp, arena, &args, false);
89 try addLibcBottomHalfIncludes(comp, arena, &args);89 try addLibcBottomHalfIncludes(comp, arena, &args);
90 return comp.build_crt_file("crt1-command", .Obj, &[1]Compilation.CSourceFile{90 return comp.build_crt_file("crt1-command", .Obj, .@"wasi crt1-command.o", &[1]Compilation.CSourceFile{
91 .{91 .{
92 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{92 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
93 "libc", try sanitize(arena, crt1_command_src_file),93 "libc", try sanitize(arena, crt1_command_src_file),
...@@ -145,7 +145,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -145,7 +145,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
145 }145 }
146 }146 }
147147
148 try comp.build_crt_file("c", .Lib, libc_sources.items);148 try comp.build_crt_file("c", .Lib, .@"wasi libc.a", libc_sources.items);
149 },149 },
150 .libwasi_emulated_process_clocks_a => {150 .libwasi_emulated_process_clocks_a => {
151 var args = std.ArrayList([]const u8).init(arena);151 var args = std.ArrayList([]const u8).init(arena);
...@@ -161,7 +161,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -161,7 +161,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
161 .extra_flags = args.items,161 .extra_flags = args.items,
162 });162 });
163 }163 }
164 try comp.build_crt_file("wasi-emulated-process-clocks", .Lib, emu_clocks_sources.items);164 try comp.build_crt_file("wasi-emulated-process-clocks", .Lib, .@"libwasi-emulated-process-clocks.a", emu_clocks_sources.items);
165 },165 },
166 .libwasi_emulated_getpid_a => {166 .libwasi_emulated_getpid_a => {
167 var args = std.ArrayList([]const u8).init(arena);167 var args = std.ArrayList([]const u8).init(arena);
...@@ -177,7 +177,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -177,7 +177,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
177 .extra_flags = args.items,177 .extra_flags = args.items,
178 });178 });
179 }179 }
180 try comp.build_crt_file("wasi-emulated-getpid", .Lib, emu_getpid_sources.items);180 try comp.build_crt_file("wasi-emulated-getpid", .Lib, .@"libwasi-emulated-getpid.a", emu_getpid_sources.items);
181 },181 },
182 .libwasi_emulated_mman_a => {182 .libwasi_emulated_mman_a => {
183 var args = std.ArrayList([]const u8).init(arena);183 var args = std.ArrayList([]const u8).init(arena);
...@@ -193,7 +193,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -193,7 +193,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
193 .extra_flags = args.items,193 .extra_flags = args.items,
194 });194 });
195 }195 }
196 try comp.build_crt_file("wasi-emulated-mman", .Lib, emu_mman_sources.items);196 try comp.build_crt_file("wasi-emulated-mman", .Lib, .@"libwasi-emulated-mman.a", emu_mman_sources.items);
197 },197 },
198 .libwasi_emulated_signal_a => {198 .libwasi_emulated_signal_a => {
199 var emu_signal_sources = std.ArrayList(Compilation.CSourceFile).init(arena);199 var emu_signal_sources = std.ArrayList(Compilation.CSourceFile).init(arena);
...@@ -228,7 +228,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -228,7 +228,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
228 }228 }
229 }229 }
230230
231 try comp.build_crt_file("wasi-emulated-signal", .Lib, emu_signal_sources.items);231 try comp.build_crt_file("wasi-emulated-signal", .Lib, .@"libwasi-emulated-signal.a", emu_signal_sources.items);
232 },232 },
233 }233 }
234}234}