Skip to content

Commit 1f86679

Browse files
committed
fix(transmute_ptr_to_ref): don't suggest .cast when to-type is DST
1 parent d4cb0b4 commit 1f86679

File tree

4 files changed

+130
-2
lines changed

4 files changed

+130
-2
lines changed

clippy_lints/src/transmute/transmute_ptr_to_ref.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,19 @@ pub(super) fn check<'tcx>(
3636

3737
let sugg = if let Some(ty) = get_explicit_type(path) {
3838
let ty_snip = snippet_with_applicability(cx, ty.span, "..", &mut app);
39-
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) {
4052
format!("{deref}{}.cast::<{ty_snip}>()", arg.maybe_paren())
4153
} else if from_ptr_ty.has_erased_regions() {
4254
sugg::make_unop(deref, arg.as_ty(format!("{cast} () as {cast} {ty_snip}"))).to_string()
@@ -46,6 +58,16 @@ pub(super) fn check<'tcx>(
4658
} else if *from_ptr_ty == *to_ref_ty {
4759
if !from_ptr_ty.has_erased_regions() {
4860
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()
4971
} else if msrv.meets(cx, msrvs::POINTER_CAST) {
5072
format!("{deref}{}.cast::<{to_ref_ty}>()", arg.maybe_paren())
5173
} else {

tests/ui/transmute_ptr_to_ref.fixed

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,4 +106,33 @@ 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: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,4 +106,33 @@ 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: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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)