Skip to content

Commit b799c1e

Browse files
authored
Merge pull request #2759 from devonhollowood/transmute-same-ptr-ptr
Don't lint lifetime-only transmutes
2 parents 400aab9 + 9118cd6 commit b799c1e

File tree

3 files changed

+79
-28
lines changed

3 files changed

+79
-28
lines changed

clippy_lints/src/transmute.rs

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ declare_clippy_lint! {
192192
declare_clippy_lint! {
193193
pub TRANSMUTE_PTR_TO_PTR,
194194
complexity,
195-
"transmutes from a pointer to a reference type"
195+
"transmutes from a pointer to a pointer / a reference to a reference"
196196
}
197197

198198
pub struct Transmute;
@@ -363,23 +363,25 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
363363
}
364364
)
365365
} else {
366-
span_lint_and_then(
367-
cx,
368-
TRANSMUTE_PTR_TO_PTR,
369-
e.span,
370-
"transmute from a reference to a reference",
371-
|db| if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) {
372-
let ty_from_and_mut = ty::TypeAndMut { ty: ty_from, mutbl: from_mutbl };
373-
let ty_to_and_mut = ty::TypeAndMut { ty: ty_to, mutbl: to_mutbl };
374-
let sugg_paren = arg.as_ty(cx.tcx.mk_ptr(ty_from_and_mut)).as_ty(cx.tcx.mk_ptr(ty_to_and_mut));
375-
let sugg = if to_mutbl == Mutability::MutMutable {
376-
sugg_paren.mut_addr_deref()
377-
} else {
378-
sugg_paren.addr_deref()
379-
};
380-
db.span_suggestion(e.span, "try", sugg.to_string());
381-
},
382-
)
366+
if cx.tcx.erase_regions(&from_ty) != cx.tcx.erase_regions(&to_ty) {
367+
span_lint_and_then(
368+
cx,
369+
TRANSMUTE_PTR_TO_PTR,
370+
e.span,
371+
"transmute from a reference to a reference",
372+
|db| if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) {
373+
let ty_from_and_mut = ty::TypeAndMut { ty: ty_from, mutbl: from_mutbl };
374+
let ty_to_and_mut = ty::TypeAndMut { ty: ty_to, mutbl: to_mutbl };
375+
let sugg_paren = arg.as_ty(cx.tcx.mk_ptr(ty_from_and_mut)).as_ty(cx.tcx.mk_ptr(ty_to_and_mut));
376+
let sugg = if to_mutbl == Mutability::MutMutable {
377+
sugg_paren.mut_addr_deref()
378+
} else {
379+
sugg_paren.addr_deref()
380+
};
381+
db.span_suggestion(e.span, "try", sugg.to_string());
382+
},
383+
)
384+
}
383385
}
384386
}
385387
},

tests/ui/transmute.rs

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,29 @@ fn bytes_to_str(b: &[u8], mb: &mut [u8]) {
140140
let _: &mut str = unsafe { std::mem::transmute(mb) };
141141
}
142142

143+
// Make sure we can modify lifetimes, which is one of the recommended uses
144+
// of transmute
145+
146+
// Make sure we can do static lifetime transmutes
147+
#[warn(transmute_ptr_to_ptr)]
148+
unsafe fn transmute_lifetime_to_static<'a, T>(t: &'a T) -> &'static T {
149+
std::mem::transmute::<&'a T, &'static T>(t)
150+
}
151+
152+
// Make sure we can do non-static lifetime transmutes
153+
#[warn(transmute_ptr_to_ptr)]
154+
unsafe fn transmute_lifetime<'a, 'b, T>(t: &'a T, u: &'b T) -> &'b T {
155+
std::mem::transmute::<&'a T, &'b T>(t)
156+
}
157+
158+
struct LifetimeParam<'a> {
159+
s: &'a str,
160+
}
161+
162+
struct GenericParam<T> {
163+
t: T,
164+
}
165+
143166
#[warn(transmute_ptr_to_ptr)]
144167
fn transmute_ptr_to_ptr() {
145168
let ptr = &1u32 as *const u32;
@@ -150,13 +173,27 @@ fn transmute_ptr_to_ptr() {
150173
let _: *mut f32 = std::mem::transmute(mut_ptr);
151174
// ref-ref transmutes; bad
152175
let _: &f32 = std::mem::transmute(&1u32);
176+
let _: &f64 = std::mem::transmute(&1f32);
177+
// ^ this test is here because both f32 and f64 are the same TypeVariant, but they are not
178+
// the same type
153179
let _: &mut f32 = std::mem::transmute(&mut 1u32);
180+
let _: &GenericParam<f32> = std::mem::transmute(&GenericParam { t: 1u32 });
154181
}
155-
// These should be fine
182+
183+
// these are recommendations for solving the above; if these lint we need to update
184+
// those suggestions
156185
let _ = ptr as *const f32;
157186
let _ = mut_ptr as *mut f32;
158187
let _ = unsafe { &*(&1u32 as *const u32 as *const f32) };
159188
let _ = unsafe { &mut *(&mut 1u32 as *mut u32 as *mut f32) };
189+
190+
// transmute internal lifetimes, should not lint
191+
let s = "hello world".to_owned();
192+
let lp = LifetimeParam { s: &s };
193+
let _: &LifetimeParam<'static> = unsafe { std::mem::transmute(&lp) };
194+
let _: &GenericParam<&LifetimeParam<'static>> = unsafe {
195+
std::mem::transmute(&GenericParam { t: &lp})
196+
};
160197
}
161198

162199
fn main() { }

tests/ui/transmute.stderr

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -205,30 +205,42 @@ error: transmute from a `&mut [u8]` to a `&mut str`
205205
| ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()`
206206

207207
error: transmute from a pointer to a pointer
208-
--> $DIR/transmute.rs:149:29
208+
--> $DIR/transmute.rs:172:29
209209
|
210-
149 | let _: *const f32 = std::mem::transmute(ptr);
210+
172 | let _: *const f32 = std::mem::transmute(ptr);
211211
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr as *const f32`
212212
|
213213
= note: `-D transmute-ptr-to-ptr` implied by `-D warnings`
214214

215215
error: transmute from a pointer to a pointer
216-
--> $DIR/transmute.rs:150:27
216+
--> $DIR/transmute.rs:173:27
217217
|
218-
150 | let _: *mut f32 = std::mem::transmute(mut_ptr);
218+
173 | let _: *mut f32 = std::mem::transmute(mut_ptr);
219219
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `mut_ptr as *mut f32`
220220

221221
error: transmute from a reference to a reference
222-
--> $DIR/transmute.rs:152:23
222+
--> $DIR/transmute.rs:175:23
223223
|
224-
152 | let _: &f32 = std::mem::transmute(&1u32);
224+
175 | let _: &f32 = std::mem::transmute(&1u32);
225225
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(&1u32 as *const u32 as *const f32)`
226226

227227
error: transmute from a reference to a reference
228-
--> $DIR/transmute.rs:153:27
228+
--> $DIR/transmute.rs:176:23
229229
|
230-
153 | let _: &mut f32 = std::mem::transmute(&mut 1u32);
230+
176 | let _: &f64 = std::mem::transmute(&1f32);
231+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(&1f32 as *const f32 as *const f64)`
232+
233+
error: transmute from a reference to a reference
234+
--> $DIR/transmute.rs:179:27
235+
|
236+
179 | let _: &mut f32 = std::mem::transmute(&mut 1u32);
231237
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(&mut 1u32 as *mut u32 as *mut f32)`
232238

233-
error: aborting due to 36 previous errors
239+
error: transmute from a reference to a reference
240+
--> $DIR/transmute.rs:180:37
241+
|
242+
180 | let _: &GenericParam<f32> = std::mem::transmute(&GenericParam { t: 1u32 });
243+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(&GenericParam { t: 1u32 } as *const GenericParam<u32> as *const GenericParam<f32>)`
244+
245+
error: aborting due to 38 previous errors
234246

0 commit comments

Comments
 (0)