diff options
| author | Mu001999 <mu001999@outlook.com> | 2025-05-10 09:55:50 +0800 |
|---|---|---|
| committer | Mu001999 <mu001999@outlook.com> | 2025-05-10 18:48:32 +0800 |
| commit | 0de994a368e9225fab812a7295f9350285cd55d3 (patch) | |
| tree | 00fd371e7569f8c1898f029f65a4440f3d08bdfe | |
| parent | 7e552b46af72df390ed233b58a7f51650515b2a8 (diff) | |
| download | rust-0de994a368e9225fab812a7295f9350285cd55d3.tar.gz rust-0de994a368e9225fab812a7295f9350285cd55d3.zip | |
Warn when #[export_name] is used with generic functions
| -rw-r--r-- | compiler/rustc_lint/src/builtin.rs | 27 | ||||
| -rw-r--r-- | tests/ui/generics/export-name-on-generics.fixed | 157 | ||||
| -rw-r--r-- | tests/ui/generics/export-name-on-generics.rs | 159 | ||||
| -rw-r--r-- | tests/ui/generics/export-name-on-generics.stderr | 144 |
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 + |
