about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-09-02 19:29:27 +0000
committerbors <bors@rust-lang.org>2020-09-02 19:29:27 +0000
commit80fc9b0ecb29050d45b17c64af004200afd3cfc2 (patch)
tree3d0269d8f9ecb027bd59a942462003ed9e01e4ea /compiler
parenta167485e279be8a11c9c09d0dddaf1d7c5724f1c (diff)
parent3524c3ef4371d0bf4dd03568a004039f18c154f7 (diff)
downloadrust-80fc9b0ecb29050d45b17c64af004200afd3cfc2.tar.gz
rust-80fc9b0ecb29050d45b17c64af004200afd3cfc2.zip
Auto merge of #76160 - scileo:format-recovery, r=petrochenkov
Improve recovery on malformed format call

The token following a format expression should be a comma. However, when it is replaced with a similar token (such as a dot), then the corresponding error is emitted, but the token is treated as a comma, and the parsing step continues.

r? @petrochenkov
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_builtin_macros/src/format.rs28
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs4
2 files changed, 24 insertions, 8 deletions
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index 48506148ed9..5d6f791f137 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -161,14 +161,26 @@ fn parse_args<'a>(
     while p.token != token::Eof {
         if !p.eat(&token::Comma) {
             if first {
-                // After `format!(""` we always expect *only* a comma...
-                let mut err = ecx.struct_span_err(p.token.span, "expected token: `,`");
-                err.span_label(p.token.span, "expected `,`");
-                p.maybe_annotate_with_ascription(&mut err, false);
-                return Err(err);
-            } else {
-                // ...after that delegate to `expect` to also include the other expected tokens.
-                let _ = p.expect(&token::Comma)?;
+                p.clear_expected_tokens();
+            }
+
+            // `Parser::expect` tries to recover using the
+            // `Parser::unexpected_try_recover` function. This function is able
+            // to recover if the expected token is a closing delimiter.
+            //
+            // As `,` is not a closing delimiter, it will always return an `Err`
+            // variant.
+            let mut err = p.expect(&token::Comma).unwrap_err();
+
+            match token::TokenKind::Comma.similar_tokens() {
+                Some(tks) if tks.contains(&p.token.kind) => {
+                    // If a similar token is found, then it may be a typo. We
+                    // consider it as a comma, and continue parsing.
+                    err.emit();
+                    p.bump();
+                }
+                // Otherwise stop the parsing and return the error.
+                _ => return Err(err),
             }
         }
         first = false;
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index d90a61cd34a..84edfecad19 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -1234,6 +1234,10 @@ impl<'a> Parser<'a> {
                 *t == token::OpenDelim(token::Brace) || *t == token::BinOp(token::Star)
             })
     }
+
+    pub fn clear_expected_tokens(&mut self) {
+        self.expected_tokens.clear();
+    }
 }
 
 crate fn make_unclosed_delims_error(