@@ -20,7 +20,7 @@ use std::mem;
2020use std:: ops:: Deref ;
2121
2222use super :: ops:: { self , NonConstOp , Status } ;
23- use super :: qualifs:: { self , HasMutInterior , NeedsDrop , NeedsNonConstDrop } ;
23+ use super :: qualifs:: { self , NeedsDrop , NeedsNonConstDrop } ;
2424use super :: resolver:: FlowSensitiveAnalysis ;
2525use super :: { ConstCx , Qualif } ;
2626use crate :: const_eval:: is_unstable_const_fn;
@@ -31,7 +31,6 @@ type QualifResults<'mir, 'tcx, Q> =
3131
3232#[ derive( Default ) ]
3333pub ( crate ) struct Qualifs < ' mir , ' tcx > {
34- has_mut_interior : Option < QualifResults < ' mir , ' tcx , HasMutInterior > > ,
3534 needs_drop : Option < QualifResults < ' mir , ' tcx , NeedsDrop > > ,
3635 needs_non_const_drop : Option < QualifResults < ' mir , ' tcx , NeedsNonConstDrop > > ,
3736}
@@ -97,36 +96,6 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
9796 needs_non_const_drop. get ( ) . contains ( local)
9897 }
9998
100- /// Returns `true` if `local` is `HasMutInterior` at the given `Location`.
101- ///
102- /// Only updates the cursor if absolutely necessary.
103- pub fn has_mut_interior (
104- & mut self ,
105- ccx : & ' mir ConstCx < ' mir , ' tcx > ,
106- local : Local ,
107- location : Location ,
108- ) -> bool {
109- let ty = ccx. body . local_decls [ local] . ty ;
110- // Peeking into opaque types causes cycles if the current function declares said opaque
111- // type. Thus we avoid short circuiting on the type and instead run the more expensive
112- // analysis that looks at the actual usage within this function
113- if !ty. has_opaque_types ( ) && !HasMutInterior :: in_any_value_of_ty ( ccx, ty) {
114- return false ;
115- }
116-
117- let has_mut_interior = self . has_mut_interior . get_or_insert_with ( || {
118- let ConstCx { tcx, body, .. } = * ccx;
119-
120- FlowSensitiveAnalysis :: new ( HasMutInterior , ccx)
121- . into_engine ( tcx, body)
122- . iterate_to_fixpoint ( )
123- . into_results_cursor ( body)
124- } ) ;
125-
126- has_mut_interior. seek_before_primary_effect ( location) ;
127- has_mut_interior. get ( ) . contains ( local)
128- }
129-
13099 fn in_return_place (
131100 & mut self ,
132101 ccx : & ' mir ConstCx < ' mir , ' tcx > ,
@@ -152,7 +121,6 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
152121 ConstQualifs {
153122 needs_drop : self . needs_drop ( ccx, RETURN_PLACE , return_loc) ,
154123 needs_non_const_drop : self . needs_non_const_drop ( ccx, RETURN_PLACE , return_loc) ,
155- has_mut_interior : self . has_mut_interior ( ccx, RETURN_PLACE , return_loc) ,
156124 tainted_by_errors,
157125 }
158126 }
@@ -373,6 +341,21 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
373341 }
374342 }
375343 }
344+
345+ fn has_interior_mut ( & self , ty : Ty < ' tcx > ) -> bool {
346+ match ty. kind ( ) {
347+ // Empty arrays have no interior mutability no matter their element type.
348+ ty:: Array ( _elem, count)
349+ if count
350+ . try_eval_target_usize ( self . tcx , self . param_env )
351+ . is_some_and ( |v| v == 0 ) =>
352+ {
353+ false
354+ }
355+ // Fallback to checking `Freeze`.
356+ _ => !ty. is_freeze ( self . tcx , self . param_env ) ,
357+ }
358+ }
376359}
377360
378361impl < ' tcx > Visitor < ' tcx > for Checker < ' _ , ' tcx > {
@@ -484,20 +467,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
484467
485468 Rvalue :: Ref ( _, BorrowKind :: Shared | BorrowKind :: Fake , place)
486469 | Rvalue :: AddressOf ( Mutability :: Not , place) => {
487- let borrowed_place_has_mut_interior = qualifs:: in_place :: < HasMutInterior , _ > (
488- self . ccx ,
489- & mut |local| self . qualifs . has_mut_interior ( self . ccx , local, location) ,
490- place. as_ref ( ) ,
491- ) ;
470+ // We don't do value-based reasoning here, since the rules for interior mutability
471+ // are not finalized yet and they seem likely to not be full value-based in the end.
472+ let borrowed_place_has_mut_interior =
473+ self . has_interior_mut ( place. ty ( self . body , self . tcx ) . ty ) ;
492474
493- // If the place is indirect, this is basically a reborrow. We have a reborrow
494- // special case above, but for raw pointers and pointers/references to `static` and
495- // when the `*` is not the first projection, `place_as_reborrow` does not recognize
496- // them as such, so we end up here. This should probably be considered a
497- // `TransientCellBorrow` (we consider the equivalent mutable case a
498- // `TransientMutBorrow`), but such reborrows got accidentally stabilized already and
499- // it is too much of a breaking change to take back.
500- if borrowed_place_has_mut_interior && !place. is_indirect ( ) {
475+ if borrowed_place_has_mut_interior {
501476 match self . const_kind ( ) {
502477 // In a const fn all borrows are transient or point to the places given via
503478 // references in the arguments (so we already checked them with
@@ -508,6 +483,11 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
508483 // to (interior) mutable memory.
509484 hir:: ConstContext :: ConstFn => self . check_op ( ops:: TransientCellBorrow ) ,
510485 _ => {
486+ // For indirect places, we are not creating a new permanent borrow, it's just as
487+ // transient as the already existing one. For reborrowing references this is handled
488+ // at the top of `visit_rvalue`, but for raw pointers we handle it here.
489+ // Pointers/references to `static mut` and cases where the `*` is not the first
490+ // projection also end up here.
511491 // Locals with StorageDead are definitely not part of the final constant value, and
512492 // it is thus inherently safe to permit such locals to have their
513493 // address taken as we can't end up with a reference to them in the
@@ -516,7 +496,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
516496 // `StorageDead` in every control flow path leading to a `return` terminator.
517497 // The good news is that interning will detect if any unexpected mutable
518498 // pointer slips through.
519- if self . local_has_storage_dead ( place. local ) {
499+ if place . is_indirect ( ) || self . local_has_storage_dead ( place. local ) {
520500 self . check_op ( ops:: TransientCellBorrow ) ;
521501 } else {
522502 self . check_op ( ops:: CellBorrow ) ;
0 commit comments