diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 5cc9b9652ab16..867c77d129de0 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3421,6 +3421,9 @@ pub enum AttrKind { /// A normal attribute. Normal(Box), + /// A synthetic attribute inserted by the compiler. + Synthetic(Box), + /// A doc comment (e.g. `/// ...`, `//! ...`, `/** ... */`, `/*! ... */`). /// Doc attributes (e.g. `#[doc="..."]`) are represented with the `Normal` /// variant (which is much less compact and thus more expensive). @@ -3430,7 +3433,8 @@ pub enum AttrKind { #[derive(Clone, Encodable, Decodable, Debug, Walkable)] pub struct NormalAttr { pub item: AttrItem, - // Tokens for the full attribute, e.g. `#[foo]`, `#![bar]`. + // Tokens for the full attribute, e.g. `#[foo]`, `#![bar]`. (Compare this with + // `ParseNtResult::Meta`; `expand_cfg_attr_item` is where the two cases interact.) pub tokens: Option, } @@ -3440,7 +3444,7 @@ impl NormalAttr { item: AttrItem { unsafety: Safety::Default, path: Path::from_ident(ident), - args: AttrItemKind::Unparsed(AttrArgs::Empty), + args: AttrArgs::Empty, }, tokens: None, } @@ -3451,48 +3455,32 @@ impl NormalAttr { pub struct AttrItem { pub unsafety: Safety, pub path: Path, - pub args: AttrItemKind, -} - -/// 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 { - 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 { - match self { - AttrItemKind::Unparsed(args) => args.span(), - AttrItemKind::Parsed(_) => None, - } - } + pub args: AttrArgs, } -/// 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. +/// Synthetic attributes are inserted by the compiler. They cannot be written in source code, and +/// so cannot be pretty-printed by the AST pretty printer (because its output should be valid Rust +/// code). They receive special treatment because they must not affect observable language +/// behaviour: they are invisible to proc macros and are unable to re-enter the parser. #[derive(Clone, Encodable, Decodable, Debug, StableHash)] -pub enum EarlyParsedAttribute { +pub enum SyntheticAttr { + /// This synthetic attribute is added by the compiler when a `cfg` attribute is expanded so that + /// subsequent code can tell that conditional compilation occurred. A `#[cfg(pred)]` with a + /// true predicate is replaced by a synthetic `CfgTrace` attribute that records the parsed + /// predicate. A `#[cfg(pred)]` with a false predicate leaves no trace because there is no node + /// left to annotate. + /// + /// The attribute is used for some diagnostics, by rustdoc (for detecting feature usage), and + /// by some clippy lints. CfgTrace(CfgEntry), + + /// This synthetic attribute is added by the compiler when a `cfg_attr` attribute is expanded so + /// that subsequent code can tell that conditional compilation occurred. A `#[cfg_attr(pred, + /// attrs)]` is replaced by a synthetic `CfgAttrTrace` attribute whether the predicate + /// evaluated true or not (or even failed to parse). The `pred` and `attrs` are not recorded + /// because they are not needed. + /// + /// The attribute is used by some clippy lints. CfgAttrTrace, } diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs index 14b317199996f..3b0478e24b195 100644 --- a/compiler/rustc_ast/src/ast_traits.rs +++ b/compiler/rustc_ast/src/ast_traits.rs @@ -170,17 +170,13 @@ impl HasTokens for Attribute { fn tokens(&self) -> Option<&LazyAttrTokenStream> { match &self.kind { AttrKind::Normal(normal) => normal.tokens.as_ref(), - kind @ AttrKind::DocComment(..) => { - panic!("Called tokens on doc comment attr {kind:?}") - } + AttrKind::Synthetic(..) | AttrKind::DocComment(..) => unreachable!(), } } fn tokens_mut(&mut self) -> Option<&mut Option> { Some(match &mut self.kind { AttrKind::Normal(normal) => &mut normal.tokens, - kind @ AttrKind::DocComment(..) => { - panic!("Called tokens_mut on doc comment attr {kind:?}") - } + AttrKind::Synthetic(..) | AttrKind::DocComment(..) => unreachable!(), }) } } diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 9774173f24780..424280e3c9be6 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -11,11 +11,10 @@ use rustc_span::{Ident, Span, Symbol, kw, 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, - PathSegment, Safety, + PathSegment, Safety, SyntheticAttr, }; use crate::token::{ self, CommentKind, Delimiter, DocFragmentKind, InvisibleOrigin, MetaVarKind, Token, @@ -63,23 +62,16 @@ impl Attribute { pub fn get_normal_item(&self) -> &AttrItem { match &self.kind { AttrKind::Normal(normal) => &normal.item, - AttrKind::DocComment(..) => panic!("unexpected doc comment"), + AttrKind::Synthetic(..) | AttrKind::DocComment(..) => unreachable!(), } } - /// 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 { + pub fn convert_normal_to_synthetic(self, synthetic_attr: SyntheticAttr) -> Attribute { match self.kind { - AttrKind::Normal(normal) => normal.item, - AttrKind::DocComment(..) => panic!("unexpected doc comment"), + AttrKind::Normal(..) => { + Attribute { kind: AttrKind::Synthetic(Box::new(synthetic_attr)), ..self } + } + AttrKind::Synthetic(..) | AttrKind::DocComment(..) => unreachable!(), } } } @@ -91,11 +83,11 @@ impl AttributeExt for Attribute { fn value_span(&self) -> Option { match &self.kind { - AttrKind::Normal(normal) => match &normal.item.args.unparsed_ref()? { + AttrKind::Normal(normal) => match &normal.item.args { AttrArgs::Eq { expr, .. } => Some(expr.span), _ => None, }, - AttrKind::DocComment(..) => None, + AttrKind::Synthetic(..) | AttrKind::DocComment(..) => None, } } @@ -104,30 +96,28 @@ impl AttributeExt for Attribute { /// a doc comment) will return `false`. fn is_doc_comment(&self) -> Option { match self.kind { - AttrKind::Normal(..) => None, + AttrKind::Normal(..) | AttrKind::Synthetic(..) => None, AttrKind::DocComment(..) => Some(self.span), } } /// For a single-segment attribute, returns its name; otherwise, returns `None`. fn name(&self) -> Option { + use SyntheticAttr::*; match &self.kind { - AttrKind::Normal(normal) => { - if let [ident] = &*normal.item.path.segments { - Some(ident.ident.name) - } else { - None - } - } + AttrKind::Normal(normal) => normal.item.name(), + AttrKind::Synthetic(CfgTrace(_) | CfgAttrTrace) => None, AttrKind::DocComment(..) => None, } } fn symbol_path(&self) -> Option> { + use SyntheticAttr::*; match &self.kind { - AttrKind::Normal(p) => { - Some(p.item.path.segments.iter().map(|i| i.ident.name).collect()) + AttrKind::Normal(normal) => { + Some(normal.item.path.segments.iter().map(|i| i.ident.name).collect()) } + AttrKind::Synthetic(CfgTrace(_) | CfgAttrTrace) => None, AttrKind::DocComment(_, _) => None, } } @@ -135,6 +125,7 @@ impl AttributeExt for Attribute { fn path_span(&self) -> Option { match &self.kind { AttrKind::Normal(attr) => Some(attr.item.path.span), + AttrKind::Synthetic(..) => unreachable!(), AttrKind::DocComment(_, _) => None, } } @@ -151,7 +142,7 @@ impl AttributeExt for Attribute { .zip(name) .all(|(s, n)| s.args.is_none() && s.ident.name == *n) } - AttrKind::DocComment(..) => false, + AttrKind::Synthetic(..) | AttrKind::DocComment(..) => false, } } @@ -160,10 +151,10 @@ impl AttributeExt for Attribute { } fn is_word(&self) -> bool { - if let AttrKind::Normal(normal) = &self.kind { - matches!(normal.item.args, AttrItemKind::Unparsed(AttrArgs::Empty)) - } else { - false + match &self.kind { + AttrKind::Normal(normal) => matches!(normal.item.args, AttrArgs::Empty), + AttrKind::Synthetic(..) => unreachable!(), + AttrKind::DocComment(..) => false, } } @@ -177,7 +168,7 @@ impl AttributeExt for Attribute { fn meta_item_list(&self) -> Option> { match &self.kind { AttrKind::Normal(normal) => normal.item.meta_item_list(), - AttrKind::DocComment(..) => None, + AttrKind::Synthetic(..) | AttrKind::DocComment(..) => None, } } @@ -199,6 +190,7 @@ impl AttributeExt for Attribute { fn value_str(&self) -> Option { match &self.kind { AttrKind::Normal(normal) => normal.item.value_str(), + AttrKind::Synthetic(..) => unreachable!(), AttrKind::DocComment(..) => None, } } @@ -211,16 +203,14 @@ impl AttributeExt for Attribute { fn doc_str_and_fragment_kind(&self) -> Option<(Symbol, DocFragmentKind)> { match &self.kind { AttrKind::DocComment(kind, data) => Some((*data, DocFragmentKind::Sugared(*kind))), - AttrKind::Normal(normal) if normal.item.path == sym::doc => { - if let Some(value) = normal.item.value_str() - && let Some(value_span) = normal.item.value_span() - { - Some((value, DocFragmentKind::Raw(value_span))) - } else { - None - } + AttrKind::Normal(normal) + if normal.item.path == sym::doc + && let Some(value) = normal.item.value_str() + && let Some(value_span) = normal.item.value_span() => + { + Some((value, DocFragmentKind::Raw(value_span))) } - _ => None, + AttrKind::Normal(..) | AttrKind::Synthetic(..) => None, } } @@ -289,13 +279,14 @@ impl Attribute { pub fn meta(&self) -> Option { match &self.kind { AttrKind::Normal(normal) => normal.item.meta(self.span), - AttrKind::DocComment(..) => None, + AttrKind::Synthetic(..) | AttrKind::DocComment(..) => None, } } pub fn meta_kind(&self) -> Option { match &self.kind { AttrKind::Normal(normal) => normal.item.meta_kind(), + AttrKind::Synthetic(..) => unreachable!(), AttrKind::DocComment(..) => None, } } @@ -308,6 +299,8 @@ impl Attribute { .unwrap_or_else(|| panic!("attribute is missing tokens: {self:?}")) .to_attr_token_stream() .to_token_trees(), + // Empty tokens here ensures synthetic attributes are invisible to proc macros. + AttrKind::Synthetic(..) => vec![], AttrKind::DocComment(comment_kind, data) => vec![TokenTree::token_alone( token::DocComment(comment_kind, self.style, data), self.span, @@ -345,12 +338,16 @@ impl Attribute { } impl AttrItem { + pub fn name(&self) -> Option { + if let [seg] = &*self.path.segments { Some(seg.ident.name) } else { None } + } + pub fn span(&self) -> Span { self.args.span().map_or(self.path.span, |args_span| self.path.span.to(args_span)) } pub fn meta_item_list(&self) -> Option> { - match &self.args.unparsed_ref()? { + match &self.args { AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => { MetaItemKind::list_from_tokens(args.tokens.clone()) } @@ -371,7 +368,7 @@ impl AttrItem { /// #[attr("value")] /// ``` fn value_str(&self) -> Option { - match &self.args.unparsed_ref()? { + match &self.args { AttrArgs::Eq { expr, .. } => match expr.kind { ExprKind::Lit(token_lit) => { LitKind::from_token_lit(token_lit).ok().and_then(|lit| lit.str()) @@ -395,7 +392,7 @@ impl AttrItem { /// #[attr("value")] /// ``` fn value_span(&self) -> Option { - match &self.args.unparsed_ref()? { + match &self.args { AttrArgs::Eq { expr, .. } => Some(expr.span), AttrArgs::Delimited(_) | AttrArgs::Empty => None, } @@ -411,7 +408,7 @@ impl AttrItem { } pub fn meta_kind(&self) -> Option { - MetaItemKind::from_attr_args(self.args.unparsed_ref()?) + MetaItemKind::from_attr_args(&self.args) } } @@ -817,13 +814,7 @@ pub fn mk_attr_word( span, )); - mk_attr_from_item( - g, - AttrItem { unsafety, path, args: AttrItemKind::Unparsed(args) }, - tokens, - style, - span, - ) + mk_attr_from_item(g, AttrItem { unsafety, path, args }, tokens, style, span) } pub fn mk_attr_nested_word( @@ -864,13 +855,7 @@ pub fn mk_attr_nested_word( span, )); - mk_attr_from_item( - g, - AttrItem { unsafety, path, args: AttrItemKind::Unparsed(attr_args) }, - tokens, - style, - span, - ) + mk_attr_from_item(g, AttrItem { unsafety, path, args: attr_args }, tokens, style, span) } pub fn mk_attr_name_value_str( @@ -906,13 +891,7 @@ pub fn mk_attr_name_value_str( span, )); - mk_attr_from_item( - g, - AttrItem { unsafety, path, args: AttrItemKind::Unparsed(args) }, - tokens, - style, - span, - ) + mk_attr_from_item(g, AttrItem { unsafety, path, args }, tokens, style, span) } pub fn filter_by_name(attrs: &[Attribute], name: Symbol) -> impl Iterator { diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 22a77f98917d7..1c3e881bd47be 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -365,7 +365,6 @@ macro_rules! common_visitor_and_walkers { crate::token::LitKind, crate::tokenstream::LazyAttrTokenStream, crate::tokenstream::TokenStream, - EarlyParsedAttribute, Movability, Mutability, Pinnedness, @@ -374,6 +373,7 @@ macro_rules! common_visitor_and_walkers { rustc_span::ErrorGuaranteed, std::borrow::Cow<'_, str>, Symbol, + SyntheticAttr, u8, usize, ); @@ -461,7 +461,6 @@ macro_rules! common_visitor_and_walkers { ModSpans, MutTy, NormalAttr, - AttrItemKind, Parens, ParenthesizedArgs, PatFieldsRest, diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 8b776edad4d6e..c7077da26a48c 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -514,22 +514,19 @@ impl<'a> AstValidator<'a> { } fn check_decl_attrs(&self, fn_decl: &FnDecl) { + use SyntheticAttr::*; fn_decl .inputs .iter() .flat_map(|i| i.attrs.as_ref()) - .filter(|attr| { - let arr = [ - sym::allow, - sym::cfg_trace, - sym::cfg_attr_trace, - sym::deny, - sym::expect, - sym::forbid, - sym::splat, - sym::warn, - ]; - !attr.has_any_name(&arr) && rustc_attr_parsing::is_builtin_attr(*attr) + .filter(|attr| match &attr.kind { + AttrKind::Normal(normal) => { + let arr = + [sym::allow, sym::deny, sym::expect, sym::forbid, sym::splat, sym::warn]; + !attr.has_any_name(&arr) && rustc_attr_parsing::is_builtin_attr(&normal.item) + } + AttrKind::Synthetic(CfgTrace(_) | CfgAttrTrace) => false, + AttrKind::DocComment(..) => true, }) .for_each(|attr| { if attr.is_doc_comment() { diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index bfca18a42635e..268ca2a7e26f8 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -15,9 +15,9 @@ use rustc_ast::tokenstream::{Spacing, TokenStream, TokenTree}; use rustc_ast::util::classify; use rustc_ast::util::comments::{Comment, CommentStyle}; use rustc_ast::{ - self as ast, AttrArgs, BindingMode, BlockCheckMode, ByRef, DelimArgs, GenericArg, GenericBound, - InlineAsmOperand, InlineAsmOptions, InlineAsmRegOrRegClass, InlineAsmTemplatePiece, PatKind, - RangeEnd, RangeSyntax, Safety, SelfKind, Term, attr, + self as ast, AttrArgs, AttrKind, BindingMode, BlockCheckMode, ByRef, DelimArgs, GenericArg, + GenericBound, InlineAsmOperand, InlineAsmOptions, InlineAsmRegOrRegClass, + InlineAsmTemplatePiece, PatKind, RangeEnd, RangeSyntax, Safety, SelfKind, Term, attr, }; use rustc_span::edition::Edition; use rustc_span::source_map::SourceMap; @@ -670,10 +670,14 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere } fn print_attribute_inline(&mut self, attr: &ast::Attribute, is_inline: bool) -> bool { - if attr.has_name(sym::cfg_trace) || attr.has_name(sym::cfg_attr_trace) { - // It's not a valid identifier, so avoid printing it - // to keep the printed code reasonably parse-able. - return false; + use ast::SyntheticAttr::*; + match attr.kind { + AttrKind::Synthetic(CfgTrace(_) | CfgAttrTrace) => { + // These are internal synthetic attributes with no syntax, so avoid printing them + // to keep the printed code reasonably parse-able. + return false; + } + AttrKind::Normal(_) | AttrKind::DocComment(..) => {} } if !is_inline { self.hardbreak_if_not_bol(); @@ -688,6 +692,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere self.print_attr_item(&normal.item, attr.span); self.word("]"); } + ast::AttrKind::Synthetic(..) => unreachable!(), // due to early return above ast::AttrKind::DocComment(comment_kind, data) => { self.word(doc_comment_to_string( DocFragmentKind::Sugared(*comment_kind), @@ -709,7 +714,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere } ast::Safety::Default | ast::Safety::Safe(_) => {} } - match &item.args.unparsed_ref().expect("Parsed attributes are never printed") { + match &item.args { AttrArgs::Delimited(DelimArgs { dspan: _, delim, tokens }) => self.print_mac_common( Some(MacHeader::Path(&item.path)), false, diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index da37e51286d53..fc7f7731199e9 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -320,7 +320,7 @@ pub fn parse_cfg_attr( features: Option<&Features>, lint_node_id: ast::NodeId, ) -> Option<(CfgEntry, Vec<(WithTokens, Span)>)> { - match cfg_attr.get_normal_item().args.unparsed_ref().unwrap() { + match &cfg_attr.get_normal_item().args { 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| { @@ -349,7 +349,7 @@ pub fn parse_cfg_attr( } _ => { let (span, reason) = if let ast::AttrArgs::Delimited(ast::DelimArgs { dspan, .. }) = - cfg_attr.get_normal_item().args.unparsed_ref()? + cfg_attr.get_normal_item().args { (dspan.entire(), AttributeParseErrorReason::ExpectedAtLeastOneArgument) } else { diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 3f9313b19ccd0..1de0bba71ffd2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -248,9 +248,6 @@ impl AttributeParser for NakedParser { // NOTE: when making changes to this list, check that `error_codes/E0736.md` remains // accurate. const ALLOW_LIST: &[rustc_span::Symbol] = &[ - // conditional compilation - sym::cfg_trace, - sym::cfg_attr_trace, // testing (allowed here so better errors can be generated in `rustc_builtin_macros::test`) sym::test, sym::ignore, diff --git a/compiler/rustc_attr_parsing/src/attributes/util.rs b/compiler/rustc_attr_parsing/src/attributes/util.rs index 82f515aff3999..22ae0da908233 100644 --- a/compiler/rustc_attr_parsing/src/attributes/util.rs +++ b/compiler/rustc_attr_parsing/src/attributes/util.rs @@ -26,8 +26,8 @@ pub fn parse_version(s: Symbol) -> Option { Some(RustcVersion { major, minor, patch }) } -pub fn is_builtin_attr(attr: &ast::Attribute) -> bool { - attr.is_doc_comment() || attr.name().is_some_and(|name| is_builtin_attr_name(name)) +pub fn is_builtin_attr(attr: &ast::AttrItem) -> bool { + attr.name().is_some_and(|name| is_builtin_attr_name(name)) } /// Parse a single integer. diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index e8bef70be550a..76efec612a7e2 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -5,7 +5,7 @@ use std::sync::atomic::{AtomicBool, Ordering}; use rustc_ast as ast; use rustc_ast::token::DocFragmentKind; -use rustc_ast::{AttrItemKind, AttrStyle, CRATE_NODE_ID, NodeId, Safety}; +use rustc_ast::{AttrStyle, CRATE_NODE_ID, NodeId, Safety}; use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level, MultiSpan}; use rustc_feature::{BUILTIN_ATTRIBUTE_MAP, Features}; @@ -20,9 +20,9 @@ use crate::attributes::AttributeSafety; use crate::context::{ ATTRIBUTE_PARSERS, AcceptContext, FinalizeContext, FinalizeFn, SharedContext, }; -use crate::early_parsed::{EARLY_PARSED_ATTRIBUTES, EarlyParsedState}; use crate::parser::{AllowExprMetavar, ArgParser, PathParser, RefPathParser}; use crate::session_diagnostics::ParsedDescription; +use crate::synthetic::SyntheticAttrState; use crate::{AttributeTemplate, OmitDoc, ShouldEmit}; pub struct EmitAttribute( @@ -158,15 +158,12 @@ impl<'sess> AttributeParser<'sess> { allow_expr_metavar: AllowExprMetavar, expected_safety: AttributeSafety, ) -> Option { - let ast::AttrKind::Normal(normal_attr) = &attr.kind else { - panic!("parse_single called on a doc attr") - }; - let parts = - normal_attr.item.path.segments.iter().map(|seg| seg.ident.name).collect::>(); + let attr_item = attr.get_normal_item(); + let parts = attr_item.path.segments.iter().map(|seg| seg.ident.name).collect::>(); - let path = AttrPath::from_ast(&normal_attr.item.path, identity); + let path = AttrPath::from_ast(&attr_item.path, identity); let args = ArgParser::from_attr_args( - &normal_attr.item.args.unparsed_ref().unwrap(), + &attr_item.args, &parts, &sess.psess, emit_errors, @@ -175,10 +172,10 @@ impl<'sess> AttributeParser<'sess> { Self::parse_single_args( sess, attr.span, - normal_attr.item.span(), + attr_item.span(), attr.style, path, - Some(normal_attr.item.unsafety), + Some(attr_item.unsafety), expected_safety, ParsedDescription::Attribute, target_span, @@ -293,7 +290,7 @@ impl<'sess> AttributeParser<'sess> { ) -> Vec { let mut attributes = Vec::new(); let mut attr_paths: Vec> = Vec::new(); - let mut early_parsed_state = EarlyParsedState::default(); + let mut synthetic_attr_state = SyntheticAttrState::default(); let mut finalizers: Vec = Vec::with_capacity(attrs.len()); @@ -329,19 +326,13 @@ impl<'sess> AttributeParser<'sess> { comment: *symbol, })); } + ast::AttrKind::Synthetic(synthetic) => { + synthetic_attr_state.accept_synthetic_attr(attr_span, lower_span, synthetic); + continue; + } ast::AttrKind::Normal(n) => { attr_paths.push(PathParser(&n.item.path)); let attr_path = AttrPath::from_ast(&n.item.path, lower_span); - - let args = match &n.item.args { - AttrItemKind::Unparsed(args) => args, - AttrItemKind::Parsed(parsed) => { - early_parsed_state - .accept_early_parsed_attribute(attr_span, lower_span, parsed); - continue; - } - }; - let parts = n.item.path.segments.iter().map(|seg| seg.ident.name).collect::>(); let inner_span = lower_span(n.item.span()); @@ -360,7 +351,7 @@ impl<'sess> AttributeParser<'sess> { } let Some(args) = ArgParser::from_attr_args( - args, + &n.item.args, &parts, &self.sess.psess, self.should_emit, @@ -431,8 +422,7 @@ impl<'sess> AttributeParser<'sess> { } else { let attr = AttrItem { path: attr_path.clone(), - args: self - .lower_attr_args(n.item.args.unparsed_ref().unwrap(), lower_span), + args: self.lower_attr_args(&n.item.args, lower_span), id: HashIgnoredAttrId { attr_id: attr.id }, style: attr.style, span: attr_span, @@ -458,7 +448,7 @@ impl<'sess> AttributeParser<'sess> { } } - early_parsed_state.finalize_early_parsed_attributes(&mut attributes); + synthetic_attr_state.finalize_synthetic_attrs(&mut attributes); for f in &finalizers { if let Some(attr) = f(&mut FinalizeContext { shared: SharedContext { @@ -507,14 +497,13 @@ impl<'sess> AttributeParser<'sess> { /// The list of attributes that are parsed attributes, /// even though they don't have a parser in `Late::parsers()` const SPECIAL_ATTRIBUTES: &[&[Symbol]] = &[ - // Cfg attrs are removed after being early-parsed, so don't need to be in the parser list + // Cfg attrs are removed after being converted into synthetic attrs and don't need to + // be in the parser list. &[sym::cfg], &[sym::cfg_attr], ]; - ATTRIBUTE_PARSERS.accepters.contains_key(path) - || EARLY_PARSED_ATTRIBUTES.contains(&path) - || SPECIAL_ATTRIBUTES.contains(&path) + ATTRIBUTE_PARSERS.accepters.contains_key(path) || SPECIAL_ATTRIBUTES.contains(&path) } fn lower_attr_args(&self, args: &ast::AttrArgs, lower_span: impl Fn(Span) -> Span) -> AttrArgs { diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 3d6148f69537c..475957f384b45 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -88,6 +88,7 @@ // tidy-alphabetical-start #![feature(decl_macro)] +#![feature(deref_patterns)] #![feature(iter_intersperse)] #![feature(try_blocks)] #![recursion_limit = "256"] @@ -98,12 +99,12 @@ mod attributes; mod check_cfg; mod context; mod diagnostics; -mod early_parsed; mod interface; pub mod parser; mod safety; mod session_diagnostics; mod stability; +mod synthetic; mod target_checking; mod template; pub mod validate_attr; diff --git a/compiler/rustc_attr_parsing/src/early_parsed.rs b/compiler/rustc_attr_parsing/src/synthetic.rs similarity index 56% rename from compiler/rustc_attr_parsing/src/early_parsed.rs rename to compiler/rustc_attr_parsing/src/synthetic.rs index 6a33cb38edf98..5e633e6ee3685 100644 --- a/compiler/rustc_attr_parsing/src/early_parsed.rs +++ b/compiler/rustc_attr_parsing/src/synthetic.rs @@ -1,48 +1,45 @@ -use rustc_ast::EarlyParsedAttribute; +use rustc_ast::SyntheticAttr; use rustc_ast::attr::data_structures::CfgEntry; use rustc_hir::Attribute; use rustc_hir::attrs::AttributeKind; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::Span; use thin_vec::ThinVec; -pub(crate) const EARLY_PARSED_ATTRIBUTES: &[&[Symbol]] = - &[&[sym::cfg_trace], &[sym::cfg_attr_trace]]; - -/// This struct contains the state necessary to convert early parsed attributes to hir attributes -/// The only conversion that really happens here is that multiple early parsed attributes are +/// This struct contains the state necessary to convert synthetic attributes to hir attributes +/// The only conversion that really happens here is that multiple synthetic attributes are /// merged into a single hir attribute, representing their combined state. /// FIXME: We should make this a nice and extendable system if this is going to be used more often #[derive(Default)] -pub(crate) struct EarlyParsedState { - /// Attribute state for `#[cfg]` trace attributes +pub(crate) struct SyntheticAttrState { + /// Attribute state for `SyntheticAttr::CfgTrace` attributes. cfg_trace: ThinVec<(CfgEntry, Span)>, - /// Attribute state for `#[cfg_attr]` trace attributes - /// The arguments of these attributes is no longer relevant for any later passes, only their presence. - /// So we discard the arguments here. + /// Attribute state for `SyntheticAttr::CfgAttrTrace` attributes. + /// The arguments of these attributes is no longer relevant for any later passes, only their + /// presence. So we discard the arguments here. cfg_attr_trace: bool, } -impl EarlyParsedState { - pub(crate) fn accept_early_parsed_attribute( +impl SyntheticAttrState { + pub(crate) fn accept_synthetic_attr( &mut self, attr_span: Span, lower_span: impl Copy + Fn(Span) -> Span, - parsed: &EarlyParsedAttribute, + synthetic: &SyntheticAttr, ) { - match parsed { - EarlyParsedAttribute::CfgTrace(cfg) => { + match synthetic { + SyntheticAttr::CfgTrace(cfg) => { let mut cfg = cfg.clone(); cfg.lower_spans(lower_span); self.cfg_trace.push((cfg, attr_span)); } - EarlyParsedAttribute::CfgAttrTrace => { + SyntheticAttr::CfgAttrTrace => { self.cfg_attr_trace = true; } } } - pub(crate) fn finalize_early_parsed_attributes(self, attributes: &mut Vec) { + pub(crate) fn finalize_synthetic_attrs(self, attributes: &mut Vec) { if !self.cfg_trace.is_empty() { attributes.push(Attribute::Parsed(AttributeKind::CfgTrace(self.cfg_trace))); } diff --git a/compiler/rustc_attr_parsing/src/validate_attr.rs b/compiler/rustc_attr_parsing/src/validate_attr.rs index 748e452a24cac..daec803a27a24 100644 --- a/compiler/rustc_attr_parsing/src/validate_attr.rs +++ b/compiler/rustc_attr_parsing/src/validate_attr.rs @@ -6,7 +6,8 @@ use std::slice; use rustc_ast::token::Delimiter; use rustc_ast::tokenstream::DelimSpan; use rustc_ast::{ - self as ast, AttrArgs, Attribute, DelimArgs, MetaItem, MetaItemInner, MetaItemKind, Safety, + self as ast, AttrArgs, AttrKind, Attribute, DelimArgs, MetaItem, MetaItemInner, MetaItemKind, + Safety, }; use rustc_errors::{Applicability, Diagnostic, PResult}; use rustc_feature::BUILTIN_ATTRIBUTE_MAP; @@ -20,9 +21,11 @@ use rustc_span::{Span, Symbol, sym}; use crate::{AttributeParser, AttributeTemplate, session_diagnostics as errors, template}; pub fn check_attr(psess: &ParseSess, attr: &Attribute) { - if attr.is_doc_comment() || attr.has_name(sym::cfg_trace) || attr.has_name(sym::cfg_attr_trace) - { - return; + use ast::SyntheticAttr::*; + match &attr.kind { + AttrKind::Normal(_) => {} + AttrKind::Synthetic(CfgTrace(_) | CfgAttrTrace) => return, + AttrKind::DocComment(..) => return, } let builtin_attr_info = attr.name().and_then(|name| BUILTIN_ATTRIBUTE_MAP.get(&name)); @@ -53,7 +56,7 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute) { } _ => { let attr_item = attr.get_normal_item(); - if let AttrArgs::Eq { .. } = attr_item.args.unparsed_ref().unwrap() { + if let AttrArgs::Eq { .. } = attr_item.args { // All key-value attributes are restricted to meta-item syntax. match parse_meta(psess, attr) { Ok(_) => {} @@ -72,7 +75,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.unparsed_ref().unwrap() { + kind: match &item.args { AttrArgs::Empty => MetaItemKind::Word, AttrArgs::Delimited(DelimArgs { dspan, delim, tokens }) => { check_meta_bad_delim(psess, *dspan, *delim); diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index d682afad25966..29013d7c8b94d 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -361,7 +361,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: rustc_ast::ast::AttrItemKind::Unparsed(ast::AttrArgs::Delimited(never_arg)), + args: ast::AttrArgs::Delimited(never_arg), }; let inline_never_attr = Box::new(ast::NormalAttr { item: inline_item, tokens: None }); let new_id = ecx.sess.psess.attr_id_generator.mk_attr_id(); @@ -423,13 +423,11 @@ mod llvm_enzyme { } }; // Now update for d_fn - 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, - }), - ); + rustc_ad_attr.item.args = 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); diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index f9ec93a1115dd..fcba0b6be4ee0 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -807,29 +807,24 @@ impl<'a> TraitDef<'a> { rustc_ast::AttrItem { unsafety: Safety::Default, path: rustc_const_unstable, - 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(), - }, - )), + 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(), + }), }, self.span, ), diff --git a/compiler/rustc_builtin_macros/src/offload.rs b/compiler/rustc_builtin_macros/src/offload.rs index 598c012309489..6218674917098 100644 --- a/compiler/rustc_builtin_macros/src/offload.rs +++ b/compiler/rustc_builtin_macros/src/offload.rs @@ -12,14 +12,10 @@ fn compile_for_device(ecx: &mut ExtCtxt<'_>) -> bool { ecx.sess.opts.unstable_opts.offload.contains(&Offload::Device) } -fn outer_normal_attr( - kind: &Box, - id: rustc_ast::AttrId, - span: Span, -) -> rustc_ast::Attribute { - let style = rustc_ast::AttrStyle::Outer; - let kind = rustc_ast::AttrKind::Normal(kind.clone()); - rustc_ast::Attribute { kind, id, style, span } +fn outer_normal_attr(normal: &Box, id: ast::AttrId, span: Span) -> ast::Attribute { + let style = ast::AttrStyle::Outer; + let kind = ast::AttrKind::Normal(normal.clone()); + ast::Attribute { kind, id, style, span } } fn extract_fn( @@ -118,7 +114,7 @@ pub(crate) fn expand_kernel( let unsafe_item = AttrItem { unsafety: ast::Safety::Unsafe(span), path: ast::Path::from_ident(Ident::new(sym::no_mangle, span)), - args: ast::AttrItemKind::Unparsed(ast::AttrArgs::Empty), + args: ast::AttrArgs::Empty, }; let no_mangle_attr = Box::new(ast::NormalAttr { item: unsafe_item, tokens: None }); @@ -182,7 +178,7 @@ pub(crate) fn expand_kernel( let inline_item = ast::AttrItem { unsafety: ast::Safety::Default, path: ast::Path::from_ident(Ident::with_dummy_span(sym::inline)), - args: rustc_ast::ast::AttrItemKind::Unparsed(ast::AttrArgs::Delimited(never_arg)), + args: ast::AttrArgs::Delimited(never_arg), }; let inline_never_attr = Box::new(ast::NormalAttr { item: inline_item, tokens: None }); diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index b03f294c4af13..030fa96a9fa68 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -7,8 +7,8 @@ use rustc_ast::tokenstream::{ AttrTokenStream, AttrTokenTree, LazyAttrTokenStream, Spacing, TokenTree, WithTokens, }; use rustc_ast::{ - self as ast, AttrItemKind, AttrKind, AttrStyle, Attribute, EarlyParsedAttribute, HasAttrs, - HasTokens, MetaItem, MetaItemInner, NodeId, NormalAttr, + self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem, MetaItemInner, NodeId, + SyntheticAttr, }; use rustc_attr_parsing::parser::AllowExprMetavar; use rustc_attr_parsing::{ @@ -143,19 +143,6 @@ pub fn pre_configure_attrs(sess: &Session, attrs: &[Attribute]) -> ast::AttrVec .collect() } -pub(crate) fn attr_into_trace(mut attr: Attribute, trace_name: Symbol) -> Attribute { - match &mut attr.kind { - AttrKind::Normal(normal) => { - let NormalAttr { item, tokens } = &mut **normal; - item.path.segments[0].ident.name = trace_name; - // This makes the trace attributes unobservable to token-based proc macros. - *tokens = Some(LazyAttrTokenStream::new_direct(AttrTokenStream::default())); - } - AttrKind::DocComment(..) => unreachable!(), - } - attr -} - #[macro_export] macro_rules! configure { ($this:ident, $node:ident) => { @@ -261,11 +248,9 @@ impl<'a> StripUnconfigured<'a> { /// is in the original source file. Gives a compiler error if the syntax of /// the attribute is incorrect. pub(crate) fn expand_cfg_attr(&self, cfg_attr: &Attribute, recursive: bool) -> Vec { - // A trace attribute left in AST in place of the original `cfg_attr` attribute. + // A synthetic trace attribute left in AST in place of the original `cfg_attr` attribute. // It can later be used by lints or other diagnostics. - let mut trace_attr = cfg_attr.clone(); - trace_attr.replace_args(AttrItemKind::Parsed(EarlyParsedAttribute::CfgAttrTrace)); - let trace_attr = attr_into_trace(trace_attr, sym::cfg_attr_trace); + let trace_attr = cfg_attr.clone().convert_normal_to_synthetic(SyntheticAttr::CfgAttrTrace); let Some((cfg_predicate, expanded_attrs)) = rustc_attr_parsing::parse_cfg_attr( cfg_attr, diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index b35f6dcb0af6f..832a991c31780 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -7,10 +7,10 @@ use rustc_ast::mut_visit::*; use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{AssocCtxt, Visitor, VisitorResult, try_visit, walk_list}; use rustc_ast::{ - self as ast, AssocItemKind, AstNodeWrapper, AttrArgs, AttrItemKind, AttrStyle, AttrVec, - DUMMY_NODE_ID, DelegationSource, DelegationSuffixes, EarlyParsedAttribute, ExprKind, - ForeignItemKind, HasAttrs, HasNodeId, Inline, ItemKind, MacStmtStyle, MetaItemInner, - MetaItemKind, ModKind, NodeId, PatKind, StmtKind, TyKind, token, + self as ast, AssocItemKind, AstNodeWrapper, AttrArgs, AttrKind, AttrStyle, AttrVec, + DUMMY_NODE_ID, DelegationSource, DelegationSuffixes, ExprKind, ForeignItemKind, HasAttrs, + HasNodeId, Inline, ItemKind, MacStmtStyle, MetaItemInner, MetaItemKind, ModKind, NodeId, + PatKind, StmtKind, SyntheticAttr, TyKind, token, }; use rustc_ast_pretty::pprust; use rustc_attr_parsing::parser::AllowExprMetavar; @@ -36,7 +36,7 @@ use rustc_span::{ErrorGuaranteed, FileName, Ident, LocalExpnId, Span, Symbol, sy use smallvec::SmallVec; use crate::base::*; -use crate::config::{StripUnconfigured, attr_into_trace}; +use crate::config::StripUnconfigured; use crate::diagnostics::{ EmptyDelegationMac, GlobDelegationOutsideImpls, GlobDelegationTraitlessQpath, IncompleteParse, RecursionLimitReached, RemoveExprNotSupported, RemoveNodeNotSupported, UnsupportedKeyValue, @@ -818,10 +818,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.unparsed_ref().unwrap() { + if let AttrArgs::Eq { .. } = attr_item.args { self.cx.dcx().emit_err(UnsupportedKeyValue { span }); } - let inner_tokens = attr_item.args.unparsed_ref().unwrap().inner_tokens(); + let inner_tokens = attr_item.args.inner_tokens(); match expander.expand_with_safety(self.cx, safety, span, inner_tokens, tokens) { Ok(tok_result) => { let fragment = self.parse_ast_fragment( @@ -2163,7 +2163,9 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { let mut cfg_pos = None; let mut attr_pos = None; for (pos, attr) in item.attrs().iter().enumerate() { - if !attr.is_doc_comment() && !self.cx.expanded_inert_attrs.is_marked(attr) { + if let AttrKind::Normal(..) = attr.kind + && !self.cx.expanded_inert_attrs.is_marked(attr) + { let name = attr.name(); if name == Some(sym::cfg) || name == Some(sym::cfg_attr) { cfg_pos = Some(pos); // a cfg attr found, no need to search anymore @@ -2207,6 +2209,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { // Detect use of feature-gated or invalid attributes on macro invocations // since they will not be detected after macro expansion. fn check_attributes(&self, attrs: &[ast::Attribute], call: &ast::MacCall) { + use SyntheticAttr::*; let features = self.cx.ecfg.features; let mut attrs = attrs.iter().peekable(); let mut span: Option = None; @@ -2239,21 +2242,30 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { self.cx.current_expansion.lint_node_id, crate::diagnostics::MacroCallUnusedDocComment { span: attr.span }, ); - } else if rustc_attr_parsing::is_builtin_attr(attr) - && !AttributeParser::is_parsed_attribute(&attr.path()) - { - let attr_name = attr.name().unwrap(); - self.cx.sess.psess.buffer_lint( - UNUSED_ATTRIBUTES, - attr.span, - self.cx.current_expansion.lint_node_id, - crate::diagnostics::UnusedBuiltinAttribute { - attr_name, - macro_name: pprust::path_to_string(&call.path), - invoc_span: call.path.span, - attr_span: attr.span, - }, - ); + continue; + } + + match &attr.kind { + AttrKind::Normal(normal) + if rustc_attr_parsing::is_builtin_attr(&normal.item) + && !AttributeParser::is_parsed_attribute(&attr.path()) => + { + let attr_name = attr.name().unwrap(); + self.cx.sess.psess.buffer_lint( + UNUSED_ATTRIBUTES, + attr.span, + self.cx.current_expansion.lint_node_id, + crate::diagnostics::UnusedBuiltinAttribute { + attr_name, + macro_name: pprust::path_to_string(&call.path), + invoc_span: call.path.span, + attr_span: attr.span, + }, + ); + } + AttrKind::Normal(_) => {} + AttrKind::Synthetic(CfgTrace(_) | CfgAttrTrace) => {} + AttrKind::DocComment(..) => unreachable!(), // handled above } } } @@ -2283,10 +2295,9 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { let res = eval_config_entry(self.cfg().sess, &cfg); if res.as_bool() { - // A trace attribute left in AST in place of the original `cfg` attribute. + // A synthetic trace attribute left in AST in place of the original `cfg` attribute. // It can later be used by lints or other diagnostics. - let mut trace_attr = attr_into_trace(attr, sym::cfg_trace); - trace_attr.replace_args(AttrItemKind::Parsed(EarlyParsedAttribute::CfgTrace(cfg))); + let trace_attr = attr.convert_normal_to_synthetic(SyntheticAttr::CfgTrace(cfg)); node.visit_attrs(|attrs| attrs.insert(pos, trace_attr)); } diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs index ec55f40b6c1e0..8bbca0ddf0f90 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -2,6 +2,7 @@ #![allow(internal_features)] #![feature(associated_type_defaults)] #![feature(default_field_values)] +#![feature(deref_patterns)] #![feature(macro_metavar_expr)] #![feature(proc_macro_diagnostic)] #![feature(proc_macro_internals)] diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index ed09a2eb958e2..cd01c29d40ac2 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -246,7 +246,6 @@ pub static BUILTIN_ATTRIBUTES: &[Symbol] = &[ sym::rustc_deprecated_safe_2024, sym::rustc_pub_transparent, - // ========================================================================== // Internal attributes: Type system related: // ========================================================================== @@ -291,12 +290,6 @@ pub static BUILTIN_ATTRIBUTES: &[Symbol] = &[ sym::rustc_macro_transparency, sym::rustc_autodiff, sym::rustc_offload_kernel, - // Traces that are left when `cfg` and `cfg_attr` attributes are expanded. - // The attributes are not gated, to avoid stability errors, but they cannot be used in stable - // or unstable code directly because `sym::cfg_(attr_)trace` are not valid identifiers, they - // can only be generated by the compiler. - sym::cfg_trace, - sym::cfg_attr_trace, // ========================================================================== // Internal attributes, Diagnostics related: diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 92928fb03b644..2e272fa3af9d0 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1380,13 +1380,6 @@ impl Attribute { } } - pub fn unwrap_normal_item(self) -> AttrItem { - match self { - Attribute::Unparsed(normal) => *normal, - _ => panic!("unexpected parsed attribute"), - } - } - pub fn value_lit(&self) -> Option<&MetaItemLit> { match &self { Attribute::Unparsed(n) => match n.as_ref() { diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index c34005d2ea7f5..5400c601ebf57 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -776,6 +776,7 @@ fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: & AttrKind::DocComment(CommentKind::Block, _) => { BuiltinUnusedDocCommentSub::BlockHelp } + AttrKind::Synthetic(..) => unreachable!(), }; cx.emit_span_lint( UNUSED_DOC_COMMENTS, diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index 5b0d99242f440..c0e3116211d8a 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -1,7 +1,7 @@ use rustc_ast as ast; use rustc_ast::token::{self, MetaVarKind}; use rustc_ast::tokenstream::{ParserRange, WithTokens}; -use rustc_ast::{AttrItemKind, Attribute, attr}; +use rustc_ast::{Attribute, attr}; use rustc_errors::codes::*; use rustc_errors::{Diag, PResult, msg}; use rustc_span::{BytePos, Span}; @@ -350,11 +350,7 @@ impl<'a> Parser<'a> { this.expect(exp!(CloseParen))?; } Ok(( - WithTokens::new(ast::AttrItem { - unsafety, - path, - args: AttrItemKind::Unparsed(args), - }), + WithTokens::new(ast::AttrItem { unsafety, path, args }), Trailing::No, UsePreAttrPos::No, )) diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 6397fc855b86c..49627a6c92c7c 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -5,7 +5,7 @@ use rustc_ast::token::Token; use rustc_ast::tokenstream::{ AttrsTarget, LazyAttrTokenStream, NodeRange, ParserRange, Spacing, TokenCursor, }; -use rustc_ast::{self as ast, AttrVec, Attribute, HasTokens}; +use rustc_ast::{self as ast, AttrKind, AttrVec, Attribute, HasTokens}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::PResult; use rustc_session::parse::ParseSess; @@ -391,15 +391,21 @@ impl<'a> Parser<'a> { } } -/// Tokens are needed if: -/// - any non-single-segment attributes (other than doc comments) are present, -/// e.g. `rustfmt::skip`; or -/// - any `cfg_attr` attributes are present; or -/// - any single-segment, non-builtin attributes are present, e.g. `derive`, -/// `test`, `global_allocator`. fn needs_tokens(attrs: &[ast::Attribute]) -> bool { - attrs.iter().any(|attr| match attr.name() { - None => !attr.is_doc_comment(), - Some(name) => name == sym::cfg_attr || !rustc_feature::is_builtin_attr_name(name), + // Tokens are needed if... + attrs.iter().any(|attr| match &attr.kind { + AttrKind::Normal(normal) => { + match normal.item.name() { + // ... a multi-segment attribute is present, e.g. `rustfmt::skip`. + None => true, + // ... `cfg_attr` or a single-segment non-builtin attribute is present, e.g. + // `derive`, `test`, `global_allocator`. + Some(name) => name == sym::cfg_attr || !rustc_feature::is_builtin_attr_name(name), + } + } + // Synthetic attributes are created only during expansion, and can't re-enter the parser + // because they have no token form. + AttrKind::Synthetic(_) => unreachable!(), + AttrKind::DocComment(..) => false, }) } diff --git a/compiler/rustc_parse/src/parser/cfg_select.rs b/compiler/rustc_parse/src/parser/cfg_select.rs index a4aeb919b106a..f5e82b96b41eb 100644 --- a/compiler/rustc_parse/src/parser/cfg_select.rs +++ b/compiler/rustc_parse/src/parser/cfg_select.rs @@ -57,6 +57,7 @@ impl<'a> Parser<'a> { for attr in attrs.take_for_recovery(self.psess) { match attr.kind { AttrKind::Normal(..) => spans.attrs.push(attr.span), + AttrKind::Synthetic(..) => unreachable!(), // `parse_outer_attributes` already emitted E0753 for inner doc comments before // recovering them as outer doc-comment attributes. AttrKind::DocComment(comment_kind, _) diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs index f9b6367d4a9d4..87193b73a1a95 100644 --- a/compiler/rustc_passes/src/input_stats.rs +++ b/compiler/rustc_passes/src/input_stats.rs @@ -773,7 +773,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { fn visit_attribute(&mut self, attr: &'v ast::Attribute) { record_variants!( (self, attr, attr.kind, None, ast, Attribute, AttrKind), - [Normal, DocComment] + [Normal, Synthetic, DocComment] ); ast_visit::walk_attribute(self, attr) } diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 3dabae553204c..d319cd7ae9281 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -557,11 +557,18 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } fn visit_attribute(&mut self, attr: &'a Attribute) { + use SyntheticAttr::*; let orig_in_attr = mem::replace(&mut self.invocation_parent.in_attr, true); - if !attr.is_doc_comment() && attr::is_builtin_attr(attr) { - self.r - .builtin_attrs - .push((attr.get_normal_item().path.segments[0].ident, self.parent_scope)); + match &attr.kind { + AttrKind::Normal(normal) => { + if attr::is_builtin_attr(&normal.item) { + self.r + .builtin_attrs + .push((normal.item.path.segments[0].ident, self.parent_scope)); + } + } + AttrKind::Synthetic(CfgTrace(_) | CfgAttrTrace) => {} + AttrKind::DocComment(..) => {} } visit::walk_attribute(self, attr); self.invocation_parent.in_attr = orig_in_attr; diff --git a/compiler/rustc_resolve/src/diagnostics/impls.rs b/compiler/rustc_resolve/src/diagnostics/impls.rs index a72e65f634b16..0b6b9899f48a6 100644 --- a/compiler/rustc_resolve/src/diagnostics/impls.rs +++ b/compiler/rustc_resolve/src/diagnostics/impls.rs @@ -1514,11 +1514,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { suggestions.extend( BUILTIN_ATTRIBUTES .iter() - // These trace attributes are compiler-generated and have - // deliberately invalid names. - .filter(|attr| { - !matches!(**attr, sym::cfg_trace | sym::cfg_attr_trace) - }) .map(|attr| TypoSuggestion::typo_from_name(*attr, res)), ); } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index de090531a6192..9db6b9f9af126 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -581,7 +581,6 @@ symbols! { cfg_accessible, cfg_attr, cfg_attr_multi, - cfg_attr_trace: "", // must not be a valid identifier cfg_boolean_literals, cfg_contract_checks, cfg_doctest, @@ -602,7 +601,6 @@ symbols! { cfg_target_object_format, cfg_target_thread_local, cfg_target_vendor, - cfg_trace: "", // must not be a valid identifier cfg_ub_checks, cfg_version, cfi, diff --git a/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs b/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs index c956738edf0eb..da9ace312f7d3 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs @@ -43,21 +43,12 @@ fn check_duplicated_attr( }; if let Some(ident) = attr.ident() { let name = ident.name; - if name == sym::doc || name == sym::cfg_attr_trace || name == sym::rustc_on_unimplemented || name == sym::reason - { + if name == sym::doc || name == sym::rustc_on_unimplemented || name == sym::reason { // FIXME: Would be nice to handle `cfg_attr` as well. Only problem is to check that cfg // conditions are the same. // `#[rustc_on_unimplemented]` contains duplicated subattributes, that's expected. return; } - if let Some(direct_parent) = parent.last() - && *direct_parent == sym::cfg_trace - && [sym::all, sym::not, sym::any].contains(&name) - { - // FIXME: We don't correctly check `cfg`s for now, so if it's more complex than just a one - // level `cfg`, we leave. - return; - } } if let Some(value) = attr.value_str() { emit_if_duplicated( diff --git a/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs b/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs index d71c8e9894bf7..3e82ff4a69545 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs @@ -1,6 +1,6 @@ use super::MIXED_ATTRIBUTES_STYLE; use clippy_utils::diagnostics::span_lint; -use rustc_ast::{AttrKind, AttrStyle, Attribute}; +use rustc_ast::{AttrKind, AttrStyle, Attribute, SyntheticAttr}; use rustc_data_structures::fx::FxHashSet; use rustc_lint::{EarlyContext, LintContext}; use rustc_span::source_map::SourceMap; @@ -12,6 +12,8 @@ enum SimpleAttrKind { Doc, /// A normal attribute, with its name symbols. Normal(Vec), + CfgTrace, + CfgAttrTrace, } impl From<&AttrKind> for SimpleAttrKind { @@ -27,6 +29,12 @@ impl From<&AttrKind> for SimpleAttrKind { .collect::>(); Self::Normal(path_symbols) }, + AttrKind::Synthetic(synthetic) => { + match &**synthetic { + SyntheticAttr::CfgTrace(_) => Self::CfgTrace, + SyntheticAttr::CfgAttrTrace => Self::CfgAttrTrace, + } + } AttrKind::DocComment(..) => Self::Doc, } } diff --git a/src/tools/clippy/clippy_lints/src/attrs/mod.rs b/src/tools/clippy/clippy_lints/src/attrs/mod.rs index 78701b3368226..2833619814cc3 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/mod.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/mod.rs @@ -17,7 +17,7 @@ use clippy_config::Conf; use clippy_utils::check_clippy_attr; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::msrvs::{self, Msrv, MsrvStack}; -use rustc_ast::{self as ast, AttrArgs, AttrItemKind, AttrKind, Attribute, MetaItemInner, MetaItemKind}; +use rustc_ast::{self as ast, AttrArgs, AttrKind, Attribute, MetaItemInner, MetaItemKind}; use rustc_hir::{ImplItem, ImplItemKind, Item, ItemKind, TraitFn, TraitItem, TraitItemKind}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; @@ -614,12 +614,8 @@ impl EarlyLintPass for PostExpansionEarlyAttributes { } if attr.has_name(sym::ignore) - && match &attr.kind { - AttrKind::Normal(normal_attr) => { - !matches!(normal_attr.item.args, AttrItemKind::Unparsed(AttrArgs::Eq { .. })) - }, - AttrKind::DocComment(..) => true, - } + && let AttrKind::Normal(normal_attr) = &attr.kind + && !matches!(normal_attr.item.args, AttrArgs::Eq { .. }) { span_lint_and_help( cx, diff --git a/src/tools/clippy/clippy_lints/src/attrs/should_panic_without_expect.rs b/src/tools/clippy/clippy_lints/src/attrs/should_panic_without_expect.rs index 1a9abd88a46ae..fd27e30a67f3b 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/should_panic_without_expect.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/should_panic_without_expect.rs @@ -2,19 +2,19 @@ use super::{Attribute, SHOULD_PANIC_WITHOUT_EXPECT}; use clippy_utils::diagnostics::span_lint_and_sugg; use rustc_ast::token::{Token, TokenKind}; use rustc_ast::tokenstream::TokenTree; -use rustc_ast::{AttrArgs, AttrItemKind, AttrKind}; +use rustc_ast::{AttrArgs, AttrKind}; use rustc_errors::Applicability; use rustc_lint::EarlyContext; use rustc_span::sym; pub(super) fn check(cx: &EarlyContext<'_>, attr: &Attribute) { if let AttrKind::Normal(normal_attr) = &attr.kind { - if let AttrItemKind::Unparsed(AttrArgs::Eq { .. }) = &normal_attr.item.args { + if let AttrArgs::Eq { .. } = &normal_attr.item.args { // `#[should_panic = ".."]` found, good return; } - if let AttrItemKind::Unparsed(AttrArgs::Delimited(args)) = &normal_attr.item.args + if let AttrArgs::Delimited(args) = &normal_attr.item.args && let mut tt_iter = args.tokens.iter() && let Some(TokenTree::Token( Token { diff --git a/src/tools/clippy/clippy_lints/src/cfg_not_test.rs b/src/tools/clippy/clippy_lints/src/cfg_not_test.rs index 88d07be0d4d46..0a1ad883c2977 100644 --- a/src/tools/clippy/clippy_lints/src/cfg_not_test.rs +++ b/src/tools/clippy/clippy_lints/src/cfg_not_test.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_ast::attr::data_structures::CfgEntry; -use rustc_ast::{AttrItemKind, EarlyParsedAttribute}; +use rustc_ast::{AttrKind, SyntheticAttr}; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; use rustc_span::sym; @@ -34,23 +34,20 @@ declare_lint_pass!(CfgNotTest => [CFG_NOT_TEST]); impl EarlyLintPass for CfgNotTest { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &rustc_ast::Attribute) { - if attr.has_name(sym::cfg_trace) { - let AttrItemKind::Parsed(EarlyParsedAttribute::CfgTrace(cfg)) = &attr.get_normal_item().args else { - unreachable!() - }; - - if contains_not_test(cfg, false) { - span_lint_and_then( - cx, - CFG_NOT_TEST, - attr.span, - "code is excluded from test builds", - |diag| { - diag.help("consider not excluding any code from test builds"); - diag.note_once("this could increase code coverage despite not actually being tested"); - }, - ); - } + if let AttrKind::Synthetic(synthetic) = &attr.kind + && let SyntheticAttr::CfgTrace(cfg) = &**synthetic + && contains_not_test(cfg, false) + { + span_lint_and_then( + cx, + CFG_NOT_TEST, + attr.span, + "code is excluded from test builds", + |diag| { + diag.help("consider not excluding any code from test builds"); + diag.note_once("this could increase code coverage despite not actually being tested"); + }, + ); } } } diff --git a/src/tools/clippy/clippy_lints/src/doc/include_in_doc_without_cfg.rs b/src/tools/clippy/clippy_lints/src/doc/include_in_doc_without_cfg.rs index 6c800f47b68a9..0a4ef50f14bb3 100644 --- a/src/tools/clippy/clippy_lints/src/doc/include_in_doc_without_cfg.rs +++ b/src/tools/clippy/clippy_lints/src/doc/include_in_doc_without_cfg.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; -use rustc_ast::{AttrArgs, AttrItemKind, AttrKind, AttrStyle, Attribute}; +use rustc_ast::{AttrArgs, AttrKind, AttrStyle, Attribute}; use rustc_errors::Applicability; use rustc_lint::EarlyContext; @@ -9,9 +9,9 @@ use super::DOC_INCLUDE_WITHOUT_CFG; pub fn check(cx: &EarlyContext<'_>, attrs: &[Attribute]) { for attr in attrs { if !attr.span.from_expansion() - && let AttrKind::Normal(ref item) = attr.kind + && let AttrKind::Normal(ref normal) = attr.kind && attr.doc_str().is_some() - && let AttrItemKind::Unparsed(AttrArgs::Eq { expr: meta, .. }) = &item.item.args + && let AttrArgs::Eq { expr: meta, .. } = &normal.item.args && !attr.span.contains(meta.span) // Since the `include_str` is already expanded at this point, we can only take the // whole attribute snippet and then modify for our suggestion. diff --git a/src/tools/clippy/clippy_lints/src/empty_line_after.rs b/src/tools/clippy/clippy_lints/src/empty_line_after.rs index f076c6d29138d..834981a582832 100644 --- a/src/tools/clippy/clippy_lints/src/empty_line_after.rs +++ b/src/tools/clippy/clippy_lints/src/empty_line_after.rs @@ -251,7 +251,7 @@ impl Stop { Some(Self { span: attr.span, kind: match attr.kind { - AttrKind::Normal(_) => StopKind::Attr, + AttrKind::Normal(_) | AttrKind::Synthetic(_) => StopKind::Attr, AttrKind::DocComment(comment_kind, _) => StopKind::Doc(comment_kind), }, first: file.lookup_line(file.relative_position(lo))?, diff --git a/src/tools/clippy/clippy_lints/src/large_include_file.rs b/src/tools/clippy/clippy_lints/src/large_include_file.rs index 39d252f4f3b6b..3c35c2fc9c82d 100644 --- a/src/tools/clippy/clippy_lints/src/large_include_file.rs +++ b/src/tools/clippy/clippy_lints/src/large_include_file.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::source::snippet_opt; use clippy_utils::sym; -use rustc_ast::{AttrArgs, AttrItemKind, AttrKind, Attribute, LitKind}; +use rustc_ast::{AttrArgs, AttrKind, Attribute, LitKind}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; use rustc_session::impl_lint_pass; @@ -89,10 +89,10 @@ impl EarlyLintPass for LargeIncludeFile { if !attr.span.from_expansion() // Currently, rustc limits the usage of macro at the top-level of attributes, // so we don't need to recurse into each level. - && let AttrKind::Normal(ref item) = attr.kind + && let AttrKind::Normal(ref normal) = attr.kind && let Some(doc) = attr.doc_str() && doc.as_str().len() as u64 > self.max_file_size - && let AttrItemKind::Unparsed(AttrArgs::Eq { expr: meta, .. }) = &item.item.args + && let AttrArgs::Eq { expr: meta, .. } = &normal.item.args && !attr.span.contains(meta.span) // Since the `include_str` is already expanded at this point, we can only take the // whole attribute snippet and then modify for our suggestion. diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index fe51f841bc8b6..07c3d2e2f0ffe 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -1004,20 +1004,13 @@ fn eq_attr(l: &Attribute, r: &Attribute) -> bool { && match (&l.kind, &r.kind) { (DocComment(l1, l2), DocComment(r1, r2)) => l1 == r1 && l2 == r2, (Normal(l), Normal(r)) => { - eq_path(&l.item.path, &r.item.path) && eq_attr_item_kind(&l.item.args, &r.item.args) + eq_path(&l.item.path, &r.item.path) && eq_attr_args(&l.item.args, &r.item.args) }, + (Synthetic(..), _) | (_, Synthetic(..)) => unreachable!(), _ => false, } } -fn eq_attr_item_kind(l: &AttrItemKind, r: &AttrItemKind) -> bool { - match (l, r) { - (AttrItemKind::Unparsed(l), AttrItemKind::Unparsed(r)) => eq_attr_args(l, r), - (AttrItemKind::Parsed(_l), AttrItemKind::Parsed(_r)) => todo!(), - _ => false, - } -} - fn eq_attr_args(l: &AttrArgs, r: &AttrArgs) -> bool { use AttrArgs::*; match (l, r) { @@ -1042,8 +1035,8 @@ pub fn is_cfg_test(item: &impl HasAttrs) -> bool { && item_list.iter().any(|item| item.has_name(sym::test)) { true - } else if attr.has_name(sym::cfg_trace) - && let AttrItemKind::Parsed(EarlyParsedAttribute::CfgTrace(cfg)) = &attr.get_normal_item().args + } else if let AttrKind::Synthetic(synthetic) = &attr.kind + && let SyntheticAttr::CfgTrace(cfg) = &**synthetic { requires_test_cfg(cfg) } else { diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs index 7b47141c9fb8a..412cdd41d0f2c 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -369,6 +369,7 @@ fn attr_search_pat(attr: &Attribute) -> (Pat, Pat) { (Pat::Str("#"), Pat::Str("]")) } }, + AttrKind::Synthetic(..) => unreachable!(), AttrKind::DocComment(_kind @ CommentKind::Line, ..) => { if attr.style == AttrStyle::Outer { (Pat::Str("///"), Pat::Str("")) diff --git a/tests/ui/stats/input-stats.stderr b/tests/ui/stats/input-stats.stderr index baabd678fefd0..79d1d633e9774 100644 --- a/tests/ui/stats/input-stats.stderr +++ b/tests/ui/stats/input-stats.stderr @@ -10,7 +10,7 @@ ast-stats - Impl 144 (NN.N%) 1 ast-stats - Trait 144 (NN.N%) 1 ast-stats - Fn 288 (NN.N%) 2 ast-stats - Use 576 (NN.N%) 4 -ast-stats PathSegment 864 (NN.N%) 36 24 +ast-stats PathSegment 840 (NN.N%) 35 24 ast-stats Ty 784 (NN.N%) 14 56 ast-stats - Ptr 56 (NN.N%) 1 ast-stats - Ref 56 (NN.N%) 1 @@ -43,7 +43,8 @@ ast-stats Param 160 (NN.N%) 4 40 ast-stats Block 144 (NN.N%) 6 24 ast-stats Attribute 128 (NN.N%) 4 32 ast-stats - DocComment 32 (NN.N%) 1 -ast-stats - Normal 96 (NN.N%) 3 +ast-stats - Synthetic 32 (NN.N%) 1 +ast-stats - Normal 64 (NN.N%) 2 ast-stats InlineAsm 120 (NN.N%) 1 120 ast-stats FnDecl 120 (NN.N%) 5 24 ast-stats Local 96 (NN.N%) 1 96 @@ -57,7 +58,7 @@ ast-stats GenericArgs 40 (NN.N%) 1 40 ast-stats - AngleBracketed 40 (NN.N%) 1 ast-stats Crate 40 (NN.N%) 1 40 ast-stats ---------------------------------------------------------------- -ast-stats Total 6_976 127 +ast-stats Total 6_952 126 ast-stats ================================================================ hir-stats ================================================================ hir-stats HIR STATS: input_stats