aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2020-12-04 17:21:55 -0700
committerAndrew Kelley <andrew@ziglang.org>2020-12-04 17:21:55 -0700
commit2ed1ed9b32ae588f6a8997248d69817b5d89a133 (patch)
tree795a5929a71352c469fcd6018bb57ca5a3ebb20c /src
parent1c5606af9fdbfa18fb312a35a73c68515967c94d (diff)
downloadzig-2ed1ed9b32ae588f6a8997248d69817b5d89a133.tar.gz
zig-2ed1ed9b32ae588f6a8997248d69817b5d89a133.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/Compilation.zig107
-rw-r--r--src/Module.zig3
-rw-r--r--src/test.zig109
3 files changed, 168 insertions, 51 deletions
diff --git a/src/Compilation.zig b/src/Compilation.zig
index 2188d7b87a..8efc911796 100644
--- a/src/Compilation.zig
+++ b/src/Compilation.zig
@@ -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;
}
diff --git a/src/Module.zig b/src/Module.zig
index 7ef32abcc3..20cb7bf195 100644
--- a/src/Module.zig
+++ b/src/Module.zig
@@ -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,
diff --git a/src/test.zig b/src/test.zig
index 0d71a6301f..c72c5207f6 100644
--- a/src/test.zig
+++ b/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);
}
}