diff options
| author | bors <bors@rust-lang.org> | 2022-12-16 13:20:14 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2022-12-16 13:20:14 +0000 |
| commit | e82a604a88fec3adc0645c5cc5328ea7eba5faa4 (patch) | |
| tree | aafe13e8c6822c8d03d987868bc131ded4421746 /compiler/rustc_parse/src/parser | |
| parent | 789313267d2f814ec0bf1861d6e22e678668e998 (diff) | |
| parent | 39bb865759dcf2cd6c5f3cf84fc1c11b2c71e7b0 (diff) | |
| download | rust-e82a604a88fec3adc0645c5cc5328ea7eba5faa4.tar.gz rust-e82a604a88fec3adc0645c5cc5328ea7eba5faa4.zip | |
Auto merge of #2731 - RalfJung:rustup, r=RalfJung
Rustup
Diffstat (limited to 'compiler/rustc_parse/src/parser')
| -rw-r--r-- | compiler/rustc_parse/src/parser/attr.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/attr_wrapper.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/diagnostics.rs | 50 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/expr.rs | 75 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/item.rs | 13 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/pat.rs | 22 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/stmt.rs | 4 |
7 files changed, 86 insertions, 80 deletions
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index c7d239b647f..686454a8f18 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -6,7 +6,6 @@ use rustc_ast::attr; use rustc_ast::token::{self, Delimiter, Nonterminal}; use rustc_errors::{error_code, fluent, Diagnostic, IntoDiagnostic, PResult}; use rustc_span::{sym, BytePos, Span}; -use std::convert::TryInto; // Public for rustfmt usage #[derive(Debug)] diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index a084a701088..b97f22417cb 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -8,7 +8,6 @@ use rustc_errors::PResult; use rustc_session::parse::ParseSess; use rustc_span::{sym, Span, DUMMY_SP}; -use std::convert::TryInto; use std::ops::Range; /// A wrapper type to ensure that the parser handles outer attributes correctly. diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index c316a4dd6b4..0191ab730c8 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -159,8 +159,6 @@ enum IsStandalone { Standalone, /// It's a subexpression, i.e., *not* standalone. Subexpr, - /// It's maybe standalone; we're not sure. - Maybe, } #[derive(Debug, Copy, Clone, PartialEq, Eq)] @@ -213,14 +211,8 @@ impl MultiSugg { err.multipart_suggestion(&self.msg, self.patches, self.applicability); } - /// Overrides individual messages and applicabilities. - fn emit_many( - err: &mut Diagnostic, - msg: &str, - applicability: Applicability, - suggestions: impl Iterator<Item = Self>, - ) { - err.multipart_suggestions(msg, suggestions.map(|s| s.patches), applicability); + fn emit_verbose(self, err: &mut Diagnostic) { + err.multipart_suggestion_verbose(&self.msg, self.patches, self.applicability); } } @@ -1267,12 +1259,10 @@ impl<'a> Parser<'a> { &mut self, operand_expr: P<Expr>, op_span: Span, - prev_is_semi: bool, + start_stmt: bool, ) -> PResult<'a, P<Expr>> { - let standalone = - if prev_is_semi { IsStandalone::Standalone } else { IsStandalone::Subexpr }; + let standalone = if start_stmt { IsStandalone::Standalone } else { IsStandalone::Subexpr }; let kind = IncDecRecovery { standalone, op: IncOrDec::Inc, fixity: UnaryFixity::Pre }; - self.recover_from_inc_dec(operand_expr, kind, op_span) } @@ -1280,13 +1270,13 @@ impl<'a> Parser<'a> { &mut self, operand_expr: P<Expr>, op_span: Span, + start_stmt: bool, ) -> PResult<'a, P<Expr>> { let kind = IncDecRecovery { - standalone: IsStandalone::Maybe, + standalone: if start_stmt { IsStandalone::Standalone } else { IsStandalone::Subexpr }, op: IncOrDec::Inc, fixity: UnaryFixity::Post, }; - self.recover_from_inc_dec(operand_expr, kind, op_span) } @@ -1315,34 +1305,25 @@ impl<'a> Parser<'a> { }; match kind.standalone { - IsStandalone::Standalone => self.inc_dec_standalone_suggest(kind, spans).emit(&mut err), + IsStandalone::Standalone => { + self.inc_dec_standalone_suggest(kind, spans).emit_verbose(&mut err) + } IsStandalone::Subexpr => { let Ok(base_src) = self.span_to_snippet(base.span) - else { return help_base_case(err, base) }; + else { return help_base_case(err, base) }; match kind.fixity { UnaryFixity::Pre => { self.prefix_inc_dec_suggest(base_src, kind, spans).emit(&mut err) } UnaryFixity::Post => { - self.postfix_inc_dec_suggest(base_src, kind, spans).emit(&mut err) + // won't suggest since we can not handle the precedences + // for example: `a + b++` has been parsed (a + b)++ and we can not suggest here + if !matches!(base.kind, ExprKind::Binary(_, _, _)) { + self.postfix_inc_dec_suggest(base_src, kind, spans).emit(&mut err) + } } } } - IsStandalone::Maybe => { - let Ok(base_src) = self.span_to_snippet(base.span) - else { return help_base_case(err, base) }; - let sugg1 = match kind.fixity { - UnaryFixity::Pre => self.prefix_inc_dec_suggest(base_src, kind, spans), - UnaryFixity::Post => self.postfix_inc_dec_suggest(base_src, kind, spans), - }; - let sugg2 = self.inc_dec_standalone_suggest(kind, spans); - MultiSugg::emit_many( - &mut err, - "use `+= 1` instead", - Applicability::Unspecified, - [sugg1, sugg2].into_iter(), - ) - } } Err(err) } @@ -1392,7 +1373,6 @@ impl<'a> Parser<'a> { } patches.push((post_span, format!(" {}= 1", kind.op.chr()))); - MultiSugg { msg: format!("use `{}= 1` instead", kind.op.chr()), patches, diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index f6a6ed379a2..c0ed450b985 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -83,7 +83,7 @@ macro_rules! maybe_whole_expr { pub(super) enum LhsExpr { NotYetParsed, AttributesParsed(AttrWrapper), - AlreadyParsed(P<Expr>), + AlreadyParsed(P<Expr>, bool), // (expr, starts_statement) } impl From<Option<AttrWrapper>> for LhsExpr { @@ -101,7 +101,7 @@ impl From<P<Expr>> for LhsExpr { /// /// This conversion does not allocate. fn from(expr: P<Expr>) -> Self { - LhsExpr::AlreadyParsed(expr) + LhsExpr::AlreadyParsed(expr, false) } } @@ -173,7 +173,9 @@ impl<'a> Parser<'a> { min_prec: usize, lhs: LhsExpr, ) -> PResult<'a, P<Expr>> { - let mut lhs = if let LhsExpr::AlreadyParsed(expr) = lhs { + let mut starts_stmt = false; + let mut lhs = if let LhsExpr::AlreadyParsed(expr, starts_statement) = lhs { + starts_stmt = starts_statement; expr } else { let attrs = match lhs { @@ -292,7 +294,7 @@ impl<'a> Parser<'a> { let op_span = self.prev_token.span.to(self.token.span); // Eat the second `+` self.bump(); - lhs = self.recover_from_postfix_increment(lhs, op_span)?; + lhs = self.recover_from_postfix_increment(lhs, op_span, starts_stmt)?; continue; } @@ -590,14 +592,15 @@ impl<'a> Parser<'a> { token::BinOp(token::Plus) if this.look_ahead(1, |t| *t == token::BinOp(token::Plus)) => { - let prev_is_semi = this.prev_token == token::Semi; + let starts_stmt = this.prev_token == token::Semi + || this.prev_token == token::CloseDelim(Delimiter::Brace); let pre_span = this.token.span.to(this.look_ahead(1, |t| t.span)); // Eat both `+`s. this.bump(); this.bump(); let operand_expr = this.parse_dot_or_call_expr(Default::default())?; - this.recover_from_prefix_increment(operand_expr, pre_span, prev_is_semi) + this.recover_from_prefix_increment(operand_expr, pre_span, starts_stmt) } token::Ident(..) if this.token.is_keyword(kw::Box) => { make_it!(this, attrs, |this, _| this.parse_box_expr(lo)) @@ -1534,15 +1537,16 @@ impl<'a> Parser<'a> { && (matches!(self.token.kind, token::CloseDelim(_) | token::Comma) || self.token.is_op()) { - let lit = self.recover_unclosed_char(label_.ident, |self_| { - self_.sess.create_err(UnexpectedTokenAfterLabel { - span: self_.token.span, - remove_label: None, - enclose_in_block: None, - }) - }); + let (lit, _) = + self.recover_unclosed_char(label_.ident, Parser::mk_token_lit_char, |self_| { + self_.sess.create_err(UnexpectedTokenAfterLabel { + span: self_.token.span, + remove_label: None, + enclose_in_block: None, + }) + }); consume_colon = false; - Ok(self.mk_expr(lo, ExprKind::Lit(lit.token_lit))) + Ok(self.mk_expr(lo, ExprKind::Lit(lit))) } else if !ate_colon && (self.check_noexpect(&TokenKind::Comma) || self.check_noexpect(&TokenKind::Gt)) { @@ -1617,12 +1621,13 @@ impl<'a> Parser<'a> { Ok(expr) } - /// Emit an error when a char is parsed as a lifetime because of a missing quote - pub(super) fn recover_unclosed_char( + /// Emit an error when a char is parsed as a lifetime because of a missing quote. + pub(super) fn recover_unclosed_char<L>( &self, lifetime: Ident, + mk_lit_char: impl FnOnce(Symbol, Span) -> L, err: impl FnOnce(&Self) -> DiagnosticBuilder<'a, ErrorGuaranteed>, - ) -> ast::MetaItemLit { + ) -> L { if let Some(mut diag) = self.sess.span_diagnostic.steal_diagnostic(lifetime.span, StashKey::LifetimeIsChar) { @@ -1644,11 +1649,7 @@ impl<'a> Parser<'a> { .emit(); } let name = lifetime.without_first_quote().name; - ast::MetaItemLit { - token_lit: token::Lit::new(token::LitKind::Char, name, None), - kind: ast::LitKind::Char(name.as_str().chars().next().unwrap_or('_')), - span: lifetime.span, - } + mk_lit_char(name, lifetime.span) } /// Recover on the syntax `do catch { ... }` suggesting `try { ... }` instead. @@ -1764,8 +1765,8 @@ impl<'a> Parser<'a> { Some(lit) => match lit.kind { ast::LitKind::Str(symbol_unescaped, style) => Ok(ast::StrLit { style, - symbol: lit.token_lit.symbol, - suffix: lit.token_lit.suffix, + symbol: lit.symbol, + suffix: lit.suffix, span: lit.span, symbol_unescaped, }), @@ -1775,7 +1776,23 @@ impl<'a> Parser<'a> { } } - fn handle_missing_lit(&mut self) -> PResult<'a, MetaItemLit> { + pub(crate) fn mk_token_lit_char(name: Symbol, span: Span) -> (token::Lit, Span) { + (token::Lit { symbol: name, suffix: None, kind: token::Char }, span) + } + + fn mk_meta_item_lit_char(name: Symbol, span: Span) -> MetaItemLit { + ast::MetaItemLit { + symbol: name, + suffix: None, + kind: ast::LitKind::Char(name.as_str().chars().next().unwrap_or('_')), + span, + } + } + + fn handle_missing_lit<L>( + &mut self, + mk_lit_char: impl FnOnce(Symbol, Span) -> L, + ) -> PResult<'a, L> { if let token::Interpolated(inner) = &self.token.kind { let expr = match inner.as_ref() { token::NtExpr(expr) => Some(expr), @@ -1799,7 +1816,7 @@ impl<'a> Parser<'a> { // On an error path, eagerly consider a lifetime to be an unclosed character lit if self.token.is_lifetime() { let lt = self.expect_lifetime(); - Ok(self.recover_unclosed_char(lt.ident, err)) + Ok(self.recover_unclosed_char(lt.ident, mk_lit_char, err)) } else { Err(err(self)) } @@ -1808,11 +1825,13 @@ impl<'a> Parser<'a> { pub(super) fn parse_token_lit(&mut self) -> PResult<'a, (token::Lit, Span)> { self.parse_opt_token_lit() .ok_or(()) - .or_else(|()| self.handle_missing_lit().map(|lit| (lit.token_lit, lit.span))) + .or_else(|()| self.handle_missing_lit(Parser::mk_token_lit_char)) } pub(super) fn parse_meta_item_lit(&mut self) -> PResult<'a, MetaItemLit> { - self.parse_opt_meta_item_lit().ok_or(()).or_else(|()| self.handle_missing_lit()) + self.parse_opt_meta_item_lit() + .ok_or(()) + .or_else(|()| self.handle_missing_lit(Parser::mk_meta_item_lit_char)) } fn recover_after_dot(&mut self) -> Option<Token> { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index ce4bc929c5c..7c2d01509de 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -22,7 +22,6 @@ use rustc_span::lev_distance::lev_distance; use rustc_span::source_map::{self, Span}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::DUMMY_SP; -use std::convert::TryFrom; use std::mem; use thin_vec::ThinVec; use tracing::debug; @@ -708,9 +707,9 @@ impl<'a> Parser<'a> { } match parse_item(self) { Ok(None) => { - let is_unnecessary_semicolon = !items.is_empty() + let mut is_unnecessary_semicolon = !items.is_empty() // When the close delim is `)` in a case like the following, `token.kind` is expected to be `token::CloseDelim(Delimiter::Parenthesis)`, - // but the actual `token.kind` is `token::CloseDelim(Delimiter::Bracket)`. + // but the actual `token.kind` is `token::CloseDelim(Delimiter::Brace)`. // This is because the `token.kind` of the close delim is treated as the same as // that of the open delim in `TokenTreesReader::parse_token_tree`, even if the delimiters of them are different. // Therefore, `token.kind` should not be compared here. @@ -729,7 +728,13 @@ impl<'a> Parser<'a> { .span_to_snippet(self.prev_token.span) .map_or(false, |snippet| snippet == "}") && self.token.kind == token::Semi; - let semicolon_span = self.token.span; + let mut semicolon_span = self.token.span; + if !is_unnecessary_semicolon { + // #105369, Detect spurious `;` before assoc fn body + is_unnecessary_semicolon = self.token == token::OpenDelim(Delimiter::Brace) + && self.prev_token.kind == token::Semi; + semicolon_span = self.prev_token.span; + } // We have to bail or we'll potentially never make progress. let non_item_span = self.token.span; let is_let = self.token.is_keyword(kw::Let); diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index cbeec951e2d..a1981e11477 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -411,16 +411,20 @@ impl<'a> Parser<'a> { { // Recover a `'a` as a `'a'` literal let lt = self.expect_lifetime(); - let lit = self.recover_unclosed_char(lt.ident, |self_| { - let expected = expected.unwrap_or("pattern"); - let msg = - format!("expected {}, found {}", expected, super::token_descr(&self_.token)); + let (lit, _) = + self.recover_unclosed_char(lt.ident, Parser::mk_token_lit_char, |self_| { + let expected = expected.unwrap_or("pattern"); + let msg = format!( + "expected {}, found {}", + expected, + super::token_descr(&self_.token) + ); - let mut err = self_.struct_span_err(self_.token.span, &msg); - err.span_label(self_.token.span, format!("expected {}", expected)); - err - }); - PatKind::Lit(self.mk_expr(lo, ExprKind::Lit(lit.token_lit))) + let mut err = self_.struct_span_err(self_.token.span, &msg); + err.span_label(self_.token.span, format!("expected {}", expected)); + err + }); + PatKind::Lit(self.mk_expr(lo, ExprKind::Lit(lit))) } else { // Try to parse everything else as literal with optional minus match self.parse_literal_maybe_minus() { diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 42197e63797..bae7f2670cb 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -164,7 +164,7 @@ impl<'a> Parser<'a> { // Perform this outside of the `collect_tokens_trailing_token` closure, // since our outer attributes do not apply to this part of the expression let expr = self.with_res(Restrictions::STMT_EXPR, |this| { - this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr)) + this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr, true)) })?; Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Expr(expr))) } else { @@ -198,7 +198,7 @@ impl<'a> Parser<'a> { let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac)); let e = self.maybe_recover_from_bad_qpath(e)?; let e = self.parse_dot_or_call_expr_with(e, lo, attrs)?; - let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?; + let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e, false))?; StmtKind::Expr(e) }; Ok(self.mk_stmt(lo.to(hi), kind)) |
