Skip to content

Commit f37b9c0

Browse files
authored
fix(transmute_ptr_to_ref): don't suggest .cast when to-type is DST (#15621)
Fixes #13357 Determining the exact placement of the `if !to_ref_ty.is_sized()`s required meticulously constructing the suggestion/truth table of `is_sized`, `msrv.meets` and `has_erased_regions`. The test cases should hopefully cover all the new combinations. changelog: [`transmute_ptr_to_ref`]: don't suggest `.cast` when to-type is DST
2 parents 49ae1d4 + 1f86679 commit f37b9c0

File tree

4 files changed

+150
-26
lines changed

4 files changed

+150
-26
lines changed

clippy_lints/src/transmute/transmute_ptr_to_ref.rs

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,32 +28,50 @@ pub(super) fn check<'tcx>(
2828
format!("transmute from a pointer type (`{from_ty}`) to a reference type (`{to_ty}`)"),
2929
|diag| {
3030
let arg = sugg::Sugg::hir(cx, arg, "..");
31-
let (deref, cast) = if *mutbl == Mutability::Mut {
32-
("&mut *", "*mut")
33-
} else {
34-
("&*", "*const")
31+
let (deref, cast) = match mutbl {
32+
Mutability::Mut => ("&mut *", "*mut"),
33+
Mutability::Not => ("&*", "*const"),
3534
};
3635
let mut app = Applicability::MachineApplicable;
3736

3837
let sugg = if let Some(ty) = get_explicit_type(path) {
3938
let ty_snip = snippet_with_applicability(cx, ty.span, "..", &mut app);
40-
if msrv.meets(cx, msrvs::POINTER_CAST) {
39+
if !to_ref_ty.is_sized(cx.tcx, cx.typing_env()) {
40+
// We can't suggest `.cast()`, because that requires `to_ref_ty` to be Sized.
41+
if from_ptr_ty.has_erased_regions() {
42+
// We can't suggest `as *mut/const () as *mut/const to_ref_ty`, because the former is a
43+
// thin pointer, whereas the latter is a wide pointer, due of its pointee, `to_ref_ty`,
44+
// being !Sized.
45+
//
46+
// The only remaining option is be to skip `*mut/const ()`, but that might not be safe
47+
// to do because of the erased regions in `from_ptr_ty`, so reduce the applicability.
48+
app = Applicability::MaybeIncorrect;
49+
}
50+
sugg::make_unop(deref, arg.as_ty(format!("{cast} {ty_snip}"))).to_string()
51+
} else if msrv.meets(cx, msrvs::POINTER_CAST) {
4152
format!("{deref}{}.cast::<{ty_snip}>()", arg.maybe_paren())
4253
} else if from_ptr_ty.has_erased_regions() {
4354
sugg::make_unop(deref, arg.as_ty(format!("{cast} () as {cast} {ty_snip}"))).to_string()
4455
} else {
4556
sugg::make_unop(deref, arg.as_ty(format!("{cast} {ty_snip}"))).to_string()
4657
}
4758
} else if *from_ptr_ty == *to_ref_ty {
48-
if from_ptr_ty.has_erased_regions() {
49-
if msrv.meets(cx, msrvs::POINTER_CAST) {
50-
format!("{deref}{}.cast::<{to_ref_ty}>()", arg.maybe_paren())
51-
} else {
52-
sugg::make_unop(deref, arg.as_ty(format!("{cast} () as {cast} {to_ref_ty}")))
53-
.to_string()
54-
}
55-
} else {
59+
if !from_ptr_ty.has_erased_regions() {
5660
sugg::make_unop(deref, arg).to_string()
61+
} else if !to_ref_ty.is_sized(cx.tcx, cx.typing_env()) {
62+
// 1. We can't suggest `.cast()`, because that requires `to_ref_ty` to be Sized.
63+
// 2. We can't suggest `as *mut/const () as *mut/const to_ref_ty`, because the former is a
64+
// thin pointer, whereas the latter is a wide pointer, due of its pointee, `to_ref_ty`,
65+
// being !Sized.
66+
//
67+
// The only remaining option is be to skip `*mut/const ()`, but that might not be safe to do
68+
// because of the erased regions in `from_ptr_ty`, so reduce the applicability.
69+
app = Applicability::MaybeIncorrect;
70+
sugg::make_unop(deref, arg.as_ty(format!("{cast} {to_ref_ty}"))).to_string()
71+
} else if msrv.meets(cx, msrvs::POINTER_CAST) {
72+
format!("{deref}{}.cast::<{to_ref_ty}>()", arg.maybe_paren())
73+
} else {
74+
sugg::make_unop(deref, arg.as_ty(format!("{cast} () as {cast} {to_ref_ty}"))).to_string()
5775
}
5876
} else {
5977
sugg::make_unop(deref, arg.as_ty(format!("{cast} {to_ref_ty}"))).to_string()

tests/ui/transmute_ptr_to_ref.fixed

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
clippy::missing_transmute_annotations
66
)]
77

8-
unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
8+
fn ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
99
unsafe {
1010
let _: &T = &*p;
1111
//~^ transmute_ptr_to_ref
@@ -37,7 +37,7 @@ unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
3737
}
3838
}
3939

40-
fn _issue1231() {
40+
fn issue1231() {
4141
struct Foo<'a, T> {
4242
bar: &'a T,
4343
}
@@ -55,7 +55,7 @@ fn _issue1231() {
5555
//~^ transmute_ptr_to_ref
5656
}
5757

58-
unsafe fn _issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'b u32 {
58+
fn issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'b u32 {
5959
unsafe {
6060
match 0 {
6161
0 => &*x.cast::<&u32>(),
@@ -71,7 +71,7 @@ unsafe fn _issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'
7171
}
7272

7373
#[clippy::msrv = "1.38"]
74-
unsafe fn _meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
74+
fn meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
7575
unsafe {
7676
let a = 0u32;
7777
let a = &a as *const u32;
@@ -89,7 +89,7 @@ unsafe fn _meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
8989
}
9090

9191
#[clippy::msrv = "1.37"]
92-
unsafe fn _under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
92+
fn under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
9393
unsafe {
9494
let a = 0u32;
9595
let a = &a as *const u32;
@@ -106,4 +106,33 @@ unsafe fn _under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
106106
}
107107
}
108108

109+
// handle DSTs
110+
fn issue13357(ptr: *const [i32], s_ptr: *const &str, a_s_ptr: *const [&str]) {
111+
unsafe {
112+
// different types, without erased regions
113+
let _ = &*(ptr as *const [u32]);
114+
//~^ transmute_ptr_to_ref
115+
let _: &[u32] = &*(ptr as *const [u32]);
116+
//~^ transmute_ptr_to_ref
117+
118+
// different types, with erased regions
119+
let _ = &*(a_s_ptr as *const [&[u8]]);
120+
//~^ transmute_ptr_to_ref
121+
let _: &[&[u8]] = &*(a_s_ptr as *const [&[u8]]);
122+
//~^ transmute_ptr_to_ref
123+
124+
// same type, without erased regions
125+
let _ = &*(ptr as *const [i32]);
126+
//~^ transmute_ptr_to_ref
127+
let _: &[i32] = &*ptr;
128+
//~^ transmute_ptr_to_ref
129+
130+
// same type, with erased regions
131+
let _ = &*(a_s_ptr as *const [&str]);
132+
//~^ transmute_ptr_to_ref
133+
let _: &[&str] = &*(a_s_ptr as *const [&str]);
134+
//~^ transmute_ptr_to_ref
135+
}
136+
}
137+
109138
fn main() {}

tests/ui/transmute_ptr_to_ref.rs

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
clippy::missing_transmute_annotations
66
)]
77

8-
unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
8+
fn ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
99
unsafe {
1010
let _: &T = std::mem::transmute(p);
1111
//~^ transmute_ptr_to_ref
@@ -37,7 +37,7 @@ unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
3737
}
3838
}
3939

40-
fn _issue1231() {
40+
fn issue1231() {
4141
struct Foo<'a, T> {
4242
bar: &'a T,
4343
}
@@ -55,7 +55,7 @@ fn _issue1231() {
5555
//~^ transmute_ptr_to_ref
5656
}
5757

58-
unsafe fn _issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'b u32 {
58+
fn issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'b u32 {
5959
unsafe {
6060
match 0 {
6161
0 => std::mem::transmute(x),
@@ -71,7 +71,7 @@ unsafe fn _issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'
7171
}
7272

7373
#[clippy::msrv = "1.38"]
74-
unsafe fn _meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
74+
fn meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
7575
unsafe {
7676
let a = 0u32;
7777
let a = &a as *const u32;
@@ -89,7 +89,7 @@ unsafe fn _meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
8989
}
9090

9191
#[clippy::msrv = "1.37"]
92-
unsafe fn _under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
92+
fn under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
9393
unsafe {
9494
let a = 0u32;
9595
let a = &a as *const u32;
@@ -106,4 +106,33 @@ unsafe fn _under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
106106
}
107107
}
108108

109+
// handle DSTs
110+
fn issue13357(ptr: *const [i32], s_ptr: *const &str, a_s_ptr: *const [&str]) {
111+
unsafe {
112+
// different types, without erased regions
113+
let _ = core::mem::transmute::<_, &[u32]>(ptr);
114+
//~^ transmute_ptr_to_ref
115+
let _: &[u32] = core::mem::transmute(ptr);
116+
//~^ transmute_ptr_to_ref
117+
118+
// different types, with erased regions
119+
let _ = core::mem::transmute::<_, &[&[u8]]>(a_s_ptr);
120+
//~^ transmute_ptr_to_ref
121+
let _: &[&[u8]] = core::mem::transmute(a_s_ptr);
122+
//~^ transmute_ptr_to_ref
123+
124+
// same type, without erased regions
125+
let _ = core::mem::transmute::<_, &[i32]>(ptr);
126+
//~^ transmute_ptr_to_ref
127+
let _: &[i32] = core::mem::transmute(ptr);
128+
//~^ transmute_ptr_to_ref
129+
130+
// same type, with erased regions
131+
let _ = core::mem::transmute::<_, &[&str]>(a_s_ptr);
132+
//~^ transmute_ptr_to_ref
133+
let _: &[&str] = core::mem::transmute(a_s_ptr);
134+
//~^ transmute_ptr_to_ref
135+
}
136+
}
137+
109138
fn main() {}

tests/ui/transmute_ptr_to_ref.stderr

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,13 @@ error: transmute from a pointer type (`*mut U`) to a reference type (`&T`)
4343
LL | let _: &T = std::mem::transmute(om);
4444
| ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(om as *const T)`
4545

46-
error: transmute from a pointer type (`*const i32`) to a reference type (`&_issue1231::Foo<'_, u8>`)
46+
error: transmute from a pointer type (`*const i32`) to a reference type (`&issue1231::Foo<'_, u8>`)
4747
--> tests/ui/transmute_ptr_to_ref.rs:46:32
4848
|
4949
LL | let _: &Foo<u8> = unsafe { std::mem::transmute::<_, &Foo<_>>(raw) };
5050
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*raw.cast::<Foo<_>>()`
5151

52-
error: transmute from a pointer type (`*const i32`) to a reference type (`&_issue1231::Foo<'_, &u8>`)
52+
error: transmute from a pointer type (`*const i32`) to a reference type (`&issue1231::Foo<'_, &u8>`)
5353
--> tests/ui/transmute_ptr_to_ref.rs:49:33
5454
|
5555
LL | let _: &Foo<&u8> = unsafe { std::mem::transmute::<_, &Foo<&_>>(raw) };
@@ -133,5 +133,53 @@ error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32
133133
LL | _ => std::mem::transmute::<_, &&'b u32>(x),
134134
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(x as *const () as *const &'b u32)`
135135

136-
error: aborting due to 22 previous errors
136+
error: transmute from a pointer type (`*const [i32]`) to a reference type (`&[u32]`)
137+
--> tests/ui/transmute_ptr_to_ref.rs:113:17
138+
|
139+
LL | let _ = core::mem::transmute::<_, &[u32]>(ptr);
140+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(ptr as *const [u32])`
141+
142+
error: transmute from a pointer type (`*const [i32]`) to a reference type (`&[u32]`)
143+
--> tests/ui/transmute_ptr_to_ref.rs:115:25
144+
|
145+
LL | let _: &[u32] = core::mem::transmute(ptr);
146+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(ptr as *const [u32])`
147+
148+
error: transmute from a pointer type (`*const [&str]`) to a reference type (`&[&[u8]]`)
149+
--> tests/ui/transmute_ptr_to_ref.rs:119:17
150+
|
151+
LL | let _ = core::mem::transmute::<_, &[&[u8]]>(a_s_ptr);
152+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a_s_ptr as *const [&[u8]])`
153+
154+
error: transmute from a pointer type (`*const [&str]`) to a reference type (`&[&[u8]]`)
155+
--> tests/ui/transmute_ptr_to_ref.rs:121:27
156+
|
157+
LL | let _: &[&[u8]] = core::mem::transmute(a_s_ptr);
158+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a_s_ptr as *const [&[u8]])`
159+
160+
error: transmute from a pointer type (`*const [i32]`) to a reference type (`&[i32]`)
161+
--> tests/ui/transmute_ptr_to_ref.rs:125:17
162+
|
163+
LL | let _ = core::mem::transmute::<_, &[i32]>(ptr);
164+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(ptr as *const [i32])`
165+
166+
error: transmute from a pointer type (`*const [i32]`) to a reference type (`&[i32]`)
167+
--> tests/ui/transmute_ptr_to_ref.rs:127:25
168+
|
169+
LL | let _: &[i32] = core::mem::transmute(ptr);
170+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*ptr`
171+
172+
error: transmute from a pointer type (`*const [&str]`) to a reference type (`&[&str]`)
173+
--> tests/ui/transmute_ptr_to_ref.rs:131:17
174+
|
175+
LL | let _ = core::mem::transmute::<_, &[&str]>(a_s_ptr);
176+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a_s_ptr as *const [&str])`
177+
178+
error: transmute from a pointer type (`*const [&str]`) to a reference type (`&[&str]`)
179+
--> tests/ui/transmute_ptr_to_ref.rs:133:26
180+
|
181+
LL | let _: &[&str] = core::mem::transmute(a_s_ptr);
182+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a_s_ptr as *const [&str])`
183+
184+
error: aborting due to 30 previous errors
137185

0 commit comments

Comments
 (0)