about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2024-02-10 13:12:28 +0100
committerGitHub <noreply@github.com>2024-02-10 13:12:28 +0100
commit0b7f0ff230b125032d1ac29a9d34195bc5d8d42a (patch)
tree8642721e601f1aded01a2f4a0d580e51a57a1510
parent232919c33a5ba8ce8b4171b03cc898c77da136cc (diff)
parent9a819ab8f7f69b5461d0a9a7f8b57f976de1ae2e (diff)
downloadrust-0b7f0ff230b125032d1ac29a9d34195bc5d8d42a.tar.gz
rust-0b7f0ff230b125032d1ac29a9d34195bc5d8d42a.zip
Rollup merge of #117614 - RalfJung:static-mut-refs, r=davidtwco,oli-obk
static mut: allow mutable reference to arbitrary types, not just slices and arrays

For historical reasons, we allow this:
```rust
static mut ARRAY: &'static mut [isize] = &mut [1];
```
However, we do not allow this:
```rust
static mut INT: &'static mut isize = &mut 1;
```

I think that's terribly inconsistent. I don't care much for `static mut`, but we have to keep it around for backwards compatibility and so we have to keep supporting it properly in the compiler. In recent refactors of how we deal with mutability of data in `static` and `const`, I almost made a fatal mistake since I tested `static mut INT: &'static mut isize = &mut 1` and concluded that we don't allow such `'static` mutable references even inside `static mut`. After all, nobody would expect this to be allowed only for arrays and slices, right?!?? So for the sake of our own sanity, and of whoever else reverse engineers these rules in the future to understand what the Rust compiler accepts or does not accept, I propose that we accept this for all types, not just arrays and slices.
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs40
-rw-r--r--tests/ui/array-slice-vec/check-static-mut-slices.rs15
-rw-r--r--tests/ui/consts/const-address-of-mut.rs2
-rw-r--r--tests/ui/consts/const-address-of-mut.stderr14
-rw-r--r--tests/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr10
-rw-r--r--tests/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr10
-rw-r--r--tests/ui/consts/static-mut-refs.rs24
-rw-r--r--tests/ui/consts/static_mut_containing_mut_ref2.rs2
-rw-r--r--tests/ui/consts/static_mut_containing_mut_ref2.stock.stderr6
9 files changed, 46 insertions, 77 deletions
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index ee3f349c6b8..28dc69859fd 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -449,35 +449,27 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                 }
             }
 
-            Rvalue::Ref(_, BorrowKind::Mut { .. }, place) => {
-                let ty = place.ty(self.body, self.tcx).ty;
-                let is_allowed = match ty.kind() {
-                    // Inside a `static mut`, `&mut [...]` is allowed.
-                    ty::Array(..) | ty::Slice(_)
-                        if self.const_kind() == hir::ConstContext::Static(hir::Mutability::Mut) =>
-                    {
-                        true
-                    }
-
-                    // FIXME(ecstaticmorse): We could allow `&mut []` inside a const context given
-                    // that this is merely a ZST and it is already eligible for promotion.
-                    // This may require an RFC?
-                    /*
-                    ty::Array(_, len) if len.try_eval_target_usize(cx.tcx, cx.param_env) == Some(0)
-                        => true,
-                    */
-                    _ => false,
-                };
+            Rvalue::Ref(_, BorrowKind::Mut { .. }, place)
+            | Rvalue::AddressOf(Mutability::Mut, place) => {
+                // Inside mutable statics, we allow arbitrary mutable references.
+                // We've allowed `static mut FOO = &mut [elements];` for a long time (the exact
+                // reasons why are lost to history), and there is no reason to restrict that to
+                // arrays and slices.
+                let is_allowed =
+                    self.const_kind() == hir::ConstContext::Static(hir::Mutability::Mut);
 
                 if !is_allowed {
-                    self.check_mut_borrow(place.local, hir::BorrowKind::Ref)
+                    self.check_mut_borrow(
+                        place.local,
+                        if matches!(rvalue, Rvalue::Ref(..)) {
+                            hir::BorrowKind::Ref
+                        } else {
+                            hir::BorrowKind::Raw
+                        },
+                    );
                 }
             }
 
-            Rvalue::AddressOf(Mutability::Mut, place) => {
-                self.check_mut_borrow(place.local, hir::BorrowKind::Raw)
-            }
-
             Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Fake, place)
             | Rvalue::AddressOf(Mutability::Not, place) => {
                 let borrowed_place_has_mut_interior = qualifs::in_place::<HasMutInterior, _>(
diff --git a/tests/ui/array-slice-vec/check-static-mut-slices.rs b/tests/ui/array-slice-vec/check-static-mut-slices.rs
deleted file mode 100644
index b89c634036e..00000000000
--- a/tests/ui/array-slice-vec/check-static-mut-slices.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-// run-pass
-#![allow(dead_code)]
-
-// Checks that mutable static items can have mutable slices
-
-
-static mut TEST: &'static mut [isize] = &mut [1];
-static mut EMPTY: &'static mut [isize] = &mut [];
-
-pub fn main() {
-    unsafe {
-        TEST[0] += 1;
-        assert_eq!(TEST[0], 2);
-    }
-}
diff --git a/tests/ui/consts/const-address-of-mut.rs b/tests/ui/consts/const-address-of-mut.rs
index 5f0c76d6285..0018bf18e41 100644
--- a/tests/ui/consts/const-address-of-mut.rs
+++ b/tests/ui/consts/const-address-of-mut.rs
@@ -4,8 +4,6 @@ const A: () = { let mut x = 2; &raw mut x; };           //~ mutable pointer
 
 static B: () = { let mut x = 2; &raw mut x; };          //~ mutable pointer
 
-static mut C: () = { let mut x = 2; &raw mut x; };      //~ mutable pointer
-
 const fn foo() {
     let mut x = 0;
     let y = &raw mut x;                                 //~ mutable pointer
diff --git a/tests/ui/consts/const-address-of-mut.stderr b/tests/ui/consts/const-address-of-mut.stderr
index 1b371fcee98..95a91ff463f 100644
--- a/tests/ui/consts/const-address-of-mut.stderr
+++ b/tests/ui/consts/const-address-of-mut.stderr
@@ -18,18 +18,8 @@ LL | static B: () = { let mut x = 2; &raw mut x; };
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: raw mutable pointers are not allowed in statics
-  --> $DIR/const-address-of-mut.rs:7:37
-   |
-LL | static mut C: () = { let mut x = 2; &raw mut x; };
-   |                                     ^^^^^^^^^^
-   |
-   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
 error[E0658]: raw mutable pointers are not allowed in constant functions
-  --> $DIR/const-address-of-mut.rs:11:13
+  --> $DIR/const-address-of-mut.rs:9:13
    |
 LL |     let y = &raw mut x;
    |             ^^^^^^^^^^
@@ -38,6 +28,6 @@ LL |     let y = &raw mut x;
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr b/tests/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr
index 2df80020fdc..4793466a987 100644
--- a/tests/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr
+++ b/tests/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr
@@ -134,11 +134,6 @@ help: skipping check for `const_mut_refs` feature
 LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) };
    |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_references_err.rs:40:49
-   |
-LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) };
-   |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: skipping check that does not even have a feature gate
   --> $DIR/mutable_references_err.rs:47:44
    |
 LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE };
@@ -149,11 +144,6 @@ help: skipping check that does not even have a feature gate
 LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE };
    |                                            ^^^^^^^
 help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_references_err.rs:50:36
-   |
-LL | static mut MUTABLE_REF: &mut i32 = &mut 42;
-   |                                    ^^^^^^^
-help: skipping check that does not even have a feature gate
   --> $DIR/mutable_references_err.rs:51:45
    |
 LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF };
diff --git a/tests/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr b/tests/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr
index 3ff6811ea61..f5f7b605c94 100644
--- a/tests/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr
+++ b/tests/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr
@@ -134,11 +134,6 @@ help: skipping check for `const_mut_refs` feature
 LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) };
    |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_references_err.rs:40:49
-   |
-LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) };
-   |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: skipping check that does not even have a feature gate
   --> $DIR/mutable_references_err.rs:47:44
    |
 LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE };
@@ -149,11 +144,6 @@ help: skipping check that does not even have a feature gate
 LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE };
    |                                            ^^^^^^^
 help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_references_err.rs:50:36
-   |
-LL | static mut MUTABLE_REF: &mut i32 = &mut 42;
-   |                                    ^^^^^^^
-help: skipping check that does not even have a feature gate
   --> $DIR/mutable_references_err.rs:51:45
    |
 LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF };
diff --git a/tests/ui/consts/static-mut-refs.rs b/tests/ui/consts/static-mut-refs.rs
new file mode 100644
index 00000000000..ff865da5aa8
--- /dev/null
+++ b/tests/ui/consts/static-mut-refs.rs
@@ -0,0 +1,24 @@
+// run-pass
+#![allow(dead_code)]
+
+// Checks that mutable static items can have mutable slices and other references
+
+
+static mut TEST: &'static mut [isize] = &mut [1];
+static mut EMPTY: &'static mut [isize] = &mut [];
+static mut INT: &'static mut isize = &mut 1;
+
+// And the same for raw pointers.
+
+static mut TEST_RAW: *mut [isize] = &mut [1isize] as *mut _;
+static mut EMPTY_RAW: *mut [isize] = &mut [] as *mut _;
+static mut INT_RAW: *mut isize = &mut 1isize as *mut _;
+
+pub fn main() {
+    unsafe {
+        TEST[0] += 1;
+        assert_eq!(TEST[0], 2);
+        *INT_RAW += 1;
+        assert_eq!(*INT_RAW, 2);
+    }
+}
diff --git a/tests/ui/consts/static_mut_containing_mut_ref2.rs b/tests/ui/consts/static_mut_containing_mut_ref2.rs
index fa79a78eab4..b71f1122cd0 100644
--- a/tests/ui/consts/static_mut_containing_mut_ref2.rs
+++ b/tests/ui/consts/static_mut_containing_mut_ref2.rs
@@ -7,7 +7,7 @@ static mut STDERR_BUFFER_SPACE: u8 = 0;
 pub static mut STDERR_BUFFER: () = unsafe {
     *(&mut STDERR_BUFFER_SPACE) = 42;
     //[mut_refs]~^ ERROR could not evaluate static initializer
-    //[stock]~^^ ERROR mutable references are not allowed in statics
+    //[stock]~^^ ERROR mutation through a reference is not allowed in statics
     //[mut_refs]~^^^ WARN mutable reference of mutable static is discouraged [static_mut_ref]
     //[stock]~^^^^ WARN mutable reference of mutable static is discouraged [static_mut_ref]
 };
diff --git a/tests/ui/consts/static_mut_containing_mut_ref2.stock.stderr b/tests/ui/consts/static_mut_containing_mut_ref2.stock.stderr
index e9fe82d2f87..aea5b8a33b5 100644
--- a/tests/ui/consts/static_mut_containing_mut_ref2.stock.stderr
+++ b/tests/ui/consts/static_mut_containing_mut_ref2.stock.stderr
@@ -13,11 +13,11 @@ help: mutable references are dangerous since if there's any other pointer or ref
 LL |     *addr_of_mut!(STDERR_BUFFER_SPACE) = 42;
    |      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-error[E0658]: mutable references are not allowed in statics
-  --> $DIR/static_mut_containing_mut_ref2.rs:8:6
+error[E0658]: mutation through a reference is not allowed in statics
+  --> $DIR/static_mut_containing_mut_ref2.rs:8:5
    |
 LL |     *(&mut STDERR_BUFFER_SPACE) = 42;
-   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable