@@ -4044,7 +4044,7 @@ impl<'a> Parser<'a> {
4044
4044
let mut stmts = vec ! [ ] ;
4045
4045
4046
4046
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 ) ? {
4048
4048
stmts. push ( stmt) ;
4049
4049
} else if self . token == token:: Eof {
4050
4050
break ;
@@ -4064,7 +4064,7 @@ impl<'a> Parser<'a> {
4064
4064
4065
4065
/// Parse a statement, including the trailing semicolon.
4066
4066
/// 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 > > {
4068
4068
let mut stmt = match self . parse_stmt_ ( ) {
4069
4069
Some ( stmt) => stmt,
4070
4070
None => return Ok ( None ) ,
@@ -4075,6 +4075,23 @@ impl<'a> Parser<'a> {
4075
4075
self . token == token:: Semi || self . token == token:: Eof {
4076
4076
stmt. node = StmtKind :: Mac ( mac) ;
4077
4077
} 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
+
4078
4095
let ( mac, _style, attrs) = mac. unwrap ( ) ;
4079
4096
let e = self . mk_mac_expr ( stmt. span . lo , stmt. span . hi , mac. node , ThinVec :: new ( ) ) ;
4080
4097
let e = self . parse_dot_or_call_expr_with ( e, stmt. span . lo , attrs) ?;
@@ -4083,11 +4100,12 @@ impl<'a> Parser<'a> {
4083
4100
}
4084
4101
}
4085
4102
4086
- stmt = self . handle_trailing_semicolon ( stmt) ?;
4103
+ stmt = self . handle_trailing_semicolon ( stmt, macro_expanded ) ?;
4087
4104
Ok ( Some ( stmt) )
4088
4105
}
4089
4106
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 > {
4091
4109
match stmt. node {
4092
4110
StmtKind :: Expr ( ref expr) if self . token != token:: Eof => {
4093
4111
// expression without semicolon
@@ -4102,7 +4120,12 @@ impl<'a> Parser<'a> {
4102
4120
}
4103
4121
}
4104
4122
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
+ }
4106
4129
}
4107
4130
_ => { }
4108
4131
}
@@ -4115,6 +4138,14 @@ impl<'a> Parser<'a> {
4115
4138
Ok ( stmt)
4116
4139
}
4117
4140
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
+
4118
4149
// Parses a sequence of bounds if a `:` is found,
4119
4150
// otherwise returns empty list.
4120
4151
fn parse_colon_then_ty_param_bounds ( & mut self ,
0 commit comments