Require passing an AttrWrapper
to collect_tokens_trailing_token
This is a pure refactoring split out from #80689. It represents the most invasive part of that PR, requiring changes in every caller of `parse_outer_attributes` In order to eagerly expand `#[cfg]` attributes while preserving the original `TokenStream`, we need to know the range of tokens that corresponds to every attribute target. This is accomplished by making `parse_outer_attributes` return an opaque `AttrWrapper` struct. An `AttrWrapper` must be converted to a plain `AttrVec` by passing it to `collect_tokens_trailing_token`. This makes it difficult to accidentally construct an AST node with attributes without calling `collect_tokens_trailing_token`, since AST nodes store an `AttrVec`, not an `AttrWrapper`. As a result, we now call `collect_tokens_trailing_token` for attribute targets which only support inert attributes, such as generic arguments and struct fields. Currently, the constructed `LazyTokenStream` is simply discarded. Future PRs will record the token range corresponding to the attribute target, allowing those tokens to be removed from an enclosing `collect_tokens_trailing_token` call if necessary.
This commit is contained in:
parent
7e0241c637
commit
0b411f56e1
9 changed files with 621 additions and 407 deletions
|
@ -3,8 +3,10 @@ use super::diagnostics::{AttemptLocalParseRecovery, Error};
|
|||
use super::expr::LhsExpr;
|
||||
use super::pat::{GateOr, RecoverComma};
|
||||
use super::path::PathStyle;
|
||||
use super::{BlockMode, ForceCollect, Parser, Restrictions, SemiColonMode, TrailingToken};
|
||||
use crate::{maybe_collect_tokens, maybe_whole};
|
||||
use super::{
|
||||
AttrWrapper, BlockMode, ForceCollect, Parser, Restrictions, SemiColonMode, TrailingToken,
|
||||
};
|
||||
use crate::maybe_whole;
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::attr::HasAttrs;
|
||||
|
@ -38,30 +40,47 @@ impl<'a> Parser<'a> {
|
|||
capture_semi: bool,
|
||||
force_collect: ForceCollect,
|
||||
) -> PResult<'a, Option<Stmt>> {
|
||||
let mut attrs = self.parse_outer_attributes()?;
|
||||
let attrs = self.parse_outer_attributes()?;
|
||||
let lo = self.token.span;
|
||||
|
||||
maybe_whole!(self, NtStmt, |stmt| {
|
||||
let mut stmt = stmt;
|
||||
stmt.visit_attrs(|stmt_attrs| {
|
||||
mem::swap(stmt_attrs, &mut attrs);
|
||||
stmt_attrs.extend(attrs);
|
||||
});
|
||||
Some(stmt)
|
||||
});
|
||||
// Don't use `maybe_whole` so that we have precise control
|
||||
// over when we bump the parser
|
||||
if let token::Interpolated(nt) = &self.token.kind {
|
||||
if let token::NtStmt(stmt) = &**nt {
|
||||
let mut stmt = stmt.clone();
|
||||
return self.collect_tokens_trailing_token(
|
||||
attrs,
|
||||
force_collect,
|
||||
|this, mut attrs| {
|
||||
stmt.visit_attrs(|stmt_attrs| {
|
||||
mem::swap(stmt_attrs, &mut attrs);
|
||||
stmt_attrs.extend(attrs);
|
||||
});
|
||||
// Make sure we capture the token::Interpolated
|
||||
this.bump();
|
||||
Ok((Some(stmt), TrailingToken::None))
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Some(if self.token.is_keyword(kw::Let) {
|
||||
self.parse_local_mk(lo, attrs.into(), capture_semi, force_collect)?
|
||||
self.parse_local_mk(lo, attrs, capture_semi, force_collect)?
|
||||
} else if self.is_kw_followed_by_ident(kw::Mut) {
|
||||
self.recover_stmt_local(lo, attrs.into(), "missing keyword", "let mut")?
|
||||
self.recover_stmt_local(
|
||||
lo,
|
||||
attrs.take_for_recovery().into(),
|
||||
"missing keyword",
|
||||
"let mut",
|
||||
)?
|
||||
} else if self.is_kw_followed_by_ident(kw::Auto) {
|
||||
self.bump(); // `auto`
|
||||
let msg = "write `let` instead of `auto` to introduce a new variable";
|
||||
self.recover_stmt_local(lo, attrs.into(), msg, "let")?
|
||||
self.recover_stmt_local(lo, attrs.take_for_recovery().into(), msg, "let")?
|
||||
} else if self.is_kw_followed_by_ident(sym::var) {
|
||||
self.bump(); // `var`
|
||||
let msg = "write `let` instead of `var` to introduce a new variable";
|
||||
self.recover_stmt_local(lo, attrs.into(), msg, "let")?
|
||||
self.recover_stmt_local(lo, attrs.take_for_recovery().into(), msg, "let")?
|
||||
} else if self.check_path() && !self.token.is_qpath_start() && !self.is_path_start_item() {
|
||||
// We have avoided contextual keywords like `union`, items with `crate` visibility,
|
||||
// or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something
|
||||
|
@ -75,14 +94,14 @@ impl<'a> Parser<'a> {
|
|||
self.mk_stmt(lo.to(item.span), StmtKind::Item(P(item)))
|
||||
} else if self.eat(&token::Semi) {
|
||||
// Do not attempt to parse an expression if we're done here.
|
||||
self.error_outer_attrs(&attrs);
|
||||
self.error_outer_attrs(&attrs.take_for_recovery());
|
||||
self.mk_stmt(lo, StmtKind::Empty)
|
||||
} else if self.token != token::CloseDelim(token::Brace) {
|
||||
// Remainder are line-expr stmts.
|
||||
let e = self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs.into()))?;
|
||||
self.mk_stmt(lo.to(e.span), StmtKind::Expr(e))
|
||||
} else {
|
||||
self.error_outer_attrs(&attrs);
|
||||
self.error_outer_attrs(&attrs.take_for_recovery());
|
||||
return Ok(None);
|
||||
}))
|
||||
}
|
||||
|
@ -90,10 +109,10 @@ impl<'a> Parser<'a> {
|
|||
fn parse_stmt_path_start(
|
||||
&mut self,
|
||||
lo: Span,
|
||||
attrs: Vec<Attribute>,
|
||||
attrs: AttrWrapper,
|
||||
force_collect: ForceCollect,
|
||||
) -> PResult<'a, Stmt> {
|
||||
maybe_collect_tokens!(self, force_collect, &attrs, |this: &mut Parser<'a>| {
|
||||
self.collect_tokens_trailing_token(attrs, force_collect, |this, attrs| {
|
||||
let path = this.parse_path(PathStyle::Expr)?;
|
||||
|
||||
if this.eat(&token::Not) {
|
||||
|
@ -142,7 +161,7 @@ impl<'a> Parser<'a> {
|
|||
// Since none of the above applied, this is an expression statement macro.
|
||||
let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac), AttrVec::new());
|
||||
let e = self.maybe_recover_from_bad_qpath(e, true)?;
|
||||
let e = self.parse_dot_or_call_expr_with(e, lo, attrs)?;
|
||||
let e = self.parse_dot_or_call_expr_with(e, lo, attrs.into())?;
|
||||
let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?;
|
||||
StmtKind::Expr(e)
|
||||
};
|
||||
|
@ -178,11 +197,11 @@ impl<'a> Parser<'a> {
|
|||
fn parse_local_mk(
|
||||
&mut self,
|
||||
lo: Span,
|
||||
attrs: AttrVec,
|
||||
attrs: AttrWrapper,
|
||||
capture_semi: bool,
|
||||
force_collect: ForceCollect,
|
||||
) -> PResult<'a, Stmt> {
|
||||
maybe_collect_tokens!(self, force_collect, &attrs, |this: &mut Parser<'a>| {
|
||||
self.collect_tokens_trailing_token(attrs, force_collect, |this, attrs| {
|
||||
this.expect_keyword(kw::Let)?;
|
||||
let local = this.parse_local(attrs.into())?;
|
||||
let trailing = if capture_semi && this.token.kind == token::Semi {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue