From 287d9afce729dd81fa9abfa860af31656d9c5e16 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Tue, 24 Jun 2025 22:33:44 +0200 Subject: Port `#[export_name]` to the new attribute parsing infrastructure Signed-off-by: Jonathan Brouwer --- compiler/rustc_codegen_ssa/src/errors.rs | 7 ------- 1 file changed, 7 deletions(-) (limited to 'compiler/rustc_codegen_ssa/src/errors.rs') diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index caac0f83f9d..315d9c92ab0 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -140,13 +140,6 @@ pub(crate) struct RequiresRustAbi { pub span: Span, } -#[derive(Diagnostic)] -#[diag(codegen_ssa_null_on_export, code = E0648)] -pub(crate) struct NullOnExport { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(codegen_ssa_unsupported_instruction_set, code = E0779)] pub(crate) struct UnsupportedInstructionSet { -- cgit 1.4.1-3-g733a5 From 3d1cee53244dce3a9e58e04c87ba8d02d964f79f Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Tue, 24 Jun 2025 23:05:45 +0200 Subject: Move mixed export_name/no_mangle check to check_attr.rs and improve the error Signed-off-by: Jonathan Brouwer --- compiler/rustc_codegen_ssa/messages.ftl | 5 -- compiler/rustc_codegen_ssa/src/codegen_attrs.rs | 56 +--------------------- compiler/rustc_codegen_ssa/src/errors.rs | 12 ----- compiler/rustc_passes/messages.ftl | 5 ++ compiler/rustc_passes/src/check_attr.rs | 33 +++++++++++++ compiler/rustc_passes/src/errors.rs | 12 +++++ .../mixed_export_name_and_no_mangle.fixed | 4 +- .../attributes/mixed_export_name_and_no_mangle.rs | 4 +- .../mixed_export_name_and_no_mangle.stderr | 12 ++--- .../mixed_export_name_and_no_mangle_2024.fixed | 15 ++++++ .../mixed_export_name_and_no_mangle_2024.rs | 17 +++++++ .../mixed_export_name_and_no_mangle_2024.stderr | 39 +++++++++++++++ 12 files changed, 133 insertions(+), 81 deletions(-) create mode 100644 tests/ui/attributes/mixed_export_name_and_no_mangle_2024.fixed create mode 100644 tests/ui/attributes/mixed_export_name_and_no_mangle_2024.rs create mode 100644 tests/ui/attributes/mixed_export_name_and_no_mangle_2024.stderr (limited to 'compiler/rustc_codegen_ssa/src/errors.rs') diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 4f2c832a3a4..6362d2edf85 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -205,11 +205,6 @@ codegen_ssa_missing_features = add the missing features in a `target_feature` at codegen_ssa_missing_query_depgraph = found CGU-reuse attribute but `-Zquery-dep-graph` was not specified -codegen_ssa_mixed_export_name_and_no_mangle = `{$no_mangle_attr}` attribute may not be used in combination with `#[export_name]` - .label = `{$no_mangle_attr}` is ignored - .note = `#[export_name]` takes precedence - .suggestion = remove the `{$no_mangle_attr}` attribute - codegen_ssa_msvc_missing_linker = the msvc targets depend on the msvc linker but `link.exe` was not found codegen_ssa_multiple_external_func_decl = multiple declarations of external function `{$function}` from library `{$library_name}` have different calling conventions diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index a6b3dfec4dc..94df5e8b361 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -9,7 +9,7 @@ use rustc_attr_data_structures::{ use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS; -use rustc_hir::{self as hir, HirId, LangItem, lang_items}; +use rustc_hir::{self as hir, LangItem, lang_items}; use rustc_middle::middle::codegen_fn_attrs::{ CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, }; @@ -87,7 +87,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(); for attr in attrs.iter() { // In some cases, attribute are only valid on functions, but it's the `check_attr` @@ -119,20 +118,14 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { .max(); } AttributeKind::Cold(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD, - AttributeKind::ExportName { name, span: attr_span } => { + AttributeKind::ExportName { name, .. } => { codegen_fn_attrs.export_name = Some(*name); - mixed_export_name_no_mangle_lint_state.track_export_name(*attr_span); } AttributeKind::Naked(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED, 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, @@ -437,8 +430,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } } - mixed_export_name_no_mangle_lint_state.lint_if_mixed(tcx); - // Apply the minimum function alignment here, so that individual backends don't have to. codegen_fn_attrs.alignment = Ord::max(codegen_fn_attrs.alignment, tcx.sess.opts.unstable_opts.min_function_alignment); @@ -665,49 +656,6 @@ fn check_link_name_xor_ordinal( } } -#[derive(Default)] -struct MixedExportNameAndNoMangleState<'a> { - export_name: Option, - hir_id: Option, - no_mangle: Option, - no_mangle_attr: Option<&'a hir::Attribute>, -} - -impl<'a> MixedExportNameAndNoMangleState<'a> { - fn track_export_name(&mut self, span: Span) { - self.export_name = Some(span); - } - - fn track_no_mangle(&mut self, span: Span, hir_id: HirId, attr_name: &'a hir::Attribute) { - self.no_mangle = Some(span); - self.hir_id = Some(hir_id); - self.no_mangle_attr = Some(attr_name); - } - - /// Emit diagnostics if the lint condition is met. - fn lint_if_mixed(self, tcx: TyCtxt<'_>) { - if let Self { - export_name: Some(export_name), - no_mangle: Some(no_mangle), - hir_id: Some(hir_id), - no_mangle_attr: Some(_), - } = self - { - tcx.emit_node_span_lint( - lint::builtin::UNUSED_ATTRIBUTES, - hir_id, - no_mangle, - errors::MixedExportNameAndNoMangle { - no_mangle, - no_mangle_attr: "#[unsafe(no_mangle)]".to_string(), - export_name, - removal_span: no_mangle, - }, - ); - } - } -} - /// We now check the #\[rustc_autodiff\] attributes which we generated from the #[autodiff(...)] /// macros. There are two forms. The pure one without args to mark primal functions (the functions /// being differentiated). The other form is #[rustc_autodiff(Mode, ActivityList)] on top of the diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 315d9c92ab0..db536af0162 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -1200,18 +1200,6 @@ pub(crate) struct ErrorCreatingImportLibrary<'a> { #[diag(codegen_ssa_aix_strip_not_used)] pub(crate) struct AixStripNotUsed; -#[derive(LintDiagnostic)] -#[diag(codegen_ssa_mixed_export_name_and_no_mangle)] -pub(crate) struct MixedExportNameAndNoMangle { - #[label] - pub no_mangle: Span, - pub no_mangle_attr: String, - #[note] - pub export_name: Span, - #[suggestion(style = "verbose", code = "", applicability = "machine-applicable")] - pub removal_span: Span, -} - #[derive(Diagnostic, Debug)] pub(crate) enum XcrunError { #[diag(codegen_ssa_xcrun_failed_invoking)] diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index f601d058b33..e2995daadfe 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -486,6 +486,11 @@ passes_missing_panic_handler = passes_missing_stability_attr = {$descr} has missing stability attribute +passes_mixed_export_name_and_no_mangle = `{$no_mangle_attr}` attribute may not be used in combination with `{$export_name_attr}` + .label = `{$no_mangle_attr}` is ignored + .note = `{$export_name_attr}` takes precedence + .suggestion = remove the `{$no_mangle_attr}` attribute + passes_multiple_rustc_main = multiple functions with a `#[rustc_main]` attribute .first = first `#[rustc_main]` function diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 7c985fa9f03..491b3699f4c 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -30,11 +30,13 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, TyCtxt, TypingMode}; use rustc_middle::{bug, span_bug}; use rustc_session::config::CrateType; +use rustc_session::lint; use rustc_session::lint::builtin::{ CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, INVALID_MACRO_EXPORT_ARGUMENTS, UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES, }; use rustc_session::parse::feature_err; +use rustc_span::edition::Edition; use rustc_span::{BytePos, DUMMY_SP, Span, Symbol, edition, sym}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs}; @@ -403,6 +405,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { 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_mix_no_mangle_export(hir_id, attrs); } fn inline_attr_str_error_with_macro_def(&self, hir_id: HirId, attr_span: Span, sym: &str) { @@ -2628,6 +2631,36 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } + fn check_mix_no_mangle_export(&self, hir_id: HirId, attrs: &[Attribute]) { + if let Some(export_name_span) = find_attr!(attrs, AttributeKind::ExportName { span: export_name_span, .. } => *export_name_span) + && let Some(no_mangle_span) = + find_attr!(attrs, AttributeKind::NoMangle(no_mangle_span) => *no_mangle_span) + { + let no_mangle_attr = if no_mangle_span.edition() >= Edition::Edition2024 { + "#[unsafe(no_mangle)]" + } else { + "#[no_mangle]" + }; + let export_name_attr = if export_name_span.edition() >= Edition::Edition2024 { + "#[unsafe(export_name)]" + } else { + "#[export_name]" + }; + + self.tcx.emit_node_span_lint( + lint::builtin::UNUSED_ATTRIBUTES, + hir_id, + no_mangle_span, + errors::MixedExportNameAndNoMangle { + no_mangle_span, + export_name_span, + no_mangle_attr, + export_name_attr, + }, + ); + } + } + /// 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) { debug!("check_autodiff"); diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index d9ec167aae3..3286ccc94f2 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -49,6 +49,18 @@ pub(crate) struct ConstContinueAttr { pub node_span: Span, } +#[derive(LintDiagnostic)] +#[diag(passes_mixed_export_name_and_no_mangle)] +pub(crate) struct MixedExportNameAndNoMangle { + #[label] + #[suggestion(style = "verbose", code = "", applicability = "machine-applicable")] + pub no_mangle_span: Span, + #[note] + pub export_name_span: Span, + pub no_mangle_attr: &'static str, + pub export_name_attr: &'static str, +} + #[derive(LintDiagnostic)] #[diag(passes_outer_crate_level_attr)] pub(crate) struct OuterCrateLevelAttr; diff --git a/tests/ui/attributes/mixed_export_name_and_no_mangle.fixed b/tests/ui/attributes/mixed_export_name_and_no_mangle.fixed index d8b5235c52f..55c196f6dec 100644 --- a/tests/ui/attributes/mixed_export_name_and_no_mangle.fixed +++ b/tests/ui/attributes/mixed_export_name_and_no_mangle.fixed @@ -3,11 +3,11 @@ //@ check-pass #![warn(unused_attributes)] -//~^ WARN `#[unsafe(no_mangle)]` attribute may not be used in combination with `#[export_name]` [unused_attributes] +//~^ WARN `#[no_mangle]` attribute may not be used in combination with `#[export_name]` [unused_attributes] #[export_name = "foo"] pub fn bar() {} -//~^ WARN `#[unsafe(no_mangle)]` attribute may not be used in combination with `#[export_name]` [unused_attributes] +//~^ WARN `#[no_mangle]` attribute may not be used in combination with `#[export_name]` [unused_attributes] #[export_name = "baz"] pub fn bak() {} diff --git a/tests/ui/attributes/mixed_export_name_and_no_mangle.rs b/tests/ui/attributes/mixed_export_name_and_no_mangle.rs index 83a673a7d13..79f1e5c19c5 100644 --- a/tests/ui/attributes/mixed_export_name_and_no_mangle.rs +++ b/tests/ui/attributes/mixed_export_name_and_no_mangle.rs @@ -4,12 +4,12 @@ #![warn(unused_attributes)] #[no_mangle] -//~^ WARN `#[unsafe(no_mangle)]` attribute may not be used in combination with `#[export_name]` [unused_attributes] +//~^ WARN `#[no_mangle]` attribute may not be used in combination with `#[export_name]` [unused_attributes] #[export_name = "foo"] pub fn bar() {} #[unsafe(no_mangle)] -//~^ WARN `#[unsafe(no_mangle)]` attribute may not be used in combination with `#[export_name]` [unused_attributes] +//~^ WARN `#[no_mangle]` attribute may not be used in combination with `#[export_name]` [unused_attributes] #[export_name = "baz"] pub fn bak() {} diff --git a/tests/ui/attributes/mixed_export_name_and_no_mangle.stderr b/tests/ui/attributes/mixed_export_name_and_no_mangle.stderr index c760d27db25..1dcaa636800 100644 --- a/tests/ui/attributes/mixed_export_name_and_no_mangle.stderr +++ b/tests/ui/attributes/mixed_export_name_and_no_mangle.stderr @@ -1,8 +1,8 @@ -warning: `#[unsafe(no_mangle)]` attribute may not be used in combination with `#[export_name]` +warning: `#[no_mangle]` attribute may not be used in combination with `#[export_name]` --> $DIR/mixed_export_name_and_no_mangle.rs:6:1 | LL | #[no_mangle] - | ^^^^^^^^^^^^ `#[unsafe(no_mangle)]` is ignored + | ^^^^^^^^^^^^ `#[no_mangle]` is ignored | note: `#[export_name]` takes precedence --> $DIR/mixed_export_name_and_no_mangle.rs:8:1 @@ -14,23 +14,23 @@ note: the lint level is defined here | LL | #![warn(unused_attributes)] | ^^^^^^^^^^^^^^^^^ -help: remove the `#[unsafe(no_mangle)]` attribute +help: remove the `#[no_mangle]` attribute | LL - #[no_mangle] | -warning: `#[unsafe(no_mangle)]` attribute may not be used in combination with `#[export_name]` +warning: `#[no_mangle]` attribute may not be used in combination with `#[export_name]` --> $DIR/mixed_export_name_and_no_mangle.rs:11:1 | LL | #[unsafe(no_mangle)] - | ^^^^^^^^^^^^^^^^^^^^ `#[unsafe(no_mangle)]` is ignored + | ^^^^^^^^^^^^^^^^^^^^ `#[no_mangle]` is ignored | note: `#[export_name]` takes precedence --> $DIR/mixed_export_name_and_no_mangle.rs:13:1 | LL | #[export_name = "baz"] | ^^^^^^^^^^^^^^^^^^^^^^ -help: remove the `#[unsafe(no_mangle)]` attribute +help: remove the `#[no_mangle]` attribute | LL - #[unsafe(no_mangle)] | diff --git a/tests/ui/attributes/mixed_export_name_and_no_mangle_2024.fixed b/tests/ui/attributes/mixed_export_name_and_no_mangle_2024.fixed new file mode 100644 index 00000000000..581cb200770 --- /dev/null +++ b/tests/ui/attributes/mixed_export_name_and_no_mangle_2024.fixed @@ -0,0 +1,15 @@ +// issue: rust-lang/rust#47446 +//@ run-rustfix +//@ check-pass +//@ edition:2024 + +#![warn(unused_attributes)] +//~^ WARN `#[unsafe(no_mangle)]` attribute may not be used in combination with `#[unsafe(export_name)]` [unused_attributes] +#[unsafe(export_name = "foo")] +pub fn bar() {} + +//~^ WARN `#[unsafe(no_mangle)]` attribute may not be used in combination with `#[unsafe(export_name)]` [unused_attributes] +#[unsafe(export_name = "baz")] +pub fn bak() {} + +fn main() {} diff --git a/tests/ui/attributes/mixed_export_name_and_no_mangle_2024.rs b/tests/ui/attributes/mixed_export_name_and_no_mangle_2024.rs new file mode 100644 index 00000000000..1e4a06132f2 --- /dev/null +++ b/tests/ui/attributes/mixed_export_name_and_no_mangle_2024.rs @@ -0,0 +1,17 @@ +// issue: rust-lang/rust#47446 +//@ run-rustfix +//@ check-pass +//@ edition:2024 + +#![warn(unused_attributes)] +#[unsafe(no_mangle)] +//~^ WARN `#[unsafe(no_mangle)]` attribute may not be used in combination with `#[unsafe(export_name)]` [unused_attributes] +#[unsafe(export_name = "foo")] +pub fn bar() {} + +#[unsafe(no_mangle)] +//~^ WARN `#[unsafe(no_mangle)]` attribute may not be used in combination with `#[unsafe(export_name)]` [unused_attributes] +#[unsafe(export_name = "baz")] +pub fn bak() {} + +fn main() {} diff --git a/tests/ui/attributes/mixed_export_name_and_no_mangle_2024.stderr b/tests/ui/attributes/mixed_export_name_and_no_mangle_2024.stderr new file mode 100644 index 00000000000..09804f9f92b --- /dev/null +++ b/tests/ui/attributes/mixed_export_name_and_no_mangle_2024.stderr @@ -0,0 +1,39 @@ +warning: `#[unsafe(no_mangle)]` attribute may not be used in combination with `#[unsafe(export_name)]` + --> $DIR/mixed_export_name_and_no_mangle_2024.rs:7:1 + | +LL | #[unsafe(no_mangle)] + | ^^^^^^^^^^^^^^^^^^^^ `#[unsafe(no_mangle)]` is ignored + | +note: `#[unsafe(export_name)]` takes precedence + --> $DIR/mixed_export_name_and_no_mangle_2024.rs:9:1 + | +LL | #[unsafe(export_name = "foo")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: the lint level is defined here + --> $DIR/mixed_export_name_and_no_mangle_2024.rs:6:9 + | +LL | #![warn(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ +help: remove the `#[unsafe(no_mangle)]` attribute + | +LL - #[unsafe(no_mangle)] + | + +warning: `#[unsafe(no_mangle)]` attribute may not be used in combination with `#[unsafe(export_name)]` + --> $DIR/mixed_export_name_and_no_mangle_2024.rs:12:1 + | +LL | #[unsafe(no_mangle)] + | ^^^^^^^^^^^^^^^^^^^^ `#[unsafe(no_mangle)]` is ignored + | +note: `#[unsafe(export_name)]` takes precedence + --> $DIR/mixed_export_name_and_no_mangle_2024.rs:14:1 + | +LL | #[unsafe(export_name = "baz")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: remove the `#[unsafe(no_mangle)]` attribute + | +LL - #[unsafe(no_mangle)] + | + +warning: 2 warnings emitted + -- cgit 1.4.1-3-g733a5 From 9e3568407234ba4b8fa772cb4acf8d18b12baa7c Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Wed, 25 Jun 2025 09:36:26 +0200 Subject: Port `#[used]` to new attribute parsing infrastructure Signed-off-by: Jonathan Brouwer --- .../rustc_attr_data_structures/src/attributes.rs | 14 ++++ .../src/encode_cross_crate.rs | 1 + .../src/attributes/codegen_attrs.rs | 83 +++++++++++++++++++++- compiler/rustc_attr_parsing/src/context.rs | 2 + compiler/rustc_codegen_ssa/messages.ftl | 2 - compiler/rustc_codegen_ssa/src/codegen_attrs.rs | 44 ++---------- compiler/rustc_codegen_ssa/src/errors.rs | 7 -- compiler/rustc_passes/messages.ftl | 3 - compiler/rustc_passes/src/check_attr.rs | 50 +++---------- compiler/rustc_passes/src/errors.rs | 7 -- tests/ui/attributes/used_with_arg.rs | 15 +++- tests/ui/attributes/used_with_arg.stderr | 39 ++++++++-- tests/ui/attributes/used_with_multi_args.rs | 2 +- tests/ui/attributes/used_with_multi_args.stderr | 16 ++++- tests/ui/lint/unused/unused-attr-duplicate.stderr | 24 +++---- 15 files changed, 185 insertions(+), 124 deletions(-) (limited to 'compiler/rustc_codegen_ssa/src/errors.rs') diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index d755afad59f..60a4f289306 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -131,6 +131,17 @@ impl Deprecation { } } +/// There are three valid forms of the attribute: +/// `#[used]`, which is semantically equivalent to `#[used(linker)]` except that the latter is currently unstable. +/// `#[used(compiler)]` +/// `#[used(linker)]` +#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(HashStable_Generic, PrintAttribute)] +pub enum UsedBy { + Compiler, + Linker, +} + /// Represents parsed *built-in* inert attributes. /// /// ## Overview @@ -285,5 +296,8 @@ pub enum AttributeKind { /// Represents `#[track_caller]` TrackCaller(Span), + + /// Represents `#[used]` + Used { used_by: UsedBy, span: Span }, // tidy-alphabetical-end } diff --git a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs index d4402f4e2e6..64bcf1fe6cc 100644 --- a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs +++ b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs @@ -38,6 +38,7 @@ impl AttributeKind { PubTransparent(..) => Yes, SkipDuringMethodDispatch { .. } => No, TrackCaller(..) => Yes, + Used { .. } => No, } } } diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 5a849e79cc3..7c412d4fa89 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -1,4 +1,4 @@ -use rustc_attr_data_structures::{AttributeKind, OptimizeAttr}; +use rustc_attr_data_structures::{AttributeKind, OptimizeAttr, UsedBy}; use rustc_feature::{AttributeTemplate, template}; use rustc_session::parse::feature_err; use rustc_span::{Span, Symbol, sym}; @@ -228,3 +228,84 @@ impl SingleAttributeParser for NoMangleParser { Some(AttributeKind::NoMangle(cx.attr_span)) } } + +#[derive(Default)] +pub(crate) struct UsedParser { + first_compiler: Option, + first_linker: Option, +} + +// A custom `AttributeParser` is used rather than a Simple attribute parser because +// - Specifying two `#[used]` attributes is a warning (but will be an error in the future) +// - But specifying two conflicting attributes: `#[used(compiler)]` and `#[used(linker)]` is already an error today +// We can change this to a Simple parser once the warning becomes an error +impl AttributeParser for UsedParser { + const ATTRIBUTES: AcceptMapping = &[( + &[sym::used], + template!(Word, List: "compiler|linker"), + |group: &mut Self, cx, args| { + let used_by = match args { + ArgParser::NoArgs => UsedBy::Linker, + ArgParser::List(list) => { + let Some(l) = list.single() else { + cx.expected_single_argument(list.span); + return; + }; + + match l.meta_item().and_then(|i| i.path().word_sym()) { + Some(sym::compiler) => { + if !cx.features().used_with_arg() { + feature_err( + &cx.sess(), + sym::used_with_arg, + cx.attr_span, + "`#[used(compiler)]` is currently unstable", + ) + .emit(); + } + UsedBy::Compiler + } + Some(sym::linker) => { + if !cx.features().used_with_arg() { + feature_err( + &cx.sess(), + sym::used_with_arg, + cx.attr_span, + "`#[used(linker)]` is currently unstable", + ) + .emit(); + } + UsedBy::Linker + } + _ => { + cx.expected_specific_argument(l.span(), vec!["compiler", "linker"]); + return; + } + } + } + ArgParser::NameValue(_) => return, + }; + + let target = match used_by { + UsedBy::Compiler => &mut group.first_compiler, + UsedBy::Linker => &mut group.first_linker, + }; + + let attr_span = cx.attr_span; + if let Some(prev) = *target { + cx.warn_unused_duplicate(prev, attr_span); + } else { + *target = Some(attr_span); + } + }, + )]; + + fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { + // Ratcheting behaviour, if both `linker` and `compiler` are specified, use `linker` + Some(match (self.first_compiler, self.first_linker) { + (_, Some(span)) => AttributeKind::Used { used_by: UsedBy::Linker, span }, + (Some(span), _) => AttributeKind::Used { used_by: UsedBy::Compiler, span }, + (None, None) => return None, + }) + } +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 83e3c75dedb..71bb86ca3d3 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -17,6 +17,7 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser}; use crate::attributes::codegen_attrs::{ ColdParser, ExportNameParser, NakedParser, NoMangleParser, OptimizeParser, TrackCallerParser, + UsedParser, }; use crate::attributes::confusables::ConfusablesParser; use crate::attributes::deprecation::DeprecationParser; @@ -103,6 +104,7 @@ attribute_parsers!( ConstStabilityParser, NakedParser, StabilityParser, + UsedParser, // tidy-alphabetical-end // tidy-alphabetical-start diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 6362d2edf85..84d63819343 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -48,8 +48,6 @@ codegen_ssa_error_writing_def_file = codegen_ssa_expected_name_value_pair = expected name value pair -codegen_ssa_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)` - codegen_ssa_extern_funcs_not_found = some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified codegen_ssa_extract_bundled_libs_archive_member = failed to get data from archive member '{$rlib}': {$error} diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 94df5e8b361..716b2d76c62 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -4,7 +4,7 @@ use rustc_abi::ExternAbi; use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode}; use rustc_ast::{LitKind, MetaItem, MetaItemInner, attr}; use rustc_attr_data_structures::{ - AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr, ReprAttr, find_attr, + AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr, ReprAttr, UsedBy, find_attr, }; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; @@ -160,6 +160,10 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER } + AttributeKind::Used { used_by, .. } => match used_by { + UsedBy::Compiler => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_COMPILER, + UsedBy::Linker => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER, + }, _ => {} } } @@ -181,44 +185,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { sym::rustc_std_internal_symbol => { codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL } - sym::used => { - let inner = attr.meta_item_list(); - match inner.as_deref() { - Some([item]) if item.has_name(sym::linker) => { - if !tcx.features().used_with_arg() { - feature_err( - &tcx.sess, - sym::used_with_arg, - attr.span(), - "`#[used(linker)]` is currently unstable", - ) - .emit(); - } - codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER; - } - Some([item]) if item.has_name(sym::compiler) => { - if !tcx.features().used_with_arg() { - feature_err( - &tcx.sess, - sym::used_with_arg, - attr.span(), - "`#[used(compiler)]` is currently unstable", - ) - .emit(); - } - codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_COMPILER; - } - Some(_) => { - tcx.dcx().emit_err(errors::ExpectedUsedSymbol { span: attr.span() }); - } - None => { - // Unconditionally using `llvm.used` causes issues in handling - // `.init_array` with the gold linker. Luckily gold has been - // deprecated with GCC 15 and rustc now warns about using gold. - codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER - } - } - } sym::thread_local => codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL, sym::target_feature => { let Some(sig) = tcx.hir_node_by_def_id(did).fn_sig() else { diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index db536af0162..1950a35b364 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -726,13 +726,6 @@ pub struct UnknownArchiveKind<'a> { pub kind: &'a str, } -#[derive(Diagnostic)] -#[diag(codegen_ssa_expected_used_symbol)] -pub(crate) struct ExpectedUsedSymbol { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(codegen_ssa_multiple_main_functions)] #[help] diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index e2995daadfe..b1c7b0fcd6c 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -816,9 +816,6 @@ passes_unused_variable_try_prefix = unused variable: `{$name}` .suggestion = if this is intentional, prefix it with an underscore -passes_used_compiler_linker = - `used(compiler)` and `used(linker)` can't be used together - passes_used_static = attribute must be applied to a `static` variable .label = but this is a {$target} diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 491b3699f4c..877bb9be289 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -200,6 +200,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::NoMangle(attr_span)) => { self.check_no_mangle(hir_id, *attr_span, span, target) } + Attribute::Parsed(AttributeKind::Used { span: attr_span, .. }) => { + self.check_used(*attr_span, target, span); + } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); match attr.path().as_slice() { @@ -333,7 +336,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::cfi_encoding // FIXME(cfi_encoding) | sym::pointee // FIXME(derive_coerce_pointee) | sym::omit_gdb_pretty_printer_section // FIXME(omit_gdb_pretty_printer_section) - | sym::used // handled elsewhere to restrict to static items | sym::instruction_set // broken on stable!!! | sym::windows_subsystem // broken on stable!!! | sym::patchable_function_entry // FIXME(patchable_function_entry) @@ -403,7 +405,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } 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_mix_no_mangle_export(hir_id, attrs); } @@ -2107,44 +2108,13 @@ 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)) { - if target != Target::Static { - self.dcx().emit_err(errors::UsedStatic { - attr_span: attr.span(), - span: target_span, - target: target.name(), - }); - } - let inner = attr.meta_item_list(); - match inner.as_deref() { - Some([item]) if item.has_name(sym::linker) => { - if used_linker_span.is_none() { - used_linker_span = Some(attr.span()); - } - } - Some([item]) if item.has_name(sym::compiler) => { - if used_compiler_span.is_none() { - used_compiler_span = Some(attr.span()); - } - } - Some(_) => { - // This error case is handled in rustc_hir_analysis::collect. - } - None => { - // Default case (compiler) when arg isn't defined. - if used_compiler_span.is_none() { - used_compiler_span = Some(attr.span()); - } - } - } - } - if let (Some(linker_span), Some(compiler_span)) = (used_linker_span, used_compiler_span) { - self.tcx - .dcx() - .emit_err(errors::UsedCompilerLinker { spans: vec![linker_span, compiler_span] }); + fn check_used(&self, attr_span: Span, target: Target, target_span: Span) { + if target != Target::Static { + self.dcx().emit_err(errors::UsedStatic { + attr_span, + span: target_span, + target: target.name(), + }); } } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 3286ccc94f2..f89d925202c 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -641,13 +641,6 @@ pub(crate) struct UsedStatic { pub target: &'static str, } -#[derive(Diagnostic)] -#[diag(passes_used_compiler_linker)] -pub(crate) struct UsedCompilerLinker { - #[primary_span] - pub spans: Vec, -} - #[derive(Diagnostic)] #[diag(passes_allow_internal_unstable)] pub(crate) struct AllowInternalUnstable { diff --git a/tests/ui/attributes/used_with_arg.rs b/tests/ui/attributes/used_with_arg.rs index ad80ff53f0e..bc7a6f07442 100644 --- a/tests/ui/attributes/used_with_arg.rs +++ b/tests/ui/attributes/used_with_arg.rs @@ -1,3 +1,4 @@ +#![deny(unused_attributes)] #![feature(used_with_arg)] #[used(linker)] @@ -6,14 +7,22 @@ static mut USED_LINKER: [usize; 1] = [0]; #[used(compiler)] static mut USED_COMPILER: [usize; 1] = [0]; -#[used(compiler)] //~ ERROR `used(compiler)` and `used(linker)` can't be used together +#[used(compiler)] #[used(linker)] static mut USED_COMPILER_LINKER2: [usize; 1] = [0]; -#[used(compiler)] //~ ERROR `used(compiler)` and `used(linker)` can't be used together -#[used(linker)] #[used(compiler)] #[used(linker)] +#[used(compiler)] //~ ERROR unused attribute +#[used(linker)] //~ ERROR unused attribute static mut USED_COMPILER_LINKER3: [usize; 1] = [0]; +#[used(compiler)] +#[used] +static mut USED_WITHOUT_ATTR1: [usize; 1] = [0]; + +#[used(linker)] +#[used] //~ ERROR unused attribute +static mut USED_WITHOUT_ATTR2: [usize; 1] = [0]; + fn main() {} diff --git a/tests/ui/attributes/used_with_arg.stderr b/tests/ui/attributes/used_with_arg.stderr index 440e5c4a5a0..9ff91a4e03b 100644 --- a/tests/ui/attributes/used_with_arg.stderr +++ b/tests/ui/attributes/used_with_arg.stderr @@ -1,18 +1,43 @@ -error: `used(compiler)` and `used(linker)` can't be used together - --> $DIR/used_with_arg.rs:9:1 +error: unused attribute + --> $DIR/used_with_arg.rs:16:1 + | +LL | #[used(compiler)] + | ^^^^^^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/used_with_arg.rs:14:1 | LL | #[used(compiler)] | ^^^^^^^^^^^^^^^^^ +note: the lint level is defined here + --> $DIR/used_with_arg.rs:1:9 + | +LL | #![deny(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ + +error: unused attribute + --> $DIR/used_with_arg.rs:17:1 + | +LL | #[used(linker)] + | ^^^^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/used_with_arg.rs:15:1 + | LL | #[used(linker)] | ^^^^^^^^^^^^^^^ -error: `used(compiler)` and `used(linker)` can't be used together - --> $DIR/used_with_arg.rs:13:1 +error: unused attribute + --> $DIR/used_with_arg.rs:25:1 + | +LL | #[used] + | ^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/used_with_arg.rs:24:1 | -LL | #[used(compiler)] - | ^^^^^^^^^^^^^^^^^ LL | #[used(linker)] | ^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors diff --git a/tests/ui/attributes/used_with_multi_args.rs b/tests/ui/attributes/used_with_multi_args.rs index d3109cc6444..1c054f792eb 100644 --- a/tests/ui/attributes/used_with_multi_args.rs +++ b/tests/ui/attributes/used_with_multi_args.rs @@ -1,6 +1,6 @@ #![feature(used_with_arg)] -#[used(compiler, linker)] //~ ERROR expected `used`, `used(compiler)` or `used(linker)` +#[used(compiler, linker)] //~ ERROR malformed `used` attribute input static mut USED_COMPILER_LINKER: [usize; 1] = [0]; fn main() {} diff --git a/tests/ui/attributes/used_with_multi_args.stderr b/tests/ui/attributes/used_with_multi_args.stderr index d4417a202d5..e48209cf204 100644 --- a/tests/ui/attributes/used_with_multi_args.stderr +++ b/tests/ui/attributes/used_with_multi_args.stderr @@ -1,8 +1,20 @@ -error: expected `used`, `used(compiler)` or `used(linker)` +error[E0805]: malformed `used` attribute input --> $DIR/used_with_multi_args.rs:3:1 | LL | #[used(compiler, linker)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^------------------^ + | | + | expected a single argument here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[used(compiler, linker)] +LL + #[used(compiler|linker)] + | +LL - #[used(compiler, linker)] +LL + #[used] + | error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0805`. diff --git a/tests/ui/lint/unused/unused-attr-duplicate.stderr b/tests/ui/lint/unused/unused-attr-duplicate.stderr index 3a520ffcb3d..a18581192ea 100644 --- a/tests/ui/lint/unused/unused-attr-duplicate.stderr +++ b/tests/ui/lint/unused/unused-attr-duplicate.stderr @@ -89,18 +89,6 @@ note: attribute also specified here LL | #[automatically_derived] | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: unused attribute - --> $DIR/unused-attr-duplicate.rs:102:1 - | -LL | #[used] - | ^^^^^^^ help: remove this attribute - | -note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:101:1 - | -LL | #[used] - | ^^^^^^^ - error: unused attribute --> $DIR/unused-attr-duplicate.rs:86:5 | @@ -289,5 +277,17 @@ note: attribute also specified here LL | #[no_mangle] | ^^^^^^^^^^^^ +error: unused attribute + --> $DIR/unused-attr-duplicate.rs:102:1 + | +LL | #[used] + | ^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/unused-attr-duplicate.rs:101:1 + | +LL | #[used] + | ^^^^^^^ + error: aborting due to 23 previous errors -- cgit 1.4.1-3-g733a5