about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2022-04-23 19:44:25 -0700
committerEsteban Küber <esteban@kuber.com.ar>2022-04-23 19:51:11 -0700
commit35874069679cf394e8a93bd5764ce13f9696096b (patch)
treebdfe89e44fe7160daac1b8fce7d357ea09a3bc43
parent1e9aa8a96b207668799365bf891a459b62410b60 (diff)
downloadrust-35874069679cf394e8a93bd5764ce13f9696096b.tar.gz
rust-35874069679cf394e8a93bd5764ce13f9696096b.zip
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.
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs43
-rw-r--r--src/test/ui/parser/raw/raw-str-unbalanced.rs20
-rw-r--r--src/test/ui/parser/raw/raw-str-unbalanced.stderr36
3 files changed, 84 insertions, 15 deletions
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index ed264045170..acc0d7a6ee0 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -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,
diff --git a/src/test/ui/parser/raw/raw-str-unbalanced.rs b/src/test/ui/parser/raw/raw-str-unbalanced.rs
index 35f118f5ce6..38537f8b31e 100644
--- a/src/test/ui/parser/raw/raw-str-unbalanced.rs
+++ b/src/test/ui/parser/raw/raw-str-unbalanced.rs
@@ -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() {}
diff --git a/src/test/ui/parser/raw/raw-str-unbalanced.stderr b/src/test/ui/parser/raw/raw-str-unbalanced.stderr
index bf8f3a7a5a4..eac8c06c1df 100644
--- a/src/test/ui/parser/raw/raw-str-unbalanced.stderr
+++ b/src/test/ui/parser/raw/raw-str-unbalanced.stderr
@@ -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