mirror of
https://github.com/rust-lang/rust
synced 2024-10-01 06:14:33 +00:00
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.
This commit is contained in:
commit
0b7f0ff230
|
@ -449,35 +449,27 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
|
|||
}
|
||||
}
|
||||
|
||||
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, _>(
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -4,8 +4,6 @@
|
|||
|
||||
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
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -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
|
||||
|
|
||||
|
@ -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
|
||||
|
|
||||
|
|
|
@ -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
|
||||
|
|
||||
|
@ -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
|
||||
|
|
||||
|
|
24
tests/ui/consts/static-mut-refs.rs
Normal file
24
tests/ui/consts/static-mut-refs.rs
Normal file
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@
|
|||
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]
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue