diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index ac1402a0faa..3a5f0ec07e7 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -808,12 +808,57 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, } ('\\', Some((next_pos, 'n'))) | ('\\', Some((next_pos, 't'))) | + ('\\', Some((next_pos, '0'))) | ('\\', Some((next_pos, '\\'))) | ('\\', Some((next_pos, '\''))) | ('\\', Some((next_pos, '\"'))) => { skips.push(*next_pos); let _ = s.next(); } + ('\\', Some((_, 'x'))) if !is_raw => { + for _ in 0..3 { // consume `\xAB` literal + if let Some((pos, _)) = s.next() { + skips.push(pos); + } else { + break; + } + } + } + ('\\', Some((_, 'u'))) if !is_raw => { + if let Some((pos, _)) = s.next() { + skips.push(pos); + } + if let Some((next_pos, next_c)) = s.next() { + if next_c == '{' { + skips.push(next_pos); + let mut i = 0; // consume up to 6 hexanumeric chars + closing `}` + while let (Some((next_pos, c)), true) = (s.next(), i < 7) { + if c.is_digit(16) { + skips.push(next_pos); + } else if c == '}' { + skips.push(next_pos); + break; + } else { + break; + } + i += 1; + } + } else if next_c.is_digit(16) { + skips.push(next_pos); + // We suggest adding `{` and `}` when appropriate, accept it here as if it + // were correct + let mut i = 0; // consume up to 6 hexanumeric chars + while let (Some((next_pos, c)), _) = (s.next(), i < 6) { + if c.is_digit(16) { + skips.push(next_pos); + } else { + break; + } + i += 1; + } + } + } + } _ if eat_ws => { // `take_while(|c| c.is_whitespace())` eat_ws = false; } diff --git a/src/test/ui/fmt/format-string-error-2.rs b/src/test/ui/fmt/format-string-error-2.rs index 3c6c15c06bb..5c25ae502ff 100644 --- a/src/test/ui/fmt/format-string-error-2.rs +++ b/src/test/ui/fmt/format-string-error-2.rs @@ -69,4 +69,19 @@ raw { \n //~^^ ERROR invalid format string println!("\t{}"); //~^ ERROR 1 positional argument in format string + + // note: `\x7B` is `{` + println!("\x7B}\u{8} {", 1); + //~^ ERROR invalid format string: expected `'}'` but string was terminated + + println!("\x7B}\u8 {", 1); + //~^ ERROR incorrect unicode escape sequence + //~| ERROR argument never used + + // note: raw strings don't escape `\xFF` and `\u{FF}` sequences + println!(r#"\x7B}\u{8} {"#, 1); + //~^ ERROR invalid format string: unmatched `}` found + + println!(r#"\x7B}\u8 {"#, 1); + //~^ ERROR invalid format string: unmatched `}` found } diff --git a/src/test/ui/fmt/format-string-error-2.stderr b/src/test/ui/fmt/format-string-error-2.stderr index face0bc0f5f..ae62ed66338 100644 --- a/src/test/ui/fmt/format-string-error-2.stderr +++ b/src/test/ui/fmt/format-string-error-2.stderr @@ -1,3 +1,15 @@ +error: incorrect unicode escape sequence + --> $DIR/format-string-error-2.rs:77:20 + | +LL | println!("/x7B}/u8 {", 1); + | ^^ + | +help: format of unicode escape sequences is `/u{…}` + --> $DIR/format-string-error-2.rs:77:20 + | +LL | println!("/x7B}/u8 {", 1); + | ^^ + error: invalid format string: expected `'}'`, found `'a'` --> $DIR/format-string-error-2.rs:5:5 | @@ -139,5 +151,39 @@ error: 1 positional argument in format string, but no arguments were given LL | println!("/t{}"); | ^^ -error: aborting due to 14 previous errors +error: invalid format string: expected `'}'` but string was terminated + --> $DIR/format-string-error-2.rs:74:27 + | +LL | println!("/x7B}/u{8} {", 1); + | -^ expected `'}'` in format string + | | + | because of this opening brace + | + = note: if you intended to print `{`, you can escape it using `{{` + +error: argument never used + --> $DIR/format-string-error-2.rs:77:28 + | +LL | println!("/x7B}/u8 {", 1); + | ------------ ^ argument never used + | | + | formatting specifier missing + +error: invalid format string: unmatched `}` found + --> $DIR/format-string-error-2.rs:82:21 + | +LL | println!(r#"/x7B}/u{8} {"#, 1); + | ^ unmatched `}` in format string + | + = note: if you intended to print `}`, you can escape it using `}}` + +error: invalid format string: unmatched `}` found + --> $DIR/format-string-error-2.rs:85:21 + | +LL | println!(r#"/x7B}/u8 {"#, 1); + | ^ unmatched `}` in format string + | + = note: if you intended to print `}`, you can escape it using `}}` + +error: aborting due to 19 previous errors