Files
rust/tests/ui/consts/miri_unleashed/mutable_references.stderr
T
Matthias Krüger 8e4c70f02b Rollup merge of #148746 - RalfJung:mutable-ref-in-const, r=davidtwco
const validation: remove check for mutable refs in final value of const

This check rejects code that is not necessarily UB, e.g. a mutable ref to a `static mut` that is very carefully used correctly. That led to us having to describe it in the Reference, which uncovered just how ad-hoc this check is (https://github.com/rust-lang/reference/issues/2074).

Even without this check, we still reject things like
```rust
const C: &mut i32 = &mut 0;
```
This is rejected by const checking -- the part of the frontend that looks at the source code and says whether it is allowed in const context. In the Reference, this restriction is explained [here](https://doc.rust-lang.org/nightly/reference/const_eval.html#r-const-eval.const-expr.borrows).

So, the check during validation is just a safety net. And it is already a safety net with gaping holes since we only check `&mut T`, not `&UnsafeCell<T>`, due to the fact that we promote some immutable values that have `!Freeze` type so `&!Freeze` actually can occur in the final value of a const.

So... it may be time for me to acknowledge that the "mutable ref in final value of const" check is a cure that's worth than the disease. Nobody asked for that check, I just added it because I was worried about soundness issues when we allow mutable references in constants. Originally it was much stricter, but I had to slowly relax it to its current form to prevent t from firing on code we intend to allow. In the end there are only 3 tests left that trigger this error, and they are all just constants containing references to mutable statics -- not the safest code in the world, but also not so bad that we have to spend a lot of time devising a core language limitation and associated Reference wording to prevent it from ever happening.

So... `@rust-lang/wg-const-eval` `@rust-lang/lang`  I propose that we allow code like this
```rust
static mut S: i32 = 3;
const C2: &'static mut i32 = unsafe { &mut * &raw mut S };
```
`@theemathas` would be great if you could try to poke a hole into this. ;)
2025-11-29 20:54:05 +01:00

206 lines
9.1 KiB
Plaintext

error[E0080]: constructing invalid value at .<deref>: encountered mutable reference or box pointing to read-only memory
--> $DIR/mutable_references.rs:13:1
|
LL | static FOO: &&mut u32 = &&mut 42;
| ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
|
= note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
HEX_DUMP
}
error[E0080]: constructing invalid value: encountered mutable reference or box pointing to read-only memory
--> $DIR/mutable_references.rs:15:1
|
LL | static OH_YES: &mut i32 = &mut 42;
| ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
|
= note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
HEX_DUMP
}
error: encountered mutable pointer in final value of static
--> $DIR/mutable_references.rs:17:1
|
LL | static BAR: &mut () = &mut ();
| ^^^^^^^^^^^^^^^^^^^
error: encountered mutable pointer in final value of static
--> $DIR/mutable_references.rs:22:1
|
LL | static BOO: &mut Foo<()> = &mut Foo(());
| ^^^^^^^^^^^^^^^^^^^^^^^^
error[E0080]: constructing invalid value: encountered mutable reference or box pointing to read-only memory
--> $DIR/mutable_references.rs:25:1
|
LL | const BLUNT: &mut i32 = &mut 42;
| ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
|
= note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
HEX_DUMP
}
error[E0080]: constructing invalid value at .x.<deref>: encountered `UnsafeCell` in read-only memory
--> $DIR/mutable_references.rs:40:1
|
LL | static MEH: Meh = Meh { x: &UnsafeCell::new(42) };
| ^^^^^^^^^^^^^^^ it is undefined behavior to use this value
|
= note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
HEX_DUMP
}
error[E0080]: constructing invalid value at .x.<deref>: encountered `UnsafeCell` in read-only memory
--> $DIR/mutable_references.rs:45:1
|
LL | const MUH: Meh = Meh {
| ^^^^^^^^^^^^^^ it is undefined behavior to use this value
|
= note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
HEX_DUMP
}
error[E0080]: constructing invalid value at .<deref>.<dyn-downcast>.x: encountered `UnsafeCell` in read-only memory
--> $DIR/mutable_references.rs:56:1
|
LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) };
| ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
|
= note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
HEX_DUMP
}
error[E0080]: constructing invalid value: encountered mutable reference or box pointing to read-only memory
--> $DIR/mutable_references.rs:62:1
|
LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
|
= note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
HEX_DUMP
}
error[E0080]: constant accesses mutable global memory
--> $DIR/mutable_references.rs:73:43
|
LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF };
| ^^^^^^^^^^^^^ evaluation of `POINTS_TO_MUTABLE2` failed here
error: encountered mutable pointer in final value of constant
--> $DIR/mutable_references.rs:76:1
|
LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: encountered mutable pointer in final value of constant
--> $DIR/mutable_references.rs:79:1
|
LL | const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: encountered mutable pointer in final value of constant
--> $DIR/mutable_references.rs:99:1
|
LL | const RAW_MUT_CAST: SyncPtr<i32> = SyncPtr { x: &mut 42 as *mut _ as *const _ };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: encountered mutable pointer in final value of constant
--> $DIR/mutable_references.rs:102:1
|
LL | const RAW_MUT_COERCE: SyncPtr<i32> = SyncPtr { x: &mut 0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0594]: cannot assign to `*OH_YES`, as `OH_YES` is an immutable static item
--> $DIR/mutable_references.rs:109:5
|
LL | static OH_YES: &mut i32 = &mut 42;
| ----------------------- this `static` cannot be written to
...
LL | *OH_YES = 99;
| ^^^^^^^^^^^^ cannot assign
warning: skipping const checks
|
help: skipping check that does not even have a feature gate
--> $DIR/mutable_references.rs:13:26
|
LL | static FOO: &&mut u32 = &&mut 42;
| ^^^^^^^
help: skipping check that does not even have a feature gate
--> $DIR/mutable_references.rs:15:27
|
LL | static OH_YES: &mut i32 = &mut 42;
| ^^^^^^^
help: skipping check that does not even have a feature gate
--> $DIR/mutable_references.rs:17:23
|
LL | static BAR: &mut () = &mut ();
| ^^^^^^^
help: skipping check that does not even have a feature gate
--> $DIR/mutable_references.rs:22:28
|
LL | static BOO: &mut Foo<()> = &mut Foo(());
| ^^^^^^^^^^^^
help: skipping check that does not even have a feature gate
--> $DIR/mutable_references.rs:25:25
|
LL | const BLUNT: &mut i32 = &mut 42;
| ^^^^^^^
help: skipping check that does not even have a feature gate
--> $DIR/mutable_references.rs:40:28
|
LL | static MEH: Meh = Meh { x: &UnsafeCell::new(42) };
| ^^^^^^^^^^^^^^^^^^^^
help: skipping check that does not even have a feature gate
--> $DIR/mutable_references.rs:47:8
|
LL | x: &UnsafeCell::new(42),
| ^^^^^^^^^^^^^^^^^^^^
help: skipping check that does not even have a feature gate
--> $DIR/mutable_references.rs:56:27
|
LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: skipping check that does not even have a feature gate
--> $DIR/mutable_references.rs:76:45
|
LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _;
| ^^^^^^^
help: skipping check that does not even have a feature gate
--> $DIR/mutable_references.rs:79:46
|
LL | const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _;
| ^^^^^^^
help: skipping check that does not even have a feature gate
--> $DIR/mutable_references.rs:84:47
|
LL | const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _;
| ^^^^^^^^^^^^^^^^^^^^
help: skipping check that does not even have a feature gate
--> $DIR/mutable_references.rs:96:51
|
LL | const RAW_SYNC: SyncPtr<AtomicI32> = SyncPtr { x: &AtomicI32::new(42) };
| ^^^^^^^^^^^^^^^^^^^
help: skipping check that does not even have a feature gate
--> $DIR/mutable_references.rs:99:49
|
LL | const RAW_MUT_CAST: SyncPtr<i32> = SyncPtr { x: &mut 42 as *mut _ as *const _ };
| ^^^^^^^
help: skipping check that does not even have a feature gate
--> $DIR/mutable_references.rs:102:51
|
LL | const RAW_MUT_COERCE: SyncPtr<i32> = SyncPtr { x: &mut 0 };
| ^^^^^^
error: aborting due to 15 previous errors; 1 warning emitted
Some errors have detailed explanations: E0080, E0594.
For more information about an error, try `rustc --explain E0080`.