@@ -3789,7 +3789,13 @@ impl<'a> Parser<'a> {
3789
3789
self . span_err ( self . last_span , message) ;
3790
3790
}
3791
3791
3792
- /// Parse a statement. may include decl.
3792
+ /// Parse a statement. This stops just before trailing semicolons on everything but items.
3793
+ /// e.g. a `StmtKind::Semi` parses to a `StmtKind::Expr`, leaving the trailing `;` unconsumed.
3794
+ ///
3795
+ /// Also, if a macro begins an expression statement, this only parses the macro. For example,
3796
+ /// ```rust
3797
+ /// vec![1].into_iter(); //< `parse_stmt` only parses the "vec![1]"
3798
+ /// ```
3793
3799
pub fn parse_stmt ( & mut self ) -> PResult < ' a , Option < Stmt > > {
3794
3800
Ok ( self . parse_stmt_ ( ) )
3795
3801
}
@@ -4038,36 +4044,14 @@ impl<'a> Parser<'a> {
4038
4044
let mut stmts = vec ! [ ] ;
4039
4045
4040
4046
while !self . eat ( & token:: CloseDelim ( token:: Brace ) ) {
4041
- let Stmt { node , span , .. } = if let Some ( s ) = self . parse_stmt_ ( ) {
4042
- s
4047
+ if let Some ( stmt ) = self . parse_full_stmt ( false ) ? {
4048
+ stmts . push ( stmt ) ;
4043
4049
} else if self . token == token:: Eof {
4044
4050
break ;
4045
4051
} else {
4046
4052
// Found only `;` or `}`.
4047
4053
continue ;
4048
4054
} ;
4049
-
4050
- match node {
4051
- StmtKind :: Expr ( e) => {
4052
- self . handle_expression_like_statement ( e, span, & mut stmts) ?;
4053
- }
4054
- StmtKind :: Mac ( mac) => {
4055
- self . handle_macro_in_block ( mac. unwrap ( ) , span, & mut stmts) ?;
4056
- }
4057
- _ => { // all other kinds of statements:
4058
- let mut hi = span. hi ;
4059
- if classify:: stmt_ends_with_semi ( & node) {
4060
- self . expect ( & token:: Semi ) ?;
4061
- hi = self . last_span . hi ;
4062
- }
4063
-
4064
- stmts. push ( Stmt {
4065
- id : ast:: DUMMY_NODE_ID ,
4066
- node : node,
4067
- span : mk_sp ( span. lo , hi)
4068
- } ) ;
4069
- }
4070
- }
4071
4055
}
4072
4056
4073
4057
Ok ( P ( ast:: Block {
@@ -4078,93 +4062,88 @@ impl<'a> Parser<'a> {
4078
4062
} ) )
4079
4063
}
4080
4064
4081
- fn handle_macro_in_block ( & mut self ,
4082
- ( mac, style, attrs) : ( ast:: Mac , MacStmtStyle , ThinVec < Attribute > ) ,
4083
- span : Span ,
4084
- stmts : & mut Vec < Stmt > )
4085
- -> PResult < ' a , ( ) > {
4086
- if style == MacStmtStyle :: NoBraces {
4087
- // statement macro without braces; might be an
4088
- // expr depending on whether a semicolon follows
4089
- match self . token {
4090
- token:: Semi => {
4091
- stmts. push ( Stmt {
4092
- id : ast:: DUMMY_NODE_ID ,
4093
- node : StmtKind :: Mac ( P ( ( mac, MacStmtStyle :: Semicolon , attrs) ) ) ,
4094
- span : mk_sp ( span. lo , self . span . hi ) ,
4095
- } ) ;
4096
- self . bump ( ) ;
4097
- }
4098
- _ => {
4099
- let e = self . mk_mac_expr ( span. lo , span. hi , mac. node , ThinVec :: new ( ) ) ;
4100
- let lo = e. span . lo ;
4101
- let e = self . parse_dot_or_call_expr_with ( e, lo, attrs) ?;
4102
- let e = self . parse_assoc_expr_with ( 0 , LhsExpr :: AlreadyParsed ( e) ) ?;
4103
- self . handle_expression_like_statement ( e, span, stmts) ?;
4104
- }
4105
- }
4106
- } else {
4107
- // statement macro; might be an expr
4108
- match self . token {
4109
- token:: Semi => {
4110
- stmts. push ( Stmt {
4111
- id : ast:: DUMMY_NODE_ID ,
4112
- node : StmtKind :: Mac ( P ( ( mac, MacStmtStyle :: Semicolon , attrs) ) ) ,
4113
- span : mk_sp ( span. lo , self . span . hi ) ,
4114
- } ) ;
4115
- self . bump ( ) ;
4116
- }
4117
- _ => {
4118
- stmts. push ( Stmt {
4119
- id : ast:: DUMMY_NODE_ID ,
4120
- node : StmtKind :: Mac ( P ( ( mac, style, attrs) ) ) ,
4121
- span : span
4122
- } ) ;
4065
+ /// Parse a statement, including the trailing semicolon.
4066
+ /// This parses expression statements that begin with macros correctly (c.f. `parse_stmt`).
4067
+ pub fn parse_full_stmt ( & mut self , macro_expanded : bool ) -> PResult < ' a , Option < Stmt > > {
4068
+ let mut stmt = match self . parse_stmt_ ( ) {
4069
+ Some ( stmt) => stmt,
4070
+ None => return Ok ( None ) ,
4071
+ } ;
4072
+
4073
+ if let StmtKind :: Mac ( mac) = stmt. node {
4074
+ if mac. 1 != MacStmtStyle :: NoBraces ||
4075
+ self . token == token:: Semi || self . token == token:: Eof {
4076
+ stmt. node = StmtKind :: Mac ( mac) ;
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) ) ;
4123
4093
}
4094
+
4095
+ let ( mac, _style, attrs) = mac. unwrap ( ) ;
4096
+ let e = self . mk_mac_expr ( stmt. span . lo , stmt. span . hi , mac. node , ThinVec :: new ( ) ) ;
4097
+ let e = self . parse_dot_or_call_expr_with ( e, stmt. span . lo , attrs) ?;
4098
+ let e = self . parse_assoc_expr_with ( 0 , LhsExpr :: AlreadyParsed ( e) ) ?;
4099
+ stmt. node = StmtKind :: Expr ( e) ;
4124
4100
}
4125
4101
}
4126
- Ok ( ( ) )
4102
+
4103
+ stmt = self . handle_trailing_semicolon ( stmt, macro_expanded) ?;
4104
+ Ok ( Some ( stmt) )
4127
4105
}
4128
4106
4129
- fn handle_expression_like_statement ( & mut self ,
4130
- e : P < Expr > ,
4131
- span : Span ,
4132
- stmts : & mut Vec < Stmt > )
4133
- -> PResult < ' a , ( ) > {
4134
- // expression without semicolon
4135
- if classify:: expr_requires_semi_to_be_stmt ( & e) {
4136
- // Just check for errors and recover; do not eat semicolon yet.
4137
- if let Err ( mut e) =
4138
- self . expect_one_of ( & [ ] , & [ token:: Semi , token:: CloseDelim ( token:: Brace ) ] )
4139
- {
4140
- e. emit ( ) ;
4141
- self . recover_stmt ( ) ;
4107
+ fn handle_trailing_semicolon ( & mut self , mut stmt : Stmt , macro_expanded : bool )
4108
+ -> PResult < ' a , Stmt > {
4109
+ match stmt. node {
4110
+ StmtKind :: Expr ( ref expr) if self . token != token:: Eof => {
4111
+ // expression without semicolon
4112
+ if classify:: expr_requires_semi_to_be_stmt ( expr) {
4113
+ // Just check for errors and recover; do not eat semicolon yet.
4114
+ if let Err ( mut e) =
4115
+ self . expect_one_of ( & [ ] , & [ token:: Semi , token:: CloseDelim ( token:: Brace ) ] )
4116
+ {
4117
+ e. emit ( ) ;
4118
+ self . recover_stmt ( ) ;
4119
+ }
4120
+ }
4121
+ }
4122
+ StmtKind :: Local ( ..) => {
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
+ }
4142
4129
}
4130
+ _ => { }
4143
4131
}
4144
4132
4145
- match self . token {
4146
- token:: Semi => {
4147
- self . bump ( ) ;
4148
- let span_with_semi = Span {
4149
- lo : span. lo ,
4150
- hi : self . last_span . hi ,
4151
- expn_id : span. expn_id ,
4152
- } ;
4153
- stmts. push ( Stmt {
4154
- id : ast:: DUMMY_NODE_ID ,
4155
- node : StmtKind :: Semi ( e) ,
4156
- span : span_with_semi,
4157
- } ) ;
4158
- }
4159
- _ => {
4160
- stmts. push ( Stmt {
4161
- id : ast:: DUMMY_NODE_ID ,
4162
- node : StmtKind :: Expr ( e) ,
4163
- span : span
4164
- } ) ;
4165
- }
4133
+ if self . eat ( & token:: Semi ) {
4134
+ stmt = stmt. add_trailing_semicolon ( ) ;
4166
4135
}
4167
- Ok ( ( ) )
4136
+
4137
+ stmt. span . hi = self . last_span . hi ;
4138
+ Ok ( stmt)
4139
+ }
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 ( ) ;
4168
4147
}
4169
4148
4170
4149
// Parses a sequence of bounds if a `:` is found,
0 commit comments