Skip to content

Commit 3175cc2

Browse files
committed
stabilize const_mut_refs
1 parent 4f1be92 commit 3175cc2

File tree

152 files changed

+286
-1376
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

152 files changed

+286
-1376
lines changed

compiler/rustc_const_eval/messages.ftl

-7
Original file line numberDiff line numberDiff line change
@@ -230,9 +230,6 @@ const_eval_memory_exhausted =
230230
const_eval_modified_global =
231231
modifying a static's initial value from another static's initializer
232232
233-
const_eval_mut_deref =
234-
mutation through a reference is not allowed in {const_eval_const_context}s
235-
236233
const_eval_mutable_ptr_in_final = encountered mutable pointer in final value of {const_eval_intern_kind}
237234
238235
const_eval_nested_static_in_thread_local = #[thread_local] does not support implicit nested statics, please create explicit static items and refer to them instead
@@ -363,10 +360,6 @@ const_eval_too_generic =
363360
const_eval_too_many_caller_args =
364361
calling a function with more arguments than it expected
365362
366-
const_eval_transient_mut_borrow = mutable references are not allowed in {const_eval_const_context}s
367-
368-
const_eval_transient_mut_raw = raw mutable pointers are not allowed in {const_eval_const_context}s
369-
370363
const_eval_try_block_from_output_non_const =
371364
`try` block cannot convert `{$ty}` to the result in {const_eval_const_context}s
372365
const_eval_unallowed_fn_pointer_call = function pointer calls are not allowed in {const_eval_const_context}s

compiler/rustc_const_eval/src/check_consts/check.rs

+6-105
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ use rustc_mir_dataflow::Analysis;
2222
use rustc_span::{sym, Span, Symbol, DUMMY_SP};
2323
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
2424
use rustc_trait_selection::traits::{self, ObligationCauseCode, ObligationCtxt};
25-
use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitor};
2625
use tracing::{debug, instrument, trace};
2726

2827
use super::ops::{self, NonConstOp, Status};
@@ -166,24 +165,6 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
166165
}
167166
}
168167

169-
struct LocalReturnTyVisitor<'a, 'mir, 'tcx> {
170-
kind: LocalKind,
171-
checker: &'a mut Checker<'mir, 'tcx>,
172-
}
173-
174-
impl<'a, 'mir, 'tcx> TypeVisitor<TyCtxt<'tcx>> for LocalReturnTyVisitor<'a, 'mir, 'tcx> {
175-
fn visit_ty(&mut self, t: Ty<'tcx>) {
176-
match t.kind() {
177-
ty::FnPtr(..) => {}
178-
ty::Ref(_, _, hir::Mutability::Mut) => {
179-
self.checker.check_op(ops::mut_ref::MutRef(self.kind));
180-
t.super_visit_with(self)
181-
}
182-
_ => t.super_visit_with(self),
183-
}
184-
}
185-
}
186-
187168
pub struct Checker<'mir, 'tcx> {
188169
ccx: &'mir ConstCx<'mir, 'tcx>,
189170
qualifs: Qualifs<'mir, 'tcx>,
@@ -230,25 +211,6 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
230211
return;
231212
}
232213

233-
// The local type and predicate checks are not free and only relevant for `const fn`s.
234-
if self.const_kind() == hir::ConstContext::ConstFn {
235-
for (idx, local) in body.local_decls.iter_enumerated() {
236-
// Handle the return place below.
237-
if idx == RETURN_PLACE {
238-
continue;
239-
}
240-
241-
self.span = local.source_info.span;
242-
self.check_local_or_return_ty(local.ty, idx);
243-
}
244-
245-
// impl trait is gone in MIR, so check the return type of a const fn by its signature
246-
// instead of the type of the return place.
247-
self.span = body.local_decls[RETURN_PLACE].source_info.span;
248-
let return_ty = self.ccx.fn_sig().output();
249-
self.check_local_or_return_ty(return_ty.skip_binder(), RETURN_PLACE);
250-
}
251-
252214
if !tcx.has_attr(def_id, sym::rustc_do_not_const_check) {
253215
self.visit_body(body);
254216
}
@@ -358,24 +320,16 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
358320
self.check_op_spanned(ops::StaticAccess, span)
359321
}
360322

361-
fn check_local_or_return_ty(&mut self, ty: Ty<'tcx>, local: Local) {
362-
let kind = self.body.local_kind(local);
363-
364-
let mut visitor = LocalReturnTyVisitor { kind, checker: self };
365-
366-
visitor.visit_ty(ty);
367-
}
368-
369323
fn check_mut_borrow(&mut self, place: &Place<'_>, kind: hir::BorrowKind) {
370-
match self.const_kind() {
324+
let is_transient = match self.const_kind() {
371325
// In a const fn all borrows are transient or point to the places given via
372326
// references in the arguments (so we already checked them with
373327
// TransientMutBorrow/MutBorrow as appropriate).
374328
// The borrow checker guarantees that no new non-transient borrows are created.
375329
// NOTE: Once we have heap allocations during CTFE we need to figure out
376330
// how to prevent `const fn` to create long-lived allocations that point
377331
// to mutable memory.
378-
hir::ConstContext::ConstFn => self.check_op(ops::TransientMutBorrow(kind)),
332+
hir::ConstContext::ConstFn => true,
379333
_ => {
380334
// For indirect places, we are not creating a new permanent borrow, it's just as
381335
// transient as the already existing one. For reborrowing references this is handled
@@ -389,12 +343,11 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
389343
// `StorageDead` in every control flow path leading to a `return` terminator.
390344
// The good news is that interning will detect if any unexpected mutable
391345
// pointer slips through.
392-
if place.is_indirect() || self.local_is_transient(place.local) {
393-
self.check_op(ops::TransientMutBorrow(kind));
394-
} else {
395-
self.check_op(ops::MutBorrow(kind));
396-
}
346+
place.is_indirect() || self.local_is_transient(place.local)
397347
}
348+
};
349+
if !is_transient {
350+
self.check_op(ops::EscapingMutBorrow(kind));
398351
}
399352
}
400353
}
@@ -636,58 +589,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
636589
}
637590
}
638591
}
639-
fn visit_projection_elem(
640-
&mut self,
641-
place_ref: PlaceRef<'tcx>,
642-
elem: PlaceElem<'tcx>,
643-
context: PlaceContext,
644-
location: Location,
645-
) {
646-
trace!(
647-
"visit_projection_elem: place_ref={:?} elem={:?} \
648-
context={:?} location={:?}",
649-
place_ref, elem, context, location,
650-
);
651-
652-
self.super_projection_elem(place_ref, elem, context, location);
653-
654-
match elem {
655-
ProjectionElem::Deref => {
656-
let base_ty = place_ref.ty(self.body, self.tcx).ty;
657-
if base_ty.is_unsafe_ptr() {
658-
if place_ref.projection.is_empty() {
659-
let decl = &self.body.local_decls[place_ref.local];
660-
// If this is a static, then this is not really dereferencing a pointer,
661-
// just directly accessing a static. That is not subject to any feature
662-
// gates (except for the one about whether statics can even be used, but
663-
// that is checked already by `visit_operand`).
664-
if let LocalInfo::StaticRef { .. } = *decl.local_info() {
665-
return;
666-
}
667-
}
668-
669-
// `*const T` is stable, `*mut T` is not
670-
if !base_ty.is_mutable_ptr() {
671-
return;
672-
}
673-
674-
self.check_op(ops::RawMutPtrDeref);
675-
}
676-
677-
if context.is_mutating_use() {
678-
self.check_op(ops::MutDeref);
679-
}
680-
}
681-
682-
ProjectionElem::ConstantIndex { .. }
683-
| ProjectionElem::Downcast(..)
684-
| ProjectionElem::OpaqueCast(..)
685-
| ProjectionElem::Subslice { .. }
686-
| ProjectionElem::Subtype(..)
687-
| ProjectionElem::Field(..)
688-
| ProjectionElem::Index(_) => {}
689-
}
690-
}
691592

692593
fn visit_source_info(&mut self, source_info: &SourceInfo) {
693594
trace!("visit_source_info: source_info={:?}", source_info);

compiler/rustc_const_eval/src/check_consts/ops.rs

+3-94
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustc_hir as hir;
88
use rustc_hir::def_id::DefId;
99
use rustc_infer::infer::TyCtxtInferExt;
1010
use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
11-
use rustc_middle::mir::{self, CallSource};
11+
use rustc_middle::mir::CallSource;
1212
use rustc_middle::span_bug;
1313
use rustc_middle::ty::print::{with_no_trimmed_paths, PrintTraitRefExt as _};
1414
use rustc_middle::ty::{
@@ -431,9 +431,9 @@ impl<'tcx> NonConstOp<'tcx> for CellBorrow {
431431
/// This op is for `&mut` borrows in the trailing expression of a constant
432432
/// which uses the "enclosing scopes rule" to leak its locals into anonymous
433433
/// static or const items.
434-
pub(crate) struct MutBorrow(pub hir::BorrowKind);
434+
pub(crate) struct EscapingMutBorrow(pub hir::BorrowKind);
435435

436-
impl<'tcx> NonConstOp<'tcx> for MutBorrow {
436+
impl<'tcx> NonConstOp<'tcx> for EscapingMutBorrow {
437437
fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
438438
Status::Forbidden
439439
}
@@ -460,49 +460,6 @@ impl<'tcx> NonConstOp<'tcx> for MutBorrow {
460460
}
461461
}
462462

463-
#[derive(Debug)]
464-
pub(crate) struct TransientMutBorrow(pub hir::BorrowKind);
465-
466-
impl<'tcx> NonConstOp<'tcx> for TransientMutBorrow {
467-
fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
468-
Status::Unstable(sym::const_mut_refs)
469-
}
470-
471-
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
472-
let kind = ccx.const_kind();
473-
match self.0 {
474-
hir::BorrowKind::Raw => ccx
475-
.tcx
476-
.sess
477-
.create_feature_err(errors::TransientMutRawErr { span, kind }, sym::const_mut_refs),
478-
hir::BorrowKind::Ref => ccx.tcx.sess.create_feature_err(
479-
errors::TransientMutBorrowErr { span, kind },
480-
sym::const_mut_refs,
481-
),
482-
}
483-
}
484-
}
485-
486-
#[derive(Debug)]
487-
pub(crate) struct MutDeref;
488-
impl<'tcx> NonConstOp<'tcx> for MutDeref {
489-
fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
490-
Status::Unstable(sym::const_mut_refs)
491-
}
492-
493-
fn importance(&self) -> DiagImportance {
494-
// Usually a side-effect of a `TransientMutBorrow` somewhere.
495-
DiagImportance::Secondary
496-
}
497-
498-
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
499-
ccx.tcx.sess.create_feature_err(
500-
errors::MutDerefErr { span, kind: ccx.const_kind() },
501-
sym::const_mut_refs,
502-
)
503-
}
504-
}
505-
506463
/// A call to a `panic()` lang item where the first argument is _not_ a `&str`.
507464
#[derive(Debug)]
508465
pub(crate) struct PanicNonStr;
@@ -524,24 +481,6 @@ impl<'tcx> NonConstOp<'tcx> for RawPtrComparison {
524481
}
525482
}
526483

527-
#[derive(Debug)]
528-
pub(crate) struct RawMutPtrDeref;
529-
impl<'tcx> NonConstOp<'tcx> for RawMutPtrDeref {
530-
fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
531-
Status::Unstable(sym::const_mut_refs)
532-
}
533-
534-
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
535-
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
536-
feature_err(
537-
&ccx.tcx.sess,
538-
sym::const_mut_refs,
539-
span,
540-
format!("dereferencing raw mutable pointers in {}s is unstable", ccx.const_kind(),),
541-
)
542-
}
543-
}
544-
545484
/// Casting raw pointer or function pointer to an integer.
546485
/// Not currently intended to ever be allowed, even behind a feature gate: operation depends on
547486
/// allocation base addresses that are not known at compile-time.
@@ -588,33 +527,3 @@ impl<'tcx> NonConstOp<'tcx> for ThreadLocalAccess {
588527
ccx.dcx().create_err(errors::ThreadLocalAccessErr { span })
589528
}
590529
}
591-
592-
/// Types that cannot appear in the signature or locals of a `const fn`.
593-
pub(crate) mod mut_ref {
594-
use super::*;
595-
596-
#[derive(Debug)]
597-
pub(crate) struct MutRef(pub mir::LocalKind);
598-
impl<'tcx> NonConstOp<'tcx> for MutRef {
599-
fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
600-
Status::Unstable(sym::const_mut_refs)
601-
}
602-
603-
fn importance(&self) -> DiagImportance {
604-
match self.0 {
605-
mir::LocalKind::Temp => DiagImportance::Secondary,
606-
mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => DiagImportance::Primary,
607-
}
608-
}
609-
610-
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
611-
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
612-
feature_err(
613-
&ccx.tcx.sess,
614-
sym::const_mut_refs,
615-
span,
616-
format!("mutable references are not allowed in {}s", ccx.const_kind()),
617-
)
618-
}
619-
}
620-
}

compiler/rustc_const_eval/src/errors.rs

-24
Original file line numberDiff line numberDiff line change
@@ -93,30 +93,6 @@ pub(crate) struct PanicNonStrErr {
9393
pub span: Span,
9494
}
9595

96-
#[derive(Diagnostic)]
97-
#[diag(const_eval_mut_deref, code = E0658)]
98-
pub(crate) struct MutDerefErr {
99-
#[primary_span]
100-
pub span: Span,
101-
pub kind: ConstContext,
102-
}
103-
104-
#[derive(Diagnostic)]
105-
#[diag(const_eval_transient_mut_borrow, code = E0658)]
106-
pub(crate) struct TransientMutBorrowErr {
107-
#[primary_span]
108-
pub span: Span,
109-
pub kind: ConstContext,
110-
}
111-
112-
#[derive(Diagnostic)]
113-
#[diag(const_eval_transient_mut_raw, code = E0658)]
114-
pub(crate) struct TransientMutRawErr {
115-
#[primary_span]
116-
pub span: Span,
117-
pub kind: ConstContext,
118-
}
119-
12096
#[derive(Diagnostic)]
12197
#[diag(const_eval_max_num_nodes_in_const)]
12298
pub(crate) struct MaxNumNodesInConstErr {

compiler/rustc_error_codes/src/error_codes/E0764.md

-4
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ A mutable reference was used in a constant.
33
Erroneous code example:
44

55
```compile_fail,E0764
6-
#![feature(const_mut_refs)]
7-
86
fn main() {
97
const OH_NO: &'static mut usize = &mut 1; // error!
108
}
@@ -26,8 +24,6 @@ Remember: you cannot use a function call inside a constant or static. However,
2624
you can totally use it in constant functions:
2725

2826
```
29-
#![feature(const_mut_refs)]
30-
3127
const fn foo(x: usize) -> usize {
3228
let mut y = 1;
3329
let z = &mut y;

compiler/rustc_feature/src/accepted.rs

+2
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ declare_features! (
143143
(accepted, const_let, "1.33.0", Some(48821)),
144144
/// Allows the use of `loop` and `while` in constants.
145145
(accepted, const_loop, "1.46.0", Some(52000)),
146+
/// Allows using `&mut` in constant functions.
147+
(accepted, const_mut_refs, "CURRENT_RUSTC_VERSION", Some(57349)),
146148
/// Allows panicking during const eval (producing compile-time errors).
147149
(accepted, const_panic, "1.57.0", Some(51999)),
148150
/// Allows dereferencing raw pointers during const eval.

compiler/rustc_feature/src/unstable.rs

-2
Original file line numberDiff line numberDiff line change
@@ -403,8 +403,6 @@ declare_features! (
403403
(incomplete, const_closures, "1.68.0", Some(106003)),
404404
/// Allows `for _ in _` loops in const contexts.
405405
(unstable, const_for, "1.56.0", Some(87575)),
406-
/// Allows using `&mut` in constant functions.
407-
(unstable, const_mut_refs, "1.41.0", Some(57349)),
408406
/// Be more precise when looking for live drops in a const context.
409407
(unstable, const_precise_live_drops, "1.46.0", Some(73255)),
410408
/// Allows references to types with interior mutability within constants

library/alloc/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -164,13 +164,13 @@
164164
//
165165
// Language features:
166166
// tidy-alphabetical-start
167+
#![cfg_attr(bootstrap, feature(const_mut_refs))]
167168
#![cfg_attr(not(test), feature(coroutine_trait))]
168169
#![cfg_attr(test, feature(panic_update_hook))]
169170
#![cfg_attr(test, feature(test))]
170171
#![feature(allocator_internals)]
171172
#![feature(allow_internal_unstable)]
172173
#![feature(cfg_sanitize)]
173-
#![feature(const_mut_refs)]
174174
#![feature(const_precise_live_drops)]
175175
#![feature(const_ptr_write)]
176176
#![feature(const_try)]

0 commit comments

Comments
 (0)