Skip to content

Commit

Permalink
Rollup merge of #117614 - RalfJung:static-mut-refs, r=davidtwco,oli-obk
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
matthiaskrgr committed Feb 10, 2024
2 parents 232919c + 9a819ab commit 0b7f0ff
Show file tree
Hide file tree
Showing 9 changed files with 46 additions and 77 deletions.
40 changes: 16 additions & 24 deletions compiler/rustc_const_eval/src/transform/check_consts/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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, _>(
Expand Down
15 changes: 0 additions & 15 deletions tests/ui/array-slice-vec/check-static-mut-slices.rs

This file was deleted.

2 changes: 0 additions & 2 deletions tests/ui/consts/const-address-of-mut.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
14 changes: 2 additions & 12 deletions tests/ui/consts/const-address-of-mut.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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;
| ^^^^^^^^^^
Expand All @@ -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`.
10 changes: 0 additions & 10 deletions tests/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -133,11 +133,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
|
Expand All @@ -148,11 +143,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
|
Expand Down
10 changes: 0 additions & 10 deletions tests/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -133,11 +133,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
|
Expand All @@ -148,11 +143,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
|
Expand Down
24 changes: 24 additions & 0 deletions tests/ui/consts/static-mut-refs.rs
Original file line number Diff line number Diff line change
@@ -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);
}
}
2 changes: 1 addition & 1 deletion tests/ui/consts/static_mut_containing_mut_ref2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
};
Expand Down
6 changes: 3 additions & 3 deletions tests/ui/consts/static_mut_containing_mut_ref2.stock.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 0b7f0ff

Please sign in to comment.