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.
This commit is contained in:
Andrew Kelley 2023-02-23 16:18:43 -07:00
parent 4db5bc7b21
commit 572cb24d1a
15 changed files with 1068 additions and 909 deletions

View File

@ -3,6 +3,7 @@ const tokenizer = @import("zig/tokenizer.zig");
const fmt = @import("zig/fmt.zig");
const assert = std.debug.assert;
pub const ErrorBundle = @import("zig/ErrorBundle.zig");
pub const Token = tokenizer.Token;
pub const Tokenizer = tokenizer.Tokenizer;
pub const fmtId = fmt.fmtId;

419
lib/std/zig/ErrorBundle.zig Normal file
View File

@ -0,0 +1,419 @@
//! To support incremental compilation, errors are stored in various places
//! so that they can be created and destroyed appropriately. This structure
//! is used to collect all the errors from the various places into one
//! convenient place for API users to consume.
string_bytes: std.ArrayListUnmanaged(u8),
/// The first thing in this array is a ErrorMessageListIndex.
extra: std.ArrayListUnmanaged(u32),
// An index into `extra` pointing at an `ErrorMessage`.
pub const MessageIndex = enum(u32) {
_,
};
/// After the header is:
/// * string_bytes
/// * extra (little endian)
pub const Header = struct {
string_bytes_len: u32,
extra_len: u32,
};
/// Trailing: ErrorMessage for each len
pub const ErrorMessageList = struct {
len: u32,
start: u32,
};
/// Trailing:
/// * ReferenceTrace for each reference_trace_len
pub const SourceLocation = struct {
/// null terminated string index
src_path: u32,
line: u32,
column: u32,
/// byte offset of starting token
span_start: u32,
/// byte offset of main error location
span_main: u32,
/// byte offset of end of last token
span_end: u32,
/// null terminated string index, possibly null.
/// Does not include the trailing newline.
source_line: u32 = 0,
reference_trace_len: u32 = 0,
};
/// Trailing:
/// * ErrorMessage for each notes_len.
pub const ErrorMessage = struct {
/// null terminated string index
msg: u32,
/// Usually one, but incremented for redundant messages.
count: u32 = 1,
/// 0 or the index into extra of a SourceLocation
src_loc: u32 = 0,
notes_len: u32 = 0,
};
pub const ReferenceTrace = struct {
/// null terminated string index
/// Except for the sentinel ReferenceTrace element, in which case:
/// * 0 means remaining references hidden
/// * >0 means N references hidden
decl_name: u32,
/// Index into extra of a SourceLocation
/// If this is 0, this is the sentinel ReferenceTrace element.
src_loc: u32,
};
pub fn init(eb: *ErrorBundle, gpa: Allocator) !void {
eb.* = .{
.string_bytes = .{},
.extra = .{},
};
// So that 0 can be used to indicate a null string.
try eb.string_bytes.append(gpa, 0);
_ = try addExtra(eb, gpa, ErrorMessageList{
.len = 0,
.start = 0,
});
}
pub fn deinit(eb: *ErrorBundle, gpa: Allocator) void {
eb.string_bytes.deinit(gpa);
eb.extra.deinit(gpa);
eb.* = undefined;
}
pub fn addString(eb: *ErrorBundle, gpa: Allocator, s: []const u8) !u32 {
const index = @intCast(u32, eb.string_bytes.items.len);
try eb.string_bytes.ensureUnusedCapacity(gpa, s.len + 1);
eb.string_bytes.appendSliceAssumeCapacity(s);
eb.string_bytes.appendAssumeCapacity(0);
return index;
}
pub fn printString(eb: *ErrorBundle, gpa: Allocator, comptime fmt: []const u8, args: anytype) !u32 {
const index = @intCast(u32, eb.string_bytes.items.len);
try eb.string_bytes.writer(gpa).print(fmt, args);
try eb.string_bytes.append(gpa, 0);
return index;
}
pub fn addErrorMessage(eb: *ErrorBundle, gpa: Allocator, em: ErrorMessage) !void {
if (eb.errorMessageCount() == 0) {
eb.setStartIndex(@intCast(u32, eb.extra.items.len));
}
_ = try addExtra(eb, gpa, em);
}
pub fn addSourceLocation(eb: *ErrorBundle, gpa: Allocator, sl: SourceLocation) !u32 {
return addExtra(eb, gpa, sl);
}
pub fn addReferenceTrace(eb: *ErrorBundle, gpa: Allocator, rt: ReferenceTrace) !void {
_ = try addExtra(eb, gpa, rt);
}
pub fn addBundle(eb: *ErrorBundle, gpa: Allocator, other: ErrorBundle) !void {
// Skip over the initial ErrorMessageList len field.
const root_fields_len = @typeInfo(ErrorMessageList).Struct.fields.len;
const other_list = other.extraData(ErrorMessageList, 0).data;
const other_extra = other.extra.items[root_fields_len..];
try eb.string_bytes.ensureUnusedCapacity(gpa, other.string_bytes.items.len);
try eb.extra.ensureUnusedCapacity(gpa, other_extra.len);
const new_string_base = @intCast(u32, eb.string_bytes.items.len);
const new_data_base = @intCast(u32, eb.extra.items.len - root_fields_len);
eb.string_bytes.appendSliceAssumeCapacity(other.string_bytes.items);
eb.extra.appendSliceAssumeCapacity(other_extra);
// Now we must offset the string indexes and extra indexes of the newly
// added extra.
var index = new_data_base + other_list.start;
for (0..other_list.len) |_| {
index = try patchMessage(eb, index, new_string_base, new_data_base);
}
}
fn patchMessage(eb: *ErrorBundle, msg_idx: usize, new_string_base: u32, new_data_base: u32) !u32 {
var msg = eb.extraData(ErrorMessage, msg_idx);
if (msg.data.msg != 0) msg.data.msg += new_string_base;
if (msg.data.src_loc != 0) msg.data.src_loc += new_data_base;
eb.setExtra(msg_idx, msg.data);
try patchSrcLoc(eb, msg.data.src_loc, new_string_base, new_data_base);
var index = @intCast(u32, msg.end);
for (0..msg.data.notes_len) |_| {
index = try patchMessage(eb, index, new_string_base, new_data_base);
}
return index;
}
fn patchSrcLoc(eb: *ErrorBundle, idx: usize, new_string_base: u32, new_data_base: u32) !void {
if (idx == 0) return;
var src_loc = eb.extraData(SourceLocation, idx);
if (src_loc.data.src_path != 0) src_loc.data.src_path += new_string_base;
if (src_loc.data.source_line != 0) src_loc.data.source_line += new_string_base;
eb.setExtra(idx, src_loc.data);
var index = src_loc.end;
for (0..src_loc.data.reference_trace_len) |_| {
var ref_trace = eb.extraData(ReferenceTrace, index);
if (ref_trace.data.decl_name != 0) ref_trace.data.decl_name += new_string_base;
if (ref_trace.data.src_loc != 0) ref_trace.data.src_loc += new_data_base;
eb.setExtra(index, ref_trace.data);
try patchSrcLoc(eb, ref_trace.data.src_loc, new_string_base, new_data_base);
index = ref_trace.end;
}
}
fn addExtra(eb: *ErrorBundle, gpa: Allocator, extra: anytype) Allocator.Error!u32 {
const fields = @typeInfo(@TypeOf(extra)).Struct.fields;
try eb.extra.ensureUnusedCapacity(gpa, fields.len);
return addExtraAssumeCapacity(eb, extra);
}
fn addExtraAssumeCapacity(eb: *ErrorBundle, extra: anytype) u32 {
const fields = @typeInfo(@TypeOf(extra)).Struct.fields;
const result = @intCast(u32, eb.extra.items.len);
eb.extra.items.len += fields.len;
setExtra(eb, result, extra);
return result;
}
fn setExtra(eb: *ErrorBundle, index: usize, extra: anytype) void {
const fields = @typeInfo(@TypeOf(extra)).Struct.fields;
var i = index;
inline for (fields) |field| {
eb.extra.items[i] = switch (field.type) {
u32 => @field(extra, field.name),
else => @compileError("bad field type"),
};
i += 1;
}
}
pub fn errorMessageCount(eb: ErrorBundle) u32 {
return eb.extra.items[0];
}
pub fn setErrorMessageCount(eb: *ErrorBundle, count: u32) void {
eb.extra.items[0] = count;
}
pub fn incrementCount(eb: *ErrorBundle, delta: u32) void {
eb.extra.items[0] += delta;
}
pub fn getStartIndex(eb: ErrorBundle) u32 {
return eb.extra.items[1];
}
pub fn setStartIndex(eb: *ErrorBundle, index: u32) void {
eb.extra.items[1] = index;
}
pub fn getErrorMessage(eb: ErrorBundle, index: MessageIndex) ErrorMessage {
return eb.extraData(ErrorMessage, @enumToInt(index)).data;
}
pub fn getSourceLocation(eb: ErrorBundle, index: u32) SourceLocation {
assert(index != 0);
return eb.extraData(SourceLocation, index).data;
}
/// Returns the requested data, as well as the new index which is at the start of the
/// trailers for the object.
fn extraData(eb: ErrorBundle, comptime T: type, index: usize) struct { data: T, end: usize } {
const fields = @typeInfo(T).Struct.fields;
var i: usize = index;
var result: T = undefined;
inline for (fields) |field| {
@field(result, field.name) = switch (field.type) {
u32 => eb.extra.items[i],
else => @compileError("bad field type"),
};
i += 1;
}
return .{
.data = result,
.end = i,
};
}
/// Given an index into `string_bytes` returns the null-terminated string found there.
pub fn nullTerminatedString(eb: ErrorBundle, index: usize) [:0]const u8 {
const string_bytes = eb.string_bytes.items;
var end: usize = index;
while (string_bytes[end] != 0) {
end += 1;
}
return string_bytes[index..end :0];
}
pub fn renderToStdErr(eb: ErrorBundle, ttyconf: std.debug.TTY.Config) void {
std.debug.getStderrMutex().lock();
defer std.debug.getStderrMutex().unlock();
const stderr = std.io.getStdErr();
return renderToWriter(eb, ttyconf, stderr.writer()) catch return;
}
pub fn renderToWriter(
eb: ErrorBundle,
ttyconf: std.debug.TTY.Config,
writer: anytype,
) anyerror!void {
const list = eb.extraData(ErrorMessageList, 0).data;
var index: usize = list.start;
for (0..list.len) |_| {
const err_msg = eb.extraData(ErrorMessage, index);
index = try renderErrorMessageToWriter(eb, err_msg.data, err_msg.end, ttyconf, writer, "error", .Red, 0);
}
}
fn renderErrorMessageToWriter(
eb: ErrorBundle,
err_msg: ErrorMessage,
end_index: usize,
ttyconf: std.debug.TTY.Config,
stderr: anytype,
kind: []const u8,
color: std.debug.TTY.Color,
indent: usize,
) anyerror!usize {
var counting_writer = std.io.countingWriter(stderr);
const counting_stderr = counting_writer.writer();
if (err_msg.src_loc != 0) {
const src = eb.extraData(SourceLocation, err_msg.src_loc);
try counting_stderr.writeByteNTimes(' ', indent);
try ttyconf.setColor(stderr, .Bold);
try counting_stderr.print("{s}:{d}:{d}: ", .{
eb.nullTerminatedString(src.data.src_path),
src.data.line + 1,
src.data.column + 1,
});
try ttyconf.setColor(stderr, color);
try counting_stderr.writeAll(kind);
try counting_stderr.writeAll(": ");
// This is the length of the part before the error message:
// e.g. "file.zig:4:5: error: "
const prefix_len = @intCast(usize, counting_stderr.context.bytes_written);
try ttyconf.setColor(stderr, .Reset);
try ttyconf.setColor(stderr, .Bold);
if (err_msg.count == 1) {
try writeMsg(eb, err_msg, stderr, prefix_len);
try stderr.writeByte('\n');
} else {
try writeMsg(eb, err_msg, stderr, prefix_len);
try ttyconf.setColor(stderr, .Dim);
try stderr.print(" ({d} times)\n", .{err_msg.count});
}
try ttyconf.setColor(stderr, .Reset);
if (src.data.source_line != 0) {
const line = eb.nullTerminatedString(src.data.source_line);
for (line) |b| switch (b) {
'\t' => try stderr.writeByte(' '),
else => try stderr.writeByte(b),
};
try stderr.writeByte('\n');
// TODO basic unicode code point monospace width
const before_caret = src.data.span_main - src.data.span_start;
// -1 since span.main includes the caret
const after_caret = src.data.span_end - src.data.span_main -| 1;
try stderr.writeByteNTimes(' ', src.data.column - before_caret);
try ttyconf.setColor(stderr, .Green);
try stderr.writeByteNTimes('~', before_caret);
try stderr.writeByte('^');
try stderr.writeByteNTimes('~', after_caret);
try stderr.writeByte('\n');
try ttyconf.setColor(stderr, .Reset);
}
var index = end_index;
for (0..err_msg.notes_len) |_| {
const note = eb.extraData(ErrorMessage, index);
index = try renderErrorMessageToWriter(eb, note.data, note.end, ttyconf, stderr, "note", .Cyan, indent);
}
if (src.data.reference_trace_len > 0) {
try ttyconf.setColor(stderr, .Reset);
try ttyconf.setColor(stderr, .Dim);
try stderr.print("referenced by:\n", .{});
var ref_index = src.end;
for (0..src.data.reference_trace_len) |_| {
const ref_trace = eb.extraData(ReferenceTrace, ref_index);
ref_index = ref_trace.end;
if (ref_trace.data.src_loc != 0) {
const ref_src = eb.getSourceLocation(ref_trace.data.src_loc);
try stderr.print(" {s}: {s}:{d}:{d}\n", .{
eb.nullTerminatedString(ref_trace.data.decl_name),
eb.nullTerminatedString(ref_src.src_path),
ref_src.line + 1,
ref_src.column + 1,
});
} else if (ref_trace.data.decl_name != 0) {
const count = ref_trace.data.decl_name;
try stderr.print(
" {d} reference(s) hidden; use '-freference-trace={d}' to see all references\n",
.{ count, count + src.data.reference_trace_len - 1 },
);
} else {
try stderr.print(
" remaining reference traces hidden; use '-freference-trace' to see all reference traces\n",
.{},
);
}
}
try stderr.writeByte('\n');
try ttyconf.setColor(stderr, .Reset);
}
return index;
} else {
try ttyconf.setColor(stderr, color);
try stderr.writeByteNTimes(' ', indent);
try stderr.writeAll(kind);
try stderr.writeAll(": ");
try ttyconf.setColor(stderr, .Reset);
const msg = eb.nullTerminatedString(err_msg.msg);
if (err_msg.count == 1) {
try stderr.print("{s}\n", .{msg});
} else {
try stderr.print("{s}", .{msg});
try ttyconf.setColor(stderr, .Dim);
try stderr.print(" ({d} times)\n", .{err_msg.count});
}
try ttyconf.setColor(stderr, .Reset);
var index = end_index;
for (0..err_msg.notes_len) |_| {
const note = eb.extraData(ErrorMessage, index);
index = try renderErrorMessageToWriter(eb, note.data, note.end, ttyconf, stderr, "note", .Cyan, indent + 4);
}
return index;
}
}
/// Splits the error message up into lines to properly indent them
/// to allow for long, good-looking error messages.
///
/// This is used to split the message in `@compileError("hello\nworld")` for example.
fn writeMsg(eb: ErrorBundle, err_msg: ErrorMessage, stderr: anytype, indent: usize) !void {
var lines = std.mem.split(u8, eb.nullTerminatedString(err_msg.msg), "\n");
while (lines.next()) |line| {
try stderr.writeAll(line);
if (lines.index == null) break;
try stderr.writeByte('\n');
try stderr.writeByteNTimes(' ', indent);
}
}
const std = @import("std");
const ErrorBundle = @This();
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;

View File

@ -133,6 +133,8 @@ pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir {
try astgen.extra.ensureTotalCapacity(gpa, tree.nodes.len + reserved_count);
astgen.extra.items.len += reserved_count;
try lowerAstErrors(&astgen);
var top_scope: Scope.Top = .{};
var gz_instructions: std.ArrayListUnmanaged(Zir.Inst.Index) = .{};
@ -10401,27 +10403,11 @@ fn appendErrorTokNotes(
args: anytype,
notes: []const u32,
) !void {
@setCold(true);
const string_bytes = &astgen.string_bytes;
const msg = @intCast(u32, string_bytes.items.len);
try string_bytes.writer(astgen.gpa).print(format ++ "\x00", args);
const notes_index: u32 = if (notes.len != 0) blk: {
const notes_start = astgen.extra.items.len;
try astgen.extra.ensureTotalCapacity(astgen.gpa, notes_start + 1 + notes.len);
astgen.extra.appendAssumeCapacity(@intCast(u32, notes.len));
astgen.extra.appendSliceAssumeCapacity(notes);
break :blk @intCast(u32, notes_start);
} else 0;
try astgen.compile_errors.append(astgen.gpa, .{
.msg = msg,
.node = 0,
.token = token,
.byte_offset = 0,
.notes = notes_index,
});
return appendErrorTokNotesOff(astgen, token, 0, format, args, notes);
}
/// Same as `fail`, except given an absolute byte offset.
/// Same as `fail`, except given a token plus an offset from its starting byte
/// offset.
fn failOff(
astgen: *AstGen,
token: Ast.TokenIndex,
@ -10429,27 +10415,36 @@ fn failOff(
comptime format: []const u8,
args: anytype,
) InnerError {
try appendErrorOff(astgen, token, byte_offset, format, args);
try appendErrorTokNotesOff(astgen, token, byte_offset, format, args, &.{});
return error.AnalysisFail;
}
fn appendErrorOff(
fn appendErrorTokNotesOff(
astgen: *AstGen,
token: Ast.TokenIndex,
byte_offset: u32,
comptime format: []const u8,
args: anytype,
) Allocator.Error!void {
notes: []const u32,
) !void {
@setCold(true);
const gpa = astgen.gpa;
const string_bytes = &astgen.string_bytes;
const msg = @intCast(u32, string_bytes.items.len);
try string_bytes.writer(astgen.gpa).print(format ++ "\x00", args);
try astgen.compile_errors.append(astgen.gpa, .{
try string_bytes.writer(gpa).print(format ++ "\x00", args);
const notes_index: u32 = if (notes.len != 0) blk: {
const notes_start = astgen.extra.items.len;
try astgen.extra.ensureTotalCapacity(gpa, notes_start + 1 + notes.len);
astgen.extra.appendAssumeCapacity(@intCast(u32, notes.len));
astgen.extra.appendSliceAssumeCapacity(notes);
break :blk @intCast(u32, notes_start);
} else 0;
try astgen.compile_errors.append(gpa, .{
.msg = msg,
.node = 0,
.token = token,
.byte_offset = byte_offset,
.notes = 0,
.notes = notes_index,
});
}
@ -10458,6 +10453,16 @@ fn errNoteTok(
token: Ast.TokenIndex,
comptime format: []const u8,
args: anytype,
) Allocator.Error!u32 {
return errNoteTokOff(astgen, token, 0, format, args);
}
fn errNoteTokOff(
astgen: *AstGen,
token: Ast.TokenIndex,
byte_offset: u32,
comptime format: []const u8,
args: anytype,
) Allocator.Error!u32 {
@setCold(true);
const string_bytes = &astgen.string_bytes;
@ -10467,7 +10472,7 @@ fn errNoteTok(
.msg = msg,
.node = 0,
.token = token,
.byte_offset = 0,
.byte_offset = byte_offset,
.notes = 0,
});
}
@ -12634,3 +12639,42 @@ fn emitDbgStmt(gz: *GenZir, line: u32, column: u32) !void {
},
} });
}
fn lowerAstErrors(astgen: *AstGen) !void {
const tree = astgen.tree;
if (tree.errors.len == 0) return;
const gpa = astgen.gpa;
const parse_err = tree.errors[0];
var msg: std.ArrayListUnmanaged(u8) = .{};
defer msg.deinit(gpa);
const token_starts = tree.tokens.items(.start);
const token_tags = tree.tokens.items(.tag);
var notes: std.ArrayListUnmanaged(u32) = .{};
defer notes.deinit(gpa);
if (token_tags[parse_err.token + @boolToInt(parse_err.token_is_prev)] == .invalid) {
const tok = parse_err.token + @boolToInt(parse_err.token_is_prev);
const bad_off = @intCast(u32, tree.tokenSlice(parse_err.token + @boolToInt(parse_err.token_is_prev)).len);
const byte_abs = token_starts[parse_err.token + @boolToInt(parse_err.token_is_prev)] + bad_off;
try notes.append(gpa, try astgen.errNoteTokOff(tok, bad_off, "invalid byte: '{'}'", .{
std.zig.fmtEscapes(tree.source[byte_abs..][0..1]),
}));
}
for (tree.errors[1..]) |note| {
if (!note.is_note) break;
msg.clearRetainingCapacity();
try tree.renderError(note, msg.writer(gpa));
try notes.append(gpa, try astgen.errNoteTok(note.token, "{s}", .{msg.items}));
}
const extra_offset = tree.errorOffset(parse_err);
msg.clearRetainingCapacity();
try tree.renderError(parse_err, msg.writer(gpa));
try astgen.appendErrorTokNotesOff(parse_err.token, extra_offset, "{s}", .{msg.items}, notes.items);
}

File diff suppressed because it is too large Load Diff

View File

@ -3756,67 +3756,9 @@ pub fn astGenFile(mod: *Module, file: *File) !void {
file.source_loaded = true;
file.tree = try Ast.parse(gpa, source, .zig);
defer if (!file.tree_loaded) file.tree.deinit(gpa);
if (file.tree.errors.len != 0) {
const parse_err = file.tree.errors[0];
var msg = std.ArrayList(u8).init(gpa);
defer msg.deinit();
const token_starts = file.tree.tokens.items(.start);
const token_tags = file.tree.tokens.items(.tag);
const extra_offset = file.tree.errorOffset(parse_err);
try file.tree.renderError(parse_err, msg.writer());
const err_msg = try gpa.create(ErrorMsg);
err_msg.* = .{
.src_loc = .{
.file_scope = file,
.parent_decl_node = 0,
.lazy = if (extra_offset == 0) .{
.token_abs = parse_err.token,
} else .{
.byte_abs = token_starts[parse_err.token] + extra_offset,
},
},
.msg = try msg.toOwnedSlice(),
};
if (token_tags[parse_err.token + @boolToInt(parse_err.token_is_prev)] == .invalid) {
const bad_off = @intCast(u32, file.tree.tokenSlice(parse_err.token + @boolToInt(parse_err.token_is_prev)).len);
const byte_abs = token_starts[parse_err.token + @boolToInt(parse_err.token_is_prev)] + bad_off;
try mod.errNoteNonLazy(.{
.file_scope = file,
.parent_decl_node = 0,
.lazy = .{ .byte_abs = byte_abs },
}, err_msg, "invalid byte: '{'}'", .{std.zig.fmtEscapes(source[byte_abs..][0..1])});
}
for (file.tree.errors[1..]) |note| {
if (!note.is_note) break;
try file.tree.renderError(note, msg.writer());
err_msg.notes = try mod.gpa.realloc(err_msg.notes, err_msg.notes.len + 1);
err_msg.notes[err_msg.notes.len - 1] = .{
.src_loc = .{
.file_scope = file,
.parent_decl_node = 0,
.lazy = .{ .token_abs = note.token },
},
.msg = try msg.toOwnedSlice(),
};
}
{
comp.mutex.lock();
defer comp.mutex.unlock();
try mod.failed_files.putNoClobber(gpa, file, err_msg);
}
file.status = .parse_failure;
return error.AnalysisFail;
}
file.tree_loaded = true;
// Any potential AST errors are converted to ZIR errors here.
file.zir = try AstGen.generate(gpa, file.tree);
file.zir_loaded = true;
file.status = .success_zir;

View File

@ -225,7 +225,7 @@ pub fn fetchAndAddDependencies(
dependencies_source: *std.ArrayList(u8),
build_roots_source: *std.ArrayList(u8),
name_prefix: []const u8,
color: main.Color,
error_bundle: *std.zig.ErrorBundle,
all_modules: *AllModules,
) !void {
const max_bytes = 10 * 1024 * 1024;
@ -250,7 +250,7 @@ pub fn fetchAndAddDependencies(
if (ast.errors.len > 0) {
const file_path = try directory.join(arena, &.{Manifest.basename});
try main.printErrsMsgToStdErr(gpa, arena, ast, file_path, color);
try main.putAstErrorsIntoBundle(gpa, ast, file_path, error_bundle);
return error.PackageFetchFailed;
}
@ -258,23 +258,18 @@ pub fn fetchAndAddDependencies(
defer manifest.deinit(gpa);
if (manifest.errors.len > 0) {
const ttyconf: std.debug.TTY.Config = switch (color) {
.auto => std.debug.detectTTYConfig(std.io.getStdErr()),
.on => .escape_codes,
.off => .no_color,
};
const file_path = try directory.join(arena, &.{Manifest.basename});
for (manifest.errors) |msg| {
Report.renderErrorMessage(ast, file_path, ttyconf, msg, &.{});
try Report.addErrorMessage(gpa, ast, file_path, error_bundle, 0, msg);
}
return error.PackageFetchFailed;
}
const report: Report = .{
.gpa = gpa,
.ast = &ast,
.directory = directory,
.color = color,
.arena = arena,
.error_bundle = error_bundle,
};
var any_error = false;
@ -307,7 +302,7 @@ pub fn fetchAndAddDependencies(
dependencies_source,
build_roots_source,
sub_prefix,
color,
error_bundle,
all_modules,
);
@ -348,10 +343,10 @@ pub fn createFilePkg(
}
const Report = struct {
gpa: Allocator,
ast: *const std.zig.Ast,
directory: Compilation.Directory,
color: main.Color,
arena: Allocator,
error_bundle: *std.zig.ErrorBundle,
fn fail(
report: Report,
@ -359,52 +354,48 @@ const Report = struct {
comptime fmt_string: []const u8,
fmt_args: anytype,
) error{ PackageFetchFailed, OutOfMemory } {
return failWithNotes(report, &.{}, tok, fmt_string, fmt_args);
}
const gpa = report.gpa;
fn failWithNotes(
report: Report,
notes: []const Compilation.AllErrors.Message,
tok: std.zig.Ast.TokenIndex,
comptime fmt_string: []const u8,
fmt_args: anytype,
) error{ PackageFetchFailed, OutOfMemory } {
const ttyconf: std.debug.TTY.Config = switch (report.color) {
.auto => std.debug.detectTTYConfig(std.io.getStdErr()),
.on => .escape_codes,
.off => .no_color,
};
const file_path = try report.directory.join(report.arena, &.{Manifest.basename});
renderErrorMessage(report.ast.*, file_path, ttyconf, .{
const file_path = try report.directory.join(gpa, &.{Manifest.basename});
defer gpa.free(file_path);
const msg = try std.fmt.allocPrint(gpa, fmt_string, fmt_args);
defer gpa.free(msg);
try addErrorMessage(report.gpa, report.ast.*, file_path, report.error_bundle, 0, .{
.tok = tok,
.off = 0,
.msg = try std.fmt.allocPrint(report.arena, fmt_string, fmt_args),
}, notes);
.msg = msg,
});
return error.PackageFetchFailed;
}
fn renderErrorMessage(
fn addErrorMessage(
gpa: Allocator,
ast: std.zig.Ast,
file_path: []const u8,
ttyconf: std.debug.TTY.Config,
eb: *std.zig.ErrorBundle,
notes_len: u32,
msg: Manifest.ErrorMessage,
notes: []const Compilation.AllErrors.Message,
) void {
) error{OutOfMemory}!void {
const token_starts = ast.tokens.items(.start);
const start_loc = ast.tokenLocation(0, msg.tok);
Compilation.AllErrors.Message.renderToStdErr(.{ .src = .{
.msg = msg.msg,
.src_path = file_path,
try eb.addErrorMessage(gpa, .{
.msg = try eb.addString(gpa, msg.msg),
.src_loc = try eb.addSourceLocation(gpa, .{
.src_path = try eb.addString(gpa, file_path),
.span_start = token_starts[msg.tok],
.span_end = @intCast(u32, token_starts[msg.tok] + ast.tokenSlice(msg.tok).len),
.span_main = token_starts[msg.tok] + msg.off,
.line = @intCast(u32, start_loc.line),
.column = @intCast(u32, start_loc.column),
.span = .{
.start = token_starts[msg.tok],
.end = @intCast(u32, token_starts[msg.tok] + ast.tokenSlice(msg.tok).len),
.main = token_starts[msg.tok] + msg.off,
},
.source_line = ast.source[start_loc.line_start..start_loc.line_end],
.notes = notes,
} }, ttyconf);
.source_line = try eb.addString(gpa, ast.source[start_loc.line_start..start_loc.line_end]),
}),
.notes_len = notes_len,
});
eb.incrementCount(1);
}
};
@ -504,9 +495,7 @@ fn fetchAndUnpack(
// by default, so the same logic applies for buffering the reader as for gzip.
try unpackTarball(gpa, &req, tmp_directory.handle, std.compress.xz);
} else {
return report.fail(dep.url_tok, "unknown file extension for path '{s}'", .{
uri.path,
});
return report.fail(dep.url_tok, "unknown file extension for path '{s}'", .{uri.path});
}
// TODO: delete files not included in the package prior to computing the package hash.
@ -533,10 +522,19 @@ fn fetchAndUnpack(
});
}
} else {
const notes: [1]Compilation.AllErrors.Message = .{.{ .plain = .{
.msg = try std.fmt.allocPrint(report.arena, "expected .hash = \"{s}\",", .{&actual_hex}),
} }};
return report.failWithNotes(&notes, dep.url_tok, "url field is missing corresponding hash field", .{});
const file_path = try report.directory.join(gpa, &.{Manifest.basename});
defer gpa.free(file_path);
const eb = report.error_bundle;
try Report.addErrorMessage(gpa, report.ast.*, file_path, eb, 1, .{
.tok = dep.url_tok,
.off = 0,
.msg = "url field is missing corresponding hash field",
});
try eb.addErrorMessage(gpa, .{
.msg = try eb.printString(gpa, "expected .hash = \"{s}\",", .{&actual_hex}),
});
return error.PackageFetchFailed;
}
const build_root = try global_cache_directory.join(gpa, &.{pkg_dir_sub_path});

View File

@ -2211,29 +2211,26 @@ pub fn fail(
fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError {
@setCold(true);
const gpa = sema.gpa;
if (crash_report.is_enabled and sema.mod.comp.debug_compile_errors) {
if (err_msg.src_loc.lazy == .unneeded) return error.NeededSourceLocation;
var arena = std.heap.ArenaAllocator.init(sema.gpa);
errdefer arena.deinit();
var errors = std.ArrayList(Compilation.AllErrors.Message).init(sema.gpa);
defer errors.deinit();
Compilation.AllErrors.add(sema.mod, &arena, &errors, err_msg.*) catch unreachable;
var errors: std.zig.ErrorBundle = undefined;
errors.init(gpa) catch unreachable;
Compilation.addModuleErrorMsg(gpa, &errors, err_msg.*) catch unreachable;
std.debug.print("compile error during Sema:\n", .{});
Compilation.AllErrors.Message.renderToStdErr(errors.items[0], .no_color);
errors.renderToStdErr(.no_color);
crash_report.compilerPanic("unexpected compile error occurred", null, null);
}
const mod = sema.mod;
ref: {
errdefer err_msg.destroy(mod.gpa);
errdefer err_msg.destroy(gpa);
if (err_msg.src_loc.lazy == .unneeded) {
return error.NeededSourceLocation;
}
try mod.failed_decls.ensureUnusedCapacity(mod.gpa, 1);
try mod.failed_files.ensureUnusedCapacity(mod.gpa, 1);
try mod.failed_decls.ensureUnusedCapacity(gpa, 1);
try mod.failed_files.ensureUnusedCapacity(gpa, 1);
const max_references = blk: {
if (sema.mod.comp.reference_trace) |num| break :blk num;
@ -2243,11 +2240,11 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError {
};
var referenced_by = if (sema.func) |some| some.owner_decl else sema.owner_decl_index;
var reference_stack = std.ArrayList(Module.ErrorMsg.Trace).init(sema.gpa);
var reference_stack = std.ArrayList(Module.ErrorMsg.Trace).init(gpa);
defer reference_stack.deinit();
// Avoid infinite loops.
var seen = std.AutoHashMap(Module.Decl.Index, void).init(sema.gpa);
var seen = std.AutoHashMap(Module.Decl.Index, void).init(gpa);
defer seen.deinit();
var cur_reference_trace: u32 = 0;
@ -2288,7 +2285,7 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError {
if (gop.found_existing) {
// If there are multiple errors for the same Decl, prefer the first one added.
sema.err = null;
err_msg.destroy(mod.gpa);
err_msg.destroy(gpa);
} else {
sema.err = err_msg;
gop.value_ptr.* = err_msg;

View File

@ -196,7 +196,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
"-DASSEMBLER",
"-Wa,--noexecstack",
});
return comp.build_crt_file("crti", .Obj, &[1]Compilation.CSourceFile{
return comp.build_crt_file("crti", .Obj, .@"glibc crti.o", &[1]Compilation.CSourceFile{
.{
.src_path = try start_asm_path(comp, arena, "crti.S"),
.cache_exempt_flags = args.items,
@ -215,7 +215,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
"-DASSEMBLER",
"-Wa,--noexecstack",
});
return comp.build_crt_file("crtn", .Obj, &[1]Compilation.CSourceFile{
return comp.build_crt_file("crtn", .Obj, .@"glibc crtn.o", &[1]Compilation.CSourceFile{
.{
.src_path = try start_asm_path(comp, arena, "crtn.S"),
.cache_exempt_flags = args.items,
@ -265,7 +265,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
.cache_exempt_flags = args.items,
};
};
return comp.build_crt_file("Scrt1", .Obj, &[_]Compilation.CSourceFile{ start_o, abi_note_o });
return comp.build_crt_file("Scrt1", .Obj, .@"glibc Scrt1.o", &[_]Compilation.CSourceFile{ start_o, abi_note_o });
},
.libc_nonshared_a => {
const s = path.sep_str;
@ -366,7 +366,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
files_index += 1;
}
const files = files_buf[0..files_index];
return comp.build_crt_file("c_nonshared", .Lib, files);
return comp.build_crt_file("c_nonshared", .Lib, .@"glibc libc_nonshared.a", files);
},
}
}
@ -1105,7 +1105,7 @@ fn buildSharedLib(
});
defer sub_compilation.destroy();
try sub_compilation.updateSubCompilation();
try comp.updateSubCompilation(sub_compilation, .@"glibc shared object");
}
// Return true if glibc has crti/crtn sources for that architecture.

View File

@ -258,7 +258,7 @@ pub fn buildLibCXX(comp: *Compilation) !void {
});
defer sub_compilation.destroy();
try sub_compilation.updateSubCompilation();
try comp.updateSubCompilation(sub_compilation, .libcxx);
assert(comp.libcxx_static_lib == null);
comp.libcxx_static_lib = Compilation.CRTFile{
@ -418,7 +418,7 @@ pub fn buildLibCXXABI(comp: *Compilation) !void {
});
defer sub_compilation.destroy();
try sub_compilation.updateSubCompilation();
try comp.updateSubCompilation(sub_compilation, .libcxxabi);
assert(comp.libcxxabi_static_lib == null);
comp.libcxxabi_static_lib = Compilation.CRTFile{

View File

@ -235,7 +235,7 @@ pub fn buildTsan(comp: *Compilation) !void {
});
defer sub_compilation.destroy();
try sub_compilation.updateSubCompilation();
try comp.updateSubCompilation(sub_compilation, .libtsan);
assert(comp.tsan_static_lib == null);
comp.tsan_static_lib = Compilation.CRTFile{

View File

@ -130,7 +130,7 @@ pub fn buildStaticLib(comp: *Compilation) !void {
});
defer sub_compilation.destroy();
try sub_compilation.updateSubCompilation();
try comp.updateSubCompilation(sub_compilation, .libunwind);
assert(comp.libunwind_static_lib == null);

View File

@ -24,6 +24,8 @@ const clang = @import("clang.zig");
const Cache = std.Build.Cache;
const target_util = @import("target.zig");
const crash_report = @import("crash_report.zig");
const Module = @import("Module.zig");
const AstGen = @import("AstGen.zig");
pub const std_options = struct {
pub const wasiCwd = wasi_cwd;
@ -3446,15 +3448,13 @@ fn buildOutputType(
var errors = try comp.getAllErrorsAlloc();
defer errors.deinit(comp.gpa);
if (errors.list.len != 0) {
if (errors.errorMessageCount() > 0) {
const ttyconf: std.debug.TTY.Config = switch (comp.color) {
.auto => std.debug.detectTTYConfig(std.io.getStdErr()),
.on => .escape_codes,
.off => .no_color,
};
for (errors.list) |full_err_msg| {
try full_err_msg.renderToWriter(ttyconf, conn.stream.writer(), "error:", .Red, 0);
}
try errors.renderToWriter(ttyconf, conn.stream.writer());
continue;
}
} else {
@ -3830,15 +3830,13 @@ fn updateModule(gpa: Allocator, comp: *Compilation, hook: AfterUpdateHook) !void
var errors = try comp.getAllErrorsAlloc();
defer errors.deinit(comp.gpa);
if (errors.list.len != 0) {
if (errors.errorMessageCount() > 0) {
const ttyconf: std.debug.TTY.Config = switch (comp.color) {
.auto => std.debug.detectTTYConfig(std.io.getStdErr()),
.on => .escape_codes,
.off => .no_color,
};
for (errors.list) |full_err_msg| {
full_err_msg.renderToStdErr(ttyconf);
}
errors.renderToStdErr(ttyconf);
const log_text = comp.getCompileLogOutput();
if (log_text.len != 0) {
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
var all_modules: Package.AllModules = .{};
defer all_modules.deinit(gpa);
var errors: std.zig.ErrorBundle = undefined;
try errors.init(gpa);
defer errors.deinit(gpa);
// Here we borrow main package's table and will replace it with a fresh
// one after this process completes.
build_pkg.fetchAndAddDependencies(
const fetch_result = build_pkg.fetchAndAddDependencies(
&main_pkg,
arena,
&thread_pool,
@ -4451,12 +4453,19 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
&dependencies_source,
&build_roots_source,
"",
color,
&errors,
&all_modules,
) catch |err| switch (err) {
error.PackageFetchFailed => process.exit(1),
else => |e| return e,
);
if (errors.errorMessageCount() > 0) {
const ttyconf: std.debug.TTY.Config = switch (color) {
.auto => std.debug.detectTTYConfig(std.io.getStdErr()),
.on => .escape_codes,
.off => .no_color,
};
errors.renderToStdErr(ttyconf);
process.exit(1);
}
try fetch_result;
try dependencies_source.appendSlice("};\npub const build_root = struct {\n");
try dependencies_source.appendSlice(build_roots_source.items);
@ -4543,7 +4552,7 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
}
fn readSourceFileToEndAlloc(
allocator: mem.Allocator,
allocator: Allocator,
input: *const fs.File,
size_hint: ?usize,
) ![:0]u8 {
@ -4687,12 +4696,9 @@ pub fn cmdFmt(gpa: Allocator, arena: Allocator, args: []const []const u8) !void
};
defer tree.deinit(gpa);
try printErrsMsgToStdErr(gpa, arena, tree, "<stdin>", color);
try printAstErrorsToStderr(gpa, tree, "<stdin>", color);
var has_ast_error = false;
if (check_ast_flag) {
const Module = @import("Module.zig");
const AstGen = @import("AstGen.zig");
var file: Module.File = .{
.status = .never_loaded,
.source_loaded = true,
@ -4715,20 +4721,16 @@ pub fn cmdFmt(gpa: Allocator, arena: Allocator, args: []const []const u8) !void
defer file.zir.deinit(gpa);
if (file.zir.hasCompileErrors()) {
var arena_instance = std.heap.ArenaAllocator.init(gpa);
defer arena_instance.deinit();
var errors = std.ArrayList(Compilation.AllErrors.Message).init(gpa);
defer errors.deinit();
try Compilation.AllErrors.addZir(arena_instance.allocator(), &errors, &file);
var errors: std.zig.ErrorBundle = undefined;
try errors.init(gpa);
defer errors.deinit(gpa);
try Compilation.addZirErrorMessages(gpa, &errors, &file);
const ttyconf: std.debug.TTY.Config = switch (color) {
.auto => std.debug.detectTTYConfig(std.io.getStdErr()),
.on => .escape_codes,
.off => .no_color,
};
for (errors.items) |full_err_msg| {
full_err_msg.renderToStdErr(ttyconf);
}
errors.renderToStdErr(ttyconf);
has_ast_error = true;
}
}
@ -4875,12 +4877,13 @@ fn fmtPathFile(
if (stat.kind == .Directory)
return error.IsDir;
const gpa = fmt.gpa;
const source_code = try readSourceFileToEndAlloc(
fmt.gpa,
gpa,
&source_file,
std.math.cast(usize, stat.size) orelse return error.FileTooBig,
);
defer fmt.gpa.free(source_code);
defer gpa.free(source_code);
source_file.close();
file_closed = true;
@ -4888,19 +4891,16 @@ fn fmtPathFile(
// Add to set after no longer possible to get error.IsDir.
if (try fmt.seen.fetchPut(stat.inode, {})) |_| return;
var tree = try Ast.parse(fmt.gpa, source_code, .zig);
defer tree.deinit(fmt.gpa);
var tree = try Ast.parse(gpa, source_code, .zig);
defer tree.deinit(gpa);
try printErrsMsgToStdErr(fmt.gpa, fmt.arena, tree, file_path, fmt.color);
try printAstErrorsToStderr(gpa, tree, file_path, fmt.color);
if (tree.errors.len != 0) {
fmt.any_error = true;
return;
}
if (fmt.check_ast) {
const Module = @import("Module.zig");
const AstGen = @import("AstGen.zig");
var file: Module.File = .{
.status = .never_loaded,
.source_loaded = true,
@ -4919,31 +4919,27 @@ fn fmtPathFile(
.root_decl = .none,
};
file.pkg = try Package.create(fmt.gpa, null, file.sub_file_path);
defer file.pkg.destroy(fmt.gpa);
file.pkg = try Package.create(gpa, null, file.sub_file_path);
defer file.pkg.destroy(gpa);
if (stat.size > max_src_size)
return error.FileTooBig;
file.zir = try AstGen.generate(fmt.gpa, file.tree);
file.zir = try AstGen.generate(gpa, file.tree);
file.zir_loaded = true;
defer file.zir.deinit(fmt.gpa);
defer file.zir.deinit(gpa);
if (file.zir.hasCompileErrors()) {
var arena_instance = std.heap.ArenaAllocator.init(fmt.gpa);
defer arena_instance.deinit();
var errors = std.ArrayList(Compilation.AllErrors.Message).init(fmt.gpa);
defer errors.deinit();
try Compilation.AllErrors.addZir(arena_instance.allocator(), &errors, &file);
var errors: std.zig.ErrorBundle = undefined;
try errors.init(gpa);
defer errors.deinit(gpa);
try Compilation.addZirErrorMessages(gpa, &errors, &file);
const ttyconf: std.debug.TTY.Config = switch (fmt.color) {
.auto => std.debug.detectTTYConfig(std.io.getStdErr()),
.on => .escape_codes,
.off => .no_color,
};
for (errors.items) |full_err_msg| {
full_err_msg.renderToStdErr(ttyconf);
}
errors.renderToStdErr(ttyconf);
fmt.any_error = true;
}
}
@ -4971,100 +4967,53 @@ fn fmtPathFile(
}
}
pub fn printErrsMsgToStdErr(
gpa: mem.Allocator,
arena: mem.Allocator,
tree: Ast,
path: []const u8,
color: Color,
) !void {
const parse_errors: []const Ast.Error = tree.errors;
var i: usize = 0;
while (i < parse_errors.len) : (i += 1) {
const parse_error = parse_errors[i];
const lok_token = parse_error.token;
const token_tags = tree.tokens.items(.tag);
const start_loc = tree.tokenLocation(0, lok_token);
const source_line = tree.source[start_loc.line_start..start_loc.line_end];
fn printAstErrorsToStderr(gpa: Allocator, tree: Ast, path: []const u8, color: Color) !void {
var error_bundle: std.zig.ErrorBundle = undefined;
try error_bundle.init(gpa);
defer error_bundle.deinit(gpa);
var text_buf = std.ArrayList(u8).init(gpa);
defer text_buf.deinit();
const writer = text_buf.writer();
try tree.renderError(parse_error, writer);
const text = try arena.dupe(u8, text_buf.items);
var notes_buffer: [2]Compilation.AllErrors.Message = undefined;
var notes_len: usize = 0;
if (token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)] == .invalid) {
const bad_off = @intCast(u32, tree.tokenSlice(parse_error.token + @boolToInt(parse_error.token_is_prev)).len);
const byte_offset = @intCast(u32, start_loc.line_start) + @intCast(u32, start_loc.column) + bad_off;
notes_buffer[notes_len] = .{
.src = .{
.src_path = path,
.msg = try std.fmt.allocPrint(arena, "invalid byte: '{'}'", .{
std.zig.fmtEscapes(tree.source[byte_offset..][0..1]),
}),
.span = .{ .start = byte_offset, .end = byte_offset + 1, .main = byte_offset },
.line = @intCast(u32, start_loc.line),
.column = @intCast(u32, start_loc.column) + bad_off,
.source_line = source_line,
},
};
notes_len += 1;
}
for (parse_errors[i + 1 ..]) |note| {
if (!note.is_note) break;
text_buf.items.len = 0;
try tree.renderError(note, writer);
const note_loc = tree.tokenLocation(0, note.token);
const byte_offset = @intCast(u32, note_loc.line_start);
notes_buffer[notes_len] = .{
.src = .{
.src_path = path,
.msg = try arena.dupe(u8, text_buf.items),
.span = .{
.start = byte_offset,
.end = byte_offset + @intCast(u32, tree.tokenSlice(note.token).len),
.main = byte_offset,
},
.line = @intCast(u32, note_loc.line),
.column = @intCast(u32, note_loc.column),
.source_line = tree.source[note_loc.line_start..note_loc.line_end],
},
};
i += 1;
notes_len += 1;
}
const extra_offset = tree.errorOffset(parse_error);
const byte_offset = @intCast(u32, start_loc.line_start) + extra_offset;
const message: Compilation.AllErrors.Message = .{
.src = .{
.src_path = path,
.msg = text,
.span = .{
.start = byte_offset,
.end = byte_offset + @intCast(u32, tree.tokenSlice(lok_token).len),
.main = byte_offset,
},
.line = @intCast(u32, start_loc.line),
.column = @intCast(u32, start_loc.column) + extra_offset,
.source_line = source_line,
.notes = notes_buffer[0..notes_len],
},
};
try putAstErrorsIntoBundle(gpa, tree, path, &error_bundle);
const ttyconf: std.debug.TTY.Config = switch (color) {
.auto => std.debug.detectTTYConfig(std.io.getStdErr()),
.on => .escape_codes,
.off => .no_color,
};
error_bundle.renderToStdErr(ttyconf);
}
message.renderToStdErr(ttyconf);
}
pub fn putAstErrorsIntoBundle(
gpa: Allocator,
tree: Ast,
path: []const u8,
error_bundle: *std.zig.ErrorBundle,
) !void {
var file: Module.File = .{
.status = .never_loaded,
.source_loaded = true,
.zir_loaded = false,
.sub_file_path = path,
.source = tree.source,
.stat = .{
.size = 0,
.inode = 0,
.mtime = 0,
},
.tree = tree,
.tree_loaded = true,
.zir = undefined,
.pkg = undefined,
.root_decl = .none,
};
file.pkg = try Package.create(gpa, null, path);
defer file.pkg.destroy(gpa);
file.zir = try AstGen.generate(gpa, file.tree);
file.zir_loaded = true;
defer file.zir.deinit(gpa);
try Compilation.addZirErrorMessages(gpa, error_bundle, &file);
}
pub const info_zen =
@ -5547,8 +5496,6 @@ pub fn cmdAstCheck(
arena: Allocator,
args: []const []const u8,
) !void {
const Module = @import("Module.zig");
const AstGen = @import("AstGen.zig");
const Zir = @import("Zir.zig");
var color: Color = .auto;
@ -5638,7 +5585,7 @@ pub fn cmdAstCheck(
file.tree_loaded = true;
defer file.tree.deinit(gpa);
try printErrsMsgToStdErr(gpa, arena, file.tree, file.sub_file_path, color);
try printAstErrorsToStderr(gpa, file.tree, file.sub_file_path, color);
if (file.tree.errors.len != 0) {
process.exit(1);
}
@ -5648,16 +5595,16 @@ pub fn cmdAstCheck(
defer file.zir.deinit(gpa);
if (file.zir.hasCompileErrors()) {
var errors = std.ArrayList(Compilation.AllErrors.Message).init(arena);
try Compilation.AllErrors.addZir(arena, &errors, &file);
var errors: std.zig.ErrorBundle = undefined;
try errors.init(gpa);
defer errors.deinit(gpa);
try Compilation.addZirErrorMessages(gpa, &errors, &file);
const ttyconf: std.debug.TTY.Config = switch (color) {
.auto => std.debug.detectTTYConfig(std.io.getStdErr()),
.on => .escape_codes,
.off => .no_color,
};
for (errors.items) |full_err_msg| {
full_err_msg.renderToStdErr(ttyconf);
}
errors.renderToStdErr(ttyconf);
process.exit(1);
}
@ -5715,8 +5662,6 @@ pub fn cmdChangelist(
arena: Allocator,
args: []const []const u8,
) !void {
const Module = @import("Module.zig");
const AstGen = @import("AstGen.zig");
const Zir = @import("Zir.zig");
const old_source_file = args[0];
@ -5764,7 +5709,7 @@ pub fn cmdChangelist(
file.tree_loaded = true;
defer file.tree.deinit(gpa);
try printErrsMsgToStdErr(gpa, arena, file.tree, old_source_file, .auto);
try printAstErrorsToStderr(gpa, file.tree, old_source_file, .auto);
if (file.tree.errors.len != 0) {
process.exit(1);
}
@ -5774,12 +5719,12 @@ pub fn cmdChangelist(
defer file.zir.deinit(gpa);
if (file.zir.hasCompileErrors()) {
var errors = std.ArrayList(Compilation.AllErrors.Message).init(arena);
try Compilation.AllErrors.addZir(arena, &errors, &file);
var errors: std.zig.ErrorBundle = undefined;
try errors.init(gpa);
defer errors.deinit(gpa);
try Compilation.addZirErrorMessages(gpa, &errors, &file);
const ttyconf = std.debug.detectTTYConfig(std.io.getStdErr());
for (errors.items) |full_err_msg| {
full_err_msg.renderToStdErr(ttyconf);
}
errors.renderToStdErr(ttyconf);
process.exit(1);
}
@ -5801,7 +5746,7 @@ pub fn cmdChangelist(
var new_tree = try Ast.parse(gpa, new_source, .zig);
defer new_tree.deinit(gpa);
try printErrsMsgToStdErr(gpa, arena, new_tree, new_source_file, .auto);
try printAstErrorsToStderr(gpa, new_tree, new_source_file, .auto);
if (new_tree.errors.len != 0) {
process.exit(1);
}
@ -5813,12 +5758,12 @@ pub fn cmdChangelist(
file.zir_loaded = true;
if (file.zir.hasCompileErrors()) {
var errors = std.ArrayList(Compilation.AllErrors.Message).init(arena);
try Compilation.AllErrors.addZir(arena, &errors, &file);
var errors: std.zig.ErrorBundle = undefined;
try errors.init(gpa);
defer errors.deinit(gpa);
try Compilation.addZirErrorMessages(gpa, &errors, &file);
const ttyconf = std.debug.detectTTYConfig(std.io.getStdErr());
for (errors.items) |full_err_msg| {
full_err_msg.renderToStdErr(ttyconf);
}
errors.renderToStdErr(ttyconf);
process.exit(1);
}

View File

@ -41,7 +41,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
//"-D_UNICODE",
//"-DWPRFLAG=1",
});
return comp.build_crt_file("crt2", .Obj, &[1]Compilation.CSourceFile{
return comp.build_crt_file("crt2", .Obj, .@"mingw-w64 crt2.o", &[1]Compilation.CSourceFile{
.{
.src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
"libc", "mingw", "crt", "crtexe.c",
@ -60,7 +60,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
"-U__CRTDLL__",
"-D__MSVCRT__",
});
return comp.build_crt_file("dllcrt2", .Obj, &[1]Compilation.CSourceFile{
return comp.build_crt_file("dllcrt2", .Obj, .@"mingw-w64 dllcrt2.o", &[1]Compilation.CSourceFile{
.{
.src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
"libc", "mingw", "crt", "crtdll.c",
@ -100,7 +100,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
.extra_flags = args.items,
};
}
return comp.build_crt_file("mingw32", .Lib, &c_source_files);
return comp.build_crt_file("mingw32", .Lib, .@"mingw-w64 mingw32.lib", &c_source_files);
},
.msvcrt_os_lib => {
@ -148,7 +148,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
};
}
}
return comp.build_crt_file("msvcrt-os", .Lib, c_source_files.items);
return comp.build_crt_file("msvcrt-os", .Lib, .@"mingw-w64 msvcrt-os.lib", c_source_files.items);
},
.mingwex_lib => {
@ -211,7 +211,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
} else {
@panic("unsupported arch");
}
return comp.build_crt_file("mingwex", .Lib, c_source_files.items);
return comp.build_crt_file("mingwex", .Lib, .@"mingw-w64 mingwex.lib", c_source_files.items);
},
.uuid_lib => {
@ -244,7 +244,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
.extra_flags = extra_flags,
};
}
return comp.build_crt_file("uuid", .Lib, &c_source_files);
return comp.build_crt_file("uuid", .Lib, .@"mingw-w64 uuid.lib", &c_source_files);
},
}
}

View File

@ -33,7 +33,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
try args.appendSlice(&[_][]const u8{
"-Qunused-arguments",
});
return comp.build_crt_file("crti", .Obj, &[1]Compilation.CSourceFile{
return comp.build_crt_file("crti", .Obj, .@"musl crti.o", &[1]Compilation.CSourceFile{
.{
.src_path = try start_asm_path(comp, arena, "crti.s"),
.extra_flags = args.items,
@ -46,7 +46,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
try args.appendSlice(&[_][]const u8{
"-Qunused-arguments",
});
return comp.build_crt_file("crtn", .Obj, &[1]Compilation.CSourceFile{
return comp.build_crt_file("crtn", .Obj, .@"musl crtn.o", &[1]Compilation.CSourceFile{
.{
.src_path = try start_asm_path(comp, arena, "crtn.s"),
.extra_flags = args.items,
@ -60,7 +60,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
"-fno-stack-protector",
"-DCRT",
});
return comp.build_crt_file("crt1", .Obj, &[1]Compilation.CSourceFile{
return comp.build_crt_file("crt1", .Obj, .@"musl crt1.o", &[1]Compilation.CSourceFile{
.{
.src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
"libc", "musl", "crt", "crt1.c",
@ -77,7 +77,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
"-fno-stack-protector",
"-DCRT",
});
return comp.build_crt_file("rcrt1", .Obj, &[1]Compilation.CSourceFile{
return comp.build_crt_file("rcrt1", .Obj, .@"musl rcrt1.o", &[1]Compilation.CSourceFile{
.{
.src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
"libc", "musl", "crt", "rcrt1.c",
@ -94,7 +94,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
"-fno-stack-protector",
"-DCRT",
});
return comp.build_crt_file("Scrt1", .Obj, &[1]Compilation.CSourceFile{
return comp.build_crt_file("Scrt1", .Obj, .@"musl Scrt1.o", &[1]Compilation.CSourceFile{
.{
.src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
"libc", "musl", "crt", "Scrt1.c",
@ -187,7 +187,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
.extra_flags = args.items,
};
}
return comp.build_crt_file("c", .Lib, c_source_files.items);
return comp.build_crt_file("c", .Lib, .@"musl libc.a", c_source_files.items);
},
.libc_so => {
const target = comp.getTarget();
@ -241,7 +241,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
});
defer sub_compilation.destroy();
try sub_compilation.updateSubCompilation();
try comp.updateSubCompilation(sub_compilation, .@"musl libc.so");
try comp.crt_files.ensureUnusedCapacity(comp.gpa, 1);

View File

@ -74,7 +74,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
var args = std.ArrayList([]const u8).init(arena);
try addCCArgs(comp, arena, &args, false);
try addLibcBottomHalfIncludes(comp, arena, &args);
return comp.build_crt_file("crt1-reactor", .Obj, &[1]Compilation.CSourceFile{
return comp.build_crt_file("crt1-reactor", .Obj, .@"wasi crt1-reactor.o", &[1]Compilation.CSourceFile{
.{
.src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
"libc", try sanitize(arena, crt1_reactor_src_file),
@ -87,7 +87,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
var args = std.ArrayList([]const u8).init(arena);
try addCCArgs(comp, arena, &args, false);
try addLibcBottomHalfIncludes(comp, arena, &args);
return comp.build_crt_file("crt1-command", .Obj, &[1]Compilation.CSourceFile{
return comp.build_crt_file("crt1-command", .Obj, .@"wasi crt1-command.o", &[1]Compilation.CSourceFile{
.{
.src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
"libc", try sanitize(arena, crt1_command_src_file),
@ -145,7 +145,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
}
}
try comp.build_crt_file("c", .Lib, libc_sources.items);
try comp.build_crt_file("c", .Lib, .@"wasi libc.a", libc_sources.items);
},
.libwasi_emulated_process_clocks_a => {
var args = std.ArrayList([]const u8).init(arena);
@ -161,7 +161,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
.extra_flags = args.items,
});
}
try comp.build_crt_file("wasi-emulated-process-clocks", .Lib, emu_clocks_sources.items);
try comp.build_crt_file("wasi-emulated-process-clocks", .Lib, .@"libwasi-emulated-process-clocks.a", emu_clocks_sources.items);
},
.libwasi_emulated_getpid_a => {
var args = std.ArrayList([]const u8).init(arena);
@ -177,7 +177,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
.extra_flags = args.items,
});
}
try comp.build_crt_file("wasi-emulated-getpid", .Lib, emu_getpid_sources.items);
try comp.build_crt_file("wasi-emulated-getpid", .Lib, .@"libwasi-emulated-getpid.a", emu_getpid_sources.items);
},
.libwasi_emulated_mman_a => {
var args = std.ArrayList([]const u8).init(arena);
@ -193,7 +193,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
.extra_flags = args.items,
});
}
try comp.build_crt_file("wasi-emulated-mman", .Lib, emu_mman_sources.items);
try comp.build_crt_file("wasi-emulated-mman", .Lib, .@"libwasi-emulated-mman.a", emu_mman_sources.items);
},
.libwasi_emulated_signal_a => {
var emu_signal_sources = std.ArrayList(Compilation.CSourceFile).init(arena);
@ -228,7 +228,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
}
}
try comp.build_crt_file("wasi-emulated-signal", .Lib, emu_signal_sources.items);
try comp.build_crt_file("wasi-emulated-signal", .Lib, .@"libwasi-emulated-signal.a", emu_signal_sources.items);
},
}
}