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

Commit 49316f8

Browse files
committed
also stabilize const_refs_to_cell
1 parent 544a6a7 commit 49316f8

38 files changed

+130
-324
lines changed

compiler/rustc_const_eval/messages.ftl

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,6 @@ const_eval_incompatible_return_types =
134134
const_eval_incompatible_types =
135135
calling a function with argument of type {$callee_ty} passing data of type {$caller_ty}
136136
137-
const_eval_interior_mutability_borrow =
138-
cannot borrow here, since the borrowed element may contain interior mutability
139-
140137
const_eval_interior_mutable_data_refer =
141138
{const_eval_const_context}s cannot refer to interior mutable data
142139
.label = this borrow of an interior mutable value may end up in the final value

compiler/rustc_const_eval/src/check_consts/check.rs

Lines changed: 19 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,10 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
320320
self.check_op_spanned(ops::StaticAccess, span)
321321
}
322322

323-
fn check_mut_borrow(&mut self, place: &Place<'_>, kind: hir::BorrowKind) {
323+
/// Returns whether this place can possibly escape the evaluation of the current const/static
324+
/// initializer. The check assumes that all already existing pointers and references point to
325+
/// non-escaping places.
326+
fn place_may_escape(&mut self, place: &Place<'_>) -> bool {
324327
let is_transient = match self.const_kind() {
325328
// In a const fn all borrows are transient or point to the places given via
326329
// references in the arguments (so we already checked them with
@@ -341,14 +344,16 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
341344
// value of the constant.
342345
// Note: This is only sound if every local that has a `StorageDead` has a
343346
// `StorageDead` in every control flow path leading to a `return` terminator.
344-
// The good news is that interning will detect if any unexpected mutable
345-
// pointer slips through.
347+
// If anything slips through, there's no safety net -- safe code can create
348+
// references to variants of `!Freeze` enums as long as that variant is `Freeze`, so
349+
// interning can't protect us here. (There *is* a safety net for mutable references
350+
// though, interning will ICE if we miss something here.)
346351
place.is_indirect() || self.local_is_transient(place.local)
347352
}
348353
};
349-
if !is_transient {
350-
self.check_op(ops::EscapingMutBorrow(kind));
351-
}
354+
// Transient places cannot possibly escape because the place doesn't exist any more at the
355+
// end of evaluation.
356+
!is_transient
352357
}
353358
}
354359

@@ -406,15 +411,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
406411
let is_allowed =
407412
self.const_kind() == hir::ConstContext::Static(hir::Mutability::Mut);
408413

409-
if !is_allowed {
410-
self.check_mut_borrow(
411-
place,
412-
if matches!(rvalue, Rvalue::Ref(..)) {
413-
hir::BorrowKind::Ref
414-
} else {
415-
hir::BorrowKind::Raw
416-
},
417-
);
414+
if !is_allowed && self.place_may_escape(place) {
415+
self.check_op(ops::EscapingMutBorrow(if matches!(rvalue, Rvalue::Ref(..)) {
416+
hir::BorrowKind::Ref
417+
} else {
418+
hir::BorrowKind::Raw
419+
}));
418420
}
419421
}
420422

@@ -426,51 +428,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
426428
place.as_ref(),
427429
);
428430

429-
// If the place is indirect, this is basically a reborrow. We have a reborrow
430-
// special case above, but for raw pointers and pointers/references to `static` and
431-
// when the `*` is not the first projection, `place_as_reborrow` does not recognize
432-
// them as such, so we end up here. This should probably be considered a
433-
// `TransientCellBorrow` (we consider the equivalent mutable case a
434-
// `TransientMutBorrow`), but such reborrows got accidentally stabilized already and
435-
// it is too much of a breaking change to take back.
436-
// However, we only want to consider places that are obtained by dereferencing
437-
// a *shared* reference. Mutable references to interior mutable data are stable,
438-
// and we don't want `&*&mut interior_mut` to be accepted.
439-
let is_indirect = place.iter_projections().any(|(base, proj)| {
440-
matches!(proj, ProjectionElem::Deref)
441-
&& matches!(
442-
base.ty(self.body, self.tcx).ty.kind(),
443-
ty::Ref(_, _, Mutability::Not) | ty::RawPtr(_, Mutability::Not)
444-
)
445-
});
446-
447-
if borrowed_place_has_mut_interior && !is_indirect {
448-
match self.const_kind() {
449-
// In a const fn all borrows are transient or point to the places given via
450-
// references in the arguments (so we already checked them with
451-
// TransientCellBorrow/CellBorrow as appropriate).
452-
// The borrow checker guarantees that no new non-transient borrows are created.
453-
// NOTE: Once we have heap allocations during CTFE we need to figure out
454-
// how to prevent `const fn` to create long-lived allocations that point
455-
// to (interior) mutable memory.
456-
hir::ConstContext::ConstFn => self.check_op(ops::TransientCellBorrow),
457-
_ => {
458-
// Locals with StorageDead are definitely not part of the final constant value, and
459-
// it is thus inherently safe to permit such locals to have their
460-
// address taken as we can't end up with a reference to them in the
461-
// final value.
462-
// Note: This is only sound if every local that has a `StorageDead` has a
463-
// `StorageDead` in every control flow path leading to a `return` terminator.
464-
// If anything slips through, there's no safety net -- safe code can create
465-
// references to variants of `!Freeze` enums as long as that variant is `Freeze`,
466-
// so interning can't protect us here.
467-
if self.local_is_transient(place.local) {
468-
self.check_op(ops::TransientCellBorrow);
469-
} else {
470-
self.check_op(ops::CellBorrow);
471-
}
472-
}
473-
}
431+
if borrowed_place_has_mut_interior && self.place_may_escape(place) {
432+
self.check_op(ops::EscapingCellBorrow);
474433
}
475434
}
476435

compiler/rustc_const_eval/src/check_consts/ops.rs

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -391,27 +391,12 @@ impl<'tcx> NonConstOp<'tcx> for LiveDrop<'tcx> {
391391
}
392392
}
393393

394-
#[derive(Debug)]
395-
/// A borrow of a type that contains an `UnsafeCell` somewhere. The borrow never escapes to
396-
/// the final value of the constant.
397-
pub(crate) struct TransientCellBorrow;
398-
impl<'tcx> NonConstOp<'tcx> for TransientCellBorrow {
399-
fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
400-
Status::Unstable(sym::const_refs_to_cell)
401-
}
402-
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
403-
ccx.tcx
404-
.sess
405-
.create_feature_err(errors::InteriorMutabilityBorrow { span }, sym::const_refs_to_cell)
406-
}
407-
}
408-
409394
#[derive(Debug)]
410395
/// A borrow of a type that contains an `UnsafeCell` somewhere. The borrow might escape to
411396
/// the final value of the constant, and thus we cannot allow this (for now). We may allow
412397
/// it in the future for static items.
413-
pub(crate) struct CellBorrow;
414-
impl<'tcx> NonConstOp<'tcx> for CellBorrow {
398+
pub(crate) struct EscapingCellBorrow;
399+
impl<'tcx> NonConstOp<'tcx> for EscapingCellBorrow {
415400
fn importance(&self) -> DiagImportance {
416401
// Most likely the code will try to do mutation with these borrows, which
417402
// triggers its own errors. Only show this one if that does not happen.

compiler/rustc_const_eval/src/errors.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -193,13 +193,6 @@ pub(crate) struct InteriorMutableDataRefer {
193193
pub teach: bool,
194194
}
195195

196-
#[derive(Diagnostic)]
197-
#[diag(const_eval_interior_mutability_borrow)]
198-
pub(crate) struct InteriorMutabilityBorrow {
199-
#[primary_span]
200-
pub span: Span,
201-
}
202-
203196
#[derive(LintDiagnostic)]
204197
#[diag(const_eval_long_running)]
205198
#[note]

compiler/rustc_feature/src/accepted.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,8 @@ declare_features! (
149149
(accepted, const_panic, "1.57.0", Some(51999)),
150150
/// Allows dereferencing raw pointers during const eval.
151151
(accepted, const_raw_ptr_deref, "1.58.0", Some(51911)),
152+
/// Allows references to types with interior mutability within constants
153+
(accepted, const_refs_to_cell, "CURRENT_RUSTC_VERSION", Some(80384)),
152154
/// Allows implementing `Copy` for closures where possible (RFC 2132).
153155
(accepted, copy_closures, "1.26.0", Some(44490)),
154156
/// Allows `crate` in paths.

compiler/rustc_feature/src/unstable.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -405,8 +405,6 @@ declare_features! (
405405
(unstable, const_for, "1.56.0", Some(87575)),
406406
/// Be more precise when looking for live drops in a const context.
407407
(unstable, const_precise_live_drops, "1.46.0", Some(73255)),
408-
/// Allows references to types with interior mutability within constants
409-
(unstable, const_refs_to_cell, "1.51.0", Some(80384)),
410408
/// Allows creating pointers and references to `static` items in constants.
411409
(unstable, const_refs_to_static, "1.78.0", Some(119618)),
412410
/// Allows `impl const Trait for T` syntax.

library/alloc/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,6 @@
114114
#![feature(const_maybe_uninit_write)]
115115
#![feature(const_option)]
116116
#![feature(const_pin)]
117-
#![feature(const_refs_to_cell)]
118117
#![feature(const_size_of_val)]
119118
#![feature(core_intrinsics)]
120119
#![feature(deprecated_suggestion)]
@@ -165,6 +164,7 @@
165164
// Language features:
166165
// tidy-alphabetical-start
167166
#![cfg_attr(bootstrap, feature(const_mut_refs))]
167+
#![cfg_attr(bootstrap, feature(const_refs_to_cell))]
168168
#![cfg_attr(not(test), feature(coroutine_trait))]
169169
#![cfg_attr(test, feature(panic_update_hook))]
170170
#![cfg_attr(test, feature(test))]

library/core/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@
192192
// Language features:
193193
// tidy-alphabetical-start
194194
#![cfg_attr(bootstrap, feature(const_mut_refs))]
195+
#![cfg_attr(bootstrap, feature(const_refs_to_cell))]
195196
#![feature(abi_unadjusted)]
196197
#![feature(adt_const_params)]
197198
#![feature(allow_internal_unsafe)]
@@ -203,7 +204,6 @@
203204
#![feature(cfg_ub_checks)]
204205
#![feature(const_for)]
205206
#![feature(const_precise_live_drops)]
206-
#![feature(const_refs_to_cell)]
207207
#![feature(decl_macro)]
208208
#![feature(deprecated_suggestion)]
209209
#![feature(doc_cfg)]

library/core/src/slice/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -846,7 +846,7 @@ impl<T> [T] {
846846
/// [`as_mut_ptr`]: slice::as_mut_ptr
847847
#[stable(feature = "slice_ptr_range", since = "1.48.0")]
848848
#[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
849-
#[rustc_allow_const_fn_unstable(const_mut_refs, const_refs_to_cell)]
849+
#[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs, const_refs_to_cell))]
850850
#[inline]
851851
#[must_use]
852852
pub const fn as_mut_ptr_range(&mut self) -> Range<*mut T> {
Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1+
//@check-pass
12
use std::cell::Cell;
23

3-
const A: () = { let x = Cell::new(2); &raw const x; }; //~ ERROR interior mutability
4+
const A: () = { let x = Cell::new(2); &raw const x; };
45

5-
static B: () = { let x = Cell::new(2); &raw const x; }; //~ ERROR interior mutability
6+
static B: () = { let x = Cell::new(2); &raw const x; };
67

7-
static mut C: () = { let x = Cell::new(2); &raw const x; }; //~ ERROR interior mutability
8+
static mut C: () = { let x = Cell::new(2); &raw const x; };
89

910
const fn foo() {
1011
let x = Cell::new(0);
11-
let y = &raw const x; //~ ERROR interior mutability
12+
let y = &raw const x;
1213
}
1314

1415
fn main() {}

0 commit comments

Comments
 (0)