diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 556f50a85af7d..55b79b63c9ee2 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1164,6 +1164,22 @@ impl AttrPath { span: path.span, } } + + /// For a single-segment attribute (i.e., `#[attr]` and not `#[path::atrr]`), + /// return the name of the attribute; otherwise, returns `None`. + pub fn name(&self) -> Option { + self.ident().map(|ident| ident.name) + } + + /// For a single-segment attribute, returns its ident; otherwise, returns `None`. + pub fn ident(&self) -> Option { + if let [ident] = self.segments.as_ref() { Some(*ident) } else { None } + } + + #[inline] + pub fn has_name(&self, name: Symbol) -> bool { + self.name() == Some(name) + } } impl fmt::Display for AttrPath { @@ -1206,27 +1222,48 @@ pub enum Attribute { Unparsed(Box), } +pub fn find_attr_items_by_name( + attrs: &[Attribute], + name: Symbol, +) -> impl Iterator { + attrs.iter().filter_map(move |attr| match attr { + Attribute::Unparsed(attr_item) if attr_item.has_name(name) => Some(&**attr_item), + _ => None, + }) +} + impl Attribute { - pub fn get_normal_item(&self) -> &AttrItem { + pub fn attr_item(self) -> Option { + match self { + Attribute::Parsed(_) => None, + Attribute::Unparsed(attr_item) => Some(*attr_item), + } + } + pub fn attr_item_ref(&self) -> Option<&AttrItem> { + match self { + Attribute::Parsed(_) => None, + Attribute::Unparsed(attr_item) => Some(attr_item), + } + } + + pub fn unwrap_attr_item_ref(&self) -> &AttrItem { match &self { Attribute::Unparsed(normal) => &normal, _ => panic!("unexpected parsed attribute"), } } - pub fn unwrap_normal_item(self) -> AttrItem { + pub fn unwrap_attr_item(self) -> AttrItem { match self { Attribute::Unparsed(normal) => *normal, _ => panic!("unexpected parsed attribute"), } } - +} +impl AttrItem { pub fn value_lit(&self) -> Option<&MetaItemLit> { match &self { - Attribute::Unparsed(n) => match n.as_ref() { - AttrItem { args: AttrArgs::Eq { eq_span: _, expr }, .. } => Some(expr), - _ => None, - }, + AttrItem { args: AttrArgs::Eq { eq_span: _, expr }, .. } => Some(expr), _ => None, } } @@ -1256,12 +1293,18 @@ impl AttributeExt for Attribute { #[inline] fn value_str(&self) -> Option { - self.value_lit().and_then(|x| x.value_str()) + match self { + Attribute::Parsed(_) => None, + Attribute::Unparsed(attr_item) => attr_item.value_lit().and_then(|x| x.value_str()), + } } #[inline] fn value_span(&self) -> Option { - self.value_lit().map(|i| i.span) + match self { + Attribute::Parsed(_) => None, + Attribute::Unparsed(attr_item) => attr_item.value_lit().map(|i| i.span), + } } /// For a single-segment attribute, returns its name; otherwise, returns `None`. @@ -1355,6 +1398,239 @@ impl AttributeExt for Attribute { } } +impl AttributeExt for AttrItem { + #[inline] + fn id(&self) -> AttrId { + self.id.attr_id + } + + #[inline] + fn meta_item_list(&self) -> Option> { + match &self { + AttrItem { args: AttrArgs::Delimited(d), .. } => { + ast::MetaItemKind::list_from_tokens(d.tokens.clone()) + } + _ => None, + } + } + + #[inline] + fn value_str(&self) -> Option { + self.value_lit().and_then(|x| x.value_str()) + } + + #[inline] + fn value_span(&self) -> Option { + self.value_lit().map(|i| i.span) + } + + /// For a single-segment attribute, returns its name; otherwise, returns `None`. + #[inline] + fn ident(&self) -> Option { + self.path.ident() + } + + #[inline] + fn path_matches(&self, name: &[Symbol]) -> bool { + self.path.segments.len() == name.len() + && self.path.segments.iter().zip(name).all(|(s, n)| s.name == *n) + } + + #[inline] + fn is_doc_comment(&self) -> bool { + false + } + + #[inline] + fn span(&self) -> Span { + self.span + } + + #[inline] + fn is_word(&self) -> bool { + matches!(self.args, AttrArgs::Empty) + } + + #[inline] + fn ident_path(&self) -> Option> { + Some(self.path.segments.iter().copied().collect()) + } + + #[inline] + fn doc_str(&self) -> Option { + if self.has_name(sym::doc) { self.value_str() } else { None } + } + #[inline] + fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> { + if self.has_name(sym::doc) { + self.value_str().map(|s| (s, CommentKind::Line)) + } else { + None + } + } + + #[inline] + fn style(&self) -> AttrStyle { + self.style + } +} + +// FIXME(fn_delegation): use function delegation instead of manually forwarding +impl AttributeExt for &'_ AttrItem { + #[inline] + fn id(&self) -> AttrId { + ::id(self) + } + + #[inline] + fn meta_item_list(&self) -> Option> { + ::meta_item_list(self) + } + + #[inline] + fn value_str(&self) -> Option { + ::value_str(self) + } + + #[inline] + fn value_span(&self) -> Option { + ::value_span(self) + } + + #[inline] + fn ident(&self) -> Option { + ::ident(self) + } + + #[inline] + fn path_matches(&self, name: &[Symbol]) -> bool { + ::path_matches(self, name) + } + + #[inline] + fn is_doc_comment(&self) -> bool { + ::is_doc_comment(self) + } + + #[inline] + fn span(&self) -> Span { + ::span(self) + } + + #[inline] + fn is_word(&self) -> bool { + ::is_word(self) + } + + #[inline] + fn ident_path(&self) -> Option> { + ::ident_path(self) + } + + #[inline] + fn doc_str(&self) -> Option { + ::doc_str(self) + } + + #[inline] + fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> { + ::doc_str_and_comment_kind(self) + } + + #[inline] + fn style(&self) -> AttrStyle { + ::style(self) + } +} + +// FIXME(fn_delegation): use function delegation instead of manually forwarding +impl AttrItem { + #[inline] + pub fn id(&self) -> AttrId { + ::id(self) + } + + #[inline] + pub fn path(&self) -> SmallVec<[Symbol; 1]> { + ::path(self) + } + + #[inline] + pub fn name(&self) -> Option { + ::name(self) + } + + #[inline] + pub fn has_name(&self, name: Symbol) -> bool { + ::has_name(self, name) + } + + #[inline] + pub fn has_any_name(&self, names: &[Symbol]) -> bool { + ::has_any_name(self, names) + } + + #[inline] + pub fn meta_item_list(&self) -> Option> { + ::meta_item_list(self) + } + + #[inline] + pub fn value_str(&self) -> Option { + ::value_str(self) + } + + #[inline] + pub fn value_span(&self) -> Option { + ::value_span(self) + } + + #[inline] + pub fn ident(&self) -> Option { + ::ident(self) + } + + #[inline] + pub fn path_matches(&self, name: &[Symbol]) -> bool { + ::path_matches(self, name) + } + + #[inline] + pub fn is_doc_comment(&self) -> bool { + ::is_doc_comment(self) + } + + #[inline] + pub fn span(&self) -> Span { + ::span(self) + } + + #[inline] + pub fn is_word(&self) -> bool { + ::is_word(self) + } + + #[inline] + pub fn ident_path(&self) -> Option> { + ::ident_path(self) + } + + #[inline] + pub fn doc_str(&self) -> Option { + ::doc_str(self) + } + + #[inline] + pub fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> { + ::doc_str_and_comment_kind(self) + } + + #[inline] + pub fn style(&self) -> AttrStyle { + ::style(self) + } +} + // FIXME(fn_delegation): use function delegation instead of manually forwarding impl Attribute { #[inline] diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index fc507285860ed..0c7c28d14c9a9 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -101,32 +101,36 @@ impl<'a> State<'a> { } for attr in attrs { - self.print_attribute_inline(attr, style); + match &attr { + hir::Attribute::Unparsed(attr) => self.print_attr_item_inline(&**attr, style), + hir::Attribute::Parsed(attr) => self.print_parsed_attribute_inline(attr, style), + } } self.hardbreak_if_not_bol(); } - fn print_attribute_inline(&mut self, attr: &hir::Attribute, style: AttrStyle) { - match &attr { - hir::Attribute::Unparsed(unparsed) => { - self.maybe_print_comment(unparsed.span.lo()); - match style { - ast::AttrStyle::Inner => self.word("#!["), - ast::AttrStyle::Outer => self.word("#["), - } - self.print_attr_item(&unparsed, unparsed.span); - self.word("]"); - self.hardbreak() - } - hir::Attribute::Parsed(AttributeKind::DocComment { style, kind, comment, .. }) => { + fn print_attr_item_inline(&mut self, unparsed: &hir::AttrItem, style: AttrStyle) { + self.maybe_print_comment(unparsed.span.lo()); + match style { + ast::AttrStyle::Inner => self.word("#!["), + ast::AttrStyle::Outer => self.word("#["), + } + self.print_attr_item(&unparsed, unparsed.span); + self.word("]"); + self.hardbreak() + } + + fn print_parsed_attribute_inline(&mut self, attr: &AttributeKind, _style: AttrStyle) { + match attr { + AttributeKind::DocComment { style, kind, comment, .. } => { self.word(rustc_ast_pretty::pprust::state::doc_comment_to_string( *kind, *style, *comment, )); self.hardbreak() } - hir::Attribute::Parsed(pa) => { + _ => { self.word("#[attr = "); - pa.print_attribute(self); + attr.print_attribute(self); self.word("]"); self.hardbreak() } @@ -298,8 +302,18 @@ where printer.s.eof() } +pub fn parsed_attribute_to_string(ann: &dyn PpAnn, attr: &AttributeKind) -> String { + to_string(ann, |s| s.print_parsed_attribute_inline(attr, AttrStyle::Outer)) +} +pub fn attr_item_to_string(ann: &dyn PpAnn, attr: &hir::AttrItem) -> String { + to_string(ann, |s| s.print_attr_item_inline(attr, AttrStyle::Outer)) +} + pub fn attribute_to_string(ann: &dyn PpAnn, attr: &hir::Attribute) -> String { - to_string(ann, |s| s.print_attribute_inline(attr, AttrStyle::Outer)) + match attr { + hir::Attribute::Parsed(attr) => parsed_attribute_to_string(ann, attr), + hir::Attribute::Unparsed(attr) => attr_item_to_string(ann, attr), + } } pub fn ty_to_string(ann: &dyn PpAnn, ty: &hir::Ty<'_>) -> String { diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs index 0e04a2a784ec8..9f432b67320e2 100644 --- a/compiler/rustc_incremental/src/assert_dep_graph.rs +++ b/compiler/rustc_incremental/src/assert_dep_graph.rs @@ -107,7 +107,7 @@ struct IfThisChanged<'tcx> { impl<'tcx> IfThisChanged<'tcx> { fn argument(&self, attr: &hir::Attribute) -> Option { let mut value = None; - for list_item in attr.meta_item_list().unwrap_or_default() { + for list_item in attr.attr_item_ref().and_then(|a| a.meta_item_list()).unwrap_or_default() { match list_item.ident() { Some(ident) if list_item.is_word() && value.is_none() => value = Some(ident.name), _ => @@ -125,47 +125,57 @@ impl<'tcx> IfThisChanged<'tcx> { let hir_id = self.tcx.local_def_id_to_hir_id(def_id); let attrs = self.tcx.hir_attrs(hir_id); for attr in attrs { - if attr.has_name(sym::rustc_if_this_changed) { - let dep_node_interned = self.argument(attr); - let dep_node = match dep_node_interned { - None => DepNode::from_def_path_hash( - self.tcx, - def_path_hash, - dep_kinds::opt_hir_owner_nodes, - ), - Some(n) => { - match DepNode::from_label_string(self.tcx, n.as_str(), def_path_hash) { - Ok(n) => n, - Err(()) => self.tcx.dcx().emit_fatal(errors::UnrecognizedDepNode { - span: attr.span(), - name: n, - }), + match attr { + hir::Attribute::Unparsed(attr_item) + if attr_item.has_name(sym::rustc_if_this_changed) => + { + let dep_node_interned = self.argument(attr); + let dep_node = match dep_node_interned { + None => DepNode::from_def_path_hash( + self.tcx, + def_path_hash, + dep_kinds::opt_hir_owner_nodes, + ), + Some(n) => { + match DepNode::from_label_string(self.tcx, n.as_str(), def_path_hash) { + Ok(n) => n, + Err(()) => self.tcx.dcx().emit_fatal(errors::UnrecognizedDepNode { + span: attr_item.span(), + name: n, + }), + } } - } - }; - self.if_this_changed.push((attr.span(), def_id.to_def_id(), dep_node)); - } else if attr.has_name(sym::rustc_then_this_would_need) { - let dep_node_interned = self.argument(attr); - let dep_node = match dep_node_interned { - Some(n) => { - match DepNode::from_label_string(self.tcx, n.as_str(), def_path_hash) { - Ok(n) => n, - Err(()) => self.tcx.dcx().emit_fatal(errors::UnrecognizedDepNode { - span: attr.span(), - name: n, - }), + }; + self.if_this_changed.push((attr_item.span(), def_id.to_def_id(), dep_node)); + } + hir::Attribute::Unparsed(attr_item) + if attr_item.has_name(sym::rustc_then_this_would_need) => + { + let dep_node_interned = self.argument(attr); + let dep_node = match dep_node_interned { + Some(n) => { + match DepNode::from_label_string(self.tcx, n.as_str(), def_path_hash) { + Ok(n) => n, + Err(()) => self.tcx.dcx().emit_fatal(errors::UnrecognizedDepNode { + span: attr_item.span(), + name: n, + }), + } } - } - None => { - self.tcx.dcx().emit_fatal(errors::MissingDepNode { span: attr.span() }); - } - }; - self.then_this_would_need.push(( - attr.span(), - dep_node_interned.unwrap(), - hir_id, - dep_node, - )); + None => { + self.tcx + .dcx() + .emit_fatal(errors::MissingDepNode { span: attr_item.span() }); + } + }; + self.then_this_would_need.push(( + attr_item.span(), + dep_node_interned.unwrap(), + hir_id, + dep_node, + )); + } + _ => {} } } } diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs index 64166255fa485..c95fb81c638bf 100644 --- a/compiler/rustc_incremental/src/persist/dirty_clean.rs +++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs @@ -19,12 +19,14 @@ //! Errors are reported if we are in the suitable configuration but //! the required condition is not met. +use rustc_ast::attr::AttributeExt; use rustc_ast::{self as ast, MetaItemInner}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::unord::UnordSet; use rustc_hir::def_id::LocalDefId; use rustc_hir::{ - Attribute, ImplItemKind, ItemKind as HirItem, Node as HirNode, TraitItemKind, intravisit, + AttrItem, Attribute, ImplItemKind, ItemKind as HirItem, Node as HirNode, TraitItemKind, + intravisit, }; use rustc_middle::dep_graph::{DepNode, DepNodeExt, label_strs}; use rustc_middle::hir::nested_filter; @@ -182,7 +184,7 @@ struct DirtyCleanVisitor<'tcx> { impl<'tcx> DirtyCleanVisitor<'tcx> { /// Possibly "deserialize" the attribute into a clean/dirty assertion - fn assertion_maybe(&mut self, item_id: LocalDefId, attr: &Attribute) -> Option { + fn assertion_maybe(&mut self, item_id: LocalDefId, attr: &AttrItem) -> Option { assert!(attr.has_name(sym::rustc_clean)); if !check_config(self.tcx, attr) { // skip: not the correct `cfg=` @@ -193,7 +195,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { } /// Gets the "auto" assertion on pre-validated attr, along with the `except` labels. - fn assertion_auto(&mut self, item_id: LocalDefId, attr: &Attribute) -> Assertion { + fn assertion_auto(&mut self, item_id: LocalDefId, attr: &AttrItem) -> Assertion { let (name, mut auto) = self.auto_labels(item_id, attr); let except = self.except(attr); let loaded_from_disk = self.loaded_from_disk(attr); @@ -206,7 +208,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { } /// `loaded_from_disk=` attribute value - fn loaded_from_disk(&self, attr: &Attribute) -> Labels { + fn loaded_from_disk(&self, attr: &AttrItem) -> Labels { for item in attr.meta_item_list().unwrap_or_else(ThinVec::new) { if item.has_name(LOADED_FROM_DISK) { let value = expect_associated_value(self.tcx, &item); @@ -218,7 +220,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { } /// `except=` attribute value - fn except(&self, attr: &Attribute) -> Labels { + fn except(&self, attr: &AttrItem) -> Labels { for item in attr.meta_item_list().unwrap_or_else(ThinVec::new) { if item.has_name(EXCEPT) { let value = expect_associated_value(self.tcx, &item); @@ -231,7 +233,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { /// Return all DepNode labels that should be asserted for this item. /// index=0 is the "name" used for error messages - fn auto_labels(&mut self, item_id: LocalDefId, attr: &Attribute) -> (&'static str, Labels) { + fn auto_labels(&mut self, item_id: LocalDefId, attr: &AttrItem) -> (&'static str, Labels) { let node = self.tcx.hir_node_by_def_id(item_id); let (name, labels) = match node { HirNode::Item(item) => { @@ -394,7 +396,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { /// Given a `#[rustc_clean]` attribute, scan for a `cfg="foo"` attribute and check whether we have /// a cfg flag called `foo`. -fn check_config(tcx: TyCtxt<'_>, attr: &Attribute) -> bool { +fn check_config(tcx: TyCtxt<'_>, attr: &AttrItem) -> bool { debug!("check_config(attr={:?})", attr); let config = &tcx.sess.psess.config; debug!("check_config: config={:?}", config); @@ -430,11 +432,11 @@ fn expect_associated_value(tcx: TyCtxt<'_>, item: &MetaItemInner) -> Symbol { /// nodes. struct FindAllAttrs<'tcx> { tcx: TyCtxt<'tcx>, - found_attrs: Vec<&'tcx Attribute>, + found_attrs: Vec<&'tcx AttrItem>, } impl<'tcx> FindAllAttrs<'tcx> { - fn is_active_attr(&mut self, attr: &Attribute) -> bool { + fn is_active_attr(&mut self, attr: &AttrItem) -> bool { if attr.has_name(sym::rustc_clean) && check_config(self.tcx, attr) { return true; } @@ -460,8 +462,9 @@ impl<'tcx> intravisit::Visitor<'tcx> for FindAllAttrs<'tcx> { } fn visit_attribute(&mut self, attr: &'tcx Attribute) { - if self.is_active_attr(attr) { - self.found_attrs.push(attr); + match attr { + Attribute::Unparsed(attr) if self.is_active_attr(attr) => self.found_attrs.push(attr), + _ => {} } } } diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 68adfb3cdb388..50423373bf296 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -291,9 +291,9 @@ impl<'tcx> InstanceKind<'tcx> { pub fn get_attrs( &self, tcx: TyCtxt<'tcx>, - attr: Symbol, - ) -> impl Iterator { - tcx.get_attrs(self.def_id(), attr) + name: Symbol, + ) -> impl Iterator { + tcx.get_attrs(self.def_id(), name) } /// Returns `true` if the LLVM version of this instance is unconditionally diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 0402d09882254..e7ec41498d8f5 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1795,9 +1795,14 @@ impl<'tcx> TyCtxt<'tcx> { pub fn get_attrs( self, did: impl Into, - attr: Symbol, - ) -> impl Iterator { - self.get_all_attrs(did).filter(move |a: &&hir::Attribute| a.has_name(attr)) + name: Symbol, + ) -> impl Iterator { + self.get_all_attrs(did).filter_map(move |a| match a { + hir::Attribute::Unparsed(attr_item) if attr_item.path.has_name(name) => { + Some(&**attr_item) + } + _ => None, + }) } /// Gets all attributes. @@ -1827,7 +1832,7 @@ impl<'tcx> TyCtxt<'tcx> { self, did: impl Into, attr: Symbol, - ) -> Option<&'tcx hir::Attribute> { + ) -> Option<&'tcx hir::AttrItem> { let did: DefId = did.into(); if did.as_local().is_some() { // it's a crate local item, we need to check feature flags @@ -1840,9 +1845,12 @@ impl<'tcx> TyCtxt<'tcx> { // we filter out unstable diagnostic attributes before // encoding attributes debug_assert!(rustc_feature::encode_cross_crate(attr)); - self.attrs_for_def(did) - .iter() - .find(|a| matches!(a.path().as_ref(), [sym::diagnostic, a] if *a == attr)) + self.attrs_for_def(did).iter().find_map(|a| match a { + hir::Attribute::Unparsed(ai) if matches!(ai.path().as_ref(), [sym::diagnostic, a] if *a == attr) => { + Some(&**ai) + } + _ => None + }) } } @@ -1850,16 +1858,23 @@ impl<'tcx> TyCtxt<'tcx> { self, did: DefId, attr: &[Symbol], - ) -> impl Iterator { - let filter_fn = move |a: &&hir::Attribute| a.path_matches(attr); + ) -> impl Iterator { + let filter_fn = move |a: &'tcx hir::Attribute| -> Option<&'tcx hir::AttrItem> { + match a { + hir::Attribute::Unparsed(attr_item) if attr_item.path_matches(attr) => { + Some(&**attr_item) + } + _ => None, + } + }; if let Some(did) = did.as_local() { - self.hir_attrs(self.local_def_id_to_hir_id(did)).iter().filter(filter_fn) + self.hir_attrs(self.local_def_id_to_hir_id(did)).iter().filter_map(filter_fn) } else { - self.attrs_for_def(did).iter().filter(filter_fn) + self.attrs_for_def(did).iter().filter_map(filter_fn) } } - pub fn get_attr(self, did: impl Into, attr: Symbol) -> Option<&'tcx hir::Attribute> { + pub fn get_attr(self, did: impl Into, attr: Symbol) -> Option<&'tcx hir::AttrItem> { if cfg!(debug_assertions) && !rustc_feature::is_valid_for_get_attr(attr) { let did: DefId = did.into(); bug!("get_attr: unexpected called with DefId `{:?}`, attr `{:?}`", did, attr); diff --git a/compiler/rustc_passes/src/abi_test.rs b/compiler/rustc_passes/src/abi_test.rs index b139ed6a66c38..5b7d158bfbcb7 100644 --- a/compiler/rustc_passes/src/abi_test.rs +++ b/compiler/rustc_passes/src/abi_test.rs @@ -1,4 +1,4 @@ -use rustc_hir::Attribute; +use rustc_hir::AttrItem; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_middle::span_bug; @@ -49,7 +49,7 @@ fn unwrap_fn_abi<'tcx>( } } -fn dump_abi_of_fn_item(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) { +fn dump_abi_of_fn_item(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &AttrItem) { let typing_env = ty::TypingEnv::post_analysis(tcx, item_def_id); let args = GenericArgs::identity_for_item(tcx, item_def_id); let instance = match Instance::try_resolve(tcx, typing_env, item_def_id.into(), args) { @@ -109,7 +109,7 @@ fn test_abi_eq<'tcx>(abi1: &'tcx FnAbi<'tcx, Ty<'tcx>>, abi2: &'tcx FnAbi<'tcx, && abi1.args.iter().zip(abi2.args.iter()).all(|(arg1, arg2)| arg1.eq_abi(arg2)) } -fn dump_abi_of_fn_type(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) { +fn dump_abi_of_fn_type(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &AttrItem) { let typing_env = ty::TypingEnv::post_analysis(tcx, item_def_id); let ty = tcx.type_of(item_def_id).instantiate_identity(); let span = tcx.def_span(item_def_id); diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index dddbf65db72ea..c27b707496572 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -18,8 +18,8 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalModDefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{ - self as hir, self, AssocItemKind, Attribute, CRATE_HIR_ID, CRATE_OWNER_ID, FnSig, ForeignItem, - HirId, Item, ItemKind, MethodKind, Safety, Target, TraitItem, + self as hir, self, AssocItemKind, AttrItem, Attribute, CRATE_HIR_ID, CRATE_OWNER_ID, FnSig, + ForeignItem, HirId, Item, ItemKind, MethodKind, Safety, Target, TraitItem, }; use rustc_macros::LintDiagnostic; use rustc_middle::hir::nested_filter; @@ -107,7 +107,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { fn check_attributes( &self, hir_id: HirId, - span: Span, + item_span: Span, target: Target, item: Option>, ) { @@ -128,15 +128,46 @@ impl<'tcx> CheckAttrVisitor<'tcx> { .check_allow_internal_unstable( hir_id, syms.first().unwrap().1, - span, + item_span, target, attrs, ), - Attribute::Parsed(AttributeKind::AllowConstFnUnstable { .. }) => { - self.check_rustc_allow_const_fn_unstable(hir_id, attr, span, target) + Attribute::Parsed(AttributeKind::AllowConstFnUnstable(_)) => { + // FIXME: this is incorrect + let attr_span = item_span; + match target { + Target::Fn | Target::Method(_) + if self.tcx.is_const_fn(hir_id.expect_owner().to_def_id()) => {} + // FIXME(#80564): We permit struct fields and match arms to have an + // `#[allow_internal_unstable]` attribute with just a lint, because we previously + // erroneously allowed it and some crates used it accidentally, to be compatible + // with crates depending on them, we can't throw an error here. + Target::Field | Target::Arm | Target::MacroDef => self + .inline_attr_str_error_with_macro_def( + hir_id, + attr_span, + "allow_internal_unstable", + ), + _ => { + self.tcx.dcx().emit_err(errors::RustcAllowConstFnUnstable { + attr_span, + span: item_span, + }); + } + } } - Attribute::Parsed(AttributeKind::Deprecation { .. }) => { - self.check_deprecated(hir_id, attr, span, target) + Attribute::Parsed(AttributeKind::Deprecation { span, deprecation: _ }) => { + match target { + Target::Closure | Target::Expression | Target::Statement | Target::Arm => { + self.tcx.emit_node_span_lint( + UNUSED_ATTRIBUTES, + hir_id, + *span, + errors::Deprecated, + ); + } + _ => {} + } } Attribute::Parsed(AttributeKind::DocComment { .. }) => { /* `#[doc]` is actually a lot more than just doc comments, so is checked below*/ } @@ -148,9 +179,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::MacroTransparency(_), ) => { /* do nothing */ } Attribute::Parsed(AttributeKind::AsPtr(attr_span)) => { - self.check_applied_to_fn_or_method(hir_id, *attr_span, span, target) + self.check_applied_to_fn_or_method(hir_id, *attr_span, item_span, target) } - Attribute::Unparsed(_) => { + Attribute::Unparsed(attr) => { + let attr: &AttrItem = attr; + let span = item_span; match attr.path().as_slice() { [sym::diagnostic, sym::do_not_recommend, ..] => { self.check_do_not_recommend(attr.span(), hir_id, target, attr, item) @@ -329,49 +362,50 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } [] => unreachable!(), } - } - } - let builtin = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)); + let builtin = + attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)); - if hir_id != CRATE_HIR_ID { - if let Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) = - attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)) - { - match attr.style() { - ast::AttrStyle::Outer => self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr.span(), - errors::OuterCrateLevelAttr, - ), - ast::AttrStyle::Inner => self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr.span(), - errors::InnerCrateLevelAttr, - ), + if hir_id != CRATE_HIR_ID { + if let Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) = + attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)) + { + match attr.style() { + ast::AttrStyle::Outer => self.tcx.emit_node_span_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span(), + errors::OuterCrateLevelAttr, + ), + ast::AttrStyle::Inner => self.tcx.emit_node_span_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span(), + errors::InnerCrateLevelAttr, + ), + } + } } - } - } - if let Some(BuiltinAttribute { duplicates, .. }) = builtin { - check_duplicates(self.tcx, attr, hir_id, *duplicates, &mut seen); + if let Some(BuiltinAttribute { duplicates, .. }) = builtin { + check_duplicates(self.tcx, attr, hir_id, *duplicates, &mut seen); + } + } } self.check_unused_attribute(hir_id, attr) } - self.check_repr(attrs, span, target, item, hir_id); - self.check_used(attrs, target, span); - self.check_rustc_force_inline(hir_id, attrs, span, target); + self.check_repr(attrs, item_span, target, item, hir_id); + self.check_used(attrs, target, item_span); + self.check_rustc_force_inline(hir_id, attrs, item_span, target); } - fn inline_attr_str_error_with_macro_def(&self, hir_id: HirId, attr: &Attribute, sym: &str) { + fn inline_attr_str_error_with_macro_def(&self, hir_id: HirId, attr_span: Span, sym: &str) { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr_span, errors::IgnoredAttrWithMacro { sym }, ); } @@ -391,7 +425,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { attr_span: Span, hir_id: HirId, target: Target, - attr: &Attribute, + attr: &AttrItem, item: Option>, ) { if !matches!(target, Target::Impl) @@ -431,7 +465,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if an `#[inline]` is applied to a function or a closure. - fn check_inline(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) { + fn check_inline(&self, hir_id: HirId, attr: &AttrItem, span: Span, target: Target) { match target { Target::Fn | Target::Closure @@ -456,7 +490,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ), // FIXME(#80564): Same for fields, arms, and macro defs Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr, "inline") + self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "inline") } _ => { self.dcx().emit_err(errors::InlineNotFnOrClosure { @@ -486,7 +520,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { /// Checks that `#[coverage(..)]` is applied to a function/closure/method, /// or to an impl block or module. - fn check_coverage(&self, attr: &Attribute, target_span: Span, target: Target) { + fn check_coverage(&self, attr: &AttrItem, target_span: Span, target: Target) { let mut not_fn_impl_mod = None; let mut no_body = None; @@ -518,7 +552,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { /// Checks that `#[optimize(..)]` is applied to a function/closure/method, /// or to an impl block or module. - fn check_optimize(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) { + fn check_optimize(&self, hir_id: HirId, attr: &AttrItem, span: Span, target: Target) { let is_valid = matches!( target, Target::Fn @@ -534,7 +568,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_no_sanitize(&self, attr: &Attribute, span: Span, target: Target) { + fn check_no_sanitize(&self, attr: &AttrItem, span: Span, target: Target) { if let Some(list) = attr.meta_item_list() { for item in list.iter() { let sym = item.name(); @@ -573,7 +607,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { fn check_generic_attr( &self, hir_id: HirId, - attr: &Attribute, + attr: &AttrItem, target: Target, allowed_target: Target, ) { @@ -597,7 +631,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { fn check_naked( &self, hir_id: HirId, - attr: &Attribute, + attr: &AttrItem, span: Span, target: Target, attrs: &[Attribute], @@ -662,52 +696,51 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } for other_attr in attrs { - // this covers "sugared doc comments" of the form `/// ...` - // it does not cover `#[doc = "..."]`, which is handled below - if other_attr.is_doc_comment() { - continue; - } - - // FIXME(jdonszelmann): once naked uses new-style parsing, - // this check can be part of the parser and be removed here match other_attr { + // this covers "sugared doc comments" of the form `/// ...` + // it does not cover `#[doc = "..."]`, which is handled below + Attribute::Parsed(AttributeKind::DocComment { .. }) => { + continue; + } + // FIXME(jdonszelmann): once naked uses new-style parsing, + // this check can be part of the parser and be removed here Attribute::Parsed( AttributeKind::Deprecation { .. } | AttributeKind::Repr { .. }, ) => { continue; } - _ => {} - } - - if other_attr.has_name(sym::target_feature) { - if !self.tcx.features().naked_functions_target_feature() { - feature_err( + Attribute::Parsed(_) => {} + Attribute::Unparsed(other_attr) => { + if other_attr.has_name(sym::target_feature) { + if !self.tcx.features().naked_functions_target_feature() { + feature_err( &self.tcx.sess, sym::naked_functions_target_feature, other_attr.span(), "`#[target_feature(/* ... */)]` is currently unstable on `#[naked]` functions", ).emit(); + return; + } else { + continue; + } + } - return; - } else { - continue; - } - } + if !other_attr.has_any_name(ALLOW_LIST) + && !matches!(other_attr.path().as_slice(), [sym::rustfmt, ..]) + { + let path = other_attr.path(); + let path: Vec<_> = path.iter().map(|s| s.as_str()).collect(); + let other_attr_name = path.join("::"); - if !other_attr.has_any_name(ALLOW_LIST) - && !matches!(other_attr.path().as_slice(), [sym::rustfmt, ..]) - { - let path = other_attr.path(); - let path: Vec<_> = path.iter().map(|s| s.as_str()).collect(); - let other_attr_name = path.join("::"); - - self.dcx().emit_err(errors::NakedFunctionIncompatibleAttribute { - span: other_attr.span(), - naked_span: attr.span(), - attr: other_attr_name, - }); + self.dcx().emit_err(errors::NakedFunctionIncompatibleAttribute { + span: other_attr.span(), + naked_span: attr.span(), + attr: other_attr_name, + }); - return; + return; + } + } } } } @@ -742,7 +775,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if `#[collapse_debuginfo]` is applied to a macro. - fn check_collapse_debuginfo(&self, attr: &Attribute, span: Span, target: Target) { + fn check_collapse_debuginfo(&self, attr: &AttrItem, span: Span, target: Target) { match target { Target::MacroDef => {} _ => { @@ -787,7 +820,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { for attr in attrs { - self.inline_attr_str_error_with_macro_def(hir_id, attr, "track_caller"); + self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "track_caller"); } } _ => { @@ -804,7 +837,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { fn check_non_exhaustive( &self, hir_id: HirId, - attr: &Attribute, + attr: &AttrItem, span: Span, target: Target, item: Option>, @@ -830,7 +863,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr, "non_exhaustive"); + self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "non_exhaustive"); } _ => { self.dcx().emit_err(errors::NonExhaustiveWrongLocation { @@ -842,7 +875,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if the `#[marker]` attribute on an `item` is valid. - fn check_marker(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) { + fn check_marker(&self, hir_id: HirId, attr: &AttrItem, span: Span, target: Target) { match target { Target::Trait => {} // FIXME(#80564): We permit struct fields, match arms and macro defs to have an @@ -850,7 +883,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr, "marker"); + self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "marker"); } _ => { self.dcx().emit_err(errors::AttrShouldBeAppliedToTrait { @@ -865,7 +898,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { fn check_target_feature( &self, hir_id: HirId, - attr: &Attribute, + attr: &AttrItem, span: Span, target: Target, attrs: &[Attribute], @@ -904,7 +937,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr, "target_feature"); + self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "target_feature"); } _ => { self.dcx().emit_err(errors::AttrShouldBeAppliedToFn { @@ -917,7 +950,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if the `#[thread_local]` attribute on `item` is valid. - fn check_thread_local(&self, attr: &Attribute, span: Span, target: Target) { + fn check_thread_local(&self, attr: &AttrItem, span: Span, target: Target) { match target { Target::ForeignStatic | Target::Static => {} _ => { @@ -1163,7 +1196,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { /// the first `inline`/`no_inline` attribute. fn check_doc_inline( &self, - attr: &Attribute, + attr: &AttrItem, meta: &MetaItemInner, hir_id: HirId, target: Target, @@ -1203,7 +1236,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { fn check_doc_masked( &self, - attr: &Attribute, + attr: &AttrItem, meta: &MetaItemInner, hir_id: HirId, target: Target, @@ -1251,12 +1284,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks that an attribute is used at the crate level. Returns `true` if valid. - fn check_attr_crate_level( - &self, - attr: &Attribute, - meta: &MetaItemInner, - hir_id: HirId, - ) -> bool { + fn check_attr_crate_level(&self, attr: &AttrItem, meta: &MetaItemInner, hir_id: HirId) -> bool { if hir_id != CRATE_HIR_ID { // insert a bang between `#` and `[...` let bang_span = attr.span().lo() + BytePos(1); @@ -1277,7 +1305,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks that `doc(test(...))` attribute contains only valid attributes and are at the right place. - fn check_test_attr(&self, attr: &Attribute, meta: &MetaItemInner, hir_id: HirId) { + fn check_test_attr(&self, attr: &AttrItem, meta: &MetaItemInner, hir_id: HirId) { if let Some(metas) = meta.meta_item_list() { for i_meta in metas { match (i_meta.name(), i_meta.meta_item()) { @@ -1338,7 +1366,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { /// [`check_doc_inline`]: Self::check_doc_inline fn check_doc_attrs( &self, - attr: &Attribute, + attr: &AttrItem, hir_id: HirId, target: Target, specified_inline: &mut Option<(bool, Span)>, @@ -1487,7 +1515,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Warns against some misuses of `#[pass_by_value]` - fn check_pass_by_value(&self, attr: &Attribute, span: Span, target: Target) { + fn check_pass_by_value(&self, attr: &AttrItem, span: Span, target: Target) { match target { Target::Struct | Target::Enum | Target::TyAlias => {} _ => { @@ -1496,7 +1524,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_allow_incoherent_impl(&self, attr: &Attribute, span: Span, target: Target) { + fn check_allow_incoherent_impl(&self, attr: &AttrItem, span: Span, target: Target) { match target { Target::Method(MethodKind::Inherent) => {} _ => { @@ -1505,7 +1533,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_has_incoherent_inherent_impls(&self, attr: &Attribute, span: Span, target: Target) { + fn check_has_incoherent_inherent_impls(&self, attr: &AttrItem, span: Span, target: Target) { match target { Target::Trait | Target::Struct | Target::Enum | Target::Union | Target::ForeignTy => {} _ => { @@ -1521,7 +1549,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.dcx().emit_err(errors::FfiPureInvalidTarget { attr_span }); return; } - if attrs.iter().any(|a| a.has_name(sym::ffi_const)) { + if hir::find_attr_items_by_name(attrs, sym::ffi_const).next().is_some() { // `#[ffi_const]` functions cannot be `#[ffi_pure]` self.dcx().emit_err(errors::BothFfiConstAndPure { attr_span }); } @@ -1534,7 +1562,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Warns against some misuses of `#[must_use]` - fn check_must_use(&self, hir_id: HirId, attr: &Attribute, target: Target) { + fn check_must_use(&self, hir_id: HirId, attr: &AttrItem, target: Target) { if matches!( target, Target::Fn @@ -1580,7 +1608,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if `#[must_not_suspend]` is applied to a struct, enum, union, or trait. - fn check_must_not_suspend(&self, attr: &Attribute, span: Span, target: Target) { + fn check_must_not_suspend(&self, attr: &AttrItem, span: Span, target: Target) { match target { Target::Struct | Target::Enum | Target::Union | Target::Trait => {} _ => { @@ -1590,7 +1618,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if `#[may_dangle]` is applied to a lifetime or type generic parameter in `Drop` impl. - fn check_may_dangle(&self, hir_id: HirId, attr: &Attribute) { + fn check_may_dangle(&self, hir_id: HirId, attr: &AttrItem) { if let hir::Node::GenericParam(param) = self.tcx.hir_node(hir_id) && matches!( param.kind, @@ -1611,7 +1639,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if `#[cold]` is applied to a non-function. - fn check_cold(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) { + fn check_cold(&self, hir_id: HirId, attr: &AttrItem, span: Span, target: Target) { match target { Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => {} // FIXME(#80564): We permit struct fields, match arms and macro defs to have an @@ -1619,7 +1647,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr, "cold"); + self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "cold"); } _ => { // FIXME: #[cold] was previously allowed on non-functions and some crates used @@ -1635,7 +1663,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if `#[link]` is applied to an item other than a foreign module. - fn check_link(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) { + fn check_link(&self, hir_id: HirId, attr: &AttrItem, span: Span, target: Target) { if target == Target::ForeignMod && let hir::Node::Item(item) = self.tcx.hir_node(hir_id) && let Item { kind: ItemKind::ForeignMod { abi, .. }, .. } = item @@ -1653,7 +1681,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if `#[link_name]` is applied to an item other than a foreign function or static. - fn check_link_name(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) { + fn check_link_name(&self, hir_id: HirId, attr: &AttrItem, span: Span, target: Target) { match target { Target::ForeignFn | Target::ForeignStatic => {} // FIXME(#80564): We permit struct fields, match arms and macro defs to have an @@ -1661,7 +1689,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr, "link_name"); + self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "link_name"); } _ => { // FIXME: #[cold] was previously allowed on non-functions/statics and some crates @@ -1687,7 +1715,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if `#[no_link]` is applied to an `extern crate`. - fn check_no_link(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) { + fn check_no_link(&self, hir_id: HirId, attr: &AttrItem, span: Span, target: Target) { match target { Target::ExternCrate => {} // FIXME(#80564): We permit struct fields, match arms and macro defs to have an @@ -1695,7 +1723,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr, "no_link"); + self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "no_link"); } _ => { self.dcx().emit_err(errors::NoLink { attr_span: attr.span(), span }); @@ -1708,7 +1736,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if `#[export_name]` is applied to a function or static. - fn check_export_name(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) { + fn check_export_name(&self, hir_id: HirId, attr: &AttrItem, span: Span, target: Target) { match target { Target::Static | Target::Fn => {} Target::Method(..) if self.is_impl_item(hir_id) => {} @@ -1717,7 +1745,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr, "export_name"); + self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "export_name"); } _ => { self.dcx().emit_err(errors::ExportName { attr_span: attr.span(), span }); @@ -1725,7 +1753,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_rustc_layout_scalar_valid_range(&self, attr: &Attribute, span: Span, target: Target) { + fn check_rustc_layout_scalar_valid_range(&self, attr: &AttrItem, span: Span, target: Target) { if target != Target::Struct { self.dcx().emit_err(errors::RustcLayoutScalarValidRangeNotStruct { attr_span: attr.span(), @@ -1749,7 +1777,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { fn check_rustc_legacy_const_generics( &self, hir_id: HirId, - attr: &Attribute, + attr: &AttrItem, span: Span, target: Target, item: Option>, @@ -1840,7 +1868,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks that the `#[rustc_lint_opt_ty]` attribute is only applied to a struct. - fn check_rustc_lint_opt_ty(&self, attr: &Attribute, span: Span, target: Target) { + fn check_rustc_lint_opt_ty(&self, attr: &AttrItem, span: Span, target: Target) { match target { Target::Struct => {} _ => { @@ -1850,7 +1878,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks that the `#[rustc_lint_opt_deny_field_access]` attribute is only applied to a field. - fn check_rustc_lint_opt_deny_field_access(&self, attr: &Attribute, span: Span, target: Target) { + fn check_rustc_lint_opt_deny_field_access(&self, attr: &AttrItem, span: Span, target: Target) { match target { Target::Field => {} _ => { @@ -1863,14 +1891,14 @@ impl<'tcx> CheckAttrVisitor<'tcx> { /// Checks that the dep-graph debugging attributes are only present when the query-dep-graph /// option is passed to the compiler. - fn check_rustc_dirty_clean(&self, attr: &Attribute) { + fn check_rustc_dirty_clean(&self, attr: &AttrItem) { if !self.tcx.sess.opts.unstable_opts.query_dep_graph { self.dcx().emit_err(errors::RustcDirtyClean { span: attr.span() }); } } /// Checks if the attribute is applied to a trait. - fn check_must_be_applied_to_trait(&self, attr: &Attribute, span: Span, target: Target) { + fn check_must_be_applied_to_trait(&self, attr: &AttrItem, span: Span, target: Target) { match target { Target::Trait => {} _ => { @@ -1883,7 +1911,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if `#[link_section]` is applied to a function or static. - fn check_link_section(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) { + fn check_link_section(&self, hir_id: HirId, attr: &AttrItem, span: Span, target: Target) { match target { Target::Static | Target::Fn | Target::Method(..) => {} // FIXME(#80564): We permit struct fields, match arms and macro defs to have an @@ -1891,7 +1919,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr, "link_section"); + self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "link_section"); } _ => { // FIXME: #[link_section] was previously allowed on non-functions/statics and some @@ -1907,7 +1935,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if `#[no_mangle]` is applied to a function or static. - fn check_no_mangle(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) { + fn check_no_mangle(&self, hir_id: HirId, attr: &AttrItem, span: Span, target: Target) { match target { Target::Static | Target::Fn => {} Target::Method(..) if self.is_impl_item(hir_id) => {} @@ -1916,7 +1944,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr, "no_mangle"); + self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "no_mangle"); } // FIXME: #[no_mangle] was previously allowed on non-functions/statics, this should be an error // The error should specify that the item that is wrong is specifically a *foreign* fn/static @@ -2153,7 +2181,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { fn check_used(&self, attrs: &[Attribute], target: Target, target_span: Span) { let mut used_linker_span = None; let mut used_compiler_span = None; - for attr in attrs.iter().filter(|attr| attr.has_name(sym::used)) { + for attr in hir::find_attr_items_by_name(attrs, sym::used) { if target != Target::Static { self.dcx().emit_err(errors::UsedStatic { attr_span: attr.span(), @@ -2234,7 +2262,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if the items on the `#[debugger_visualizer]` attribute are valid. - fn check_debugger_visualizer(&self, attr: &Attribute, target: Target) { + fn check_debugger_visualizer(&self, attr: &AttrItem, target: Target) { // Here we only check that the #[debugger_visualizer] attribute is attached // to nothing other than a module. All other checks are done in the // `debugger_visualizer` query where they need to be done for decoding @@ -2247,34 +2275,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - /// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros. - /// (Allows proc_macro functions) - fn check_rustc_allow_const_fn_unstable( - &self, - hir_id: HirId, - attr: &Attribute, - span: Span, - target: Target, - ) { - match target { - Target::Fn | Target::Method(_) - if self.tcx.is_const_fn(hir_id.expect_owner().to_def_id()) => {} - // FIXME(#80564): We permit struct fields and match arms to have an - // `#[allow_internal_unstable]` attribute with just a lint, because we previously - // erroneously allowed it and some crates used it accidentally, to be compatible - // with crates depending on them, we can't throw an error here. - Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr, "allow_internal_unstable") - } - _ => { - self.tcx - .dcx() - .emit_err(errors::RustcAllowConstFnUnstable { attr_span: attr.span(), span }); - } - } - } - - fn check_rustc_std_internal_symbol(&self, attr: &Attribute, span: Span, target: Target) { + fn check_rustc_std_internal_symbol(&self, attr: &AttrItem, span: Span, target: Target) { match target { Target::Fn | Target::Static | Target::ForeignFn | Target::ForeignStatic => {} _ => { @@ -2294,7 +2295,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_link_ordinal(&self, attr: &Attribute, _span: Span, target: Target) { + fn check_link_ordinal(&self, attr: &AttrItem, _span: Span, target: Target) { match target { Target::ForeignFn | Target::ForeignStatic => {} _ => { @@ -2309,21 +2310,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_deprecated(&self, hir_id: HirId, attr: &Attribute, _span: Span, target: Target) { - match target { - Target::Closure | Target::Expression | Target::Statement | Target::Arm => { - self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr.span(), - errors::Deprecated, - ); - } - _ => {} - } - } - - fn check_macro_use(&self, hir_id: HirId, attr: &Attribute, target: Target) { + fn check_macro_use(&self, hir_id: HirId, attr: &AttrItem, target: Target) { let Some(name) = attr.name() else { return; }; @@ -2340,7 +2327,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_macro_export(&self, hir_id: HirId, attr: &Attribute, target: Target) { + fn check_macro_export(&self, hir_id: HirId, attr: &AttrItem, target: Target) { if target != Target::MacroDef { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, @@ -2383,97 +2370,111 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } fn check_unused_attribute(&self, hir_id: HirId, attr: &Attribute) { - // FIXME(jdonszelmann): deduplicate these checks after more attrs are parsed. This is very - // ugly now but can 100% be removed later. - if let Attribute::Parsed(p) = attr { - match p { - AttributeKind::Repr(reprs) => { - for (r, span) in reprs { - if let ReprAttr::ReprEmpty = r { - self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - *span, - errors::Unused { - attr_span: *span, - note: errors::UnusedNote::EmptyList { name: sym::repr }, - }, - ); + match attr { + Attribute::Parsed(p) => + // FIXME(jdonszelmann): deduplicate these checks after more attrs are parsed. This is very + // ugly now but can 100% be removed later. + { + match p { + AttributeKind::Repr(reprs) => { + for (r, span) in reprs { + if let ReprAttr::ReprEmpty = r { + self.tcx.emit_node_span_lint( + UNUSED_ATTRIBUTES, + hir_id, + *span, + errors::Unused { + attr_span: *span, + note: errors::UnusedNote::EmptyList { name: sym::repr }, + }, + ); + } } + return; } - return; + _ => {} } - _ => {} } - } - - // Warn on useless empty attributes. - let note = if attr.has_any_name(&[ - sym::macro_use, - sym::allow, - sym::expect, - sym::warn, - sym::deny, - sym::forbid, - sym::feature, - sym::target_feature, - ]) && attr.meta_item_list().is_some_and(|list| list.is_empty()) - { - errors::UnusedNote::EmptyList { name: attr.name().unwrap() } - } else if attr.has_any_name(&[sym::allow, sym::warn, sym::deny, sym::forbid, sym::expect]) - && let Some(meta) = attr.meta_item_list() - && let [meta] = meta.as_slice() - && let Some(item) = meta.meta_item() - && let MetaItemKind::NameValue(_) = &item.kind - && item.path == sym::reason - { - errors::UnusedNote::NoLints { name: attr.name().unwrap() } - } else if attr.has_any_name(&[sym::allow, sym::warn, sym::deny, sym::forbid, sym::expect]) - && let Some(meta) = attr.meta_item_list() - && meta.iter().any(|meta| { - meta.meta_item().map_or(false, |item| item.path == sym::linker_messages) - }) - { - if hir_id != CRATE_HIR_ID { - match attr.style() { - ast::AttrStyle::Outer => self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr.span(), - errors::OuterCrateLevelAttr, - ), - ast::AttrStyle::Inner => self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr.span(), - errors::InnerCrateLevelAttr, - ), - }; - return; - } else { - let never_needs_link = self - .tcx - .crate_types() - .iter() - .all(|kind| matches!(kind, CrateType::Rlib | CrateType::Staticlib)); - if never_needs_link { - errors::UnusedNote::LinkerMessagesBinaryCrateOnly + Attribute::Unparsed(attr) => { + // Warn on useless empty attributes. + let note = if attr.has_any_name(&[ + sym::macro_use, + sym::allow, + sym::expect, + sym::warn, + sym::deny, + sym::forbid, + sym::feature, + sym::target_feature, + ]) && attr.meta_item_list().is_some_and(|list| list.is_empty()) + { + errors::UnusedNote::EmptyList { name: attr.name().unwrap() } + } else if attr.has_any_name(&[ + sym::allow, + sym::warn, + sym::deny, + sym::forbid, + sym::expect, + ]) && let Some(meta) = attr.meta_item_list() + && let [meta] = meta.as_slice() + && let Some(item) = meta.meta_item() + && let MetaItemKind::NameValue(_) = &item.kind + && item.path == sym::reason + { + errors::UnusedNote::NoLints { name: attr.name().unwrap() } + } else if attr.has_any_name(&[ + sym::allow, + sym::warn, + sym::deny, + sym::forbid, + sym::expect, + ]) && let Some(meta) = attr.meta_item_list() + && meta.iter().any(|meta| { + meta.meta_item().map_or(false, |item| item.path == sym::linker_messages) + }) + { + if hir_id != CRATE_HIR_ID { + match attr.style() { + ast::AttrStyle::Outer => self.tcx.emit_node_span_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span(), + errors::OuterCrateLevelAttr, + ), + ast::AttrStyle::Inner => self.tcx.emit_node_span_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span(), + errors::InnerCrateLevelAttr, + ), + }; + return; + } else { + let never_needs_link = self + .tcx + .crate_types() + .iter() + .all(|kind| matches!(kind, CrateType::Rlib | CrateType::Staticlib)); + if never_needs_link { + errors::UnusedNote::LinkerMessagesBinaryCrateOnly + } else { + return; + } + } + } else if attr.has_name(sym::default_method_body_is_const) { + errors::UnusedNote::DefaultMethodBodyConst } else { return; - } + }; + + self.tcx.emit_node_span_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span(), + errors::Unused { attr_span: attr.span(), note }, + ) } - } else if attr.has_name(sym::default_method_body_is_const) { - errors::UnusedNote::DefaultMethodBodyConst - } else { - return; }; - - self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr.span(), - errors::Unused { attr_span: attr.span(), note }, - ); } /// A best effort attempt to create an error for a mismatching proc macro signature. @@ -2584,7 +2585,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_coroutine(&self, attr: &Attribute, target: Target) { + fn check_coroutine(&self, attr: &AttrItem, target: Target) { match target { Target::Closure => return, _ => { @@ -2593,7 +2594,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_type_const(&self, hir_id: HirId, attr: &Attribute, target: Target) { + fn check_type_const(&self, hir_id: HirId, attr: &AttrItem, target: Target) { let tcx = self.tcx; if target == Target::AssocConst && let parent = tcx.parent(hir_id.expect_owner().to_def_id()) @@ -2610,7 +2611,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_linkage(&self, attr: &Attribute, span: Span, target: Target) { + fn check_linkage(&self, attr: &AttrItem, span: Span, target: Target) { match target { Target::Fn | Target::Method(..) @@ -2671,7 +2672,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if `#[autodiff]` is applied to an item other than a function item. - fn check_autodiff(&self, _hir_id: HirId, _attr: &Attribute, span: Span, target: Target) { + fn check_autodiff(&self, _hir_id: HirId, _attr: &AttrItem, span: Span, target: Target) { debug!("check_autodiff"); match target { Target::Fn => {} @@ -2910,7 +2911,7 @@ pub(crate) fn provide(providers: &mut Providers) { fn check_duplicates( tcx: TyCtxt<'_>, - attr: &Attribute, + attr: &AttrItem, hir_id: HirId, duplicates: AttributeDuplicates, seen: &mut FxHashMap, diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs index a19faf0fa8367..006772bc26115 100644 --- a/compiler/rustc_passes/src/layout_test.rs +++ b/compiler/rustc_passes/src/layout_test.rs @@ -1,5 +1,5 @@ use rustc_abi::{HasDataLayout, TargetDataLayout}; -use rustc_hir::Attribute; +use rustc_hir::AttrItem; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_middle::span_bug; @@ -66,7 +66,7 @@ pub fn ensure_wf<'tcx>( } } -fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) { +fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &AttrItem) { let typing_env = ty::TypingEnv::post_analysis(tcx, item_def_id); let ty = tcx.type_of(item_def_id).instantiate_identity(); let span = tcx.def_span(item_def_id.to_def_id()); diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs index 93d164e7d01f8..dc42043281eb1 100644 --- a/compiler/rustc_passes/src/weak_lang_items.rs +++ b/compiler/rustc_passes/src/weak_lang_items.rs @@ -45,7 +45,7 @@ struct WeakLangItemVisitor<'a, 'tcx> { impl<'ast> visit::Visitor<'ast> for WeakLangItemVisitor<'_, '_> { fn visit_foreign_item(&mut self, i: &'ast ast::ForeignItem) { - if let Some((lang_item, _)) = lang_items::extract(&i.attrs) { + if let Some((lang_item, _)) = lang_items::extract(i.attrs.as_slice()) { if let Some(item) = LangItem::from_name(lang_item) && item.is_weak() { diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index baa4c0681e806..54e25b3aa63ef 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -275,15 +275,11 @@ impl<'tcx> SmirCtxt<'tcx> { let attr_name: Vec<_> = attr.iter().map(|seg| rustc_span::Symbol::intern(&seg)).collect(); tcx.get_attrs_by_path(did, &attr_name) .filter_map(|attribute| { - if let Attribute::Unparsed(u) = attribute { - let attr_str = rustc_hir_pretty::attribute_to_string(&tcx, attribute); - Some(stable_mir::crate_def::Attribute::new( - attr_str, - u.span.stable(&mut *tables), - )) - } else { - None - } + let attr_str = rustc_hir_pretty::attr_item_to_string(&tcx, attribute); + Some(stable_mir::crate_def::Attribute::new( + attr_str, + attribute.span.stable(&mut *tables), + )) }) .collect() } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs index 89dab90dc681c..78551c6f45ca8 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs @@ -4,9 +4,8 @@ use std::path::PathBuf; use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit}; use rustc_errors::codes::*; use rustc_errors::{ErrorGuaranteed, struct_span_code_err}; -use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::{AttrArgs, Attribute}; +use rustc_hir::{self as hir, AttrArgs, AttrItem}; use rustc_macros::LintDiagnostic; use rustc_middle::bug; use rustc_middle::ty::print::PrintTraitRefExt; @@ -645,20 +644,13 @@ impl<'tcx> OnUnimplementedDirective { } fn parse_attribute( - attr: &Attribute, + attr: &AttrItem, is_diagnostic_namespace_variant: bool, tcx: TyCtxt<'tcx>, item_def_id: DefId, ) -> Result, ErrorGuaranteed> { let result = if let Some(items) = attr.meta_item_list() { - Self::parse( - tcx, - item_def_id, - &items, - attr.span(), - true, - is_diagnostic_namespace_variant, - ) + Self::parse(tcx, item_def_id, &items, attr.span, true, is_diagnostic_namespace_variant) } else if let Some(value) = attr.value_str() { if !is_diagnostic_namespace_variant { Ok(Some(OnUnimplementedDirective { @@ -680,9 +672,8 @@ impl<'tcx> OnUnimplementedDirective { append_const_msg: None, })) } else { - let item = attr.get_normal_item(); - let report_span = match &item.args { - AttrArgs::Empty => item.path.span, + let report_span = match &attr.args { + AttrArgs::Empty => attr.path.span, AttrArgs::Delimited(args) => args.dspan.entire(), AttrArgs::Eq { eq_span, expr } => eq_span.to(expr.span), }; @@ -698,29 +689,23 @@ impl<'tcx> OnUnimplementedDirective { Ok(None) } } else if is_diagnostic_namespace_variant { - match attr { - Attribute::Unparsed(p) if !matches!(p.args, AttrArgs::Empty) => { - if let Some(item_def_id) = item_def_id.as_local() { - tcx.emit_node_span_lint( - UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, - tcx.local_def_id_to_hir_id(item_def_id), - attr.span(), - MalformedOnUnimplementedAttrLint::new(attr.span()), - ); - } - } - _ => { - if let Some(item_def_id) = item_def_id.as_local() { - tcx.emit_node_span_lint( - UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, - tcx.local_def_id_to_hir_id(item_def_id), - attr.span(), - MissingOptionsForOnUnimplementedAttr, - ) - } + if !matches!(attr.args, AttrArgs::Empty) { + if let Some(item_def_id) = item_def_id.as_local() { + tcx.emit_node_span_lint( + UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + tcx.local_def_id_to_hir_id(item_def_id), + attr.span(), + MalformedOnUnimplementedAttrLint::new(attr.span()), + ); } + } else if let Some(item_def_id) = item_def_id.as_local() { + tcx.emit_node_span_lint( + UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + tcx.local_def_id_to_hir_id(item_def_id), + attr.span(), + MissingOptionsForOnUnimplementedAttr, + ) }; - Ok(None) } else { let reported = tcx.dcx().delayed_bug("of_item: neither meta_item_list nor value_str"); diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index c58b07a5b6731..866e046097fd2 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -579,7 +579,7 @@ pub(crate) fn has_doc_flag(tcx: TyCtxt<'_>, did: DefId, flag: Symbol) -> bool { } pub(crate) fn attrs_have_doc_flag<'a>( - mut attrs: impl Iterator, + mut attrs: impl Iterator, flag: Symbol, ) -> bool { attrs.any(|attr| attr.meta_item_list().is_some_and(|l| ast::attr::list_contains_name(&l, flag))) diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index f4e4cd924f7ff..1a7dd424b7db1 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -66,9 +66,11 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> let mut parent = Some(tcx.parent(impl_def_id)); while let Some(did) = parent { attr_buf.extend( - tcx.get_attrs(did, sym::doc) + tcx.get_all_attrs(did) .filter(|attr| { - if let Some([attr]) = attr.meta_item_list().as_deref() { + if !attr.has_name(sym::doc) { + false + } else if let Some([attr]) = attr.meta_item_list().as_deref() { attr.has_name(sym::cfg) } else { false diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs index 70655838b6af0..0e23676212d8b 100644 --- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs +++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs @@ -2,7 +2,7 @@ use hir::FnSig; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::def_id::DefIdSet; -use rustc_hir::{self as hir, Attribute, QPath}; +use rustc_hir::{self as hir, AttrItem, Attribute, QPath}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty::{self, Ty}; @@ -103,7 +103,7 @@ fn check_needless_must_use( item_id: hir::OwnerId, item_span: Span, fn_header_span: Span, - attr: &Attribute, + attr: &AttrItem, attrs: &[Attribute], sig: &FnSig<'_>, ) {