From: Jeffrey Seyfried Date: Sun, 26 Jun 2016 02:19:34 +0000 (+0000) Subject: Rollup merge of #34436 - jseyfried:no_block_expr, r=eddyb X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=9bb3ea0febcbb8f6d7715256a5644daa985cf4e7;p=rust.git Rollup merge of #34436 - jseyfried:no_block_expr, r=eddyb To allow these braced macro invocation, this PR removes the optional expression from `ast::Block` and instead uses a `StmtKind::Expr` at the end of the statement list. Currently, braced macro invocations in blocks can expand into statements (and items) except when they are last in a block, in which case they can only expand into expressions. For example, ```rust macro_rules! make_stmt { () => { let x = 0; } } fn f() { make_stmt! {} //< This is OK... let x = 0; //< ... unless this line is commented out. } ``` Fixes #34418. --- 9bb3ea0febcbb8f6d7715256a5644daa985cf4e7 diff --cc src/librustc_driver/driver.rs index 927953b034b,c0be9298439..eb442c0a34e --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@@ -763,6 -763,10 +763,9 @@@ pub fn phase_2_configure_and_expand<'a> } pub fn assign_node_ids(sess: &Session, krate: ast::Crate) -> ast::Crate { - use syntax::codemap::Spanned; + use syntax::ptr::P; + use syntax::util::move_map::MoveMap; + struct NodeIdAssigner<'a> { sess: &'a Session, } @@@ -772,6 -776,27 +775,27 @@@ assert_eq!(old_id, ast::DUMMY_NODE_ID); self.sess.next_node_id() } + + fn fold_block(&mut self, block: P) -> P { + block.map(|mut block| { + block.id = self.new_id(block.id); + + let stmt = block.stmts.pop(); + block.stmts = block.stmts.move_flat_map(|s| self.fold_stmt(s).into_iter()); - if let Some(Spanned { node: ast::StmtKind::Expr(expr, _), span }) = stmt { ++ if let Some(ast::Stmt { node: ast::StmtKind::Expr(expr), span, .. }) = stmt { + let expr = self.fold_expr(expr); - let id = expr.id; - block.stmts.push(Spanned { ++ block.stmts.push(ast::Stmt { ++ id: expr.id, ++ node: ast::StmtKind::Expr(expr), + span: span, - node: ast::StmtKind::Expr(expr, id) + }); + } else if let Some(stmt) = stmt { + block.stmts.extend(self.fold_stmt(stmt)); + } + + block + }) + } } let krate = time(sess.time_passes(), diff --cc src/librustc_driver/pretty.rs index 80eea76e107,4c0082ed5b8..baac455a25f --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@@ -657,11 -657,13 +657,14 @@@ impl fold::Folder for ReplaceBodyWithLo fn fold_block(&mut self, b: P) -> P { fn expr_to_block(rules: ast::BlockCheckMode, e: Option>) -> P { P(ast::Block { - expr: e, - stmts: vec![], - stmts: e.map(|e| codemap::Spanned { ++ stmts: e.map(|e| ast::Stmt { ++ id: ast::DUMMY_NODE_ID, + span: e.span, - node: ast::StmtKind::Expr(e, ast::DUMMY_NODE_ID), ++ node: ast::StmtKind::Expr(e), + }).into_iter().collect(), rules: rules, id: ast::DUMMY_NODE_ID, - span: codemap::DUMMY_SP, + span: syntax_pos::DUMMY_SP, }) } diff --cc src/libsyntax/ast.rs index dcdc1e60a99,e138119149c..a352715b20b --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@@ -826,18 -797,31 +823,18 @@@ impl fmt::Debug for Stmt #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)] pub enum StmtKind { - /// Could be an item or a local (let) binding: - Decl(P, NodeId), + /// A local (let) binding. + Local(P), - /// Expr without trailing semi-colon - Expr(P, NodeId), + /// An item definition. + Item(P), - /// Expr without trailing semi-colon (must have unit type). - /// Expr with trailing semi-colon (may have any type): - Semi(P, NodeId), ++ /// Expr without trailing semi-colon. + Expr(P), - Mac(P, MacStmtStyle, ThinAttributes), -} + Semi(P), -impl StmtKind { - pub fn id(&self) -> Option { - match *self { - StmtKind::Decl(_, id) => Some(id), - StmtKind::Expr(_, id) => Some(id), - StmtKind::Semi(_, id) => Some(id), - StmtKind::Mac(..) => None, - } - } - - pub fn attrs(&self) -> &[Attribute] { - HasAttrs::attrs(self) - } + Mac(P<(Mac, MacStmtStyle, ThinVec)>), } #[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] diff --cc src/libsyntax/ext/build.rs index f4ae23ed8be,4bfbd37edd9..435241f426e --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@@ -509,11 -505,11 +506,19 @@@ impl<'a> AstBuilder for ExtCtxt<'a> } fn stmt_expr(&self, expr: P) -> ast::Stmt { - respan(expr.span, ast::StmtKind::Expr(expr, ast::DUMMY_NODE_ID)) ++ ast::Stmt { ++ id: ast::DUMMY_NODE_ID, ++ span: expr.span, ++ node: ast::StmtKind::Expr(expr), ++ } + } + + fn stmt_semi(&self, expr: P) -> ast::Stmt { - respan(expr.span, ast::StmtKind::Semi(expr, ast::DUMMY_NODE_ID)) + ast::Stmt { + id: ast::DUMMY_NODE_ID, + span: expr.span, + node: ast::StmtKind::Semi(expr), + } } fn stmt_let(&self, sp: Span, mutbl: bool, ident: ast::Ident, @@@ -558,42 -551,30 +563,37 @@@ init: Some(ex), id: ast::DUMMY_NODE_ID, span: sp, - attrs: None, + attrs: ast::ThinVec::new(), }); - let decl = respan(sp, ast::DeclKind::Local(local)); - P(respan(sp, ast::StmtKind::Decl(P(decl), ast::DUMMY_NODE_ID))) + P(ast::Stmt { + id: ast::DUMMY_NODE_ID, + node: ast::StmtKind::Local(local), + span: sp, + }) } - fn block(&self, span: Span, stmts: Vec, - expr: Option>) -> P { - self.block_all(span, stmts, expr) - } - fn stmt_item(&self, sp: Span, item: P) -> ast::Stmt { - let decl = respan(sp, ast::DeclKind::Item(item)); - respan(sp, ast::StmtKind::Decl(P(decl), ast::DUMMY_NODE_ID)) + ast::Stmt { + id: ast::DUMMY_NODE_ID, + node: ast::StmtKind::Item(item), + span: sp, + } } fn block_expr(&self, expr: P) -> P { - self.block_all(expr.span, Vec::new(), Some(expr)) - } - fn block_all(&self, - span: Span, - stmts: Vec, - expr: Option>) -> P { - P(ast::Block { - stmts: stmts, - expr: expr, - id: ast::DUMMY_NODE_ID, - rules: BlockCheckMode::Default, - span: span, - }) - self.block(expr.span, vec![Spanned { ++ self.block(expr.span, vec![ast::Stmt { ++ id: ast::DUMMY_NODE_ID, + span: expr.span, - node: ast::StmtKind::Expr(expr, ast::DUMMY_NODE_ID), ++ node: ast::StmtKind::Expr(expr), + }]) + } + fn block(&self, span: Span, stmts: Vec) -> P { + P(ast::Block { + stmts: stmts, + id: ast::DUMMY_NODE_ID, + rules: BlockCheckMode::Default, + span: span, + }) } fn expr(&self, span: Span, node: ast::ExprKind) -> P { diff --cc src/libsyntax/parse/mod.rs index 0c5a672dfbc,f79d6e8421a..bbcc044d43c --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@@ -954,10 -950,9 +954,9 @@@ mod tests ), }), span: sp(17,18), - attrs: None,}), - ast::DUMMY_NODE_ID), + attrs: ThinVec::new()})), + id: ast::DUMMY_NODE_ID, span: sp(17,19)}), - expr: None, id: ast::DUMMY_NODE_ID, rules: ast::BlockCheckMode::Default, // no idea span: sp(15,21), diff --cc src/libsyntax/parse/parser.rs index 83401011ed4,dea6589fe7c..813d90103b8 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@@ -3236,9 -3217,11 +3236,12 @@@ impl<'a> Parser<'a> let body_expr = self.parse_expr()?; P(ast::Block { id: ast::DUMMY_NODE_ID, - stmts: vec![], span: body_expr.span, - expr: Some(body_expr), - stmts: vec![Spanned { ++ stmts: vec![Stmt { + span: body_expr.span, - node: StmtKind::Expr(body_expr, ast::DUMMY_NODE_ID), ++ node: StmtKind::Expr(body_expr), ++ id: ast::DUMMY_NODE_ID, + }], rules: BlockCheckMode::Default, }) } @@@ -4098,10 -4084,9 +4101,9 @@@ /// Precondition: already parsed the '{'. fn parse_block_tail(&mut self, lo: BytePos, s: BlockCheckMode) -> PResult<'a, P> { let mut stmts = vec![]; - let mut expr = None; while !self.eat(&token::CloseDelim(token::Brace)) { - let Spanned {node, span} = if let Some(s) = self.parse_stmt_() { + let Stmt {node, span, ..} = if let Some(s) = self.parse_stmt_() { s } else if self.token == token::Eof { break; @@@ -4109,13 -4094,48 +4111,13 @@@ // Found only `;` or `}`. continue; }; + match node { - StmtKind::Expr(e, _) => { + StmtKind::Expr(e) => { - self.handle_expression_like_statement(e, span, &mut stmts, &mut expr)?; + self.handle_expression_like_statement(e, span, &mut stmts)?; } - StmtKind::Mac(mac, MacStmtStyle::NoBraces, attrs) => { - // statement macro without braces - match self.token { - token::Semi => { - stmts.push(Spanned { - node: StmtKind::Mac(mac, MacStmtStyle::Semicolon, attrs), - span: mk_sp(span.lo, self.span.hi), - }); - self.bump(); - } - _ => { - let e = self.mk_mac_expr(span.lo, span.hi, - mac.and_then(|m| m.node), - None); - let lo = e.span.lo; - let e = self.parse_dot_or_call_expr_with(e, lo, attrs)?; - let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?; - self.handle_expression_like_statement(e, span, &mut stmts)?; - } - } - } - StmtKind::Mac(m, style, attrs) => { - // statement macro; might be an expr - match self.token { - token::Semi => { - stmts.push(Spanned { - node: StmtKind::Mac(m, MacStmtStyle::Semicolon, attrs), - span: mk_sp(span.lo, self.span.hi), - }); - self.bump(); - } - _ => { - stmts.push(Spanned { - node: StmtKind::Mac(m, style, attrs), - span: span - }); - } - } + StmtKind::Mac(mac) => { - self.handle_macro_in_block(mac.unwrap(), span, &mut stmts, &mut expr)?; ++ self.handle_macro_in_block(mac.unwrap(), span, &mut stmts)?; } _ => { // all other kinds of statements: let mut hi = span.hi; @@@ -4142,60 -4160,6 +4143,54 @@@ })) } + fn handle_macro_in_block(&mut self, + (mac, style, attrs): (ast::Mac, MacStmtStyle, ThinVec), + span: Span, - stmts: &mut Vec, - last_block_expr: &mut Option>) ++ stmts: &mut Vec) + -> PResult<'a, ()> { + if style == MacStmtStyle::NoBraces { + // statement macro without braces; might be an + // expr depending on whether a semicolon follows + match self.token { + token::Semi => { + stmts.push(Stmt { + id: ast::DUMMY_NODE_ID, + node: StmtKind::Mac(P((mac, MacStmtStyle::Semicolon, attrs))), + span: mk_sp(span.lo, self.span.hi), + }); + self.bump(); + } + _ => { + let e = self.mk_mac_expr(span.lo, span.hi, mac.node, ThinVec::new()); + let lo = e.span.lo; + let e = self.parse_dot_or_call_expr_with(e, lo, attrs)?; + let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?; - self.handle_expression_like_statement(e, span, stmts, last_block_expr)?; ++ self.handle_expression_like_statement(e, span, stmts)?; + } + } + } else { + // statement macro; might be an expr + match self.token { + token::Semi => { + stmts.push(Stmt { + id: ast::DUMMY_NODE_ID, + node: StmtKind::Mac(P((mac, MacStmtStyle::Semicolon, attrs))), + span: mk_sp(span.lo, self.span.hi), + }); + self.bump(); + } - token::CloseDelim(token::Brace) => { - // if a block ends in `m!(arg)` without - // a `;`, it must be an expr - *last_block_expr = Some(self.mk_mac_expr(span.lo, span.hi, mac.node, attrs)); - } + _ => { + stmts.push(Stmt { + id: ast::DUMMY_NODE_ID, + node: StmtKind::Mac(P((mac, style, attrs))), + span: span + }); + } + } + } + Ok(()) + } + fn handle_expression_like_statement(&mut self, e: P, span: Span, @@@ -4227,11 -4189,9 +4221,10 @@@ span: span_with_semi, }); } - token::CloseDelim(token::Brace) => *last_block_expr = Some(e), _ => { - stmts.push(Spanned { - node: StmtKind::Expr(e, ast::DUMMY_NODE_ID), + stmts.push(Stmt { + id: ast::DUMMY_NODE_ID, + node: StmtKind::Expr(e), span: span }); } diff --cc src/libsyntax/print/pprust.rs index d399f538004,00edd5585c2..b56cec72a95 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@@ -1605,28 -1593,17 +1605,32 @@@ impl<'a> State<'a> pub fn print_stmt(&mut self, st: &ast::Stmt) -> io::Result<()> { try!(self.maybe_print_comment(st.span.lo)); match st.node { - ast::StmtKind::Decl(ref decl, _) => { - try!(self.print_decl(&decl)); + ast::StmtKind::Local(ref loc) => { + try!(self.print_outer_attributes(&loc.attrs)); + try!(self.space_if_not_bol()); + try!(self.ibox(INDENT_UNIT)); + try!(self.word_nbsp("let")); + + try!(self.ibox(INDENT_UNIT)); + try!(self.print_local_decl(&loc)); + try!(self.end()); + if let Some(ref init) = loc.init { + try!(self.nbsp()); + try!(self.word_space("=")); + try!(self.print_expr(&init)); + } ++ try!(word(&mut self.s, ";")); + self.end()?; } - ast::StmtKind::Expr(ref expr, _) => { + ast::StmtKind::Item(ref item) => self.print_item(&item)?, + ast::StmtKind::Expr(ref expr) => { try!(self.space_if_not_bol()); try!(self.print_expr_outer_attr_style(&expr, false)); + if parse::classify::expr_requires_semi_to_be_stmt(expr) { + try!(word(&mut self.s, ";")); + } } - ast::StmtKind::Semi(ref expr, _) => { + ast::StmtKind::Semi(ref expr) => { try!(self.space_if_not_bol()); try!(self.print_expr_outer_attr_style(&expr, false)); try!(word(&mut self.s, ";")); @@@ -1692,17 -1665,17 +1693,17 @@@ try!(self.print_inner_attributes(attrs)); - for st in &blk.stmts { - try!(self.print_stmt(st)); - } - match blk.expr { - Some(ref expr) => { - try!(self.space_if_not_bol()); - try!(self.print_expr_outer_attr_style(&expr, false)); - try!(self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi))); + for (i, st) in blk.stmts.iter().enumerate() { + match st.node { - ast::StmtKind::Expr(ref expr, _) if i == blk.stmts.len() - 1 => { ++ ast::StmtKind::Expr(ref expr) if i == blk.stmts.len() - 1 => { + try!(self.space_if_not_bol()); + try!(self.print_expr_outer_attr_style(&expr, false)); + try!(self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi))); + } + _ => try!(self.print_stmt(st)), } - _ => () } + try!(self.bclose_maybe_open(blk.span, indented, close_box)); self.ann.post(self, NodeBlock(blk)) } @@@ -2111,16 -2084,15 +2112,13 @@@ _ => false }; - if !default_return || !body.stmts.is_empty() || body.expr.is_none() { - try!(self.print_block_unclosed(&body)); - } else { - // we extract the block, so as not to create another set of boxes - let i_expr = body.expr.as_ref().unwrap(); - match i_expr.node { - ast::ExprKind::Block(ref blk) => { + match body.stmts.last().map(|stmt| &stmt.node) { - Some(&ast::StmtKind::Expr(ref i_expr, _)) if default_return && - body.stmts.len() == 1 => { ++ Some(&ast::StmtKind::Expr(ref i_expr)) if default_return && ++ body.stmts.len() == 1 => { + // we extract the block, so as not to create another set of boxes + if let ast::ExprKind::Block(ref blk) = i_expr.node { - try!(self.print_block_unclosed_with_attrs( - &blk, - i_expr.attrs.as_attr_slice())); + try!(self.print_block_unclosed_with_attrs(&blk, &i_expr.attrs)); - } - _ => { + } else { // this is a bare expression try!(self.print_expr(&i_expr)); try!(self.end()); // need to close a box diff --cc src/libsyntax/visit.rs index 571965ef872,cf91f5ece72..1fc4e54d218 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@@ -588,22 -606,19 +588,21 @@@ pub fn walk_struct_field(vi walk_list!(visitor, visit_attribute, &struct_field.attrs); } -pub fn walk_block<'v, V: Visitor<'v>>(visitor: &mut V, block: &'v Block) { +pub fn walk_block(visitor: &mut V, block: &Block) { walk_list!(visitor, visit_stmt, &block.stmts); - walk_list!(visitor, visit_expr, &block.expr); } -pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt) { +pub fn walk_stmt(visitor: &mut V, statement: &Stmt) { match statement.node { - StmtKind::Decl(ref declaration, _) => visitor.visit_decl(declaration), - StmtKind::Expr(ref expression, _) | StmtKind::Semi(ref expression, _) => { + StmtKind::Local(ref local) => visitor.visit_local(local), + StmtKind::Item(ref item) => visitor.visit_item(item), + StmtKind::Expr(ref expression) | StmtKind::Semi(ref expression) => { visitor.visit_expr(expression) } - StmtKind::Mac(ref mac, _, ref attrs) => { + StmtKind::Mac(ref mac) => { + let (ref mac, _, ref attrs) = **mac; visitor.visit_mac(mac); - for attr in attrs.as_attr_slice() { + for attr in attrs.iter() { visitor.visit_attribute(attr); } } diff --cc src/libsyntax_ext/format.rs index 5be2bf7cdf9,8cf95625694..f311f16f11b --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@@ -442,14 -441,13 +442,14 @@@ impl<'a, 'b> Context<'a, 'b> let name = ecx.ident_of(name); let item = ecx.item(sp, name, vec![], st); - let decl = respan(sp, ast::DeclKind::Item(item)); + let stmt = ast::Stmt { + id: ast::DUMMY_NODE_ID, + node: ast::StmtKind::Item(item), + span: sp, + }; // Wrap the declaration in a block so that it forms a single expression. - ecx.expr_block(ecx.block(sp, vec![stmt], Some(ecx.expr_ident(sp, name)))) - ecx.expr_block(ecx.block(sp, vec![ - respan(sp, ast::StmtKind::Decl(P(decl), ast::DUMMY_NODE_ID)), - ecx.stmt_expr(ecx.expr_ident(sp, name)), - ])) ++ ecx.expr_block(ecx.block(sp, vec![stmt, ecx.stmt_expr(ecx.expr_ident(sp, name))])) } /// Actually builds the expression which the iformat! block will be expanded