@@ -33,18 +33,19 @@ use rustc_ast::tokenstream::{
3333 ParserRange , ParserReplacement , Spacing , TokenCursor , TokenStream , TokenTree , TokenTreeCursor ,
3434} ;
3535use rustc_ast:: util:: case:: Case ;
36+ use rustc_ast:: util:: classify;
3637use rustc_ast:: {
37- self as ast, AnonConst , AttrArgs , AttrId , BlockCheckMode , ByRef , Const , CoroutineKind ,
38- DUMMY_NODE_ID , DelimArgs , Expr , ExprKind , Extern , HasAttrs , HasTokens , MgcaDisambiguation ,
39- Mutability , Recovered , Safety , StrLit , Visibility , VisibilityKind ,
38+ self as ast, AnonConst , AttrArgs , AttrId , BinOpKind , BlockCheckMode , ByRef , Const ,
39+ CoroutineKind , DUMMY_NODE_ID , DelimArgs , Expr , ExprKind , Extern , HasAttrs , HasTokens ,
40+ MgcaDisambiguation , Mutability , Recovered , Safety , StrLit , Visibility , VisibilityKind ,
4041} ;
4142use rustc_ast_pretty:: pprust;
4243use rustc_data_structures:: debug_assert_matches;
4344use rustc_data_structures:: fx:: FxHashMap ;
4445use rustc_errors:: { Applicability , Diag , FatalError , MultiSpan , PResult } ;
4546use rustc_index:: interval:: IntervalSet ;
4647use rustc_session:: parse:: ParseSess ;
47- use rustc_span:: { Ident , Span , Symbol , kw, sym} ;
48+ use rustc_span:: { ErrorGuaranteed , Ident , Span , Symbol , kw, sym} ;
4849use thin_vec:: ThinVec ;
4950use token_type:: TokenTypeSet ;
5051pub use token_type:: { ExpKeywordPair , ExpTokenPair , TokenType } ;
@@ -233,6 +234,10 @@ pub struct Parser<'a> {
233234 /// Whether the parser is allowed to do recovery.
234235 /// This is disabled when parsing macro arguments, see #103534
235236 recovery : Recovery = Recovery :: Allowed ,
237+ /// Whether we're parsing a function body.
238+ in_fn_body : bool = false,
239+ /// Whether we have detected a missing semicolon in the function body.
240+ pub fn_body_missing_semi_guar : Option < ErrorGuaranteed > = None ,
236241}
237242
238243// This type is used a lot, e.g. it's cloned when matching many declarative macro rules with
@@ -1681,6 +1686,65 @@ impl<'a> Parser<'a> {
16811686 _ => self . prev_token . span ,
16821687 }
16831688 }
1689+
1690+ fn missing_semi_from_binop (
1691+ & self ,
1692+ kind_desc : & str ,
1693+ expr : & Expr ,
1694+ decl_lo : Option < Span > ,
1695+ ) -> Option < ( Span , ErrorGuaranteed ) > {
1696+ if self . token == TokenKind :: Semi {
1697+ return None ;
1698+ }
1699+ if !self . may_recover ( ) || expr. span . from_expansion ( ) {
1700+ return None ;
1701+ }
1702+ let sm = self . psess . source_map ( ) ;
1703+ if let ExprKind :: Binary ( op, lhs, rhs) = & expr. kind
1704+ && sm. is_multiline ( lhs. span . shrink_to_hi ( ) . until ( rhs. span . shrink_to_lo ( ) ) )
1705+ && matches ! ( op. node, BinOpKind :: Mul | BinOpKind :: BitAnd )
1706+ && classify:: expr_requires_semi_to_be_stmt ( rhs)
1707+ {
1708+ let lhs_end_span = lhs. span . shrink_to_hi ( ) ;
1709+ let token_str = token_descr ( & self . token ) ;
1710+ let mut err = self
1711+ . dcx ( )
1712+ . struct_span_err ( lhs_end_span, format ! ( "expected `;`, found {token_str}" ) ) ;
1713+ err. span_label ( self . token . span , "unexpected token" ) ;
1714+
1715+ // Use the declaration start if provided, otherwise fall back to lhs_end_span.
1716+ let continuation_start = decl_lo. unwrap_or ( lhs_end_span) ;
1717+ let continuation_span = continuation_start. until ( rhs. span . shrink_to_hi ( ) ) ;
1718+ err. span_label (
1719+ continuation_span,
1720+ format ! (
1721+ "to finish parsing this {kind_desc}, expected this to be followed by a `;`" ,
1722+ ) ,
1723+ ) ;
1724+ let op_desc = match op. node {
1725+ BinOpKind :: BitAnd => "a bit-and" ,
1726+ BinOpKind :: Mul => "a multiplication" ,
1727+ _ => "a binary" ,
1728+ } ;
1729+ let mut note_spans = MultiSpan :: new ( ) ;
1730+ note_spans. push_span_label ( lhs. span , "parsed as the left-hand expression" ) ;
1731+ note_spans. push_span_label ( rhs. span , "parsed as the right-hand expression" ) ;
1732+ note_spans. push_span_label ( op. span , format ! ( "this was parsed as {op_desc}" ) ) ;
1733+ err. span_note (
1734+ note_spans,
1735+ format ! ( "the {kind_desc} was parsed as having {op_desc} binary expression" ) ,
1736+ ) ;
1737+
1738+ err. span_suggestion (
1739+ lhs_end_span,
1740+ format ! ( "you may have meant to write a `;` to terminate the {kind_desc} earlier" ) ,
1741+ ";" ,
1742+ Applicability :: MaybeIncorrect ,
1743+ ) ;
1744+ return Some ( ( lhs. span , err. emit ( ) ) ) ;
1745+ }
1746+ None
1747+ }
16841748}
16851749
16861750// Metavar captures of various kinds.
0 commit comments