Auto merge of #13631 - samueltardieu:push-uoowutzkvsrk, r=Centri3

no_mangle attribute requires unsafe in Rust 2024

Tests without unsafe must not run in edition 2024. Also, error messages have been modified to include the full attribute, so that a use of `#[unsafe(no_mangle)]` does not produce an error message containing `#[no_mangle]`.

changelog: [`no_mangle_attribute`]: handle `#[unsafe(no_mangle)]` as well
This commit is contained in:
bors 2024-11-03 19:43:19 +00:00
commit a1a9aaef87
5 changed files with 164 additions and 23 deletions

View File

@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet_with_applicability; use clippy_utils::source::{snippet, snippet_with_applicability};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{Item, ItemKind}; use rustc_hir::{Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
@ -18,13 +18,13 @@ declare_clippy_lint! {
/// Rust ABI can break this at any point. /// Rust ABI can break this at any point.
/// ///
/// ### Example /// ### Example
/// ```no_run /// ```rust,ignore
/// #[no_mangle] /// #[no_mangle]
/// fn example(arg_one: u32, arg_two: usize) {} /// fn example(arg_one: u32, arg_two: usize) {}
/// ``` /// ```
/// ///
/// Use instead: /// Use instead:
/// ```no_run /// ```rust,ignore
/// #[no_mangle] /// #[no_mangle]
/// extern "C" fn example(arg_one: u32, arg_two: usize) {} /// extern "C" fn example(arg_one: u32, arg_two: usize) {}
/// ``` /// ```
@ -40,24 +40,25 @@ impl<'tcx> LateLintPass<'tcx> for NoMangleWithRustAbi {
if let ItemKind::Fn(fn_sig, _, _) = &item.kind { if let ItemKind::Fn(fn_sig, _, _) = &item.kind {
let attrs = cx.tcx.hir().attrs(item.hir_id()); let attrs = cx.tcx.hir().attrs(item.hir_id());
let mut app = Applicability::MaybeIncorrect; let mut app = Applicability::MaybeIncorrect;
let snippet = snippet_with_applicability(cx, fn_sig.span, "..", &mut app); let fn_snippet = snippet_with_applicability(cx, fn_sig.span, "..", &mut app);
for attr in attrs { for attr in attrs {
if let Some(ident) = attr.ident() if let Some(ident) = attr.ident()
&& ident.name == rustc_span::sym::no_mangle && ident.name == rustc_span::sym::no_mangle
&& fn_sig.header.abi == Abi::Rust && fn_sig.header.abi == Abi::Rust
&& let Some((fn_attrs, _)) = snippet.split_once("fn") && let Some((fn_attrs, _)) = fn_snippet.split_once("fn")
&& !fn_attrs.contains("extern") && !fn_attrs.contains("extern")
{ {
let sugg_span = fn_sig let sugg_span = fn_sig
.span .span
.with_lo(fn_sig.span.lo() + BytePos::from_usize(fn_attrs.len())) .with_lo(fn_sig.span.lo() + BytePos::from_usize(fn_attrs.len()))
.shrink_to_lo(); .shrink_to_lo();
let attr_snippet = snippet(cx, attr.span, "..");
span_lint_and_then( span_lint_and_then(
cx, cx,
NO_MANGLE_WITH_RUST_ABI, NO_MANGLE_WITH_RUST_ABI,
fn_sig.span, fn_sig.span,
"`#[no_mangle]` set on a function with the default (`Rust`) ABI", format!("`{attr_snippet}` set on a function with the default (`Rust`) ABI"),
|diag| { |diag| {
diag.span_suggestion(sugg_span, "set an ABI", "extern \"C\" ", app) diag.span_suggestion(sugg_span, "set an ABI", "extern \"C\" ", app)
.span_suggestion(sugg_span, "or explicitly set the default", "extern \"Rust\" ", app); .span_suggestion(sugg_span, "or explicitly set the default", "extern \"Rust\" ", app);

View File

@ -2,30 +2,30 @@
#![allow(unused)] #![allow(unused)]
#![warn(clippy::no_mangle_with_rust_abi)] #![warn(clippy::no_mangle_with_rust_abi)]
#[no_mangle] #[unsafe(no_mangle)]
fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {} fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {}
//~^ ERROR: `#[no_mangle]` set on a function with the default (`Rust`) ABI //~^ ERROR: `#[unsafe(no_mangle)]` set on a function with the default (`Rust`) ABI
//~| NOTE: `-D clippy::no-mangle-with-rust-abi` implied by `-D warnings` //~| NOTE: `-D clippy::no-mangle-with-rust-abi` implied by `-D warnings`
#[no_mangle] #[unsafe(no_mangle)]
pub fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {} pub fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {}
//~^ ERROR: `#[no_mangle]` set on a function with the default (`Rust`) ABI //~^ ERROR: `#[unsafe(no_mangle)]` set on a function with the default (`Rust`) ABI
/// # Safety /// # Safety
/// This function shouldn't be called unless the horsemen are ready /// This function shouldn't be called unless the horsemen are ready
#[no_mangle] #[unsafe(no_mangle)]
pub unsafe fn rust_abi_fn_three(arg_one: u32, arg_two: usize) {} pub unsafe fn rust_abi_fn_three(arg_one: u32, arg_two: usize) {}
//~^ ERROR: `#[no_mangle]` set on a function with the default (`Rust`) ABI //~^ ERROR: `#[unsafe(no_mangle)]` set on a function with the default (`Rust`) ABI
/// # Safety /// # Safety
/// This function shouldn't be called unless the horsemen are ready /// This function shouldn't be called unless the horsemen are ready
#[no_mangle] #[unsafe(no_mangle)]
unsafe fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {} unsafe fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {}
//~^ ERROR: `#[no_mangle]` set on a function with the default (`Rust`) ABI //~^ ERROR: `#[unsafe(no_mangle)]` set on a function with the default (`Rust`) ABI
#[no_mangle] #[unsafe(no_mangle)]
fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines( fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines(
//~^ ERROR: `#[no_mangle]` set on a function with the default (`Rust`) ABI //~^ ERROR: `#[unsafe(no_mangle)]` set on a function with the default (`Rust`) ABI
arg_one: u32, arg_one: u32,
arg_two: usize, arg_two: usize,
) -> u32 { ) -> u32 {
@ -33,13 +33,13 @@ fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lin
} }
// Must not run on functions that explicitly opt in to using the Rust ABI with `extern "Rust"` // Must not run on functions that explicitly opt in to using the Rust ABI with `extern "Rust"`
#[no_mangle] #[unsafe(no_mangle)]
#[rustfmt::skip] #[rustfmt::skip]
extern "Rust" fn rust_abi_fn_explicit_opt_in(arg_one: u32, arg_two: usize) {} extern "Rust" fn rust_abi_fn_explicit_opt_in(arg_one: u32, arg_two: usize) {}
fn rust_abi_fn_again(arg_one: u32, arg_two: usize) {} fn rust_abi_fn_again(arg_one: u32, arg_two: usize) {}
#[no_mangle] #[unsafe(no_mangle)]
extern "C" fn c_abi_fn(arg_one: u32, arg_two: usize) {} 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) {} extern "C" fn c_abi_fn_again(arg_one: u32, arg_two: usize) {}

View File

@ -1,4 +1,4 @@
error: `#[no_mangle]` set on a function with the default (`Rust`) ABI error: `#[unsafe(no_mangle)]` set on a function with the default (`Rust`) ABI
--> tests/ui/no_mangle_with_rust_abi.rs:6:1 --> tests/ui/no_mangle_with_rust_abi.rs:6:1
| |
LL | fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {} LL | fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {}
@ -15,7 +15,7 @@ help: or explicitly set the default
LL | extern "Rust" fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {} LL | extern "Rust" fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {}
| +++++++++++++ | +++++++++++++
error: `#[no_mangle]` set on a function with the default (`Rust`) ABI error: `#[unsafe(no_mangle)]` set on a function with the default (`Rust`) ABI
--> tests/ui/no_mangle_with_rust_abi.rs:11:1 --> tests/ui/no_mangle_with_rust_abi.rs:11:1
| |
LL | pub fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {} LL | pub fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {}
@ -30,7 +30,7 @@ help: or explicitly set the default
LL | pub extern "Rust" fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {} LL | pub extern "Rust" fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {}
| +++++++++++++ | +++++++++++++
error: `#[no_mangle]` set on a function with the default (`Rust`) ABI error: `#[unsafe(no_mangle)]` set on a function with the default (`Rust`) ABI
--> tests/ui/no_mangle_with_rust_abi.rs:17:1 --> tests/ui/no_mangle_with_rust_abi.rs:17:1
| |
LL | pub unsafe fn rust_abi_fn_three(arg_one: u32, arg_two: usize) {} LL | pub unsafe fn rust_abi_fn_three(arg_one: u32, arg_two: usize) {}
@ -45,7 +45,7 @@ help: or explicitly set the default
LL | pub unsafe extern "Rust" fn rust_abi_fn_three(arg_one: u32, arg_two: usize) {} LL | pub unsafe extern "Rust" fn rust_abi_fn_three(arg_one: u32, arg_two: usize) {}
| +++++++++++++ | +++++++++++++
error: `#[no_mangle]` set on a function with the default (`Rust`) ABI error: `#[unsafe(no_mangle)]` set on a function with the default (`Rust`) ABI
--> tests/ui/no_mangle_with_rust_abi.rs:23:1 --> tests/ui/no_mangle_with_rust_abi.rs:23:1
| |
LL | unsafe fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {} LL | unsafe fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {}
@ -60,7 +60,7 @@ help: or explicitly set the default
LL | unsafe extern "Rust" fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {} LL | unsafe extern "Rust" fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {}
| +++++++++++++ | +++++++++++++
error: `#[no_mangle]` set on a function with the default (`Rust`) ABI error: `#[unsafe(no_mangle)]` set on a function with the default (`Rust`) ABI
--> tests/ui/no_mangle_with_rust_abi.rs:27:1 --> tests/ui/no_mangle_with_rust_abi.rs:27:1
| |
LL | / fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines( LL | / fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines(

View File

@ -0,0 +1,57 @@
//@edition:2021
//
// Edition 2024 requires the use of #[unsafe(no_mangle)]
//@no-rustfix: overlapping suggestions
#![allow(unused)]
#![warn(clippy::no_mangle_with_rust_abi)]
#[no_mangle]
fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {}
//~^ ERROR: `#[no_mangle]` set on a function with the default (`Rust`) ABI
//~| NOTE: `-D clippy::no-mangle-with-rust-abi` implied by `-D warnings`
#[no_mangle]
pub fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {}
//~^ ERROR: `#[no_mangle]` set on a function with the default (`Rust`) ABI
/// # Safety
/// This function shouldn't be called unless the horsemen are ready
#[no_mangle]
pub unsafe fn rust_abi_fn_three(arg_one: u32, arg_two: usize) {}
//~^ ERROR: `#[no_mangle]` set on a function with the default (`Rust`) ABI
/// # Safety
/// This function shouldn't be called unless the horsemen are ready
#[no_mangle]
unsafe fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {}
//~^ ERROR: `#[no_mangle]` set on a function with the default (`Rust`) ABI
#[no_mangle]
fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines(
//~^ ERROR: `#[no_mangle]` set on a function with the default (`Rust`) ABI
arg_one: u32,
arg_two: usize,
) -> u32 {
0
}
// Must not run on functions that explicitly opt in to using the Rust ABI with `extern "Rust"`
#[no_mangle]
#[rustfmt::skip]
extern "Rust" fn rust_abi_fn_explicit_opt_in(arg_one: u32, arg_two: usize) {}
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) {}
extern "C" {
fn c_abi_in_block(arg_one: u32, arg_two: usize);
}
fn main() {
// test code goes here
}

View File

@ -0,0 +1,83 @@
error: `#[no_mangle]` set on a function with the default (`Rust`) ABI
--> tests/ui/no_mangle_with_rust_abi_2021.rs:10:1
|
LL | fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `-D clippy::no-mangle-with-rust-abi` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::no_mangle_with_rust_abi)]`
help: set an ABI
|
LL | extern "C" fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {}
| ++++++++++
help: or explicitly set the default
|
LL | extern "Rust" fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {}
| +++++++++++++
error: `#[no_mangle]` set on a function with the default (`Rust`) ABI
--> tests/ui/no_mangle_with_rust_abi_2021.rs:15:1
|
LL | pub fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: set an ABI
|
LL | pub extern "C" fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {}
| ++++++++++
help: or explicitly set the default
|
LL | pub extern "Rust" fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {}
| +++++++++++++
error: `#[no_mangle]` set on a function with the default (`Rust`) ABI
--> tests/ui/no_mangle_with_rust_abi_2021.rs:21:1
|
LL | pub unsafe fn rust_abi_fn_three(arg_one: u32, arg_two: usize) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: set an ABI
|
LL | pub unsafe extern "C" fn rust_abi_fn_three(arg_one: u32, arg_two: usize) {}
| ++++++++++
help: or explicitly set the default
|
LL | pub unsafe extern "Rust" fn rust_abi_fn_three(arg_one: u32, arg_two: usize) {}
| +++++++++++++
error: `#[no_mangle]` set on a function with the default (`Rust`) ABI
--> tests/ui/no_mangle_with_rust_abi_2021.rs:27:1
|
LL | unsafe fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: set an ABI
|
LL | unsafe extern "C" fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {}
| ++++++++++
help: or explicitly set the default
|
LL | unsafe extern "Rust" fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {}
| +++++++++++++
error: `#[no_mangle]` set on a function with the default (`Rust`) ABI
--> tests/ui/no_mangle_with_rust_abi_2021.rs:31:1
|
LL | / fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines(
LL | |
LL | | arg_one: u32,
LL | | arg_two: usize,
LL | | ) -> u32 {
| |________^
|
help: set an ABI
|
LL | extern "C" fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines(
| ++++++++++
help: or explicitly set the default
|
LL | extern "Rust" fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines(
| +++++++++++++
error: aborting due to 5 previous errors