Auto merge of #111567 - Urgau:uplift_cast_ref_to_mut, r=b-naber
Uplift `clippy::cast_ref_to_mut` lint
This PR aims at uplifting the `clippy::cast_ref_to_mut` lint into rustc.
## `cast_ref_to_mut`
(deny-by-default)
The `cast_ref_to_mut` lint checks for casts of `&T` to `&mut T` without using interior mutability.
### Example
```rust,compile_fail
fn x(r: &i32) {
unsafe {
*(r as *const i32 as *mut i32) += 1;
}
}
```
### Explanation
Casting `&T` to `&mut T` without interior mutability is undefined behavior, as it's a violation of Rust reference aliasing requirements.
-----
Mostly followed the instructions for uplifting a clippy lint described here: https://github.com/rust-lang/rust/pull/99696#pullrequestreview-1134072751
`@rustbot` label: +I-lang-nominated
r? compiler
-----
For Clippy:
changelog: Moves: Uplifted `clippy::cast_ref_to_mut` into rustc
This commit is contained in:
commit
ba1690bedd
22 changed files with 276 additions and 170 deletions
|
|
@ -9,6 +9,7 @@ impl <const B: &'static bool> T<B> {
|
|||
unsafe {
|
||||
*(B as *const bool as *mut bool) = false;
|
||||
//~^ ERROR evaluation of constant value failed [E0080]
|
||||
//~| ERROR casting `&T` to `&mut T` is undefined behavior
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,11 @@
|
|||
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
--> $DIR/issue-100313.rs:10:13
|
||||
|
|
||||
LL | *(B as *const bool as *mut bool) = false;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[deny(cast_ref_to_mut)]` on by default
|
||||
|
||||
error[E0080]: evaluation of constant value failed
|
||||
--> $DIR/issue-100313.rs:10:13
|
||||
|
|
||||
|
|
@ -10,11 +18,11 @@ note: inside `T::<&true>::set_false`
|
|||
LL | *(B as *const bool as *mut bool) = false;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
note: inside `_`
|
||||
--> $DIR/issue-100313.rs:18:5
|
||||
--> $DIR/issue-100313.rs:19:5
|
||||
|
|
||||
LL | x.set_false();
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
||||
|
|
|
|||
50
tests/ui/lint/cast_ref_to_mut.rs
Normal file
50
tests/ui/lint/cast_ref_to_mut.rs
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
// check-fail
|
||||
|
||||
#![feature(ptr_from_ref)]
|
||||
|
||||
extern "C" {
|
||||
// N.B., mutability can be easily incorrect in FFI calls -- as
|
||||
// in C, the default is mutable pointers.
|
||||
fn ffi(c: *mut u8);
|
||||
fn int_ffi(c: *mut i32);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let s = String::from("Hello");
|
||||
let a = &s;
|
||||
unsafe {
|
||||
let num = &3i32;
|
||||
let mut_num = &mut 3i32;
|
||||
|
||||
(*(a as *const _ as *mut String)).push_str(" world");
|
||||
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
|
||||
*(a as *const _ as *mut _) = String::from("Replaced");
|
||||
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
|
||||
*(a as *const _ as *mut String) += " world";
|
||||
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
|
||||
let _num = &mut *(num as *const i32 as *mut i32);
|
||||
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
|
||||
let _num = &mut *(num as *const i32).cast_mut();
|
||||
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
|
||||
let _num = *{ num as *const i32 }.cast_mut();
|
||||
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
|
||||
*std::ptr::from_ref(num).cast_mut() += 1;
|
||||
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
|
||||
*std::ptr::from_ref({ num }).cast_mut() += 1;
|
||||
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
|
||||
*{ std::ptr::from_ref(num) }.cast_mut() += 1;
|
||||
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
|
||||
*(std::ptr::from_ref({ num }) as *mut i32) += 1;
|
||||
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
|
||||
|
||||
// Shouldn't be warned against
|
||||
println!("{}", *(num as *const _ as *const i16));
|
||||
println!("{}", *(mut_num as *mut _ as *mut i16));
|
||||
ffi(a.as_ptr() as *mut _);
|
||||
int_ffi(num as *const _ as *mut _);
|
||||
int_ffi(&3 as *const _ as *mut _);
|
||||
let mut value = 3;
|
||||
let value: *const i32 = &mut value;
|
||||
*(value as *const i16 as *mut i16) = 42;
|
||||
}
|
||||
}
|
||||
64
tests/ui/lint/cast_ref_to_mut.stderr
Normal file
64
tests/ui/lint/cast_ref_to_mut.stderr
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
--> $DIR/cast_ref_to_mut.rs:19:9
|
||||
|
|
||||
LL | (*(a as *const _ as *mut String)).push_str(" world");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[deny(cast_ref_to_mut)]` on by default
|
||||
|
||||
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
--> $DIR/cast_ref_to_mut.rs:21:9
|
||||
|
|
||||
LL | *(a as *const _ as *mut _) = String::from("Replaced");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
--> $DIR/cast_ref_to_mut.rs:23:9
|
||||
|
|
||||
LL | *(a as *const _ as *mut String) += " world";
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
--> $DIR/cast_ref_to_mut.rs:25:25
|
||||
|
|
||||
LL | let _num = &mut *(num as *const i32 as *mut i32);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
--> $DIR/cast_ref_to_mut.rs:27:25
|
||||
|
|
||||
LL | let _num = &mut *(num as *const i32).cast_mut();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
--> $DIR/cast_ref_to_mut.rs:29:20
|
||||
|
|
||||
LL | let _num = *{ num as *const i32 }.cast_mut();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
--> $DIR/cast_ref_to_mut.rs:31:9
|
||||
|
|
||||
LL | *std::ptr::from_ref(num).cast_mut() += 1;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
--> $DIR/cast_ref_to_mut.rs:33:9
|
||||
|
|
||||
LL | *std::ptr::from_ref({ num }).cast_mut() += 1;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
--> $DIR/cast_ref_to_mut.rs:35:9
|
||||
|
|
||||
LL | *{ std::ptr::from_ref(num) }.cast_mut() += 1;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
--> $DIR/cast_ref_to_mut.rs:37:9
|
||||
|
|
||||
LL | *(std::ptr::from_ref({ num }) as *mut i32) += 1;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 10 previous errors
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue