Skip to content

Don't lint lifetime-only transmutes #2759

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 29, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 20 additions & 18 deletions clippy_lints/src/transmute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ declare_clippy_lint! {
declare_clippy_lint! {
pub TRANSMUTE_PTR_TO_PTR,
complexity,
"transmutes from a pointer to a reference type"
"transmutes from a pointer to a pointer / a reference to a reference"
}

pub struct Transmute;
Expand Down Expand Up @@ -363,23 +363,25 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
}
)
} else {
span_lint_and_then(
cx,
TRANSMUTE_PTR_TO_PTR,
e.span,
"transmute from a reference to a reference",
|db| if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) {
let ty_from_and_mut = ty::TypeAndMut { ty: ty_from, mutbl: from_mutbl };
let ty_to_and_mut = ty::TypeAndMut { ty: ty_to, mutbl: to_mutbl };
let sugg_paren = arg.as_ty(cx.tcx.mk_ptr(ty_from_and_mut)).as_ty(cx.tcx.mk_ptr(ty_to_and_mut));
let sugg = if to_mutbl == Mutability::MutMutable {
sugg_paren.mut_addr_deref()
} else {
sugg_paren.addr_deref()
};
db.span_suggestion(e.span, "try", sugg.to_string());
},
)
if cx.tcx.erase_regions(&from_ty) != cx.tcx.erase_regions(&to_ty) {
span_lint_and_then(
cx,
TRANSMUTE_PTR_TO_PTR,
e.span,
"transmute from a reference to a reference",
|db| if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) {
let ty_from_and_mut = ty::TypeAndMut { ty: ty_from, mutbl: from_mutbl };
let ty_to_and_mut = ty::TypeAndMut { ty: ty_to, mutbl: to_mutbl };
let sugg_paren = arg.as_ty(cx.tcx.mk_ptr(ty_from_and_mut)).as_ty(cx.tcx.mk_ptr(ty_to_and_mut));
let sugg = if to_mutbl == Mutability::MutMutable {
sugg_paren.mut_addr_deref()
} else {
sugg_paren.addr_deref()
};
db.span_suggestion(e.span, "try", sugg.to_string());
},
)
}
}
}
},
Expand Down
39 changes: 38 additions & 1 deletion tests/ui/transmute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,29 @@ fn bytes_to_str(b: &[u8], mb: &mut [u8]) {
let _: &mut str = unsafe { std::mem::transmute(mb) };
}

// Make sure we can modify lifetimes, which is one of the recommended uses
// of transmute

// Make sure we can do static lifetime transmutes
#[warn(transmute_ptr_to_ptr)]
unsafe fn transmute_lifetime_to_static<'a, T>(t: &'a T) -> &'static T {
std::mem::transmute::<&'a T, &'static T>(t)
}

// Make sure we can do non-static lifetime transmutes
#[warn(transmute_ptr_to_ptr)]
unsafe fn transmute_lifetime<'a, 'b, T>(t: &'a T, u: &'b T) -> &'b T {
std::mem::transmute::<&'a T, &'b T>(t)
}

struct LifetimeParam<'a> {
s: &'a str,
}

struct GenericParam<T> {
t: T,
}

#[warn(transmute_ptr_to_ptr)]
fn transmute_ptr_to_ptr() {
let ptr = &1u32 as *const u32;
Expand All @@ -150,13 +173,27 @@ fn transmute_ptr_to_ptr() {
let _: *mut f32 = std::mem::transmute(mut_ptr);
// ref-ref transmutes; bad
let _: &f32 = std::mem::transmute(&1u32);
let _: &f64 = std::mem::transmute(&1f32);
// ^ this test is here because both f32 and f64 are the same TypeVariant, but they are not
// the same type
let _: &mut f32 = std::mem::transmute(&mut 1u32);
let _: &GenericParam<f32> = std::mem::transmute(&GenericParam { t: 1u32 });
}
// These should be fine

// these are recommendations for solving the above; if these lint we need to update
// those suggestions
let _ = ptr as *const f32;
let _ = mut_ptr as *mut f32;
let _ = unsafe { &*(&1u32 as *const u32 as *const f32) };
let _ = unsafe { &mut *(&mut 1u32 as *mut u32 as *mut f32) };

// transmute internal lifetimes, should not lint
let s = "hello world".to_owned();
let lp = LifetimeParam { s: &s };
let _: &LifetimeParam<'static> = unsafe { std::mem::transmute(&lp) };
let _: &GenericParam<&LifetimeParam<'static>> = unsafe {
std::mem::transmute(&GenericParam { t: &lp})
};
}

fn main() { }
30 changes: 21 additions & 9 deletions tests/ui/transmute.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -205,30 +205,42 @@ error: transmute from a `&mut [u8]` to a `&mut str`
| ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()`

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

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

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

error: transmute from a reference to a reference
--> $DIR/transmute.rs:153:27
--> $DIR/transmute.rs:176:23
|
153 | let _: &mut f32 = std::mem::transmute(&mut 1u32);
176 | let _: &f64 = std::mem::transmute(&1f32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(&1f32 as *const f32 as *const f64)`

error: transmute from a reference to a reference
--> $DIR/transmute.rs:179:27
|
179 | let _: &mut f32 = std::mem::transmute(&mut 1u32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(&mut 1u32 as *mut u32 as *mut f32)`

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

error: aborting due to 38 previous errors