about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMu001999 <mu001999@outlook.com>2025-05-10 09:55:50 +0800
committerMu001999 <mu001999@outlook.com>2025-05-10 18:48:32 +0800
commit0de994a368e9225fab812a7295f9350285cd55d3 (patch)
tree00fd371e7569f8c1898f029f65a4440f3d08bdfe
parent7e552b46af72df390ed233b58a7f51650515b2a8 (diff)
downloadrust-0de994a368e9225fab812a7295f9350285cd55d3.tar.gz
rust-0de994a368e9225fab812a7295f9350285cd55d3.zip
Warn when #[export_name] is used with generic functions
-rw-r--r--compiler/rustc_lint/src/builtin.rs27
-rw-r--r--tests/ui/generics/export-name-on-generics.fixed157
-rw-r--r--tests/ui/generics/export-name-on-generics.rs159
-rw-r--r--tests/ui/generics/export-name-on-generics.stderr144
4 files changed, 477 insertions, 10 deletions
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 41b43f64798..95e31e4af1e 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -976,6 +976,9 @@ declare_lint! {
     /// ```rust
     /// #[unsafe(no_mangle)]
     /// fn foo<T>(t: T) {}
+    ///
+    /// #[unsafe(export_name = "bar")]
+    /// fn bar<T>(t: T) {}
     /// ```
     ///
     /// {{produces}}
@@ -983,10 +986,11 @@ declare_lint! {
     /// ### Explanation
     ///
     /// A function with generics must have its symbol mangled to accommodate
-    /// the generic parameter. The [`no_mangle` attribute] has no effect in
-    /// this situation, and should be removed.
+    /// the generic parameter. The [`no_mangle`] and [`export_name`] attributes
+    /// have no effect in this situation, and should be removed.
     ///
-    /// [`no_mangle` attribute]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute
+    /// [`no_mangle`]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute
+    /// [`export_name`]: https://doc.rust-lang.org/reference/abi.html#the-export_name-attribute
     NO_MANGLE_GENERIC_ITEMS,
     Warn,
     "generic items must be mangled"
@@ -997,7 +1001,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 = |no_mangle_attr: &hir::Attribute,
+        let check_no_mangle_on_generic_fn = |attr: &hir::Attribute,
                                              impl_generics: Option<&hir::Generics<'_>>,
                                              generics: &hir::Generics<'_>,
                                              span| {
@@ -1010,7 +1014,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
                         cx.emit_span_lint(
                             NO_MANGLE_GENERIC_ITEMS,
                             span,
-                            BuiltinNoMangleGeneric { suggestion: no_mangle_attr.span() },
+                            BuiltinNoMangleGeneric { suggestion: attr.span() },
                         );
                         break;
                     }
@@ -1019,8 +1023,10 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
         };
         match it.kind {
             hir::ItemKind::Fn { generics, .. } => {
-                if let Some(no_mangle_attr) = attr::find_by_name(attrs, sym::no_mangle) {
-                    check_no_mangle_on_generic_fn(no_mangle_attr, None, generics, it.span);
+                if let Some(attr) = attr::find_by_name(attrs, sym::export_name)
+                    .or_else(|| attr::find_by_name(attrs, sym::no_mangle))
+                {
+                    check_no_mangle_on_generic_fn(attr, None, generics, it.span);
                 }
             }
             hir::ItemKind::Const(..) => {
@@ -1048,11 +1054,12 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
             hir::ItemKind::Impl(hir::Impl { generics, items, .. }) => {
                 for it in *items {
                     if let hir::AssocItemKind::Fn { .. } = it.kind {
-                        if let Some(no_mangle_attr) =
-                            attr::find_by_name(cx.tcx.hir_attrs(it.id.hir_id()), sym::no_mangle)
+                        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))
                         {
                             check_no_mangle_on_generic_fn(
-                                no_mangle_attr,
+                                attr,
                                 Some(generics),
                                 cx.tcx.hir_get_generics(it.id.owner_id.def_id).unwrap(),
                                 it.span,
diff --git a/tests/ui/generics/export-name-on-generics.fixed b/tests/ui/generics/export-name-on-generics.fixed
new file mode 100644
index 00000000000..4430cd9a299
--- /dev/null
+++ b/tests/ui/generics/export-name-on-generics.fixed
@@ -0,0 +1,157 @@
+//@ run-rustfix
+#![allow(dead_code, elided_named_lifetimes)]
+#![deny(no_mangle_generic_items)]
+
+pub fn foo<T>() {} //~ ERROR functions generic over types or consts must be mangled
+
+pub extern "C" fn bar<T>() {} //~ ERROR functions generic over types or consts must be mangled
+
+#[export_name = "baz"]
+pub fn baz(x: &i32) -> &i32 { x }
+
+#[export_name = "qux"]
+pub fn qux<'a>(x: &'a i32) -> &i32 { x }
+
+pub struct Foo;
+
+impl Foo {
+    
+    pub fn foo<T>() {} //~ ERROR functions generic over types or consts must be mangled
+
+    
+    pub extern "C" fn bar<T>() {} //~ ERROR functions generic over types or consts must be mangled
+
+    #[export_name = "baz"]
+    pub fn baz(x: &i32) -> &i32 { x }
+
+    #[export_name = "qux"]
+    pub fn qux<'a>(x: &'a i32) -> &i32 { x }
+}
+
+trait Trait1 {
+    fn foo<T>();
+    extern "C" fn bar<T>();
+    fn baz(x: &i32) -> &i32;
+    fn qux<'a>(x: &'a i32) -> &i32;
+}
+
+impl Trait1 for Foo {
+    
+    fn foo<T>() {} //~ ERROR functions generic over types or consts must be mangled
+
+    
+    extern "C" fn bar<T>() {} //~ ERROR functions generic over types or consts must be mangled
+
+    #[export_name = "baz"]
+    fn baz(x: &i32) -> &i32 { x }
+
+    #[export_name = "qux"]
+    fn qux<'a>(x: &'a i32) -> &i32 { x }
+}
+
+trait Trait2<T> {
+    fn foo();
+    fn foo2<U>();
+    extern "C" fn bar();
+    fn baz(x: &i32) -> &i32;
+    fn qux<'a>(x: &'a i32) -> &i32;
+}
+
+impl<T> Trait2<T> for Foo {
+    
+    fn foo() {} //~ ERROR functions generic over types or consts must be mangled
+
+    
+    fn foo2<U>() {} //~ ERROR functions generic over types or consts must be mangled
+
+    
+    extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled
+
+    
+    fn baz(x: &i32) -> &i32 { x } //~ ERROR functions generic over types or consts must be mangled
+
+    
+    fn qux<'a>(x: &'a i32) -> &i32 { x } //~ ERROR functions generic over types or consts must be mangled
+}
+
+pub struct Bar<T>(#[allow(dead_code)] T);
+
+impl<T> Bar<T> {
+    
+    pub fn foo() {} //~ ERROR functions generic over types or consts must be mangled
+
+    
+    pub extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled
+
+    
+    pub fn baz<U>() {} //~ ERROR functions generic over types or consts must be mangled
+}
+
+impl Bar<i32> {
+    #[export_name = "qux"]
+    pub fn qux() {}
+}
+
+trait Trait3 {
+    fn foo();
+    extern "C" fn bar();
+    fn baz<U>();
+}
+
+impl<T> Trait3 for Bar<T> {
+    
+    fn foo() {} //~ ERROR functions generic over types or consts must be mangled
+
+    
+    extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled
+
+    
+    fn baz<U>() {} //~ ERROR functions generic over types or consts must be mangled
+}
+
+pub struct Baz<'a>(#[allow(dead_code)] &'a i32);
+
+impl<'a> Baz<'a> {
+    #[export_name = "foo"]
+    pub fn foo() {}
+
+    #[export_name = "bar"]
+    pub fn bar<'b>(x: &'b i32) -> &i32 { x }
+}
+
+trait Trait4 {
+    fn foo();
+    fn bar<'a>(x: &'a i32) -> &i32;
+}
+
+impl Trait4 for Bar<i32> {
+    #[export_name = "foo"]
+    fn foo() {}
+
+    #[export_name = "bar"]
+    fn bar<'b>(x: &'b i32) -> &i32 { x }
+}
+
+impl<'a> Trait4 for Baz<'a> {
+    #[export_name = "foo"]
+    fn foo() {}
+
+    #[export_name = "bar"]
+    fn bar<'b>(x: &'b i32) -> &i32 { x }
+}
+
+trait Trait5<T> {
+    fn foo();
+}
+
+impl Trait5<i32> for Foo {
+    #[export_name = "foo"]
+    fn foo() {}
+}
+
+impl Trait5<i32> for Bar<i32> {
+    #[export_name = "foo"]
+    fn foo() {}
+}
+
+fn main() {}
diff --git a/tests/ui/generics/export-name-on-generics.rs b/tests/ui/generics/export-name-on-generics.rs
new file mode 100644
index 00000000000..cbf11021960
--- /dev/null
+++ b/tests/ui/generics/export-name-on-generics.rs
@@ -0,0 +1,159 @@
+//@ run-rustfix
+#![allow(dead_code, elided_named_lifetimes)]
+#![deny(no_mangle_generic_items)]
+
+#[export_name = "foo"]
+pub fn foo<T>() {} //~ ERROR functions generic over types or consts must be mangled
+
+#[export_name = "bar"]
+pub extern "C" fn bar<T>() {} //~ ERROR functions generic over types or consts must be mangled
+
+#[export_name = "baz"]
+pub fn baz(x: &i32) -> &i32 { x }
+
+#[export_name = "qux"]
+pub fn qux<'a>(x: &'a i32) -> &i32 { x }
+
+pub struct Foo;
+
+impl Foo {
+    #[export_name = "foo"]
+    pub fn foo<T>() {} //~ ERROR functions generic over types or consts must be mangled
+
+    #[export_name = "bar"]
+    pub extern "C" fn bar<T>() {} //~ ERROR functions generic over types or consts must be mangled
+
+    #[export_name = "baz"]
+    pub fn baz(x: &i32) -> &i32 { x }
+
+    #[export_name = "qux"]
+    pub fn qux<'a>(x: &'a i32) -> &i32 { x }
+}
+
+trait Trait1 {
+    fn foo<T>();
+    extern "C" fn bar<T>();
+    fn baz(x: &i32) -> &i32;
+    fn qux<'a>(x: &'a i32) -> &i32;
+}
+
+impl Trait1 for Foo {
+    #[export_name = "foo"]
+    fn foo<T>() {} //~ ERROR functions generic over types or consts must be mangled
+
+    #[export_name = "bar"]
+    extern "C" fn bar<T>() {} //~ ERROR functions generic over types or consts must be mangled
+
+    #[export_name = "baz"]
+    fn baz(x: &i32) -> &i32 { x }
+
+    #[export_name = "qux"]
+    fn qux<'a>(x: &'a i32) -> &i32 { x }
+}
+
+trait Trait2<T> {
+    fn foo();
+    fn foo2<U>();
+    extern "C" fn bar();
+    fn baz(x: &i32) -> &i32;
+    fn qux<'a>(x: &'a i32) -> &i32;
+}
+
+impl<T> Trait2<T> for Foo {
+    #[export_name = "foo"]
+    fn foo() {} //~ ERROR functions generic over types or consts must be mangled
+
+    #[export_name = "foo2"]
+    fn foo2<U>() {} //~ ERROR functions generic over types or consts must be mangled
+
+    #[export_name = "baz"]
+    extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled
+
+    #[export_name = "baz"]
+    fn baz(x: &i32) -> &i32 { x } //~ ERROR functions generic over types or consts must be mangled
+
+    #[export_name = "qux"]
+    fn qux<'a>(x: &'a i32) -> &i32 { x } //~ ERROR functions generic over types or consts must be mangled
+}
+
+pub struct Bar<T>(#[allow(dead_code)] T);
+
+impl<T> Bar<T> {
+    #[export_name = "foo"]
+    pub fn foo() {} //~ ERROR functions generic over types or consts must be mangled
+
+    #[export_name = "bar"]
+    pub extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled
+
+    #[export_name = "baz"]
+    pub fn baz<U>() {} //~ ERROR functions generic over types or consts must be mangled
+}
+
+impl Bar<i32> {
+    #[export_name = "qux"]
+    pub fn qux() {}
+}
+
+trait Trait3 {
+    fn foo();
+    extern "C" fn bar();
+    fn baz<U>();
+}
+
+impl<T> Trait3 for Bar<T> {
+    #[export_name = "foo"]
+    fn foo() {} //~ ERROR functions generic over types or consts must be mangled
+
+    #[export_name = "bar"]
+    extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled
+
+    #[export_name = "baz"]
+    fn baz<U>() {} //~ ERROR functions generic over types or consts must be mangled
+}
+
+pub struct Baz<'a>(#[allow(dead_code)] &'a i32);
+
+impl<'a> Baz<'a> {
+    #[export_name = "foo"]
+    pub fn foo() {}
+
+    #[export_name = "bar"]
+    pub fn bar<'b>(x: &'b i32) -> &i32 { x }
+}
+
+trait Trait4 {
+    fn foo();
+    fn bar<'a>(x: &'a i32) -> &i32;
+}
+
+impl Trait4 for Bar<i32> {
+    #[export_name = "foo"]
+    fn foo() {}
+
+    #[export_name = "bar"]
+    fn bar<'b>(x: &'b i32) -> &i32 { x }
+}
+
+impl<'a> Trait4 for Baz<'a> {
+    #[export_name = "foo"]
+    fn foo() {}
+
+    #[export_name = "bar"]
+    fn bar<'b>(x: &'b i32) -> &i32 { x }
+}
+
+trait Trait5<T> {
+    fn foo();
+}
+
+impl Trait5<i32> for Foo {
+    #[export_name = "foo"]
+    fn foo() {}
+}
+
+impl Trait5<i32> for Bar<i32> {
+    #[export_name = "foo"]
+    fn foo() {}
+}
+
+fn main() {}
diff --git a/tests/ui/generics/export-name-on-generics.stderr b/tests/ui/generics/export-name-on-generics.stderr
new file mode 100644
index 00000000000..7bc7b8ca559
--- /dev/null
+++ b/tests/ui/generics/export-name-on-generics.stderr
@@ -0,0 +1,144 @@
+error: functions generic over types or consts must be mangled
+  --> $DIR/export-name-on-generics.rs:6:1
+   |
+LL | #[export_name = "foo"]
+   | ---------------------- help: remove this attribute
+LL | pub fn foo<T>() {}
+   | ^^^^^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/export-name-on-generics.rs:3:9
+   |
+LL | #![deny(no_mangle_generic_items)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: functions generic over types or consts must be mangled
+  --> $DIR/export-name-on-generics.rs:9:1
+   |
+LL | #[export_name = "bar"]
+   | ---------------------- help: remove this attribute
+LL | pub extern "C" fn bar<T>() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: functions generic over types or consts must be mangled
+  --> $DIR/export-name-on-generics.rs:21:5
+   |
+LL |     #[export_name = "foo"]
+   |     ---------------------- help: remove this attribute
+LL |     pub fn foo<T>() {}
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: functions generic over types or consts must be mangled
+  --> $DIR/export-name-on-generics.rs:24:5
+   |
+LL |     #[export_name = "bar"]
+   |     ---------------------- help: remove this attribute
+LL |     pub extern "C" fn bar<T>() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: functions generic over types or consts must be mangled
+  --> $DIR/export-name-on-generics.rs:42:5
+   |
+LL |     #[export_name = "foo"]
+   |     ---------------------- help: remove this attribute
+LL |     fn foo<T>() {}
+   |     ^^^^^^^^^^^^^^
+
+error: functions generic over types or consts must be mangled
+  --> $DIR/export-name-on-generics.rs:45:5
+   |
+LL |     #[export_name = "bar"]
+   |     ---------------------- help: remove this attribute
+LL |     extern "C" fn bar<T>() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: functions generic over types or consts must be mangled
+  --> $DIR/export-name-on-generics.rs:64:5
+   |
+LL |     #[export_name = "foo"]
+   |     ---------------------- help: remove this attribute
+LL |     fn foo() {}
+   |     ^^^^^^^^^^^
+
+error: functions generic over types or consts must be mangled
+  --> $DIR/export-name-on-generics.rs:67:5
+   |
+LL |     #[export_name = "foo2"]
+   |     ----------------------- help: remove this attribute
+LL |     fn foo2<U>() {}
+   |     ^^^^^^^^^^^^^^^
+
+error: functions generic over types or consts must be mangled
+  --> $DIR/export-name-on-generics.rs:70:5
+   |
+LL |     #[export_name = "baz"]
+   |     ---------------------- help: remove this attribute
+LL |     extern "C" fn bar() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+error: functions generic over types or consts must be mangled
+  --> $DIR/export-name-on-generics.rs:73:5
+   |
+LL |     #[export_name = "baz"]
+   |     ---------------------- help: remove this attribute
+LL |     fn baz(x: &i32) -> &i32 { x }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: functions generic over types or consts must be mangled
+  --> $DIR/export-name-on-generics.rs:76:5
+   |
+LL |     #[export_name = "qux"]
+   |     ---------------------- help: remove this attribute
+LL |     fn qux<'a>(x: &'a i32) -> &i32 { x }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: functions generic over types or consts must be mangled
+  --> $DIR/export-name-on-generics.rs:83:5
+   |
+LL |     #[export_name = "foo"]
+   |     ---------------------- help: remove this attribute
+LL |     pub fn foo() {}
+   |     ^^^^^^^^^^^^^^^
+
+error: functions generic over types or consts must be mangled
+  --> $DIR/export-name-on-generics.rs:86:5
+   |
+LL |     #[export_name = "bar"]
+   |     ---------------------- help: remove this attribute
+LL |     pub extern "C" fn bar() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: functions generic over types or consts must be mangled
+  --> $DIR/export-name-on-generics.rs:89:5
+   |
+LL |     #[export_name = "baz"]
+   |     ---------------------- help: remove this attribute
+LL |     pub fn baz<U>() {}
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: functions generic over types or consts must be mangled
+  --> $DIR/export-name-on-generics.rs:105:5
+   |
+LL |     #[export_name = "foo"]
+   |     ---------------------- help: remove this attribute
+LL |     fn foo() {}
+   |     ^^^^^^^^^^^
+
+error: functions generic over types or consts must be mangled
+  --> $DIR/export-name-on-generics.rs:108:5
+   |
+LL |     #[export_name = "bar"]
+   |     ---------------------- help: remove this attribute
+LL |     extern "C" fn bar() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+error: functions generic over types or consts must be mangled
+  --> $DIR/export-name-on-generics.rs:111:5
+   |
+LL |     #[export_name = "baz"]
+   |     ---------------------- help: remove this attribute
+LL |     fn baz<U>() {}
+   |     ^^^^^^^^^^^^^^
+
+error: aborting due to 17 previous errors
+