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_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
|
.label = casting happend here
|
||||||
|
|
||||||
lint_lintpass_by_hand = implementing `LintPass` by hand
|
lint_lintpass_by_hand = implementing `LintPass` by hand
|
||||||
|
|
|
@ -745,10 +745,17 @@ pub enum InvalidFromUtf8Diag {
|
||||||
|
|
||||||
// reference_casting.rs
|
// reference_casting.rs
|
||||||
#[derive(LintDiagnostic)]
|
#[derive(LintDiagnostic)]
|
||||||
#[diag(lint_invalid_reference_casting)]
|
pub enum InvalidReferenceCastingDiag {
|
||||||
pub struct InvalidReferenceCastingDiag {
|
#[diag(lint_invalid_reference_casting_borrow_as_mut)]
|
||||||
#[label]
|
BorrowAsMut {
|
||||||
pub orig_cast: Option<Span>,
|
#[label]
|
||||||
|
orig_cast: Option<Span>,
|
||||||
|
},
|
||||||
|
#[diag(lint_invalid_reference_casting_assign_to_ref)]
|
||||||
|
AssignToRef {
|
||||||
|
#[label]
|
||||||
|
orig_cast: Option<Span>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// hidden_unicode_codepoints.rs
|
// hidden_unicode_codepoints.rs
|
||||||
|
|
|
@ -73,13 +73,25 @@ impl<'tcx> LateLintPass<'tcx> for InvalidReferenceCasting {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
if is_cast_from_const_to_mut(cx, e) {
|
let orig_cast = if is_cast_from_const_to_mut(cx, e) {
|
||||||
cx.emit_spanned_lint(INVALID_REFERENCE_CASTING, expr.span, InvalidReferenceCastingDiag { orig_cast: None });
|
None
|
||||||
} else if let ExprKind::Path(QPath::Resolved(_, path)) = e.kind
|
} else if let ExprKind::Path(QPath::Resolved(_, path)) = e.kind
|
||||||
&& let Res::Local(hir_id) = &path.res
|
&& let Res::Local(hir_id) = &path.res
|
||||||
&& let Some(orig_cast) = self.casted.get(hir_id) {
|
&& 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 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 s = String::from("Hello");
|
||||||
let a = &s;
|
let a = &s;
|
||||||
unsafe {
|
let num = &3i32;
|
||||||
let num = &3i32;
|
|
||||||
let mut_num = &mut 3i32;
|
|
||||||
|
|
||||||
*(a as *const _ as *mut _) = String::from("Replaced");
|
*(a as *const _ as *mut _) = String::from("Replaced");
|
||||||
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
|
//~^ ERROR assigning to `&T` is undefined behavior
|
||||||
*(a as *const _ as *mut String) += " world";
|
*(a as *const _ as *mut String) += " world";
|
||||||
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
|
//~^ ERROR assigning to `&T` is undefined behavior
|
||||||
let _num = &mut *(num as *const i32 as *mut i32);
|
*std::ptr::from_ref(num).cast_mut() += 1;
|
||||||
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
|
//~^ ERROR assigning to `&T` is undefined behavior
|
||||||
let _num = &mut *(num as *const i32).cast_mut();
|
*std::ptr::from_ref({ num }).cast_mut() += 1;
|
||||||
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
|
//~^ ERROR assigning to `&T` is undefined behavior
|
||||||
*std::ptr::from_ref(num).cast_mut() += 1;
|
*{ std::ptr::from_ref(num) }.cast_mut() += 1;
|
||||||
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
|
//~^ ERROR assigning to `&T` is undefined behavior
|
||||||
*std::ptr::from_ref({ num }).cast_mut() += 1;
|
*(std::ptr::from_ref({ num }) as *mut i32) += 1;
|
||||||
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
|
//~^ ERROR assigning to `&T` is undefined behavior
|
||||||
*{ std::ptr::from_ref(num) }.cast_mut() += 1;
|
let value = num as *const i32 as *mut i32;
|
||||||
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
|
*value = 1;
|
||||||
*(std::ptr::from_ref({ num }) as *mut i32) += 1;
|
//~^ ERROR assigning to `&T` is undefined behavior
|
||||||
//~^ 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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`
|
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
|
= 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`
|
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`
|
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`
|
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`
|
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`
|
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`
|
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`
|
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
|
||||||
--> $DIR/reference_casting.rs:33:9
|
--> $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`
|
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
|
||||||
--> $DIR/reference_casting.rs:36:9
|
--> $DIR/reference_casting.rs:40:5
|
||||||
|
|
|
|
||||||
LL | let value = num as *const i32 as *mut i32;
|
LL | *(a as *const _ as *mut String) += " world";
|
||||||
| ----------------------------- casting happend here
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
LL | *value = 1;
|
|
||||||
| ^^^^^^^^^^
|
|
||||||
|
|
||||||
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
Add a link
Reference in a new issue