Skip to content

Commit 9bb3ea0

Browse files
committed
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.
2 parents 8eddf02 + 8cad251 commit 9bb3ea0

File tree

22 files changed

+161
-116
lines changed

22 files changed

+161
-116
lines changed

src/librustc/hir/lowering.rs

+15-2
Original file line numberDiff line numberDiff line change
@@ -574,10 +574,23 @@ impl<'a> LoweringContext<'a> {
574574
}
575575

576576
fn lower_block(&mut self, b: &Block) -> P<hir::Block> {
577+
let mut stmts = Vec::new();
578+
let mut expr = None;
579+
580+
if let Some((last, rest)) = b.stmts.split_last() {
581+
stmts = rest.iter().map(|s| self.lower_stmt(s)).collect::<Vec<_>>();
582+
let last = self.lower_stmt(last);
583+
if let hir::StmtExpr(e, _) = last.node {
584+
expr = Some(e);
585+
} else {
586+
stmts.push(last);
587+
}
588+
}
589+
577590
P(hir::Block {
578591
id: b.id,
579-
stmts: b.stmts.iter().map(|s| self.lower_stmt(s)).collect(),
580-
expr: b.expr.as_ref().map(|ref x| self.lower_expr(x)),
592+
stmts: stmts.into(),
593+
expr: expr,
581594
rules: self.lower_block_check_mode(&b.rules),
582595
span: b.span,
583596
})

src/librustc_driver/driver.rs

+24
Original file line numberDiff line numberDiff line change
@@ -763,6 +763,9 @@ pub fn phase_2_configure_and_expand<'a>(sess: &Session,
763763
}
764764

765765
pub fn assign_node_ids(sess: &Session, krate: ast::Crate) -> ast::Crate {
766+
use syntax::ptr::P;
767+
use syntax::util::move_map::MoveMap;
768+
766769
struct NodeIdAssigner<'a> {
767770
sess: &'a Session,
768771
}
@@ -772,6 +775,27 @@ pub fn assign_node_ids(sess: &Session, krate: ast::Crate) -> ast::Crate {
772775
assert_eq!(old_id, ast::DUMMY_NODE_ID);
773776
self.sess.next_node_id()
774777
}
778+
779+
fn fold_block(&mut self, block: P<ast::Block>) -> P<ast::Block> {
780+
block.map(|mut block| {
781+
block.id = self.new_id(block.id);
782+
783+
let stmt = block.stmts.pop();
784+
block.stmts = block.stmts.move_flat_map(|s| self.fold_stmt(s).into_iter());
785+
if let Some(ast::Stmt { node: ast::StmtKind::Expr(expr), span, .. }) = stmt {
786+
let expr = self.fold_expr(expr);
787+
block.stmts.push(ast::Stmt {
788+
id: expr.id,
789+
node: ast::StmtKind::Expr(expr),
790+
span: span,
791+
});
792+
} else if let Some(stmt) = stmt {
793+
block.stmts.extend(self.fold_stmt(stmt));
794+
}
795+
796+
block
797+
})
798+
}
775799
}
776800

777801
let krate = time(sess.time_passes(),

src/librustc_driver/pretty.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -657,8 +657,11 @@ impl fold::Folder for ReplaceBodyWithLoop {
657657
fn fold_block(&mut self, b: P<ast::Block>) -> P<ast::Block> {
658658
fn expr_to_block(rules: ast::BlockCheckMode, e: Option<P<ast::Expr>>) -> P<ast::Block> {
659659
P(ast::Block {
660-
expr: e,
661-
stmts: vec![],
660+
stmts: e.map(|e| ast::Stmt {
661+
id: ast::DUMMY_NODE_ID,
662+
span: e.span,
663+
node: ast::StmtKind::Expr(e),
664+
}).into_iter().collect(),
662665
rules: rules,
663666
id: ast::DUMMY_NODE_ID,
664667
span: syntax_pos::DUMMY_SP,

src/libsyntax/ast.rs

+1-4
Original file line numberDiff line numberDiff line change
@@ -557,9 +557,6 @@ impl PartialEq for MetaItemKind {
557557
pub struct Block {
558558
/// Statements in a block
559559
pub stmts: Vec<Stmt>,
560-
/// An expression at the end of the block
561-
/// without a semicolon, if any
562-
pub expr: Option<P<Expr>>,
563560
pub id: NodeId,
564561
/// Distinguishes between `unsafe { ... }` and `{ ... }`
565562
pub rules: BlockCheckMode,
@@ -832,7 +829,7 @@ pub enum StmtKind {
832829
/// An item definition.
833830
Item(P<Item>),
834831

835-
/// Expr without trailing semi-colon (must have unit type).
832+
/// Expr without trailing semi-colon.
836833
Expr(P<Expr>),
837834

838835
Semi(P<Expr>),

src/libsyntax/ext/build.rs

+26-26
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ pub trait AstBuilder {
8888

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

101102
// blocks
102-
fn block(&self, span: Span, stmts: Vec<ast::Stmt>,
103-
expr: Option<P<ast::Expr>>) -> P<ast::Block>;
103+
fn block(&self, span: Span, stmts: Vec<ast::Stmt>) -> P<ast::Block>;
104104
fn block_expr(&self, expr: P<ast::Expr>) -> P<ast::Block>;
105-
fn block_all(&self, span: Span,
106-
stmts: Vec<ast::Stmt>,
107-
expr: Option<P<ast::Expr>>) -> P<ast::Block>;
108105

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

511508
fn stmt_expr(&self, expr: P<ast::Expr>) -> ast::Stmt {
509+
ast::Stmt {
510+
id: ast::DUMMY_NODE_ID,
511+
span: expr.span,
512+
node: ast::StmtKind::Expr(expr),
513+
}
514+
}
515+
516+
fn stmt_semi(&self, expr: P<ast::Expr>) -> ast::Stmt {
512517
ast::Stmt {
513518
id: ast::DUMMY_NODE_ID,
514519
span: expr.span,
@@ -567,11 +572,6 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
567572
})
568573
}
569574

570-
fn block(&self, span: Span, stmts: Vec<ast::Stmt>,
571-
expr: Option<P<Expr>>) -> P<ast::Block> {
572-
self.block_all(span, stmts, expr)
573-
}
574-
575575
fn stmt_item(&self, sp: Span, item: P<ast::Item>) -> ast::Stmt {
576576
ast::Stmt {
577577
id: ast::DUMMY_NODE_ID,
@@ -581,19 +581,19 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
581581
}
582582

583583
fn block_expr(&self, expr: P<ast::Expr>) -> P<ast::Block> {
584-
self.block_all(expr.span, Vec::new(), Some(expr))
585-
}
586-
fn block_all(&self,
587-
span: Span,
588-
stmts: Vec<ast::Stmt>,
589-
expr: Option<P<ast::Expr>>) -> P<ast::Block> {
590-
P(ast::Block {
591-
stmts: stmts,
592-
expr: expr,
593-
id: ast::DUMMY_NODE_ID,
594-
rules: BlockCheckMode::Default,
595-
span: span,
596-
})
584+
self.block(expr.span, vec![ast::Stmt {
585+
id: ast::DUMMY_NODE_ID,
586+
span: expr.span,
587+
node: ast::StmtKind::Expr(expr),
588+
}])
589+
}
590+
fn block(&self, span: Span, stmts: Vec<ast::Stmt>) -> P<ast::Block> {
591+
P(ast::Block {
592+
stmts: stmts,
593+
id: ast::DUMMY_NODE_ID,
594+
rules: BlockCheckMode::Default,
595+
span: span,
596+
})
597597
}
598598

599599
fn expr(&self, span: Span, node: ast::ExprKind) -> P<ast::Expr> {
@@ -962,14 +962,14 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
962962
ids: Vec<ast::Ident>,
963963
stmts: Vec<ast::Stmt>)
964964
-> P<ast::Expr> {
965-
self.lambda(span, ids, self.block(span, stmts, None))
965+
self.lambda(span, ids, self.block(span, stmts))
966966
}
967967
fn lambda_stmts_0(&self, span: Span, stmts: Vec<ast::Stmt>) -> P<ast::Expr> {
968-
self.lambda0(span, self.block(span, stmts, None))
968+
self.lambda0(span, self.block(span, stmts))
969969
}
970970
fn lambda_stmts_1(&self, span: Span, stmts: Vec<ast::Stmt>,
971971
ident: ast::Ident) -> P<ast::Expr> {
972-
self.lambda1(span, self.block(span, stmts, None), ident)
972+
self.lambda1(span, self.block(span, stmts), ident)
973973
}
974974

975975
fn arg(&self, span: Span, ident: ast::Ident, ty: P<ast::Ty>) -> ast::Arg {

src/libsyntax/ext/expand.rs

+1-10
Original file line numberDiff line numberDiff line change
@@ -611,23 +611,14 @@ pub fn expand_block(blk: P<Block>, fld: &mut MacroExpander) -> P<Block> {
611611

612612
// expand the elements of a block.
613613
pub fn expand_block_elts(b: P<Block>, fld: &mut MacroExpander) -> P<Block> {
614-
b.map(|Block {id, stmts, expr, rules, span}| {
614+
b.map(|Block {id, stmts, rules, span}| {
615615
let new_stmts = stmts.into_iter().flat_map(|x| {
616616
// perform pending renames and expand macros in the statement
617617
fld.fold_stmt(x).into_iter()
618618
}).collect();
619-
let new_expr = expr.map(|x| {
620-
let expr = {
621-
let pending_renames = &mut fld.cx.syntax_env.info().pending_renames;
622-
let mut rename_fld = IdentRenamer{renames:pending_renames};
623-
rename_fld.fold_expr(x)
624-
};
625-
fld.fold_expr(expr)
626-
});
627619
Block {
628620
id: fld.new_id(id),
629621
stmts: new_stmts,
630-
expr: new_expr,
631622
rules: rules,
632623
span: span
633624
}

src/libsyntax/ext/quote.rs

+11-13
Original file line numberDiff line numberDiff line change
@@ -513,10 +513,8 @@ pub fn expand_quote_matcher(cx: &mut ExtCtxt,
513513
let (cx_expr, tts) = parse_arguments_to_quote(cx, tts);
514514
let mut vector = mk_stmts_let(cx, sp);
515515
vector.extend(statements_mk_tts(cx, &tts[..], true));
516-
let block = cx.expr_block(
517-
cx.block_all(sp,
518-
vector,
519-
Some(cx.expr_ident(sp, id_ext("tt")))));
516+
vector.push(cx.stmt_expr(cx.expr_ident(sp, id_ext("tt"))));
517+
let block = cx.expr_block(cx.block(sp, vector));
520518

521519
let expanded = expand_wrapper(cx, sp, cx_expr, block, &[&["syntax", "ext", "quote", "rt"]]);
522520
base::MacEager::expr(expanded)
@@ -766,8 +764,9 @@ fn statements_mk_tt(cx: &ExtCtxt, tt: &TokenTree, matcher: bool) -> Vec<ast::Stm
766764
let stmt_let_tt = cx.stmt_let(sp, true, id_ext("tt"), cx.expr_vec_ng(sp));
767765
let mut tts_stmts = vec![stmt_let_tt];
768766
tts_stmts.extend(statements_mk_tts(cx, &seq.tts[..], matcher));
769-
let e_tts = cx.expr_block(cx.block(sp, tts_stmts,
770-
Some(cx.expr_ident(sp, id_ext("tt")))));
767+
tts_stmts.push(cx.stmt_expr(cx.expr_ident(sp, id_ext("tt"))));
768+
let e_tts = cx.expr_block(cx.block(sp, tts_stmts));
769+
771770
let e_separator = match seq.separator {
772771
Some(ref sep) => cx.expr_some(sp, expr_mk_token(cx, sp, sep)),
773772
None => cx.expr_none(sp),
@@ -882,10 +881,8 @@ fn expand_tts(cx: &ExtCtxt, sp: Span, tts: &[TokenTree])
882881

883882
let mut vector = mk_stmts_let(cx, sp);
884883
vector.extend(statements_mk_tts(cx, &tts[..], false));
885-
let block = cx.expr_block(
886-
cx.block_all(sp,
887-
vector,
888-
Some(cx.expr_ident(sp, id_ext("tt")))));
884+
vector.push(cx.stmt_expr(cx.expr_ident(sp, id_ext("tt"))));
885+
let block = cx.expr_block(cx.block(sp, vector));
889886

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

902-
let stmts = imports.iter().map(|path| {
899+
let mut stmts = imports.iter().map(|path| {
903900
// make item: `use ...;`
904901
let path = path.iter().map(|s| s.to_string()).collect();
905902
cx.stmt_item(sp, cx.item_use_glob(sp, ast::Visibility::Inherited, ids_ext(path)))
906-
}).chain(Some(stmt_let_ext_cx)).collect();
903+
}).chain(Some(stmt_let_ext_cx)).collect::<Vec<_>>();
904+
stmts.push(cx.stmt_expr(expr));
907905

908-
cx.expr_block(cx.block_all(sp, stmts, Some(expr)))
906+
cx.expr_block(cx.block(sp, stmts))
909907
}
910908

911909
fn expand_parse_call(cx: &ExtCtxt,

src/libsyntax/fold.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -818,10 +818,9 @@ fn noop_fold_bounds<T: Folder>(bounds: TyParamBounds, folder: &mut T)
818818
}
819819

820820
pub fn noop_fold_block<T: Folder>(b: P<Block>, folder: &mut T) -> P<Block> {
821-
b.map(|Block {id, stmts, expr, rules, span}| Block {
821+
b.map(|Block {id, stmts, rules, span}| Block {
822822
id: folder.new_id(id),
823823
stmts: stmts.move_flat_map(|s| folder.fold_stmt(s).into_iter()),
824-
expr: expr.and_then(|x| folder.fold_opt_expr(x)),
825824
rules: rules,
826825
span: folder.new_span(span),
827826
})

src/libsyntax/parse/mod.rs

-1
Original file line numberDiff line numberDiff line change
@@ -957,7 +957,6 @@ mod tests {
957957
attrs: ThinVec::new()})),
958958
id: ast::DUMMY_NODE_ID,
959959
span: sp(17,19)}),
960-
expr: None,
961960
id: ast::DUMMY_NODE_ID,
962961
rules: ast::BlockCheckMode::Default, // no idea
963962
span: sp(15,21),

src/libsyntax/parse/parser.rs

+10-17
Original file line numberDiff line numberDiff line change
@@ -3236,9 +3236,12 @@ impl<'a> Parser<'a> {
32363236
let body_expr = self.parse_expr()?;
32373237
P(ast::Block {
32383238
id: ast::DUMMY_NODE_ID,
3239-
stmts: vec![],
32403239
span: body_expr.span,
3241-
expr: Some(body_expr),
3240+
stmts: vec![Stmt {
3241+
span: body_expr.span,
3242+
node: StmtKind::Expr(body_expr),
3243+
id: ast::DUMMY_NODE_ID,
3244+
}],
32423245
rules: BlockCheckMode::Default,
32433246
})
32443247
}
@@ -4098,7 +4101,6 @@ impl<'a> Parser<'a> {
40984101
/// Precondition: already parsed the '{'.
40994102
fn parse_block_tail(&mut self, lo: BytePos, s: BlockCheckMode) -> PResult<'a, P<Block>> {
41004103
let mut stmts = vec![];
4101-
let mut expr = None;
41024104

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

41134115
match node {
41144116
StmtKind::Expr(e) => {
4115-
self.handle_expression_like_statement(e, span, &mut stmts, &mut expr)?;
4117+
self.handle_expression_like_statement(e, span, &mut stmts)?;
41164118
}
41174119
StmtKind::Mac(mac) => {
4118-
self.handle_macro_in_block(mac.unwrap(), span, &mut stmts, &mut expr)?;
4120+
self.handle_macro_in_block(mac.unwrap(), span, &mut stmts)?;
41194121
}
41204122
_ => { // all other kinds of statements:
41214123
let mut hi = span.hi;
@@ -4135,7 +4137,6 @@ impl<'a> Parser<'a> {
41354137

41364138
Ok(P(ast::Block {
41374139
stmts: stmts,
4138-
expr: expr,
41394140
id: ast::DUMMY_NODE_ID,
41404141
rules: s,
41414142
span: mk_sp(lo, self.last_span.hi),
@@ -4145,8 +4146,7 @@ impl<'a> Parser<'a> {
41454146
fn handle_macro_in_block(&mut self,
41464147
(mac, style, attrs): (ast::Mac, MacStmtStyle, ThinVec<Attribute>),
41474148
span: Span,
4148-
stmts: &mut Vec<Stmt>,
4149-
last_block_expr: &mut Option<P<Expr>>)
4149+
stmts: &mut Vec<Stmt>)
41504150
-> PResult<'a, ()> {
41514151
if style == MacStmtStyle::NoBraces {
41524152
// statement macro without braces; might be an
@@ -4165,7 +4165,7 @@ impl<'a> Parser<'a> {
41654165
let lo = e.span.lo;
41664166
let e = self.parse_dot_or_call_expr_with(e, lo, attrs)?;
41674167
let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?;
4168-
self.handle_expression_like_statement(e, span, stmts, last_block_expr)?;
4168+
self.handle_expression_like_statement(e, span, stmts)?;
41694169
}
41704170
}
41714171
} else {
@@ -4179,11 +4179,6 @@ impl<'a> Parser<'a> {
41794179
});
41804180
self.bump();
41814181
}
4182-
token::CloseDelim(token::Brace) => {
4183-
// if a block ends in `m!(arg)` without
4184-
// a `;`, it must be an expr
4185-
*last_block_expr = Some(self.mk_mac_expr(span.lo, span.hi, mac.node, attrs));
4186-
}
41874182
_ => {
41884183
stmts.push(Stmt {
41894184
id: ast::DUMMY_NODE_ID,
@@ -4199,8 +4194,7 @@ impl<'a> Parser<'a> {
41994194
fn handle_expression_like_statement(&mut self,
42004195
e: P<Expr>,
42014196
span: Span,
4202-
stmts: &mut Vec<Stmt>,
4203-
last_block_expr: &mut Option<P<Expr>>)
4197+
stmts: &mut Vec<Stmt>)
42044198
-> PResult<'a, ()> {
42054199
// expression without semicolon
42064200
if classify::expr_requires_semi_to_be_stmt(&e) {
@@ -4227,7 +4221,6 @@ impl<'a> Parser<'a> {
42274221
span: span_with_semi,
42284222
});
42294223
}
4230-
token::CloseDelim(token::Brace) => *last_block_expr = Some(e),
42314224
_ => {
42324225
stmts.push(Stmt {
42334226
id: ast::DUMMY_NODE_ID,

0 commit comments

Comments
 (0)