Improve diagnostics of the invalid_reference_casting lint
This commit is contained in:
parent
50a46710a9
commit
20a6b57106
5 changed files with 151 additions and 76 deletions
|
@ -318,7 +318,10 @@ lint_invalid_nan_comparisons_eq_ne = incorrect NaN comparison, NaN cannot be dir
|
|||
|
||||
lint_invalid_nan_comparisons_lt_le_gt_ge = incorrect NaN comparison, NaN is not orderable
|
||||
|
||||
lint_invalid_reference_casting = casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
lint_invalid_reference_casting_assign_to_ref = assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
|
||||
.label = casting happend here
|
||||
|
||||
lint_invalid_reference_casting_borrow_as_mut = casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
.label = casting happend here
|
||||
|
||||
lint_lintpass_by_hand = implementing `LintPass` by hand
|
||||
|
|
|
@ -745,10 +745,17 @@ pub enum InvalidFromUtf8Diag {
|
|||
|
||||
// reference_casting.rs
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_invalid_reference_casting)]
|
||||
pub struct InvalidReferenceCastingDiag {
|
||||
#[label]
|
||||
pub orig_cast: Option<Span>,
|
||||
pub enum InvalidReferenceCastingDiag {
|
||||
#[diag(lint_invalid_reference_casting_borrow_as_mut)]
|
||||
BorrowAsMut {
|
||||
#[label]
|
||||
orig_cast: Option<Span>,
|
||||
},
|
||||
#[diag(lint_invalid_reference_casting_assign_to_ref)]
|
||||
AssignToRef {
|
||||
#[label]
|
||||
orig_cast: Option<Span>,
|
||||
},
|
||||
}
|
||||
|
||||
// hidden_unicode_codepoints.rs
|
||||
|
|
|
@ -73,13 +73,25 @@ impl<'tcx> LateLintPass<'tcx> for InvalidReferenceCasting {
|
|||
return;
|
||||
};
|
||||
|
||||
if is_cast_from_const_to_mut(cx, e) {
|
||||
cx.emit_spanned_lint(INVALID_REFERENCE_CASTING, expr.span, InvalidReferenceCastingDiag { orig_cast: None });
|
||||
let orig_cast = if is_cast_from_const_to_mut(cx, e) {
|
||||
None
|
||||
} else if let ExprKind::Path(QPath::Resolved(_, path)) = e.kind
|
||||
&& let Res::Local(hir_id) = &path.res
|
||||
&& let Some(orig_cast) = self.casted.get(hir_id) {
|
||||
cx.emit_spanned_lint(INVALID_REFERENCE_CASTING, expr.span, InvalidReferenceCastingDiag { orig_cast: Some(*orig_cast) });
|
||||
}
|
||||
Some(*orig_cast)
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
|
||||
cx.emit_spanned_lint(
|
||||
INVALID_REFERENCE_CASTING,
|
||||
expr.span,
|
||||
if matches!(expr.kind, ExprKind::AddrOf(..)) {
|
||||
InvalidReferenceCastingDiag::BorrowAsMut { orig_cast }
|
||||
} else {
|
||||
InvalidReferenceCastingDiag::AssignToRef { orig_cast }
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,42 +9,63 @@ extern "C" {
|
|||
fn int_ffi(c: *mut i32);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
unsafe fn ref_to_mut() {
|
||||
let num = &3i32;
|
||||
|
||||
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 = &mut *std::ptr::from_ref(num).cast_mut();
|
||||
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
|
||||
let _num = &mut *std::ptr::from_ref({ num }).cast_mut();
|
||||
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
|
||||
let _num = &mut *{ std::ptr::from_ref(num) }.cast_mut();
|
||||
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
|
||||
let _num = &mut *(std::ptr::from_ref({ num }) as *mut i32);
|
||||
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
|
||||
|
||||
let deferred = num as *const i32 as *mut i32;
|
||||
let _num = &mut *deferred;
|
||||
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
|
||||
}
|
||||
|
||||
unsafe fn assign_to_ref() {
|
||||
let s = String::from("Hello");
|
||||
let a = &s;
|
||||
unsafe {
|
||||
let num = &3i32;
|
||||
let mut_num = &mut 3i32;
|
||||
let num = &3i32;
|
||||
|
||||
*(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
|
||||
*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
|
||||
let value = num as *const i32 as *mut i32;
|
||||
*value = 1;
|
||||
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
|
||||
|
||||
// Shouldn't be warned against
|
||||
*(num as *const i32 as *mut i32);
|
||||
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;
|
||||
}
|
||||
*(a as *const _ as *mut _) = String::from("Replaced");
|
||||
//~^ ERROR assigning to `&T` is undefined behavior
|
||||
*(a as *const _ as *mut String) += " world";
|
||||
//~^ ERROR assigning to `&T` is undefined behavior
|
||||
*std::ptr::from_ref(num).cast_mut() += 1;
|
||||
//~^ ERROR assigning to `&T` is undefined behavior
|
||||
*std::ptr::from_ref({ num }).cast_mut() += 1;
|
||||
//~^ ERROR assigning to `&T` is undefined behavior
|
||||
*{ std::ptr::from_ref(num) }.cast_mut() += 1;
|
||||
//~^ ERROR assigning to `&T` is undefined behavior
|
||||
*(std::ptr::from_ref({ num }) as *mut i32) += 1;
|
||||
//~^ ERROR assigning to `&T` is undefined behavior
|
||||
let value = num as *const i32 as *mut i32;
|
||||
*value = 1;
|
||||
//~^ ERROR assigning to `&T` is undefined behavior
|
||||
}
|
||||
|
||||
unsafe fn no_warn() {
|
||||
let num = &3i32;
|
||||
let mut_num = &mut 3i32;
|
||||
let a = &String::from("ffi");
|
||||
|
||||
*(num as *const i32 as *mut i32);
|
||||
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;
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -1,60 +1,92 @@
|
|||
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
--> $DIR/reference_casting.rs:19:9
|
||||
--> $DIR/reference_casting.rs:15:16
|
||||
|
|
||||
LL | *(a as *const _ as *mut _) = String::from("Replaced");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | let _num = &mut *(num as *const i32 as *mut i32);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[deny(invalid_reference_casting)]` on by default
|
||||
|
||||
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
--> $DIR/reference_casting.rs:21:9
|
||||
--> $DIR/reference_casting.rs:17:16
|
||||
|
|
||||
LL | *(a as *const _ as *mut String) += " world";
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
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/reference_casting.rs:23:20
|
||||
--> $DIR/reference_casting.rs:19:16
|
||||
|
|
||||
LL | let _num = &mut *(num as *const i32 as *mut i32);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | let _num = &mut *std::ptr::from_ref(num).cast_mut();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
--> $DIR/reference_casting.rs:25:20
|
||||
--> $DIR/reference_casting.rs:21:16
|
||||
|
|
||||
LL | let _num = &mut *(num as *const i32).cast_mut();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | let _num = &mut *std::ptr::from_ref({ num }).cast_mut();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
--> $DIR/reference_casting.rs:27:9
|
||||
--> $DIR/reference_casting.rs:23:16
|
||||
|
|
||||
LL | *std::ptr::from_ref(num).cast_mut() += 1;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | let _num = &mut *{ std::ptr::from_ref(num) }.cast_mut();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
--> $DIR/reference_casting.rs:29:9
|
||||
--> $DIR/reference_casting.rs:25:16
|
||||
|
|
||||
LL | *std::ptr::from_ref({ num }).cast_mut() += 1;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | let _num = &mut *(std::ptr::from_ref({ num }) as *mut i32);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
--> $DIR/reference_casting.rs:31:9
|
||||
--> $DIR/reference_casting.rs:29:16
|
||||
|
|
||||
LL | *{ std::ptr::from_ref(num) }.cast_mut() += 1;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | let deferred = num as *const i32 as *mut i32;
|
||||
| ----------------------------- casting happend here
|
||||
LL | let _num = &mut *deferred;
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
--> $DIR/reference_casting.rs:33:9
|
||||
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
|
||||
--> $DIR/reference_casting.rs:38:5
|
||||
|
|
||||
LL | *(std::ptr::from_ref({ num }) as *mut i32) += 1;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
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/reference_casting.rs:36:9
|
||||
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
|
||||
--> $DIR/reference_casting.rs:40:5
|
||||
|
|
||||
LL | let value = num as *const i32 as *mut i32;
|
||||
| ----------------------------- casting happend here
|
||||
LL | *value = 1;
|
||||
| ^^^^^^^^^^
|
||||
LL | *(a as *const _ as *mut String) += " world";
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 9 previous errors
|
||||
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
|
||||
--> $DIR/reference_casting.rs:42:5
|
||||
|
|
||||
LL | *std::ptr::from_ref(num).cast_mut() += 1;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
|
||||
--> $DIR/reference_casting.rs:44:5
|
||||
|
|
||||
LL | *std::ptr::from_ref({ num }).cast_mut() += 1;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
|
||||
--> $DIR/reference_casting.rs:46:5
|
||||
|
|
||||
LL | *{ std::ptr::from_ref(num) }.cast_mut() += 1;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
|
||||
--> $DIR/reference_casting.rs:48:5
|
||||
|
|
||||
LL | *(std::ptr::from_ref({ num }) as *mut i32) += 1;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
|
||||
--> $DIR/reference_casting.rs:51:5
|
||||
|
|
||||
LL | let value = num as *const i32 as *mut i32;
|
||||
| ----------------------------- casting happend here
|
||||
LL | *value = 1;
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: aborting due to 14 previous errors
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue