]> git.lizzy.rs Git - rust.git/blobdiff - src/libsyntax/parse/parser.rs
Auto merge of #34925 - jseyfried:nested_macros, r=eddyb
[rust.git] / src / libsyntax / parse / parser.rs
index 32107026eedf46e36b4a7db4e10491dfbdc4a1b2..c143e190c6fc16ce814c785d88aab8e0d5889974 100644 (file)
@@ -3793,13 +3793,8 @@ fn expected_item_err(&self, attrs: &[Attribute]) {
 
     /// Parse a statement. This stops just before trailing semicolons on everything but items.
     /// e.g. a `StmtKind::Semi` parses to a `StmtKind::Expr`, leaving the trailing `;` unconsumed.
-    ///
-    /// Also, if a macro begins an expression statement, this only parses the macro. For example,
-    /// ```rust
-    /// vec![1].into_iter(); //< `parse_stmt` only parses the "vec![1]"
-    /// ```
     pub fn parse_stmt(&mut self) -> PResult<'a, Option<Stmt>> {
-        Ok(self.parse_stmt_())
+        Ok(self.parse_stmt_(true))
     }
 
     // Eat tokens until we can be relatively sure we reached the end of the
@@ -3863,15 +3858,15 @@ fn recover_stmt_(&mut self, break_on_semi: SemiColonMode) {
         }
     }
 
-    fn parse_stmt_(&mut self) -> Option<Stmt> {
-        self.parse_stmt_without_recovery().unwrap_or_else(|mut e| {
+    fn parse_stmt_(&mut self, macro_expanded: bool) -> Option<Stmt> {
+        self.parse_stmt_without_recovery(macro_expanded).unwrap_or_else(|mut e| {
             e.emit();
             self.recover_stmt_(SemiColonMode::Break);
             None
         })
     }
 
-    fn parse_stmt_without_recovery(&mut self) -> PResult<'a, Option<Stmt>> {
+    fn parse_stmt_without_recovery(&mut self, macro_expanded: bool) -> PResult<'a, Option<Stmt>> {
         maybe_whole!(Some deref self, NtStmt);
 
         let attrs = self.parse_outer_attributes()?;
@@ -3934,10 +3929,34 @@ fn parse_stmt_without_recovery(&mut self) -> PResult<'a, Option<Stmt>> {
 
             if id.name == keywords::Invalid.name() {
                 let mac = spanned(lo, hi, Mac_ { path: pth, tts: tts });
+                let node = if delim == token::Brace ||
+                              self.token == token::Semi || self.token == token::Eof {
+                    StmtKind::Mac(P((mac, style, attrs.into())))
+                }
+                // We used to incorrectly stop parsing macro-expanded statements here.
+                // If the next token will be an error anyway but could have parsed with the
+                // earlier behavior, stop parsing here and emit a warning to avoid breakage.
+                else if macro_expanded && self.token.can_begin_expr() && match self.token {
+                    // These can continue an expression, so we can't stop parsing and warn.
+                    token::OpenDelim(token::Paren) | token::OpenDelim(token::Bracket) |
+                    token::BinOp(token::Minus) | token::BinOp(token::Star) |
+                    token::BinOp(token::And) | token::BinOp(token::Or) |
+                    token::AndAnd | token::OrOr |
+                    token::DotDot | token::DotDotDot => false,
+                    _ => true,
+                } {
+                    self.warn_missing_semicolon();
+                    StmtKind::Mac(P((mac, style, attrs.into())))
+                } else {
+                    let e = self.mk_mac_expr(lo, hi, mac.node, ThinVec::new());
+                    let e = self.parse_dot_or_call_expr_with(e, lo, attrs.into())?;
+                    let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?;
+                    StmtKind::Expr(e)
+                };
                 Stmt {
                     id: ast::DUMMY_NODE_ID,
-                    node: StmtKind::Mac(P((mac, style, attrs.into()))),
                     span: mk_sp(lo, hi),
+                    node: node,
                 }
             } else {
                 // if it has a special ident, it's definitely an item
@@ -4065,49 +4084,12 @@ fn parse_block_tail(&mut self, lo: BytePos, s: BlockCheckMode) -> PResult<'a, P<
     }
 
     /// Parse a statement, including the trailing semicolon.
-    /// This parses expression statements that begin with macros correctly (c.f. `parse_stmt`).
     pub fn parse_full_stmt(&mut self, macro_expanded: bool) -> PResult<'a, Option<Stmt>> {
-        let mut stmt = match self.parse_stmt_() {
+        let mut stmt = match self.parse_stmt_(macro_expanded) {
             Some(stmt) => stmt,
             None => return Ok(None),
         };
 
-        if let StmtKind::Mac(mac) = stmt.node {
-            if mac.1 != MacStmtStyle::NoBraces ||
-               self.token == token::Semi || self.token == token::Eof {
-                stmt.node = StmtKind::Mac(mac);
-            } else {
-                // We used to incorrectly stop parsing macro-expanded statements here.
-                // If the next token will be an error anyway but could have parsed with the
-                // earlier behavior, stop parsing here and emit a warning to avoid breakage.
-                if macro_expanded && self.token.can_begin_expr() && match self.token {
-                    // These tokens can continue an expression, so we can't stop parsing and warn.
-                    token::OpenDelim(token::Paren) | token::OpenDelim(token::Bracket) |
-                    token::BinOp(token::Minus) | token::BinOp(token::Star) |
-                    token::BinOp(token::And) | token::BinOp(token::Or) |
-                    token::AndAnd | token::OrOr |
-                    token::DotDot | token::DotDotDot => false,
-                    _ => true,
-                } {
-                    self.warn_missing_semicolon();
-                    stmt.node = StmtKind::Mac(mac);
-                    return Ok(Some(stmt));
-                }
-
-                let (mac, _style, attrs) = mac.unwrap();
-                let e = self.mk_mac_expr(stmt.span.lo, stmt.span.hi, mac.node, ThinVec::new());
-                let e = self.parse_dot_or_call_expr_with(e, stmt.span.lo, attrs)?;
-                let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?;
-                stmt.node = StmtKind::Expr(e);
-            }
-        }
-
-        stmt = self.handle_trailing_semicolon(stmt, macro_expanded)?;
-        Ok(Some(stmt))
-    }
-
-    fn handle_trailing_semicolon(&mut self, mut stmt: Stmt, macro_expanded: bool)
-                                 -> PResult<'a, Stmt> {
         match stmt.node {
             StmtKind::Expr(ref expr) if self.token != token::Eof => {
                 // expression without semicolon
@@ -4137,7 +4119,7 @@ fn handle_trailing_semicolon(&mut self, mut stmt: Stmt, macro_expanded: bool)
         }
 
         stmt.span.hi = self.last_span.hi;
-        Ok(stmt)
+        Ok(Some(stmt))
     }
 
     fn warn_missing_semicolon(&self) {