rust-lang / rust-clippy

A bunch of lints to catch common mistakes and improve your Rust code. Book: https://doc.rust-lang.org/clippy/
https://rust-lang.github.io/rust-clippy/
Other
11.44k stars 1.54k forks source link

transmute_ptr_to_ptr: exclude instances between reference where itself is not definitely UB? #11356

Open KisaragiEffective opened 1 year ago

KisaragiEffective commented 1 year ago

cc #6372

Description

transmute_ptr_to_ptr is too noisy for instance of between references even it is pedantic currently IMO.

This issue suggests avoid triggering if following conditions are met, because those do not trigger UBs:

  1. the call does not extends lifetime, nor change it to unrelated one.
  2. at least one of following conditions are met
    1. the Src is an enum and it has #[repr(C)] or #[repr($integer)] or #[repr(transparent)], and Dst is corresponding type.
    2. the Src is an struct and it has #[repr(transparent)], and Dst is reference to the inner type.
    3. the Src is an struct which has single field and #[repr(C)], and Dst is reference to the field type.

Purpose

The lint should not be warn on &'a E ~> &'a E::Repr (where E is any field-less enum), &'a Transparent ~> &'a Transparent::Inner (where Transparent is struct with #[repr(transparent)]). The former can be achieved by primitive cast, but latter is not:

#[repr(C)] // also applicable if layout is i*, u*, or transparent
enum ExpReprC {
    Zero = 0,
}

#[repr(transparent)] // also applicable if layout is C
struct Transparent(u8);

fn main() {
    let m: ExpReprC = ExpReprC::Zero;
    let x: &u8 = unsafe { std::mem::transmute(&m) };

    let m: Transparent = Transparent(42);
    let x: &u8 = unsafe { std::mem::transmute(&m) };

}

Version

rustc 1.73.0-nightly (31395ec38 2023-07-24)
binary: rustc            
commit-hash: 31395ec38250b60b380fd3c27e94756aba3557de
commit-date: 2023-07-24  
host: x86_64-unknown-linux-gnu
release: 1.73.0-nightly  
LLVM version: 16.0.5

Additional Labels

@rustbot label C-question

asquared31415 commented 1 year ago

All of these cases would be better served by &x.field or &x as REPR_TYPE, which does the same operation, but restricts the lifetime and ensures that the types are correct.

the call does not extends lifetime, nor change it to unrelated one. transmute returns an "unbound lifetime" so whether a lifetime change happens is very liable to change with small inference changes in the program.

It's perfectly fine that a pedantic lint lints on possible sound but fragile code.

Jarcho commented 1 year ago

&(x as REPR_TYPE) doesn't work as it creates a reference to a temporary. (&x as REPR_TYPE is casting the reference)