Create a rustc_ast representation for parsed attributes
This commit is contained in:
parent
da476f1942
commit
03fb7eeced
11 changed files with 115 additions and 48 deletions
|
|
@ -34,6 +34,7 @@ use rustc_span::source_map::{Spanned, respan};
|
|||
use rustc_span::{ByteSymbol, DUMMY_SP, ErrorGuaranteed, Ident, Span, Symbol, kw, sym};
|
||||
use thin_vec::{ThinVec, thin_vec};
|
||||
|
||||
use crate::attr::data_structures::CfgEntry;
|
||||
pub use crate::format::*;
|
||||
use crate::token::{self, CommentKind, Delimiter};
|
||||
use crate::tokenstream::{DelimSpan, LazyAttrTokenStream, TokenStream};
|
||||
|
|
@ -3390,7 +3391,7 @@ impl NormalAttr {
|
|||
item: AttrItem {
|
||||
unsafety: Safety::Default,
|
||||
path: Path::from_ident(ident),
|
||||
args: AttrArgs::Empty,
|
||||
args: AttrItemKind::Unparsed(AttrArgs::Empty),
|
||||
tokens: None,
|
||||
},
|
||||
tokens: None,
|
||||
|
|
@ -3402,11 +3403,51 @@ impl NormalAttr {
|
|||
pub struct AttrItem {
|
||||
pub unsafety: Safety,
|
||||
pub path: Path,
|
||||
pub args: AttrArgs,
|
||||
pub args: AttrItemKind,
|
||||
// Tokens for the meta item, e.g. just the `foo` within `#[foo]` or `#![foo]`.
|
||||
pub tokens: Option<LazyAttrTokenStream>,
|
||||
}
|
||||
|
||||
/// Some attributes are stored in a parsed form, for performance reasons.
|
||||
/// Their arguments don't have to be reparsed everytime they're used
|
||||
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
|
||||
pub enum AttrItemKind {
|
||||
Parsed(EarlyParsedAttribute),
|
||||
Unparsed(AttrArgs),
|
||||
}
|
||||
|
||||
impl AttrItemKind {
|
||||
pub fn unparsed(self) -> Option<AttrArgs> {
|
||||
match self {
|
||||
AttrItemKind::Unparsed(args) => Some(args),
|
||||
AttrItemKind::Parsed(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unparsed_ref(&self) -> Option<&AttrArgs> {
|
||||
match self {
|
||||
AttrItemKind::Unparsed(args) => Some(args),
|
||||
AttrItemKind::Parsed(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn span(&self) -> Option<Span> {
|
||||
match self {
|
||||
AttrItemKind::Unparsed(args) => args.span(),
|
||||
AttrItemKind::Parsed(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Some attributes are stored in parsed form in the AST.
|
||||
/// This is done for performance reasons, so the attributes don't need to be reparsed on every use.
|
||||
///
|
||||
/// Currently all early parsed attributes are excluded from pretty printing at rustc_ast_pretty::pprust::state::print_attribute_inline.
|
||||
/// When adding new early parsed attributes, consider whether they should be pretty printed.
|
||||
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
pub enum EarlyParsedAttribute {
|
||||
}
|
||||
|
||||
impl AttrItem {
|
||||
pub fn is_valid_for_outer_style(&self) -> bool {
|
||||
self.path == sym::cfg_attr
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
//! Functions dealing with attributes and meta items.
|
||||
|
||||
pub mod data_structures;
|
||||
pub mod version;
|
||||
|
||||
use std::fmt::Debug;
|
||||
use std::sync::atomic::{AtomicU32, Ordering};
|
||||
|
||||
|
|
@ -8,6 +11,7 @@ use rustc_span::{Ident, Span, Symbol, sym};
|
|||
use smallvec::{SmallVec, smallvec};
|
||||
use thin_vec::{ThinVec, thin_vec};
|
||||
|
||||
use crate::AttrItemKind;
|
||||
use crate::ast::{
|
||||
AttrArgs, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute, DUMMY_NODE_ID, DelimArgs,
|
||||
Expr, ExprKind, LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NormalAttr, Path,
|
||||
|
|
@ -62,6 +66,15 @@ impl Attribute {
|
|||
}
|
||||
}
|
||||
|
||||
/// Replaces the arguments of this attribute with new arguments `AttrItemKind`.
|
||||
/// This is useful for making this attribute into a trace attribute, and should otherwise be avoided.
|
||||
pub fn replace_args(&mut self, new_args: AttrItemKind) {
|
||||
match &mut self.kind {
|
||||
AttrKind::Normal(normal) => normal.item.args = new_args,
|
||||
AttrKind::DocComment(..) => panic!("unexpected doc comment"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unwrap_normal_item(self) -> AttrItem {
|
||||
match self.kind {
|
||||
AttrKind::Normal(normal) => normal.item,
|
||||
|
|
@ -77,7 +90,7 @@ impl AttributeExt for Attribute {
|
|||
|
||||
fn value_span(&self) -> Option<Span> {
|
||||
match &self.kind {
|
||||
AttrKind::Normal(normal) => match &normal.item.args {
|
||||
AttrKind::Normal(normal) => match &normal.item.args.unparsed_ref()? {
|
||||
AttrArgs::Eq { expr, .. } => Some(expr.span),
|
||||
_ => None,
|
||||
},
|
||||
|
|
@ -147,7 +160,7 @@ impl AttributeExt for Attribute {
|
|||
|
||||
fn is_word(&self) -> bool {
|
||||
if let AttrKind::Normal(normal) = &self.kind {
|
||||
matches!(normal.item.args, AttrArgs::Empty)
|
||||
matches!(normal.item.args, AttrItemKind::Unparsed(AttrArgs::Empty))
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
|
@ -303,7 +316,7 @@ impl AttrItem {
|
|||
}
|
||||
|
||||
pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
|
||||
match &self.args {
|
||||
match &self.args.unparsed_ref()? {
|
||||
AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => {
|
||||
MetaItemKind::list_from_tokens(args.tokens.clone())
|
||||
}
|
||||
|
|
@ -324,7 +337,7 @@ impl AttrItem {
|
|||
/// #[attr("value")]
|
||||
/// ```
|
||||
fn value_str(&self) -> Option<Symbol> {
|
||||
match &self.args {
|
||||
match &self.args.unparsed_ref()? {
|
||||
AttrArgs::Eq { expr, .. } => match expr.kind {
|
||||
ExprKind::Lit(token_lit) => {
|
||||
LitKind::from_token_lit(token_lit).ok().and_then(|lit| lit.str())
|
||||
|
|
@ -348,7 +361,7 @@ impl AttrItem {
|
|||
/// #[attr("value")]
|
||||
/// ```
|
||||
fn value_span(&self) -> Option<Span> {
|
||||
match &self.args {
|
||||
match &self.args.unparsed_ref()? {
|
||||
AttrArgs::Eq { expr, .. } => Some(expr.span),
|
||||
AttrArgs::Delimited(_) | AttrArgs::Empty => None,
|
||||
}
|
||||
|
|
@ -364,7 +377,7 @@ impl AttrItem {
|
|||
}
|
||||
|
||||
pub fn meta_kind(&self) -> Option<MetaItemKind> {
|
||||
MetaItemKind::from_attr_args(&self.args)
|
||||
MetaItemKind::from_attr_args(self.args.unparsed_ref()?)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -699,7 +712,13 @@ fn mk_attr(
|
|||
args: AttrArgs,
|
||||
span: Span,
|
||||
) -> Attribute {
|
||||
mk_attr_from_item(g, AttrItem { unsafety, path, args, tokens: None }, None, style, span)
|
||||
mk_attr_from_item(
|
||||
g,
|
||||
AttrItem { unsafety, path, args: AttrItemKind::Unparsed(args), tokens: None },
|
||||
None,
|
||||
style,
|
||||
span,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn mk_attr_from_item(
|
||||
|
|
|
|||
|
|
@ -366,6 +366,7 @@ macro_rules! common_visitor_and_walkers {
|
|||
crate::token::LitKind,
|
||||
crate::tokenstream::LazyAttrTokenStream,
|
||||
crate::tokenstream::TokenStream,
|
||||
EarlyParsedAttribute,
|
||||
Movability,
|
||||
Mutability,
|
||||
Pinnedness,
|
||||
|
|
@ -457,6 +458,7 @@ macro_rules! common_visitor_and_walkers {
|
|||
ModSpans,
|
||||
MutTy,
|
||||
NormalAttr,
|
||||
AttrItemKind,
|
||||
Parens,
|
||||
ParenthesizedArgs,
|
||||
PatFieldsRest,
|
||||
|
|
|
|||
|
|
@ -694,7 +694,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
}
|
||||
ast::Safety::Default | ast::Safety::Safe(_) => {}
|
||||
}
|
||||
match &item.args {
|
||||
match &item.args.unparsed_ref().expect("Parsed attributes are never printed") {
|
||||
AttrArgs::Delimited(DelimArgs { dspan: _, delim, tokens }) => self.print_mac_common(
|
||||
Some(MacHeader::Path(&item.path)),
|
||||
false,
|
||||
|
|
|
|||
|
|
@ -294,11 +294,9 @@ pub fn parse_cfg_attr(
|
|||
sess: &Session,
|
||||
features: Option<&Features>,
|
||||
) -> Option<(CfgEntry, Vec<(AttrItem, Span)>)> {
|
||||
match cfg_attr.get_normal_item().args {
|
||||
ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, ref tokens })
|
||||
if !tokens.is_empty() =>
|
||||
{
|
||||
check_cfg_attr_bad_delim(&sess.psess, dspan, delim);
|
||||
match cfg_attr.get_normal_item().args.unparsed_ref().unwrap() {
|
||||
ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, tokens }) if !tokens.is_empty() => {
|
||||
check_cfg_attr_bad_delim(&sess.psess, *dspan, *delim);
|
||||
match parse_in(&sess.psess, tokens.clone(), "`cfg_attr` input", |p| {
|
||||
parse_cfg_attr_internal(p, sess, features, cfg_attr)
|
||||
}) {
|
||||
|
|
@ -322,7 +320,7 @@ pub fn parse_cfg_attr(
|
|||
}
|
||||
_ => {
|
||||
let (span, reason) = if let ast::AttrArgs::Delimited(ast::DelimArgs { dspan, .. }) =
|
||||
cfg_attr.get_normal_item().args
|
||||
cfg_attr.get_normal_item().args.unparsed_ref()?
|
||||
{
|
||||
(dspan.entire(), AttributeParseErrorReason::ExpectedAtLeastOneArgument)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -122,10 +122,10 @@ impl ArgParser {
|
|||
}
|
||||
|
||||
if args.delim != Delimiter::Parenthesis {
|
||||
psess.dcx().emit_err(MetaBadDelim {
|
||||
should_emit.emit_err(psess.dcx().create_err(MetaBadDelim {
|
||||
span: args.dspan.entire(),
|
||||
sugg: MetaBadDelimSugg { open: args.dspan.open, close: args.dspan.close },
|
||||
});
|
||||
}));
|
||||
return None;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute) {
|
|||
}
|
||||
_ => {
|
||||
let attr_item = attr.get_normal_item();
|
||||
if let AttrArgs::Eq { .. } = attr_item.args {
|
||||
if let AttrArgs::Eq { .. } = attr_item.args.unparsed_ref().unwrap() {
|
||||
// All key-value attributes are restricted to meta-item syntax.
|
||||
match parse_meta(psess, attr) {
|
||||
Ok(_) => {}
|
||||
|
|
@ -67,7 +67,7 @@ pub fn parse_meta<'a>(psess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Met
|
|||
unsafety: item.unsafety,
|
||||
span: attr.span,
|
||||
path: item.path.clone(),
|
||||
kind: match &item.args {
|
||||
kind: match &item.args.unparsed_ref().unwrap() {
|
||||
AttrArgs::Empty => MetaItemKind::Word,
|
||||
AttrArgs::Delimited(DelimArgs { dspan, delim, tokens }) => {
|
||||
check_meta_bad_delim(psess, *dspan, *delim);
|
||||
|
|
|
|||
|
|
@ -358,7 +358,7 @@ mod llvm_enzyme {
|
|||
let inline_item = ast::AttrItem {
|
||||
unsafety: ast::Safety::Default,
|
||||
path: ast::Path::from_ident(Ident::with_dummy_span(sym::inline)),
|
||||
args: ast::AttrArgs::Delimited(never_arg),
|
||||
args: rustc_ast::ast::AttrItemKind::Unparsed(ast::AttrArgs::Delimited(never_arg)),
|
||||
tokens: None,
|
||||
};
|
||||
let inline_never_attr = Box::new(ast::NormalAttr { item: inline_item, tokens: None });
|
||||
|
|
@ -421,11 +421,13 @@ mod llvm_enzyme {
|
|||
}
|
||||
};
|
||||
// Now update for d_fn
|
||||
rustc_ad_attr.item.args = rustc_ast::AttrArgs::Delimited(rustc_ast::DelimArgs {
|
||||
dspan: DelimSpan::dummy(),
|
||||
delim: rustc_ast::token::Delimiter::Parenthesis,
|
||||
tokens: ts,
|
||||
});
|
||||
rustc_ad_attr.item.args = rustc_ast::ast::AttrItemKind::Unparsed(
|
||||
rustc_ast::AttrArgs::Delimited(rustc_ast::DelimArgs {
|
||||
dspan: DelimSpan::dummy(),
|
||||
delim: rustc_ast::token::Delimiter::Parenthesis,
|
||||
tokens: ts,
|
||||
}),
|
||||
);
|
||||
|
||||
let new_id = ecx.sess.psess.attr_id_generator.mk_attr_id();
|
||||
let d_attr = outer_normal_attr(&rustc_ad_attr, new_id, span);
|
||||
|
|
|
|||
|
|
@ -807,24 +807,29 @@ impl<'a> TraitDef<'a> {
|
|||
rustc_ast::AttrItem {
|
||||
unsafety: Safety::Default,
|
||||
path: rustc_const_unstable,
|
||||
args: AttrArgs::Delimited(DelimArgs {
|
||||
dspan: DelimSpan::from_single(self.span),
|
||||
delim: rustc_ast::token::Delimiter::Parenthesis,
|
||||
tokens: [
|
||||
TokenKind::Ident(sym::feature, IdentIsRaw::No),
|
||||
TokenKind::Eq,
|
||||
TokenKind::lit(LitKind::Str, sym::derive_const, None),
|
||||
TokenKind::Comma,
|
||||
TokenKind::Ident(sym::issue, IdentIsRaw::No),
|
||||
TokenKind::Eq,
|
||||
TokenKind::lit(LitKind::Str, sym::derive_const_issue, None),
|
||||
]
|
||||
.into_iter()
|
||||
.map(|kind| {
|
||||
TokenTree::Token(Token { kind, span: self.span }, Spacing::Alone)
|
||||
})
|
||||
.collect(),
|
||||
}),
|
||||
args: rustc_ast::ast::AttrItemKind::Unparsed(AttrArgs::Delimited(
|
||||
DelimArgs {
|
||||
dspan: DelimSpan::from_single(self.span),
|
||||
delim: rustc_ast::token::Delimiter::Parenthesis,
|
||||
tokens: [
|
||||
TokenKind::Ident(sym::feature, IdentIsRaw::No),
|
||||
TokenKind::Eq,
|
||||
TokenKind::lit(LitKind::Str, sym::derive_const, None),
|
||||
TokenKind::Comma,
|
||||
TokenKind::Ident(sym::issue, IdentIsRaw::No),
|
||||
TokenKind::Eq,
|
||||
TokenKind::lit(LitKind::Str, sym::derive_const_issue, None),
|
||||
]
|
||||
.into_iter()
|
||||
.map(|kind| {
|
||||
TokenTree::Token(
|
||||
Token { kind, span: self.span },
|
||||
Spacing::Alone,
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
},
|
||||
)),
|
||||
tokens: None,
|
||||
},
|
||||
self.span,
|
||||
|
|
|
|||
|
|
@ -813,10 +813,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
};
|
||||
let attr_item = attr.get_normal_item();
|
||||
let safety = attr_item.unsafety;
|
||||
if let AttrArgs::Eq { .. } = attr_item.args {
|
||||
if let AttrArgs::Eq { .. } = attr_item.args.unparsed_ref().unwrap() {
|
||||
self.cx.dcx().emit_err(UnsupportedKeyValue { span });
|
||||
}
|
||||
let inner_tokens = attr_item.args.inner_tokens();
|
||||
let inner_tokens = attr_item.args.unparsed_ref().unwrap().inner_tokens();
|
||||
match expander.expand_with_safety(self.cx, safety, span, inner_tokens, tokens) {
|
||||
Ok(tok_result) => {
|
||||
let fragment = self.parse_ast_fragment(
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use rustc_ast as ast;
|
||||
use rustc_ast::token::{self, MetaVarKind};
|
||||
use rustc_ast::tokenstream::ParserRange;
|
||||
use rustc_ast::{Attribute, attr};
|
||||
use rustc_ast::{AttrItemKind, Attribute, attr};
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{Diag, PResult};
|
||||
use rustc_span::{BytePos, Span};
|
||||
|
|
@ -313,7 +313,7 @@ impl<'a> Parser<'a> {
|
|||
this.expect(exp!(CloseParen))?;
|
||||
}
|
||||
Ok((
|
||||
ast::AttrItem { unsafety, path, args, tokens: None },
|
||||
ast::AttrItem { unsafety, path, args: AttrItemKind::Unparsed(args), tokens: None },
|
||||
Trailing::No,
|
||||
UsePreAttrPos::No,
|
||||
))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue