stage2: introduce Module.failed_root_source_file
Use case: zig build-exe non_existent_file.zig Previous behavior: error.FileNotFound, followed by an error return trace Behavior after this commit: error: unable to read non_existent_file.zig: FileNotFound (end of stderr, exit code 1) This turns AllErrors.Message into a tagged union which now has the capability to represent both "plain" errors as well as source-based errors (with file, line, column, byte offset). The "no entry point found" error has moved to be a plain error message.
This commit is contained in:
parent
1c5606af9f
commit
2ed1ed9b32
@ -226,20 +226,32 @@ pub const AllErrors = struct {
|
||||
arena: std.heap.ArenaAllocator.State,
|
||||
list: []const Message,
|
||||
|
||||
pub const Message = struct {
|
||||
src_path: []const u8,
|
||||
line: usize,
|
||||
column: usize,
|
||||
byte_offset: usize,
|
||||
msg: []const u8,
|
||||
pub const Message = union(enum) {
|
||||
src: struct {
|
||||
src_path: []const u8,
|
||||
line: usize,
|
||||
column: usize,
|
||||
byte_offset: usize,
|
||||
msg: []const u8,
|
||||
},
|
||||
plain: struct {
|
||||
msg: []const u8,
|
||||
},
|
||||
|
||||
pub fn renderToStdErr(self: Message) void {
|
||||
std.debug.print("{}:{}:{}: error: {}\n", .{
|
||||
self.src_path,
|
||||
self.line + 1,
|
||||
self.column + 1,
|
||||
self.msg,
|
||||
});
|
||||
switch (self) {
|
||||
.src => |src| {
|
||||
std.debug.print("{s}:{d}:{d}: error: {s}\n", .{
|
||||
src.src_path,
|
||||
src.line + 1,
|
||||
src.column + 1,
|
||||
src.msg,
|
||||
});
|
||||
},
|
||||
.plain => |plain| {
|
||||
std.debug.print("error: {s}\n", .{plain.msg});
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -256,13 +268,23 @@ pub const AllErrors = struct {
|
||||
) !void {
|
||||
const loc = std.zig.findLineColumn(source, simple_err_msg.byte_offset);
|
||||
try errors.append(.{
|
||||
.src_path = try arena.allocator.dupe(u8, sub_file_path),
|
||||
.msg = try arena.allocator.dupe(u8, simple_err_msg.msg),
|
||||
.byte_offset = simple_err_msg.byte_offset,
|
||||
.line = loc.line,
|
||||
.column = loc.column,
|
||||
.src = .{
|
||||
.src_path = try arena.allocator.dupe(u8, sub_file_path),
|
||||
.msg = try arena.allocator.dupe(u8, simple_err_msg.msg),
|
||||
.byte_offset = simple_err_msg.byte_offset,
|
||||
.line = loc.line,
|
||||
.column = loc.column,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
fn addPlain(
|
||||
arena: *std.heap.ArenaAllocator,
|
||||
errors: *std.ArrayList(Message),
|
||||
msg: []const u8,
|
||||
) !void {
|
||||
try errors.append(.{ .plain = .{ .msg = msg } });
|
||||
}
|
||||
};
|
||||
|
||||
pub const Directory = struct {
|
||||
@ -1169,11 +1191,15 @@ pub fn update(self: *Compilation) !void {
|
||||
// to force a refresh we unload now.
|
||||
if (module.root_scope.cast(Module.Scope.File)) |zig_file| {
|
||||
zig_file.unload(module.gpa);
|
||||
module.failed_root_src_file = null;
|
||||
module.analyzeContainer(&zig_file.root_container) catch |err| switch (err) {
|
||||
error.AnalysisFail => {
|
||||
assert(self.totalErrorCount() != 0);
|
||||
},
|
||||
else => |e| return e,
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
else => |e| {
|
||||
module.failed_root_src_file = e;
|
||||
},
|
||||
};
|
||||
} else if (module.root_scope.cast(Module.Scope.ZIRModule)) |zir_module| {
|
||||
zir_module.unload(module.gpa);
|
||||
@ -1251,7 +1277,8 @@ pub fn totalErrorCount(self: *Compilation) usize {
|
||||
if (self.bin_file.options.module) |module| {
|
||||
total += module.failed_decls.items().len +
|
||||
module.failed_exports.items().len +
|
||||
module.failed_files.items().len;
|
||||
module.failed_files.items().len +
|
||||
@boolToInt(module.failed_root_src_file != null);
|
||||
}
|
||||
|
||||
// The "no entry point found" error only counts if there are no other errors.
|
||||
@ -1293,21 +1320,22 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
|
||||
const source = try decl.scope.getSource(module);
|
||||
try AllErrors.add(&arena, &errors, decl.scope.subFilePath(), source, err_msg.*);
|
||||
}
|
||||
if (module.failed_root_src_file) |err| {
|
||||
const file_path = try module.root_pkg.root_src_directory.join(&arena.allocator, &[_][]const u8{
|
||||
module.root_pkg.root_src_path,
|
||||
});
|
||||
const msg = try std.fmt.allocPrint(&arena.allocator, "unable to read {s}: {s}", .{
|
||||
file_path, @errorName(err),
|
||||
});
|
||||
try AllErrors.addPlain(&arena, &errors, msg);
|
||||
}
|
||||
}
|
||||
|
||||
if (errors.items.len == 0 and self.link_error_flags.no_entry_point_found) {
|
||||
const global_err_src_path = blk: {
|
||||
if (self.bin_file.options.module) |module| break :blk module.root_pkg.root_src_path;
|
||||
if (self.c_source_files.len != 0) break :blk self.c_source_files[0].src_path;
|
||||
if (self.bin_file.options.objects.len != 0) break :blk self.bin_file.options.objects[0];
|
||||
break :blk "(no file)";
|
||||
};
|
||||
try errors.append(.{
|
||||
.src_path = global_err_src_path,
|
||||
.line = 0,
|
||||
.column = 0,
|
||||
.byte_offset = 0,
|
||||
.msg = try std.fmt.allocPrint(&arena.allocator, "no entry point found", .{}),
|
||||
.plain = .{
|
||||
.msg = try std.fmt.allocPrint(&arena.allocator, "no entry point found", .{}),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@ -2644,12 +2672,19 @@ pub fn updateSubCompilation(sub_compilation: *Compilation) !void {
|
||||
|
||||
if (errors.list.len != 0) {
|
||||
for (errors.list) |full_err_msg| {
|
||||
log.err("{}:{}:{}: {}\n", .{
|
||||
full_err_msg.src_path,
|
||||
full_err_msg.line + 1,
|
||||
full_err_msg.column + 1,
|
||||
full_err_msg.msg,
|
||||
});
|
||||
switch (full_err_msg) {
|
||||
.src => |src| {
|
||||
log.err("{s}:{d}:{d}: {s}\n", .{
|
||||
src.src_path,
|
||||
src.line + 1,
|
||||
src.column + 1,
|
||||
src.msg,
|
||||
});
|
||||
},
|
||||
.plain => |plain| {
|
||||
log.err("{s}", .{plain.msg});
|
||||
},
|
||||
}
|
||||
}
|
||||
return error.BuildingLibCObjectFailed;
|
||||
}
|
||||
|
@ -78,6 +78,9 @@ import_table: std.StringArrayHashMapUnmanaged(*Scope.File) = .{},
|
||||
/// previous analysis.
|
||||
generation: u32 = 0,
|
||||
|
||||
/// When populated it means there was an error opening/reading the root source file.
|
||||
failed_root_src_file: ?anyerror = null,
|
||||
|
||||
stage1_flags: packed struct {
|
||||
have_winmain: bool = false,
|
||||
have_wwinmain: bool = false,
|
||||
|
109
src/test.zig
109
src/test.zig
@ -22,10 +22,52 @@ test "self-hosted" {
|
||||
try ctx.run();
|
||||
}
|
||||
|
||||
const ErrorMsg = struct {
|
||||
msg: []const u8,
|
||||
line: u32,
|
||||
column: u32,
|
||||
const ErrorMsg = union(enum) {
|
||||
src: struct {
|
||||
msg: []const u8,
|
||||
line: u32,
|
||||
column: u32,
|
||||
},
|
||||
plain: struct {
|
||||
msg: []const u8,
|
||||
},
|
||||
|
||||
fn init(other: Compilation.AllErrors.Message) ErrorMsg {
|
||||
switch (other) {
|
||||
.src => |src| return .{
|
||||
.src = .{
|
||||
.msg = src.msg,
|
||||
.line = @intCast(u32, src.line),
|
||||
.column = @intCast(u32, src.column),
|
||||
},
|
||||
},
|
||||
.plain => |plain| return .{
|
||||
.plain = .{
|
||||
.msg = plain.msg,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn format(
|
||||
self: ErrorMsg,
|
||||
comptime fmt: []const u8,
|
||||
options: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) !void {
|
||||
switch (self) {
|
||||
.src => |src| {
|
||||
return writer.print(":{d}:{d}: error: {s}", .{
|
||||
src.line + 1,
|
||||
src.column + 1,
|
||||
src.msg,
|
||||
});
|
||||
},
|
||||
.plain => |plain| {
|
||||
return writer.print("error: {s}", .{plain.msg});
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
pub const TestContext = struct {
|
||||
@ -112,7 +154,8 @@ pub const TestContext = struct {
|
||||
var array = self.updates.allocator.alloc(ErrorMsg, errors.len) catch unreachable;
|
||||
for (errors) |e, i| {
|
||||
if (e[0] != ':') {
|
||||
@panic("Invalid test: error must be specified as follows:\n:line:column: error: message\n=========\n");
|
||||
array[i] = .{ .plain = .{ .msg = e } };
|
||||
continue;
|
||||
}
|
||||
var cur = e[1..];
|
||||
var line_index = std.mem.indexOf(u8, cur, ":");
|
||||
@ -137,9 +180,11 @@ pub const TestContext = struct {
|
||||
}
|
||||
|
||||
array[i] = .{
|
||||
.msg = msg,
|
||||
.line = line - 1,
|
||||
.column = column - 1,
|
||||
.src = .{
|
||||
.msg = msg,
|
||||
.line = line - 1,
|
||||
.column = column - 1,
|
||||
},
|
||||
};
|
||||
}
|
||||
self.updates.append(.{ .src = src, .case = .{ .Error = array } }) catch unreachable;
|
||||
@ -544,8 +589,17 @@ pub const TestContext = struct {
|
||||
defer all_errors.deinit(allocator);
|
||||
if (all_errors.list.len != 0) {
|
||||
std.debug.print("\nErrors occurred updating the compilation:\n================\n", .{});
|
||||
for (all_errors.list) |err| {
|
||||
std.debug.print(":{}:{}: error: {}\n================\n", .{ err.line + 1, err.column + 1, err.msg });
|
||||
for (all_errors.list) |err_msg| {
|
||||
switch (err_msg) {
|
||||
.src => |src| {
|
||||
std.debug.print(":{d}:{d}: error: {s}\n================\n", .{
|
||||
src.line + 1, src.column + 1, src.msg,
|
||||
});
|
||||
},
|
||||
.plain => |plain| {
|
||||
std.debug.print("error: {s}\n================\n", .{plain.msg});
|
||||
},
|
||||
}
|
||||
}
|
||||
if (case.cbe) {
|
||||
const C = comp.bin_file.cast(link.File.C).?;
|
||||
@ -618,12 +672,34 @@ pub const TestContext = struct {
|
||||
defer all_errors.deinit(allocator);
|
||||
for (all_errors.list) |a| {
|
||||
for (e) |ex, i| {
|
||||
if (a.line == ex.line and a.column == ex.column and std.mem.eql(u8, ex.msg, a.msg)) {
|
||||
handled_errors[i] = true;
|
||||
break;
|
||||
const a_tag: @TagType(@TypeOf(a)) = a;
|
||||
const ex_tag: @TagType(@TypeOf(ex)) = ex;
|
||||
switch (a) {
|
||||
.src => |src| {
|
||||
if (ex_tag != .src) continue;
|
||||
|
||||
if (src.line == ex.src.line and
|
||||
src.column == ex.src.column and
|
||||
std.mem.eql(u8, ex.src.msg, src.msg))
|
||||
{
|
||||
handled_errors[i] = true;
|
||||
break;
|
||||
}
|
||||
},
|
||||
.plain => |plain| {
|
||||
if (ex_tag != .plain) continue;
|
||||
|
||||
if (std.mem.eql(u8, ex.plain.msg, plain.msg)) {
|
||||
handled_errors[i] = true;
|
||||
break;
|
||||
}
|
||||
},
|
||||
}
|
||||
} else {
|
||||
std.debug.print("{}\nUnexpected error:\n================\n:{}:{}: error: {}\n================\nTest failed.\n", .{ case.name, a.line + 1, a.column + 1, a.msg });
|
||||
std.debug.print(
|
||||
"{s}\nUnexpected error:\n================\n{}\n================\nTest failed.\n",
|
||||
.{ case.name, ErrorMsg.init(a) },
|
||||
);
|
||||
std.process.exit(1);
|
||||
}
|
||||
}
|
||||
@ -631,7 +707,10 @@ pub const TestContext = struct {
|
||||
for (handled_errors) |h, i| {
|
||||
if (!h) {
|
||||
const er = e[i];
|
||||
std.debug.print("{}\nDid not receive error:\n================\n{}:{}: {}\n================\nTest failed.\n", .{ case.name, er.line, er.column, er.msg });
|
||||
std.debug.print(
|
||||
"{s}\nDid not receive error:\n================\n{}\n================\nTest failed.\n",
|
||||
.{ case.name, er },
|
||||
);
|
||||
std.process.exit(1);
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ pub fn addCases(ctx: *TestContext) !void {
|
||||
{
|
||||
var case = ctx.exe("hello world with updates", linux_x64);
|
||||
|
||||
case.addError("", &[_][]const u8{":1:1: error: no entry point found"});
|
||||
case.addError("", &[_][]const u8{"no entry point found"});
|
||||
|
||||
// Incorrect return type
|
||||
case.addError(
|
||||
@ -147,7 +147,7 @@ pub fn addCases(ctx: *TestContext) !void {
|
||||
|
||||
{
|
||||
var case = ctx.exe("hello world with updates", macosx_x64);
|
||||
case.addError("", &[_][]const u8{":1:1: error: no entry point found"});
|
||||
case.addError("", &[_][]const u8{"no entry point found"});
|
||||
|
||||
// Incorrect return type
|
||||
case.addError(
|
||||
|
Loading…
x
Reference in New Issue
Block a user