about summary refs log tree commit diff
path: root/compiler/rustc_parse/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_parse/src')
-rw-r--r--compiler/rustc_parse/src/lib.rs1
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs31
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs30
-rw-r--r--compiler/rustc_parse/src/parser/item.rs3
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs28
5 files changed, 66 insertions, 27 deletions
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index f3bdd63ee6d..113af328a91 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -6,6 +6,7 @@
 #![feature(let_chains)]
 #![feature(let_else)]
 #![feature(never_type)]
+#![feature(rustc_attrs)]
 #![recursion_limit = "256"]
 
 #[macro_use]
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index acf892cec53..63055c56c5c 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -244,7 +244,7 @@ impl MultiSugg {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(slug = "parser-maybe-report-ambiguous-plus")]
+#[error(parser::maybe_report_ambiguous_plus)]
 struct AmbiguousPlus {
     pub sum_ty: String,
     #[primary_span]
@@ -253,7 +253,7 @@ struct AmbiguousPlus {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0178", slug = "parser-maybe-recover-from-bad-type-plus")]
+#[error(parser::maybe_recover_from_bad_type_plus, code = "E0178")]
 struct BadTypePlus {
     pub ty: String,
     #[primary_span]
@@ -265,7 +265,7 @@ struct BadTypePlus {
 #[derive(SessionSubdiagnostic)]
 pub enum BadTypePlusSub {
     #[suggestion(
-        slug = "parser-add-paren",
+        parser::add_paren,
         code = "{sum_with_parens}",
         applicability = "machine-applicable"
     )]
@@ -274,12 +274,12 @@ pub enum BadTypePlusSub {
         #[primary_span]
         span: Span,
     },
-    #[label(slug = "parser-forgot-paren")]
+    #[label(parser::forgot_paren)]
     ForgotParen {
         #[primary_span]
         span: Span,
     },
-    #[label(slug = "parser-expect-path")]
+    #[label(parser::expect_path)]
     ExpectPath {
         #[primary_span]
         span: Span,
@@ -287,7 +287,7 @@ pub enum BadTypePlusSub {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(slug = "parser-maybe-recover-from-bad-qpath-stage-2")]
+#[error(parser::maybe_recover_from_bad_qpath_stage_2)]
 struct BadQPathStage2 {
     #[primary_span]
     #[suggestion(applicability = "maybe-incorrect")]
@@ -296,7 +296,7 @@ struct BadQPathStage2 {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(slug = "parser-incorrect-semicolon")]
+#[error(parser::incorrect_semicolon)]
 struct IncorrectSemicolon<'a> {
     #[primary_span]
     #[suggestion_short(applicability = "machine-applicable")]
@@ -307,26 +307,26 @@ struct IncorrectSemicolon<'a> {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(slug = "parser-incorrect-use-of-await")]
+#[error(parser::incorrect_use_of_await)]
 struct IncorrectUseOfAwait {
     #[primary_span]
-    #[suggestion(message = "parentheses-suggestion", applicability = "machine-applicable")]
+    #[suggestion(parser::parentheses_suggestion, applicability = "machine-applicable")]
     span: Span,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(slug = "parser-incorrect-use-of-await")]
+#[error(parser::incorrect_use_of_await)]
 struct IncorrectAwait {
     #[primary_span]
     span: Span,
-    #[suggestion(message = "postfix-suggestion", code = "{expr}.await{question_mark}")]
+    #[suggestion(parser::postfix_suggestion, code = "{expr}.await{question_mark}")]
     sugg_span: (Span, Applicability),
     expr: String,
     question_mark: &'static str,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(slug = "parser-in-in-typo")]
+#[error(parser::in_in_typo)]
 struct InInTypo {
     #[primary_span]
     span: Span,
@@ -357,6 +357,7 @@ impl<'a> DerefMut for SnapshotParser<'a> {
 }
 
 impl<'a> Parser<'a> {
+    #[rustc_lint_diagnostics]
     pub(super) fn span_err<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -365,6 +366,7 @@ impl<'a> Parser<'a> {
         err.span_err(sp, self.diagnostic())
     }
 
+    #[rustc_lint_diagnostics]
     pub fn struct_span_err<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -1355,7 +1357,10 @@ impl<'a> Parser<'a> {
                     s.print_mutability(mut_ty.mutbl, false);
                     s.popen();
                     s.print_type(&mut_ty.ty);
-                    s.print_type_bounds(" +", &bounds);
+                    if !bounds.is_empty() {
+                        s.word(" + ");
+                        s.print_type_bounds(&bounds);
+                    }
                     s.pclose()
                 });
 
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 81bab0e3513..2c43563b104 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -7,6 +7,7 @@ use super::{
 };
 use crate::maybe_recover_from_interpolated_ty_qpath;
 
+use core::mem;
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Delimiter, Token, TokenKind};
 use rustc_ast::tokenstream::Spacing;
@@ -26,7 +27,6 @@ use rustc_session::lint::BuiltinLintDiagnostics;
 use rustc_span::source_map::{self, Span, Spanned};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{BytePos, Pos};
-use std::mem;
 
 /// Possibly accepts an `token::Interpolated` expression (a pre-parsed expression
 /// dropped into the token stream, which happens while parsing the result of
@@ -2343,7 +2343,9 @@ impl<'a> Parser<'a> {
 
     /// Parses the condition of a `if` or `while` expression.
     fn parse_cond_expr(&mut self) -> PResult<'a, P<Expr>> {
-        let cond = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
+        let cond = self.with_let_management(true, |local_self| {
+            local_self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)
+        })?;
 
         if let ExprKind::Let(..) = cond.kind {
             // Remove the last feature gating of a `let` expression since it's stable.
@@ -2356,6 +2358,13 @@ impl<'a> Parser<'a> {
     /// Parses a `let $pat = $expr` pseudo-expression.
     /// The `let` token has already been eaten.
     fn parse_let_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
+        if !self.let_expr_allowed {
+            self.struct_span_err(
+                self.prev_token.span,
+                "expected expression, found `let` statement",
+            )
+            .emit();
+        }
         let lo = self.prev_token.span;
         let pat = self.parse_pat_allow_top_alt(
             None,
@@ -2672,6 +2681,8 @@ impl<'a> Parser<'a> {
     }
 
     pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> {
+        // Used to check the `let_chains` and `if_let_guard` features mostly by scaning
+        // `&&` tokens.
         fn check_let_expr(expr: &Expr) -> (bool, bool) {
             match expr.kind {
                 ExprKind::Binary(_, ref lhs, ref rhs) => {
@@ -2694,7 +2705,7 @@ impl<'a> Parser<'a> {
             )?;
             let guard = if this.eat_keyword(kw::If) {
                 let if_span = this.prev_token.span;
-                let cond = this.parse_expr()?;
+                let cond = this.with_let_management(true, |local_this| local_this.parse_expr())?;
                 let (has_let_expr, does_not_have_bin_op) = check_let_expr(&cond);
                 if has_let_expr {
                     if does_not_have_bin_op {
@@ -3256,4 +3267,17 @@ impl<'a> Parser<'a> {
             Ok((res, trailing))
         })
     }
+
+    // Calls `f` with the internal `let_expr_allowed` set to `let_expr_allowed` and then
+    // sets the internal `let_expr_allowed` back to its original value.
+    fn with_let_management<T>(
+        &mut self,
+        let_expr_allowed: bool,
+        f: impl FnOnce(&mut Self) -> T,
+    ) -> T {
+        let last_let_expr_allowed = mem::replace(&mut self.let_expr_allowed, let_expr_allowed);
+        let rslt = f(self);
+        self.let_expr_allowed = last_let_expr_allowed;
+        rslt
+    }
 }
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index bf685aa8cad..87bc0d9762e 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -271,8 +271,7 @@ impl<'a> Parser<'a> {
             // MACRO_RULES ITEM
             self.parse_item_macro_rules(vis, has_bang)?
         } else if self.isnt_macro_invocation()
-            && (self.token.is_ident_named(Symbol::intern("import"))
-                || self.token.is_ident_named(Symbol::intern("using")))
+            && (self.token.is_ident_named(sym::import) || self.token.is_ident_named(sym::using))
         {
             return self.recover_import_as_use();
         } else if self.isnt_macro_invocation() && vis.kind.is_pub() {
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 6d6667717f0..67e6402c0ae 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -147,12 +147,15 @@ pub struct Parser<'a> {
     /// This allows us to recover when the user forget to add braces around
     /// multiple statements in the closure body.
     pub current_closure: Option<ClosureSpans>,
+    /// Used to track where `let`s are allowed. For example, `if true && let 1 = 1` is valid
+    /// but `[1, 2, 3][let _ = ()]` is not.
+    let_expr_allowed: bool,
 }
 
 // This type is used a lot, e.g. it's cloned when matching many declarative macro rules. Make sure
 // it doesn't unintentionally get bigger.
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Parser<'_>, 328);
+rustc_data_structures::static_assert_size!(Parser<'_>, 336);
 
 /// Stores span information about a closure.
 #[derive(Clone)]
@@ -455,6 +458,7 @@ impl<'a> Parser<'a> {
                 inner_attr_ranges: Default::default(),
             },
             current_closure: None,
+            let_expr_allowed: false,
         };
 
         // Make parser point to the first token.
@@ -887,22 +891,19 @@ impl<'a> Parser<'a> {
         let mut first_note = MultiSpan::from(vec![initial_semicolon]);
         first_note.push_span_label(
             initial_semicolon,
-            "this `;` turns the preceding closure into a statement".to_string(),
+            "this `;` turns the preceding closure into a statement",
         );
         first_note.push_span_label(
             closure_spans.body,
-            "this expression is a statement because of the trailing semicolon".to_string(),
+            "this expression is a statement because of the trailing semicolon",
         );
         expect_err.span_note(first_note, "statement found outside of a block");
 
         let mut second_note = MultiSpan::from(vec![closure_spans.whole_closure]);
-        second_note.push_span_label(
-            closure_spans.whole_closure,
-            "this is the parsed closure...".to_string(),
-        );
+        second_note.push_span_label(closure_spans.whole_closure, "this is the parsed closure...");
         second_note.push_span_label(
             following_token_span,
-            "...but likely you meant the closure to end here".to_string(),
+            "...but likely you meant the closure to end here",
         );
         expect_err.span_note(second_note, "the closure body may be incorrectly delimited");
 
@@ -1352,7 +1353,16 @@ impl<'a> Parser<'a> {
 
     /// Parses `extern string_literal?`.
     fn parse_extern(&mut self) -> Extern {
-        if self.eat_keyword(kw::Extern) { Extern::from_abi(self.parse_abi()) } else { Extern::None }
+        if self.eat_keyword(kw::Extern) {
+            let mut extern_span = self.prev_token.span;
+            let abi = self.parse_abi();
+            if let Some(abi) = abi {
+                extern_span = extern_span.to(abi.span);
+            }
+            Extern::from_abi(abi, extern_span)
+        } else {
+            Extern::None
+        }
     }
 
     /// Parses a string literal as an ABI spec.