Skip to content

Commit 5152229

Browse files
committed
Add lint detects using #[export_name] on generic functions
1 parent 7e552b4 commit 5152229

File tree

6 files changed

+535
-43
lines changed

6 files changed

+535
-43
lines changed

compiler/rustc_lint/messages.ftl

+5-2
Original file line numberDiff line numberDiff line change
@@ -124,11 +124,14 @@ lint_builtin_mutable_transmutes =
124124
transmuting &T to &mut T is undefined behavior, even if the reference is unused, consider instead using an UnsafeCell
125125
126126
lint_builtin_no_mangle_fn = declaration of a `no_mangle` function
127-
lint_builtin_no_mangle_generic = functions generic over types or consts must be mangled
128-
.suggestion = remove this attribute
129127
130128
lint_builtin_no_mangle_method = declaration of a `no_mangle` method
129+
130+
lint_builtin_no_mangle_or_export_name_generic = functions generic over types or consts must be mangled
131+
.suggestion = remove this attribute
132+
131133
lint_builtin_no_mangle_static = declaration of a `no_mangle` static
134+
132135
lint_builtin_non_shorthand_field_patterns = the `{$ident}:` in this pattern is redundant
133136
.suggestion = use shorthand field pattern
134137

compiler/rustc_lint/src/builtin.rs

+66-37
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,11 @@ use crate::lints::{
5454
BuiltinExplicitOutlives, BuiltinExplicitOutlivesSuggestion, BuiltinFeatureIssueNote,
5555
BuiltinIncompleteFeatures, BuiltinIncompleteFeaturesHelp, BuiltinInternalFeatures,
5656
BuiltinKeywordIdents, BuiltinMissingCopyImpl, BuiltinMissingDebugImpl, BuiltinMissingDoc,
57-
BuiltinMutablesTransmutes, BuiltinNoMangleGeneric, BuiltinNonShorthandFieldPatterns,
58-
BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds, BuiltinTypeAliasBounds,
59-
BuiltinUngatedAsyncFnTrackCaller, BuiltinUnpermittedTypeInit, BuiltinUnpermittedTypeInitSub,
60-
BuiltinUnreachablePub, BuiltinUnsafe, BuiltinUnstableFeatures, BuiltinUnusedDocComment,
61-
BuiltinUnusedDocCommentSub, BuiltinWhileTrue, InvalidAsmLabel,
57+
BuiltinMutablesTransmutes, BuiltinNoMangleOrExportNameGeneric,
58+
BuiltinNonShorthandFieldPatterns, BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds,
59+
BuiltinTypeAliasBounds, BuiltinUngatedAsyncFnTrackCaller, BuiltinUnpermittedTypeInit,
60+
BuiltinUnpermittedTypeInitSub, BuiltinUnreachablePub, BuiltinUnsafe, BuiltinUnstableFeatures,
61+
BuiltinUnusedDocComment, BuiltinUnusedDocCommentSub, BuiltinWhileTrue, InvalidAsmLabel,
6262
};
6363
use crate::nonstandard_style::{MethodLateContext, method_context};
6464
use crate::{
@@ -992,36 +992,69 @@ declare_lint! {
992992
"generic items must be mangled"
993993
}
994994

995-
declare_lint_pass!(InvalidNoMangleItems => [NO_MANGLE_CONST_ITEMS, NO_MANGLE_GENERIC_ITEMS]);
995+
declare_lint! {
996+
/// The `export_name_generic_items` lint detects using `#[export_name]` on generic functions.
997+
///
998+
/// ### Example
999+
/// ```rust,compile_fail
1000+
/// #[export_name = "exported_name"]
1001+
/// fn foo<T>() {}
1002+
/// ```
1003+
///
1004+
/// {{produces}}
1005+
///
1006+
/// ### Explanation
1007+
///
1008+
/// A function with generics must have its symbol mangled to accommodate
1009+
/// the generic parameter. The [`export_name` attribute] has no effect in
1010+
/// this situation, and should be removed.
1011+
///
1012+
/// [`export_name` attribute]: https://doc.rust-lang.org/reference/abi.html#the-export_name-attribute
1013+
pub EXPORT_NAME_GENERIC_ITEMS,
1014+
Warn,
1015+
"generic items must be mangled, export_name would avoid mangling"
1016+
}
1017+
1018+
declare_lint_pass!(InvalidNoMangleItems => [NO_MANGLE_CONST_ITEMS, NO_MANGLE_GENERIC_ITEMS, EXPORT_NAME_GENERIC_ITEMS]);
9961019

9971020
impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
9981021
fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
9991022
let attrs = cx.tcx.hir_attrs(it.hir_id());
1000-
let check_no_mangle_on_generic_fn = |no_mangle_attr: &hir::Attribute,
1001-
impl_generics: Option<&hir::Generics<'_>>,
1002-
generics: &hir::Generics<'_>,
1003-
span| {
1004-
for param in
1005-
generics.params.iter().chain(impl_generics.map(|g| g.params).into_iter().flatten())
1006-
{
1007-
match param.kind {
1008-
GenericParamKind::Lifetime { .. } => {}
1009-
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
1010-
cx.emit_span_lint(
1011-
NO_MANGLE_GENERIC_ITEMS,
1012-
span,
1013-
BuiltinNoMangleGeneric { suggestion: no_mangle_attr.span() },
1014-
);
1015-
break;
1023+
let check_no_mangle_or_export_name_on_generic_fn =
1024+
|attrs: &[hir::Attribute],
1025+
impl_generics: Option<&hir::Generics<'_>>,
1026+
generics: &hir::Generics<'_>,
1027+
span| {
1028+
let (lint, attr) =
1029+
if let Some(export_name_attr) = attr::find_by_name(attrs, sym::export_name) {
1030+
(EXPORT_NAME_GENERIC_ITEMS, export_name_attr)
1031+
} else if let Some(no_mangle_attr) = attr::find_by_name(attrs, sym::no_mangle) {
1032+
(NO_MANGLE_GENERIC_ITEMS, no_mangle_attr)
1033+
} else {
1034+
return;
1035+
};
1036+
1037+
for param in generics
1038+
.params
1039+
.iter()
1040+
.chain(impl_generics.map(|g| g.params).into_iter().flatten())
1041+
{
1042+
match param.kind {
1043+
GenericParamKind::Lifetime { .. } => {}
1044+
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
1045+
cx.emit_span_lint(
1046+
lint,
1047+
span,
1048+
BuiltinNoMangleOrExportNameGeneric { suggestion: attr.span() },
1049+
);
1050+
break;
1051+
}
10161052
}
10171053
}
1018-
}
1019-
};
1054+
};
10201055
match it.kind {
10211056
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);
1024-
}
1057+
check_no_mangle_or_export_name_on_generic_fn(attrs, None, generics, it.span);
10251058
}
10261059
hir::ItemKind::Const(..) => {
10271060
if attr::contains_name(attrs, sym::no_mangle) {
@@ -1048,16 +1081,12 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
10481081
hir::ItemKind::Impl(hir::Impl { generics, items, .. }) => {
10491082
for it in *items {
10501083
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)
1053-
{
1054-
check_no_mangle_on_generic_fn(
1055-
no_mangle_attr,
1056-
Some(generics),
1057-
cx.tcx.hir_get_generics(it.id.owner_id.def_id).unwrap(),
1058-
it.span,
1059-
);
1060-
}
1084+
check_no_mangle_or_export_name_on_generic_fn(
1085+
cx.tcx.hir_attrs(it.id.hir_id()),
1086+
Some(generics),
1087+
cx.tcx.hir_get_generics(it.id.owner_id.def_id).unwrap(),
1088+
it.span,
1089+
);
10611090
}
10621091
}
10631092
}

compiler/rustc_lint/src/lints.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -217,10 +217,10 @@ pub(crate) enum BuiltinUnusedDocCommentSub {
217217
}
218218

219219
#[derive(LintDiagnostic)]
220-
#[diag(lint_builtin_no_mangle_generic)]
221-
pub(crate) struct BuiltinNoMangleGeneric {
222-
// Use of `#[no_mangle]` suggests FFI intent; correct
223-
// fix may be to monomorphize source by hand
220+
#[diag(lint_builtin_no_mangle_or_export_name_generic)]
221+
pub(crate) struct BuiltinNoMangleOrExportNameGeneric {
222+
// Use of `#[no_mangle]` or `#[export_name = ".."]` suggests FFI intent;
223+
// correct fix may be to monomorphize source by hand
224224
#[suggestion(style = "short", code = "", applicability = "maybe-incorrect")]
225225
pub suggestion: Span,
226226
}
+157
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
//@ run-rustfix
2+
#![allow(dead_code, elided_named_lifetimes)]
3+
#![deny(export_name_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() {}

0 commit comments

Comments
 (0)