about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSven Kanoldt <sven+oss@d34dl0ck.me>2024-10-09 14:24:15 +0200
committerSven Kanoldt <sven@d34dl0ck.me>2024-11-15 15:25:19 +0100
commit1696f534abe0655ee43ed57972a62d1cce42c233 (patch)
tree82216ade3ea3ebce9a4a164903cf4d0a9aa0b932
parentf00f68245ebe85960000adaab18c1fe8da104cfe (diff)
downloadrust-1696f534abe0655ee43ed57972a62d1cce42c233.tar.gz
rust-1696f534abe0655ee43ed57972a62d1cce42c233.zip
fix: rust-lang/rust#47446
- Add test for issue 47446
- Implement the new lint lint_builtin_mixed_export_name_and_no_mangle
- Add suggestion how to fix it
-rw-r--r--Cargo.lock1
-rw-r--r--compiler/rustc_codegen_ssa/Cargo.toml1
-rw-r--r--compiler/rustc_codegen_ssa/messages.ftl5
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs57
-rw-r--r--compiler/rustc_codegen_ssa/src/errors.rs14
-rw-r--r--tests/ui/asm/naked-functions.rs1
-rw-r--r--tests/ui/attributes/mixed_export_name_and_no_mangle.fixed14
-rw-r--r--tests/ui/attributes/mixed_export_name_and_no_mangle.rs16
-rw-r--r--tests/ui/attributes/mixed_export_name_and_no_mangle.stderr39
9 files changed, 143 insertions, 5 deletions
diff --git a/Cargo.lock b/Cargo.lock
index b98c4fd0642..762f98cd4ac 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3453,6 +3453,7 @@ dependencies = [
  "rustc_abi",
  "rustc_arena",
  "rustc_ast",
+ "rustc_ast_pretty",
  "rustc_attr",
  "rustc_data_structures",
  "rustc_errors",
diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml
index b898cfec796..01cf9369df7 100644
--- a/compiler/rustc_codegen_ssa/Cargo.toml
+++ b/compiler/rustc_codegen_ssa/Cargo.toml
@@ -17,6 +17,7 @@ regex = "1.4"
 rustc_abi = { path = "../rustc_abi" }
 rustc_arena = { path = "../rustc_arena" }
 rustc_ast = { path = "../rustc_ast" }
+rustc_ast_pretty = { path = "../rustc_ast_pretty" }
 rustc_attr = { path = "../rustc_attr" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl
index 62db3d5a98c..56188714b44 100644
--- a/compiler/rustc_codegen_ssa/messages.ftl
+++ b/compiler/rustc_codegen_ssa/messages.ftl
@@ -201,6 +201,11 @@ codegen_ssa_missing_memory_ordering = Atomic intrinsic missing memory ordering
 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 32e9422e005..59c543bb397 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -3,11 +3,10 @@ use rustc_attr::{InlineAttr, InstructionSetAttr, OptimizeAttr, list_contains_nam
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::codes::*;
 use rustc_errors::{DiagMessage, SubdiagMessage, struct_span_code_err};
-use rustc_hir as hir;
 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::{LangItem, lang_items};
+use rustc_hir::{self as hir, HirId, LangItem, lang_items};
 use rustc_middle::middle::codegen_fn_attrs::{
     CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry,
 };
@@ -78,6 +77,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
     let mut inline_span = None;
     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`
@@ -116,7 +116,12 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
             sym::naked => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED,
             sym::no_mangle => {
                 if tcx.opt_item_name(did.to_def_id()).is_some() {
-                    codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE
+                    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),
+                        rustc_ast_pretty::pprust::attribute_to_string(attr),
+                    );
                 } else {
                     tcx.dcx()
                         .struct_span_err(
@@ -240,6 +245,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                         .emit();
                     }
                     codegen_fn_attrs.export_name = Some(s);
+                    mixed_export_name_no_mangle_lint_state.track_export_name(attr.span);
                 }
             }
             sym::target_feature => {
@@ -513,6 +519,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
         }
     }
 
+    mixed_export_name_no_mangle_lint_state.lint_if_mixed(tcx);
+
     codegen_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| {
         if !attr.has_name(sym::inline) {
             return ia;
@@ -779,6 +787,49 @@ fn check_link_name_xor_ordinal(
     }
 }
 
+#[derive(Default)]
+struct MixedExportNameAndNoMangleState {
+    export_name: Option<Span>,
+    hir_id: Option<HirId>,
+    no_mangle: Option<Span>,
+    no_mangle_attr_name: Option<String>,
+}
+
+impl MixedExportNameAndNoMangleState {
+    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: String) {
+        self.no_mangle = Some(span);
+        self.hir_id = Some(hir_id);
+        self.no_mangle_attr_name = 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_name: Some(no_mangle_attr_name),
+        } = self
+        {
+            tcx.emit_node_span_lint(
+                lint::builtin::UNUSED_ATTRIBUTES,
+                hir_id,
+                no_mangle,
+                errors::MixedExportNameAndNoMangle {
+                    no_mangle,
+                    no_mangle_attr: no_mangle_attr_name,
+                    export_name,
+                    removal_span: no_mangle,
+                },
+            );
+        }
+    }
+}
+
 pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers { codegen_fn_attrs, should_inherit_track_caller, ..*providers };
 }
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index f93cb52ea3e..00f8654e670 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -10,7 +10,7 @@ use rustc_errors::codes::*;
 use rustc_errors::{
     Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level,
 };
-use rustc_macros::{Diagnostic, Subdiagnostic};
+use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_middle::ty::Ty;
 use rustc_middle::ty::layout::LayoutError;
 use rustc_span::{Span, Symbol};
@@ -1114,3 +1114,15 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for TargetFeatureDisableOrEnable<'_
 #[derive(Diagnostic)]
 #[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,
+}
diff --git a/tests/ui/asm/naked-functions.rs b/tests/ui/asm/naked-functions.rs
index 5c58f1498cc..e7e5d84f2a5 100644
--- a/tests/ui/asm/naked-functions.rs
+++ b/tests/ui/asm/naked-functions.rs
@@ -219,7 +219,6 @@ pub unsafe extern "C" fn compatible_must_use_attributes() -> u64 {
 
 #[export_name = "exported_function_name"]
 #[link_section = ".custom_section"]
-#[no_mangle]
 #[naked]
 pub unsafe extern "C" fn compatible_ffi_attributes_1() {
     naked_asm!("", options(raw));
diff --git a/tests/ui/attributes/mixed_export_name_and_no_mangle.fixed b/tests/ui/attributes/mixed_export_name_and_no_mangle.fixed
new file mode 100644
index 00000000000..7224d4289e3
--- /dev/null
+++ b/tests/ui/attributes/mixed_export_name_and_no_mangle.fixed
@@ -0,0 +1,14 @@
+// issue: rust-lang/rust#47446
+//@ run-rustfix
+//@ check-pass
+
+#![warn(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]
+#[export_name = "baz"]
+pub fn bak() {}
+
+fn main() {}
diff --git a/tests/ui/attributes/mixed_export_name_and_no_mangle.rs b/tests/ui/attributes/mixed_export_name_and_no_mangle.rs
new file mode 100644
index 00000000000..149a7904e1e
--- /dev/null
+++ b/tests/ui/attributes/mixed_export_name_and_no_mangle.rs
@@ -0,0 +1,16 @@
+// issue: rust-lang/rust#47446
+//@ run-rustfix
+//@ check-pass
+
+#![warn(unused_attributes)]
+#[no_mangle]
+//~^ 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]
+#[export_name = "baz"]
+pub fn bak() {}
+
+fn main() {}
diff --git a/tests/ui/attributes/mixed_export_name_and_no_mangle.stderr b/tests/ui/attributes/mixed_export_name_and_no_mangle.stderr
new file mode 100644
index 00000000000..ba63127ba2d
--- /dev/null
+++ b/tests/ui/attributes/mixed_export_name_and_no_mangle.stderr
@@ -0,0 +1,39 @@
+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]
+   | ^^^^^^^^^^^^ `#[no_mangle]` is ignored
+   |
+note: `#[export_name]` takes precedence
+  --> $DIR/mixed_export_name_and_no_mangle.rs:8:1
+   |
+LL | #[export_name = "foo"]
+   | ^^^^^^^^^^^^^^^^^^^^^^
+note: the lint level is defined here
+  --> $DIR/mixed_export_name_and_no_mangle.rs:5:9
+   |
+LL | #![warn(unused_attributes)]
+   |         ^^^^^^^^^^^^^^^^^
+help: remove the `#[no_mangle]` attribute
+   |
+LL - #[no_mangle]
+   |
+
+warning: `#[unsafe(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
+   |
+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
+   |
+LL - #[unsafe(no_mangle)]
+   |
+
+warning: 2 warnings emitted
+