Skip to content

Commit

Permalink
Add new lint no_mangle_with_rust_abi
Browse files Browse the repository at this point in the history
  • Loading branch information
nindalf committed Feb 18, 2023
1 parent e1da002 commit 2dd9898
Show file tree
Hide file tree
Showing 9 changed files with 126 additions and 3 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4621,6 +4621,7 @@ Released 2018-09-13
[`no_effect`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect
[`no_effect_replace`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect_replace
[`no_effect_underscore_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect_underscore_binding
[`no_mangle_with_rust_abi`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_mangle_with_rust_abi
[`non_ascii_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_ascii_literal
[`non_octal_unix_permissions`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_octal_unix_permissions
[`non_send_fields_in_send_ty`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_send_fields_in_send_ty
Expand Down
1 change: 1 addition & 0 deletions clippy_lints/src/declared_lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::no_effect::NO_EFFECT_INFO,
crate::no_effect::NO_EFFECT_UNDERSCORE_BINDING_INFO,
crate::no_effect::UNNECESSARY_OPERATION_INFO,
crate::no_mangle_with_rust_abi::NO_MANGLE_WITH_RUST_ABI_INFO,
crate::non_copy_const::BORROW_INTERIOR_MUTABLE_CONST_INFO,
crate::non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST_INFO,
crate::non_expressive_names::JUST_UNDERSCORES_AND_DIGITS_INFO,
Expand Down
2 changes: 2 additions & 0 deletions clippy_lints/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ mod neg_cmp_op_on_partial_ord;
mod neg_multiply;
mod new_without_default;
mod no_effect;
mod no_mangle_with_rust_abi;
mod non_copy_const;
mod non_expressive_names;
mod non_octal_unix_permissions;
Expand Down Expand Up @@ -916,6 +917,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(size_of_ref::SizeOfRef));
store.register_late_pass(|_| Box::new(multiple_unsafe_ops_per_block::MultipleUnsafeOpsPerBlock));
store.register_late_pass(|_| Box::new(extra_unused_type_parameters::ExtraUnusedTypeParameters));
store.register_late_pass(|_| Box::new(no_mangle_with_rust_abi::NoMangleWithRustAbi));
// add lints here, do not remove this comment, it's used in `new_lint`
}

Expand Down
60 changes: 60 additions & 0 deletions clippy_lints/src/no_mangle_with_rust_abi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use rustc_errors::Applicability;
use rustc_hir::{Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_target::spec::abi::Abi;

declare_clippy_lint! {
/// ### What it does
/// Checks for Rust ABI functions with the `#[no_mangle]` attribute.
///
/// ### Why is this bad?
/// The Rust ABI is not stable, but in many simple cases matches enough
/// with the C ABI that it is possible to forget to add `extern "C"` to a
/// function called from C. Changes to the Rust ABI can break this at any
/// point.
///
/// ### Example
/// ```rust
/// #[no_mangle]
/// fn example(arg_one: u32, arg_two: usize) {}
/// ```
///
/// Use instead:
/// ```rust
/// #[no_mangle]
/// extern "C" fn example(arg_one: u32, arg_two: usize) {}
/// ```
#[clippy::version = "1.69.0"]
pub NO_MANGLE_WITH_RUST_ABI,
suspicious,
"convert Rust ABI functions to C ABI"
}
declare_lint_pass!(NoMangleWithRustAbi => [NO_MANGLE_WITH_RUST_ABI]);

impl<'tcx> LateLintPass<'tcx> for NoMangleWithRustAbi {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
if let ItemKind::Fn(fn_sig, _, _) = &item.kind {
let attrs = cx.tcx.hir().attrs(item.hir_id());
for attr in attrs {
if let Some(ident) = attr.ident()
&& ident.name.as_str() == "no_mangle"
&& fn_sig.header.abi == Abi::Rust {
let mut applicability = Applicability::MachineApplicable;
let span = fn_sig.span;
span_lint_and_sugg(
cx,
NO_MANGLE_WITH_RUST_ABI,
span,
&format!("attribute #[no_mangle] set on a Rust ABI function"),
"try",
format!(r#"extern "C" {}"#, snippet_with_applicability(cx, span, "..", &mut applicability)),
applicability
);
}
}
}
}
}
2 changes: 1 addition & 1 deletion tests/ui/must_use_candidates.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ pub unsafe fn mutates_static() -> usize {
}

#[no_mangle]
pub fn unmangled(i: bool) -> bool {
extern "C" pub fn unmangled(i: bool) -> bool {
!i
}

Expand Down
2 changes: 1 addition & 1 deletion tests/ui/must_use_candidates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ pub unsafe fn mutates_static() -> usize {
}

#[no_mangle]
pub fn unmangled(i: bool) -> bool {
pub extern "C" fn unmangled(i: bool) -> bool {
!i
}

Expand Down
10 changes: 9 additions & 1 deletion tests/ui/must_use_candidates.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,13 @@ error: this function could have a `#[must_use]` attribute
LL | pub fn arcd(_x: Arc<u32>) -> bool {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn arcd(_x: Arc<u32>) -> bool`

error: aborting due to 5 previous errors
error: attribute #[no_mangle] set on a Rust ABI function
--> $DIR/must_use_candidates.rs:87:1
|
LL | pub fn unmangled(i: bool) -> bool {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `extern "C" pub fn unmangled(i: bool) -> bool`
|
= note: `-D clippy::no-mangle-with-rust-abi` implied by `-D warnings`

error: aborting due to 6 previous errors

24 changes: 24 additions & 0 deletions tests/ui/no_mangle_with_rust_abi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#![allow(unused)]
#![warn(clippy::no_mangle_with_rust_abi)]

#[no_mangle]
fn rust_abi_fn(arg_one: u32, arg_two: usize) {}

#[no_mangle]
fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines(
arg_one: u32,
arg_two: usize,
) -> u32 {
0
}

fn rust_abi_fn_again(arg_one: u32, arg_two: usize) {}

#[no_mangle]
extern "C" fn c_abi_fn(arg_one: u32, arg_two: usize) {}

extern "C" fn c_abi_fn_again(arg_one: u32, arg_two: usize) {}

fn main() {
// test code goes here
}
27 changes: 27 additions & 0 deletions tests/ui/no_mangle_with_rust_abi.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
error: attribute #[no_mangle] set on a Rust ABI function
--> $DIR/no_mangle_with_rust_abi.rs:5:1
|
LL | fn rust_abi_fn(arg_one: u32, arg_two: usize) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `extern "C" fn rust_abi_fn(arg_one: u32, arg_two: usize)`
|
= note: `-D clippy::no-mangle-with-rust-abi` implied by `-D warnings`

error: attribute #[no_mangle] set on a Rust ABI function
--> $DIR/no_mangle_with_rust_abi.rs:8:1
|
LL | / fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines(
LL | | arg_one: u32,
LL | | arg_two: usize,
LL | | ) -> u32 {
| |________^
|
help: try
|
LL + extern "C" fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines(
LL + arg_one: u32,
LL + arg_two: usize,
LL ~ ) -> u32 {
|

error: aborting due to 2 previous errors

0 comments on commit 2dd9898

Please sign in to comment.