about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDuddino <rezziandrea106@gmail.com>2020-04-17 14:07:44 +0200
committerDuddino <rezziandrea106@gmail.com>2020-04-17 14:08:08 +0200
commitba61fe432a13e63ea81112dd63d60b28cc63b40e (patch)
tree5dffc4167aa4cd64313900213c6690e694f77d5b
parent534a41a32952d36ec73656357777ebbea707aeb4 (diff)
downloadrust-ba61fe432a13e63ea81112dd63d60b28cc63b40e.tar.gz
rust-ba61fe432a13e63ea81112dd63d60b28cc63b40e.zip
Account for use of `try!()` in 2018 edition and guide users in the right direction
-rw-r--r--src/librustc_parse/parser/diagnostics.rs33
-rw-r--r--src/librustc_parse/parser/expr.rs2
-rw-r--r--src/test/ui/try-macro-suggestion.rs9
-rw-r--r--src/test/ui/try-macro-suggestion.stderr30
4 files changed, 74 insertions, 0 deletions
diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs
index 12b9b682682..06122df304d 100644
--- a/src/librustc_parse/parser/diagnostics.rs
+++ b/src/librustc_parse/parser/diagnostics.rs
@@ -1054,6 +1054,39 @@ impl<'a> Parser<'a> {
         }
     }
 
+    pub(super) fn try_macro_suggestion(&mut self) -> DiagnosticBuilder<'a> {
+        let is_questionmark = self.look_ahead(1, |t| t == &token::Not); //check for !
+        let is_open = self.look_ahead(2, |t| t == &token::OpenDelim(token::Paren)); //check for (
+
+        if is_questionmark && is_open {
+            let lo = self.token.span;
+            self.bump(); //remove try
+            self.bump(); //remove !
+            let try_span = lo.to(self.token.span); //we take the try!( span
+            self.bump(); //remove (
+            let is_empty = self.token == token::CloseDelim(token::Paren); //check if the block is empty
+            self.consume_block(token::Paren, ConsumeClosingDelim::No); //eat the block
+            let hi = self.token.span;
+            self.bump(); //remove )
+            let mut err = self.struct_span_err(lo.to(hi), "use of deprecated `try` macro");
+            err.note("in the 2018 edition `try` is a reserved keyword, and the `try!()` macro is deprecated");
+            if !is_empty {
+                err.multipart_suggestion(
+                    "you can use the `?` operator instead",
+                    vec![(try_span, "".to_owned()), (hi, "?".to_owned())],
+                    Applicability::MachineApplicable,
+                );
+                err.span_suggestion(lo.shrink_to_lo(), "alternatively, you can still access the deprecated `try!()` macro using the \"raw identifier\" syntax", "r#".to_string(), Applicability::MachineApplicable);
+            } else {
+                //if the try! macro is empty, it isn't possible to suggest something using the `?` operator
+                err.span_suggestion(lo.shrink_to_lo(), "you can still access the deprecated `try!()` macro using the \"raw identifier\" syntax", "r#".to_string(), Applicability::MachineApplicable);
+            }
+            err
+        } else {
+            self.expected_expression_found() // The user isn't trying to invoke the try! macro
+        }
+    }
+
     /// Recovers a situation like `for ( $pat in $expr )`
     /// and suggest writing `for $pat in $expr` instead.
     ///
diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs
index 4e3c5fa63de..907a8c2dce2 100644
--- a/src/librustc_parse/parser/expr.rs
+++ b/src/librustc_parse/parser/expr.rs
@@ -1001,11 +1001,13 @@ impl<'a> Parser<'a> {
 
     fn parse_lit_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
         let lo = self.token.span;
+        let is_try = self.token.is_keyword(kw::Try);
         match self.parse_opt_lit() {
             Some(literal) => {
                 let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Lit(literal), attrs);
                 self.maybe_recover_from_bad_qpath(expr, true)
             }
+            None if is_try => Err(self.try_macro_suggestion()),
             None => Err(self.expected_expression_found()),
         }
     }
diff --git a/src/test/ui/try-macro-suggestion.rs b/src/test/ui/try-macro-suggestion.rs
new file mode 100644
index 00000000000..635ceac0b19
--- /dev/null
+++ b/src/test/ui/try-macro-suggestion.rs
@@ -0,0 +1,9 @@
+// compile-flags: --edition 2018
+fn foo() -> Result<(), ()> {
+    Ok(try!()); //~ ERROR use of deprecated `try` macro
+    Ok(try!(Ok(()))) //~ ERROR use of deprecated `try` macro
+}
+
+fn main() {
+    let _ = foo();
+}
diff --git a/src/test/ui/try-macro-suggestion.stderr b/src/test/ui/try-macro-suggestion.stderr
new file mode 100644
index 00000000000..9d833ef5ed9
--- /dev/null
+++ b/src/test/ui/try-macro-suggestion.stderr
@@ -0,0 +1,30 @@
+error: use of deprecated `try` macro
+  --> $DIR/try-macro-suggestion.rs:3:8
+   |
+LL |     Ok(try!());
+   |        ^^^^^^
+   |
+   = note: in the 2018 edition `try` is a reserved keyword, and the `try!()` macro is deprecated
+help: you can still access the deprecated `try!()` macro using the "raw identifier" syntax
+   |
+LL |     Ok(r#try!());
+   |        ^^
+
+error: use of deprecated `try` macro
+  --> $DIR/try-macro-suggestion.rs:4:8
+   |
+LL |     Ok(try!(Ok(())))
+   |        ^^^^^^^^^^^^
+   |
+   = note: in the 2018 edition `try` is a reserved keyword, and the `try!()` macro is deprecated
+help: you can use the `?` operator instead
+   |
+LL |     Ok(Ok(())?)
+   |       --     ^
+help: alternatively, you can still access the deprecated `try!()` macro using the "raw identifier" syntax
+   |
+LL |     Ok(r#try!(Ok(())))
+   |        ^^
+
+error: aborting due to 2 previous errors
+