@@ -4044,7 +4044,7 @@ impl<'a> Parser<'a> {
40444044 let mut stmts = vec ! [ ] ;
40454045
40464046 while !self . eat ( & token:: CloseDelim ( token:: Brace ) ) {
4047- if let Some ( stmt) = self . parse_full_stmt ( ) ? {
4047+ if let Some ( stmt) = self . parse_full_stmt ( false ) ? {
40484048 stmts. push ( stmt) ;
40494049 } else if self . token == token:: Eof {
40504050 break ;
@@ -4064,7 +4064,7 @@ impl<'a> Parser<'a> {
40644064
40654065 /// Parse a statement, including the trailing semicolon.
40664066 /// This parses expression statements that begin with macros correctly (c.f. `parse_stmt`).
4067- pub fn parse_full_stmt ( & mut self ) -> PResult < ' a , Option < Stmt > > {
4067+ pub fn parse_full_stmt ( & mut self , macro_expanded : bool ) -> PResult < ' a , Option < Stmt > > {
40684068 let mut stmt = match self . parse_stmt_ ( ) {
40694069 Some ( stmt) => stmt,
40704070 None => return Ok ( None ) ,
@@ -4075,6 +4075,23 @@ impl<'a> Parser<'a> {
40754075 self . token == token:: Semi || self . token == token:: Eof {
40764076 stmt. node = StmtKind :: Mac ( mac) ;
40774077 } else {
4078+ // We used to incorrectly stop parsing macro-expanded statements here.
4079+ // If the next token will be an error anyway but could have parsed with the
4080+ // earlier behavior, stop parsing here and emit a warning to avoid breakage.
4081+ if macro_expanded && self . token . can_begin_expr ( ) && match self . token {
4082+ // These tokens can continue an expression, so we can't stop parsing and warn.
4083+ token:: OpenDelim ( token:: Paren ) | token:: OpenDelim ( token:: Bracket ) |
4084+ token:: BinOp ( token:: Minus ) | token:: BinOp ( token:: Star ) |
4085+ token:: BinOp ( token:: And ) | token:: BinOp ( token:: Or ) |
4086+ token:: AndAnd | token:: OrOr |
4087+ token:: DotDot | token:: DotDotDot => false ,
4088+ _ => true ,
4089+ } {
4090+ self . warn_missing_semicolon ( ) ;
4091+ stmt. node = StmtKind :: Mac ( mac) ;
4092+ return Ok ( Some ( stmt) ) ;
4093+ }
4094+
40784095 let ( mac, _style, attrs) = mac. unwrap ( ) ;
40794096 let e = self . mk_mac_expr ( stmt. span . lo , stmt. span . hi , mac. node , ThinVec :: new ( ) ) ;
40804097 let e = self . parse_dot_or_call_expr_with ( e, stmt. span . lo , attrs) ?;
@@ -4083,11 +4100,12 @@ impl<'a> Parser<'a> {
40834100 }
40844101 }
40854102
4086- stmt = self . handle_trailing_semicolon ( stmt) ?;
4103+ stmt = self . handle_trailing_semicolon ( stmt, macro_expanded ) ?;
40874104 Ok ( Some ( stmt) )
40884105 }
40894106
4090- fn handle_trailing_semicolon ( & mut self , mut stmt : Stmt ) -> PResult < ' a , Stmt > {
4107+ fn handle_trailing_semicolon ( & mut self , mut stmt : Stmt , macro_expanded : bool )
4108+ -> PResult < ' a , Stmt > {
40914109 match stmt. node {
40924110 StmtKind :: Expr ( ref expr) if self . token != token:: Eof => {
40934111 // expression without semicolon
@@ -4102,7 +4120,12 @@ impl<'a> Parser<'a> {
41024120 }
41034121 }
41044122 StmtKind :: Local ( ..) => {
4105- self . expect_one_of ( & [ token:: Semi ] , & [ ] ) ?;
4123+ // We used to incorrectly allow a macro-expanded let statement to lack a semicolon.
4124+ if macro_expanded && self . token != token:: Semi {
4125+ self . warn_missing_semicolon ( ) ;
4126+ } else {
4127+ self . expect_one_of ( & [ token:: Semi ] , & [ ] ) ?;
4128+ }
41064129 }
41074130 _ => { }
41084131 }
@@ -4115,6 +4138,14 @@ impl<'a> Parser<'a> {
41154138 Ok ( stmt)
41164139 }
41174140
4141+ fn warn_missing_semicolon ( & self ) {
4142+ self . diagnostic ( ) . struct_span_warn ( self . span , {
4143+ & format ! ( "expected `;`, found `{}`" , self . this_token_to_string( ) )
4144+ } ) . note ( {
4145+ "This was erroneously allowed and will become a hard error in a future release"
4146+ } ) . emit ( ) ;
4147+ }
4148+
41184149 // Parses a sequence of bounds if a `:` is found,
41194150 // otherwise returns empty list.
41204151 fn parse_colon_then_ty_param_bounds ( & mut self ,
0 commit comments