Skip to content

Commit 74d0f34

Browse files
committed
Warn when #[export_name] is used with generic functions
1 parent 7e552b4 commit 74d0f34

File tree

4 files changed

+481
-9
lines changed

4 files changed

+481
-9
lines changed

compiler/rustc_lint/src/builtin.rs

+21-9
Original file line numberDiff line numberDiff line change
@@ -976,17 +976,21 @@ declare_lint! {
976976
/// ```rust
977977
/// #[unsafe(no_mangle)]
978978
/// fn foo<T>(t: T) {}
979+
///
980+
/// #[unsafe(export_name = "bar")]
981+
/// fn bar<T>(t: T) {}
979982
/// ```
980983
///
981984
/// {{produces}}
982985
///
983986
/// ### Explanation
984987
///
985988
/// A function with generics must have its symbol mangled to accommodate
986-
/// the generic parameter. The [`no_mangle` attribute] has no effect in
987-
/// this situation, and should be removed.
989+
/// the generic parameter. The [`no_mangle` attribute] and [`export_name` attribute]
990+
/// has no effect in this situation, and should be removed.
988991
///
989992
/// [`no_mangle` attribute]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute
993+
/// [`export_name` attribute]: https://doc.rust-lang.org/reference/abi.html#the-export_name-attribute
990994
NO_MANGLE_GENERIC_ITEMS,
991995
Warn,
992996
"generic items must be mangled"
@@ -997,7 +1001,7 @@ declare_lint_pass!(InvalidNoMangleItems => [NO_MANGLE_CONST_ITEMS, NO_MANGLE_GEN
9971001
impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
9981002
fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
9991003
let attrs = cx.tcx.hir_attrs(it.hir_id());
1000-
let check_no_mangle_on_generic_fn = |no_mangle_attr: &hir::Attribute,
1004+
let check_no_mangle_on_generic_fn = |attr: &hir::Attribute,
10011005
impl_generics: Option<&hir::Generics<'_>>,
10021006
generics: &hir::Generics<'_>,
10031007
span| {
@@ -1010,7 +1014,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
10101014
cx.emit_span_lint(
10111015
NO_MANGLE_GENERIC_ITEMS,
10121016
span,
1013-
BuiltinNoMangleGeneric { suggestion: no_mangle_attr.span() },
1017+
BuiltinNoMangleGeneric { suggestion: attr.span() },
10141018
);
10151019
break;
10161020
}
@@ -1019,8 +1023,10 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
10191023
};
10201024
match it.kind {
10211025
hir::ItemKind::Fn { generics, .. } => {
1022-
if let Some(no_mangle_attr) = attr::find_by_name(attrs, sym::no_mangle) {
1023-
check_no_mangle_on_generic_fn(no_mangle_attr, None, generics, it.span);
1026+
if let Some(attr) = attr::find_by_name(attrs, sym::export_name)
1027+
.or_else(|| attr::find_by_name(attrs, sym::no_mangle))
1028+
{
1029+
check_no_mangle_on_generic_fn(attr, None, generics, it.span);
10241030
}
10251031
}
10261032
hir::ItemKind::Const(..) => {
@@ -1048,11 +1054,17 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
10481054
hir::ItemKind::Impl(hir::Impl { generics, items, .. }) => {
10491055
for it in *items {
10501056
if let hir::AssocItemKind::Fn { .. } = it.kind {
1051-
if let Some(no_mangle_attr) =
1052-
attr::find_by_name(cx.tcx.hir_attrs(it.id.hir_id()), sym::no_mangle)
1057+
if let Some(attr) =
1058+
attr::find_by_name(cx.tcx.hir_attrs(it.id.hir_id()), sym::export_name)
1059+
.or_else(|| {
1060+
attr::find_by_name(
1061+
cx.tcx.hir_attrs(it.id.hir_id()),
1062+
sym::no_mangle,
1063+
)
1064+
})
10531065
{
10541066
check_no_mangle_on_generic_fn(
1055-
no_mangle_attr,
1067+
attr,
10561068
Some(generics),
10571069
cx.tcx.hir_get_generics(it.id.owner_id.def_id).unwrap(),
10581070
it.span,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
//@ run-rustfix
2+
#![allow(dead_code, elided_named_lifetimes)]
3+
#![deny(no_mangle_generic_items)]
4+
5+
pub fn foo<T>() {} //~ ERROR functions generic over types or consts must be mangled
6+
7+
pub extern "C" fn bar<T>() {} //~ ERROR functions generic over types or consts must be mangled
8+
9+
#[export_name = "baz"]
10+
pub fn baz(x: &i32) -> &i32 { x }
11+
12+
#[export_name = "qux"]
13+
pub fn qux<'a>(x: &'a i32) -> &i32 { x }
14+
15+
pub struct Foo;
16+
17+
impl Foo {
18+
19+
pub fn foo<T>() {} //~ ERROR functions generic over types or consts must be mangled
20+
21+
22+
pub extern "C" fn bar<T>() {} //~ ERROR functions generic over types or consts must be mangled
23+
24+
#[export_name = "baz"]
25+
pub fn baz(x: &i32) -> &i32 { x }
26+
27+
#[export_name = "qux"]
28+
pub fn qux<'a>(x: &'a i32) -> &i32 { x }
29+
}
30+
31+
trait Trait1 {
32+
fn foo<T>();
33+
extern "C" fn bar<T>();
34+
fn baz(x: &i32) -> &i32;
35+
fn qux<'a>(x: &'a i32) -> &i32;
36+
}
37+
38+
impl Trait1 for Foo {
39+
40+
fn foo<T>() {} //~ ERROR functions generic over types or consts must be mangled
41+
42+
43+
extern "C" fn bar<T>() {} //~ ERROR functions generic over types or consts must be mangled
44+
45+
#[export_name = "baz"]
46+
fn baz(x: &i32) -> &i32 { x }
47+
48+
#[export_name = "qux"]
49+
fn qux<'a>(x: &'a i32) -> &i32 { x }
50+
}
51+
52+
trait Trait2<T> {
53+
fn foo();
54+
fn foo2<U>();
55+
extern "C" fn bar();
56+
fn baz(x: &i32) -> &i32;
57+
fn qux<'a>(x: &'a i32) -> &i32;
58+
}
59+
60+
impl<T> Trait2<T> for Foo {
61+
62+
fn foo() {} //~ ERROR functions generic over types or consts must be mangled
63+
64+
65+
fn foo2<U>() {} //~ ERROR functions generic over types or consts must be mangled
66+
67+
68+
extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled
69+
70+
71+
fn baz(x: &i32) -> &i32 { x } //~ ERROR functions generic over types or consts must be mangled
72+
73+
74+
fn qux<'a>(x: &'a i32) -> &i32 { x } //~ ERROR functions generic over types or consts must be mangled
75+
}
76+
77+
pub struct Bar<T>(#[allow(dead_code)] T);
78+
79+
impl<T> Bar<T> {
80+
81+
pub fn foo() {} //~ ERROR functions generic over types or consts must be mangled
82+
83+
84+
pub extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled
85+
86+
87+
pub fn baz<U>() {} //~ ERROR functions generic over types or consts must be mangled
88+
}
89+
90+
impl Bar<i32> {
91+
#[export_name = "qux"]
92+
pub fn qux() {}
93+
}
94+
95+
trait Trait3 {
96+
fn foo();
97+
extern "C" fn bar();
98+
fn baz<U>();
99+
}
100+
101+
impl<T> Trait3 for Bar<T> {
102+
103+
fn foo() {} //~ ERROR functions generic over types or consts must be mangled
104+
105+
106+
extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled
107+
108+
109+
fn baz<U>() {} //~ ERROR functions generic over types or consts must be mangled
110+
}
111+
112+
pub struct Baz<'a>(#[allow(dead_code)] &'a i32);
113+
114+
impl<'a> Baz<'a> {
115+
#[export_name = "foo"]
116+
pub fn foo() {}
117+
118+
#[export_name = "bar"]
119+
pub fn bar<'b>(x: &'b i32) -> &i32 { x }
120+
}
121+
122+
trait Trait4 {
123+
fn foo();
124+
fn bar<'a>(x: &'a i32) -> &i32;
125+
}
126+
127+
impl Trait4 for Bar<i32> {
128+
#[export_name = "foo"]
129+
fn foo() {}
130+
131+
#[export_name = "bar"]
132+
fn bar<'b>(x: &'b i32) -> &i32 { x }
133+
}
134+
135+
impl<'a> Trait4 for Baz<'a> {
136+
#[export_name = "foo"]
137+
fn foo() {}
138+
139+
#[export_name = "bar"]
140+
fn bar<'b>(x: &'b i32) -> &i32 { x }
141+
}
142+
143+
trait Trait5<T> {
144+
fn foo();
145+
}
146+
147+
impl Trait5<i32> for Foo {
148+
#[export_name = "foo"]
149+
fn foo() {}
150+
}
151+
152+
impl Trait5<i32> for Bar<i32> {
153+
#[export_name = "foo"]
154+
fn foo() {}
155+
}
156+
157+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
//@ run-rustfix
2+
#![allow(dead_code, elided_named_lifetimes)]
3+
#![deny(no_mangle_generic_items)]
4+
5+
#[export_name = "foo"]
6+
pub fn foo<T>() {} //~ ERROR functions generic over types or consts must be mangled
7+
8+
#[export_name = "bar"]
9+
pub extern "C" fn bar<T>() {} //~ ERROR functions generic over types or consts must be mangled
10+
11+
#[export_name = "baz"]
12+
pub fn baz(x: &i32) -> &i32 { x }
13+
14+
#[export_name = "qux"]
15+
pub fn qux<'a>(x: &'a i32) -> &i32 { x }
16+
17+
pub struct Foo;
18+
19+
impl Foo {
20+
#[export_name = "foo"]
21+
pub fn foo<T>() {} //~ ERROR functions generic over types or consts must be mangled
22+
23+
#[export_name = "bar"]
24+
pub extern "C" fn bar<T>() {} //~ ERROR functions generic over types or consts must be mangled
25+
26+
#[export_name = "baz"]
27+
pub fn baz(x: &i32) -> &i32 { x }
28+
29+
#[export_name = "qux"]
30+
pub fn qux<'a>(x: &'a i32) -> &i32 { x }
31+
}
32+
33+
trait Trait1 {
34+
fn foo<T>();
35+
extern "C" fn bar<T>();
36+
fn baz(x: &i32) -> &i32;
37+
fn qux<'a>(x: &'a i32) -> &i32;
38+
}
39+
40+
impl Trait1 for Foo {
41+
#[export_name = "foo"]
42+
fn foo<T>() {} //~ ERROR functions generic over types or consts must be mangled
43+
44+
#[export_name = "bar"]
45+
extern "C" fn bar<T>() {} //~ ERROR functions generic over types or consts must be mangled
46+
47+
#[export_name = "baz"]
48+
fn baz(x: &i32) -> &i32 { x }
49+
50+
#[export_name = "qux"]
51+
fn qux<'a>(x: &'a i32) -> &i32 { x }
52+
}
53+
54+
trait Trait2<T> {
55+
fn foo();
56+
fn foo2<U>();
57+
extern "C" fn bar();
58+
fn baz(x: &i32) -> &i32;
59+
fn qux<'a>(x: &'a i32) -> &i32;
60+
}
61+
62+
impl<T> Trait2<T> for Foo {
63+
#[export_name = "foo"]
64+
fn foo() {} //~ ERROR functions generic over types or consts must be mangled
65+
66+
#[export_name = "foo2"]
67+
fn foo2<U>() {} //~ ERROR functions generic over types or consts must be mangled
68+
69+
#[export_name = "baz"]
70+
extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled
71+
72+
#[export_name = "baz"]
73+
fn baz(x: &i32) -> &i32 { x } //~ ERROR functions generic over types or consts must be mangled
74+
75+
#[export_name = "qux"]
76+
fn qux<'a>(x: &'a i32) -> &i32 { x } //~ ERROR functions generic over types or consts must be mangled
77+
}
78+
79+
pub struct Bar<T>(#[allow(dead_code)] T);
80+
81+
impl<T> Bar<T> {
82+
#[export_name = "foo"]
83+
pub fn foo() {} //~ ERROR functions generic over types or consts must be mangled
84+
85+
#[export_name = "bar"]
86+
pub extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled
87+
88+
#[export_name = "baz"]
89+
pub fn baz<U>() {} //~ ERROR functions generic over types or consts must be mangled
90+
}
91+
92+
impl Bar<i32> {
93+
#[export_name = "qux"]
94+
pub fn qux() {}
95+
}
96+
97+
trait Trait3 {
98+
fn foo();
99+
extern "C" fn bar();
100+
fn baz<U>();
101+
}
102+
103+
impl<T> Trait3 for Bar<T> {
104+
#[export_name = "foo"]
105+
fn foo() {} //~ ERROR functions generic over types or consts must be mangled
106+
107+
#[export_name = "bar"]
108+
extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled
109+
110+
#[export_name = "baz"]
111+
fn baz<U>() {} //~ ERROR functions generic over types or consts must be mangled
112+
}
113+
114+
pub struct Baz<'a>(#[allow(dead_code)] &'a i32);
115+
116+
impl<'a> Baz<'a> {
117+
#[export_name = "foo"]
118+
pub fn foo() {}
119+
120+
#[export_name = "bar"]
121+
pub fn bar<'b>(x: &'b i32) -> &i32 { x }
122+
}
123+
124+
trait Trait4 {
125+
fn foo();
126+
fn bar<'a>(x: &'a i32) -> &i32;
127+
}
128+
129+
impl Trait4 for Bar<i32> {
130+
#[export_name = "foo"]
131+
fn foo() {}
132+
133+
#[export_name = "bar"]
134+
fn bar<'b>(x: &'b i32) -> &i32 { x }
135+
}
136+
137+
impl<'a> Trait4 for Baz<'a> {
138+
#[export_name = "foo"]
139+
fn foo() {}
140+
141+
#[export_name = "bar"]
142+
fn bar<'b>(x: &'b i32) -> &i32 { x }
143+
}
144+
145+
trait Trait5<T> {
146+
fn foo();
147+
}
148+
149+
impl Trait5<i32> for Foo {
150+
#[export_name = "foo"]
151+
fn foo() {}
152+
}
153+
154+
impl Trait5<i32> for Bar<i32> {
155+
#[export_name = "foo"]
156+
fn foo() {}
157+
}
158+
159+
fn main() {}

0 commit comments

Comments
 (0)