authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-07-02 13:26:10-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-07-02 13:28:31-07:00
log5103053977573131d8040a53d9ab3f2afd1b01b0
tree39919ce5c6497f9583f441d73458b1f7fc5c3da3
parentc5c23db6278332044c0606d78419000b68185e0c

compile errors test harness: support unknown file/line/column

This gets us 2 more passing compile error test cases.

3 files changed, 66 insertions(+), 38 deletions(-)

lib/std/fmt.zig+2-2
...@@ -362,8 +362,8 @@ pub fn format(...@@ -362,8 +362,8 @@ pub fn format(
362 const missing_count = arg_state.args_len - @popCount(ArgSetType, arg_state.used_args);362 const missing_count = arg_state.args_len - @popCount(ArgSetType, arg_state.used_args);
363 switch (missing_count) {363 switch (missing_count) {
364 0 => unreachable,364 0 => unreachable,
365 1 => @compileError("Unused argument in \"" ++ fmt ++ "\""),365 1 => @compileError("Unused argument in '" ++ fmt ++ "'"),
366 else => @compileError((comptime comptimePrint("{d}", .{missing_count})) ++ " unused arguments in \"" ++ fmt ++ "\""),366 else => @compileError((comptime comptimePrint("{d}", .{missing_count})) ++ " unused arguments in '" ++ fmt ++ "'"),
367 }367 }
368 }368 }
369}369}
src/test.zig+55-35
...@@ -37,7 +37,11 @@ const ErrorMsg = union(enum) {...@@ -37,7 +37,11 @@ const ErrorMsg = union(enum) {
37 src: struct {37 src: struct {
38 src_path: []const u8,38 src_path: []const u8,
39 msg: []const u8,39 msg: []const u8,
40 // maxint means match anything
41 // this is a workaround for stage1 compiler bug I ran into when making it ?u32
40 line: u32,42 line: u32,
43 // maxint means match anything
44 // this is a workaround for stage1 compiler bug I ran into when making it ?u32
41 column: u32,45 column: u32,
42 kind: Kind,46 kind: Kind,
43 },47 },
...@@ -81,13 +85,23 @@ const ErrorMsg = union(enum) {...@@ -81,13 +85,23 @@ const ErrorMsg = union(enum) {
81 _ = options;85 _ = options;
82 switch (self) {86 switch (self) {
83 .src => |src| {87 .src => |src| {
84 return writer.print("{s}:{d}:{d}: {s}: {s}", .{88 if (!std.mem.eql(u8, src.src_path, "?") or
85 src.src_path,89 src.line != std.math.maxInt(u32) or
86 src.line + 1,90 src.column != std.math.maxInt(u32))
87 src.column + 1,91 {
88 @tagName(src.kind),92 try writer.print("{s}:", .{src.src_path});
89 src.msg,93 if (src.line != std.math.maxInt(u32)) {
90 });94 try writer.print("{d}:", .{src.line + 1});
95 } else {
96 try writer.writeAll("?:");
97 }
98 if (src.column != std.math.maxInt(u32)) {
99 try writer.print("{d}: ", .{src.column + 1});
100 } else {
101 try writer.writeAll("?: ");
102 }
103 }
104 return writer.print("{s}: {s}", .{ @tagName(src.kind), src.msg });
91 },105 },
92 .plain => |plain| {106 .plain => |plain| {
93 return writer.print("{s}: {s}", .{ @tagName(plain.kind), plain.msg });107 return writer.print("{s}: {s}", .{ @tagName(plain.kind), plain.msg });
...@@ -220,8 +234,14 @@ pub const TestContext = struct {...@@ -220,8 +234,14 @@ pub const TestContext = struct {
220 const kind_text = it.next() orelse @panic("missing 'error'/'note'");234 const kind_text = it.next() orelse @panic("missing 'error'/'note'");
221 const msg = it.rest()[1..]; // skip over the space at end of "error: "235 const msg = it.rest()[1..]; // skip over the space at end of "error: "
222236
223 const line = std.fmt.parseInt(u32, line_text, 10) catch @panic("bad line number");237 const line: ?u32 = if (std.mem.eql(u8, line_text, "?"))
224 const column = std.fmt.parseInt(u32, col_text, 10) catch @panic("bad column number");238 null
239 else
240 std.fmt.parseInt(u32, line_text, 10) catch @panic("bad line number");
241 const column: ?u32 = if (std.mem.eql(u8, line_text, "?"))
242 null
243 else
244 std.fmt.parseInt(u32, col_text, 10) catch @panic("bad column number");
225 const kind: ErrorMsg.Kind = if (std.mem.eql(u8, kind_text, " error"))245 const kind: ErrorMsg.Kind = if (std.mem.eql(u8, kind_text, " error"))
226 .@"error"246 .@"error"
227 else if (std.mem.eql(u8, kind_text, " note"))247 else if (std.mem.eql(u8, kind_text, " note"))
...@@ -229,16 +249,28 @@ pub const TestContext = struct {...@@ -229,16 +249,28 @@ pub const TestContext = struct {
229 else249 else
230 @panic("expected 'error'/'note'");250 @panic("expected 'error'/'note'");
231251
232 if (line == 0 or column == 0) {252 const line_0based: u32 = if (line) |n| blk: {
233 @panic("line and column must be specified starting at one");253 if (n == 0) {
234 }254 print("{s}: line must be specified starting at one\n", .{self.name});
255 return;
256 }
257 break :blk n - 1;
258 } else std.math.maxInt(u32);
259
260 const column_0based: u32 = if (column) |n| blk: {
261 if (n == 0) {
262 print("{s}: line must be specified starting at one\n", .{self.name});
263 return;
264 }
265 break :blk n - 1;
266 } else std.math.maxInt(u32);
235267
236 array[i] = .{268 array[i] = .{
237 .src = .{269 .src = .{
238 .src_path = src_path,270 .src_path = src_path,
239 .msg = msg,271 .msg = msg,
240 .line = line - 1,272 .line = line_0based,
241 .column = column - 1,273 .column = column_0based,
242 .kind = kind,274 .kind = kind,
243 },275 },
244 };276 };
...@@ -737,7 +769,7 @@ pub const TestContext = struct {...@@ -737,7 +769,7 @@ pub const TestContext = struct {
737 }769 }
738 var ok = true;770 var ok = true;
739 if (case.expect_exact) {771 if (case.expect_exact) {
740 var err_iter = ErrLineIter.init(result.stderr);772 var err_iter = std.mem.split(result.stderr, "\n");
741 var i: usize = 0;773 var i: usize = 0;
742 ok = while (err_iter.next()) |line| : (i += 1) {774 ok = while (err_iter.next()) |line| : (i += 1) {
743 if (i >= case_error_list.len) break false;775 if (i >= case_error_list.len) break false;
...@@ -940,8 +972,10 @@ pub const TestContext = struct {...@@ -940,8 +972,10 @@ pub const TestContext = struct {
940 std.mem.eql(u8, case_msg.src.src_path, actual_msg.src_path);972 std.mem.eql(u8, case_msg.src.src_path, actual_msg.src_path);
941973
942 if (src_path_ok and974 if (src_path_ok and
943 actual_msg.line == case_msg.src.line and975 (case_msg.src.line == std.math.maxInt(u32) or
944 actual_msg.column == case_msg.src.column and976 actual_msg.line == case_msg.src.line) and
977 (case_msg.src.column == std.math.maxInt(u32) or
978 actual_msg.column == case_msg.src.column) and
945 std.mem.eql(u8, case_msg.src.msg, actual_msg.msg) and979 std.mem.eql(u8, case_msg.src.msg, actual_msg.msg) and
946 case_msg.src.kind == .@"error")980 case_msg.src.kind == .@"error")
947 {981 {
...@@ -978,8 +1012,10 @@ pub const TestContext = struct {...@@ -978,8 +1012,10 @@ pub const TestContext = struct {
978 }1012 }
979 if (ex_tag != .src) continue;1013 if (ex_tag != .src) continue;
9801014
981 if (actual_msg.line == case_msg.src.line and1015 if ((case_msg.src.line == std.math.maxInt(u32) or
982 actual_msg.column == case_msg.src.column and1016 actual_msg.line == case_msg.src.line) and
1017 (case_msg.src.column == std.math.maxInt(u32) or
1018 actual_msg.column == case_msg.src.column) and
983 std.mem.eql(u8, case_msg.src.msg, actual_msg.msg) and1019 std.mem.eql(u8, case_msg.src.msg, actual_msg.msg) and
984 case_msg.src.kind == .note)1020 case_msg.src.kind == .note)
985 {1021 {
...@@ -1162,19 +1198,3 @@ fn dumpArgs(argv: []const []const u8) void {...@@ -1162,19 +1198,3 @@ fn dumpArgs(argv: []const []const u8) void {
1162}1198}
11631199
1164const tmp_src_path = "tmp.zig";1200const tmp_src_path = "tmp.zig";
1165
1166const ErrLineIter = struct {
1167 lines: std.mem.SplitIterator,
1168
1169 fn init(input: []const u8) ErrLineIter {
1170 return ErrLineIter{ .lines = std.mem.split(input, "\n") };
1171 }
1172
1173 fn next(self: *ErrLineIter) ?[]const u8 {
1174 while (self.lines.next()) |line| {
1175 if (std.mem.indexOf(u8, line, tmp_src_path) != null)
1176 return line;
1177 }
1178 return null;
1179 }
1180};
test/compile_errors.zig+9-1
...@@ -2,6 +2,14 @@ const std = @import("std");...@@ -2,6 +2,14 @@ const std = @import("std");
2const TestContext = @import("../src/test.zig").TestContext;2const TestContext = @import("../src/test.zig").TestContext;
33
4pub fn addCases(ctx: *TestContext) !void {4pub fn addCases(ctx: *TestContext) !void {
5 ctx.exeErrStage1("std.fmt error for unused arguments",
6 \\pub fn main() !void {
7 \\ @import("std").debug.print("{d} {d} {d} {d} {d}", .{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15});
8 \\}
9 , &.{
10 "?:?:?: error: 10 unused arguments in '{d} {d} {d} {d} {d}'",
11 });
12
5 ctx.objErrStage1("lazy pointer with undefined element type",13 ctx.objErrStage1("lazy pointer with undefined element type",
6 \\export fn foo() void {14 \\export fn foo() void {
7 \\ comptime var T: type = undefined;15 \\ comptime var T: type = undefined;
...@@ -6120,7 +6128,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -6120,7 +6128,7 @@ pub fn addCases(ctx: *TestContext) !void {
6120 \\6128 \\
6121 \\export fn entry() usize { return @sizeOf(@TypeOf(resource)); }6129 \\export fn entry() usize { return @sizeOf(@TypeOf(resource)); }
6122 , &[_][]const u8{6130 , &[_][]const u8{
6123 "tmp.zig:1:29: error: unable to find 'bogus.txt'",6131 "tmp.zig:1:29: error: unable to find '",
6124 });6132 });
61256133
6126 ctx.objErrStage1("non-const expression in struct literal outside function",6134 ctx.objErrStage1("non-const expression in struct literal outside function",