Skip to content

Commit

Permalink
Better handle too many # recovery in raw str
Browse files Browse the repository at this point in the history
Point at all the unnecessary trailing `#`.
Better handle interaction with outer attributes when `;` is missing.

Fix rust-lang#95030.
  • Loading branch information
estebank committed Apr 24, 2022
1 parent 1e9aa8a commit 3587406
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 15 deletions.
43 changes: 34 additions & 9 deletions compiler/rustc_parse/src/parser/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -538,22 +544,41 @@ 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 {
kind: LitKind::StrRaw(n_hashes) | LitKind::ByteStrRaw(n_hashes),
..
}),
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,
Expand Down
20 changes: 19 additions & 1 deletion src/test/ui/parser/raw/raw-str-unbalanced.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,22 @@
static s: &'static str =
r#""## //~ ERROR too many `#` when terminating raw string
;

static s2: &'static str =
r#"
"## //~ too many `#` when terminating raw string
"#### //~ 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() {}
36 changes: 31 additions & 5 deletions src/test/ui/parser/raw/raw-str-unbalanced.stderr
Original file line number Diff line number Diff line change
@@ -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
|
LL | / r#"
LL | | "####
| | -^^^ help: remove the extra `#`s
| |________|
| this raw string started with 1 `#`

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
|
= note: the raw string started with 1 `#`s
LL | const B: &'static str = r""##
| ---^^ help: remove the extra `#`s
| |
| this raw string started with 0 `#`s

error: aborting due to previous error
error: aborting due to 4 previous errors

0 comments on commit 3587406

Please sign in to comment.