Skip to content

Commit 7e166a2

Browse files
committed
fix: Correct error message for invalid bytes in strings,
comments, and character literals
1 parent ae5b1a9 commit 7e166a2

8 files changed

+93
-4
lines changed

lib/std/zig/Ast.zig

+17
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,19 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void {
458458
return stream.writeAll("for input is not captured");
459459
},
460460

461+
.invalid_byte => {
462+
const tok_slice = tree.source[tree.tokens.items(.start)[parse_error.token]..];
463+
return stream.print("{s} contains invalid byte: '{'}'", .{
464+
switch (tok_slice[0]) {
465+
'\'' => "character literal",
466+
'"', '\\' => "string literal",
467+
'/' => "comment",
468+
else => unreachable,
469+
},
470+
std.zig.fmtEscapes(tok_slice[parse_error.extra.offset..][0..1]),
471+
});
472+
},
473+
461474
.expected_token => {
462475
const found_tag = token_tags[parse_error.token + @intFromBool(parse_error.token_is_prev)];
463476
const expected_symbol = parse_error.extra.expected_tag.symbol();
@@ -2926,6 +2939,7 @@ pub const Error = struct {
29262939
extra: union {
29272940
none: void,
29282941
expected_tag: Token.Tag,
2942+
offset: usize,
29292943
} = .{ .none = {} },
29302944

29312945
pub const Tag = enum {
@@ -2996,6 +3010,9 @@ pub const Error = struct {
29963010

29973011
/// `expected_tag` is populated.
29983012
expected_token,
3013+
3014+
/// `offset` is populated
3015+
invalid_byte,
29993016
};
30003017
};
30013018

lib/std/zig/AstGen.zig

+33
Original file line numberDiff line numberDiff line change
@@ -13981,6 +13981,39 @@ fn lowerAstErrors(astgen: *AstGen) !void {
1398113981
var notes: std.ArrayListUnmanaged(u32) = .empty;
1398213982
defer notes.deinit(gpa);
1398313983

13984+
const token_starts = tree.tokens.items(.start);
13985+
const token_tags = tree.tokens.items(.tag);
13986+
const parse_err = tree.errors[0];
13987+
const tok = parse_err.token + @intFromBool(parse_err.token_is_prev);
13988+
const tok_start = token_starts[tok];
13989+
const start_char = tree.source[tok_start];
13990+
13991+
if (token_tags[tok] == .invalid and
13992+
(start_char == '\"' or start_char == '\'' or start_char == '/' or mem.startsWith(u8, tree.source[tok_start..], "\\\\")))
13993+
{
13994+
const tok_len: u32 = @intCast(tree.tokenSlice(tok).len);
13995+
const tok_end = tok_start + tok_len;
13996+
const bad_off = blk: {
13997+
var idx = tok_start;
13998+
while (idx < tok_end) : (idx += 1) {
13999+
switch (tree.source[idx]) {
14000+
0x00...0x09, 0x0b...0x1f, 0x7f => break,
14001+
else => {},
14002+
}
14003+
}
14004+
break :blk idx - tok_start;
14005+
};
14006+
14007+
const err: Ast.Error = .{
14008+
.tag = Ast.Error.Tag.invalid_byte,
14009+
.token = tok,
14010+
.extra = .{ .offset = bad_off },
14011+
};
14012+
msg.clearRetainingCapacity();
14013+
try tree.renderError(err, msg.writer(gpa));
14014+
return try astgen.appendErrorTokNotesOff(tok, bad_off, "{s}", .{msg.items}, notes.items);
14015+
}
14016+
1398414017
var cur_err = tree.errors[0];
1398514018
for (tree.errors[1..]) |err| {
1398614019
if (err.is_note) {

test/cases/compile_errors/normal_string_with_newline.zig

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ b";
55
// backend=stage2
66
// target=native
77
//
8-
// :1:13: error: expected expression, found 'invalid token'
8+
// :1:15: error: string literal contains invalid byte: '\n'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// Some comment
2+
export fn entry() void {}
3+
4+
// error
5+
// backend=stage2
6+
// target=native
7+
//
8+
// :1:8: error: comment contains invalid byte: '\t'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/// Some doc comment
2+
export fn entry() void {}
3+
4+
// error
5+
// backend=stage2
6+
// target=native
7+
//
8+
// :1:13: error: comment contains invalid byte: '\t'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
export fn entry() void {
2+
const foo =
3+
\\const S = struct {
4+
\\ // hello
5+
\\}
6+
;
7+
_ = foo;
8+
}
9+
// error
10+
// backend=stage2
11+
// target=native
12+
//
13+
// :4:11: error: string literal contains invalid byte: '\t'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export fn entry() void {
2+
const foo = " hello";
3+
_ = foo;
4+
}
5+
6+
// error
7+
// backend=stage2
8+
// target=native
9+
//
10+
// :2:18: error: string literal contains invalid byte: '\t'

test/compile_errors.zig

+3-3
Original file line numberDiff line numberDiff line change
@@ -217,23 +217,23 @@ pub fn addCases(ctx: *Cases, b: *std.Build) !void {
217217
const case = ctx.obj("invalid byte in string", b.graph.host);
218218

219219
case.addError("_ = \"\x01Q\";", &[_][]const u8{
220-
":1:5: error: expected expression, found 'invalid token'",
220+
":1:6: error: string literal contains invalid byte: '\\x01'",
221221
});
222222
}
223223

224224
{
225225
const case = ctx.obj("invalid byte in comment", b.graph.host);
226226

227227
case.addError("//\x01Q", &[_][]const u8{
228-
":1:1: error: expected type expression, found 'invalid token'",
228+
":1:3: error: comment contains invalid byte: '\\x01'",
229229
});
230230
}
231231

232232
{
233233
const case = ctx.obj("control character in character literal", b.graph.host);
234234

235235
case.addError("const c = '\x01';", &[_][]const u8{
236-
":1:11: error: expected expression, found 'invalid token'",
236+
":1:12: error: character literal contains invalid byte: '\\x01'",
237237
});
238238
}
239239

0 commit comments

Comments
 (0)