Auto merge of #86492 - hyd-dev:no-mangle-method, r=petrochenkov
Associated functions that contain extern indicator or have `#[rustc_std_internal_symbol]` are reachable Previously these fails to link with ``undefined reference to `foo'``: <details> <summary>Example 1</summary> ```rs struct AssocFn; impl AssocFn { #[no_mangle] fn foo() {} } fn main() { extern "Rust" { fn foo(); } unsafe { foo() } } ``` ([Playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=f1244afcdd26e2a28445f6e82ca46b50)) </details> <details> <summary>Example 2</summary> ```rs #![crate_name = "lib"] #![crate_type = "lib"] struct AssocFn; impl AssocFn { #[no_mangle] fn foo() {} } ``` ```rs extern crate lib; fn main() { extern "Rust" { fn foo(); } unsafe { foo() } } ``` </details> But I believe they should link successfully, because this works: <details> ```rs #[no_mangle] fn foo() {} fn main() { extern "Rust" { fn foo(); } unsafe { foo() } } ``` ([Playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=789b3f283ee6126f53939429103ed98d)) </details> This PR fixes the problem, by adding associated functions that have "custom linkage" to `reachable_set`, just like normal functions. I haven't tested whether #76211 and [Miri](https://github.com/rust-lang/miri/issues/1837) are fixed by this PR yet, but I'm submitting this anyway since this fixes the examples above. I added a `run-pass` test that combines my two examples above, but I'm not sure if that's the right way to test this. Maybe I should add / modify an existing codegen test (`src/test/codegen/export-no-mangle.rs`?) instead?
This commit is contained in:
commit
5a19ffe1c2
19 changed files with 934 additions and 265 deletions
|
@ -417,6 +417,25 @@ impl EarlyLintPass for UnsafeCode {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_impl_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) {
|
||||
if let ast::AssocItemKind::Fn(..) = it.kind {
|
||||
if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) {
|
||||
self.report_overriden_symbol_name(
|
||||
cx,
|
||||
attr.span,
|
||||
"declaration of a `no_mangle` method",
|
||||
);
|
||||
}
|
||||
if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) {
|
||||
self.report_overriden_symbol_name(
|
||||
cx,
|
||||
attr.span,
|
||||
"declaration of a method with `export_name`",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_fn(&mut self, cx: &EarlyContext<'_>, fk: FnKind<'_>, span: Span, _: ast::NodeId) {
|
||||
if let FnKind::Fn(
|
||||
ctxt,
|
||||
|
@ -1115,31 +1134,37 @@ 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: &ast::Attribute,
|
||||
impl_generics: Option<&hir::Generics<'_>>,
|
||||
generics: &hir::Generics<'_>,
|
||||
span| {
|
||||
for param in
|
||||
generics.params.iter().chain(impl_generics.map(|g| g.params).into_iter().flatten())
|
||||
{
|
||||
match param.kind {
|
||||
GenericParamKind::Lifetime { .. } => {}
|
||||
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
|
||||
cx.struct_span_lint(NO_MANGLE_GENERIC_ITEMS, span, |lint| {
|
||||
lint.build("functions generic over types or consts must be mangled")
|
||||
.span_suggestion_short(
|
||||
no_mangle_attr.span,
|
||||
"remove this attribute",
|
||||
String::new(),
|
||||
// Use of `#[no_mangle]` suggests FFI intent; correct
|
||||
// fix may be to monomorphize source by hand
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
.emit();
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
match it.kind {
|
||||
hir::ItemKind::Fn(.., ref generics, _) => {
|
||||
if let Some(no_mangle_attr) = cx.sess().find_by_name(attrs, sym::no_mangle) {
|
||||
for param in generics.params {
|
||||
match param.kind {
|
||||
GenericParamKind::Lifetime { .. } => {}
|
||||
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
|
||||
cx.struct_span_lint(NO_MANGLE_GENERIC_ITEMS, it.span, |lint| {
|
||||
lint.build(
|
||||
"functions generic over types or consts must be mangled",
|
||||
)
|
||||
.span_suggestion_short(
|
||||
no_mangle_attr.span,
|
||||
"remove this attribute",
|
||||
String::new(),
|
||||
// Use of `#[no_mangle]` suggests FFI intent; correct
|
||||
// fix may be to monomorphize source by hand
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
.emit();
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
check_no_mangle_on_generic_fn(no_mangle_attr, None, generics, it.span);
|
||||
}
|
||||
}
|
||||
hir::ItemKind::Const(..) => {
|
||||
|
@ -1170,6 +1195,23 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
|
|||
});
|
||||
}
|
||||
}
|
||||
hir::ItemKind::Impl(hir::Impl { ref generics, items, .. }) => {
|
||||
for it in items {
|
||||
if let hir::AssocItemKind::Fn { .. } = it.kind {
|
||||
if let Some(no_mangle_attr) = cx
|
||||
.sess()
|
||||
.find_by_name(cx.tcx.hir().attrs(it.id.hir_id()), sym::no_mangle)
|
||||
{
|
||||
check_no_mangle_on_generic_fn(
|
||||
no_mangle_attr,
|
||||
Some(generics),
|
||||
cx.tcx.hir().get_generics(it.id.def_id.to_def_id()).unwrap(),
|
||||
it.span,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -391,9 +391,14 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase {
|
|||
_: Span,
|
||||
id: hir::HirId,
|
||||
) {
|
||||
let attrs = cx.tcx.hir().attrs(id);
|
||||
match &fk {
|
||||
FnKind::Method(ident, ..) => match method_context(cx, id) {
|
||||
FnKind::Method(ident, sig, ..) => match method_context(cx, id) {
|
||||
MethodLateContext::PlainImpl => {
|
||||
if sig.header.abi != Abi::Rust && cx.sess().contains_name(attrs, sym::no_mangle)
|
||||
{
|
||||
return;
|
||||
}
|
||||
self.check_snake_case(cx, "method", ident);
|
||||
}
|
||||
MethodLateContext::TraitAutoImpl => {
|
||||
|
@ -402,7 +407,6 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase {
|
|||
_ => (),
|
||||
},
|
||||
FnKind::ItemFn(ident, _, header, _) => {
|
||||
let attrs = cx.tcx.hir().attrs(id);
|
||||
// Skip foreign-ABI #[no_mangle] functions (Issue #31924)
|
||||
if header.abi != Abi::Rust && cx.sess().contains_name(attrs, sym::no_mangle) {
|
||||
return;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue