Properly handle attributes on statements
We now collect tokens for the underlying node wrapped by `StmtKind` instead of storing tokens directly in `Stmt`. `LazyTokenStream` now supports capturing a trailing semicolon after it is initially constructed. This allows us to avoid refactoring statement parsing to wrap the parsing of the semicolon in `parse_tokens`. Attributes on item statements (e.g. `fn foo() { #[bar] struct MyStruct; }`) are now treated as item attributes, not statement attributes, which is consistent with how we handle attributes on other kinds of statements. The feature-gating code is adjusted so that proc-macro attributes are still allowed on item statements on stable. Two built-in macros (`#[global_allocator]` and `#[test]`) needed to be adjusted to support being passed `Annotatable::Stmt`.
This commit is contained in:
parent
72da5a9d85
commit
de88bf148b
20 changed files with 485 additions and 187 deletions
|
@ -374,7 +374,6 @@ macro_rules! make_stmts_default {
|
|||
id: ast::DUMMY_NODE_ID,
|
||||
span: e.span,
|
||||
kind: ast::StmtKind::Expr(e),
|
||||
tokens: None
|
||||
}]
|
||||
})
|
||||
};
|
||||
|
@ -617,7 +616,6 @@ impl MacResult for DummyResult {
|
|||
id: ast::DUMMY_NODE_ID,
|
||||
kind: ast::StmtKind::Expr(DummyResult::raw_expr(self.span, self.is_error)),
|
||||
span: self.span,
|
||||
tokens: None
|
||||
}])
|
||||
}
|
||||
|
||||
|
|
|
@ -140,12 +140,7 @@ impl<'a> ExtCtxt<'a> {
|
|||
}
|
||||
|
||||
pub fn stmt_expr(&self, expr: P<ast::Expr>) -> ast::Stmt {
|
||||
ast::Stmt {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span: expr.span,
|
||||
kind: ast::StmtKind::Expr(expr),
|
||||
tokens: None,
|
||||
}
|
||||
ast::Stmt { id: ast::DUMMY_NODE_ID, span: expr.span, kind: ast::StmtKind::Expr(expr) }
|
||||
}
|
||||
|
||||
pub fn stmt_let(&self, sp: Span, mutbl: bool, ident: Ident, ex: P<ast::Expr>) -> ast::Stmt {
|
||||
|
@ -162,13 +157,9 @@ impl<'a> ExtCtxt<'a> {
|
|||
id: ast::DUMMY_NODE_ID,
|
||||
span: sp,
|
||||
attrs: AttrVec::new(),
|
||||
});
|
||||
ast::Stmt {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
kind: ast::StmtKind::Local(local),
|
||||
span: sp,
|
||||
tokens: None,
|
||||
}
|
||||
});
|
||||
ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span: sp }
|
||||
}
|
||||
|
||||
// Generates `let _: Type;`, which is usually used for type assertions.
|
||||
|
@ -180,17 +171,13 @@ impl<'a> ExtCtxt<'a> {
|
|||
id: ast::DUMMY_NODE_ID,
|
||||
span,
|
||||
attrs: AttrVec::new(),
|
||||
tokens: None,
|
||||
});
|
||||
ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span, tokens: None }
|
||||
ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span }
|
||||
}
|
||||
|
||||
pub fn stmt_item(&self, sp: Span, item: P<ast::Item>) -> ast::Stmt {
|
||||
ast::Stmt {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
kind: ast::StmtKind::Item(item),
|
||||
span: sp,
|
||||
tokens: None,
|
||||
}
|
||||
ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Item(item), span: sp }
|
||||
}
|
||||
|
||||
pub fn block_expr(&self, expr: P<ast::Expr>) -> P<ast::Block> {
|
||||
|
@ -200,7 +187,6 @@ impl<'a> ExtCtxt<'a> {
|
|||
id: ast::DUMMY_NODE_ID,
|
||||
span: expr.span,
|
||||
kind: ast::StmtKind::Expr(expr),
|
||||
tokens: None,
|
||||
}],
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1274,12 +1274,6 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
|
|||
// we'll expand attributes on expressions separately
|
||||
if !stmt.is_expr() {
|
||||
let attr = if stmt.is_item() {
|
||||
// FIXME: Implement proper token collection for statements
|
||||
if let StmtKind::Item(item) = &mut stmt.kind {
|
||||
stmt.tokens = item.tokens.take()
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
self.take_first_attr(&mut stmt)
|
||||
} else {
|
||||
// Ignore derives on non-item statements for backwards compatibility.
|
||||
|
@ -1295,7 +1289,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
|
|||
}
|
||||
|
||||
if let StmtKind::MacCall(mac) = stmt.kind {
|
||||
let MacCallStmt { mac, style, attrs } = mac.into_inner();
|
||||
let MacCallStmt { mac, style, attrs, tokens: _ } = mac.into_inner();
|
||||
self.check_attributes(&attrs);
|
||||
let mut placeholder =
|
||||
self.collect_bang(mac, stmt.span, AstFragmentKind::Stmts).make_stmts();
|
||||
|
@ -1312,10 +1306,10 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
|
|||
}
|
||||
|
||||
// The placeholder expander gives ids to statements, so we avoid folding the id here.
|
||||
let ast::Stmt { id, kind, span, tokens } = stmt;
|
||||
let ast::Stmt { id, kind, span } = stmt;
|
||||
noop_flat_map_stmt_kind(kind, self)
|
||||
.into_iter()
|
||||
.map(|kind| ast::Stmt { id, kind, span, tokens: tokens.clone() })
|
||||
.map(|kind| ast::Stmt { id, kind, span })
|
||||
.collect()
|
||||
}
|
||||
|
||||
|
|
|
@ -104,8 +104,9 @@ pub fn placeholder(
|
|||
mac: mac_placeholder(),
|
||||
style: ast::MacStmtStyle::Braces,
|
||||
attrs: ast::AttrVec::new(),
|
||||
tokens: None,
|
||||
});
|
||||
ast::Stmt { id, span, kind: ast::StmtKind::MacCall(mac), tokens: None }
|
||||
ast::Stmt { id, span, kind: ast::StmtKind::MacCall(mac) }
|
||||
}]),
|
||||
AstFragmentKind::Arms => AstFragment::Arms(smallvec![ast::Arm {
|
||||
attrs: Default::default(),
|
||||
|
@ -331,12 +332,8 @@ impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> {
|
|||
|
||||
// FIXME: We will need to preserve the original semicolon token and
|
||||
// span as part of #15701
|
||||
let empty_stmt = ast::Stmt {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
kind: ast::StmtKind::Empty,
|
||||
span: DUMMY_SP,
|
||||
tokens: None,
|
||||
};
|
||||
let empty_stmt =
|
||||
ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Empty, span: DUMMY_SP };
|
||||
|
||||
if let Some(stmt) = stmts.pop() {
|
||||
if stmt.has_trailing_semicolon() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue