From 63a48e407d9ba75bf0bf67a552a78bab054fb119 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sun, 27 Jul 2025 12:56:02 +0200 Subject: [PATCH 1/5] Add lint against integer to pointer transmutes --- compiler/rustc_lint/messages.ftl | 8 ++ compiler/rustc_lint/src/lints.rs | 40 ++++++++ compiler/rustc_lint/src/transmute.rs | 94 +++++++++++++++++- tests/ui/lint/int_to_ptr.fixed | 37 +++++++ tests/ui/lint/int_to_ptr.rs | 37 +++++++ tests/ui/lint/int_to_ptr.stderr | 139 +++++++++++++++++++++++++++ 6 files changed, 354 insertions(+), 1 deletion(-) create mode 100644 tests/ui/lint/int_to_ptr.fixed create mode 100644 tests/ui/lint/int_to_ptr.rs create mode 100644 tests/ui/lint/int_to_ptr.stderr diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 1a1cfc9fa6f1b..30c71f8560a17 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -476,6 +476,14 @@ lint_invalid_reference_casting_note_book = for more information, visit + .help_exposed_provenance = for more information about exposed provenance, see + .suggestion_as = use `as` cast instead to use a previously exposed provenance + .suggestion_without_provenance_mut = if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` + lint_legacy_derive_helpers = derive helper attribute is used before it is introduced .label = the attribute is introduced here diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index fd8d0f832aa47..324de60d9921a 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1603,6 +1603,46 @@ impl<'a> LintDiagnostic<'a, ()> for DropGlue<'_> { } } +// transmute.rs +#[derive(LintDiagnostic)] +#[diag(lint_int_to_ptr_transmutes)] +#[note] +#[note(lint_note_exposed_provenance)] +#[help(lint_suggestion_without_provenance_mut)] +#[help(lint_help_transmute)] +#[help(lint_help_exposed_provenance)] +pub(crate) struct IntegerToPtrTransmutes<'tcx> { + #[subdiagnostic] + pub suggestion: IntegerToPtrTransmutesSuggestion<'tcx>, +} + +#[derive(Subdiagnostic)] +// FIXME: recommend `with_exposed_provenance` when it's const-stable +pub(crate) enum IntegerToPtrTransmutesSuggestion<'tcx> { + #[multipart_suggestion(lint_suggestion_as, applicability = "machine-applicable")] + ToPtr { + dst: Ty<'tcx>, + paren_left: &'static str, + paren_right: &'static str, + #[suggestion_part(code = "{paren_left}")] + start_call: Span, + #[suggestion_part(code = "{paren_right} as {dst}")] + end_call: Span, + }, + #[multipart_suggestion(lint_suggestion_as, applicability = "machine-applicable")] + ToRef { + dst: Ty<'tcx>, + ptr_mutbl: &'static str, + ref_mutbl: &'static str, + paren_left: &'static str, + paren_right: &'static str, + #[suggestion_part(code = "&{ref_mutbl}*({paren_left}")] + start_call: Span, + #[suggestion_part(code = "{paren_right} as *{ptr_mutbl} {dst})")] + end_call: Span, + }, +} + // types.rs #[derive(LintDiagnostic)] #[diag(lint_range_endpoint_out_of_range)] diff --git a/compiler/rustc_lint/src/transmute.rs b/compiler/rustc_lint/src/transmute.rs index bc1d4587d076e..28fb9b505cb65 100644 --- a/compiler/rustc_lint/src/transmute.rs +++ b/compiler/rustc_lint/src/transmute.rs @@ -1,3 +1,4 @@ +use rustc_ast::LitKind; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::LocalDefId; @@ -7,6 +8,7 @@ use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint, impl_lint_pass}; use rustc_span::sym; +use crate::lints::{IntegerToPtrTransmutes, IntegerToPtrTransmutesSuggestion}; use crate::{LateContext, LateLintPass}; declare_lint! { @@ -67,9 +69,42 @@ declare_lint! { "detects transmutes that can also be achieved by other operations" } +declare_lint! { + /// The `integer_to_ptr_transmutes` lint detects integer to pointer + /// transmutes where the resulting pointers are undefined behavior to dereference. + /// + /// ### Example + /// + /// ```rust + /// fn foo(a: usize) -> *const u8 { + /// unsafe { + /// std::mem::transmute::(a) + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Any attempt to use the resulting pointers are undefined behavior as the resulting + /// pointers won't have any provenance. + /// + /// Alternatively, `as` casts should be used, as they do not carry the provenance + /// requirement or if the wanting to create pointers without provenance + /// `ptr::without_provenance_mut` should be used. + /// + /// See [std::mem::transmute] in the reference for more details. + /// + /// [std::mem::transmute]: https://doc.rust-lang.org/std/mem/fn.transmute.html + pub INTEGER_TO_PTR_TRANSMUTES, + Warn, + "detects integer to pointer transmutes", +} + pub(crate) struct CheckTransmutes; -impl_lint_pass!(CheckTransmutes => [PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS, UNNECESSARY_TRANSMUTES]); +impl_lint_pass!(CheckTransmutes => [PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS, UNNECESSARY_TRANSMUTES, INTEGER_TO_PTR_TRANSMUTES]); impl<'tcx> LateLintPass<'tcx> for CheckTransmutes { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { @@ -94,6 +129,63 @@ impl<'tcx> LateLintPass<'tcx> for CheckTransmutes { check_ptr_transmute_in_const(cx, expr, body_owner_def_id, const_context, src, dst); check_unnecessary_transmute(cx, expr, callee, arg, const_context, src, dst); + check_int_to_ptr_transmute(cx, expr, arg, src, dst); + } +} + +/// Check for transmutes from integer to pointers (*const/*mut, &/&mut and fn()). +/// +/// Using the resulting pointers would be undefined behavior. +fn check_int_to_ptr_transmute<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'tcx>, + arg: &'tcx hir::Expr<'tcx>, + src: Ty<'tcx>, + dst: Ty<'tcx>, +) { + if matches!(src.kind(), ty::Uint(_) | ty::Int(_)) + && let ty::Ref(_, inner_ty, mutbl) | ty::RawPtr(inner_ty, mutbl) = dst.kind() + // bail-out if the argument is literal 0 as we have other lints for those cases + && !matches!(arg.kind, hir::ExprKind::Lit(hir::Lit { node: LitKind::Int(v, _), .. }) if v == 0) + // bail-out if the inner type if a ZST + && cx.tcx + .layout_of(cx.typing_env().as_query_input(*inner_ty)) + .is_ok_and(|layout| !layout.is_1zst()) + { + // does the argument needs parenthesis + let mut paren_left = ""; + let mut paren_right = ""; + if matches!(arg.kind, hir::ExprKind::Binary(..)) { + paren_left = "("; + paren_right = ")"; + } + + cx.tcx.emit_node_span_lint( + INTEGER_TO_PTR_TRANSMUTES, + expr.hir_id, + expr.span, + IntegerToPtrTransmutes { + suggestion: if dst.is_ref() { + IntegerToPtrTransmutesSuggestion::ToRef { + dst: *inner_ty, + ref_mutbl: mutbl.prefix_str(), + ptr_mutbl: mutbl.ptr_str(), + paren_left, + paren_right, + start_call: expr.span.shrink_to_lo().until(arg.span), + end_call: arg.span.shrink_to_hi().until(expr.span.shrink_to_hi()), + } + } else { + IntegerToPtrTransmutesSuggestion::ToPtr { + dst, + paren_left, + paren_right, + start_call: expr.span.shrink_to_lo().until(arg.span), + end_call: arg.span.shrink_to_hi().until(expr.span.shrink_to_hi()), + } + }, + }, + ); } } diff --git a/tests/ui/lint/int_to_ptr.fixed b/tests/ui/lint/int_to_ptr.fixed new file mode 100644 index 0000000000000..cb1206447334c --- /dev/null +++ b/tests/ui/lint/int_to_ptr.fixed @@ -0,0 +1,37 @@ +// Checks for the `integer_to_pointer_transmutes` lint + +//@ check-pass +//@ run-rustfix + +#![allow(unused_unsafe)] +#![allow(dead_code)] + +unsafe fn should_lint(a: usize) { + let _ptr = unsafe { a as *const u8 }; + //~^ WARN transmuting an integer to a pointer + let _ptr = unsafe { &*(a as *const u8) }; + //~^ WARN transmuting an integer to a pointer + let _ptr = unsafe { 42usize as *const u8 }; + //~^ WARN transmuting an integer to a pointer + let _ptr = unsafe { (a + a) as *const u8 }; + //~^ WARN transmuting an integer to a pointer +} + +const unsafe fn should_lintin_const(a: usize) { + let _ptr = unsafe { a as *const u8 }; + //~^ WARN transmuting an integer to a pointer + let _ptr = unsafe { &*(a as *const u8) }; + //~^ WARN transmuting an integer to a pointer + let _ptr = unsafe { 42usize as *const u8 }; + //~^ WARN transmuting an integer to a pointer + let _ptr = unsafe { (a + a) as *const u8 }; + //~^ WARN transmuting an integer to a pointer +} + +unsafe fn should_not_lint(a: usize) { + let _ptr = unsafe { std::mem::transmute::(0usize) }; // linted by other lints + let _ptr = unsafe { std::mem::transmute::(a) }; // inner type is a ZST + let _ptr = unsafe { std::mem::transmute::(a) }; // omit fn-ptr for now +} + +fn main() {} diff --git a/tests/ui/lint/int_to_ptr.rs b/tests/ui/lint/int_to_ptr.rs new file mode 100644 index 0000000000000..a991e96e656ed --- /dev/null +++ b/tests/ui/lint/int_to_ptr.rs @@ -0,0 +1,37 @@ +// Checks for the `integer_to_pointer_transmutes` lint + +//@ check-pass +//@ run-rustfix + +#![allow(unused_unsafe)] +#![allow(dead_code)] + +unsafe fn should_lint(a: usize) { + let _ptr = unsafe { std::mem::transmute::(a) }; + //~^ WARN transmuting an integer to a pointer + let _ptr = unsafe { std::mem::transmute::(a) }; + //~^ WARN transmuting an integer to a pointer + let _ptr = unsafe { std::mem::transmute::(42usize) }; + //~^ WARN transmuting an integer to a pointer + let _ptr = unsafe { std::mem::transmute::(a + a) }; + //~^ WARN transmuting an integer to a pointer +} + +const unsafe fn should_lintin_const(a: usize) { + let _ptr = unsafe { std::mem::transmute::(a) }; + //~^ WARN transmuting an integer to a pointer + let _ptr = unsafe { std::mem::transmute::(a) }; + //~^ WARN transmuting an integer to a pointer + let _ptr = unsafe { std::mem::transmute::(42usize) }; + //~^ WARN transmuting an integer to a pointer + let _ptr = unsafe { std::mem::transmute::(a + a) }; + //~^ WARN transmuting an integer to a pointer +} + +unsafe fn should_not_lint(a: usize) { + let _ptr = unsafe { std::mem::transmute::(0usize) }; // linted by other lints + let _ptr = unsafe { std::mem::transmute::(a) }; // inner type is a ZST + let _ptr = unsafe { std::mem::transmute::(a) }; // omit fn-ptr for now +} + +fn main() {} diff --git a/tests/ui/lint/int_to_ptr.stderr b/tests/ui/lint/int_to_ptr.stderr new file mode 100644 index 0000000000000..f5994379e9328 --- /dev/null +++ b/tests/ui/lint/int_to_ptr.stderr @@ -0,0 +1,139 @@ +warning: transmuting an integer to a pointer creates a pointer without provenance + --> $DIR/int_to_ptr.rs:10:25 + | +LL | let _ptr = unsafe { std::mem::transmute::(a) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this is dangerous because dereferencing the resulting pointer is undefined behavior + = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance + = help: if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` + = help: for more information about transmute, see + = help: for more information about exposed provenance, see + = note: `#[warn(integer_to_ptr_transmutes)]` on by default +help: use `as` cast instead to use a previously exposed provenance + | +LL - let _ptr = unsafe { std::mem::transmute::(a) }; +LL + let _ptr = unsafe { a as *const u8 }; + | + +warning: transmuting an integer to a pointer creates a pointer without provenance + --> $DIR/int_to_ptr.rs:12:25 + | +LL | let _ptr = unsafe { std::mem::transmute::(a) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this is dangerous because dereferencing the resulting pointer is undefined behavior + = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance + = help: if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` + = help: for more information about transmute, see + = help: for more information about exposed provenance, see +help: use `as` cast instead to use a previously exposed provenance + | +LL - let _ptr = unsafe { std::mem::transmute::(a) }; +LL + let _ptr = unsafe { &*(a as *const u8) }; + | + +warning: transmuting an integer to a pointer creates a pointer without provenance + --> $DIR/int_to_ptr.rs:14:25 + | +LL | let _ptr = unsafe { std::mem::transmute::(42usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this is dangerous because dereferencing the resulting pointer is undefined behavior + = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance + = help: if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` + = help: for more information about transmute, see + = help: for more information about exposed provenance, see +help: use `as` cast instead to use a previously exposed provenance + | +LL - let _ptr = unsafe { std::mem::transmute::(42usize) }; +LL + let _ptr = unsafe { 42usize as *const u8 }; + | + +warning: transmuting an integer to a pointer creates a pointer without provenance + --> $DIR/int_to_ptr.rs:16:25 + | +LL | let _ptr = unsafe { std::mem::transmute::(a + a) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this is dangerous because dereferencing the resulting pointer is undefined behavior + = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance + = help: if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` + = help: for more information about transmute, see + = help: for more information about exposed provenance, see +help: use `as` cast instead to use a previously exposed provenance + | +LL - let _ptr = unsafe { std::mem::transmute::(a + a) }; +LL + let _ptr = unsafe { (a + a) as *const u8 }; + | + +warning: transmuting an integer to a pointer creates a pointer without provenance + --> $DIR/int_to_ptr.rs:21:25 + | +LL | let _ptr = unsafe { std::mem::transmute::(a) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this is dangerous because dereferencing the resulting pointer is undefined behavior + = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance + = help: if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` + = help: for more information about transmute, see + = help: for more information about exposed provenance, see +help: use `as` cast instead to use a previously exposed provenance + | +LL - let _ptr = unsafe { std::mem::transmute::(a) }; +LL + let _ptr = unsafe { a as *const u8 }; + | + +warning: transmuting an integer to a pointer creates a pointer without provenance + --> $DIR/int_to_ptr.rs:23:25 + | +LL | let _ptr = unsafe { std::mem::transmute::(a) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this is dangerous because dereferencing the resulting pointer is undefined behavior + = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance + = help: if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` + = help: for more information about transmute, see + = help: for more information about exposed provenance, see +help: use `as` cast instead to use a previously exposed provenance + | +LL - let _ptr = unsafe { std::mem::transmute::(a) }; +LL + let _ptr = unsafe { &*(a as *const u8) }; + | + +warning: transmuting an integer to a pointer creates a pointer without provenance + --> $DIR/int_to_ptr.rs:25:25 + | +LL | let _ptr = unsafe { std::mem::transmute::(42usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this is dangerous because dereferencing the resulting pointer is undefined behavior + = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance + = help: if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` + = help: for more information about transmute, see + = help: for more information about exposed provenance, see +help: use `as` cast instead to use a previously exposed provenance + | +LL - let _ptr = unsafe { std::mem::transmute::(42usize) }; +LL + let _ptr = unsafe { 42usize as *const u8 }; + | + +warning: transmuting an integer to a pointer creates a pointer without provenance + --> $DIR/int_to_ptr.rs:27:25 + | +LL | let _ptr = unsafe { std::mem::transmute::(a + a) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this is dangerous because dereferencing the resulting pointer is undefined behavior + = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance + = help: if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` + = help: for more information about transmute, see + = help: for more information about exposed provenance, see +help: use `as` cast instead to use a previously exposed provenance + | +LL - let _ptr = unsafe { std::mem::transmute::(a + a) }; +LL + let _ptr = unsafe { (a + a) as *const u8 }; + | + +warning: 8 warnings emitted + From 8ea4d2f4854ffdc295ecc1743d61c69b5b1dccfd Mon Sep 17 00:00:00 2001 From: Urgau Date: Sun, 27 Jul 2025 13:20:46 +0200 Subject: [PATCH 2/5] Allow `integer_to_ptr_transmutes` in core --- library/core/src/ptr/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index dbe3999b4a433..d9b5e791e1d25 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -914,6 +914,7 @@ pub const fn dangling() -> *const T { #[must_use] #[stable(feature = "strict_provenance", since = "1.84.0")] #[rustc_const_stable(feature = "strict_provenance", since = "1.84.0")] +#[allow(integer_to_ptr_transmutes)] // Expected semantics here. pub const fn without_provenance_mut(addr: usize) -> *mut T { // An int-to-pointer transmute currently has exactly the intended semantics: it creates a // pointer without provenance. Note that this is *not* a stable guarantee about transmute From 28bcb169f044fd1489af9181386fae597550b3be Mon Sep 17 00:00:00 2001 From: Urgau Date: Sun, 27 Jul 2025 13:41:10 +0200 Subject: [PATCH 3/5] Allow `integer_to_ptr_transmutes` in tests --- src/tools/miri/tests/fail/branchless-select-i128-pointer.rs | 2 ++ src/tools/miri/tests/fail/provenance/provenance_transmute.rs | 2 ++ src/tools/miri/tests/fail/validity/dangling_ref1.rs | 3 +++ src/tools/miri/tests/panic/transmute_fat2.rs | 2 ++ src/tools/miri/tests/pass/binops.rs | 1 + src/tools/miri/tests/pass/too-large-primval-write-problem.rs | 2 ++ tests/ui/binop/binops.rs | 1 + 7 files changed, 13 insertions(+) diff --git a/src/tools/miri/tests/fail/branchless-select-i128-pointer.rs b/src/tools/miri/tests/fail/branchless-select-i128-pointer.rs index 2b861e5447b03..7147813c4b6c1 100644 --- a/src/tools/miri/tests/fail/branchless-select-i128-pointer.rs +++ b/src/tools/miri/tests/fail/branchless-select-i128-pointer.rs @@ -1,3 +1,5 @@ +#![allow(integer_to_ptr_transmutes)] + use std::mem::transmute; #[cfg(target_pointer_width = "32")] diff --git a/src/tools/miri/tests/fail/provenance/provenance_transmute.rs b/src/tools/miri/tests/fail/provenance/provenance_transmute.rs index d72f10530d7ab..60cb9a7f6bfb1 100644 --- a/src/tools/miri/tests/fail/provenance/provenance_transmute.rs +++ b/src/tools/miri/tests/fail/provenance/provenance_transmute.rs @@ -1,5 +1,7 @@ //@compile-flags: -Zmiri-permissive-provenance +#![allow(integer_to_ptr_transmutes)] + use std::mem; // This is the example from diff --git a/src/tools/miri/tests/fail/validity/dangling_ref1.rs b/src/tools/miri/tests/fail/validity/dangling_ref1.rs index fc3a9f344638f..57ba1117e765e 100644 --- a/src/tools/miri/tests/fail/validity/dangling_ref1.rs +++ b/src/tools/miri/tests/fail/validity/dangling_ref1.rs @@ -1,5 +1,8 @@ // Make sure we catch this even without Stacked Borrows //@compile-flags: -Zmiri-disable-stacked-borrows + +#![allow(integer_to_ptr_transmutes)] + use std::mem; fn main() { diff --git a/src/tools/miri/tests/panic/transmute_fat2.rs b/src/tools/miri/tests/panic/transmute_fat2.rs index e695ff2d57ba5..7441f25d03ea7 100644 --- a/src/tools/miri/tests/panic/transmute_fat2.rs +++ b/src/tools/miri/tests/panic/transmute_fat2.rs @@ -1,3 +1,5 @@ +#![allow(integer_to_ptr_transmutes)] + fn main() { #[cfg(all(target_endian = "little", target_pointer_width = "64"))] let bad = unsafe { std::mem::transmute::(42) }; diff --git a/src/tools/miri/tests/pass/binops.rs b/src/tools/miri/tests/pass/binops.rs index 0aff7acb29d44..fcbe6c85b7b8f 100644 --- a/src/tools/miri/tests/pass/binops.rs +++ b/src/tools/miri/tests/pass/binops.rs @@ -32,6 +32,7 @@ fn test_bool() { assert_eq!(true ^ true, false); } +#[allow(integer_to_ptr_transmutes)] fn test_ptr() { unsafe { let p1: *const u8 = ::std::mem::transmute(0_usize); diff --git a/src/tools/miri/tests/pass/too-large-primval-write-problem.rs b/src/tools/miri/tests/pass/too-large-primval-write-problem.rs index f4c418bd78a99..00882b7ecca6e 100644 --- a/src/tools/miri/tests/pass/too-large-primval-write-problem.rs +++ b/src/tools/miri/tests/pass/too-large-primval-write-problem.rs @@ -7,6 +7,8 @@ // // This is just intended as a regression test to make sure we don't reintroduce this problem. +#![allow(integer_to_ptr_transmutes)] + #[cfg(target_pointer_width = "32")] fn main() { use std::mem::transmute; diff --git a/tests/ui/binop/binops.rs b/tests/ui/binop/binops.rs index 7142190a45b9a..702e9a61345b7 100644 --- a/tests/ui/binop/binops.rs +++ b/tests/ui/binop/binops.rs @@ -35,6 +35,7 @@ fn test_bool() { assert_eq!(true ^ true, false); } +#[allow(integer_to_ptr_transmutes)] fn test_ptr() { unsafe { let p1: *const u8 = ::std::mem::transmute(0_usize); From f1eb2c4d45010c40c178232de4ea8aec8c567ba2 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sun, 27 Jul 2025 18:17:06 +0200 Subject: [PATCH 4/5] Recommend `with_exposed_provenance` instead of `as` casts in non-const --- compiler/rustc_lint/src/lints.rs | 21 ++++- compiler/rustc_lint/src/transmute.rs | 78 +++++++++++------ tests/ui/lint/int_to_ptr.fixed | 22 +++-- tests/ui/lint/int_to_ptr.rs | 18 +++- tests/ui/lint/int_to_ptr.stderr | 122 +++++++++++++++++++++------ 5 files changed, 194 insertions(+), 67 deletions(-) diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 324de60d9921a..8f2c6bf5f1b32 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1617,10 +1617,27 @@ pub(crate) struct IntegerToPtrTransmutes<'tcx> { } #[derive(Subdiagnostic)] -// FIXME: recommend `with_exposed_provenance` when it's const-stable +// FIXME: always recommend `with_exposed_provenance` when it's const-stable pub(crate) enum IntegerToPtrTransmutesSuggestion<'tcx> { #[multipart_suggestion(lint_suggestion_as, applicability = "machine-applicable")] ToPtr { + dst: Ty<'tcx>, + suffix: &'static str, + #[suggestion_part(code = "std::ptr::with_exposed_provenance{suffix}::<{dst}>(")] + start_call: Span, + }, + #[multipart_suggestion(lint_suggestion_as, applicability = "machine-applicable")] + ToRef { + dst: Ty<'tcx>, + suffix: &'static str, + ref_mutbl: &'static str, + #[suggestion_part( + code = "&{ref_mutbl}*std::ptr::with_exposed_provenance{suffix}::<{dst}>(" + )] + start_call: Span, + }, + #[multipart_suggestion(lint_suggestion_as, applicability = "machine-applicable")] + ToPtrInConst { dst: Ty<'tcx>, paren_left: &'static str, paren_right: &'static str, @@ -1630,7 +1647,7 @@ pub(crate) enum IntegerToPtrTransmutesSuggestion<'tcx> { end_call: Span, }, #[multipart_suggestion(lint_suggestion_as, applicability = "machine-applicable")] - ToRef { + ToRefInConst { dst: Ty<'tcx>, ptr_mutbl: &'static str, ref_mutbl: &'static str, diff --git a/compiler/rustc_lint/src/transmute.rs b/compiler/rustc_lint/src/transmute.rs index 28fb9b505cb65..881ee53b8929c 100644 --- a/compiler/rustc_lint/src/transmute.rs +++ b/compiler/rustc_lint/src/transmute.rs @@ -90,13 +90,15 @@ declare_lint! { /// Any attempt to use the resulting pointers are undefined behavior as the resulting /// pointers won't have any provenance. /// - /// Alternatively, `as` casts should be used, as they do not carry the provenance - /// requirement or if the wanting to create pointers without provenance - /// `ptr::without_provenance_mut` should be used. + /// Alternatively, [`std::ptr::with_exposed_provenance`] or `as` casts should be used, + /// as they do not carry the provenance requirement. If the wanting to create pointers + /// without provenance [`std::ptr::without_provenance`] should be used instead. /// - /// See [std::mem::transmute] in the reference for more details. + /// See [`std::mem::transmute`] in the reference for more details. /// - /// [std::mem::transmute]: https://doc.rust-lang.org/std/mem/fn.transmute.html + /// [`std::mem::transmute`]: https://doc.rust-lang.org/std/mem/fn.transmute.html + /// [`std::ptr::with_exposed_provenance`]: https://doc.rust-lang.org/std/ptr/fn.with_exposed_provenance.html + /// [`std::ptr::without_provenance`]: https://doc.rust-lang.org/std/ptr/fn.without_provenance.html pub INTEGER_TO_PTR_TRANSMUTES, Warn, "detects integer to pointer transmutes", @@ -152,36 +154,56 @@ fn check_int_to_ptr_transmute<'tcx>( .layout_of(cx.typing_env().as_query_input(*inner_ty)) .is_ok_and(|layout| !layout.is_1zst()) { - // does the argument needs parenthesis - let mut paren_left = ""; - let mut paren_right = ""; - if matches!(arg.kind, hir::ExprKind::Binary(..)) { - paren_left = "("; - paren_right = ")"; - } - cx.tcx.emit_node_span_lint( INTEGER_TO_PTR_TRANSMUTES, expr.hir_id, expr.span, IntegerToPtrTransmutes { - suggestion: if dst.is_ref() { - IntegerToPtrTransmutesSuggestion::ToRef { - dst: *inner_ty, - ref_mutbl: mutbl.prefix_str(), - ptr_mutbl: mutbl.ptr_str(), - paren_left, - paren_right, - start_call: expr.span.shrink_to_lo().until(arg.span), - end_call: arg.span.shrink_to_hi().until(expr.span.shrink_to_hi()), + // FIXME: once https://github.com/rust-lang/rust/issues/144538 finishes, + // we can recommend the method in const context too. + suggestion: if !cx.tcx.hir_is_inside_const_context(expr.hir_id) { + let suffix = if mutbl.is_mut() { "_mut" } else { "" }; + if dst.is_ref() { + IntegerToPtrTransmutesSuggestion::ToRef { + dst: *inner_ty, + suffix, + ref_mutbl: mutbl.prefix_str(), + start_call: expr.span.shrink_to_lo().until(arg.span), + } + } else { + IntegerToPtrTransmutesSuggestion::ToPtr { + dst: *inner_ty, + suffix, + start_call: expr.span.shrink_to_lo().until(arg.span), + } } } else { - IntegerToPtrTransmutesSuggestion::ToPtr { - dst, - paren_left, - paren_right, - start_call: expr.span.shrink_to_lo().until(arg.span), - end_call: arg.span.shrink_to_hi().until(expr.span.shrink_to_hi()), + // does the argument needs parenthesis + let mut paren_left = ""; + let mut paren_right = ""; + if matches!(arg.kind, hir::ExprKind::Binary(..)) { + paren_left = "("; + paren_right = ")"; + } + + if dst.is_ref() { + IntegerToPtrTransmutesSuggestion::ToRefInConst { + dst: *inner_ty, + ref_mutbl: mutbl.prefix_str(), + ptr_mutbl: mutbl.ptr_str(), + paren_left, + paren_right, + start_call: expr.span.shrink_to_lo().until(arg.span), + end_call: arg.span.shrink_to_hi().until(expr.span.shrink_to_hi()), + } + } else { + IntegerToPtrTransmutesSuggestion::ToPtrInConst { + dst, + paren_left, + paren_right, + start_call: expr.span.shrink_to_lo().until(arg.span), + end_call: arg.span.shrink_to_hi().until(expr.span.shrink_to_hi()), + } } }, }, diff --git a/tests/ui/lint/int_to_ptr.fixed b/tests/ui/lint/int_to_ptr.fixed index cb1206447334c..e2248aadcc2c2 100644 --- a/tests/ui/lint/int_to_ptr.fixed +++ b/tests/ui/lint/int_to_ptr.fixed @@ -7,21 +7,31 @@ #![allow(dead_code)] unsafe fn should_lint(a: usize) { - let _ptr = unsafe { a as *const u8 }; + let _ptr: *const u8 = unsafe { std::ptr::with_exposed_provenance::(a) }; //~^ WARN transmuting an integer to a pointer - let _ptr = unsafe { &*(a as *const u8) }; + let _ptr: *mut u8 = unsafe { std::ptr::with_exposed_provenance_mut::(a) }; //~^ WARN transmuting an integer to a pointer - let _ptr = unsafe { 42usize as *const u8 }; + let _ref: &'static u8 = unsafe { &*std::ptr::with_exposed_provenance::(a) }; //~^ WARN transmuting an integer to a pointer - let _ptr = unsafe { (a + a) as *const u8 }; + let _ref: &'static mut u8 = unsafe { &mut *std::ptr::with_exposed_provenance_mut::(a) }; + //~^ WARN transmuting an integer to a pointer + + let _ptr = unsafe { std::ptr::with_exposed_provenance::(42usize) }; + //~^ WARN transmuting an integer to a pointer + let _ptr = unsafe { std::ptr::with_exposed_provenance::(a + a) }; //~^ WARN transmuting an integer to a pointer } const unsafe fn should_lintin_const(a: usize) { - let _ptr = unsafe { a as *const u8 }; + let _ptr: *const u8 = unsafe { a as *const u8 }; + //~^ WARN transmuting an integer to a pointer + let _ptr: *mut u8 = unsafe { a as *mut u8 }; //~^ WARN transmuting an integer to a pointer - let _ptr = unsafe { &*(a as *const u8) }; + let _ref: &'static u8 = unsafe { &*(a as *const u8) }; //~^ WARN transmuting an integer to a pointer + let _ref: &'static mut u8 = unsafe { &mut *(a as *mut u8) }; + //~^ WARN transmuting an integer to a pointer + let _ptr = unsafe { 42usize as *const u8 }; //~^ WARN transmuting an integer to a pointer let _ptr = unsafe { (a + a) as *const u8 }; diff --git a/tests/ui/lint/int_to_ptr.rs b/tests/ui/lint/int_to_ptr.rs index a991e96e656ed..7f60da47b85d8 100644 --- a/tests/ui/lint/int_to_ptr.rs +++ b/tests/ui/lint/int_to_ptr.rs @@ -7,10 +7,15 @@ #![allow(dead_code)] unsafe fn should_lint(a: usize) { - let _ptr = unsafe { std::mem::transmute::(a) }; + let _ptr: *const u8 = unsafe { std::mem::transmute::(a) }; //~^ WARN transmuting an integer to a pointer - let _ptr = unsafe { std::mem::transmute::(a) }; + let _ptr: *mut u8 = unsafe { std::mem::transmute::(a) }; //~^ WARN transmuting an integer to a pointer + let _ref: &'static u8 = unsafe { std::mem::transmute::(a) }; + //~^ WARN transmuting an integer to a pointer + let _ref: &'static mut u8 = unsafe { std::mem::transmute::(a) }; + //~^ WARN transmuting an integer to a pointer + let _ptr = unsafe { std::mem::transmute::(42usize) }; //~^ WARN transmuting an integer to a pointer let _ptr = unsafe { std::mem::transmute::(a + a) }; @@ -18,10 +23,15 @@ unsafe fn should_lint(a: usize) { } const unsafe fn should_lintin_const(a: usize) { - let _ptr = unsafe { std::mem::transmute::(a) }; + let _ptr: *const u8 = unsafe { std::mem::transmute::(a) }; //~^ WARN transmuting an integer to a pointer - let _ptr = unsafe { std::mem::transmute::(a) }; + let _ptr: *mut u8 = unsafe { std::mem::transmute::(a) }; //~^ WARN transmuting an integer to a pointer + let _ref: &'static u8 = unsafe { std::mem::transmute::(a) }; + //~^ WARN transmuting an integer to a pointer + let _ref: &'static mut u8 = unsafe { std::mem::transmute::(a) }; + //~^ WARN transmuting an integer to a pointer + let _ptr = unsafe { std::mem::transmute::(42usize) }; //~^ WARN transmuting an integer to a pointer let _ptr = unsafe { std::mem::transmute::(a + a) }; diff --git a/tests/ui/lint/int_to_ptr.stderr b/tests/ui/lint/int_to_ptr.stderr index f5994379e9328..ab7a3bc08551e 100644 --- a/tests/ui/lint/int_to_ptr.stderr +++ b/tests/ui/lint/int_to_ptr.stderr @@ -1,8 +1,8 @@ warning: transmuting an integer to a pointer creates a pointer without provenance - --> $DIR/int_to_ptr.rs:10:25 + --> $DIR/int_to_ptr.rs:10:36 | -LL | let _ptr = unsafe { std::mem::transmute::(a) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _ptr: *const u8 = unsafe { std::mem::transmute::(a) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this is dangerous because dereferencing the resulting pointer is undefined behavior = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance @@ -12,15 +12,15 @@ LL | let _ptr = unsafe { std::mem::transmute::(a) }; = note: `#[warn(integer_to_ptr_transmutes)]` on by default help: use `as` cast instead to use a previously exposed provenance | -LL - let _ptr = unsafe { std::mem::transmute::(a) }; -LL + let _ptr = unsafe { a as *const u8 }; +LL - let _ptr: *const u8 = unsafe { std::mem::transmute::(a) }; +LL + let _ptr: *const u8 = unsafe { std::ptr::with_exposed_provenance::(a) }; | warning: transmuting an integer to a pointer creates a pointer without provenance - --> $DIR/int_to_ptr.rs:12:25 + --> $DIR/int_to_ptr.rs:12:34 | -LL | let _ptr = unsafe { std::mem::transmute::(a) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _ptr: *mut u8 = unsafe { std::mem::transmute::(a) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this is dangerous because dereferencing the resulting pointer is undefined behavior = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance @@ -29,12 +29,46 @@ LL | let _ptr = unsafe { std::mem::transmute::(a) }; = help: for more information about exposed provenance, see help: use `as` cast instead to use a previously exposed provenance | -LL - let _ptr = unsafe { std::mem::transmute::(a) }; -LL + let _ptr = unsafe { &*(a as *const u8) }; +LL - let _ptr: *mut u8 = unsafe { std::mem::transmute::(a) }; +LL + let _ptr: *mut u8 = unsafe { std::ptr::with_exposed_provenance_mut::(a) }; | warning: transmuting an integer to a pointer creates a pointer without provenance - --> $DIR/int_to_ptr.rs:14:25 + --> $DIR/int_to_ptr.rs:14:38 + | +LL | let _ref: &'static u8 = unsafe { std::mem::transmute::(a) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this is dangerous because dereferencing the resulting pointer is undefined behavior + = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance + = help: if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` + = help: for more information about transmute, see + = help: for more information about exposed provenance, see +help: use `as` cast instead to use a previously exposed provenance + | +LL - let _ref: &'static u8 = unsafe { std::mem::transmute::(a) }; +LL + let _ref: &'static u8 = unsafe { &*std::ptr::with_exposed_provenance::(a) }; + | + +warning: transmuting an integer to a pointer creates a pointer without provenance + --> $DIR/int_to_ptr.rs:16:42 + | +LL | let _ref: &'static mut u8 = unsafe { std::mem::transmute::(a) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this is dangerous because dereferencing the resulting pointer is undefined behavior + = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance + = help: if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` + = help: for more information about transmute, see + = help: for more information about exposed provenance, see +help: use `as` cast instead to use a previously exposed provenance + | +LL - let _ref: &'static mut u8 = unsafe { std::mem::transmute::(a) }; +LL + let _ref: &'static mut u8 = unsafe { &mut *std::ptr::with_exposed_provenance_mut::(a) }; + | + +warning: transmuting an integer to a pointer creates a pointer without provenance + --> $DIR/int_to_ptr.rs:19:25 | LL | let _ptr = unsafe { std::mem::transmute::(42usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -47,11 +81,11 @@ LL | let _ptr = unsafe { std::mem::transmute::(42usize) }; help: use `as` cast instead to use a previously exposed provenance | LL - let _ptr = unsafe { std::mem::transmute::(42usize) }; -LL + let _ptr = unsafe { 42usize as *const u8 }; +LL + let _ptr = unsafe { std::ptr::with_exposed_provenance::(42usize) }; | warning: transmuting an integer to a pointer creates a pointer without provenance - --> $DIR/int_to_ptr.rs:16:25 + --> $DIR/int_to_ptr.rs:21:25 | LL | let _ptr = unsafe { std::mem::transmute::(a + a) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -64,14 +98,48 @@ LL | let _ptr = unsafe { std::mem::transmute::(a + a) }; help: use `as` cast instead to use a previously exposed provenance | LL - let _ptr = unsafe { std::mem::transmute::(a + a) }; -LL + let _ptr = unsafe { (a + a) as *const u8 }; +LL + let _ptr = unsafe { std::ptr::with_exposed_provenance::(a + a) }; | warning: transmuting an integer to a pointer creates a pointer without provenance - --> $DIR/int_to_ptr.rs:21:25 + --> $DIR/int_to_ptr.rs:26:36 + | +LL | let _ptr: *const u8 = unsafe { std::mem::transmute::(a) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this is dangerous because dereferencing the resulting pointer is undefined behavior + = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance + = help: if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` + = help: for more information about transmute, see + = help: for more information about exposed provenance, see +help: use `as` cast instead to use a previously exposed provenance + | +LL - let _ptr: *const u8 = unsafe { std::mem::transmute::(a) }; +LL + let _ptr: *const u8 = unsafe { a as *const u8 }; + | + +warning: transmuting an integer to a pointer creates a pointer without provenance + --> $DIR/int_to_ptr.rs:28:34 + | +LL | let _ptr: *mut u8 = unsafe { std::mem::transmute::(a) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this is dangerous because dereferencing the resulting pointer is undefined behavior + = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance + = help: if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` + = help: for more information about transmute, see + = help: for more information about exposed provenance, see +help: use `as` cast instead to use a previously exposed provenance + | +LL - let _ptr: *mut u8 = unsafe { std::mem::transmute::(a) }; +LL + let _ptr: *mut u8 = unsafe { a as *mut u8 }; + | + +warning: transmuting an integer to a pointer creates a pointer without provenance + --> $DIR/int_to_ptr.rs:30:38 | -LL | let _ptr = unsafe { std::mem::transmute::(a) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _ref: &'static u8 = unsafe { std::mem::transmute::(a) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this is dangerous because dereferencing the resulting pointer is undefined behavior = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance @@ -80,15 +148,15 @@ LL | let _ptr = unsafe { std::mem::transmute::(a) }; = help: for more information about exposed provenance, see help: use `as` cast instead to use a previously exposed provenance | -LL - let _ptr = unsafe { std::mem::transmute::(a) }; -LL + let _ptr = unsafe { a as *const u8 }; +LL - let _ref: &'static u8 = unsafe { std::mem::transmute::(a) }; +LL + let _ref: &'static u8 = unsafe { &*(a as *const u8) }; | warning: transmuting an integer to a pointer creates a pointer without provenance - --> $DIR/int_to_ptr.rs:23:25 + --> $DIR/int_to_ptr.rs:32:42 | -LL | let _ptr = unsafe { std::mem::transmute::(a) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _ref: &'static mut u8 = unsafe { std::mem::transmute::(a) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this is dangerous because dereferencing the resulting pointer is undefined behavior = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance @@ -97,12 +165,12 @@ LL | let _ptr = unsafe { std::mem::transmute::(a) }; = help: for more information about exposed provenance, see help: use `as` cast instead to use a previously exposed provenance | -LL - let _ptr = unsafe { std::mem::transmute::(a) }; -LL + let _ptr = unsafe { &*(a as *const u8) }; +LL - let _ref: &'static mut u8 = unsafe { std::mem::transmute::(a) }; +LL + let _ref: &'static mut u8 = unsafe { &mut *(a as *mut u8) }; | warning: transmuting an integer to a pointer creates a pointer without provenance - --> $DIR/int_to_ptr.rs:25:25 + --> $DIR/int_to_ptr.rs:35:25 | LL | let _ptr = unsafe { std::mem::transmute::(42usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -119,7 +187,7 @@ LL + let _ptr = unsafe { 42usize as *const u8 }; | warning: transmuting an integer to a pointer creates a pointer without provenance - --> $DIR/int_to_ptr.rs:27:25 + --> $DIR/int_to_ptr.rs:37:25 | LL | let _ptr = unsafe { std::mem::transmute::(a + a) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -135,5 +203,5 @@ LL - let _ptr = unsafe { std::mem::transmute::(a + a) }; LL + let _ptr = unsafe { (a + a) as *const u8 }; | -warning: 8 warnings emitted +warning: 12 warnings emitted From 18980df6cd19c6e87746634d894f0fdfc679bf28 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sun, 27 Jul 2025 21:21:49 +0200 Subject: [PATCH 5/5] Adjust clippy lints for rustc `integer_to_ptr_transmutes` lint --- .../src/transmute/useless_transmute.rs | 12 +---- src/tools/clippy/tests/ui/transmute.rs | 3 +- src/tools/clippy/tests/ui/transmute.stderr | 46 +++++++------------ .../transmutes_expressible_as_ptr_casts.fixed | 3 -- .../ui/transmutes_expressible_as_ptr_casts.rs | 3 -- ...transmutes_expressible_as_ptr_casts.stderr | 32 ++++++------- 6 files changed, 32 insertions(+), 67 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs index ec5fb2793f976..b898920baefc2 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs @@ -49,17 +49,7 @@ pub(super) fn check<'tcx>( true }, (ty::Int(_) | ty::Uint(_), ty::RawPtr(_, _)) => { - span_lint_and_then( - cx, - USELESS_TRANSMUTE, - e.span, - "transmute from an integer to a pointer", - |diag| { - if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) { - diag.span_suggestion(e.span, "try", arg.as_ty(to_ty.to_string()), Applicability::Unspecified); - } - }, - ); + // Handled by the upstream rustc `integer_to_ptr_transmutes` lint true }, _ => false, diff --git a/src/tools/clippy/tests/ui/transmute.rs b/src/tools/clippy/tests/ui/transmute.rs index e968e7a59244d..e7099104f942d 100644 --- a/src/tools/clippy/tests/ui/transmute.rs +++ b/src/tools/clippy/tests/ui/transmute.rs @@ -4,6 +4,7 @@ dead_code, clippy::borrow_as_ptr, unnecessary_transmutes, + integer_to_ptr_transmutes, clippy::needless_lifetimes, clippy::missing_transmute_annotations )] @@ -60,12 +61,10 @@ fn useless() { //~^ useless_transmute let _: *const usize = std::mem::transmute(5_isize); - //~^ useless_transmute let _ = std::ptr::dangling::(); let _: *const usize = std::mem::transmute(1 + 1usize); - //~^ useless_transmute let _ = (1 + 1_usize) as *const usize; } diff --git a/src/tools/clippy/tests/ui/transmute.stderr b/src/tools/clippy/tests/ui/transmute.stderr index 79528ec06f1bf..9478db09481a8 100644 --- a/src/tools/clippy/tests/ui/transmute.stderr +++ b/src/tools/clippy/tests/ui/transmute.stderr @@ -1,5 +1,5 @@ error: transmute from a reference to a pointer - --> tests/ui/transmute.rs:33:27 + --> tests/ui/transmute.rs:34:27 | LL | let _: *const T = core::mem::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T` @@ -8,61 +8,49 @@ LL | let _: *const T = core::mem::transmute(t); = help: to override `-D warnings` add `#[allow(clippy::useless_transmute)]` error: transmute from a reference to a pointer - --> tests/ui/transmute.rs:36:25 + --> tests/ui/transmute.rs:37:25 | LL | let _: *mut T = core::mem::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *mut T` error: transmute from a reference to a pointer - --> tests/ui/transmute.rs:39:27 + --> tests/ui/transmute.rs:40:27 | LL | let _: *const U = core::mem::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *const U` error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:47:27 + --> tests/ui/transmute.rs:48:27 | LL | let _: Vec = core::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:50:27 + --> tests/ui/transmute.rs:51:27 | LL | let _: Vec = core::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:53:27 + --> tests/ui/transmute.rs:54:27 | LL | let _: Vec = std::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:56:27 + --> tests/ui/transmute.rs:57:27 | LL | let _: Vec = std::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:59:27 + --> tests/ui/transmute.rs:60:27 | LL | let _: Vec = my_transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^ -error: transmute from an integer to a pointer - --> tests/ui/transmute.rs:62:31 - | -LL | let _: *const usize = std::mem::transmute(5_isize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `5_isize as *const usize` - -error: transmute from an integer to a pointer - --> tests/ui/transmute.rs:67:31 - | -LL | let _: *const usize = std::mem::transmute(1 + 1usize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(1 + 1usize) as *const usize` - error: transmute from a type (`*const Usize`) to the type that it points to (`Usize`) - --> tests/ui/transmute.rs:99:24 + --> tests/ui/transmute.rs:98:24 | LL | let _: Usize = core::mem::transmute(int_const_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -71,25 +59,25 @@ LL | let _: Usize = core::mem::transmute(int_const_ptr); = help: to override `-D warnings` add `#[allow(clippy::crosspointer_transmute)]` error: transmute from a type (`*mut Usize`) to the type that it points to (`Usize`) - --> tests/ui/transmute.rs:102:24 + --> tests/ui/transmute.rs:101:24 | LL | let _: Usize = core::mem::transmute(int_mut_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`Usize`) to a pointer to that type (`*const Usize`) - --> tests/ui/transmute.rs:105:31 + --> tests/ui/transmute.rs:104:31 | LL | let _: *const Usize = core::mem::transmute(my_int()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`Usize`) to a pointer to that type (`*mut Usize`) - --> tests/ui/transmute.rs:108:29 + --> tests/ui/transmute.rs:107:29 | LL | let _: *mut Usize = core::mem::transmute(my_int()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a `u8` to a `bool` - --> tests/ui/transmute.rs:115:28 + --> tests/ui/transmute.rs:114:28 | LL | let _: bool = unsafe { std::mem::transmute(0_u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `0_u8 != 0` @@ -98,7 +86,7 @@ LL | let _: bool = unsafe { std::mem::transmute(0_u8) }; = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_bool)]` error: transmute from a `&[u8]` to a `&str` - --> tests/ui/transmute.rs:122:28 + --> tests/ui/transmute.rs:121:28 | LL | let _: &str = unsafe { std::mem::transmute(B) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(B).unwrap()` @@ -107,16 +95,16 @@ LL | let _: &str = unsafe { std::mem::transmute(B) }; = help: to override `-D warnings` add `#[allow(clippy::transmute_bytes_to_str)]` error: transmute from a `&mut [u8]` to a `&mut str` - --> tests/ui/transmute.rs:125:32 + --> tests/ui/transmute.rs:124:32 | LL | let _: &mut str = unsafe { std::mem::transmute(mb) }; | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()` error: transmute from a `&[u8]` to a `&str` - --> tests/ui/transmute.rs:128:30 + --> tests/ui/transmute.rs:127:30 | LL | const _: &str = unsafe { std::mem::transmute(B) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_unchecked(B)` -error: aborting due to 18 previous errors +error: aborting due to 16 previous errors diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed index e7ad2a1cbbcb1..02f67f79e2b19 100644 --- a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed +++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed @@ -13,9 +13,6 @@ fn main() { // We should see an error message for each transmute, and no error messages for // the casts, since the casts are the recommended fixes. - // e is an integer and U is *U_0, while U_0: Sized; addr-ptr-cast - let _ptr_i32_transmute = unsafe { usize::MAX as *const i32 }; - //~^ useless_transmute let ptr_i32 = usize::MAX as *const i32; // e has type *T, U is *U_0, and either U_0: Sized ... diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs index 42a81777a8267..c5e156405ebca 100644 --- a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs +++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs @@ -13,9 +13,6 @@ fn main() { // We should see an error message for each transmute, and no error messages for // the casts, since the casts are the recommended fixes. - // e is an integer and U is *U_0, while U_0: Sized; addr-ptr-cast - let _ptr_i32_transmute = unsafe { transmute::(usize::MAX) }; - //~^ useless_transmute let ptr_i32 = usize::MAX as *const i32; // e has type *T, U is *U_0, and either U_0: Sized ... diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr index 7746f087cc714..f39a64d57eb49 100644 --- a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr +++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr @@ -1,14 +1,5 @@ -error: transmute from an integer to a pointer - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:17:39 - | -LL | let _ptr_i32_transmute = unsafe { transmute::(usize::MAX) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `usize::MAX as *const i32` - | - = note: `-D clippy::useless-transmute` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::useless_transmute)]` - error: transmute from a pointer to a pointer - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:22:38 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:19:38 | LL | let _ptr_i8_transmute = unsafe { transmute::<*const i32, *const i8>(ptr_i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -22,7 +13,7 @@ LL + let _ptr_i8_transmute = unsafe { ptr_i32.cast::() }; | error: transmute from a pointer to a pointer - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:29:46 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:26:46 | LL | let _ptr_to_unsized_transmute = unsafe { transmute::<*const [i32], *const [u32]>(slice_ptr) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -34,7 +25,7 @@ LL + let _ptr_to_unsized_transmute = unsafe { slice_ptr as *const [u32] }; | error: transmute from `*const i32` to `usize` which could be expressed as a pointer cast instead - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:36:50 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:33:50 | LL | let _usize_from_int_ptr_transmute = unsafe { transmute::<*const i32, usize>(ptr_i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr_i32 as usize` @@ -43,40 +34,43 @@ LL | let _usize_from_int_ptr_transmute = unsafe { transmute::<*const i32, us = help: to override `-D warnings` add `#[allow(clippy::transmutes_expressible_as_ptr_casts)]` error: transmute from a reference to a pointer - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:43:41 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:40:41 | LL | let _array_ptr_transmute = unsafe { transmute::<&[i32; 4], *const [i32; 4]>(array_ref) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `array_ref as *const [i32; 4]` + | + = note: `-D clippy::useless-transmute` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::useless_transmute)]` error: transmute from `fn(usize) -> u8` to `*const usize` which could be expressed as a pointer cast instead - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:52:41 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:49:41 | LL | let _usize_ptr_transmute = unsafe { transmute:: u8, *const usize>(foo) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `foo as *const usize` error: transmute from `fn(usize) -> u8` to `usize` which could be expressed as a pointer cast instead - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:57:49 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:54:49 | LL | let _usize_from_fn_ptr_transmute = unsafe { transmute:: u8, usize>(foo) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `foo as usize` error: transmute from `*const u32` to `usize` which could be expressed as a pointer cast instead - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:61:36 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:58:36 | LL | let _usize_from_ref = unsafe { transmute::<*const u32, usize>(&1u32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&1u32 as *const u32 as usize` error: transmute from a reference to a pointer - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:73:14 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:70:14 | LL | unsafe { transmute::<&[i32; 1], *const u8>(in_param) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `in_param as *const [i32; 1] as *const u8` error: transmute from `fn()` to `*const u8` which could be expressed as a pointer cast instead - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:92:28 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:89:28 | LL | let _x: u8 = unsafe { *std::mem::transmute::(f) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(f as *const u8)` -error: aborting due to 10 previous errors +error: aborting due to 9 previous errors