@@ -32,18 +32,19 @@ use rustc_ast::tokenstream::{
3232 ParserRange , ParserReplacement , Spacing , TokenCursor , TokenStream , TokenTree , TokenTreeCursor ,
3333} ;
3434use rustc_ast:: util:: case:: Case ;
35+ use rustc_ast:: util:: classify;
3536use rustc_ast:: {
36- self as ast, AnonConst , AttrArgs , AttrId , ByRef , Const , CoroutineKind , DUMMY_NODE_ID ,
37- DelimArgs , Expr , ExprKind , Extern , HasAttrs , HasTokens , MgcaDisambiguation , Mutability ,
38- Recovered , Safety , StrLit , Visibility , VisibilityKind ,
37+ self as ast, AnonConst , AttrArgs , AttrId , BinOpKind , ByRef , Const , CoroutineKind ,
38+ DUMMY_NODE_ID , DelimArgs , Expr , ExprKind , Extern , HasAttrs , HasTokens , MgcaDisambiguation ,
39+ Mutability , Recovered , Safety , StrLit , Visibility , VisibilityKind ,
3940} ;
4041use rustc_ast_pretty:: pprust;
4142use rustc_data_structures:: debug_assert_matches;
4243use rustc_data_structures:: fx:: FxHashMap ;
4344use rustc_errors:: { Applicability , Diag , FatalError , MultiSpan , PResult } ;
4445use rustc_index:: interval:: IntervalSet ;
4546use rustc_session:: parse:: ParseSess ;
46- use rustc_span:: { Ident , Span , Symbol , kw, sym} ;
47+ use rustc_span:: { ErrorGuaranteed , Ident , Span , Symbol , kw, sym} ;
4748use thin_vec:: ThinVec ;
4849use token_type:: TokenTypeSet ;
4950pub use token_type:: { ExpKeywordPair , ExpTokenPair , TokenType } ;
@@ -232,6 +233,10 @@ pub struct Parser<'a> {
232233 /// Whether the parser is allowed to do recovery.
233234 /// This is disabled when parsing macro arguments, see #103534
234235 recovery : Recovery = Recovery :: Allowed ,
236+ /// Whether we're parsing a function body.
237+ in_fn_body : bool = false,
238+ /// Whether we have detected a missing semicolon in function body.
239+ pub fn_body_missing_semi_guar : Option < ErrorGuaranteed > = None ,
235240}
236241
237242// This type is used a lot, e.g. it's cloned when matching many declarative macro rules with
@@ -1649,6 +1654,65 @@ impl<'a> Parser<'a> {
16491654 _ => self . prev_token . span ,
16501655 }
16511656 }
1657+
1658+ fn missing_semi_from_binop (
1659+ & self ,
1660+ kind_desc : & str ,
1661+ expr : & Expr ,
1662+ decl_lo : Option < Span > ,
1663+ ) -> Option < ( Span , ErrorGuaranteed ) > {
1664+ if self . token == TokenKind :: Semi {
1665+ return None ;
1666+ }
1667+ if !self . may_recover ( ) || expr. span . from_expansion ( ) {
1668+ return None ;
1669+ }
1670+ let sm = self . psess . source_map ( ) ;
1671+ if let ExprKind :: Binary ( op, lhs, rhs) = & expr. kind
1672+ && sm. is_multiline ( lhs. span . shrink_to_hi ( ) . until ( rhs. span . shrink_to_lo ( ) ) )
1673+ && matches ! ( op. node, BinOpKind :: Mul | BinOpKind :: BitAnd )
1674+ && classify:: expr_requires_semi_to_be_stmt ( rhs)
1675+ {
1676+ let lhs_end_span = lhs. span . shrink_to_hi ( ) ;
1677+ let token_str = token_descr ( & self . token ) ;
1678+ let mut err = self
1679+ . dcx ( )
1680+ . struct_span_err ( lhs_end_span, format ! ( "expected `;`, found {token_str}" ) ) ;
1681+ err. span_label ( self . token . span , "unexpected token" ) ;
1682+
1683+ // Use the declaration start if provided, otherwise fall back to lhs_end_span.
1684+ let continuation_start = decl_lo. unwrap_or ( lhs_end_span) ;
1685+ let continuation_span = continuation_start. until ( rhs. span . shrink_to_hi ( ) ) ;
1686+ err. span_label (
1687+ continuation_span,
1688+ format ! (
1689+ "to finish parsing this {kind_desc}, expected this to be followed by a `;`" ,
1690+ ) ,
1691+ ) ;
1692+ let op_desc = match op. node {
1693+ BinOpKind :: BitAnd => "a bit-and" ,
1694+ BinOpKind :: Mul => "a multiplication" ,
1695+ _ => "a binary" ,
1696+ } ;
1697+ let mut note_spans = MultiSpan :: new ( ) ;
1698+ note_spans. push_span_label ( lhs. span , "parsed as the left-hand expression" ) ;
1699+ note_spans. push_span_label ( rhs. span , "parsed as the right-hand expression" ) ;
1700+ note_spans. push_span_label ( op. span , format ! ( "this was parsed as {op_desc}" ) ) ;
1701+ err. span_note (
1702+ note_spans,
1703+ format ! ( "the {kind_desc} was parsed as having {op_desc} binary expression" ) ,
1704+ ) ;
1705+
1706+ err. span_suggestion (
1707+ lhs_end_span,
1708+ format ! ( "you may have meant to write a `;` to terminate the {kind_desc} earlier" ) ,
1709+ ";" ,
1710+ Applicability :: MaybeIncorrect ,
1711+ ) ;
1712+ return Some ( ( lhs. span , err. emit ( ) ) ) ;
1713+ }
1714+ None
1715+ }
16521716}
16531717
16541718// Metavar captures of various kinds.
0 commit comments