Rollup merge of #96355 - estebank:issue-95030, r=compiler-errors

Better handle too many `#` recovery in raw str

Point at all the unnecessary trailing `#`.
Better handle interaction with outer attributes when `;` is missing.

Fix #95030.
This commit is contained in:
Dylan DPC 2022-04-26 01:21:22 +02:00 committed by GitHub
commit 77031f3d99
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 85 additions and 16 deletions

View file

@ -431,10 +431,11 @@ impl<'a> Parser<'a> {
return Ok(true);
} else if self.look_ahead(0, |t| {
t == &token::CloseDelim(token::Brace)
|| (
t.can_begin_expr() && t != &token::Semi && t != &token::Pound
// Avoid triggering with too many trailing `#` in raw string.
)
|| (t.can_begin_expr() && t != &token::Semi && t != &token::Pound)
// Avoid triggering with too many trailing `#` in raw string.
|| (sm.is_multiline(
self.prev_token.span.shrink_to_hi().until(self.token.span.shrink_to_lo())
) && t == &token::Pound)
}) {
// Missing semicolon typo. This is triggered if the next token could either start a
// new statement or is a block close. For example:
@ -508,7 +509,12 @@ impl<'a> Parser<'a> {
}
if self.check_too_many_raw_str_terminators(&mut err) {
return Err(err);
if expected.contains(&TokenType::Token(token::Semi)) && self.eat(&token::Semi) {
err.emit();
return Ok(true);
} else {
return Err(err);
}
}
if self.prev_token.span == DUMMY_SP {
@ -538,6 +544,7 @@ impl<'a> Parser<'a> {
}
fn check_too_many_raw_str_terminators(&mut self, err: &mut Diagnostic) -> bool {
let sm = self.sess.source_map();
match (&self.prev_token.kind, &self.token.kind) {
(
TokenKind::Literal(Lit {
@ -545,15 +552,33 @@ impl<'a> Parser<'a> {
..
}),
TokenKind::Pound,
) => {
) if !sm.is_multiline(
self.prev_token.span.shrink_to_hi().until(self.token.span.shrink_to_lo()),
) =>
{
let n_hashes: u8 = *n_hashes;
err.set_primary_message("too many `#` when terminating raw string");
let str_span = self.prev_token.span;
let mut span = self.token.span;
let mut count = 0;
while self.token.kind == TokenKind::Pound
&& !sm.is_multiline(span.shrink_to_hi().until(self.token.span.shrink_to_lo()))
{
span = span.with_hi(self.token.span.hi());
self.bump();
count += 1;
}
err.set_span(span);
err.span_suggestion(
self.token.span,
"remove the extra `#`",
span,
&format!("remove the extra `#`{}", pluralize!(count)),
String::new(),
Applicability::MachineApplicable,
);
err.note(&format!("the raw string started with {n_hashes} `#`s"));
err.span_label(
str_span,
&format!("this raw string started with {n_hashes} `#`{}", pluralize!(n_hashes)),
);
true
}
_ => false,

View file

@ -1,4 +1,22 @@
static s: &'static str =
r#"
"## //~ too many `#` when terminating raw string
r#""## //~ ERROR too many `#` when terminating raw string
;
static s2: &'static str =
r#"
"#### //~ ERROR too many `#` when terminating raw string
;
const A: &'static str = r"" //~ ERROR expected `;`, found `#`
// Test
#[test]
fn test() {}
const B: &'static str = r""## //~ ERROR too many `#` when terminating raw string
// Test
#[test]
fn test2() {}
fn main() {}

View file

@ -1,10 +1,36 @@
error: too many `#` when terminating raw string
--> $DIR/raw-str-unbalanced.rs:3:9
--> $DIR/raw-str-unbalanced.rs:2:10
|
LL | "##
| ^ help: remove the extra `#`
LL | r#""##
| -----^ help: remove the extra `#`
| |
| this raw string started with 1 `#`
error: too many `#` when terminating raw string
--> $DIR/raw-str-unbalanced.rs:7:9
|
= note: the raw string started with 1 `#`s
LL | / r#"
LL | | "####
| | -^^^ help: remove the extra `#`s
| |________|
| this raw string started with 1 `#`
error: aborting due to previous error
error: expected `;`, found `#`
--> $DIR/raw-str-unbalanced.rs:10:28
|
LL | const A: &'static str = r""
| ^ help: add `;` here
...
LL | #[test]
| - unexpected token
error: too many `#` when terminating raw string
--> $DIR/raw-str-unbalanced.rs:16:28
|
LL | const B: &'static str = r""##
| ---^^ help: remove the extra `#`s
| |
| this raw string started with 0 `#`s
error: aborting due to 4 previous errors