authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-07-01 00:14:58-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-07-02 13:27:35-07:00
log24c432608f6b07020fa0b18fc9c868ad6abd9b15
treef9650d8c9aa36d6fddd45b1f70847304da16c0f5
parent3f680abbe2c4d2eeefd0eb73b8af25d1768e6ceb

stage2: improve compile errors from tokenizer

In order to not regress the quality of compile errors, some improvements had to be made. * std.zig.parseCharLiteral is improved to return more detailed parse failure information. * tokenizer is improved to handle null bytes in the middle of strings, character literals, and line comments. * validating how many unicode escape digits in string literals is moved to std.zig.parseStringLiteral rather than handled in the tokenizer. * when a tokenizer error occurs, if the reported token is the 'invalid' tag, an error note is added to point to the invalid byte location. Further improvements would be: - Mention the expected set of allowed bytes at this location. - Display the invalid byte (if printable, print it, otherwise escape-print it).

6 files changed, 306 insertions(+), 103 deletions(-)

lib/std/zig.zig+147-56
......@@ -6,6 +6,7 @@
66const std = @import("std.zig");
77const tokenizer = @import("zig/tokenizer.zig");
88const fmt = @import("zig/fmt.zig");
9const assert = std.debug.assert;
910
1011pub const Token = tokenizer.Token;
1112pub const Tokenizer = tokenizer.Tokenizer;
......@@ -183,29 +184,48 @@ pub fn binNameAlloc(allocator: *std.mem.Allocator, options: BinNameOptions) erro
183184 }
184185}
185186
187pub const ParsedCharLiteral = union(enum) {
188 success: u32,
189 /// The character after backslash is not recognized.
190 invalid_escape_character: usize,
191 /// Expected hex digit at this index.
192 expected_hex_digit: usize,
193 /// Unicode escape sequence had no digits with rbrace at this index.
194 empty_unicode_escape_sequence: usize,
195 /// Expected hex digit or '}' at this index.
196 expected_hex_digit_or_rbrace: usize,
197 /// The unicode point is outside the range of Unicode codepoints.
198 unicode_escape_overflow: usize,
199 /// Expected '{' at this index.
200 expected_lbrace: usize,
201 /// Expected the terminating single quote at this index.
202 expected_end: usize,
203 /// The character at this index cannot be represented without an escape sequence.
204 invalid_character: usize,
205};
206
186207/// Only validates escape sequence characters.
187208/// Slice must be valid utf8 starting and ending with "'" and exactly one codepoint in between.
188pub fn parseCharLiteral(
189 slice: []const u8,
190 bad_index: *usize, // populated if error.InvalidCharacter is returned
191) error{InvalidCharacter}!u32 {
192 std.debug.assert(slice.len >= 3 and slice[0] == '\'' and slice[slice.len - 1] == '\'');
209pub fn parseCharLiteral(slice: []const u8) ParsedCharLiteral {
210 assert(slice.len >= 3 and slice[0] == '\'' and slice[slice.len - 1] == '\'');
193211
194 if (slice[1] == '\\') {
195 switch (slice[2]) {
196 'n' => return '\n',
197 'r' => return '\r',
198 '\\' => return '\\',
199 't' => return '\t',
200 '\'' => return '\'',
201 '"' => return '"',
212 switch (slice[1]) {
213 0 => return .{ .invalid_character = 1 },
214 '\\' => switch (slice[2]) {
215 'n' => return .{ .success = '\n' },
216 'r' => return .{ .success = '\r' },
217 '\\' => return .{ .success = '\\' },
218 't' => return .{ .success = '\t' },
219 '\'' => return .{ .success = '\'' },
220 '"' => return .{ .success = '"' },
202221 'x' => {
203 if (slice.len != 6) {
204 bad_index.* = slice.len - 2;
205 return error.InvalidCharacter;
222 if (slice.len < 4) {
223 return .{ .expected_hex_digit = 3 };
206224 }
207225 var value: u32 = 0;
208 for (slice[3..5]) |c, i| {
226 var i: usize = 3;
227 while (i < 5) : (i += 1) {
228 const c = slice[i];
209229 switch (c) {
210230 '0'...'9' => {
211231 value *= 16;
......@@ -220,20 +240,28 @@ pub fn parseCharLiteral(
220240 value += c - 'A' + 10;
221241 },
222242 else => {
223 bad_index.* = 3 + i;
224 return error.InvalidCharacter;
243 return .{ .expected_hex_digit = i };
225244 },
226245 }
227246 }
228 return value;
247 if (slice[i] != '\'') {
248 return .{ .expected_end = i };
249 }
250 return .{ .success = value };
229251 },
230252 'u' => {
231 if (slice.len < "'\\u{0}'".len or slice[3] != '{' or slice[slice.len - 2] != '}') {
232 bad_index.* = 2;
233 return error.InvalidCharacter;
253 var i: usize = 3;
254 if (slice[i] != '{') {
255 return .{ .expected_lbrace = i };
234256 }
257 i += 1;
258 if (slice[i] == '}') {
259 return .{ .empty_unicode_escape_sequence = i };
260 }
261
235262 var value: u32 = 0;
236 for (slice[4 .. slice.len - 2]) |c, i| {
263 while (i < slice.len) : (i += 1) {
264 const c = slice[i];
237265 switch (c) {
238266 '0'...'9' => {
239267 value *= 16;
......@@ -247,49 +275,112 @@ pub fn parseCharLiteral(
247275 value *= 16;
248276 value += c - 'A' + 10;
249277 },
250 else => {
251 bad_index.* = 4 + i;
252 return error.InvalidCharacter;
278 '}' => {
279 i += 1;
280 break;
253281 },
282 else => return .{ .expected_hex_digit_or_rbrace = i },
254283 }
255284 if (value > 0x10ffff) {
256 bad_index.* = 4 + i;
257 return error.InvalidCharacter;
285 return .{ .unicode_escape_overflow = i };
258286 }
259287 }
260 return value;
261 },
262 else => {
263 bad_index.* = 2;
264 return error.InvalidCharacter;
288 if (slice[i] != '\'') {
289 return .{ .expected_end = i };
290 }
291 return .{ .success = value };
265292 },
266 }
293 else => return .{ .invalid_escape_character = 2 },
294 },
295 else => {
296 const codepoint = std.unicode.utf8Decode(slice[1 .. slice.len - 1]) catch unreachable;
297 return .{ .success = codepoint };
298 },
267299 }
268 return std.unicode.utf8Decode(slice[1 .. slice.len - 1]) catch unreachable;
269300}
270301
271302test "parseCharLiteral" {
272 var bad_index: usize = undefined;
273 try std.testing.expectEqual(try parseCharLiteral("'a'", &bad_index), 'a');
274 try std.testing.expectEqual(try parseCharLiteral("'ä'", &bad_index), 'ä');
275 try std.testing.expectEqual(try parseCharLiteral("'\\x00'", &bad_index), 0);
276 try std.testing.expectEqual(try parseCharLiteral("'\\x4f'", &bad_index), 0x4f);
277 try std.testing.expectEqual(try parseCharLiteral("'\\x4F'", &bad_index), 0x4f);
278 try std.testing.expectEqual(try parseCharLiteral("'ぁ'", &bad_index), 0x3041);
279 try std.testing.expectEqual(try parseCharLiteral("'\\u{0}'", &bad_index), 0);
280 try std.testing.expectEqual(try parseCharLiteral("'\\u{3041}'", &bad_index), 0x3041);
281 try std.testing.expectEqual(try parseCharLiteral("'\\u{7f}'", &bad_index), 0x7f);
282 try std.testing.expectEqual(try parseCharLiteral("'\\u{7FFF}'", &bad_index), 0x7FFF);
303 try std.testing.expectEqual(
304 ParsedCharLiteral{ .success = 'a' },
305 parseCharLiteral("'a'"),
306 );
307 try std.testing.expectEqual(
308 ParsedCharLiteral{ .success = 'ä' },
309 parseCharLiteral("'ä'"),
310 );
311 try std.testing.expectEqual(
312 ParsedCharLiteral{ .success = 0 },
313 parseCharLiteral("'\\x00'"),
314 );
315 try std.testing.expectEqual(
316 ParsedCharLiteral{ .success = 0x4f },
317 parseCharLiteral("'\\x4f'"),
318 );
319 try std.testing.expectEqual(
320 ParsedCharLiteral{ .success = 0x4f },
321 parseCharLiteral("'\\x4F'"),
322 );
323 try std.testing.expectEqual(
324 ParsedCharLiteral{ .success = 0x3041 },
325 parseCharLiteral("'ぁ'"),
326 );
327 try std.testing.expectEqual(
328 ParsedCharLiteral{ .success = 0 },
329 parseCharLiteral("'\\u{0}'"),
330 );
331 try std.testing.expectEqual(
332 ParsedCharLiteral{ .success = 0x3041 },
333 parseCharLiteral("'\\u{3041}'"),
334 );
335 try std.testing.expectEqual(
336 ParsedCharLiteral{ .success = 0x7f },
337 parseCharLiteral("'\\u{7f}'"),
338 );
339 try std.testing.expectEqual(
340 ParsedCharLiteral{ .success = 0x7fff },
341 parseCharLiteral("'\\u{7FFF}'"),
342 );
283343
284 try std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\x0'", &bad_index));
285 try std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\x000'", &bad_index));
286 try std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\y'", &bad_index));
287 try std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\u'", &bad_index));
288 try std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\uFFFF'", &bad_index));
289 try std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\u{}'", &bad_index));
290 try std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\u{FFFFFF}'", &bad_index));
291 try std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\u{FFFF'", &bad_index));
292 try std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\u{FFFF}x'", &bad_index));
344 try std.testing.expectEqual(
345 ParsedCharLiteral{ .expected_hex_digit = 4 },
346 parseCharLiteral("'\\x0'"),
347 );
348 try std.testing.expectEqual(
349 ParsedCharLiteral{ .expected_end = 5 },
350 parseCharLiteral("'\\x000'"),
351 );
352 try std.testing.expectEqual(
353 ParsedCharLiteral{ .invalid_escape_character = 2 },
354 parseCharLiteral("'\\y'"),
355 );
356 try std.testing.expectEqual(
357 ParsedCharLiteral{ .expected_lbrace = 3 },
358 parseCharLiteral("'\\u'"),
359 );
360 try std.testing.expectEqual(
361 ParsedCharLiteral{ .expected_lbrace = 3 },
362 parseCharLiteral("'\\uFFFF'"),
363 );
364 try std.testing.expectEqual(
365 ParsedCharLiteral{ .empty_unicode_escape_sequence = 4 },
366 parseCharLiteral("'\\u{}'"),
367 );
368 try std.testing.expectEqual(
369 ParsedCharLiteral{ .unicode_escape_overflow = 9 },
370 parseCharLiteral("'\\u{FFFFFF}'"),
371 );
372 try std.testing.expectEqual(
373 ParsedCharLiteral{ .expected_hex_digit_or_rbrace = 8 },
374 parseCharLiteral("'\\u{FFFF'"),
375 );
376 try std.testing.expectEqual(
377 ParsedCharLiteral{ .expected_end = 9 },
378 parseCharLiteral("'\\u{FFFF}x'"),
379 );
380 try std.testing.expectEqual(
381 ParsedCharLiteral{ .invalid_character = 1 },
382 parseCharLiteral("'\x00'"),
383 );
293384}
294385
295386test {
lib/std/zig/tokenizer.zig+25-18
......@@ -701,12 +701,19 @@ pub const Tokenizer = struct {
701701 self.index += 1;
702702 break;
703703 },
704 0, '\n', '\r' => break, // Look for this error later.
704 0 => {
705 if (self.index == self.buffer.len) {
706 break;
707 } else {
708 self.checkLiteralCharacter();
709 }
710 },
711 '\n', '\r' => break, // Look for this error later.
705712 else => self.checkLiteralCharacter(),
706713 },
707714
708715 .string_literal_backslash => switch (c) {
709 0, '\n', '\r' => break, // Look for this error later.
716 '\n', '\r' => break, // Look for this error later.
710717 else => {
711718 state = .string_literal;
712719 },
......@@ -774,7 +781,6 @@ pub const Tokenizer = struct {
774781 .char_literal_unicode_escape_saw_u => switch (c) {
775782 '{' => {
776783 state = .char_literal_unicode_escape;
777 seen_escape_digits = 0;
778784 },
779785 else => {
780786 result.tag = .invalid;
......@@ -783,16 +789,9 @@ pub const Tokenizer = struct {
783789 },
784790
785791 .char_literal_unicode_escape => switch (c) {
786 '0'...'9', 'a'...'f', 'A'...'F' => {
787 seen_escape_digits += 1;
788 },
792 '0'...'9', 'a'...'f', 'A'...'F' => {},
789793 '}' => {
790 if (seen_escape_digits == 0) {
791 result.tag = .invalid;
792 state = .char_literal_unicode_invalid;
793 } else {
794 state = .char_literal_end;
795 }
794 state = .char_literal_end; // too many/few digits handled later
796795 },
797796 else => {
798797 result.tag = .invalid;
......@@ -1026,7 +1025,13 @@ pub const Tokenizer = struct {
10261025 },
10271026 },
10281027 .line_comment_start => switch (c) {
1029 0 => break,
1028 0 => {
1029 if (self.index != self.buffer.len) {
1030 result.tag = .invalid;
1031 self.index += 1;
1032 }
1033 break;
1034 },
10301035 '/' => {
10311036 state = .doc_comment_start;
10321037 },
......@@ -1441,7 +1446,7 @@ test "tokenizer - code point literal with unicode escapes" {
14411446 , &.{ .invalid, .invalid });
14421447 try testTokenize(
14431448 \\'\u{}'
1444 , &.{ .invalid, .invalid });
1449 , &.{.char_literal});
14451450 try testTokenize(
14461451 \\'\u{s}'
14471452 , &.{ .invalid, .invalid });
......@@ -1924,15 +1929,17 @@ test "tokenizer - invalid builtin identifiers" {
19241929 try testTokenize("@0()", &.{ .invalid, .integer_literal, .l_paren, .r_paren });
19251930}
19261931
1927fn testTokenize(source: []const u8, expected_tokens: []const Token.Tag) !void {
1932fn testTokenize(source: [:0]const u8, expected_tokens: []const Token.Tag) !void {
19281933 var tokenizer = Tokenizer.init(source);
19291934 for (expected_tokens) |expected_token_id| {
19301935 const token = tokenizer.next();
19311936 if (token.tag != expected_token_id) {
1932 std.debug.panic("expected {s}, found {s}\n", .{ @tagName(expected_token_id), @tagName(token.tag) });
1937 std.debug.panic("expected {s}, found {s}\n", .{
1938 @tagName(expected_token_id), @tagName(token.tag),
1939 });
19331940 }
19341941 }
19351942 const last_token = tokenizer.next();
1936 try std.testing.expect(last_token.tag == .eof);
1937 try std.testing.expect(last_token.loc.start == source.len);
1943 try std.testing.expectEqual(Token.Tag.eof, last_token.tag);
1944 try std.testing.expectEqual(source.len, last_token.loc.start);
19381945}
src/AstGen.zig+65-9
......@@ -6380,20 +6380,76 @@ fn charLiteral(gz: *GenZir, rl: ResultLoc, node: ast.Node.Index) !Zir.Inst.Ref {
63806380 const main_token = main_tokens[node];
63816381 const slice = tree.tokenSlice(main_token);
63826382
6383 var bad_index: usize = undefined;
6384 const value = std.zig.parseCharLiteral(slice, &bad_index) catch |err| switch (err) {
6385 error.InvalidCharacter => {
6386 const bad_byte = slice[bad_index];
6383 switch (std.zig.parseCharLiteral(slice)) {
6384 .success => |codepoint| {
6385 const result = try gz.addInt(codepoint);
6386 return rvalue(gz, rl, result, node);
6387 },
6388 .invalid_escape_character => |bad_index| {
63876389 return astgen.failOff(
63886390 main_token,
63896391 @intCast(u32, bad_index),
6390 "invalid character: '{c}'\n",
6391 .{bad_byte},
6392 "invalid escape character: '{c}'",
6393 .{slice[bad_index]},
63926394 );
63936395 },
6394 };
6395 const result = try gz.addInt(value);
6396 return rvalue(gz, rl, result, node);
6396 .expected_hex_digit => |bad_index| {
6397 return astgen.failOff(
6398 main_token,
6399 @intCast(u32, bad_index),
6400 "expected hex digit, found '{c}'",
6401 .{slice[bad_index]},
6402 );
6403 },
6404 .empty_unicode_escape_sequence => |bad_index| {
6405 return astgen.failOff(
6406 main_token,
6407 @intCast(u32, bad_index),
6408 "empty unicode escape sequence",
6409 .{},
6410 );
6411 },
6412 .expected_hex_digit_or_rbrace => |bad_index| {
6413 return astgen.failOff(
6414 main_token,
6415 @intCast(u32, bad_index),
6416 "expected hex digit or '}}', found '{c}'",
6417 .{slice[bad_index]},
6418 );
6419 },
6420 .unicode_escape_overflow => |bad_index| {
6421 return astgen.failOff(
6422 main_token,
6423 @intCast(u32, bad_index),
6424 "unicode escape too large to be a valid codepoint",
6425 .{},
6426 );
6427 },
6428 .expected_lbrace => |bad_index| {
6429 return astgen.failOff(
6430 main_token,
6431 @intCast(u32, bad_index),
6432 "expected '{{', found '{c}",
6433 .{slice[bad_index]},
6434 );
6435 },
6436 .expected_end => |bad_index| {
6437 return astgen.failOff(
6438 main_token,
6439 @intCast(u32, bad_index),
6440 "expected ending single quote ('), found '{c}",
6441 .{slice[bad_index]},
6442 );
6443 },
6444 .invalid_character => |bad_index| {
6445 return astgen.failOff(
6446 main_token,
6447 @intCast(u32, bad_index),
6448 "invalid byte in character literal: '{c}'",
6449 .{slice[bad_index]},
6450 );
6451 },
6452 }
63976453}
63986454
63996455fn integerLiteral(gz: *GenZir, rl: ResultLoc, node: ast.Node.Index) InnerError!Zir.Inst.Ref {
src/Module.zig+9
......@@ -2466,6 +2466,7 @@ pub fn astGenFile(mod: *Module, file: *Scope.File) !void {
24662466 defer msg.deinit();
24672467
24682468 const token_starts = file.tree.tokens.items(.start);
2469 const token_tags = file.tree.tokens.items(.tag);
24692470
24702471 try file.tree.renderError(parse_err, msg.writer());
24712472 const err_msg = try gpa.create(ErrorMsg);
......@@ -2477,6 +2478,14 @@ pub fn astGenFile(mod: *Module, file: *Scope.File) !void {
24772478 },
24782479 .msg = msg.toOwnedSlice(),
24792480 };
2481 if (token_tags[parse_err.token] == .invalid) {
2482 const bad_off = @intCast(u32, file.tree.tokenSlice(parse_err.token).len);
2483 try mod.errNoteNonLazy(.{
2484 .file_scope = file,
2485 .parent_decl_node = 0,
2486 .lazy = .{ .byte_abs = token_starts[parse_err.token] + bad_off },
2487 }, err_msg, "invalid byte here", .{});
2488 }
24802489
24812490 {
24822491 const lock = comp.mutex.acquire();
src/main.zig+20
......@@ -3380,6 +3380,7 @@ fn printErrMsgToStdErr(
33803380 color: Color,
33813381) !void {
33823382 const lok_token = parse_error.token;
3383 const token_tags = tree.tokens.items(.tag);
33833384 const start_loc = tree.tokenLocation(0, lok_token);
33843385 const source_line = tree.source[start_loc.line_start..start_loc.line_end];
33853386
......@@ -3389,6 +3390,24 @@ fn printErrMsgToStdErr(
33893390 try tree.renderError(parse_error, writer);
33903391 const text = text_buf.items;
33913392
3393 var notes_buffer: [1]Compilation.AllErrors.Message = undefined;
3394 var notes_len: usize = 0;
3395
3396 if (token_tags[parse_error.token] == .invalid) {
3397 const bad_off = @intCast(u32, tree.tokenSlice(parse_error.token).len);
3398 notes_buffer[notes_len] = .{
3399 .src = .{
3400 .src_path = path,
3401 .msg = "invalid byte here",
3402 .byte_offset = @intCast(u32, start_loc.line_start) + bad_off,
3403 .line = @intCast(u32, start_loc.line),
3404 .column = @intCast(u32, start_loc.column) + bad_off,
3405 .source_line = source_line,
3406 },
3407 };
3408 notes_len += 1;
3409 }
3410
33923411 const message: Compilation.AllErrors.Message = .{
33933412 .src = .{
33943413 .src_path = path,
......@@ -3397,6 +3416,7 @@ fn printErrMsgToStdErr(
33973416 .line = @intCast(u32, start_loc.line),
33983417 .column = @intCast(u32, start_loc.column),
33993418 .source_line = source_line,
3419 .notes = notes_buffer[0..notes_len],
34003420 },
34013421 };
34023422
test/compile_errors.zig+40-20
......@@ -1506,7 +1506,8 @@ pub fn addCases(ctx: *TestContext) !void {
15061506 \\ _ = bad;
15071507 \\}
15081508 , &[_][]const u8{
1509 "tmp.zig:2:28: error: invalid character: 'a'",
1509 "tmp.zig:2:21: error: expected expression, found 'invalid'",
1510 "tmp.zig:2:28: note: invalid byte here",
15101511 });
15111512
15121513 ctx.objErrStage1("invalid exponent in float literal - 2",
......@@ -1515,7 +1516,8 @@ pub fn addCases(ctx: *TestContext) !void {
15151516 \\ _ = bad;
15161517 \\}
15171518 , &[_][]const u8{
1518 "tmp.zig:2:29: error: invalid character: 'F'",
1519 "tmp.zig:2:21: error: expected expression, found 'invalid'",
1520 "tmp.zig:2:29: note: invalid byte here",
15191521 });
15201522
15211523 ctx.objErrStage1("invalid underscore placement in float literal - 1",
......@@ -1524,7 +1526,8 @@ pub fn addCases(ctx: *TestContext) !void {
15241526 \\ _ = bad;
15251527 \\}
15261528 , &[_][]const u8{
1527 "tmp.zig:2:23: error: invalid character: '_'",
1529 "tmp.zig:2:21: error: expected expression, found 'invalid'",
1530 "tmp.zig:2:23: note: invalid byte here",
15281531 });
15291532
15301533 ctx.objErrStage1("invalid underscore placement in float literal - 2",
......@@ -1533,7 +1536,8 @@ pub fn addCases(ctx: *TestContext) !void {
15331536 \\ _ = bad;
15341537 \\}
15351538 , &[_][]const u8{
1536 "tmp.zig:2:23: error: invalid character: '.'",
1539 "tmp.zig:2:21: error: expected expression, found 'invalid'",
1540 "tmp.zig:2:23: note: invalid byte here",
15371541 });
15381542
15391543 ctx.objErrStage1("invalid underscore placement in float literal - 3",
......@@ -1542,7 +1546,8 @@ pub fn addCases(ctx: *TestContext) !void {
15421546 \\ _ = bad;
15431547 \\}
15441548 , &[_][]const u8{
1545 "tmp.zig:2:25: error: invalid character: ';'",
1549 "tmp.zig:2:21: error: expected expression, found 'invalid'",
1550 "tmp.zig:2:25: note: invalid byte here",
15461551 });
15471552
15481553 ctx.objErrStage1("invalid underscore placement in float literal - 4",
......@@ -1551,7 +1556,8 @@ pub fn addCases(ctx: *TestContext) !void {
15511556 \\ _ = bad;
15521557 \\}
15531558 , &[_][]const u8{
1554 "tmp.zig:2:25: error: invalid character: '_'",
1559 "tmp.zig:2:21: error: expected expression, found 'invalid'",
1560 "tmp.zig:2:25: note: invalid byte here",
15551561 });
15561562
15571563 ctx.objErrStage1("invalid underscore placement in float literal - 5",
......@@ -1560,7 +1566,8 @@ pub fn addCases(ctx: *TestContext) !void {
15601566 \\ _ = bad;
15611567 \\}
15621568 , &[_][]const u8{
1563 "tmp.zig:2:26: error: invalid character: '_'",
1569 "tmp.zig:2:21: error: expected expression, found 'invalid'",
1570 "tmp.zig:2:26: note: invalid byte here",
15641571 });
15651572
15661573 ctx.objErrStage1("invalid underscore placement in float literal - 6",
......@@ -1569,7 +1576,8 @@ pub fn addCases(ctx: *TestContext) !void {
15691576 \\ _ = bad;
15701577 \\}
15711578 , &[_][]const u8{
1572 "tmp.zig:2:26: error: invalid character: '_'",
1579 "tmp.zig:2:21: error: expected expression, found 'invalid'",
1580 "tmp.zig:2:26: note: invalid byte here",
15731581 });
15741582
15751583 ctx.objErrStage1("invalid underscore placement in float literal - 7",
......@@ -1578,7 +1586,8 @@ pub fn addCases(ctx: *TestContext) !void {
15781586 \\ _ = bad;
15791587 \\}
15801588 , &[_][]const u8{
1581 "tmp.zig:2:28: error: invalid character: ';'",
1589 "tmp.zig:2:21: error: expected expression, found 'invalid'",
1590 "tmp.zig:2:28: note: invalid byte here",
15821591 });
15831592
15841593 ctx.objErrStage1("invalid underscore placement in float literal - 9",
......@@ -1587,7 +1596,8 @@ pub fn addCases(ctx: *TestContext) !void {
15871596 \\ _ = bad;
15881597 \\}
15891598 , &[_][]const u8{
1590 "tmp.zig:2:23: error: invalid character: '_'",
1599 "tmp.zig:2:21: error: expected expression, found 'invalid'",
1600 "tmp.zig:2:23: note: invalid byte here",
15911601 });
15921602
15931603 ctx.objErrStage1("invalid underscore placement in float literal - 10",
......@@ -1596,7 +1606,8 @@ pub fn addCases(ctx: *TestContext) !void {
15961606 \\ _ = bad;
15971607 \\}
15981608 , &[_][]const u8{
1599 "tmp.zig:2:25: error: invalid character: '_'",
1609 "tmp.zig:2:21: error: expected expression, found 'invalid'",
1610 "tmp.zig:2:25: note: invalid byte here",
16001611 });
16011612
16021613 ctx.objErrStage1("invalid underscore placement in float literal - 11",
......@@ -1605,7 +1616,8 @@ pub fn addCases(ctx: *TestContext) !void {
16051616 \\ _ = bad;
16061617 \\}
16071618 , &[_][]const u8{
1608 "tmp.zig:2:28: error: invalid character: '_'",
1619 "tmp.zig:2:21: error: expected expression, found 'invalid'",
1620 "tmp.zig:2:28: note: invalid byte here",
16091621 });
16101622
16111623 ctx.objErrStage1("invalid underscore placement in float literal - 12",
......@@ -1614,7 +1626,8 @@ pub fn addCases(ctx: *TestContext) !void {
16141626 \\ _ = bad;
16151627 \\}
16161628 , &[_][]const u8{
1617 "tmp.zig:2:23: error: invalid character: 'x'",
1629 "tmp.zig:2:21: error: expected expression, found 'invalid'",
1630 "tmp.zig:2:23: note: invalid byte here",
16181631 });
16191632
16201633 ctx.objErrStage1("invalid underscore placement in float literal - 13",
......@@ -1623,7 +1636,8 @@ pub fn addCases(ctx: *TestContext) !void {
16231636 \\ _ = bad;
16241637 \\}
16251638 , &[_][]const u8{
1626 "tmp.zig:2:23: error: invalid character: '_'",
1639 "tmp.zig:2:21: error: expected expression, found 'invalid'",
1640 "tmp.zig:2:23: note: invalid byte here",
16271641 });
16281642
16291643 ctx.objErrStage1("invalid underscore placement in float literal - 14",
......@@ -1632,7 +1646,8 @@ pub fn addCases(ctx: *TestContext) !void {
16321646 \\ _ = bad;
16331647 \\}
16341648 , &[_][]const u8{
1635 "tmp.zig:2:27: error: invalid character: 'p'",
1649 "tmp.zig:2:21: error: expected expression, found 'invalid'",
1650 "tmp.zig:2:27: note: invalid byte here",
16361651 });
16371652
16381653 ctx.objErrStage1("invalid underscore placement in int literal - 1",
......@@ -1641,7 +1656,8 @@ pub fn addCases(ctx: *TestContext) !void {
16411656 \\ _ = bad;
16421657 \\}
16431658 , &[_][]const u8{
1644 "tmp.zig:2:26: error: invalid character: ';'",
1659 "tmp.zig:2:21: error: expected expression, found 'invalid'",
1660 "tmp.zig:2:26: note: invalid byte here",
16451661 });
16461662
16471663 ctx.objErrStage1("invalid underscore placement in int literal - 2",
......@@ -1650,7 +1666,8 @@ pub fn addCases(ctx: *TestContext) !void {
16501666 \\ _ = bad;
16511667 \\}
16521668 , &[_][]const u8{
1653 "tmp.zig:2:28: error: invalid character: ';'",
1669 "tmp.zig:2:21: error: expected expression, found 'invalid'",
1670 "tmp.zig:2:28: note: invalid byte here",
16541671 });
16551672
16561673 ctx.objErrStage1("invalid underscore placement in int literal - 3",
......@@ -1659,7 +1676,8 @@ pub fn addCases(ctx: *TestContext) !void {
16591676 \\ _ = bad;
16601677 \\}
16611678 , &[_][]const u8{
1662 "tmp.zig:2:28: error: invalid character: ';'",
1679 "tmp.zig:2:21: error: expected expression, found 'invalid'",
1680 "tmp.zig:2:28: note: invalid byte here",
16631681 });
16641682
16651683 ctx.objErrStage1("invalid underscore placement in int literal - 4",
......@@ -1668,7 +1686,8 @@ pub fn addCases(ctx: *TestContext) !void {
16681686 \\ _ = bad;
16691687 \\}
16701688 , &[_][]const u8{
1671 "tmp.zig:2:28: error: invalid character: ';'",
1689 "tmp.zig:2:21: error: expected expression, found 'invalid'",
1690 "tmp.zig:2:28: note: invalid byte here",
16721691 });
16731692
16741693 ctx.objErrStage1("comptime struct field, no init value",
......@@ -7544,7 +7563,8 @@ pub fn addCases(ctx: *TestContext) !void {
75447563 \\ const a = '\U1234';
75457564 \\}
75467565 , &[_][]const u8{
7547 "tmp.zig:2:17: error: invalid character: 'U'",
7566 "tmp.zig:2:15: error: expected expression, found 'invalid'",
7567 "tmp.zig:2:18: note: invalid byte here",
75487568 });
75497569
75507570 ctx.objErrStage1("invalid empty unicode escape",