about summary refs log tree commit diff
diff options
context:
space:
mode:
authorUrgau <urgau@numericable.fr>2023-07-14 22:15:28 +0200
committerUrgau <urgau@numericable.fr>2023-07-29 12:20:59 +0200
commit50a46710a9c6942751930fa963e0d70d84128859 (patch)
treeb382e23d9e9702a680c80940613da4ac6cb8ea66
parentf3dafe91ff753e3a801aa336d41be9eca75925bc (diff)
downloadrust-50a46710a9c6942751930fa963e0d70d84128859.tar.gz
rust-50a46710a9c6942751930fa963e0d70d84128859.zip
Avoid linting on expression that are only UB with SB/TB
-rw-r--r--compiler/rustc_lint/src/reference_casting.rs17
-rw-r--r--tests/ui/lint/reference_casting.rs5
-rw-r--r--tests/ui/lint/reference_casting.stderr48
3 files changed, 34 insertions, 36 deletions
diff --git a/compiler/rustc_lint/src/reference_casting.rs b/compiler/rustc_lint/src/reference_casting.rs
index e6cab4cebe7..428bf750bbd 100644
--- a/compiler/rustc_lint/src/reference_casting.rs
+++ b/compiler/rustc_lint/src/reference_casting.rs
@@ -56,7 +56,20 @@ impl<'tcx> LateLintPass<'tcx> for InvalidReferenceCasting {
     }
 
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        let ExprKind::Unary(UnOp::Deref, e) = &expr.kind else {
+        // &mut <expr>
+        let inner = if let ExprKind::AddrOf(_, Mutability::Mut, expr) = expr.kind {
+            expr
+        // <expr> = ...
+        } else if let ExprKind::Assign(expr, _, _) = expr.kind {
+            expr
+        // <expr> += ...
+        } else if let ExprKind::AssignOp(_, expr, _) = expr.kind {
+            expr
+        } else {
+            return;
+        };
+
+        let ExprKind::Unary(UnOp::Deref, e) = &inner.kind else {
             return;
         };
 
@@ -103,5 +116,5 @@ fn is_cast_from_const_to_mut<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>)
     };
 
     let e = e.peel_blocks();
-    matches!(cx.typeck_results().node_type(e.hir_id).kind(), ty::Ref(..))
+    matches!(cx.typeck_results().node_type(e.hir_id).kind(), ty::Ref(_, _, Mutability::Not))
 }
diff --git a/tests/ui/lint/reference_casting.rs b/tests/ui/lint/reference_casting.rs
index c3168cd4c01..aa946038c99 100644
--- a/tests/ui/lint/reference_casting.rs
+++ b/tests/ui/lint/reference_casting.rs
@@ -16,8 +16,6 @@ fn main() {
         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";
@@ -26,8 +24,6 @@ fn main() {
         //~^ 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;
@@ -41,6 +37,7 @@ fn main() {
         //~^ 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 _);
diff --git a/tests/ui/lint/reference_casting.stderr b/tests/ui/lint/reference_casting.stderr
index d9ce4b38387..22bc66264d0 100644
--- a/tests/ui/lint/reference_casting.stderr
+++ b/tests/ui/lint/reference_casting.stderr
@@ -1,72 +1,60 @@
 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
    |
-LL |         (*(a as *const _ as *mut String)).push_str(" world");
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         *(a as *const _ as *mut _) = String::from("Replaced");
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = 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
    |
-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: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/reference_casting.rs:25:25
+  --> $DIR/reference_casting.rs:23:20
    |
 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/reference_casting.rs:27:25
+  --> $DIR/reference_casting.rs:25:20
    |
 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: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/reference_casting.rs:31:9
+  --> $DIR/reference_casting.rs:27: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/reference_casting.rs:33:9
+  --> $DIR/reference_casting.rs:29: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/reference_casting.rs:35:9
+  --> $DIR/reference_casting.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/reference_casting.rs:37:9
+  --> $DIR/reference_casting.rs:33:9
    |
 LL |         *(std::ptr::from_ref({ num }) as *mut i32) += 1;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
-  --> $DIR/reference_casting.rs:40:9
+  --> $DIR/reference_casting.rs:36:9
    |
 LL |         let value = num as *const i32 as *mut i32;
    |                     ----------------------------- casting happend here
 LL |         *value = 1;
-   |         ^^^^^^
+   |         ^^^^^^^^^^
 
-error: aborting due to 11 previous errors
+error: aborting due to 9 previous errors