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:
@@ -1,8 +1,6 @@
|
||||
use super::diagnostics::{dummy_arg, ConsumeClosingDelim, Error};
|
||||
use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
|
||||
use super::{FollowedByType, ForceCollect, Parser, PathStyle, TrailingToken};
|
||||
|
||||
use crate::{maybe_collect_tokens, maybe_whole};
|
||||
use super::{AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, TrailingToken};
|
||||
|
||||
use rustc_ast::ast::*;
|
||||
use rustc_ast::ptr::P;
|
||||
@@ -108,25 +106,40 @@ impl<'a> Parser<'a> {
|
||||
|
||||
pub(super) fn parse_item_common(
|
||||
&mut self,
|
||||
mut attrs: Vec<Attribute>,
|
||||
attrs: AttrWrapper,
|
||||
mac_allowed: bool,
|
||||
attrs_allowed: bool,
|
||||
req_name: ReqName,
|
||||
force_collect: ForceCollect,
|
||||
) -> PResult<'a, Option<Item>> {
|
||||
maybe_whole!(self, NtItem, |item| {
|
||||
let mut item = item;
|
||||
mem::swap(&mut item.attrs, &mut attrs);
|
||||
item.attrs.extend(attrs);
|
||||
Some(item.into_inner())
|
||||
});
|
||||
// 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::NtItem(item) = &**nt {
|
||||
let item = item.clone();
|
||||
|
||||
return self.collect_tokens_trailing_token(
|
||||
attrs,
|
||||
force_collect,
|
||||
|this, mut attrs| {
|
||||
let mut item = item;
|
||||
mem::swap(&mut item.attrs, &mut attrs);
|
||||
item.attrs.extend(attrs);
|
||||
// Bump the parser so the we capture the token::Interpolated
|
||||
this.bump();
|
||||
Ok((Some(item.into_inner()), TrailingToken::None))
|
||||
},
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
let mut unclosed_delims = vec![];
|
||||
let item = maybe_collect_tokens!(self, force_collect, &attrs, |this: &mut Self| {
|
||||
let item = this.parse_item_common_(attrs, mac_allowed, attrs_allowed, req_name);
|
||||
unclosed_delims.append(&mut this.unclosed_delims);
|
||||
Ok((item?, TrailingToken::None))
|
||||
})?;
|
||||
let item =
|
||||
self.collect_tokens_trailing_token(attrs, force_collect, |this: &mut Self, attrs| {
|
||||
let item = this.parse_item_common_(attrs, mac_allowed, attrs_allowed, req_name);
|
||||
unclosed_delims.append(&mut this.unclosed_delims);
|
||||
Ok((item?, TrailingToken::None))
|
||||
})?;
|
||||
|
||||
self.unclosed_delims.append(&mut unclosed_delims);
|
||||
Ok(item)
|
||||
@@ -1109,39 +1122,45 @@ impl<'a> Parser<'a> {
|
||||
|
||||
fn parse_enum_variant(&mut self) -> PResult<'a, Option<Variant>> {
|
||||
let variant_attrs = self.parse_outer_attributes()?;
|
||||
let vlo = self.token.span;
|
||||
self.collect_tokens_trailing_token(
|
||||
variant_attrs,
|
||||
ForceCollect::No,
|
||||
|this, variant_attrs| {
|
||||
let vlo = this.token.span;
|
||||
|
||||
let vis = self.parse_visibility(FollowedByType::No)?;
|
||||
if !self.recover_nested_adt_item(kw::Enum)? {
|
||||
return Ok(None);
|
||||
}
|
||||
let ident = self.parse_ident()?;
|
||||
let vis = this.parse_visibility(FollowedByType::No)?;
|
||||
if !this.recover_nested_adt_item(kw::Enum)? {
|
||||
return Ok((None, TrailingToken::None));
|
||||
}
|
||||
let ident = this.parse_ident()?;
|
||||
|
||||
let struct_def = if self.check(&token::OpenDelim(token::Brace)) {
|
||||
// Parse a struct variant.
|
||||
let (fields, recovered) = self.parse_record_struct_body()?;
|
||||
VariantData::Struct(fields, recovered)
|
||||
} else if self.check(&token::OpenDelim(token::Paren)) {
|
||||
VariantData::Tuple(self.parse_tuple_struct_body()?, DUMMY_NODE_ID)
|
||||
} else {
|
||||
VariantData::Unit(DUMMY_NODE_ID)
|
||||
};
|
||||
let struct_def = if this.check(&token::OpenDelim(token::Brace)) {
|
||||
// Parse a struct variant.
|
||||
let (fields, recovered) = this.parse_record_struct_body()?;
|
||||
VariantData::Struct(fields, recovered)
|
||||
} else if this.check(&token::OpenDelim(token::Paren)) {
|
||||
VariantData::Tuple(this.parse_tuple_struct_body()?, DUMMY_NODE_ID)
|
||||
} else {
|
||||
VariantData::Unit(DUMMY_NODE_ID)
|
||||
};
|
||||
|
||||
let disr_expr =
|
||||
if self.eat(&token::Eq) { Some(self.parse_anon_const_expr()?) } else { None };
|
||||
let disr_expr =
|
||||
if this.eat(&token::Eq) { Some(this.parse_anon_const_expr()?) } else { None };
|
||||
|
||||
let vr = ast::Variant {
|
||||
ident,
|
||||
vis,
|
||||
id: DUMMY_NODE_ID,
|
||||
attrs: variant_attrs,
|
||||
data: struct_def,
|
||||
disr_expr,
|
||||
span: vlo.to(self.prev_token.span),
|
||||
is_placeholder: false,
|
||||
};
|
||||
let vr = ast::Variant {
|
||||
ident,
|
||||
vis,
|
||||
id: DUMMY_NODE_ID,
|
||||
attrs: variant_attrs,
|
||||
data: struct_def,
|
||||
disr_expr,
|
||||
span: vlo.to(this.prev_token.span),
|
||||
is_placeholder: false,
|
||||
};
|
||||
|
||||
Ok(Some(vr))
|
||||
Ok((Some(vr), TrailingToken::MaybeComma))
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// Parses `struct Foo { ... }`.
|
||||
@@ -1262,17 +1281,23 @@ impl<'a> Parser<'a> {
|
||||
// Unit like structs are handled in parse_item_struct function
|
||||
self.parse_paren_comma_seq(|p| {
|
||||
let attrs = p.parse_outer_attributes()?;
|
||||
let lo = p.token.span;
|
||||
let vis = p.parse_visibility(FollowedByType::Yes)?;
|
||||
let ty = p.parse_ty()?;
|
||||
Ok(StructField {
|
||||
span: lo.to(ty.span),
|
||||
vis,
|
||||
ident: None,
|
||||
id: DUMMY_NODE_ID,
|
||||
ty,
|
||||
attrs,
|
||||
is_placeholder: false,
|
||||
p.collect_tokens_trailing_token(attrs, ForceCollect::No, |p, attrs| {
|
||||
let lo = p.token.span;
|
||||
let vis = p.parse_visibility(FollowedByType::Yes)?;
|
||||
let ty = p.parse_ty()?;
|
||||
|
||||
Ok((
|
||||
StructField {
|
||||
span: lo.to(ty.span),
|
||||
vis,
|
||||
ident: None,
|
||||
id: DUMMY_NODE_ID,
|
||||
ty,
|
||||
attrs,
|
||||
is_placeholder: false,
|
||||
},
|
||||
TrailingToken::MaybeComma,
|
||||
))
|
||||
})
|
||||
})
|
||||
.map(|(r, _)| r)
|
||||
@@ -1281,9 +1306,11 @@ impl<'a> Parser<'a> {
|
||||
/// Parses an element of a struct declaration.
|
||||
fn parse_struct_decl_field(&mut self) -> PResult<'a, StructField> {
|
||||
let attrs = self.parse_outer_attributes()?;
|
||||
let lo = self.token.span;
|
||||
let vis = self.parse_visibility(FollowedByType::No)?;
|
||||
self.parse_single_struct_field(lo, vis, attrs)
|
||||
self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
|
||||
let lo = this.token.span;
|
||||
let vis = this.parse_visibility(FollowedByType::No)?;
|
||||
Ok((this.parse_single_struct_field(lo, vis, attrs)?, TrailingToken::None))
|
||||
})
|
||||
}
|
||||
|
||||
/// Parses a structure field declaration.
|
||||
@@ -1736,74 +1763,79 @@ impl<'a> Parser<'a> {
|
||||
fn parse_param_general(&mut self, req_name: ReqName, first_param: bool) -> PResult<'a, Param> {
|
||||
let lo = self.token.span;
|
||||
let attrs = self.parse_outer_attributes()?;
|
||||
self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
|
||||
// Possibly parse `self`. Recover if we parsed it and it wasn't allowed here.
|
||||
if let Some(mut param) = this.parse_self_param()? {
|
||||
param.attrs = attrs.into();
|
||||
let res = if first_param { Ok(param) } else { this.recover_bad_self_param(param) };
|
||||
return Ok((res?, TrailingToken::None));
|
||||
}
|
||||
|
||||
// Possibly parse `self`. Recover if we parsed it and it wasn't allowed here.
|
||||
if let Some(mut param) = self.parse_self_param()? {
|
||||
param.attrs = attrs.into();
|
||||
return if first_param { Ok(param) } else { self.recover_bad_self_param(param) };
|
||||
}
|
||||
let is_name_required = match this.token.kind {
|
||||
token::DotDotDot => false,
|
||||
_ => req_name(this.token.span.edition()),
|
||||
};
|
||||
let (pat, ty) = if is_name_required || this.is_named_param() {
|
||||
debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required);
|
||||
|
||||
let is_name_required = match self.token.kind {
|
||||
token::DotDotDot => false,
|
||||
_ => req_name(self.token.span.edition()),
|
||||
};
|
||||
let (pat, ty) = if is_name_required || self.is_named_param() {
|
||||
debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required);
|
||||
let pat = this.parse_fn_param_pat()?;
|
||||
if let Err(mut err) = this.expect(&token::Colon) {
|
||||
return if let Some(ident) =
|
||||
this.parameter_without_type(&mut err, pat, is_name_required, first_param)
|
||||
{
|
||||
err.emit();
|
||||
Ok((dummy_arg(ident), TrailingToken::None))
|
||||
} else {
|
||||
Err(err)
|
||||
};
|
||||
}
|
||||
|
||||
let pat = self.parse_fn_param_pat()?;
|
||||
if let Err(mut err) = self.expect(&token::Colon) {
|
||||
return if let Some(ident) =
|
||||
self.parameter_without_type(&mut err, pat, is_name_required, first_param)
|
||||
this.eat_incorrect_doc_comment_for_param_type();
|
||||
(pat, this.parse_ty_for_param()?)
|
||||
} else {
|
||||
debug!("parse_param_general ident_to_pat");
|
||||
let parser_snapshot_before_ty = this.clone();
|
||||
this.eat_incorrect_doc_comment_for_param_type();
|
||||
let mut ty = this.parse_ty_for_param();
|
||||
if ty.is_ok()
|
||||
&& this.token != token::Comma
|
||||
&& this.token != token::CloseDelim(token::Paren)
|
||||
{
|
||||
err.emit();
|
||||
Ok(dummy_arg(ident))
|
||||
} else {
|
||||
Err(err)
|
||||
};
|
||||
}
|
||||
|
||||
self.eat_incorrect_doc_comment_for_param_type();
|
||||
(pat, self.parse_ty_for_param()?)
|
||||
} else {
|
||||
debug!("parse_param_general ident_to_pat");
|
||||
let parser_snapshot_before_ty = self.clone();
|
||||
self.eat_incorrect_doc_comment_for_param_type();
|
||||
let mut ty = self.parse_ty_for_param();
|
||||
if ty.is_ok()
|
||||
&& self.token != token::Comma
|
||||
&& self.token != token::CloseDelim(token::Paren)
|
||||
{
|
||||
// This wasn't actually a type, but a pattern looking like a type,
|
||||
// so we are going to rollback and re-parse for recovery.
|
||||
ty = self.unexpected();
|
||||
}
|
||||
match ty {
|
||||
Ok(ty) => {
|
||||
let ident = Ident::new(kw::Empty, self.prev_token.span);
|
||||
let bm = BindingMode::ByValue(Mutability::Not);
|
||||
let pat = self.mk_pat_ident(ty.span, bm, ident);
|
||||
(pat, ty)
|
||||
// This wasn't actually a type, but a pattern looking like a type,
|
||||
// so we are going to rollback and re-parse for recovery.
|
||||
ty = this.unexpected();
|
||||
}
|
||||
// If this is a C-variadic argument and we hit an error, return the error.
|
||||
Err(err) if self.token == token::DotDotDot => return Err(err),
|
||||
// Recover from attempting to parse the argument as a type without pattern.
|
||||
Err(mut err) => {
|
||||
err.cancel();
|
||||
*self = parser_snapshot_before_ty;
|
||||
self.recover_arg_parse()?
|
||||
match ty {
|
||||
Ok(ty) => {
|
||||
let ident = Ident::new(kw::Empty, this.prev_token.span);
|
||||
let bm = BindingMode::ByValue(Mutability::Not);
|
||||
let pat = this.mk_pat_ident(ty.span, bm, ident);
|
||||
(pat, ty)
|
||||
}
|
||||
// If this is a C-variadic argument and we hit an error, return the error.
|
||||
Err(err) if this.token == token::DotDotDot => return Err(err),
|
||||
// Recover from attempting to parse the argument as a type without pattern.
|
||||
Err(mut err) => {
|
||||
err.cancel();
|
||||
*this = parser_snapshot_before_ty;
|
||||
this.recover_arg_parse()?
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
let span = lo.until(self.token.span);
|
||||
let span = lo.until(this.token.span);
|
||||
|
||||
Ok(Param {
|
||||
attrs: attrs.into(),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
is_placeholder: false,
|
||||
pat,
|
||||
span,
|
||||
ty,
|
||||
Ok((
|
||||
Param {
|
||||
attrs: attrs.into(),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
is_placeholder: false,
|
||||
pat,
|
||||
span,
|
||||
ty,
|
||||
},
|
||||
TrailingToken::None,
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user