Auto merge of #78296 - Aaron1011:fix/stmt-tokens, r=petrochenkov
Properly handle attributes on statements We now collect tokens for the underlying node wrapped by `StmtKind` nstead 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:
commit
4ae328bef4
52 changed files with 603 additions and 256 deletions
|
@ -901,10 +901,39 @@ pub struct Stmt {
|
|||
pub id: NodeId,
|
||||
pub kind: StmtKind,
|
||||
pub span: Span,
|
||||
pub tokens: Option<LazyTokenStream>,
|
||||
}
|
||||
|
||||
impl Stmt {
|
||||
pub fn tokens(&self) -> Option<&LazyTokenStream> {
|
||||
match self.kind {
|
||||
StmtKind::Local(ref local) => local.tokens.as_ref(),
|
||||
StmtKind::Item(ref item) => item.tokens.as_ref(),
|
||||
StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => expr.tokens.as_ref(),
|
||||
StmtKind::Empty => None,
|
||||
StmtKind::MacCall(ref mac) => mac.tokens.as_ref(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tokens_mut(&mut self) -> Option<&mut LazyTokenStream> {
|
||||
match self.kind {
|
||||
StmtKind::Local(ref mut local) => local.tokens.as_mut(),
|
||||
StmtKind::Item(ref mut item) => item.tokens.as_mut(),
|
||||
StmtKind::Expr(ref mut expr) | StmtKind::Semi(ref mut expr) => expr.tokens.as_mut(),
|
||||
StmtKind::Empty => None,
|
||||
StmtKind::MacCall(ref mut mac) => mac.tokens.as_mut(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_tokens(&mut self, tokens: Option<LazyTokenStream>) {
|
||||
match self.kind {
|
||||
StmtKind::Local(ref mut local) => local.tokens = tokens,
|
||||
StmtKind::Item(ref mut item) => item.tokens = tokens,
|
||||
StmtKind::Expr(ref mut expr) | StmtKind::Semi(ref mut expr) => expr.tokens = tokens,
|
||||
StmtKind::Empty => {}
|
||||
StmtKind::MacCall(ref mut mac) => mac.tokens = tokens,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_trailing_semicolon(&self) -> bool {
|
||||
match &self.kind {
|
||||
StmtKind::Semi(_) => true,
|
||||
|
@ -912,18 +941,25 @@ impl Stmt {
|
|||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a parsed `Stmt` to a `Stmt` with
|
||||
/// a trailing semicolon.
|
||||
///
|
||||
/// This only modifies the parsed AST struct, not the attached
|
||||
/// `LazyTokenStream`. The parser is responsible for calling
|
||||
/// `CreateTokenStream::add_trailing_semi` when there is actually
|
||||
/// a semicolon in the tokenstream.
|
||||
pub fn add_trailing_semicolon(mut self) -> Self {
|
||||
self.kind = match self.kind {
|
||||
StmtKind::Expr(expr) => StmtKind::Semi(expr),
|
||||
StmtKind::MacCall(mac) => {
|
||||
StmtKind::MacCall(mac.map(|MacCallStmt { mac, style: _, attrs }| MacCallStmt {
|
||||
mac,
|
||||
style: MacStmtStyle::Semicolon,
|
||||
attrs,
|
||||
StmtKind::MacCall(mac.map(|MacCallStmt { mac, style: _, attrs, tokens }| {
|
||||
MacCallStmt { mac, style: MacStmtStyle::Semicolon, attrs, tokens }
|
||||
}))
|
||||
}
|
||||
kind => kind,
|
||||
};
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -963,6 +999,7 @@ pub struct MacCallStmt {
|
|||
pub mac: MacCall,
|
||||
pub style: MacStmtStyle,
|
||||
pub attrs: AttrVec,
|
||||
pub tokens: Option<LazyTokenStream>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug)]
|
||||
|
@ -988,6 +1025,7 @@ pub struct Local {
|
|||
pub init: Option<P<Expr>>,
|
||||
pub span: Span,
|
||||
pub attrs: AttrVec,
|
||||
pub tokens: Option<LazyTokenStream>,
|
||||
}
|
||||
|
||||
/// An arm of a 'match'.
|
||||
|
|
|
@ -579,13 +579,14 @@ pub fn noop_visit_parenthesized_parameter_data<T: MutVisitor>(
|
|||
}
|
||||
|
||||
pub fn noop_visit_local<T: MutVisitor>(local: &mut P<Local>, vis: &mut T) {
|
||||
let Local { id, pat, ty, init, span, attrs } = local.deref_mut();
|
||||
let Local { id, pat, ty, init, span, attrs, tokens } = local.deref_mut();
|
||||
vis.visit_id(id);
|
||||
vis.visit_pat(pat);
|
||||
visit_opt(ty, |ty| vis.visit_ty(ty));
|
||||
visit_opt(init, |init| vis.visit_expr(init));
|
||||
vis.visit_span(span);
|
||||
visit_thin_attrs(attrs, vis);
|
||||
visit_lazy_tts(tokens, vis);
|
||||
}
|
||||
|
||||
pub fn noop_visit_attribute<T: MutVisitor>(attr: &mut Attribute, vis: &mut T) {
|
||||
|
@ -1328,16 +1329,12 @@ pub fn noop_filter_map_expr<T: MutVisitor>(mut e: P<Expr>, vis: &mut T) -> Optio
|
|||
}
|
||||
|
||||
pub fn noop_flat_map_stmt<T: MutVisitor>(
|
||||
Stmt { kind, mut span, mut id, mut tokens }: Stmt,
|
||||
Stmt { kind, mut span, mut id }: Stmt,
|
||||
vis: &mut T,
|
||||
) -> SmallVec<[Stmt; 1]> {
|
||||
vis.visit_id(&mut id);
|
||||
vis.visit_span(&mut span);
|
||||
visit_lazy_tts(&mut tokens, vis);
|
||||
noop_flat_map_stmt_kind(kind, vis)
|
||||
.into_iter()
|
||||
.map(|kind| Stmt { id, kind, span, tokens: tokens.clone() })
|
||||
.collect()
|
||||
noop_flat_map_stmt_kind(kind, vis).into_iter().map(|kind| Stmt { id, kind, span }).collect()
|
||||
}
|
||||
|
||||
pub fn noop_flat_map_stmt_kind<T: MutVisitor>(
|
||||
|
@ -1354,9 +1351,10 @@ pub fn noop_flat_map_stmt_kind<T: MutVisitor>(
|
|||
StmtKind::Semi(expr) => vis.filter_map_expr(expr).into_iter().map(StmtKind::Semi).collect(),
|
||||
StmtKind::Empty => smallvec![StmtKind::Empty],
|
||||
StmtKind::MacCall(mut mac) => {
|
||||
let MacCallStmt { mac: mac_, style: _, attrs } = mac.deref_mut();
|
||||
let MacCallStmt { mac: mac_, style: _, attrs, tokens } = mac.deref_mut();
|
||||
vis.visit_mac_call(mac_);
|
||||
visit_thin_attrs(attrs, vis);
|
||||
visit_lazy_tts(tokens, vis);
|
||||
smallvec![StmtKind::MacCall(mac)]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -121,10 +121,14 @@ where
|
|||
}
|
||||
|
||||
pub trait CreateTokenStream: sync::Send + sync::Sync {
|
||||
fn add_trailing_semi(&self) -> Box<dyn CreateTokenStream>;
|
||||
fn create_token_stream(&self) -> TokenStream;
|
||||
}
|
||||
|
||||
impl CreateTokenStream for TokenStream {
|
||||
fn add_trailing_semi(&self) -> Box<dyn CreateTokenStream> {
|
||||
panic!("Cannot call `add_trailing_semi` on a `TokenStream`!");
|
||||
}
|
||||
fn create_token_stream(&self) -> TokenStream {
|
||||
self.clone()
|
||||
}
|
||||
|
@ -141,6 +145,13 @@ impl LazyTokenStream {
|
|||
LazyTokenStream(Lrc::new(Box::new(inner)))
|
||||
}
|
||||
|
||||
/// Extends the captured stream by one token,
|
||||
/// which must be a trailing semicolon. This
|
||||
/// affects the `TokenStream` created by `make_tokenstream`.
|
||||
pub fn add_trailing_semi(&self) -> LazyTokenStream {
|
||||
LazyTokenStream(Lrc::new(self.0.add_trailing_semi()))
|
||||
}
|
||||
|
||||
pub fn create_token_stream(&self) -> TokenStream {
|
||||
self.0.create_token_stream()
|
||||
}
|
||||
|
|
|
@ -689,7 +689,7 @@ pub fn walk_stmt<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Stmt) {
|
|||
StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => visitor.visit_expr(expr),
|
||||
StmtKind::Empty => {}
|
||||
StmtKind::MacCall(ref mac) => {
|
||||
let MacCallStmt { ref mac, style: _, ref attrs } = **mac;
|
||||
let MacCallStmt { ref mac, style: _, ref attrs, tokens: _ } = **mac;
|
||||
visitor.visit_mac_call(mac);
|
||||
for attr in attrs.iter() {
|
||||
visitor.visit_attribute(attr);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue