Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 36cde67

Browse files
authoredJun 27, 2025
Rollup merge of #140942 - RalfJung:const-ref-to-mut, r=oli-obk
const-eval: allow constants to refer to mutable/external memory, but reject such constants as patterns This fixes #140653 by accepting code such as this: ```rust static FOO: AtomicU32 = AtomicU32::new(0); const C: &'static AtomicU32 = &FOO; ``` This can be written entirely in safe code, so there can't really be anything wrong with it. We also accept the much more questionable following code, since it looks very similar to the interpreter: ```rust static mut FOO2: u32 = 0; const C2: &'static u32 = unsafe { &mut FOO2 }; ``` Using this without causing UB is at least very hard (the details are unclear since it is related to how the aliasing model deals with the staging of const-eval vs runtime code). If a constant like `C2` is used as a pattern, we emit an error: ``` error: constant BAD_PATTERN cannot be used as pattern --> $DIR/const_refs_to_static_fail.rs:30:9 | LL | BAD_PATTERN => {}, | ^^^^^^^^^^^ | = note: constants that reference mutable or external memory cannot be used as pattern ``` (If you somehow manage to build a pattern with constant `C`, you'd get the same error, but that should be impossible: we don't have a type that can be used in patterns and that has interior mutability.) The same treatment is afforded for shared references to `extern static`, for the same reason: the const evaluation is entirely fine with it, we just can't build a pattern for it -- and when using interior mutability, this can be totally sound. We do still not accept anything where there is an `&mut` in the final value of the const, as that should always require unsafe code and it's hard to imagine a sound use-case that would require this.
2 parents 0446a0d + bade3fd commit 36cde67

File tree

61 files changed

+448
-373
lines changed

Some content is hidden

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

61 files changed

+448
-373
lines changed
 

‎compiler/rustc_const_eval/messages.ftl

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -124,12 +124,13 @@ const_eval_incompatible_return_types =
124124
const_eval_incompatible_types =
125125
calling a function with argument of type {$callee_ty} passing data of type {$caller_ty}
126126
127-
const_eval_interior_mutable_ref_escaping =
128-
{const_eval_const_context}s cannot refer to interior mutable data
129-
.label = this borrow of an interior mutable value may end up in the final value
127+
const_eval_interior_mutable_borrow_escaping =
128+
interior mutable shared borrows of lifetime-extended temporaries in the top-level scope of a {const_eval_const_context} are not allowed
129+
.label = this borrow of an interior mutable value refers to a lifetime-extended temporary
130130
.help = to fix this, the value can be extracted to a separate `static` item and then referenced
131131
.teach_note =
132-
References that escape into the final value of a constant or static must be immutable.
132+
This creates a raw pointer to a temporary that has its lifetime extended to last for the entire program.
133+
Lifetime-extended temporaries in constants and statics must be immutable.
133134
This is to avoid accidentally creating shared mutable state.
134135
135136
@@ -207,33 +208,23 @@ const_eval_long_running =
207208
.label = the const evaluator is currently interpreting this expression
208209
.help = the constant being evaluated
209210
210-
const_eval_max_num_nodes_in_const = maximum number of nodes exceeded in constant {$global_const_id}
211-
212211
const_eval_memory_exhausted =
213212
tried to allocate more memory than available to compiler
214213
215214
const_eval_modified_global =
216215
modifying a static's initial value from another static's initializer
217216
218-
const_eval_mutable_ptr_in_final = encountered mutable pointer in final value of {const_eval_intern_kind}
219-
220-
const_eval_mutable_raw_escaping =
221-
raw mutable pointers are not allowed in the final value of {const_eval_const_context}s
217+
const_eval_mutable_borrow_escaping =
218+
mutable borrows of lifetime-extended temporaries in the top-level scope of a {const_eval_const_context} are not allowed
222219
.teach_note =
223-
Pointers that escape into the final value of a constant or static must be immutable.
220+
This creates a reference to a temporary that has its lifetime extended to last for the entire program.
221+
Lifetime-extended temporaries in constants and statics must be immutable.
224222
This is to avoid accidentally creating shared mutable state.
225223
226224
227225
If you really want global mutable state, try using an interior mutable `static` or a `static mut`.
228226
229-
const_eval_mutable_ref_escaping =
230-
mutable references are not allowed in the final value of {const_eval_const_context}s
231-
.teach_note =
232-
References that escape into the final value of a constant or static must be immutable.
233-
This is to avoid accidentally creating shared mutable state.
234-
235-
236-
If you really want global mutable state, try using an interior mutable `static` or a `static mut`.
227+
const_eval_mutable_ptr_in_final = encountered mutable pointer in final value of {const_eval_intern_kind}
237228
238229
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
239230
@@ -437,9 +428,6 @@ const_eval_unwind_past_top =
437428
## (We'd love to sort this differently to make that more clear but tidy won't let us...)
438429
const_eval_validation_box_to_uninhabited = {$front_matter}: encountered a box pointing to uninhabited type {$ty}
439430
440-
const_eval_validation_const_ref_to_extern = {$front_matter}: encountered reference to `extern` static in `const`
441-
const_eval_validation_const_ref_to_mutable = {$front_matter}: encountered reference to mutable memory in `const`
442-
443431
const_eval_validation_dangling_box_no_provenance = {$front_matter}: encountered a dangling box ({$pointer} has no provenance)
444432
const_eval_validation_dangling_box_out_of_bounds = {$front_matter}: encountered a dangling box (going beyond the bounds of its allocation)
445433
const_eval_validation_dangling_box_use_after_free = {$front_matter}: encountered a dangling box (use-after-free)
@@ -479,6 +467,7 @@ const_eval_validation_invalid_ref_meta = {$front_matter}: encountered invalid re
479467
const_eval_validation_invalid_ref_slice_meta = {$front_matter}: encountered invalid reference metadata: slice is bigger than largest supported object
480468
const_eval_validation_invalid_vtable_ptr = {$front_matter}: encountered {$value}, but expected a vtable pointer
481469
const_eval_validation_invalid_vtable_trait = {$front_matter}: wrong trait in wide pointer vtable: expected `{$expected_dyn_type}`, but encountered `{$vtable_dyn_type}`
470+
const_eval_validation_mutable_ref_in_const = {$front_matter}: encountered mutable reference in `const` value
482471
const_eval_validation_mutable_ref_to_immutable = {$front_matter}: encountered mutable reference or box pointing to read-only memory
483472
const_eval_validation_never_val = {$front_matter}: encountered a value of the never type `!`
484473
const_eval_validation_null_box = {$front_matter}: encountered a null box

‎compiler/rustc_const_eval/src/check_consts/check.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -595,11 +595,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
595595
self.const_kind() == hir::ConstContext::Static(hir::Mutability::Mut);
596596

597597
if !is_allowed && self.place_may_escape(place) {
598-
self.check_op(ops::EscapingMutBorrow(if matches!(rvalue, Rvalue::Ref(..)) {
599-
hir::BorrowKind::Ref
600-
} else {
601-
hir::BorrowKind::Raw
602-
}));
598+
self.check_op(ops::EscapingMutBorrow);
603599
}
604600
}
605601

0 commit comments

Comments
 (0)