From 5d0ace21a2c286396270d0eebfd9696a1753c63c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sun, 12 Jul 2026 19:53:19 +1000 Subject: [PATCH 1/2] Remove unused `unwrap_normal_item` methods. --- compiler/rustc_ast/src/attr/mod.rs | 11 ++--------- compiler/rustc_hir/src/hir.rs | 7 ------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 2e54e1a7c320c..82a3706ec2b6b 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -66,21 +66,14 @@ 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. + /// 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, - AttrKind::DocComment(..) => panic!("unexpected doc comment"), - } - } } impl AttributeExt for Attribute { diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 6a6d55705eaa6..446d7aca0f5be 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() { From 8c97bb0ff6724a5fe2c7dffac4e6db213c83181b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 13 Jul 2026 08:55:56 +1000 Subject: [PATCH 2/2] Remove `NormalAttr` By inlining `AttrItem` into `NormalAttr` and then renaming the result `AttrItem` (because `AttrItem` is a better and more widely-used name than `NormalAttr`). This is a very mechanical change, except for the following. - In `expand_cfg_attr_item`, where the commit adds some comments explaining the token usage and adds an assertion, in order to clarify existing behaviour. - An expanded comment on `AttrItem`. - An expanded comment on `ParseNtResult`. --- compiler/rustc_ast/src/ast.rs | 30 ++++---- compiler/rustc_ast/src/attr/mod.rs | 68 +++++++------------ compiler/rustc_ast/src/visit.rs | 1 - compiler/rustc_ast_lowering/src/expr.rs | 2 +- compiler/rustc_ast_pretty/src/pprust/state.rs | 2 +- compiler/rustc_attr_parsing/src/interface.rs | 30 ++++---- compiler/rustc_builtin_macros/src/autodiff.rs | 16 ++--- .../src/deriving/generic/mod.rs | 1 + compiler/rustc_builtin_macros/src/offload.rs | 18 ++--- compiler/rustc_expand/src/build.rs | 2 +- compiler/rustc_expand/src/config.rs | 19 ++++-- compiler/rustc_lint/src/builtin.rs | 2 +- compiler/rustc_parse/src/parser/attr.rs | 2 +- .../rustc_parse/src/parser/diagnostics.rs | 8 +-- compiler/rustc_parse/src/parser/mod.rs | 2 + compiler/rustc_parse/src/parser/stmt.rs | 2 +- .../src/attrs/mixed_attributes_style.rs | 1 - .../clippy/clippy_lints/src/attrs/mod.rs | 2 +- .../src/attrs/should_panic_without_expect.rs | 4 +- .../clippy_lints/src/crate_in_macro_def.rs | 2 +- .../src/doc/include_in_doc_without_cfg.rs | 2 +- .../clippy_lints/src/large_include_file.rs | 2 +- .../clippy/clippy_utils/src/ast_utils/mod.rs | 2 +- src/tools/rustfmt/src/attr.rs | 2 +- src/tools/rustfmt/src/skip.rs | 2 +- src/tools/rustfmt/src/visitor.rs | 2 +- 26 files changed, 104 insertions(+), 122 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 3293da27d2912..970d134971c8f 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3416,7 +3416,7 @@ pub struct Attribute { #[derive(Clone, Encodable, Decodable, Debug, Walkable)] pub enum AttrKind { /// A normal attribute. - Normal(Box), + Normal(Box), /// A doc comment (e.g. `/// ...`, `//! ...`, `/** ... */`, `/*! ... */`). /// Doc attributes (e.g. `#[doc="..."]`) are represented with the `Normal` @@ -3425,32 +3425,26 @@ pub enum AttrKind { } #[derive(Clone, Encodable, Decodable, Debug, Walkable)] -pub struct NormalAttr { - pub item: AttrItem, - // Tokens for the full attribute, e.g. `#[foo]`, `#![bar]`. +pub struct AttrItem { + pub unsafety: Safety, + pub path: Path, + pub args: AttrItemKind, + // 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, } -impl NormalAttr { +impl AttrItem { pub fn from_ident(ident: Ident) -> Self { Self { - item: AttrItem { - unsafety: Safety::Default, - path: Path::from_ident(ident), - args: AttrItemKind::Unparsed(AttrArgs::Empty), - }, + unsafety: Safety::Default, + path: Path::from_ident(ident), + args: AttrItemKind::Unparsed(AttrArgs::Empty), tokens: None, } } } -#[derive(Clone, Encodable, Decodable, Debug, Walkable)] -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)] @@ -4382,6 +4376,7 @@ mod size_asserts { // tidy-alphabetical-start static_assert_size!(AssocItem, 72); static_assert_size!(AssocItemKind, 16); + static_assert_size!(AttrItem, 72); static_assert_size!(AttrKind, 16); static_assert_size!(Attribute, 32); static_assert_size!(Block, 24); @@ -4407,7 +4402,6 @@ mod size_asserts { static_assert_size!(MetaItem, 80); static_assert_size!(MetaItemKind, 40); static_assert_size!(MetaItemLit, 40); - static_assert_size!(NormalAttr, 72); static_assert_size!(Param, 40); static_assert_size!(Pat, 64); static_assert_size!(PatKind, 48); diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 82a3706ec2b6b..57aa592febe85 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -14,15 +14,13 @@ 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, + Expr, ExprKind, LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, Path, PathSegment, + Safety, }; use crate::token::{ self, CommentKind, Delimiter, DocFragmentKind, InvisibleOrigin, MetaVarKind, Token, }; -use crate::tokenstream::{ - DelimSpan, LazyAttrTokenStream, Spacing, TokenStream, TokenStreamIter, TokenTree, -}; +use crate::tokenstream::{DelimSpan, Spacing, TokenStream, TokenStreamIter, TokenTree}; use crate::util::comments; use crate::util::literal::escape_string_symbol; @@ -61,7 +59,7 @@ impl AttrIdGenerator { impl Attribute { pub fn get_normal_item(&self) -> &AttrItem { match &self.kind { - AttrKind::Normal(normal) => &normal.item, + AttrKind::Normal(normal) => normal, AttrKind::DocComment(..) => panic!("unexpected doc comment"), } } @@ -70,7 +68,7 @@ impl Attribute { /// 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::Normal(normal) => normal.args = new_args, AttrKind::DocComment(..) => panic!("unexpected doc comment"), } } @@ -83,7 +81,7 @@ 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.args.unparsed_ref()? { AttrArgs::Eq { expr, .. } => Some(expr.span), _ => None, }, @@ -105,7 +103,7 @@ impl AttributeExt for Attribute { fn name(&self) -> Option { match &self.kind { AttrKind::Normal(normal) => { - if let [ident] = &*normal.item.path.segments { + if let [ident] = &*normal.path.segments { Some(ident.ident.name) } else { None @@ -117,16 +115,14 @@ impl AttributeExt for Attribute { fn symbol_path(&self) -> Option> { match &self.kind { - AttrKind::Normal(p) => { - Some(p.item.path.segments.iter().map(|i| i.ident.name).collect()) - } + AttrKind::Normal(p) => Some(p.path.segments.iter().map(|i| i.ident.name).collect()), AttrKind::DocComment(_, _) => None, } } fn path_span(&self) -> Option { match &self.kind { - AttrKind::Normal(attr) => Some(attr.item.path.span), + AttrKind::Normal(attr) => Some(attr.path.span), AttrKind::DocComment(_, _) => None, } } @@ -134,9 +130,8 @@ impl AttributeExt for Attribute { fn path_matches(&self, name: &[Symbol]) -> bool { match &self.kind { AttrKind::Normal(normal) => { - normal.item.path.segments.len() == name.len() + normal.path.segments.len() == name.len() && normal - .item .path .segments .iter() @@ -153,7 +148,7 @@ impl AttributeExt for Attribute { fn is_word(&self) -> bool { if let AttrKind::Normal(normal) = &self.kind { - matches!(normal.item.args, AttrItemKind::Unparsed(AttrArgs::Empty)) + matches!(normal.args, AttrItemKind::Unparsed(AttrArgs::Empty)) } else { false } @@ -168,7 +163,7 @@ impl AttributeExt for Attribute { /// ``` fn meta_item_list(&self) -> Option> { match &self.kind { - AttrKind::Normal(normal) => normal.item.meta_item_list(), + AttrKind::Normal(normal) => normal.meta_item_list(), AttrKind::DocComment(..) => None, } } @@ -190,7 +185,7 @@ impl AttributeExt for Attribute { /// ``` fn value_str(&self) -> Option { match &self.kind { - AttrKind::Normal(normal) => normal.item.value_str(), + AttrKind::Normal(normal) => normal.value_str(), AttrKind::DocComment(..) => None, } } @@ -203,9 +198,9 @@ 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() + AttrKind::Normal(normal) if normal.path == sym::doc => { + if let Some(value) = normal.value_str() + && let Some(value_span) = normal.value_span() { Some((value, DocFragmentKind::Raw(value_span))) } else { @@ -223,7 +218,7 @@ impl AttributeExt for Attribute { fn doc_str(&self) -> Option { match &self.kind { AttrKind::DocComment(.., data) => Some(*data), - AttrKind::Normal(normal) if normal.item.path == sym::doc => normal.item.value_str(), + AttrKind::Normal(normal) if normal.path == sym::doc => normal.value_str(), _ => None, } } @@ -231,9 +226,7 @@ impl AttributeExt for Attribute { fn doc_resolution_scope(&self) -> Option { match &self.kind { AttrKind::DocComment(..) => Some(self.style), - AttrKind::Normal(normal) - if normal.item.path == sym::doc && normal.item.value_str().is_some() => - { + AttrKind::Normal(normal) if normal.path == sym::doc && normal.value_str().is_some() => { Some(self.style) } _ => None, @@ -280,14 +273,14 @@ impl Attribute { /// Extracts the MetaItem from inside this Attribute. pub fn meta(&self) -> Option { match &self.kind { - AttrKind::Normal(normal) => normal.item.meta(self.span), + AttrKind::Normal(normal) => normal.meta(self.span), AttrKind::DocComment(..) => None, } } pub fn meta_kind(&self) -> Option { match &self.kind { - AttrKind::Normal(normal) => normal.item.meta_kind(), + AttrKind::Normal(normal) => normal.meta_kind(), AttrKind::DocComment(..) => None, } } @@ -309,16 +302,14 @@ impl Attribute { pub fn deprecation_note(&self) -> Option { match &self.kind { - AttrKind::Normal(normal) if normal.item.path == sym::deprecated => { - let meta = &normal.item; - + AttrKind::Normal(normal) if normal.path == sym::deprecated => { // #[deprecated = "..."] - if let Some(s) = meta.value_str() { - return Some(Ident { name: s, span: meta.span() }); + if let Some(s) = normal.value_str() { + return Some(Ident { name: s, span: normal.span() }); } // #[deprecated(note = "...")] - if let Some(list) = meta.meta_item_list() { + if let Some(list) = normal.meta_item_list() { for nested in list { if let Some(mi) = nested.meta_item() && mi.path == sym::note @@ -740,8 +731,7 @@ fn mk_attr( ) -> Attribute { mk_attr_from_item( g, - AttrItem { unsafety, path, args: AttrItemKind::Unparsed(args) }, - None, + AttrItem { unsafety, path, args: AttrItemKind::Unparsed(args), tokens: None }, style, span, ) @@ -750,16 +740,10 @@ fn mk_attr( pub fn mk_attr_from_item( g: &AttrIdGenerator, item: AttrItem, - tokens: Option, style: AttrStyle, span: Span, ) -> Attribute { - Attribute { - kind: AttrKind::Normal(Box::new(NormalAttr { item, tokens })), - id: g.mk_attr_id(), - style, - span, - } + Attribute { kind: AttrKind::Normal(Box::new(item)), id: g.mk_attr_id(), style, span } } pub fn mk_attr_word( diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index e25c1a0b31937..e78380d2860eb 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -460,7 +460,6 @@ macro_rules! common_visitor_and_walkers { ModKind, ModSpans, MutTy, - NormalAttr, AttrItemKind, Parens, ParenthesizedArgs, diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 4ed23e032d234..3e7aacfb1d5fb 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -929,7 +929,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_attrs( inner_hir_id, &[Attribute { - kind: AttrKind::Normal(Box::new(NormalAttr::from_ident(Ident::new( + kind: AttrKind::Normal(Box::new(AttrItem::from_ident(Ident::new( sym::track_caller, span, )))), diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index bfca18a42635e..94d2d7823555c 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -685,7 +685,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere ast::AttrStyle::Inner => self.word("#!["), ast::AttrStyle::Outer => self.word("#["), } - self.print_attr_item(&normal.item, attr.span); + self.print_attr_item(normal, attr.span); self.word("]"); } ast::AttrKind::DocComment(comment_kind, data) => { diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index e8bef70be550a..889a86e44becc 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -161,12 +161,11 @@ impl<'sess> AttributeParser<'sess> { 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 parts = normal_attr.path.segments.iter().map(|seg| seg.ident.name).collect::>(); - let path = AttrPath::from_ast(&normal_attr.item.path, identity); + let path = AttrPath::from_ast(&normal_attr.path, identity); let args = ArgParser::from_attr_args( - &normal_attr.item.args.unparsed_ref().unwrap(), + &normal_attr.args.unparsed_ref().unwrap(), &parts, &sess.psess, emit_errors, @@ -175,10 +174,10 @@ impl<'sess> AttributeParser<'sess> { Self::parse_single_args( sess, attr.span, - normal_attr.item.span(), + normal_attr.span(), attr.style, path, - Some(normal_attr.item.unsafety), + Some(normal_attr.unsafety), expected_safety, ParsedDescription::Attribute, target_span, @@ -330,10 +329,10 @@ impl<'sess> AttributeParser<'sess> { })); } ast::AttrKind::Normal(n) => { - attr_paths.push(PathParser(&n.item.path)); - let attr_path = AttrPath::from_ast(&n.item.path, lower_span); + attr_paths.push(PathParser(&n.path)); + let attr_path = AttrPath::from_ast(&n.path, lower_span); - let args = match &n.item.args { + let args = match &n.args { AttrItemKind::Unparsed(args) => args, AttrItemKind::Parsed(parsed) => { early_parsed_state @@ -343,14 +342,14 @@ impl<'sess> AttributeParser<'sess> { }; let parts = - n.item.path.segments.iter().map(|seg| seg.ident.name).collect::>(); - let inner_span = lower_span(n.item.span()); + n.path.segments.iter().map(|seg| seg.ident.name).collect::>(); + let inner_span = lower_span(n.span()); if let Some(accept) = ATTRIBUTE_PARSERS.accepters.get(parts.as_slice()) { self.check_attribute_safety( &attr_path, inner_span, - n.item.unsafety, + n.unsafety, accept.safety, &mut emit_lint, ); @@ -414,7 +413,7 @@ impl<'sess> AttributeParser<'sess> { attr_style: attr.style, parsed_description: ParsedDescription::Attribute, template: &accept.template, - attr_safety: n.item.unsafety, + attr_safety: n.unsafety, attr_path: attr_path.clone(), #[cfg(debug_assertions)] has_target_been_checked: false, @@ -431,8 +430,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.args.unparsed_ref().unwrap(), lower_span), id: HashIgnoredAttrId { attr_id: attr.id }, style: attr.style, span: attr_span, @@ -441,7 +439,7 @@ impl<'sess> AttributeParser<'sess> { self.check_attribute_safety( &attr_path, inner_span, - n.item.unsafety, + n.unsafety, AttributeSafety::Normal, &mut emit_lint, ); diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index 1b9305a3d5851..c918bdc2dd1ca 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -27,7 +27,7 @@ mod llvm_enzyme { use crate::diagnostics; pub(crate) fn outer_normal_attr( - kind: &Box, + kind: &Box, id: rustc_ast::AttrId, span: Span, ) -> rustc_ast::Attribute { @@ -347,7 +347,7 @@ mod llvm_enzyme { eii_impls: ThinVec::new(), }); let mut rustc_ad_attr = - Box::new(ast::NormalAttr::from_ident(Ident::with_dummy_span(sym::rustc_autodiff))); + Box::new(ast::AttrItem::from_ident(Ident::with_dummy_span(sym::rustc_autodiff))); let ts2: Vec = vec![TokenTree::Token( Token::new(TokenKind::Ident(sym::never, false.into()), span), @@ -358,12 +358,12 @@ mod llvm_enzyme { delim: ast::token::Delimiter::Parenthesis, tokens: TokenStream::from_iter(ts2), }; - let inline_item = ast::AttrItem { + let inline_never_attr = Box::new(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)), - }; - let inline_never_attr = Box::new(ast::NormalAttr { item: inline_item, tokens: None }); + tokens: None, + }); let new_id = ecx.sess.psess.attr_id_generator.mk_attr_id(); let attr = outer_normal_attr(&rustc_ad_attr, new_id, span); let new_id = ecx.sess.psess.attr_id_generator.mk_attr_id(); @@ -373,8 +373,8 @@ mod llvm_enzyme { fn same_attribute(attr: &ast::AttrKind, item: &ast::AttrKind) -> bool { match (attr, item) { (ast::AttrKind::Normal(a), ast::AttrKind::Normal(b)) => { - let a = &a.item.path; - let b = &b.item.path; + let a = &a.path; + let b = &b.path; a.segments.iter().eq_by(&b.segments, |a, b| a.ident == b.ident) } _ => false, @@ -423,7 +423,7 @@ mod llvm_enzyme { } }; // Now update for d_fn - rustc_ad_attr.item.args = rustc_ast::ast::AttrItemKind::Unparsed( + rustc_ad_attr.args = rustc_ast::ast::AttrItemKind::Unparsed( rustc_ast::AttrArgs::Delimited(rustc_ast::DelimArgs { dspan: DelimSpan::dummy(), delim: rustc_ast::token::Delimiter::Parenthesis, diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index f9ec93a1115dd..54a9185955c4c 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -830,6 +830,7 @@ impl<'a> TraitDef<'a> { .collect(), }, )), + tokens: None, }, self.span, ), diff --git a/compiler/rustc_builtin_macros/src/offload.rs b/compiler/rustc_builtin_macros/src/offload.rs index 598c012309489..aa20b948f2c87 100644 --- a/compiler/rustc_builtin_macros/src/offload.rs +++ b/compiler/rustc_builtin_macros/src/offload.rs @@ -13,12 +13,12 @@ fn compile_for_device(ecx: &mut ExtCtxt<'_>) -> bool { } fn outer_normal_attr( - kind: &Box, + item: &Box, id: rustc_ast::AttrId, span: Span, ) -> rustc_ast::Attribute { let style = rustc_ast::AttrStyle::Outer; - let kind = rustc_ast::AttrKind::Normal(kind.clone()); + let kind = rustc_ast::AttrKind::Normal(item.clone()); rustc_ast::Attribute { kind, id, style, span } } @@ -107,7 +107,7 @@ pub(crate) fn expand_kernel( // rustc_offload_kernel attr let rustc_offload_kernel_attr = - Box::new(ast::NormalAttr::from_ident(Ident::with_dummy_span(sym::rustc_offload_kernel))); + Box::new(ast::AttrItem::from_ident(Ident::with_dummy_span(sym::rustc_offload_kernel))); let rustc_offload_kernel = outer_normal_attr( &rustc_offload_kernel_attr, ecx.sess.psess.attr_id_generator.mk_attr_id(), @@ -115,13 +115,13 @@ pub(crate) fn expand_kernel( ); // unsafe(no_mangle) attr - let unsafe_item = AttrItem { + let no_mangle_attr = Box::new(AttrItem { unsafety: ast::Safety::Unsafe(span), path: ast::Path::from_ident(Ident::new(sym::no_mangle, span)), args: ast::AttrItemKind::Unparsed(ast::AttrArgs::Empty), - }; + tokens: None, + }); - let no_mangle_attr = Box::new(ast::NormalAttr { item: unsafe_item, tokens: None }); let new_id = ecx.sess.psess.attr_id_generator.mk_attr_id(); let unsafe_no_mangle = outer_normal_attr(&no_mangle_attr, new_id, span); @@ -179,12 +179,12 @@ pub(crate) fn expand_kernel( tokens: TokenStream::from_iter(ts), }; - let inline_item = ast::AttrItem { + let inline_never_attr = Box::new(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)), - }; - let inline_never_attr = Box::new(ast::NormalAttr { item: inline_item, tokens: None }); + tokens: None, + }); let new_id = ecx.sess.psess.attr_id_generator.mk_attr_id(); let inline_never = outer_normal_attr(&inline_never_attr, new_id, span); diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 325cf413bd236..9c0f6a0207211 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -777,6 +777,6 @@ impl<'a> ExtCtxt<'a> { // Builds an attribute fully manually. pub fn attr_nested(&self, inner: AttrItem, span: Span) -> ast::Attribute { let g = &self.sess.psess.attr_id_generator; - attr::mk_attr_from_item(g, inner, None, ast::AttrStyle::Outer, span) + attr::mk_attr_from_item(g, inner, ast::AttrStyle::Outer, span) } } diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index b3582494f226e..bb36a82980f05 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -8,7 +8,7 @@ use rustc_ast::tokenstream::{ }; use rustc_ast::{ self as ast, AttrItemKind, AttrKind, AttrStyle, Attribute, EarlyParsedAttribute, HasAttrs, - HasTokens, MetaItem, MetaItemInner, NodeId, NormalAttr, + HasTokens, MetaItem, MetaItemInner, NodeId, }; use rustc_attr_parsing::parser::AllowExprMetavar; use rustc_attr_parsing::{ @@ -146,10 +146,9 @@ pub fn pre_configure_attrs(sess: &Session, attrs: &[Attribute]) -> ast::AttrVec 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; + normal.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())); + normal.tokens = Some(LazyAttrTokenStream::new_direct(AttrTokenStream::default())); } AttrKind::DocComment(..) => unreachable!(), } @@ -308,9 +307,13 @@ impl<'a> StripUnconfigured<'a> { fn expand_cfg_attr_item( &self, cfg_attr: &Attribute, - (attr_item, attr_item_span): (WithTokens, Span), + (mut attr_item, attr_item_span): (WithTokens, Span), ) -> Attribute { // Convert `#[cfg_attr(pred, attr)]` to `#[attr]`. + // + // Note that we read from `attr_item.tokens` (something like `foo`, from the `WithTokens`) + // and then write to `attr_item.node.tokens` (something like `#[foo]` or `#![foo]`, to + // the `AttrItem` itself). // Use the `#` from `#[cfg_attr(pred, attr)]` in the result `#[attr]`. let mut orig_trees = cfg_attr.token_trees().into_iter(); @@ -345,6 +348,7 @@ impl<'a> StripUnconfigured<'a> { delim_span, delim_spacing, Delimiter::Bracket, + // Read existing tokens from the `WithTokens`. attr_item .tokens .as_ref() @@ -352,11 +356,12 @@ impl<'a> StripUnconfigured<'a> { .to_attr_token_stream(), )); - let attr_tokens = Some(LazyAttrTokenStream::new_direct(AttrTokenStream::new(trees))); + // Write new tokens to the `AttrItem`. + assert!(attr_item.node.tokens.is_none()); + attr_item.node.tokens = Some(LazyAttrTokenStream::new_direct(AttrTokenStream::new(trees))); let attr = ast::attr::mk_attr_from_item( &self.sess.psess.attr_id_generator, attr_item.node, - attr_tokens, cfg_attr.style, attr_item_span, ); diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index ea0f8f22ab187..95f968d1e5096 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -754,7 +754,7 @@ fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: & while let Some(attr) = attrs.next() { let (is_doc_comment, is_doc_attribute) = match &attr.kind { AttrKind::DocComment(..) => (true, false), - AttrKind::Normal(normal) if normal.item.path == sym::doc => (true, true), + AttrKind::Normal(normal) if normal.path == sym::doc => (true, true), _ => (false, false), }; if is_doc_comment { diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index 4d92b8273d5c9..5aec3ba426da7 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -177,7 +177,6 @@ impl<'a> Parser<'a> { Ok(attr::mk_attr_from_item( &self.psess.attr_id_generator, attr_item.node, - None, style, attr_sp, )) @@ -354,6 +353,7 @@ impl<'a> Parser<'a> { unsafety, path, args: AttrItemKind::Unparsed(args), + tokens: None, }), Trailing::No, UsePreAttrPos::No, diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 254e7e410f579..43893b9411644 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -859,9 +859,9 @@ impl<'a> Parser<'a> { let mut snapshot = self.create_snapshot_for_diagnostic(); if let [attr] = &expr.attrs[..] && let ast::AttrKind::Normal(attr_kind) = &attr.kind - && let [segment] = &attr_kind.item.path.segments[..] + && let [segment] = &attr_kind.path.segments[..] && segment.ident.name == sym::cfg - && let Some(args_span) = attr_kind.item.args.span() + && let Some(args_span) = attr_kind.args.span() && let next_attr = match snapshot.parse_attribute(InnerAttrPolicy::Forbidden(None)) { Ok(next_attr) => next_attr, @@ -871,8 +871,8 @@ impl<'a> Parser<'a> { } } && let ast::AttrKind::Normal(next_attr_kind) = next_attr.kind - && let Some(next_attr_args_span) = next_attr_kind.item.args.span() - && let [next_segment] = &next_attr_kind.item.path.segments[..] + && let Some(next_attr_args_span) = next_attr_kind.args.span() + && let [next_segment] = &next_attr_kind.path.segments[..] && segment.ident.name == sym::cfg { let next_expr = match snapshot.parse_expr() { diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 8a8d1bd2c2e3f..fa72e660c0e87 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1836,6 +1836,8 @@ pub enum ParseNtResult { Literal(Box), Ty(WithTokens>), // These tokens are for the attr item, e.g. just the `foo` within `#[foo]` or `#![foo]`. + // (Compare this with `AttrItem::tokens`; `expand_cfg_attr_item` is where the two cases + // interact.) Meta(WithTokens>), Path(WithTokens>), Vis(WithTokens>), diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index a0412c4a7f3df..145e0ce72d003 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -499,7 +499,7 @@ impl<'a> Parser<'a> { let (attrs, block) = self.parse_inner_attrs_and_block(None)?; if let [.., last] = &*attrs { let suggest_to_outer = match &last.kind { - ast::AttrKind::Normal(attr) => attr.item.is_valid_for_outer_style(), + ast::AttrKind::Normal(attr) => attr.is_valid_for_outer_style(), _ => false, }; self.error_on_forbidden_inner_attr( 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..97bf23fb0dcba 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 @@ -19,7 +19,6 @@ impl From<&AttrKind> for SimpleAttrKind { match value { AttrKind::Normal(attr) => { let path_symbols = attr - .item .path .segments .iter() diff --git a/src/tools/clippy/clippy_lints/src/attrs/mod.rs b/src/tools/clippy/clippy_lints/src/attrs/mod.rs index 78701b3368226..c1c4ff0405bc9 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/mod.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/mod.rs @@ -616,7 +616,7 @@ 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 { .. })) + !matches!(normal_attr.args, AttrItemKind::Unparsed(AttrArgs::Eq { .. })) }, AttrKind::DocComment(..) => true, } 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..9e8327d521cfc 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 @@ -9,12 +9,12 @@ 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 AttrItemKind::Unparsed(AttrArgs::Eq { .. }) = &normal_attr.args { // `#[should_panic = ".."]` found, good return; } - if let AttrItemKind::Unparsed(AttrArgs::Delimited(args)) = &normal_attr.item.args + if let AttrItemKind::Unparsed(AttrArgs::Delimited(args)) = &normal_attr.args && let mut tt_iter = args.tokens.iter() && let Some(TokenTree::Token( Token { diff --git a/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs b/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs index 509b345048c1e..3c7d477daf0ba 100644 --- a/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs +++ b/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs @@ -73,7 +73,7 @@ impl EarlyLintPass for CrateInMacroDef { fn is_macro_export(attr: &Attribute) -> bool { if let AttrKind::Normal(normal) = &attr.kind - && let [segment] = normal.item.path.segments.as_slice() + && let [segment] = normal.path.segments.as_slice() { segment.ident.name == sym::macro_export } else { 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..eb8c7e4fce370 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 @@ -11,7 +11,7 @@ pub fn check(cx: &EarlyContext<'_>, attrs: &[Attribute]) { if !attr.span.from_expansion() && let AttrKind::Normal(ref item) = attr.kind && attr.doc_str().is_some() - && let AttrItemKind::Unparsed(AttrArgs::Eq { expr: meta, .. }) = &item.item.args + && let AttrItemKind::Unparsed(AttrArgs::Eq { expr: meta, .. }) = &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/large_include_file.rs b/src/tools/clippy/clippy_lints/src/large_include_file.rs index 39d252f4f3b6b..5e7fdc7975829 100644 --- a/src/tools/clippy/clippy_lints/src/large_include_file.rs +++ b/src/tools/clippy/clippy_lints/src/large_include_file.rs @@ -92,7 +92,7 @@ impl EarlyLintPass for LargeIncludeFile { && let AttrKind::Normal(ref item) = 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 AttrItemKind::Unparsed(AttrArgs::Eq { expr: meta, .. }) = &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 c89130fb647a4..eae886e2d6b86 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -1013,7 +1013,7 @@ 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.path, &r.path) && eq_attr_item_kind(&l.args, &r.args) }, _ => false, } diff --git a/src/tools/rustfmt/src/attr.rs b/src/tools/rustfmt/src/attr.rs index ac9ce2e87963e..c28fe58a76cd6 100644 --- a/src/tools/rustfmt/src/attr.rs +++ b/src/tools/rustfmt/src/attr.rs @@ -368,7 +368,7 @@ impl Rewrite for ast::Attribute { Ok(meta.rewrite_result(context, shape).map_or_else( |_| snippet.to_owned(), |rw| match &self.kind { - ast::AttrKind::Normal(normal_attr) => match normal_attr.item.unsafety { + ast::AttrKind::Normal(normal_attr) => match normal_attr.unsafety { // For #![feature(unsafe_attributes)] // See https://github.com/rust-lang/rust/issues/123757 ast::Safety::Unsafe(_) => format!("{}[unsafe({})]", prefix, rw), diff --git a/src/tools/rustfmt/src/skip.rs b/src/tools/rustfmt/src/skip.rs index cd3860d3d7f0a..4b69519e0513a 100644 --- a/src/tools/rustfmt/src/skip.rs +++ b/src/tools/rustfmt/src/skip.rs @@ -110,7 +110,7 @@ fn get_skip_names(kind: &str, attrs: &[ast::Attribute]) -> Vec { // rustc_ast::ast::Path is implemented partialEq // but it is designed for segments.len() == 1 if let ast::AttrKind::Normal(normal) = &attr.kind { - if pprust::path_to_string(&normal.item.path) != path { + if pprust::path_to_string(&normal.path) != path { continue; } } diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs index 560d62e9d57d7..2673b7810f3f6 100644 --- a/src/tools/rustfmt/src/visitor.rs +++ b/src/tools/rustfmt/src/visitor.rs @@ -874,7 +874,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { } else { match &attr.kind { ast::AttrKind::Normal(ref normal) - if self.is_unknown_rustfmt_attr(&normal.item.path.segments) => + if self.is_unknown_rustfmt_attr(&normal.path.segments) => { let file_name = self.psess.span_to_filename(attr.span); self.report.append(