@@ -3789,7 +3789,13 @@ impl<'a> Parser<'a> {
37893789 self . span_err ( self . last_span , message) ;
37903790 }
37913791
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+ /// ```
37933799 pub fn parse_stmt ( & mut self ) -> PResult < ' a , Option < Stmt > > {
37943800 Ok ( self . parse_stmt_ ( ) )
37953801 }
@@ -4038,36 +4044,14 @@ impl<'a> Parser<'a> {
40384044 let mut stmts = vec ! [ ] ;
40394045
40404046 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 ) ;
40434049 } else if self . token == token:: Eof {
40444050 break ;
40454051 } else {
40464052 // Found only `;` or `}`.
40474053 continue ;
40484054 } ;
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- }
40714055 }
40724056
40734057 Ok ( P ( ast:: Block {
@@ -4078,93 +4062,88 @@ impl<'a> Parser<'a> {
40784062 } ) )
40794063 }
40804064
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) ) ;
41234093 }
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) ;
41244100 }
41254101 }
4126- Ok ( ( ) )
4102+
4103+ stmt = self . handle_trailing_semicolon ( stmt, macro_expanded) ?;
4104+ Ok ( Some ( stmt) )
41274105 }
41284106
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+ }
41424129 }
4130+ _ => { }
41434131 }
41444132
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 ( ) ;
41664135 }
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 ( ) ;
41684147 }
41694148
41704149 // Parses a sequence of bounds if a `:` is found,
0 commit comments