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.
This commit is contained in:
Jeffrey Seyfried
2016-06-26 02:19:34 +00:00
22 changed files with 160 additions and 115 deletions

View File

@@ -1619,12 +1619,16 @@ impl<'a> State<'a> {
try!(self.word_space("="));
try!(self.print_expr(&init));
}
try!(word(&mut self.s, ";"));
self.end()?;
}
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) => {
try!(self.space_if_not_bol());
@@ -1646,9 +1650,6 @@ impl<'a> State<'a> {
}
}
}
if parse::classify::stmt_ends_with_semi(&st.node) {
try!(word(&mut self.s, ";"));
}
self.maybe_print_trailing_comment(st.span, None)
}
@@ -1692,17 +1693,17 @@ impl<'a> State<'a> {
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 => {
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,22 +2112,21 @@ impl<'a> State<'a> {
_ => 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 => {
// 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));
}
_ => {
} else {
// this is a bare expression
try!(self.print_expr(&i_expr));
try!(self.end()); // need to close a box
}
}
_ => try!(self.print_block_unclosed(&body)),
}
// a box will be closed by print_expr, but we didn't want an overall
// wrapper so we closed the corresponding opening. so create an
// empty box to satisfy the close.