Skip to content

Commit

Permalink
Rollup merge of rust-lang#34436 - jseyfried:no_block_expr, r=eddyb
Browse files Browse the repository at this point in the history
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 rust-lang#34418.
  • Loading branch information
jseyfried committed Jun 26, 2016
2 parents 8eddf02 + 8cad251 commit 9bb3ea0
Show file tree
Hide file tree
Showing 22 changed files with 161 additions and 116 deletions.
17 changes: 15 additions & 2 deletions src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -574,10 +574,23 @@ impl<'a> LoweringContext<'a> {
}

fn lower_block(&mut self, b: &Block) -> P<hir::Block> {
let mut stmts = Vec::new();
let mut expr = None;

if let Some((last, rest)) = b.stmts.split_last() {
stmts = rest.iter().map(|s| self.lower_stmt(s)).collect::<Vec<_>>();
let last = self.lower_stmt(last);
if let hir::StmtExpr(e, _) = last.node {
expr = Some(e);
} else {
stmts.push(last);
}
}

P(hir::Block {
id: b.id,
stmts: b.stmts.iter().map(|s| self.lower_stmt(s)).collect(),
expr: b.expr.as_ref().map(|ref x| self.lower_expr(x)),
stmts: stmts.into(),
expr: expr,
rules: self.lower_block_check_mode(&b.rules),
span: b.span,
})
Expand Down
24 changes: 24 additions & 0 deletions src/librustc_driver/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -763,6 +763,9 @@ pub fn phase_2_configure_and_expand<'a>(sess: &Session,
}

pub fn assign_node_ids(sess: &Session, krate: ast::Crate) -> ast::Crate {
use syntax::ptr::P;
use syntax::util::move_map::MoveMap;

struct NodeIdAssigner<'a> {
sess: &'a Session,
}
Expand All @@ -772,6 +775,27 @@ pub fn assign_node_ids(sess: &Session, krate: ast::Crate) -> ast::Crate {
assert_eq!(old_id, ast::DUMMY_NODE_ID);
self.sess.next_node_id()
}

fn fold_block(&mut self, block: P<ast::Block>) -> P<ast::Block> {
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(ast::Stmt { node: ast::StmtKind::Expr(expr), span, .. }) = stmt {
let expr = self.fold_expr(expr);
block.stmts.push(ast::Stmt {
id: expr.id,
node: ast::StmtKind::Expr(expr),
span: span,
});
} else if let Some(stmt) = stmt {
block.stmts.extend(self.fold_stmt(stmt));
}

block
})
}
}

let krate = time(sess.time_passes(),
Expand Down
7 changes: 5 additions & 2 deletions src/librustc_driver/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -657,8 +657,11 @@ impl fold::Folder for ReplaceBodyWithLoop {
fn fold_block(&mut self, b: P<ast::Block>) -> P<ast::Block> {
fn expr_to_block(rules: ast::BlockCheckMode, e: Option<P<ast::Expr>>) -> P<ast::Block> {
P(ast::Block {
expr: e,
stmts: vec![],
stmts: e.map(|e| ast::Stmt {
id: ast::DUMMY_NODE_ID,
span: e.span,
node: ast::StmtKind::Expr(e),
}).into_iter().collect(),
rules: rules,
id: ast::DUMMY_NODE_ID,
span: syntax_pos::DUMMY_SP,
Expand Down
5 changes: 1 addition & 4 deletions src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -557,9 +557,6 @@ impl PartialEq for MetaItemKind {
pub struct Block {
/// Statements in a block
pub stmts: Vec<Stmt>,
/// An expression at the end of the block
/// without a semicolon, if any
pub expr: Option<P<Expr>>,
pub id: NodeId,
/// Distinguishes between `unsafe { ... }` and `{ ... }`
pub rules: BlockCheckMode,
Expand Down Expand Up @@ -832,7 +829,7 @@ pub enum StmtKind {
/// An item definition.
Item(P<Item>),

/// Expr without trailing semi-colon (must have unit type).
/// Expr without trailing semi-colon.
Expr(P<Expr>),

Semi(P<Expr>),
Expand Down
52 changes: 26 additions & 26 deletions src/libsyntax/ext/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ pub trait AstBuilder {

// statements
fn stmt_expr(&self, expr: P<ast::Expr>) -> ast::Stmt;
fn stmt_semi(&self, expr: P<ast::Expr>) -> ast::Stmt;
fn stmt_let(&self, sp: Span, mutbl: bool, ident: ast::Ident, ex: P<ast::Expr>) -> ast::Stmt;
fn stmt_let_typed(&self,
sp: Span,
Expand All @@ -99,12 +100,8 @@ pub trait AstBuilder {
fn stmt_item(&self, sp: Span, item: P<ast::Item>) -> ast::Stmt;

// blocks
fn block(&self, span: Span, stmts: Vec<ast::Stmt>,
expr: Option<P<ast::Expr>>) -> P<ast::Block>;
fn block(&self, span: Span, stmts: Vec<ast::Stmt>) -> P<ast::Block>;
fn block_expr(&self, expr: P<ast::Expr>) -> P<ast::Block>;
fn block_all(&self, span: Span,
stmts: Vec<ast::Stmt>,
expr: Option<P<ast::Expr>>) -> P<ast::Block>;

// expressions
fn expr(&self, span: Span, node: ast::ExprKind) -> P<ast::Expr>;
Expand Down Expand Up @@ -509,6 +506,14 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
}

fn stmt_expr(&self, expr: P<ast::Expr>) -> ast::Stmt {
ast::Stmt {
id: ast::DUMMY_NODE_ID,
span: expr.span,
node: ast::StmtKind::Expr(expr),
}
}

fn stmt_semi(&self, expr: P<ast::Expr>) -> ast::Stmt {
ast::Stmt {
id: ast::DUMMY_NODE_ID,
span: expr.span,
Expand Down Expand Up @@ -567,11 +572,6 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
})
}

fn block(&self, span: Span, stmts: Vec<ast::Stmt>,
expr: Option<P<Expr>>) -> P<ast::Block> {
self.block_all(span, stmts, expr)
}

fn stmt_item(&self, sp: Span, item: P<ast::Item>) -> ast::Stmt {
ast::Stmt {
id: ast::DUMMY_NODE_ID,
Expand All @@ -581,19 +581,19 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
}

fn block_expr(&self, expr: P<ast::Expr>) -> P<ast::Block> {
self.block_all(expr.span, Vec::new(), Some(expr))
}
fn block_all(&self,
span: Span,
stmts: Vec<ast::Stmt>,
expr: Option<P<ast::Expr>>) -> P<ast::Block> {
P(ast::Block {
stmts: stmts,
expr: expr,
id: ast::DUMMY_NODE_ID,
rules: BlockCheckMode::Default,
span: span,
})
self.block(expr.span, vec![ast::Stmt {
id: ast::DUMMY_NODE_ID,
span: expr.span,
node: ast::StmtKind::Expr(expr),
}])
}
fn block(&self, span: Span, stmts: Vec<ast::Stmt>) -> P<ast::Block> {
P(ast::Block {
stmts: stmts,
id: ast::DUMMY_NODE_ID,
rules: BlockCheckMode::Default,
span: span,
})
}

fn expr(&self, span: Span, node: ast::ExprKind) -> P<ast::Expr> {
Expand Down Expand Up @@ -962,14 +962,14 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
ids: Vec<ast::Ident>,
stmts: Vec<ast::Stmt>)
-> P<ast::Expr> {
self.lambda(span, ids, self.block(span, stmts, None))
self.lambda(span, ids, self.block(span, stmts))
}
fn lambda_stmts_0(&self, span: Span, stmts: Vec<ast::Stmt>) -> P<ast::Expr> {
self.lambda0(span, self.block(span, stmts, None))
self.lambda0(span, self.block(span, stmts))
}
fn lambda_stmts_1(&self, span: Span, stmts: Vec<ast::Stmt>,
ident: ast::Ident) -> P<ast::Expr> {
self.lambda1(span, self.block(span, stmts, None), ident)
self.lambda1(span, self.block(span, stmts), ident)
}

fn arg(&self, span: Span, ident: ast::Ident, ty: P<ast::Ty>) -> ast::Arg {
Expand Down
11 changes: 1 addition & 10 deletions src/libsyntax/ext/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -611,23 +611,14 @@ pub fn expand_block(blk: P<Block>, fld: &mut MacroExpander) -> P<Block> {

// expand the elements of a block.
pub fn expand_block_elts(b: P<Block>, fld: &mut MacroExpander) -> P<Block> {
b.map(|Block {id, stmts, expr, rules, span}| {
b.map(|Block {id, stmts, rules, span}| {
let new_stmts = stmts.into_iter().flat_map(|x| {
// perform pending renames and expand macros in the statement
fld.fold_stmt(x).into_iter()
}).collect();
let new_expr = expr.map(|x| {
let expr = {
let pending_renames = &mut fld.cx.syntax_env.info().pending_renames;
let mut rename_fld = IdentRenamer{renames:pending_renames};
rename_fld.fold_expr(x)
};
fld.fold_expr(expr)
});
Block {
id: fld.new_id(id),
stmts: new_stmts,
expr: new_expr,
rules: rules,
span: span
}
Expand Down
24 changes: 11 additions & 13 deletions src/libsyntax/ext/quote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -513,10 +513,8 @@ pub fn expand_quote_matcher(cx: &mut ExtCtxt,
let (cx_expr, tts) = parse_arguments_to_quote(cx, tts);
let mut vector = mk_stmts_let(cx, sp);
vector.extend(statements_mk_tts(cx, &tts[..], true));
let block = cx.expr_block(
cx.block_all(sp,
vector,
Some(cx.expr_ident(sp, id_ext("tt")))));
vector.push(cx.stmt_expr(cx.expr_ident(sp, id_ext("tt"))));
let block = cx.expr_block(cx.block(sp, vector));

let expanded = expand_wrapper(cx, sp, cx_expr, block, &[&["syntax", "ext", "quote", "rt"]]);
base::MacEager::expr(expanded)
Expand Down Expand Up @@ -766,8 +764,9 @@ fn statements_mk_tt(cx: &ExtCtxt, tt: &TokenTree, matcher: bool) -> Vec<ast::Stm
let stmt_let_tt = cx.stmt_let(sp, true, id_ext("tt"), cx.expr_vec_ng(sp));
let mut tts_stmts = vec![stmt_let_tt];
tts_stmts.extend(statements_mk_tts(cx, &seq.tts[..], matcher));
let e_tts = cx.expr_block(cx.block(sp, tts_stmts,
Some(cx.expr_ident(sp, id_ext("tt")))));
tts_stmts.push(cx.stmt_expr(cx.expr_ident(sp, id_ext("tt"))));
let e_tts = cx.expr_block(cx.block(sp, tts_stmts));

let e_separator = match seq.separator {
Some(ref sep) => cx.expr_some(sp, expr_mk_token(cx, sp, sep)),
None => cx.expr_none(sp),
Expand Down Expand Up @@ -882,10 +881,8 @@ fn expand_tts(cx: &ExtCtxt, sp: Span, tts: &[TokenTree])

let mut vector = mk_stmts_let(cx, sp);
vector.extend(statements_mk_tts(cx, &tts[..], false));
let block = cx.expr_block(
cx.block_all(sp,
vector,
Some(cx.expr_ident(sp, id_ext("tt")))));
vector.push(cx.stmt_expr(cx.expr_ident(sp, id_ext("tt"))));
let block = cx.expr_block(cx.block(sp, vector));

(cx_expr, block)
}
Expand All @@ -899,13 +896,14 @@ fn expand_wrapper(cx: &ExtCtxt,
let cx_expr_borrow = cx.expr_addr_of(sp, cx.expr_deref(sp, cx_expr));
let stmt_let_ext_cx = cx.stmt_let(sp, false, id_ext("ext_cx"), cx_expr_borrow);

let stmts = imports.iter().map(|path| {
let mut stmts = imports.iter().map(|path| {
// make item: `use ...;`
let path = path.iter().map(|s| s.to_string()).collect();
cx.stmt_item(sp, cx.item_use_glob(sp, ast::Visibility::Inherited, ids_ext(path)))
}).chain(Some(stmt_let_ext_cx)).collect();
}).chain(Some(stmt_let_ext_cx)).collect::<Vec<_>>();
stmts.push(cx.stmt_expr(expr));

cx.expr_block(cx.block_all(sp, stmts, Some(expr)))
cx.expr_block(cx.block(sp, stmts))
}

fn expand_parse_call(cx: &ExtCtxt,
Expand Down
3 changes: 1 addition & 2 deletions src/libsyntax/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -818,10 +818,9 @@ fn noop_fold_bounds<T: Folder>(bounds: TyParamBounds, folder: &mut T)
}

pub fn noop_fold_block<T: Folder>(b: P<Block>, folder: &mut T) -> P<Block> {
b.map(|Block {id, stmts, expr, rules, span}| Block {
b.map(|Block {id, stmts, rules, span}| Block {
id: folder.new_id(id),
stmts: stmts.move_flat_map(|s| folder.fold_stmt(s).into_iter()),
expr: expr.and_then(|x| folder.fold_opt_expr(x)),
rules: rules,
span: folder.new_span(span),
})
Expand Down
1 change: 0 additions & 1 deletion src/libsyntax/parse/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -957,7 +957,6 @@ mod tests {
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),
Expand Down
27 changes: 10 additions & 17 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3236,9 +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![Stmt {
span: body_expr.span,
node: StmtKind::Expr(body_expr),
id: ast::DUMMY_NODE_ID,
}],
rules: BlockCheckMode::Default,
})
}
Expand Down Expand Up @@ -4098,7 +4101,6 @@ impl<'a> Parser<'a> {
/// Precondition: already parsed the '{'.
fn parse_block_tail(&mut self, lo: BytePos, s: BlockCheckMode) -> PResult<'a, P<Block>> {
let mut stmts = vec![];
let mut expr = None;

while !self.eat(&token::CloseDelim(token::Brace)) {
let Stmt {node, span, ..} = if let Some(s) = self.parse_stmt_() {
Expand All @@ -4112,10 +4114,10 @@ impl<'a> Parser<'a> {

match node {
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) => {
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;
Expand All @@ -4135,7 +4137,6 @@ impl<'a> Parser<'a> {

Ok(P(ast::Block {
stmts: stmts,
expr: expr,
id: ast::DUMMY_NODE_ID,
rules: s,
span: mk_sp(lo, self.last_span.hi),
Expand All @@ -4145,8 +4146,7 @@ impl<'a> Parser<'a> {
fn handle_macro_in_block(&mut self,
(mac, style, attrs): (ast::Mac, MacStmtStyle, ThinVec<Attribute>),
span: Span,
stmts: &mut Vec<Stmt>,
last_block_expr: &mut Option<P<Expr>>)
stmts: &mut Vec<Stmt>)
-> PResult<'a, ()> {
if style == MacStmtStyle::NoBraces {
// statement macro without braces; might be an
Expand All @@ -4165,7 +4165,7 @@ impl<'a> Parser<'a> {
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 {
Expand All @@ -4179,11 +4179,6 @@ impl<'a> Parser<'a> {
});
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,
Expand All @@ -4199,8 +4194,7 @@ impl<'a> Parser<'a> {
fn handle_expression_like_statement(&mut self,
e: P<Expr>,
span: Span,
stmts: &mut Vec<Stmt>,
last_block_expr: &mut Option<P<Expr>>)
stmts: &mut Vec<Stmt>)
-> PResult<'a, ()> {
// expression without semicolon
if classify::expr_requires_semi_to_be_stmt(&e) {
Expand All @@ -4227,7 +4221,6 @@ impl<'a> Parser<'a> {
span: span_with_semi,
});
}
token::CloseDelim(token::Brace) => *last_block_expr = Some(e),
_ => {
stmts.push(Stmt {
id: ast::DUMMY_NODE_ID,
Expand Down
Loading

0 comments on commit 9bb3ea0

Please sign in to comment.