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:
commit
9bb3ea0feb
@ -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,
|
||||
})
|
||||
|
@ -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,
|
||||
}
|
||||
@ -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(),
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
@ -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>),
|
||||
|
@ -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,
|
||||
@ -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>;
|
||||
@ -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,
|
||||
@ -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,
|
||||
@ -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))
|
||||
self.block(expr.span, vec![ast::Stmt {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span: expr.span,
|
||||
node: ast::StmtKind::Expr(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,
|
||||
})
|
||||
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> {
|
||||
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
@ -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),
|
||||
@ -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)
|
||||
}
|
||||
@ -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,
|
||||
|
@ -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),
|
||||
})
|
||||
|
@ -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),
|
||||
|
@ -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,
|
||||
})
|
||||
}
|
||||
@ -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_() {
|
||||
@ -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;
|
||||
@ -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),
|
||||
@ -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
|
||||
@ -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 {
|
||||
@ -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,
|
||||
@ -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) {
|
||||
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -478,7 +478,7 @@ fn mk_main(cx: &mut TestCtxt) -> P<ast::Item> {
|
||||
let main_attr = ecx.attribute(sp, main_meta);
|
||||
// pub fn main() { ... }
|
||||
let main_ret_ty = ecx.ty(sp, ast::TyKind::Tup(vec![]));
|
||||
let main_body = ecx.block_all(sp, vec![call_test_main], None);
|
||||
let main_body = ecx.block(sp, vec![call_test_main]);
|
||||
let main = ast::ItemKind::Fn(ecx.fn_decl(vec![], main_ret_ty),
|
||||
ast::Unsafety::Normal,
|
||||
ast::Constness::NotConst,
|
||||
|
@ -590,7 +590,6 @@ pub fn walk_struct_field<V: Visitor>(visitor: &mut V, struct_field: &StructField
|
||||
|
||||
pub fn walk_block<V: Visitor>(visitor: &mut V, block: &Block) {
|
||||
walk_list!(visitor, visit_stmt, &block.stmts);
|
||||
walk_list!(visitor, visit_expr, &block.expr);
|
||||
}
|
||||
|
||||
pub fn walk_stmt<V: Visitor>(visitor: &mut V, statement: &Stmt) {
|
||||
|
@ -145,12 +145,10 @@ fn cs_clone(
|
||||
|
||||
match mode {
|
||||
Mode::Shallow => {
|
||||
cx.expr_block(cx.block(trait_span,
|
||||
all_fields.iter()
|
||||
.map(subcall)
|
||||
.map(|e| cx.stmt_expr(e))
|
||||
.collect(),
|
||||
Some(cx.expr_deref(trait_span, cx.expr_self(trait_span)))))
|
||||
let mut stmts: Vec<_> =
|
||||
all_fields.iter().map(subcall).map(|e| cx.stmt_expr(e)).collect();
|
||||
stmts.push(cx.stmt_expr(cx.expr_deref(trait_span, cx.expr_self(trait_span))));
|
||||
cx.expr_block(cx.block(trait_span, stmts))
|
||||
}
|
||||
Mode::Deep => {
|
||||
match *vdata {
|
||||
|
@ -30,7 +30,7 @@ pub fn expand_deriving_eq(cx: &mut ExtCtxt,
|
||||
// create `a.<method>(); b.<method>(); c.<method>(); ...`
|
||||
// (where method is `assert_receiver_is_total_eq`)
|
||||
let stmts = exprs.into_iter().map(|e| cx.stmt_expr(e)).collect();
|
||||
let block = cx.block(span, stmts, None);
|
||||
let block = cx.block(span, stmts);
|
||||
cx.expr_block(block)
|
||||
},
|
||||
Box::new(|cx, sp, _, _| {
|
||||
|
@ -78,7 +78,7 @@ fn show_substructure(cx: &mut ExtCtxt, span: Span,
|
||||
|
||||
let fmt = substr.nonself_args[0].clone();
|
||||
|
||||
let stmts = match *substr.fields {
|
||||
let mut stmts = match *substr.fields {
|
||||
Struct(_, ref fields) | EnumMatching(_, _, ref fields) => {
|
||||
let mut stmts = vec![];
|
||||
if !is_struct {
|
||||
@ -136,7 +136,8 @@ fn show_substructure(cx: &mut ExtCtxt, span: Span,
|
||||
token::str_to_ident("finish"),
|
||||
vec![]);
|
||||
|
||||
let block = cx.block(span, stmts, Some(expr));
|
||||
stmts.push(cx.stmt_expr(expr));
|
||||
let block = cx.block(span, stmts);
|
||||
cx.expr_block(block)
|
||||
}
|
||||
|
||||
|
@ -285,7 +285,7 @@ fn encodable_substructure(cx: &mut ExtCtxt, trait_span: Span,
|
||||
cx.expr_str(trait_span, substr.type_ident.name.as_str()),
|
||||
blk
|
||||
));
|
||||
cx.expr_block(cx.block(trait_span, vec!(me), Some(ret)))
|
||||
cx.expr_block(cx.block(trait_span, vec![me, cx.stmt_expr(ret)]))
|
||||
}
|
||||
|
||||
_ => cx.bug("expected Struct or EnumMatching in derive(Encodable)")
|
||||
|
@ -1332,8 +1332,8 @@ impl<'a> MethodDef<'a> {
|
||||
// }
|
||||
let all_match = cx.expr_match(sp, match_arg, match_arms);
|
||||
let arm_expr = cx.expr_if(sp, discriminant_test, all_match, Some(arm_expr));
|
||||
cx.expr_block(
|
||||
cx.block_all(sp, index_let_stmts, Some(arm_expr)))
|
||||
index_let_stmts.push(cx.stmt_expr(arm_expr));
|
||||
cx.expr_block(cx.block(sp, index_let_stmts))
|
||||
} else if variants.is_empty() {
|
||||
// As an additional wrinkle, For a zero-variant enum A,
|
||||
// currently the compiler
|
||||
|
@ -99,5 +99,5 @@ fn hash_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure)
|
||||
stmts.push(call_hash(span, self_.clone()));
|
||||
}
|
||||
|
||||
cx.expr_block(cx.block(trait_span, stmts, None))
|
||||
cx.expr_block(cx.block(trait_span, stmts))
|
||||
}
|
||||
|
@ -298,8 +298,7 @@ fn call_intrinsic(cx: &ExtCtxt,
|
||||
let call = cx.expr_call_global(span, path, args);
|
||||
|
||||
cx.expr_block(P(ast::Block {
|
||||
stmts: vec![],
|
||||
expr: Some(call),
|
||||
stmts: vec![cx.stmt_expr(call)],
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated),
|
||||
span: span }))
|
||||
|
@ -449,7 +449,7 @@ impl<'a, 'b> Context<'a, 'b> {
|
||||
};
|
||||
|
||||
// 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![stmt, ecx.stmt_expr(ecx.expr_ident(sp, name))]))
|
||||
}
|
||||
|
||||
/// Actually builds the expression which the iformat! block will be expanded
|
||||
|
31
src/test/compile-fail/issue-34418.rs
Normal file
31
src/test/compile-fail/issue-34418.rs
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
#![allow(unused)]
|
||||
|
||||
macro_rules! make_item {
|
||||
() => { fn f() {} }
|
||||
}
|
||||
|
||||
macro_rules! make_stmt {
|
||||
() => { let x = 0; }
|
||||
}
|
||||
|
||||
fn f() {
|
||||
make_item! {}
|
||||
}
|
||||
|
||||
fn g() {
|
||||
make_stmt! {}
|
||||
}
|
||||
|
||||
#[rustc_error]
|
||||
fn main() {} //~ ERROR compilation successful
|
Loading…
Reference in New Issue
Block a user