Skip to content

Commit 3cc8c8d

Browse files
committed
allow statics pointing to mutable statics
1 parent ef32456 commit 3cc8c8d

File tree

11 files changed

+207
-91
lines changed

11 files changed

+207
-91
lines changed

compiler/rustc_const_eval/messages.ftl

-1
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,6 @@ const_eval_validation_invalid_fn_ptr = {$front_matter}: encountered {$value}, bu
453453
const_eval_validation_invalid_ref_meta = {$front_matter}: encountered invalid reference metadata: total size is bigger than largest supported object
454454
const_eval_validation_invalid_ref_slice_meta = {$front_matter}: encountered invalid reference metadata: slice is bigger than largest supported object
455455
const_eval_validation_invalid_vtable_ptr = {$front_matter}: encountered {$value}, but expected a vtable pointer
456-
const_eval_validation_mutable_ref_in_const_or_static = {$front_matter}: encountered mutable reference in a `const` or `static`
457456
const_eval_validation_mutable_ref_to_immutable = {$front_matter}: encountered mutable reference or box pointing to read-only memory
458457
const_eval_validation_never_val = {$front_matter}: encountered a value of the never type `!`
459458
const_eval_validation_null_box = {$front_matter}: encountered a null box

compiler/rustc_const_eval/src/errors.rs

-2
Original file line numberDiff line numberDiff line change
@@ -614,7 +614,6 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
614614
PartialPointer => const_eval_validation_partial_pointer,
615615
ConstRefToMutable => const_eval_validation_const_ref_to_mutable,
616616
ConstRefToExtern => const_eval_validation_const_ref_to_extern,
617-
MutableRefInConstOrStatic => const_eval_validation_mutable_ref_in_const_or_static,
618617
MutableRefToImmutable => const_eval_validation_mutable_ref_to_immutable,
619618
NullFnPtr => const_eval_validation_null_fn_ptr,
620619
NeverVal => const_eval_validation_never_val,
@@ -768,7 +767,6 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
768767
}
769768
NullPtr { .. }
770769
| PtrToStatic { .. }
771-
| MutableRefInConstOrStatic
772770
| ConstRefToMutable
773771
| ConstRefToExtern
774772
| MutableRefToImmutable

compiler/rustc_const_eval/src/interpret/validity.rs

+8-17
Original file line numberDiff line numberDiff line change
@@ -148,14 +148,6 @@ impl CtfeValidationMode {
148148
}
149149
}
150150
}
151-
152-
fn may_contain_mutable_ref(self) -> bool {
153-
match self {
154-
CtfeValidationMode::Static { mutbl } => mutbl == Mutability::Mut,
155-
CtfeValidationMode::Promoted { .. } => false,
156-
CtfeValidationMode::Const { .. } => false,
157-
}
158-
}
159151
}
160152

161153
/// State for tracking recursive validation of references
@@ -511,20 +503,19 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
511503
// If this allocation has size zero, there is no actual mutability here.
512504
let (size, _align, _alloc_kind) = self.ecx.get_alloc_info(alloc_id);
513505
if size != Size::ZERO {
506+
// Mutable pointer to immutable memory is no good.
514507
if ptr_expected_mutbl == Mutability::Mut
515508
&& alloc_actual_mutbl == Mutability::Not
516509
{
517510
throw_validation_failure!(self.path, MutableRefToImmutable);
518511
}
519-
if ptr_expected_mutbl == Mutability::Mut
520-
&& self.ctfe_mode.is_some_and(|c| !c.may_contain_mutable_ref())
521-
{
522-
throw_validation_failure!(self.path, MutableRefInConstOrStatic);
523-
}
524-
if alloc_actual_mutbl == Mutability::Mut
525-
&& matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. }))
526-
{
527-
throw_validation_failure!(self.path, ConstRefToMutable);
512+
// In a const, everything must be completely immutable.
513+
if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. })) {
514+
if ptr_expected_mutbl == Mutability::Mut
515+
|| alloc_actual_mutbl == Mutability::Mut
516+
{
517+
throw_validation_failure!(self.path, ConstRefToMutable);
518+
}
528519
}
529520
}
530521
// Potentially skip recursive check.

compiler/rustc_middle/src/mir/interpret/error.rs

-1
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,6 @@ pub enum ValidationErrorKind<'tcx> {
420420
PartialPointer,
421421
PtrToUninhabited { ptr_kind: PointerKind, ty: Ty<'tcx> },
422422
PtrToStatic { ptr_kind: PointerKind },
423-
MutableRefInConstOrStatic,
424423
ConstRefToMutable,
425424
ConstRefToExtern,
426425
MutableRefToImmutable,

tests/ui/consts/const-mut-refs/const_mut_refs.rs

+5
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ const fn bazz(foo: &mut Foo) -> usize {
3333
// Empty slices get promoted so this passes the static checks.
3434
// Make sure it also passes the dynamic checks.
3535
static MUTABLE_REFERENCE_HOLDER: Mutex<&mut [u8]> = Mutex::new(&mut []);
36+
// This variant with a non-empty slice also seems entirely reasonable.
37+
static MUTABLE_REFERENCE_HOLDER2: Mutex<&mut [u8]> = unsafe {
38+
static mut FOO: [u8; 1] = [42]; // a private static that we are sure nobody else will reference
39+
Mutex::new(&mut *std::ptr::addr_of_mut!(FOO))
40+
};
3641

3742
fn main() {
3843
let _: [(); foo().bar()] = [(); 1];

tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs

+4-8
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,7 @@ const fn helper() -> Option<&'static mut i32> { unsafe {
1818
Some(&mut *std::ptr::addr_of_mut!(BUFFER))
1919
} }
2020
const MUT: Option<&mut i32> = helper(); //~ ERROR it is undefined behavior to use this value
21-
//~^ encountered mutable reference
22-
static MUT_STATIC: Option<&mut i32> = helper(); //~ ERROR it is undefined behavior to use this value
23-
//~^ encountered mutable reference
21+
//~^ encountered reference to mutable
2422

2523
const fn helper_int2ptr() -> Option<&'static mut i32> { unsafe {
2624
// Undefined behaviour (integer as pointer), who doesn't love tests like this.
@@ -38,11 +36,9 @@ const fn helper_dangling() -> Option<&'static mut i32> { unsafe {
3836
const DANGLING: Option<&mut i32> = helper_dangling(); //~ ERROR encountered dangling pointer
3937
static DANGLING_STATIC: Option<&mut i32> = helper_dangling(); //~ ERROR encountered dangling pointer
4038

41-
// Variant of the real-world case in <https://github.com/rust-lang/rust/issues/120450>.
42-
// Maybe we should allow this in the future (then the rest should move to `const_mut_refs.rs`),
43-
// but for now we reject it.
39+
// These are fine! Just statics pointing to mutable statics, nothing fundamentally wrong with this.
40+
static MUT_STATIC: Option<&mut i32> = helper();
4441
static mut MUT_ARRAY: &mut [u8] = &mut [42];
45-
static MUTEX: Mutex<&mut [u8]> = Mutex::new(unsafe { &mut *MUT_ARRAY }); //~ ERROR it is undefined behavior to use this value
46-
//~^ encountered mutable reference
42+
static MUTEX: Mutex<&mut [u8]> = Mutex::new(unsafe { &mut *MUT_ARRAY });
4743

4844
fn main() {}

tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr

+6-28
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,15 @@ error[E0080]: it is undefined behavior to use this value
22
--> $DIR/mut_ref_in_final_dynamic_check.rs:20:1
33
|
44
LL | const MUT: Option<&mut i32> = helper();
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Some)>.0: encountered mutable reference in a `const` or `static`
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Some)>.0: encountered reference to mutable memory in `const`
66
|
77
= 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.
88
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
99
HEX_DUMP
1010
}
1111

1212
error[E0080]: it is undefined behavior to use this value
13-
--> $DIR/mut_ref_in_final_dynamic_check.rs:22:1
14-
|
15-
LL | static MUT_STATIC: Option<&mut i32> = helper();
16-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Some)>.0: encountered mutable reference in a `const` or `static`
17-
|
18-
= 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.
19-
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
20-
HEX_DUMP
21-
}
22-
23-
error[E0080]: it is undefined behavior to use this value
24-
--> $DIR/mut_ref_in_final_dynamic_check.rs:29:1
13+
--> $DIR/mut_ref_in_final_dynamic_check.rs:27:1
2514
|
2615
LL | const INT2PTR: Option<&mut i32> = helper_int2ptr();
2716
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Some)>.0: encountered a dangling reference (0x2a[noalloc] has no provenance)
@@ -32,7 +21,7 @@ LL | const INT2PTR: Option<&mut i32> = helper_int2ptr();
3221
}
3322

3423
error[E0080]: it is undefined behavior to use this value
35-
--> $DIR/mut_ref_in_final_dynamic_check.rs:31:1
24+
--> $DIR/mut_ref_in_final_dynamic_check.rs:29:1
3625
|
3726
LL | static INT2PTR_STATIC: Option<&mut i32> = helper_int2ptr();
3827
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Some)>.0: encountered a dangling reference (0x2a[noalloc] has no provenance)
@@ -43,28 +32,17 @@ LL | static INT2PTR_STATIC: Option<&mut i32> = helper_int2ptr();
4332
}
4433

4534
error: encountered dangling pointer in final value of constant
46-
--> $DIR/mut_ref_in_final_dynamic_check.rs:38:1
35+
--> $DIR/mut_ref_in_final_dynamic_check.rs:36:1
4736
|
4837
LL | const DANGLING: Option<&mut i32> = helper_dangling();
4938
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5039

5140
error: encountered dangling pointer in final value of static
52-
--> $DIR/mut_ref_in_final_dynamic_check.rs:39:1
41+
--> $DIR/mut_ref_in_final_dynamic_check.rs:37:1
5342
|
5443
LL | static DANGLING_STATIC: Option<&mut i32> = helper_dangling();
5544
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5645

57-
error[E0080]: it is undefined behavior to use this value
58-
--> $DIR/mut_ref_in_final_dynamic_check.rs:45:1
59-
|
60-
LL | static MUTEX: Mutex<&mut [u8]> = Mutex::new(unsafe { &mut *MUT_ARRAY });
61-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .data.value: encountered mutable reference in a `const` or `static`
62-
|
63-
= 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.
64-
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
65-
HEX_DUMP
66-
}
67-
68-
error: aborting due to 7 previous errors
46+
error: aborting due to 5 previous errors
6947

7048
For more information about this error, try `rustc --explain E0080`.

tests/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ error[E0080]: it is undefined behavior to use this value
1414
--> $DIR/mutable_references_err.rs:33:1
1515
|
1616
LL | const SUBTLE: &mut i32 = unsafe { &mut FOO };
17-
| ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference in a `const` or `static`
17+
| ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered reference to mutable memory in `const`
1818
|
1919
= 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.
2020
= note: the raw bytes of the constant (size: 8, align: 8) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
error: encountered mutable pointer in final value of constant
2+
--> $DIR/mutable_references_err.rs:18:1
3+
|
4+
LL | const MUH: Meh = Meh {
5+
| ^^^^^^^^^^^^^^
6+
7+
error: encountered mutable pointer in final value of constant
8+
--> $DIR/mutable_references_err.rs:29:1
9+
|
10+
LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) };
11+
| ^^^^^^^^^^^^^^^^^^^^^^^
12+
13+
error[E0080]: it is undefined behavior to use this value
14+
--> $DIR/mutable_references_err.rs:34:1
15+
|
16+
LL | const SUBTLE: &mut i32 = unsafe { &mut FOO };
17+
| ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered reference to mutable memory in `const`
18+
|
19+
= 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.
20+
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
21+
HEX_DUMP
22+
}
23+
24+
error: encountered mutable pointer in final value of constant
25+
--> $DIR/mutable_references_err.rs:37:1
26+
|
27+
LL | const BLUNT: &mut i32 = &mut 42;
28+
| ^^^^^^^^^^^^^^^^^^^^^
29+
30+
error[E0080]: it is undefined behavior to use this value
31+
--> $DIR/mutable_references_err.rs:42:1
32+
|
33+
LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) };
34+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory
35+
|
36+
= 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.
37+
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
38+
HEX_DUMP
39+
}
40+
41+
error[E0080]: it is undefined behavior to use this value
42+
--> $DIR/mutable_references_err.rs:49:1
43+
|
44+
LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE };
45+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered reference to mutable memory in `const`
46+
|
47+
= 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.
48+
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
49+
HEX_DUMP
50+
}
51+
52+
note: erroneous constant encountered
53+
--> $DIR/mutable_references_err.rs:51:34
54+
|
55+
LL | const READS_FROM_MUTABLE: i32 = *POINTS_TO_MUTABLE1;
56+
| ^^^^^^^^^^^^^^^^^^
57+
58+
error[E0080]: evaluation of constant value failed
59+
--> $DIR/mutable_references_err.rs:53:43
60+
|
61+
LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF };
62+
| ^^^^^^^^^^^^^ constant accesses mutable global memory
63+
64+
error: encountered mutable pointer in final value of constant
65+
--> $DIR/mutable_references_err.rs:57:1
66+
|
67+
LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _;
68+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
69+
70+
error: encountered mutable pointer in final value of constant
71+
--> $DIR/mutable_references_err.rs:59:1
72+
|
73+
LL | const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _;
74+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
75+
76+
error: encountered mutable pointer in final value of constant
77+
--> $DIR/mutable_references_err.rs:61:1
78+
|
79+
LL | const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _;
80+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
81+
82+
error: encountered mutable pointer in final value of constant
83+
--> $DIR/mutable_references_err.rs:73:1
84+
|
85+
LL | const RAW_SYNC: SyncPtr<AtomicI32> = SyncPtr { x: &AtomicI32::new(42) };
86+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
87+
88+
error: encountered mutable pointer in final value of constant
89+
--> $DIR/mutable_references_err.rs:75:1
90+
|
91+
LL | const RAW_MUT_CAST: SyncPtr<i32> = SyncPtr { x: &mut 42 as *mut _ as *const _ };
92+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
93+
94+
error: encountered mutable pointer in final value of constant
95+
--> $DIR/mutable_references_err.rs:77:1
96+
|
97+
LL | const RAW_MUT_COERCE: SyncPtr<i32> = SyncPtr { x: &mut 0 };
98+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
99+
100+
warning: skipping const checks
101+
|
102+
help: skipping check that does not even have a feature gate
103+
--> $DIR/mutable_references_err.rs:20:8
104+
|
105+
LL | x: &UnsafeCell::new(42),
106+
| ^^^^^^^^^^^^^^^^^^^^
107+
help: skipping check that does not even have a feature gate
108+
--> $DIR/mutable_references_err.rs:29:27
109+
|
110+
LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) };
111+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
112+
help: skipping check for `const_refs_to_static` feature
113+
--> $DIR/mutable_references_err.rs:34:40
114+
|
115+
LL | const SUBTLE: &mut i32 = unsafe { &mut FOO };
116+
| ^^^
117+
help: skipping check for `const_mut_refs` feature
118+
--> $DIR/mutable_references_err.rs:34:35
119+
|
120+
LL | const SUBTLE: &mut i32 = unsafe { &mut FOO };
121+
| ^^^^^^^^
122+
help: skipping check that does not even have a feature gate
123+
--> $DIR/mutable_references_err.rs:37:25
124+
|
125+
LL | const BLUNT: &mut i32 = &mut 42;
126+
| ^^^^^^^
127+
help: skipping check for `const_mut_refs` feature
128+
--> $DIR/mutable_references_err.rs:42:49
129+
|
130+
LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) };
131+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
132+
help: skipping check for `const_mut_refs` feature
133+
--> $DIR/mutable_references_err.rs:42:49
134+
|
135+
LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) };
136+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
137+
help: skipping check for `const_refs_to_static` feature
138+
--> $DIR/mutable_references_err.rs:49:44
139+
|
140+
LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE };
141+
| ^^^^^^^
142+
help: skipping check for `const_refs_to_static` feature
143+
--> $DIR/mutable_references_err.rs:53:45
144+
|
145+
LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF };
146+
| ^^^^^^^^^^^
147+
help: skipping check that does not even have a feature gate
148+
--> $DIR/mutable_references_err.rs:57:45
149+
|
150+
LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _;
151+
| ^^^^^^^
152+
help: skipping check that does not even have a feature gate
153+
--> $DIR/mutable_references_err.rs:59:46
154+
|
155+
LL | const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _;
156+
| ^^^^^^^
157+
help: skipping check that does not even have a feature gate
158+
--> $DIR/mutable_references_err.rs:61:47
159+
|
160+
LL | const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _;
161+
| ^^^^^^^^^^^^^^^^^^^^
162+
help: skipping check that does not even have a feature gate
163+
--> $DIR/mutable_references_err.rs:73:51
164+
|
165+
LL | const RAW_SYNC: SyncPtr<AtomicI32> = SyncPtr { x: &AtomicI32::new(42) };
166+
| ^^^^^^^^^^^^^^^^^^^
167+
help: skipping check that does not even have a feature gate
168+
--> $DIR/mutable_references_err.rs:75:49
169+
|
170+
LL | const RAW_MUT_CAST: SyncPtr<i32> = SyncPtr { x: &mut 42 as *mut _ as *const _ };
171+
| ^^^^^^^
172+
help: skipping check that does not even have a feature gate
173+
--> $DIR/mutable_references_err.rs:77:51
174+
|
175+
LL | const RAW_MUT_COERCE: SyncPtr<i32> = SyncPtr { x: &mut 0 };
176+
| ^^^^^^
177+
178+
error: aborting due to 13 previous errors; 1 warning emitted
179+
180+
For more information about this error, try `rustc --explain E0080`.

tests/ui/error-codes/E0017.rs

-4
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,4 @@ static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR cannot borrow immutable
1515
static CONST_REF: &'static mut i32 = &mut C; //~ ERROR mutable references are not allowed
1616
//~| WARN taking a mutable
1717

18-
static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M };
19-
//~^ WARN mutable reference to mutable static is discouraged [static_mut_refs]
20-
//~| ERROR undefined behavior
21-
2218
fn main() {}

0 commit comments

Comments
 (0)