Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 0b84184

Browse files
committed
Allow references to interior mutable data behind a feature gate
1 parent a609fb4 commit 0b84184

23 files changed

+171
-41
lines changed

compiler/rustc_error_codes/src/error_codes/E0492.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@ A borrow of a constant containing interior mutability was attempted.
33
Erroneous code example:
44

55
```compile_fail,E0492
6+
#![feature(const_refs_to_cell)]
67
use std::sync::atomic::AtomicUsize;
78
89
const A: AtomicUsize = AtomicUsize::new(0);
9-
static B: &'static AtomicUsize = &A;
10+
const B: &'static AtomicUsize = &A;
1011
// error: cannot borrow a constant which may contain interior mutability,
1112
// create a static instead
1213
```
@@ -18,7 +19,7 @@ can't be changed via a shared `&` pointer, but interior mutability would allow
1819
it. That is, a constant value could be mutated. On the other hand, a `static` is
1920
explicitly a single memory location, which can be mutated at will.
2021

21-
So, in order to solve this error, either use statics which are `Sync`:
22+
So, in order to solve this error, use statics which are `Sync`:
2223

2324
```
2425
use std::sync::atomic::AtomicUsize;
@@ -30,6 +31,7 @@ static B: &'static AtomicUsize = &A; // ok!
3031
You can also have this error while using a cell type:
3132

3233
```compile_fail,E0492
34+
#![feature(const_refs_to_cell)]
3335
use std::cell::Cell;
3436
3537
const A: Cell<usize> = Cell::new(1);

compiler/rustc_feature/src/active.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,9 @@ declare_features! (
626626
/// Allows const generics to have default values (e.g. `struct Foo<const N: usize = 3>(...);`).
627627
(active, const_generics_defaults, "1.51.0", Some(44580), None),
628628

629+
/// Allows references to types with interior mutability within constants
630+
(active, const_refs_to_cell, "1.51.0", Some(80384), None),
631+
629632
// -------------------------------------------------------------------------
630633
// feature-group-end: actual feature gates
631634
// -------------------------------------------------------------------------

compiler/rustc_mir/src/transform/check_consts/ops.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,9 +208,29 @@ impl NonConstOp for LiveDrop {
208208
}
209209
}
210210

211+
#[derive(Debug)]
212+
pub struct CellBorrowBehindRef;
213+
impl NonConstOp for CellBorrowBehindRef {
214+
fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
215+
Status::Unstable(sym::const_refs_to_cell)
216+
}
217+
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
218+
feature_err(
219+
&ccx.tcx.sess.parse_sess,
220+
sym::const_refs_to_cell,
221+
span,
222+
"cannot borrow here, since the borrowed element may contain interior mutability",
223+
)
224+
}
225+
}
226+
211227
#[derive(Debug)]
212228
pub struct CellBorrow;
213229
impl NonConstOp for CellBorrow {
230+
fn importance(&self) -> DiagnosticImportance {
231+
// The problematic cases will already emit a `CellBorrowBehindRef`
232+
DiagnosticImportance::Secondary
233+
}
214234
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
215235
struct_span_err!(
216236
ccx.tcx.sess,

compiler/rustc_mir/src/transform/check_consts/validation.rs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorReported};
44
use rustc_hir::def_id::DefId;
55
use rustc_hir::{self as hir, HirId, LangItem};
6+
use rustc_index::bit_set::BitSet;
67
use rustc_infer::infer::TyCtxtInferExt;
78
use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
89
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
@@ -188,6 +189,9 @@ pub struct Validator<'mir, 'tcx> {
188189
/// The span of the current statement.
189190
span: Span,
190191

192+
/// A set that stores for each local whether it has a `StorageDead` for it somewhere.
193+
local_has_storage_dead: Option<BitSet<Local>>,
194+
191195
error_emitted: Option<ErrorReported>,
192196
secondary_errors: Vec<Diagnostic>,
193197
}
@@ -206,6 +210,7 @@ impl Validator<'mir, 'tcx> {
206210
span: ccx.body.span,
207211
ccx,
208212
qualifs: Default::default(),
213+
local_has_storage_dead: None,
209214
error_emitted: None,
210215
secondary_errors: Vec::new(),
211216
}
@@ -282,6 +287,27 @@ impl Validator<'mir, 'tcx> {
282287
}
283288
}
284289

290+
fn local_has_storage_dead(&mut self, local: Local) -> bool {
291+
let ccx = self.ccx;
292+
self.local_has_storage_dead
293+
.get_or_insert_with(|| {
294+
struct StorageDeads {
295+
locals: BitSet<Local>,
296+
}
297+
impl Visitor<'tcx> for StorageDeads {
298+
fn visit_statement(&mut self, stmt: &Statement<'tcx>, _: Location) {
299+
if let StatementKind::StorageDead(l) = stmt.kind {
300+
self.locals.insert(l);
301+
}
302+
}
303+
}
304+
let mut v = StorageDeads { locals: BitSet::new_empty(ccx.body.local_decls.len()) };
305+
v.visit_body(ccx.body);
306+
v.locals
307+
})
308+
.contains(local)
309+
}
310+
285311
pub fn qualifs_in_return_place(&mut self) -> ConstQualifs {
286312
self.qualifs.in_return_place(self.ccx, self.error_emitted)
287313
}
@@ -556,7 +582,13 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
556582
);
557583

558584
if borrowed_place_has_mut_interior {
559-
self.check_op(ops::CellBorrow);
585+
// Locals without StorageDead follow the "trailing expression" rule, meaning
586+
// they are essentially anonymous static items themselves.
587+
if self.local_has_storage_dead(place.local) {
588+
self.check_op(ops::CellBorrowBehindRef);
589+
} else {
590+
self.check_op(ops::CellBorrow);
591+
}
560592
}
561593
}
562594

compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,7 @@ symbols! {
381381
const_ptr,
382382
const_raw_ptr_deref,
383383
const_raw_ptr_to_usize_cast,
384+
const_refs_to_cell,
384385
const_slice_ptr,
385386
const_trait_bound_opt_out,
386387
const_trait_impl,
Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,39 @@
1-
error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
1+
error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability
22
--> $DIR/const-address-of-interior-mut.rs:5:39
33
|
44
LL | const A: () = { let x = Cell::new(2); &raw const x; };
55
| ^^^^^^^^^^^^
6+
|
7+
= note: see issue #80384 <https://github.com/rust-lang/rust/issues/80384> for more information
8+
= help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable
69

7-
error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
10+
error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability
811
--> $DIR/const-address-of-interior-mut.rs:7:40
912
|
1013
LL | static B: () = { let x = Cell::new(2); &raw const x; };
1114
| ^^^^^^^^^^^^
15+
|
16+
= note: see issue #80384 <https://github.com/rust-lang/rust/issues/80384> for more information
17+
= help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable
1218

13-
error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
19+
error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability
1420
--> $DIR/const-address-of-interior-mut.rs:9:44
1521
|
1622
LL | static mut C: () = { let x = Cell::new(2); &raw const x; };
1723
| ^^^^^^^^^^^^
24+
|
25+
= note: see issue #80384 <https://github.com/rust-lang/rust/issues/80384> for more information
26+
= help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable
1827

19-
error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
28+
error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability
2029
--> $DIR/const-address-of-interior-mut.rs:13:13
2130
|
2231
LL | let y = &raw const x;
2332
| ^^^^^^^^^^^^
33+
|
34+
= note: see issue #80384 <https://github.com/rust-lang/rust/issues/80384> for more information
35+
= help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable
2436

2537
error: aborting due to 4 previous errors
2638

27-
For more information about this error, try `rustc --explain E0492`.
39+
For more information about this error, try `rustc --explain E0658`.

src/test/ui/consts/const-multi-ref.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ const _: i32 = {
1313

1414
const _: std::cell::Cell<i32> = {
1515
let mut a = std::cell::Cell::new(5);
16-
let p = &a; //~ ERROR cannot borrow a constant which may contain interior mutability
16+
let p = &a; //~ ERROR borrowed element may contain interior mutability
1717

1818
let reborrow = {p};
1919
let pp = &reborrow;

src/test/ui/consts/const-multi-ref.stderr

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,16 @@ error[E0764]: mutable references are not allowed in constants
44
LL | let p = &mut a;
55
| ^^^^^^ `&mut` is only allowed in `const fn`
66

7-
error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
7+
error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability
88
--> $DIR/const-multi-ref.rs:16:13
99
|
1010
LL | let p = &a;
1111
| ^^
12+
|
13+
= note: see issue #80384 <https://github.com/rust-lang/rust/issues/80384> for more information
14+
= help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable
1215

1316
error: aborting due to 2 previous errors
1417

15-
Some errors have detailed explanations: E0492, E0764.
16-
For more information about an error, try `rustc --explain E0492`.
18+
Some errors have detailed explanations: E0658, E0764.
19+
For more information about an error, try `rustc --explain E0658`.

src/test/ui/consts/partial_qualif.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#![feature(const_refs_to_cell)]
2+
13
use std::cell::Cell;
24

35
const FOO: &(Cell<usize>, bool) = {

src/test/ui/consts/partial_qualif.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
2-
--> $DIR/partial_qualif.rs:6:5
2+
--> $DIR/partial_qualif.rs:8:5
33
|
44
LL | &{a}
55
| ^^^^

0 commit comments

Comments
 (0)