about summary refs log tree commit diff
diff options
context:
space:
mode:
authorUrgau <urgau@numericable.fr>2023-07-14 22:25:47 +0200
committerUrgau <urgau@numericable.fr>2023-07-29 12:20:59 +0200
commit20a6b571063d33c4b1a786c558f74edbda3012ea (patch)
treeaed81caf56603e7ca6e9b8ea1ff8871df04fdf44
parent50a46710a9c6942751930fa963e0d70d84128859 (diff)
downloadrust-20a6b571063d33c4b1a786c558f74edbda3012ea.tar.gz
rust-20a6b571063d33c4b1a786c558f74edbda3012ea.zip
Improve diagnostics of the invalid_reference_casting lint
-rw-r--r--compiler/rustc_lint/messages.ftl5
-rw-r--r--compiler/rustc_lint/src/lints.rs15
-rw-r--r--compiler/rustc_lint/src/reference_casting.rs20
-rw-r--r--tests/ui/lint/reference_casting.rs93
-rw-r--r--tests/ui/lint/reference_casting.stderr96
5 files changed, 152 insertions, 77 deletions
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 95f0b651962..f482e3d7c12 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -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
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 6d774070ec4..a6a48bf4ffa 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -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
diff --git a/compiler/rustc_lint/src/reference_casting.rs b/compiler/rustc_lint/src/reference_casting.rs
index 428bf750bbd..ed3d4721049 100644
--- a/compiler/rustc_lint/src/reference_casting.rs
+++ b/compiler/rustc_lint/src/reference_casting.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 }
+            },
+        );
     }
 }
 
diff --git a/tests/ui/lint/reference_casting.rs b/tests/ui/lint/reference_casting.rs
index aa946038c99..6e70626ef99 100644
--- a/tests/ui/lint/reference_casting.rs
+++ b/tests/ui/lint/reference_casting.rs
@@ -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;
-
-        *(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;
-    }
+    let num = &3i32;
+
+    *(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() {}
diff --git a/tests/ui/lint/reference_casting.stderr b/tests/ui/lint/reference_casting.stderr
index 22bc66264d0..02b23600557 100644
--- a/tests/ui/lint/reference_casting.stderr
+++ b/tests/ui/lint/reference_casting.stderr
@@ -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 |     *(a as *const _ as *mut String) += " world";
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+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;
-   |         ^^^^^^^^^^
+LL |     let value = num as *const i32 as *mut i32;
+   |                 ----------------------------- casting happend here
+LL |     *value = 1;
+   |     ^^^^^^^^^^
 
-error: aborting due to 9 previous errors
+error: aborting due to 14 previous errors