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");
33const fmt = @import("zig/fmt.zig");
44const assert = std.debug.assert;
55
6pub const ErrorBundle = @import("zig/ErrorBundle.zig");
67pub const Token = tokenizer.Token;
78pub const Tokenizer = tokenizer.Tokenizer;
89pub 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 {
133133 try astgen.extra.ensureTotalCapacity(gpa, tree.nodes.len + reserved_count);
134134 astgen.extra.items.len += reserved_count;
135135
136 try lowerAstErrors(&astgen);
137
136138 var top_scope: Scope.Top = .{};
137139
138140 var gz_instructions: std.ArrayListUnmanaged(Zir.Inst.Index) = .{};
......@@ -10401,27 +10403,11 @@ fn appendErrorTokNotes(
1040110403 args: anytype,
1040210404 notes: []const u32,
1040310405) !void {
10404 @setCold(true);
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 });
10406 return appendErrorTokNotesOff(astgen, token, 0, format, args, notes);
1042210407}
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.
1042510411fn failOff(
1042610412 astgen: *AstGen,
1042710413 token: Ast.TokenIndex,
......@@ -10429,27 +10415,36 @@ fn failOff(
1042910415 comptime format: []const u8,
1043010416 args: anytype,
1043110417) InnerError {
10432 try appendErrorOff(astgen, token, byte_offset, format, args);
10418 try appendErrorTokNotesOff(astgen, token, byte_offset, format, args, &.{});
1043310419 return error.AnalysisFail;
1043410420}
1043510421
10436fn appendErrorOff(
10422fn appendErrorTokNotesOff(
1043710423 astgen: *AstGen,
1043810424 token: Ast.TokenIndex,
1043910425 byte_offset: u32,
1044010426 comptime format: []const u8,
1044110427 args: anytype,
10442) Allocator.Error!void {
10428 notes: []const u32,
10429) !void {
1044310430 @setCold(true);
10431 const gpa = astgen.gpa;
1044410432 const string_bytes = &astgen.string_bytes;
1044510433 const msg = @intCast(u32, string_bytes.items.len);
10446 try string_bytes.writer(astgen.gpa).print(format ++ "\x00", args);
10447 try astgen.compile_errors.append(astgen.gpa, .{
10434 try string_bytes.writer(gpa).print(format ++ "\x00", args);
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, .{
1044810443 .msg = msg,
1044910444 .node = 0,
1045010445 .token = token,
1045110446 .byte_offset = byte_offset,
10452 .notes = 0,
10447 .notes = notes_index,
1045310448 });
1045410449}
1045510450
......@@ -10458,6 +10453,16 @@ fn errNoteTok(
1045810453 token: Ast.TokenIndex,
1045910454 comptime format: []const u8,
1046010455 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,
1046110466) Allocator.Error!u32 {
1046210467 @setCold(true);
1046310468 const string_bytes = &astgen.string_bytes;
......@@ -10467,7 +10472,7 @@ fn errNoteTok(
1046710472 .msg = msg,
1046810473 .node = 0,
1046910474 .token = token,
10470 .byte_offset = 0,
10475 .byte_offset = byte_offset,
1047110476 .notes = 0,
1047210477 });
1047310478}
......@@ -12634,3 +12639,42 @@ fn emitDbgStmt(gz: *GenZir, line: u32, column: u32) !void {
1263412639 },
1263512640 } });
1263612641}
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);
99const Target = std.Target;
1010const ThreadPool = std.Thread.Pool;
1111const WaitGroup = std.Thread.WaitGroup;
12const ErrorBundle = std.zig.ErrorBundle;
1213
1314const Value = @import("value.zig").Value;
1415const Type = @import("type.zig").Type;
......@@ -334,12 +335,41 @@ pub const MiscTask = enum {
334335 libssp,
335336 zig_libc,
336337 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",
337367};
338368
339369pub const MiscError = struct {
340370 /// Allocated with gpa.
341371 msg: []u8,
342 children: ?AllErrors = null,
372 children: ?ErrorBundle = null,
343373
344374 pub fn deinit(misc_err: *MiscError, gpa: Allocator) void {
345375 gpa.free(misc_err.msg);
......@@ -365,448 +395,6 @@ pub const LldError = struct {
365395 }
366396};
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
810398pub const Directory = Cache.Directory;
811399
812400pub const EmitLoc = struct {
......@@ -2891,7 +2479,7 @@ pub fn makeBinFileWritable(self: *Compilation) !void {
28912479}
28922480
28932481/// This function is temporally single-threaded.
2894pub fn totalErrorCount(self: *Compilation) usize {
2482pub fn totalErrorCount(self: *Compilation) u32 {
28952483 var total: usize = self.failed_c_objects.count() + self.misc_failures.count() +
28962484 @boolToInt(self.alloc_failure_occurred) + self.lld_errors.items.len;
28972485
......@@ -2951,17 +2539,16 @@ pub fn totalErrorCount(self: *Compilation) usize {
29512539 }
29522540 }
29532541
2954 return total;
2542 return @intCast(u32, total);
29552543}
29562544
29572545/// This function is temporally single-threaded.
2958pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
2959 var arena = std.heap.ArenaAllocator.init(self.gpa);
2960 errdefer arena.deinit();
2961 const arena_allocator = arena.allocator();
2546pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle {
2547 const gpa = self.gpa;
29622548
2963 var errors = std.ArrayList(AllErrors.Message).init(self.gpa);
2964 defer errors.deinit();
2549 var bundle: ErrorBundle = undefined;
2550 try bundle.init(gpa);
2551 errdefer bundle.deinit(gpa);
29652552
29662553 {
29672554 var it = self.failed_c_objects.iterator();
......@@ -2970,53 +2557,63 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
29702557 const err_msg = entry.value_ptr.*;
29712558 // TODO these fields will need to be adjusted when we have proper
29722559 // C error reporting bubbling up.
2973 try errors.append(.{
2974 .src = .{
2975 .src_path = try arena_allocator.dupe(u8, c_object.src.src_path),
2976 .msg = try std.fmt.allocPrint(arena_allocator, "unable to build C object: {s}", .{
2977 err_msg.msg,
2978 }),
2979 .span = .{ .start = 0, .end = 1, .main = 0 },
2560 try bundle.addErrorMessage(gpa, .{
2561 .msg = try bundle.printString(gpa, "unable to build C object: {s}", .{
2562 err_msg.msg,
2563 }),
2564 .src_loc = try bundle.addSourceLocation(gpa, .{
2565 .src_path = try bundle.addString(gpa, c_object.src.src_path),
2566 .span_start = 0,
2567 .span_main = 0,
2568 .span_end = 1,
29802569 .line = err_msg.line,
29812570 .column = err_msg.column,
2982 .source_line = null, // TODO
2983 },
2571 .source_line = 0, // TODO
2572 }),
29842573 });
2574 bundle.incrementCount(1);
29852575 }
29862576 }
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(.{
2996 .plain = .{
2997 .msg = try arena_allocator.dupe(u8, lld_error.msg),
2998 .notes = notes,
2999 },
2578 for (self.lld_errors.items) |lld_error| {
2579 try bundle.addErrorMessage(gpa, .{
2580 .msg = try bundle.addString(gpa, lld_error.msg),
2581 .notes_len = @intCast(u32, lld_error.context_lines.len),
30002582 });
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 }
30012590 }
30022591 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);
30042598 }
30052599 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);
30072604 }
30082605 if (self.bin_file.options.module) |module| {
30092606 {
30102607 var it = module.failed_files.iterator();
30112608 while (it.next()) |entry| {
30122609 if (entry.value_ptr.*) |msg| {
3013 try AllErrors.add(module, &arena, &errors, msg.*);
2610 try addModuleErrorMsg(gpa, &bundle, msg.*);
30142611 } else {
30152612 // Must be ZIR errors. In order for ZIR errors to exist, the parsing
30162613 // must have completed successfully.
30172614 const tree = try entry.key_ptr.*.getTree(module.gpa);
30182615 assert(tree.errors.len == 0);
3019 try AllErrors.addZir(arena_allocator, &errors, entry.key_ptr.*);
2616 try addZirErrorMessages(gpa, &bundle, entry.key_ptr.*);
30202617 }
30212618 }
30222619 }
......@@ -3024,7 +2621,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
30242621 var it = module.failed_embed_files.iterator();
30252622 while (it.next()) |entry| {
30262623 const msg = entry.value_ptr.*;
3027 try AllErrors.add(module, &arena, &errors, msg.*);
2624 try addModuleErrorMsg(gpa, &bundle, msg.*);
30282625 }
30292626 }
30302627 {
......@@ -3034,23 +2631,21 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
30342631 // Skip errors for Decls within files that had a parse failure.
30352632 // We'll try again once parsing succeeds.
30362633 if (decl.getFileScope().okToReportErrors()) {
3037 try AllErrors.add(module, &arena, &errors, entry.value_ptr.*.*);
2634 try addModuleErrorMsg(gpa, &bundle, entry.value_ptr.*.*);
30382635 if (module.cimport_errors.get(entry.key_ptr.*)) |cimport_errors| for (cimport_errors) |c_error| {
3039 if (c_error.path) |some|
3040 try errors.append(.{
3041 .src = .{
3042 .src_path = try arena_allocator.dupe(u8, std.mem.span(some)),
3043 .span = .{ .start = c_error.offset, .end = c_error.offset + 1, .main = c_error.offset },
3044 .msg = try arena_allocator.dupe(u8, std.mem.span(c_error.msg)),
3045 .line = c_error.line,
3046 .column = c_error.column,
3047 .source_line = if (c_error.source_line) |line| try arena_allocator.dupe(u8, std.mem.span(line)) else null,
3048 },
3049 })
3050 else
3051 try errors.append(.{
3052 .plain = .{ .msg = try arena_allocator.dupe(u8, std.mem.span(c_error.msg)) },
3053 });
2636 try bundle.addErrorMessage(gpa, .{
2637 .msg = try bundle.addString(gpa, std.mem.span(c_error.msg)),
2638 .src_loc = if (c_error.path) |some| try bundle.addSourceLocation(gpa, .{
2639 .src_path = try bundle.addString(gpa, std.mem.span(some)),
2640 .span_start = c_error.offset,
2641 .span_main = c_error.offset,
2642 .span_end = c_error.offset + 1,
2643 .line = c_error.line,
2644 .column = c_error.column,
2645 .source_line = if (c_error.source_line) |line| try bundle.addString(gpa, std.mem.span(line)) else 0,
2646 }) else 0,
2647 });
2648 bundle.incrementCount(1);
30542649 };
30552650 }
30562651 }
......@@ -3062,45 +2657,40 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
30622657 // Skip errors for Decls within files that had a parse failure.
30632658 // We'll try again once parsing succeeds.
30642659 if (decl.getFileScope().okToReportErrors()) {
3065 try AllErrors.add(module, &arena, &errors, entry.value_ptr.*.*);
2660 try addModuleErrorMsg(gpa, &bundle, entry.value_ptr.*.*);
30662661 }
30672662 }
30682663 }
30692664 for (module.failed_exports.values()) |value| {
3070 try AllErrors.add(module, &arena, &errors, value.*);
2665 try addModuleErrorMsg(gpa, &bundle, value.*);
30712666 }
30722667 }
30732668
3074 if (errors.items.len == 0) {
2669 if (bundle.errorMessageCount() == 0) {
30752670 if (self.link_error_flags.no_entry_point_found) {
3076 try errors.append(.{
3077 .plain = .{
3078 .msg = try std.fmt.allocPrint(arena_allocator, "no entry point found", .{}),
3079 },
2671 try bundle.addErrorMessage(gpa, .{
2672 .msg = try bundle.addString(gpa, "no entry point found"),
30802673 });
2674 bundle.incrementCount(1);
30812675 }
30822676 }
30832677
30842678 if (self.link_error_flags.missing_libc) {
3085 const notes = try arena_allocator.create([2]AllErrors.Message);
3086 notes.* = .{
3087 .{ .plain = .{
3088 .msg = try arena_allocator.dupe(u8, "run 'zig libc -h' to learn about libc installations"),
3089 } },
3090 .{ .plain = .{
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 },
2679 try bundle.addErrorMessage(gpa, .{
2680 .msg = try bundle.addString(gpa, "libc not available"),
2681 .notes_len = 2,
2682 });
2683 try bundle.addErrorMessage(gpa, .{
2684 .msg = try bundle.addString(gpa, "run 'zig libc -h' to learn about libc installations"),
30992685 });
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);
31002690 }
31012691
31022692 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) {
31042694 const keys = module.compile_log_decls.keys();
31052695 const values = module.compile_log_decls.values();
31062696 // First one will be the error; subsequent ones will be notes.
......@@ -3121,16 +2711,259 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
31212711 };
31222712 }
31232713
3124 try AllErrors.add(module, &arena, &errors, err_msg);
2714 try addModuleErrorMsg(gpa, &bundle, err_msg);
31252715 }
31262716 }
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{
3131 .list = try arena_allocator.dupe(AllErrors.Message, errors.items),
3132 .arena = arena.state,
2729 hasher.update(ctx.eb.nullTerminatedString(key.msg));
2730 if (key.src_loc != 0) {
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;
31332778 };
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);
31342967}
31352968
31362969pub fn getCompileLogOutput(self: *Compilation) []const u8 {
......@@ -5417,34 +5250,29 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca
54175250 return buffer.toOwnedSliceSentinel(0);
54185251}
54195252
5420pub fn updateSubCompilation(sub_compilation: *Compilation) !void {
5421 try sub_compilation.update();
5422
5423 // Look for compilation errors in this sub_compilation
5424 // TODO instead of logging these errors, handle them in the callsites
5425 // of updateSubCompilation and attach them as sub-errors, properly
5426 // surfacing the errors. You can see an example of this already
5427 // done inside buildOutputFromZig.
5428 var errors = try sub_compilation.getAllErrorsAlloc();
5429 defer errors.deinit(sub_compilation.gpa);
5430
5431 if (errors.list.len != 0) {
5432 for (errors.list) |full_err_msg| {
5433 switch (full_err_msg) {
5434 .src => |src| {
5435 log.err("{s}:{d}:{d}: {s}", .{
5436 src.src_path,
5437 src.line + 1,
5438 src.column + 1,
5439 src.msg,
5440 });
5441 },
5442 .plain => |plain| {
5443 log.err("{s}", .{plain.msg});
5444 },
5445 }
5446 }
5447 return error.BuildingLibCObjectFailed;
5253pub fn updateSubCompilation(
5254 parent_comp: *Compilation,
5255 sub_comp: *Compilation,
5256 misc_task: MiscTask,
5257) !void {
5258 try sub_comp.update();
5259
5260 // Look for compilation errors in this sub compilation
5261 const gpa = parent_comp.gpa;
5262 var keep_errors = false;
5263 var errors = try sub_comp.getAllErrorsAlloc();
5264 defer if (!keep_errors) errors.deinit(gpa);
5265
5266 if (errors.errorMessageCount() > 0) {
5267 try parent_comp.misc_failures.ensureUnusedCapacity(gpa, 1);
5268 parent_comp.misc_failures.putAssumeCapacityNoClobber(misc_task, .{
5269 .msg = try std.fmt.allocPrint(gpa, "sub-compilation of {s} failed", .{
5270 @tagName(misc_task),
5271 }),
5272 .children = errors,
5273 });
5274 keep_errors = true;
5275 return error.SubCompilationFailed;
54485276 }
54495277}
54505278
......@@ -5520,23 +5348,7 @@ fn buildOutputFromZig(
55205348 });
55215349 defer sub_compilation.destroy();
55225350
5523 try sub_compilation.update();
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 }
5351 try comp.updateSubCompilation(sub_compilation, misc_task_tag);
55405352
55415353 assert(out.* == null);
55425354 out.* = Compilation.CRTFile{
......@@ -5551,6 +5363,7 @@ pub fn build_crt_file(
55515363 comp: *Compilation,
55525364 root_name: []const u8,
55535365 output_mode: std.builtin.OutputMode,
5366 misc_task_tag: MiscTask,
55545367 c_source_files: []const Compilation.CSourceFile,
55555368) !void {
55565369 const tracy_trace = trace(@src());
......@@ -5611,7 +5424,7 @@ pub fn build_crt_file(
56115424 });
56125425 defer sub_compilation.destroy();
56135426
5614 try sub_compilation.updateSubCompilation();
5427 try comp.updateSubCompilation(sub_compilation, misc_task_tag);
56155428
56165429 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 {
37563756 file.source_loaded = true;
37573757
37583758 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 }
38183759 file.tree_loaded = true;
38193760
3761 // Any potential AST errors are converted to ZIR errors here.
38203762 file.zir = try AstGen.generate(gpa, file.tree);
38213763 file.zir_loaded = true;
38223764 file.status = .success_zir;
src/Package.zig+53-55
......@@ -225,7 +225,7 @@ pub fn fetchAndAddDependencies(
225225 dependencies_source: *std.ArrayList(u8),
226226 build_roots_source: *std.ArrayList(u8),
227227 name_prefix: []const u8,
228 color: main.Color,
228 error_bundle: *std.zig.ErrorBundle,
229229 all_modules: *AllModules,
230230) !void {
231231 const max_bytes = 10 * 1024 * 1024;
......@@ -250,7 +250,7 @@ pub fn fetchAndAddDependencies(
250250
251251 if (ast.errors.len > 0) {
252252 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);
254254 return error.PackageFetchFailed;
255255 }
256256
......@@ -258,23 +258,18 @@ pub fn fetchAndAddDependencies(
258258 defer manifest.deinit(gpa);
259259
260260 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 };
266261 const file_path = try directory.join(arena, &.{Manifest.basename});
267262 for (manifest.errors) |msg| {
268 Report.renderErrorMessage(ast, file_path, ttyconf, msg, &.{});
263 try Report.addErrorMessage(gpa, ast, file_path, error_bundle, 0, msg);
269264 }
270265 return error.PackageFetchFailed;
271266 }
272267
273268 const report: Report = .{
269 .gpa = gpa,
274270 .ast = &ast,
275271 .directory = directory,
276 .color = color,
277 .arena = arena,
272 .error_bundle = error_bundle,
278273 };
279274
280275 var any_error = false;
......@@ -307,7 +302,7 @@ pub fn fetchAndAddDependencies(
307302 dependencies_source,
308303 build_roots_source,
309304 sub_prefix,
310 color,
305 error_bundle,
311306 all_modules,
312307 );
313308
......@@ -348,10 +343,10 @@ pub fn createFilePkg(
348343}
349344
350345const Report = struct {
346 gpa: Allocator,
351347 ast: *const std.zig.Ast,
352348 directory: Compilation.Directory,
353 color: main.Color,
354 arena: Allocator,
349 error_bundle: *std.zig.ErrorBundle,
355350
356351 fn fail(
357352 report: Report,
......@@ -359,52 +354,48 @@ const Report = struct {
359354 comptime fmt_string: []const u8,
360355 fmt_args: anytype,
361356 ) error{ PackageFetchFailed, OutOfMemory } {
362 return failWithNotes(report, &.{}, tok, fmt_string, fmt_args);
363 }
357 const gpa = report.gpa;
364358
365 fn failWithNotes(
366 report: Report,
367 notes: []const Compilation.AllErrors.Message,
368 tok: std.zig.Ast.TokenIndex,
369 comptime fmt_string: []const u8,
370 fmt_args: anytype,
371 ) error{ PackageFetchFailed, OutOfMemory } {
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, .{
359 const file_path = try report.directory.join(gpa, &.{Manifest.basename});
360 defer gpa.free(file_path);
361
362 const msg = try std.fmt.allocPrint(gpa, fmt_string, fmt_args);
363 defer gpa.free(msg);
364
365 try addErrorMessage(report.gpa, report.ast.*, file_path, report.error_bundle, 0, .{
379366 .tok = tok,
380367 .off = 0,
381 .msg = try std.fmt.allocPrint(report.arena, fmt_string, fmt_args),
382 }, notes);
368 .msg = msg,
369 });
370
383371 return error.PackageFetchFailed;
384372 }
385373
386 fn renderErrorMessage(
374 fn addErrorMessage(
375 gpa: Allocator,
387376 ast: std.zig.Ast,
388377 file_path: []const u8,
389 ttyconf: std.debug.TTY.Config,
378 eb: *std.zig.ErrorBundle,
379 notes_len: u32,
390380 msg: Manifest.ErrorMessage,
391 notes: []const Compilation.AllErrors.Message,
392 ) void {
381 ) error{OutOfMemory}!void {
393382 const token_starts = ast.tokens.items(.start);
394383 const start_loc = ast.tokenLocation(0, msg.tok);
395 Compilation.AllErrors.Message.renderToStdErr(.{ .src = .{
396 .msg = msg.msg,
397 .src_path = file_path,
398 .line = @intCast(u32, start_loc.line),
399 .column = @intCast(u32, start_loc.column),
400 .span = .{
401 .start = token_starts[msg.tok],
402 .end = @intCast(u32, token_starts[msg.tok] + ast.tokenSlice(msg.tok).len),
403 .main = token_starts[msg.tok] + msg.off,
404 },
405 .source_line = ast.source[start_loc.line_start..start_loc.line_end],
406 .notes = notes,
407 } }, ttyconf);
384
385 try eb.addErrorMessage(gpa, .{
386 .msg = try eb.addString(gpa, msg.msg),
387 .src_loc = try eb.addSourceLocation(gpa, .{
388 .src_path = try eb.addString(gpa, file_path),
389 .span_start = token_starts[msg.tok],
390 .span_end = @intCast(u32, token_starts[msg.tok] + ast.tokenSlice(msg.tok).len),
391 .span_main = token_starts[msg.tok] + msg.off,
392 .line = @intCast(u32, start_loc.line),
393 .column = @intCast(u32, start_loc.column),
394 .source_line = try eb.addString(gpa, ast.source[start_loc.line_start..start_loc.line_end]),
395 }),
396 .notes_len = notes_len,
397 });
398 eb.incrementCount(1);
408399 }
409400};
410401
......@@ -504,9 +495,7 @@ fn fetchAndUnpack(
504495 // by default, so the same logic applies for buffering the reader as for gzip.
505496 try unpackTarball(gpa, &req, tmp_directory.handle, std.compress.xz);
506497 } else {
507 return report.fail(dep.url_tok, "unknown file extension for path '{s}'", .{
508 uri.path,
509 });
498 return report.fail(dep.url_tok, "unknown file extension for path '{s}'", .{uri.path});
510499 }
511500
512501 // TODO: delete files not included in the package prior to computing the package hash.
......@@ -533,10 +522,19 @@ fn fetchAndUnpack(
533522 });
534523 }
535524 } else {
536 const notes: [1]Compilation.AllErrors.Message = .{.{ .plain = .{
537 .msg = try std.fmt.allocPrint(report.arena, "expected .hash = \"{s}\",", .{&actual_hex}),
538 } }};
539 return report.failWithNotes(&notes, dep.url_tok, "url field is missing corresponding hash field", .{});
525 const file_path = try report.directory.join(gpa, &.{Manifest.basename});
526 defer gpa.free(file_path);
527
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;
540538 }
541539
542540 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(
22112211
22122212fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError {
22132213 @setCold(true);
2214 const gpa = sema.gpa;
22142215
22152216 if (crash_report.is_enabled and sema.mod.comp.debug_compile_errors) {
22162217 if (err_msg.src_loc.lazy == .unneeded) return error.NeededSourceLocation;
2217 var arena = std.heap.ArenaAllocator.init(sema.gpa);
2218 errdefer arena.deinit();
2219 var errors = std.ArrayList(Compilation.AllErrors.Message).init(sema.gpa);
2220 defer errors.deinit();
2221
2222 Compilation.AllErrors.add(sema.mod, &arena, &errors, err_msg.*) catch unreachable;
2223
2218 var errors: std.zig.ErrorBundle = undefined;
2219 errors.init(gpa) catch unreachable;
2220 Compilation.addModuleErrorMsg(gpa, &errors, err_msg.*) catch unreachable;
22242221 std.debug.print("compile error during Sema:\n", .{});
2225 Compilation.AllErrors.Message.renderToStdErr(errors.items[0], .no_color);
2222 errors.renderToStdErr(.no_color);
22262223 crash_report.compilerPanic("unexpected compile error occurred", null, null);
22272224 }
22282225
22292226 const mod = sema.mod;
22302227 ref: {
2231 errdefer err_msg.destroy(mod.gpa);
2228 errdefer err_msg.destroy(gpa);
22322229 if (err_msg.src_loc.lazy == .unneeded) {
22332230 return error.NeededSourceLocation;
22342231 }
2235 try mod.failed_decls.ensureUnusedCapacity(mod.gpa, 1);
2236 try mod.failed_files.ensureUnusedCapacity(mod.gpa, 1);
2232 try mod.failed_decls.ensureUnusedCapacity(gpa, 1);
2233 try mod.failed_files.ensureUnusedCapacity(gpa, 1);
22372234
22382235 const max_references = blk: {
22392236 if (sema.mod.comp.reference_trace) |num| break :blk num;
......@@ -2243,11 +2240,11 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError {
22432240 };
22442241
22452242 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);
22472244 defer reference_stack.deinit();
22482245
22492246 // 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);
22512248 defer seen.deinit();
22522249
22532250 var cur_reference_trace: u32 = 0;
......@@ -2288,7 +2285,7 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError {
22882285 if (gop.found_existing) {
22892286 // If there are multiple errors for the same Decl, prefer the first one added.
22902287 sema.err = null;
2291 err_msg.destroy(mod.gpa);
2288 err_msg.destroy(gpa);
22922289 } else {
22932290 sema.err = err_msg;
22942291 gop.value_ptr.* = err_msg;
src/glibc.zig+5-5
......@@ -196,7 +196,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
196196 "-DASSEMBLER",
197197 "-Wa,--noexecstack",
198198 });
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{
200200 .{
201201 .src_path = try start_asm_path(comp, arena, "crti.S"),
202202 .cache_exempt_flags = args.items,
......@@ -215,7 +215,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
215215 "-DASSEMBLER",
216216 "-Wa,--noexecstack",
217217 });
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{
219219 .{
220220 .src_path = try start_asm_path(comp, arena, "crtn.S"),
221221 .cache_exempt_flags = args.items,
......@@ -265,7 +265,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
265265 .cache_exempt_flags = args.items,
266266 };
267267 };
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 });
269269 },
270270 .libc_nonshared_a => {
271271 const s = path.sep_str;
......@@ -366,7 +366,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
366366 files_index += 1;
367367 }
368368 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);
370370 },
371371 }
372372}
......@@ -1105,7 +1105,7 @@ fn buildSharedLib(
11051105 });
11061106 defer sub_compilation.destroy();
11071107
1108 try sub_compilation.updateSubCompilation();
1108 try comp.updateSubCompilation(sub_compilation, .@"glibc shared object");
11091109}
11101110
11111111// 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 {
258258 });
259259 defer sub_compilation.destroy();
260260
261 try sub_compilation.updateSubCompilation();
261 try comp.updateSubCompilation(sub_compilation, .libcxx);
262262
263263 assert(comp.libcxx_static_lib == null);
264264 comp.libcxx_static_lib = Compilation.CRTFile{
......@@ -418,7 +418,7 @@ pub fn buildLibCXXABI(comp: *Compilation) !void {
418418 });
419419 defer sub_compilation.destroy();
420420
421 try sub_compilation.updateSubCompilation();
421 try comp.updateSubCompilation(sub_compilation, .libcxxabi);
422422
423423 assert(comp.libcxxabi_static_lib == null);
424424 comp.libcxxabi_static_lib = Compilation.CRTFile{
src/libtsan.zig+1-1
......@@ -235,7 +235,7 @@ pub fn buildTsan(comp: *Compilation) !void {
235235 });
236236 defer sub_compilation.destroy();
237237
238 try sub_compilation.updateSubCompilation();
238 try comp.updateSubCompilation(sub_compilation, .libtsan);
239239
240240 assert(comp.tsan_static_lib == null);
241241 comp.tsan_static_lib = Compilation.CRTFile{
src/libunwind.zig+1-1
......@@ -130,7 +130,7 @@ pub fn buildStaticLib(comp: *Compilation) !void {
130130 });
131131 defer sub_compilation.destroy();
132132
133 try sub_compilation.updateSubCompilation();
133 try comp.updateSubCompilation(sub_compilation, .libunwind);
134134
135135 assert(comp.libunwind_static_lib == null);
136136
src/main.zig+104-159
......@@ -24,6 +24,8 @@ const clang = @import("clang.zig");
2424const Cache = std.Build.Cache;
2525const target_util = @import("target.zig");
2626const crash_report = @import("crash_report.zig");
27const Module = @import("Module.zig");
28const AstGen = @import("AstGen.zig");
2729
2830pub const std_options = struct {
2931 pub const wasiCwd = wasi_cwd;
......@@ -3446,15 +3448,13 @@ fn buildOutputType(
34463448 var errors = try comp.getAllErrorsAlloc();
34473449 defer errors.deinit(comp.gpa);
34483450
3449 if (errors.list.len != 0) {
3451 if (errors.errorMessageCount() > 0) {
34503452 const ttyconf: std.debug.TTY.Config = switch (comp.color) {
34513453 .auto => std.debug.detectTTYConfig(std.io.getStdErr()),
34523454 .on => .escape_codes,
34533455 .off => .no_color,
34543456 };
3455 for (errors.list) |full_err_msg| {
3456 try full_err_msg.renderToWriter(ttyconf, conn.stream.writer(), "error:", .Red, 0);
3457 }
3457 try errors.renderToWriter(ttyconf, conn.stream.writer());
34583458 continue;
34593459 }
34603460 } else {
......@@ -3830,15 +3830,13 @@ fn updateModule(gpa: Allocator, comp: *Compilation, hook: AfterUpdateHook) !void
38303830 var errors = try comp.getAllErrorsAlloc();
38313831 defer errors.deinit(comp.gpa);
38323832
3833 if (errors.list.len != 0) {
3833 if (errors.errorMessageCount() > 0) {
38343834 const ttyconf: std.debug.TTY.Config = switch (comp.color) {
38353835 .auto => std.debug.detectTTYConfig(std.io.getStdErr()),
38363836 .on => .escape_codes,
38373837 .off => .no_color,
38383838 };
3839 for (errors.list) |full_err_msg| {
3840 full_err_msg.renderToStdErr(ttyconf);
3841 }
3839 errors.renderToStdErr(ttyconf);
38423840 const log_text = comp.getCompileLogOutput();
38433841 if (log_text.len != 0) {
38443842 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
44384436 var all_modules: Package.AllModules = .{};
44394437 defer all_modules.deinit(gpa);
44404438
4439 var errors: std.zig.ErrorBundle = undefined;
4440 try errors.init(gpa);
4441 defer errors.deinit(gpa);
4442
44414443 // Here we borrow main package's table and will replace it with a fresh
44424444 // one after this process completes.
4443 build_pkg.fetchAndAddDependencies(
4445 const fetch_result = build_pkg.fetchAndAddDependencies(
44444446 &main_pkg,
44454447 arena,
44464448 &thread_pool,
......@@ -4451,12 +4453,19 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
44514453 &dependencies_source,
44524454 &build_roots_source,
44534455 "",
4454 color,
4456 &errors,
44554457 &all_modules,
4456 ) catch |err| switch (err) {
4457 error.PackageFetchFailed => process.exit(1),
4458 else => |e| return e,
4459 };
4458 );
4459 if (errors.errorMessageCount() > 0) {
4460 const ttyconf: std.debug.TTY.Config = switch (color) {
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
44614470 try dependencies_source.appendSlice("};\npub const build_root = struct {\n");
44624471 try dependencies_source.appendSlice(build_roots_source.items);
......@@ -4543,7 +4552,7 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
45434552}
45444553
45454554fn readSourceFileToEndAlloc(
4546 allocator: mem.Allocator,
4555 allocator: Allocator,
45474556 input: *const fs.File,
45484557 size_hint: ?usize,
45494558) ![:0]u8 {
......@@ -4687,12 +4696,9 @@ pub fn cmdFmt(gpa: Allocator, arena: Allocator, args: []const []const u8) !void
46874696 };
46884697 defer tree.deinit(gpa);
46894698
4690 try printErrsMsgToStdErr(gpa, arena, tree, "<stdin>", color);
4699 try printAstErrorsToStderr(gpa, tree, "<stdin>", color);
46914700 var has_ast_error = false;
46924701 if (check_ast_flag) {
4693 const Module = @import("Module.zig");
4694 const AstGen = @import("AstGen.zig");
4695
46964702 var file: Module.File = .{
46974703 .status = .never_loaded,
46984704 .source_loaded = true,
......@@ -4715,20 +4721,16 @@ pub fn cmdFmt(gpa: Allocator, arena: Allocator, args: []const []const u8) !void
47154721 defer file.zir.deinit(gpa);
47164722
47174723 if (file.zir.hasCompileErrors()) {
4718 var arena_instance = std.heap.ArenaAllocator.init(gpa);
4719 defer arena_instance.deinit();
4720 var errors = std.ArrayList(Compilation.AllErrors.Message).init(gpa);
4721 defer errors.deinit();
4722
4723 try Compilation.AllErrors.addZir(arena_instance.allocator(), &errors, &file);
4724 var errors: std.zig.ErrorBundle = undefined;
4725 try errors.init(gpa);
4726 defer errors.deinit(gpa);
4727 try Compilation.addZirErrorMessages(gpa, &errors, &file);
47244728 const ttyconf: std.debug.TTY.Config = switch (color) {
47254729 .auto => std.debug.detectTTYConfig(std.io.getStdErr()),
47264730 .on => .escape_codes,
47274731 .off => .no_color,
47284732 };
4729 for (errors.items) |full_err_msg| {
4730 full_err_msg.renderToStdErr(ttyconf);
4731 }
4733 errors.renderToStdErr(ttyconf);
47324734 has_ast_error = true;
47334735 }
47344736 }
......@@ -4875,12 +4877,13 @@ fn fmtPathFile(
48754877 if (stat.kind == .Directory)
48764878 return error.IsDir;
48774879
4880 const gpa = fmt.gpa;
48784881 const source_code = try readSourceFileToEndAlloc(
4879 fmt.gpa,
4882 gpa,
48804883 &source_file,
48814884 std.math.cast(usize, stat.size) orelse return error.FileTooBig,
48824885 );
4883 defer fmt.gpa.free(source_code);
4886 defer gpa.free(source_code);
48844887
48854888 source_file.close();
48864889 file_closed = true;
......@@ -4888,19 +4891,16 @@ fn fmtPathFile(
48884891 // Add to set after no longer possible to get error.IsDir.
48894892 if (try fmt.seen.fetchPut(stat.inode, {})) |_| return;
48904893
4891 var tree = try Ast.parse(fmt.gpa, source_code, .zig);
4892 defer tree.deinit(fmt.gpa);
4894 var tree = try Ast.parse(gpa, source_code, .zig);
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);
48954898 if (tree.errors.len != 0) {
48964899 fmt.any_error = true;
48974900 return;
48984901 }
48994902
49004903 if (fmt.check_ast) {
4901 const Module = @import("Module.zig");
4902 const AstGen = @import("AstGen.zig");
4903
49044904 var file: Module.File = .{
49054905 .status = .never_loaded,
49064906 .source_loaded = true,
......@@ -4919,31 +4919,27 @@ fn fmtPathFile(
49194919 .root_decl = .none,
49204920 };
49214921
4922 file.pkg = try Package.create(fmt.gpa, null, file.sub_file_path);
4923 defer file.pkg.destroy(fmt.gpa);
4922 file.pkg = try Package.create(gpa, null, file.sub_file_path);
4923 defer file.pkg.destroy(gpa);
49244924
49254925 if (stat.size > max_src_size)
49264926 return error.FileTooBig;
49274927
4928 file.zir = try AstGen.generate(fmt.gpa, file.tree);
4928 file.zir = try AstGen.generate(gpa, file.tree);
49294929 file.zir_loaded = true;
4930 defer file.zir.deinit(fmt.gpa);
4930 defer file.zir.deinit(gpa);
49314931
49324932 if (file.zir.hasCompileErrors()) {
4933 var arena_instance = std.heap.ArenaAllocator.init(fmt.gpa);
4934 defer arena_instance.deinit();
4935 var errors = std.ArrayList(Compilation.AllErrors.Message).init(fmt.gpa);
4936 defer errors.deinit();
4937
4938 try Compilation.AllErrors.addZir(arena_instance.allocator(), &errors, &file);
4933 var errors: std.zig.ErrorBundle = undefined;
4934 try errors.init(gpa);
4935 defer errors.deinit(gpa);
4936 try Compilation.addZirErrorMessages(gpa, &errors, &file);
49394937 const ttyconf: std.debug.TTY.Config = switch (fmt.color) {
49404938 .auto => std.debug.detectTTYConfig(std.io.getStdErr()),
49414939 .on => .escape_codes,
49424940 .off => .no_color,
49434941 };
4944 for (errors.items) |full_err_msg| {
4945 full_err_msg.renderToStdErr(ttyconf);
4946 }
4942 errors.renderToStdErr(ttyconf);
49474943 fmt.any_error = true;
49484944 }
49494945 }
......@@ -4971,100 +4967,53 @@ fn fmtPathFile(
49714967 }
49724968}
49734969
4974pub fn printErrsMsgToStdErr(
4975 gpa: mem.Allocator,
4976 arena: mem.Allocator,
4970fn printAstErrorsToStderr(gpa: Allocator, tree: Ast, path: []const u8, color: Color) !void {
4971 var error_bundle: std.zig.ErrorBundle = undefined;
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,
49774987 tree: Ast,
49784988 path: []const u8,
4979 color: Color,
4989 error_bundle: *std.zig.ErrorBundle,
49804990) !void {
4981 const parse_errors: []const Ast.Error = tree.errors;
4982 var i: usize = 0;
4983 while (i < parse_errors.len) : (i += 1) {
4984 const parse_error = parse_errors[i];
4985 const lok_token = parse_error.token;
4986 const token_tags = tree.tokens.items(.tag);
4987 const start_loc = tree.tokenLocation(0, lok_token);
4988 const source_line = tree.source[start_loc.line_start..start_loc.line_end];
4989
4990 var text_buf = std.ArrayList(u8).init(gpa);
4991 defer text_buf.deinit();
4992 const writer = text_buf.writer();
4993 try tree.renderError(parse_error, writer);
4994 const text = try arena.dupe(u8, text_buf.items);
4995
4996 var notes_buffer: [2]Compilation.AllErrors.Message = undefined;
4997 var notes_len: usize = 0;
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 }
4991 var file: Module.File = .{
4992 .status = .never_loaded,
4993 .source_loaded = true,
4994 .zir_loaded = false,
4995 .sub_file_path = path,
4996 .source = tree.source,
4997 .stat = .{
4998 .size = 0,
4999 .inode = 0,
5000 .mtime = 0,
5001 },
5002 .tree = tree,
5003 .tree_loaded = true,
5004 .zir = undefined,
5005 .pkg = undefined,
5006 .root_decl = .none,
5007 };
50415008
5042 const extra_offset = tree.errorOffset(parse_error);
5043 const byte_offset = @intCast(u32, start_loc.line_start) + extra_offset;
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 };
5009 file.pkg = try Package.create(gpa, null, path);
5010 defer file.pkg.destroy(gpa);
50595011
5060 const ttyconf: std.debug.TTY.Config = switch (color) {
5061 .auto => std.debug.detectTTYConfig(std.io.getStdErr()),
5062 .on => .escape_codes,
5063 .off => .no_color,
5064 };
5012 file.zir = try AstGen.generate(gpa, file.tree);
5013 file.zir_loaded = true;
5014 defer file.zir.deinit(gpa);
50655015
5066 message.renderToStdErr(ttyconf);
5067 }
5016 try Compilation.addZirErrorMessages(gpa, error_bundle, &file);
50685017}
50695018
50705019pub const info_zen =
......@@ -5547,8 +5496,6 @@ pub fn cmdAstCheck(
55475496 arena: Allocator,
55485497 args: []const []const u8,
55495498) !void {
5550 const Module = @import("Module.zig");
5551 const AstGen = @import("AstGen.zig");
55525499 const Zir = @import("Zir.zig");
55535500
55545501 var color: Color = .auto;
......@@ -5638,7 +5585,7 @@ pub fn cmdAstCheck(
56385585 file.tree_loaded = true;
56395586 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);
56425589 if (file.tree.errors.len != 0) {
56435590 process.exit(1);
56445591 }
......@@ -5648,16 +5595,16 @@ pub fn cmdAstCheck(
56485595 defer file.zir.deinit(gpa);
56495596
56505597 if (file.zir.hasCompileErrors()) {
5651 var errors = std.ArrayList(Compilation.AllErrors.Message).init(arena);
5652 try Compilation.AllErrors.addZir(arena, &errors, &file);
5598 var errors: std.zig.ErrorBundle = undefined;
5599 try errors.init(gpa);
5600 defer errors.deinit(gpa);
5601 try Compilation.addZirErrorMessages(gpa, &errors, &file);
56535602 const ttyconf: std.debug.TTY.Config = switch (color) {
56545603 .auto => std.debug.detectTTYConfig(std.io.getStdErr()),
56555604 .on => .escape_codes,
56565605 .off => .no_color,
56575606 };
5658 for (errors.items) |full_err_msg| {
5659 full_err_msg.renderToStdErr(ttyconf);
5660 }
5607 errors.renderToStdErr(ttyconf);
56615608 process.exit(1);
56625609 }
56635610
......@@ -5715,8 +5662,6 @@ pub fn cmdChangelist(
57155662 arena: Allocator,
57165663 args: []const []const u8,
57175664) !void {
5718 const Module = @import("Module.zig");
5719 const AstGen = @import("AstGen.zig");
57205665 const Zir = @import("Zir.zig");
57215666
57225667 const old_source_file = args[0];
......@@ -5764,7 +5709,7 @@ pub fn cmdChangelist(
57645709 file.tree_loaded = true;
57655710 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);
57685713 if (file.tree.errors.len != 0) {
57695714 process.exit(1);
57705715 }
......@@ -5774,12 +5719,12 @@ pub fn cmdChangelist(
57745719 defer file.zir.deinit(gpa);
57755720
57765721 if (file.zir.hasCompileErrors()) {
5777 var errors = std.ArrayList(Compilation.AllErrors.Message).init(arena);
5778 try Compilation.AllErrors.addZir(arena, &errors, &file);
5722 var errors: std.zig.ErrorBundle = undefined;
5723 try errors.init(gpa);
5724 defer errors.deinit(gpa);
5725 try Compilation.addZirErrorMessages(gpa, &errors, &file);
57795726 const ttyconf = std.debug.detectTTYConfig(std.io.getStdErr());
5780 for (errors.items) |full_err_msg| {
5781 full_err_msg.renderToStdErr(ttyconf);
5782 }
5727 errors.renderToStdErr(ttyconf);
57835728 process.exit(1);
57845729 }
57855730
......@@ -5801,7 +5746,7 @@ pub fn cmdChangelist(
58015746 var new_tree = try Ast.parse(gpa, new_source, .zig);
58025747 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);
58055750 if (new_tree.errors.len != 0) {
58065751 process.exit(1);
58075752 }
......@@ -5813,12 +5758,12 @@ pub fn cmdChangelist(
58135758 file.zir_loaded = true;
58145759
58155760 if (file.zir.hasCompileErrors()) {
5816 var errors = std.ArrayList(Compilation.AllErrors.Message).init(arena);
5817 try Compilation.AllErrors.addZir(arena, &errors, &file);
5761 var errors: std.zig.ErrorBundle = undefined;
5762 try errors.init(gpa);
5763 defer errors.deinit(gpa);
5764 try Compilation.addZirErrorMessages(gpa, &errors, &file);
58185765 const ttyconf = std.debug.detectTTYConfig(std.io.getStdErr());
5819 for (errors.items) |full_err_msg| {
5820 full_err_msg.renderToStdErr(ttyconf);
5821 }
5766 errors.renderToStdErr(ttyconf);
58225767 process.exit(1);
58235768 }
58245769
src/mingw.zig+6-6
......@@ -41,7 +41,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
4141 //"-D_UNICODE",
4242 //"-DWPRFLAG=1",
4343 });
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{
4545 .{
4646 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
4747 "libc", "mingw", "crt", "crtexe.c",
......@@ -60,7 +60,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
6060 "-U__CRTDLL__",
6161 "-D__MSVCRT__",
6262 });
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{
6464 .{
6565 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
6666 "libc", "mingw", "crt", "crtdll.c",
......@@ -100,7 +100,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
100100 .extra_flags = args.items,
101101 };
102102 }
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);
104104 },
105105
106106 .msvcrt_os_lib => {
......@@ -148,7 +148,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
148148 };
149149 }
150150 }
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);
152152 },
153153
154154 .mingwex_lib => {
......@@ -211,7 +211,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
211211 } else {
212212 @panic("unsupported arch");
213213 }
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);
215215 },
216216
217217 .uuid_lib => {
......@@ -244,7 +244,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
244244 .extra_flags = extra_flags,
245245 };
246246 }
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);
248248 },
249249 }
250250}
src/musl.zig+7-7
......@@ -33,7 +33,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
3333 try args.appendSlice(&[_][]const u8{
3434 "-Qunused-arguments",
3535 });
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{
3737 .{
3838 .src_path = try start_asm_path(comp, arena, "crti.s"),
3939 .extra_flags = args.items,
......@@ -46,7 +46,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
4646 try args.appendSlice(&[_][]const u8{
4747 "-Qunused-arguments",
4848 });
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{
5050 .{
5151 .src_path = try start_asm_path(comp, arena, "crtn.s"),
5252 .extra_flags = args.items,
......@@ -60,7 +60,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
6060 "-fno-stack-protector",
6161 "-DCRT",
6262 });
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{
6464 .{
6565 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
6666 "libc", "musl", "crt", "crt1.c",
......@@ -77,7 +77,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
7777 "-fno-stack-protector",
7878 "-DCRT",
7979 });
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{
8181 .{
8282 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
8383 "libc", "musl", "crt", "rcrt1.c",
......@@ -94,7 +94,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
9494 "-fno-stack-protector",
9595 "-DCRT",
9696 });
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{
9898 .{
9999 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
100100 "libc", "musl", "crt", "Scrt1.c",
......@@ -187,7 +187,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
187187 .extra_flags = args.items,
188188 };
189189 }
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);
191191 },
192192 .libc_so => {
193193 const target = comp.getTarget();
......@@ -241,7 +241,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
241241 });
242242 defer sub_compilation.destroy();
243243
244 try sub_compilation.updateSubCompilation();
244 try comp.updateSubCompilation(sub_compilation, .@"musl libc.so");
245245
246246 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 {
7474 var args = std.ArrayList([]const u8).init(arena);
7575 try addCCArgs(comp, arena, &args, false);
7676 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{
7878 .{
7979 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
8080 "libc", try sanitize(arena, crt1_reactor_src_file),
......@@ -87,7 +87,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
8787 var args = std.ArrayList([]const u8).init(arena);
8888 try addCCArgs(comp, arena, &args, false);
8989 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{
9191 .{
9292 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
9393 "libc", try sanitize(arena, crt1_command_src_file),
......@@ -145,7 +145,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
145145 }
146146 }
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);
149149 },
150150 .libwasi_emulated_process_clocks_a => {
151151 var args = std.ArrayList([]const u8).init(arena);
......@@ -161,7 +161,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
161161 .extra_flags = args.items,
162162 });
163163 }
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);
165165 },
166166 .libwasi_emulated_getpid_a => {
167167 var args = std.ArrayList([]const u8).init(arena);
......@@ -177,7 +177,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
177177 .extra_flags = args.items,
178178 });
179179 }
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);
181181 },
182182 .libwasi_emulated_mman_a => {
183183 var args = std.ArrayList([]const u8).init(arena);
......@@ -193,7 +193,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
193193 .extra_flags = args.items,
194194 });
195195 }
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);
197197 },
198198 .libwasi_emulated_signal_a => {
199199 var emu_signal_sources = std.ArrayList(Compilation.CSourceFile).init(arena);
......@@ -228,7 +228,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
228228 }
229229 }
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);
232232 },
233233 }
234234}