From 2084831cd54eb603fec6cd85ebd9d1426b09f628 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sun, 22 Jun 2025 12:14:38 +0200 Subject: [PATCH] Port `#[no_mangle]` to new attribute parsing infrastructure Signed-off-by: Jonathan Brouwer --- .../src/attributes.rs | 3 ++ .../src/attributes/codegen_attrs.rs | 18 +++++++ compiler/rustc_attr_parsing/src/context.rs | 3 +- compiler/rustc_codegen_ssa/messages.ftl | 2 + .../rustc_codegen_ssa/src/codegen_attrs.rs | 48 +++++++++---------- compiler/rustc_codegen_ssa/src/errors.rs | 8 ++++ compiler/rustc_lint/src/builtin.rs | 21 ++++---- compiler/rustc_lint/src/nonstandard_style.rs | 12 +++-- compiler/rustc_passes/src/check_attr.rs | 15 +++--- src/librustdoc/clean/types.rs | 22 ++++----- src/librustdoc/html/render/mod.rs | 4 +- src/librustdoc/html/render/print_item.rs | 2 +- src/librustdoc/json/conversions.rs | 2 +- src/rustdoc-json-types/lib.rs | 4 +- .../clippy_lints/src/functions/must_use.rs | 5 +- .../src/no_mangle_with_rust_abi.rs | 7 +-- .../lint/unused/unused-attr-duplicate.stderr | 24 +++++----- 17 files changed, 120 insertions(+), 80 deletions(-) diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index ce1d808026230..c7487847e6f26 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -244,6 +244,9 @@ pub enum AttributeKind { reason: Option, }, + /// Represents `#[no_mangle]` + NoMangle(Span), + /// Represents `#[optimize(size|speed)]` Optimize(OptimizeAttr, Span), diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 1b03525a5ce84..ba4e2935004c7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -56,3 +56,21 @@ impl SingleAttributeParser for ColdParser { Some(AttributeKind::Cold(cx.attr_span)) } } + +pub(crate) struct NoMangleParser; + +impl SingleAttributeParser for NoMangleParser { + const PATH: &[rustc_span::Symbol] = &[sym::no_mangle]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const TEMPLATE: AttributeTemplate = template!(Word); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + if !args.no_args() { + cx.expected_no_args(args.span().unwrap_or(cx.attr_span)); + return None; + }; + + Some(AttributeKind::NoMangle(cx.attr_span)) + } +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index fbe874d606cc9..171995dc9cbd1 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -15,7 +15,7 @@ use rustc_session::Session; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser}; -use crate::attributes::codegen_attrs::{ColdParser, OptimizeParser}; +use crate::attributes::codegen_attrs::{ColdParser, NoMangleParser, OptimizeParser}; use crate::attributes::confusables::ConfusablesParser; use crate::attributes::deprecation::DeprecationParser; use crate::attributes::inline::{InlineParser, RustcForceInlineParser}; @@ -114,6 +114,7 @@ attribute_parsers!( Single, Single, Single, + Single, Single, Single, Single, diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 2bd8644e0d7fc..b2e86414d9024 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -221,6 +221,8 @@ codegen_ssa_multiple_main_functions = entry symbol `main` declared multiple time codegen_ssa_no_field = no field `{$name}` +codegen_ssa_no_mangle_nameless = `#[no_mangle]` cannot be used on {$definition} as it has no name + codegen_ssa_no_module_named = no module named `{$user_path}` (mangled: {$cgu_name}). available modules: {$cgu_names} diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 39818be5bde5a..b554ccfac50e1 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -23,6 +23,7 @@ use rustc_span::{Ident, Span, sym}; use rustc_target::spec::SanitizerSet; use crate::errors; +use crate::errors::NoMangleNameless; use crate::target_features::{ check_target_feature_trait_unsafe, check_tied_features, from_target_feature_attr, }; @@ -87,7 +88,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { let mut link_ordinal_span = None; let mut no_sanitize_span = None; let mut mixed_export_name_no_mangle_lint_state = MixedExportNameAndNoMangleState::default(); - let mut no_mangle_span = None; for attr in attrs.iter() { // In some cases, attribute are only valid on functions, but it's the `check_attr` @@ -122,6 +122,25 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } AttributeKind::Cold(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD, AttributeKind::Align { align, .. } => codegen_fn_attrs.alignment = Some(*align), + AttributeKind::NoMangle(attr_span) => { + if tcx.opt_item_name(did.to_def_id()).is_some() { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE; + mixed_export_name_no_mangle_lint_state.track_no_mangle( + *attr_span, + tcx.local_def_id_to_hir_id(did), + attr, + ); + } else { + tcx.dcx().emit_err(NoMangleNameless { + span: *attr_span, + definition: format!( + "{} {}", + tcx.def_descr_article(did.to_def_id()), + tcx.def_descr(did.to_def_id()) + ), + }); + } + } _ => {} } } @@ -141,28 +160,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED } sym::naked => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED, - sym::no_mangle => { - no_mangle_span = Some(attr.span()); - if tcx.opt_item_name(did.to_def_id()).is_some() { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE; - mixed_export_name_no_mangle_lint_state.track_no_mangle( - attr.span(), - tcx.local_def_id_to_hir_id(did), - attr, - ); - } else { - tcx.dcx() - .struct_span_err( - attr.span(), - format!( - "`#[no_mangle]` cannot be used on {} {} as it has no name", - tcx.def_descr_article(did.to_def_id()), - tcx.def_descr(did.to_def_id()), - ), - ) - .emit(); - } - } sym::rustc_std_internal_symbol => { codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL } @@ -544,12 +541,15 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) && codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) { + let no_mangle_span = + find_attr!(attrs, AttributeKind::NoMangle(no_mangle_span) => *no_mangle_span) + .unwrap_or_default(); let lang_item = lang_items::extract(attrs).map_or(None, |(name, _span)| LangItem::from_name(name)); let mut err = tcx .dcx() .struct_span_err( - no_mangle_span.unwrap_or_default(), + no_mangle_span, "`#[no_mangle]` cannot be used on internal language items", ) .with_note("Rustc requires this item to have a specific mangled name.") diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 72e71b97a1743..caac0f83f9d95 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -1310,3 +1310,11 @@ impl Diagnostic<'_, G> for TargetFeatureDisableOrEnable<'_ diag } } + +#[derive(Diagnostic)] +#[diag(codegen_ssa_no_mangle_nameless)] +pub(crate) struct NoMangleNameless { + #[primary_span] + pub span: Span, + pub definition: String, +} diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index dedea54f8e081..ac405277c4ed2 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -21,6 +21,7 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_ast::visit::{FnCtxt, FnKind}; use rustc_ast::{self as ast, *}; use rustc_ast_pretty::pprust::expr_to_string; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_errors::{Applicability, LintDiagnostic}; use rustc_feature::GateIssue; use rustc_hir as hir; @@ -954,7 +955,7 @@ declare_lint_pass!(InvalidNoMangleItems => [NO_MANGLE_CONST_ITEMS, NO_MANGLE_GEN impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) { let attrs = cx.tcx.hir_attrs(it.hir_id()); - let check_no_mangle_on_generic_fn = |attr: &hir::Attribute, + let check_no_mangle_on_generic_fn = |attr_span: Span, impl_generics: Option<&hir::Generics<'_>>, generics: &hir::Generics<'_>, span| { @@ -967,7 +968,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { cx.emit_span_lint( NO_MANGLE_GENERIC_ITEMS, span, - BuiltinNoMangleGeneric { suggestion: attr.span() }, + BuiltinNoMangleGeneric { suggestion: attr_span }, ); break; } @@ -976,14 +977,15 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { }; match it.kind { hir::ItemKind::Fn { generics, .. } => { - if let Some(attr) = attr::find_by_name(attrs, sym::export_name) - .or_else(|| attr::find_by_name(attrs, sym::no_mangle)) + if let Some(attr_span) = attr::find_by_name(attrs, sym::export_name) + .map(|at| at.span()) + .or_else(|| find_attr!(attrs, AttributeKind::NoMangle(span) => *span)) { - check_no_mangle_on_generic_fn(attr, None, generics, it.span); + check_no_mangle_on_generic_fn(attr_span, None, generics, it.span); } } hir::ItemKind::Const(..) => { - if attr::contains_name(attrs, sym::no_mangle) { + if find_attr!(attrs, AttributeKind::NoMangle(..)) { // account for "pub const" (#45562) let start = cx .tcx @@ -1008,11 +1010,12 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { for it in *items { if let hir::AssocItemKind::Fn { .. } = it.kind { let attrs = cx.tcx.hir_attrs(it.id.hir_id()); - if let Some(attr) = attr::find_by_name(attrs, sym::export_name) - .or_else(|| attr::find_by_name(attrs, sym::no_mangle)) + if let Some(attr_span) = attr::find_by_name(attrs, sym::export_name) + .map(|at| at.span()) + .or_else(|| find_attr!(attrs, AttributeKind::NoMangle(span) => *span)) { check_no_mangle_on_generic_fn( - attr, + attr_span, Some(generics), cx.tcx.hir_get_generics(it.id.owner_id.def_id).unwrap(), it.span, diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 1b60466a589d2..f39e1506390d5 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -1,5 +1,5 @@ use rustc_abi::ExternAbi; -use rustc_attr_data_structures::{AttributeKind, ReprAttr}; +use rustc_attr_data_structures::{AttributeKind, ReprAttr, find_attr}; use rustc_attr_parsing::AttributeParser; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::FnKind; @@ -396,7 +396,9 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { match &fk { FnKind::Method(ident, sig, ..) => match method_context(cx, id) { MethodLateContext::PlainImpl => { - if sig.header.abi != ExternAbi::Rust && cx.tcx.has_attr(id, sym::no_mangle) { + if sig.header.abi != ExternAbi::Rust + && find_attr!(cx.tcx.get_all_attrs(id), AttributeKind::NoMangle(..)) + { return; } self.check_snake_case(cx, "method", ident); @@ -408,7 +410,9 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { }, FnKind::ItemFn(ident, _, header) => { // Skip foreign-ABI #[no_mangle] functions (Issue #31924) - if header.abi != ExternAbi::Rust && cx.tcx.has_attr(id, sym::no_mangle) { + if header.abi != ExternAbi::Rust + && find_attr!(cx.tcx.get_all_attrs(id), AttributeKind::NoMangle(..)) + { return; } self.check_snake_case(cx, "function", ident); @@ -514,7 +518,7 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals { let attrs = cx.tcx.hir_attrs(it.hir_id()); match it.kind { hir::ItemKind::Static(_, ident, ..) - if !ast::attr::contains_name(attrs, sym::no_mangle) => + if !find_attr!(attrs, AttributeKind::NoMangle(..)) => { NonUpperCaseGlobals::check_upper_case(cx, "static variable", &ident); } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index e11ec2ed47ab9..ad1a2a0427376 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -174,6 +174,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::MustUse { span, .. }) => { self.check_must_use(hir_id, *span, target) } + Attribute::Parsed(AttributeKind::NoMangle(attr_span)) => { + self.check_no_mangle(hir_id, *attr_span, span, target) + } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); match attr.path().as_slice() { @@ -261,7 +264,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::link, ..] => self.check_link(hir_id, attr, span, target), [sym::link_name, ..] => self.check_link_name(hir_id, attr, span, target), [sym::link_section, ..] => self.check_link_section(hir_id, attr, span, target), - [sym::no_mangle, ..] => self.check_no_mangle(hir_id, attr, span, target), [sym::macro_use, ..] | [sym::macro_escape, ..] => { self.check_macro_use(hir_id, attr, target) } @@ -698,6 +700,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::Deprecation { .. } | AttributeKind::Repr { .. } | AttributeKind::Align { .. } + | AttributeKind::NoMangle(..) | AttributeKind::Cold(..) | AttributeKind::MustUse { .. }, ) => { @@ -1952,7 +1955,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_span: Span, span: Span, target: Target) { match target { Target::Static | Target::Fn => {} Target::Method(..) if self.is_impl_item(hir_id) => {} @@ -1961,7 +1964,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.span(), "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 @@ -1975,8 +1978,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), - errors::NoMangleForeign { span, attr_span: attr.span(), foreign_item_kind }, + attr_span, + errors::NoMangleForeign { span, attr_span, foreign_item_kind }, ); } _ => { @@ -1985,7 +1988,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr_span, errors::NoMangle { span }, ); } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index c0a9d8c84f6cd..0aedc7f5219c8 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -746,15 +746,17 @@ impl Item { Some(tcx.visibility(def_id)) } - pub(crate) fn attributes_without_repr(&self, tcx: TyCtxt<'_>, is_json: bool) -> Vec { + fn attributes_without_repr(&self, tcx: TyCtxt<'_>, is_json: bool) -> Vec { const ALLOWED_ATTRIBUTES: &[Symbol] = &[sym::export_name, sym::link_section, sym::no_mangle, sym::non_exhaustive]; - self.attrs .other_attrs .iter() .filter_map(|attr| { - if is_json { + // NoMangle is special-cased because cargo-semver-checks uses it + if matches!(attr, hir::Attribute::Parsed(AttributeKind::NoMangle(..))) { + Some("#[no_mangle]".to_string()) + } else if is_json { match attr { // rustdoc-json stores this in `Item::deprecation`, so we // don't want it it `Item::attrs`. @@ -767,26 +769,22 @@ impl Item { s }), } - } else if attr.has_any_name(ALLOWED_ATTRIBUTES) { + } else { + if !attr.has_any_name(ALLOWED_ATTRIBUTES) { + return None; + } Some( rustc_hir_pretty::attribute_to_string(&tcx, attr) .replace("\\\n", "") .replace('\n', "") .replace(" ", " "), ) - } else { - None } }) .collect() } - pub(crate) fn attributes_and_repr( - &self, - tcx: TyCtxt<'_>, - cache: &Cache, - is_json: bool, - ) -> Vec { + pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, cache: &Cache, is_json: bool) -> Vec { let mut attrs = self.attributes_without_repr(tcx, is_json); if let Some(repr_attr) = self.repr(tcx, cache, is_json) { diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 66d5aafa3c1ef..ed58bae70bd46 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1194,7 +1194,7 @@ fn render_assoc_item( // a whitespace prefix and newline. fn render_attributes_in_pre(it: &clean::Item, prefix: &str, cx: &Context<'_>) -> impl fmt::Display { fmt::from_fn(move |f| { - for a in it.attributes_and_repr(cx.tcx(), cx.cache(), false) { + for a in it.attributes(cx.tcx(), cx.cache(), false) { writeln!(f, "{prefix}{a}")?; } Ok(()) @@ -1210,7 +1210,7 @@ fn render_code_attribute(code_attr: CodeAttribute, w: &mut impl fmt::Write) { // When an attribute is rendered inside a tag, it is formatted using // a div to produce a newline after it. fn render_attributes_in_code(w: &mut impl fmt::Write, it: &clean::Item, cx: &Context<'_>) { - for attr in it.attributes_and_repr(cx.tcx(), cx.cache(), false) { + for attr in it.attributes(cx.tcx(), cx.cache(), false) { render_code_attribute(CodeAttribute(attr), w); } } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index a75088d27ccda..515424cbef19b 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1491,7 +1491,7 @@ impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> { writeln!(f, "{repr}")?; }; } else { - for a in self.it.attributes_and_repr(self.cx.tcx(), self.cx.cache(), false) { + for a in self.it.attributes(self.cx.tcx(), self.cx.cache(), false) { writeln!(f, "{a}")?; } } diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index abad6e480291e..0778b5b56f5d6 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -40,7 +40,7 @@ impl JsonRenderer<'_> { }) .collect(); let docs = item.opt_doc_value(); - let attrs = item.attributes_and_repr(self.tcx, &self.cache, true); + let attrs = item.attributes(self.tcx, &self.cache, true); let span = item.span(self.tcx); let visibility = item.visibility(self.tcx); let clean::ItemInner { name, item_id, .. } = *item.inner; diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index e5c246cb69c3e..0e72ddd9db1ed 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -37,8 +37,8 @@ pub type FxHashMap = HashMap; // re-export for use in src/librustdoc // will instead cause conflicts. See #94591 for more. (This paragraph and the "Latest feature" line // are deliberately not in a doc comment, because they need not be in public docs.) // -// Latest feature: Pretty printing of must_use attributes changed -pub const FORMAT_VERSION: u32 = 52; +// Latest feature: Pretty printing of no_mangle attributes changed +pub const FORMAT_VERSION: u32 = 53; /// The root of the emitted JSON blob. /// 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 ea9ed4ddade70..c0c23e217fd4b 100644 --- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs +++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs @@ -15,9 +15,8 @@ use clippy_utils::ty::is_must_use_ty; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{return_ty, trait_ref_of_method}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; -use rustc_attr_data_structures::AttributeKind; use rustc_span::Symbol; -use rustc_attr_data_structures::find_attr; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use core::ops::ControlFlow; @@ -36,7 +35,7 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_> let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); if let Some((attr_span, reason)) = attr { check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, *attr_span, *reason, attrs, sig); - } else if is_public && !is_proc_macro(attrs) && !attrs.iter().any(|a| a.has_name(sym::no_mangle)) { + } else if is_public && !is_proc_macro(attrs) && !find_attr!(attrs, AttributeKind::NoMangle(..)) { check_must_use_candidate( cx, sig.decl, diff --git a/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs b/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs index b71dde9069184..0159c5d2ac1b1 100644 --- a/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs +++ b/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs @@ -6,6 +6,8 @@ use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::{BytePos, Pos}; +use rustc_attr_data_structures::AttributeKind; +use rustc_hir::Attribute; declare_clippy_lint! { /// ### What it does @@ -44,8 +46,7 @@ impl<'tcx> LateLintPass<'tcx> for NoMangleWithRustAbi { let mut app = Applicability::MaybeIncorrect; let fn_snippet = snippet_with_applicability(cx, fn_sig.span.with_hi(ident.span.lo()), "..", &mut app); for attr in attrs { - if let Some(ident) = attr.ident() - && ident.name == rustc_span::sym::no_mangle + if let Attribute::Parsed(AttributeKind::NoMangle(attr_span)) = attr && fn_sig.header.abi == ExternAbi::Rust && let Some((fn_attrs, _)) = fn_snippet.rsplit_once("fn") && !fn_attrs.contains("extern") @@ -54,7 +55,7 @@ impl<'tcx> LateLintPass<'tcx> for NoMangleWithRustAbi { .span .with_lo(fn_sig.span.lo() + BytePos::from_usize(fn_attrs.len())) .shrink_to_lo(); - let attr_snippet = snippet(cx, attr.span(), ".."); + let attr_snippet = snippet(cx, *attr_span, ".."); span_lint_and_then( cx, diff --git a/tests/ui/lint/unused/unused-attr-duplicate.stderr b/tests/ui/lint/unused/unused-attr-duplicate.stderr index 6fdd0adf4cff3..4abf7dd134e62 100644 --- a/tests/ui/lint/unused/unused-attr-duplicate.stderr +++ b/tests/ui/lint/unused/unused-attr-duplicate.stderr @@ -114,18 +114,6 @@ LL | #[export_name = "exported_symbol_name2"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -error: unused attribute - --> $DIR/unused-attr-duplicate.rs:98:1 - | -LL | #[no_mangle] - | ^^^^^^^^^^^^ help: remove this attribute - | -note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:97:1 - | -LL | #[no_mangle] - | ^^^^^^^^^^^^ - error: unused attribute --> $DIR/unused-attr-duplicate.rs:102:1 | @@ -289,5 +277,17 @@ note: attribute also specified here LL | #[cold] | ^^^^^^^ +error: unused attribute + --> $DIR/unused-attr-duplicate.rs:98:1 + | +LL | #[no_mangle] + | ^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/unused-attr-duplicate.rs:97:1 + | +LL | #[no_mangle] + | ^^^^^^^^^^^^ + error: aborting due to 23 previous errors