diff options
| author | bors <bors@rust-lang.org> | 2023-01-13 13:11:11 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2023-01-13 13:11:11 +0000 |
| commit | cd952c8c694c28b9bb95a5d98c90186381e225c2 (patch) | |
| tree | 7ecd84a4f5c11bae743e22efaff4617a4197a7f6 /compiler/rustc_parse/src/parser | |
| parent | cb1592518e09098c19d90b4f4f0a8f0373cc1bd5 (diff) | |
| parent | 4aa07c921abafcc43fc9d545d8ec86b80103ec4e (diff) | |
| download | rust-cd952c8c694c28b9bb95a5d98c90186381e225c2.tar.gz rust-cd952c8c694c28b9bb95a5d98c90186381e225c2.zip | |
Auto merge of #2756 - RalfJung:rustup, r=RalfJung
Rustup
Diffstat (limited to 'compiler/rustc_parse/src/parser')
| -rw-r--r-- | compiler/rustc_parse/src/parser/diagnostics.rs | 37 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/expr.rs | 10 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/generics.rs | 118 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/item.rs | 17 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/mod.rs | 14 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/stmt.rs | 11 |
6 files changed, 176 insertions, 31 deletions
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index d9fa3e31db9..4c918c6702e 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -12,9 +12,10 @@ use crate::errors::{ IncorrectAwait, IncorrectSemicolon, IncorrectUseOfAwait, ParenthesesInForHead, ParenthesesInForHeadSugg, PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath, - StructLiteralBodyWithoutPathSugg, SuggEscapeToUseAsIdentifier, SuggRemoveComma, - UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration, - UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead, + StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens, StructLiteralNeedingParensSugg, + SuggEscapeToUseAsIdentifier, SuggRemoveComma, UnexpectedConstInGenericParam, + UnexpectedConstParamDeclaration, UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, + UseEqInstead, }; use crate::lexer::UnmatchedBrace; @@ -623,12 +624,15 @@ impl<'a> Parser<'a> { &mut self, lo: Span, s: BlockCheckMode, + maybe_struct_name: token::Token, + can_be_struct_literal: bool, ) -> Option<PResult<'a, P<Block>>> { if self.token.is_ident() && self.look_ahead(1, |t| t == &token::Colon) { // We might be having a struct literal where people forgot to include the path: // fn foo() -> Foo { // field: value, // } + info!(?maybe_struct_name, ?self.token); let mut snapshot = self.create_snapshot_for_diagnostic(); let path = Path { segments: ThinVec::new(), @@ -648,13 +652,6 @@ impl<'a> Parser<'a> { // field: value, // } } err.delay_as_bug(); - self.sess.emit_err(StructLiteralBodyWithoutPath { - span: expr.span, - sugg: StructLiteralBodyWithoutPathSugg { - before: expr.span.shrink_to_lo(), - after: expr.span.shrink_to_hi(), - }, - }); self.restore_snapshot(snapshot); let mut tail = self.mk_block( vec![self.mk_stmt_err(expr.span)], @@ -662,7 +659,25 @@ impl<'a> Parser<'a> { lo.to(self.prev_token.span), ); tail.could_be_bare_literal = true; - Ok(tail) + if maybe_struct_name.is_ident() && can_be_struct_literal { + // Account for `if Example { a: one(), }.is_pos() {}`. + Err(self.sess.create_err(StructLiteralNeedingParens { + span: maybe_struct_name.span.to(expr.span), + sugg: StructLiteralNeedingParensSugg { + before: maybe_struct_name.span.shrink_to_lo(), + after: expr.span.shrink_to_hi(), + }, + })) + } else { + self.sess.emit_err(StructLiteralBodyWithoutPath { + span: expr.span, + sugg: StructLiteralBodyWithoutPathSugg { + before: expr.span.shrink_to_lo(), + after: expr.span.shrink_to_hi(), + }, + }); + Ok(tail) + } } (Err(err), Ok(tail)) => { // We have a block tail that contains a somehow valid type ascription expr. diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 9f436783ced..dd2b03988c3 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1325,7 +1325,10 @@ impl<'a> Parser<'a> { self.parse_array_or_repeat_expr(Delimiter::Bracket) } else if self.check_path() { self.parse_path_start_expr() - } else if self.check_keyword(kw::Move) || self.check_keyword(kw::Static) { + } else if self.check_keyword(kw::Move) + || self.check_keyword(kw::Static) + || self.check_const_closure() + { self.parse_closure_expr() } else if self.eat_keyword(kw::If) { self.parse_if_expr() @@ -2039,7 +2042,7 @@ impl<'a> Parser<'a> { }); } - let (attrs, blk) = self.parse_block_common(lo, blk_mode)?; + let (attrs, blk) = self.parse_block_common(lo, blk_mode, true)?; Ok(self.mk_expr_with_attrs(blk.span, ExprKind::Block(blk, opt_label), attrs)) } @@ -2065,6 +2068,8 @@ impl<'a> Parser<'a> { ClosureBinder::NotPresent }; + let constness = self.parse_constness(Case::Sensitive); + let movability = if self.eat_keyword(kw::Static) { Movability::Static } else { Movability::Movable }; @@ -2111,6 +2116,7 @@ impl<'a> Parser<'a> { ExprKind::Closure(Box::new(ast::Closure { binder, capture_clause, + constness, asyncness, movability, fn_decl, diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index fa75670b2ed..8ba811715d8 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -1,11 +1,20 @@ +use crate::errors::{WhereClauseBeforeTupleStructBody, WhereClauseBeforeTupleStructBodySugg}; + use super::{ForceCollect, Parser, TrailingToken}; +use ast::token::Delimiter; use rustc_ast::token; use rustc_ast::{ self as ast, AttrVec, GenericBounds, GenericParam, GenericParamKind, TyKind, WhereClause, }; use rustc_errors::{Applicability, PResult}; -use rustc_span::symbol::kw; +use rustc_span::symbol::{kw, Ident}; +use rustc_span::Span; + +enum PredicateOrStructBody { + Predicate(ast::WherePredicate), + StructBody(Vec<ast::FieldDef>), +} impl<'a> Parser<'a> { /// Parses bounds of a lifetime parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`. @@ -240,23 +249,39 @@ impl<'a> Parser<'a> { }) } - /// Parses an optional where-clause and places it in `generics`. + /// Parses an optional where-clause. /// /// ```ignore (only-for-syntax-highlight) /// where T : Trait<U, V> + 'b, 'a : 'b /// ``` pub(super) fn parse_where_clause(&mut self) -> PResult<'a, WhereClause> { + self.parse_where_clause_common(None).map(|(clause, _)| clause) + } + + pub(super) fn parse_struct_where_clause( + &mut self, + struct_name: Ident, + body_insertion_point: Span, + ) -> PResult<'a, (WhereClause, Option<Vec<ast::FieldDef>>)> { + self.parse_where_clause_common(Some((struct_name, body_insertion_point))) + } + + fn parse_where_clause_common( + &mut self, + struct_: Option<(Ident, Span)>, + ) -> PResult<'a, (WhereClause, Option<Vec<ast::FieldDef>>)> { let mut where_clause = WhereClause { has_where_token: false, predicates: Vec::new(), span: self.prev_token.span.shrink_to_hi(), }; + let mut tuple_struct_body = None; if !self.eat_keyword(kw::Where) { - return Ok(where_clause); + return Ok((where_clause, None)); } where_clause.has_where_token = true; - let lo = self.prev_token.span; + let where_lo = self.prev_token.span; // We are considering adding generics to the `where` keyword as an alternative higher-rank // parameter syntax (as in `where<'a>` or `where<T>`. To avoid that being a breaking @@ -272,7 +297,8 @@ impl<'a> Parser<'a> { } loop { - let lo = self.token.span; + let where_sp = where_lo.to(self.prev_token.span); + let pred_lo = self.token.span; if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) { let lifetime = self.expect_lifetime(); // Bounds starting with a colon are mandatory, but possibly empty. @@ -280,13 +306,21 @@ impl<'a> Parser<'a> { let bounds = self.parse_lt_param_bounds(); where_clause.predicates.push(ast::WherePredicate::RegionPredicate( ast::WhereRegionPredicate { - span: lo.to(self.prev_token.span), + span: pred_lo.to(self.prev_token.span), lifetime, bounds, }, )); } else if self.check_type() { - where_clause.predicates.push(self.parse_ty_where_predicate()?); + match self.parse_ty_where_predicate_or_recover_tuple_struct_body( + struct_, pred_lo, where_sp, + )? { + PredicateOrStructBody::Predicate(pred) => where_clause.predicates.push(pred), + PredicateOrStructBody::StructBody(body) => { + tuple_struct_body = Some(body); + break; + } + } } else { break; } @@ -297,7 +331,7 @@ impl<'a> Parser<'a> { if self.eat_keyword_noexpect(kw::Where) { let msg = "cannot define duplicate `where` clauses on an item"; let mut err = self.struct_span_err(self.token.span, msg); - err.span_label(lo, "previous `where` clause starts here"); + err.span_label(pred_lo, "previous `where` clause starts here"); err.span_suggestion_verbose( prev_token.shrink_to_hi().to(self.prev_token.span), "consider joining the two `where` clauses into one", @@ -310,8 +344,72 @@ impl<'a> Parser<'a> { } } - where_clause.span = lo.to(self.prev_token.span); - Ok(where_clause) + where_clause.span = where_lo.to(self.prev_token.span); + Ok((where_clause, tuple_struct_body)) + } + + fn parse_ty_where_predicate_or_recover_tuple_struct_body( + &mut self, + struct_: Option<(Ident, Span)>, + pred_lo: Span, + where_sp: Span, + ) -> PResult<'a, PredicateOrStructBody> { + let mut snapshot = None; + + if let Some(struct_) = struct_ + && self.may_recover() + && self.token.kind == token::OpenDelim(Delimiter::Parenthesis) + { + snapshot = Some((struct_, self.create_snapshot_for_diagnostic())); + }; + + match self.parse_ty_where_predicate() { + Ok(pred) => Ok(PredicateOrStructBody::Predicate(pred)), + Err(type_err) => { + let Some(((struct_name, body_insertion_point), mut snapshot)) = snapshot else { + return Err(type_err); + }; + + // Check if we might have encountered an out of place tuple struct body. + match snapshot.parse_tuple_struct_body() { + // Since we don't know the exact reason why we failed to parse the + // predicate (we might have stumbled upon something bogus like `(T): ?`), + // employ a simple heuristic to weed out some pathological cases: + // Look for a semicolon (strong indicator) or anything that might mark + // the end of the item (weak indicator) following the body. + Ok(body) + if matches!(snapshot.token.kind, token::Semi | token::Eof) + || snapshot.token.can_begin_item() => + { + type_err.cancel(); + + let body_sp = pred_lo.to(snapshot.prev_token.span); + let map = self.sess.source_map(); + + self.sess.emit_err(WhereClauseBeforeTupleStructBody { + span: where_sp, + name: struct_name.span, + body: body_sp, + sugg: map.span_to_snippet(body_sp).ok().map(|body| { + WhereClauseBeforeTupleStructBodySugg { + left: body_insertion_point.shrink_to_hi(), + snippet: body, + right: map.end_point(where_sp).to(body_sp), + } + }), + }); + + self.restore_snapshot(snapshot); + Ok(PredicateOrStructBody::StructBody(body)) + } + Ok(_) => Err(type_err), + Err(body_err) => { + body_err.cancel(); + Err(type_err) + } + } + } + } } fn parse_ty_where_predicate(&mut self) -> PResult<'a, ast::WherePredicate> { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index a958c294930..53680a82bdc 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1454,8 +1454,16 @@ impl<'a> Parser<'a> { // struct. let vdata = if self.token.is_keyword(kw::Where) { - generics.where_clause = self.parse_where_clause()?; - if self.eat(&token::Semi) { + let tuple_struct_body; + (generics.where_clause, tuple_struct_body) = + self.parse_struct_where_clause(class_name, generics.span)?; + + if let Some(body) = tuple_struct_body { + // If we see a misplaced tuple struct body: `struct Foo<T> where T: Copy, (T);` + let body = VariantData::Tuple(body, DUMMY_NODE_ID); + self.expect_semi()?; + body + } else if self.eat(&token::Semi) { // If we see a: `struct Foo<T> where T: Copy;` style decl. VariantData::Unit(DUMMY_NODE_ID) } else { @@ -1575,7 +1583,7 @@ impl<'a> Parser<'a> { Ok((fields, recovered)) } - fn parse_tuple_struct_body(&mut self) -> PResult<'a, Vec<FieldDef>> { + pub(super) fn parse_tuple_struct_body(&mut self) -> PResult<'a, Vec<FieldDef>> { // This is the case where we find `struct Foo<T>(T) where T: Copy;` // Unit like structs are handled in parse_item_struct function self.parse_paren_comma_seq(|p| { @@ -2214,7 +2222,8 @@ impl<'a> Parser<'a> { *sig_hi = self.prev_token.span; (AttrVec::new(), None) } else if self.check(&token::OpenDelim(Delimiter::Brace)) || self.token.is_whole_block() { - self.parse_inner_attrs_and_block().map(|(attrs, body)| (attrs, Some(body)))? + self.parse_block_common(self.token.span, BlockCheckMode::Default, false) + .map(|(attrs, body)| (attrs, Some(body)))? } else if self.token.kind == token::Eq { // Recover `fn foo() = $expr;`. self.bump(); // `=` diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 49d31981539..ffb23b50a16 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -542,9 +542,9 @@ impl<'a> Parser<'a> { } } - /// Expect next token to be edible or inedible token. If edible, + /// Expect next token to be edible or inedible token. If edible, /// then consume it; if inedible, then return without consuming - /// anything. Signal a fatal error if next token is unexpected. + /// anything. Signal a fatal error if next token is unexpected. pub fn expect_one_of( &mut self, edible: &[TokenKind], @@ -736,6 +736,16 @@ impl<'a> Parser<'a> { self.check_or_expected(self.token.can_begin_const_arg(), TokenType::Const) } + fn check_const_closure(&self) -> bool { + self.is_keyword_ahead(0, &[kw::Const]) + && self.look_ahead(1, |t| match &t.kind { + token::Ident(kw::Move | kw::Static | kw::Async, _) + | token::OrOr + | token::BinOp(token::Or) => true, + _ => false, + }) + } + fn check_inline_const(&self, dist: usize) -> bool { self.is_keyword_ahead(dist, &[kw::Const]) && self.look_ahead(dist + 1, |t| match &t.kind { diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 0daae457d30..1e5c2834960 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -498,7 +498,7 @@ impl<'a> Parser<'a> { /// Parses a block. Inner attributes are allowed. pub(super) fn parse_inner_attrs_and_block(&mut self) -> PResult<'a, (AttrVec, P<Block>)> { - self.parse_block_common(self.token.span, BlockCheckMode::Default) + self.parse_block_common(self.token.span, BlockCheckMode::Default, true) } /// Parses a block. Inner attributes are allowed. @@ -506,16 +506,23 @@ impl<'a> Parser<'a> { &mut self, lo: Span, blk_mode: BlockCheckMode, + can_be_struct_literal: bool, ) -> PResult<'a, (AttrVec, P<Block>)> { maybe_whole!(self, NtBlock, |x| (AttrVec::new(), x)); + let maybe_ident = self.prev_token.clone(); self.maybe_recover_unexpected_block_label(); if !self.eat(&token::OpenDelim(Delimiter::Brace)) { return self.error_block_no_opening_brace(); } let attrs = self.parse_inner_attributes()?; - let tail = match self.maybe_suggest_struct_literal(lo, blk_mode) { + let tail = match self.maybe_suggest_struct_literal( + lo, + blk_mode, + maybe_ident, + can_be_struct_literal, + ) { Some(tail) => tail?, None => self.parse_block_tail(lo, blk_mode, AttemptLocalParseRecovery::Yes)?, }; |
