@@ -445,22 +445,22 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
445445 // Determine whether this pointer expects to be pointing to something mutable.
446446 let ptr_expected_mutbl = match ptr_kind {
447447 PointerKind :: Box => Mutability :: Mut ,
448- PointerKind :: Ref => {
449- let tam = value. layout . ty . builtin_deref ( false ) . unwrap ( ) ;
450- // ZST never require mutability. We do not take into account interior mutability
451- // here since we cannot know if there really is an `UnsafeCell` inside
452- // `Option<UnsafeCell>` -- so we check that in the recursive descent behind this
453- // reference.
454- if size == Size :: ZERO { Mutability :: Not } else { tam. mutbl }
448+ PointerKind :: Ref ( mutbl) => {
449+ // We do not take into account interior mutability here since we cannot know if
450+ // there really is an `UnsafeCell` inside `Option<UnsafeCell>` -- so we check
451+ // that in the recursive descent behind this reference (controlled by
452+ // `allow_immutable_unsafe_cell`).
453+ mutbl
455454 }
456455 } ;
457456 // Proceed recursively even for ZST, no reason to skip them!
458457 // `!` is a ZST and we want to validate it.
459458 if let Ok ( ( alloc_id, _offset, _prov) ) = self . ecx . ptr_try_get_alloc_id ( place. ptr ( ) ) {
459+ let mut skip_recursive_check = false ;
460460 // Let's see what kind of memory this points to.
461461 // `unwrap` since dangling pointers have already been handled.
462462 let alloc_kind = self . ecx . tcx . try_get_global_alloc ( alloc_id) . unwrap ( ) ;
463- match alloc_kind {
463+ let alloc_actual_mutbl = match alloc_kind {
464464 GlobalAlloc :: Static ( did) => {
465465 // Special handling for pointers to statics (irrespective of their type).
466466 assert ! ( !self . ecx. tcx. is_thread_local_static( did) ) ;
@@ -474,12 +474,6 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
474474 . no_bound_vars ( )
475475 . expect ( "statics should not have generic parameters" )
476476 . is_freeze ( * self . ecx . tcx , ty:: ParamEnv :: reveal_all ( ) ) ;
477- // Mutability check.
478- if ptr_expected_mutbl == Mutability :: Mut {
479- if !is_mut {
480- throw_validation_failure ! ( self . path, MutableRefToImmutable ) ;
481- }
482- }
483477 // Mode-specific checks
484478 match self . ctfe_mode {
485479 Some (
@@ -494,42 +488,49 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
494488 // trigger cycle errors if we try to compute the value of the other static
495489 // and that static refers back to us (potentially through a promoted).
496490 // This could miss some UB, but that's fine.
497- return Ok ( ( ) ) ;
491+ skip_recursive_check = true ;
498492 }
499493 Some ( CtfeValidationMode :: Const { .. } ) => {
500- // For consts on the other hand we have to recursively check;
501- // pattern matching assumes a valid value. However we better make
502- // sure this is not mutable.
503- if is_mut {
504- throw_validation_failure ! ( self . path, ConstRefToMutable ) ;
505- }
506494 // We can't recursively validate `extern static`, so we better reject them.
507495 if self . ecx . tcx . is_foreign_item ( did) {
508496 throw_validation_failure ! ( self . path, ConstRefToExtern ) ;
509497 }
510498 }
511499 None => { }
512500 }
501+ // Return alloc mutability
502+ if is_mut { Mutability :: Mut } else { Mutability :: Not }
513503 }
514- GlobalAlloc :: Memory ( alloc) => {
515- if alloc. inner ( ) . mutability == Mutability :: Mut
516- && matches ! ( self . ctfe_mode, Some ( CtfeValidationMode :: Const { .. } ) )
517- {
518- throw_validation_failure ! ( self . path, ConstRefToMutable ) ;
519- }
520- if ptr_expected_mutbl == Mutability :: Mut
521- && alloc. inner ( ) . mutability == Mutability :: Not
522- {
523- throw_validation_failure ! ( self . path, MutableRefToImmutable ) ;
524- }
525- }
504+ GlobalAlloc :: Memory ( alloc) => alloc. inner ( ) . mutability ,
526505 GlobalAlloc :: Function ( ..) | GlobalAlloc :: VTable ( ..) => {
527506 // These are immutable, we better don't allow mutable pointers here.
528- if ptr_expected_mutbl == Mutability :: Mut {
529- throw_validation_failure ! ( self . path, MutableRefToImmutable ) ;
530- }
507+ Mutability :: Not
508+ }
509+ } ;
510+ // Mutability check.
511+ // If this allocation has size zero, there is no actual mutability here.
512+ let ( size, _align, _alloc_kind) = self . ecx . get_alloc_info ( alloc_id) ;
513+ if size != Size :: ZERO {
514+ if ptr_expected_mutbl == Mutability :: Mut
515+ && alloc_actual_mutbl == Mutability :: Not
516+ {
517+ throw_validation_failure ! ( self . path, MutableRefToImmutable ) ;
518+ }
519+ if ptr_expected_mutbl == Mutability :: Mut
520+ && self . ctfe_mode . is_some_and ( |c| !c. may_contain_mutable_ref ( ) )
521+ {
522+ throw_validation_failure ! ( self . path, MutableRefInConstOrStatic ) ;
523+ }
524+ if alloc_actual_mutbl == Mutability :: Mut
525+ && matches ! ( self . ctfe_mode, Some ( CtfeValidationMode :: Const { .. } ) )
526+ {
527+ throw_validation_failure ! ( self . path, ConstRefToMutable ) ;
531528 }
532529 }
530+ // Potentially skip recursive check.
531+ if skip_recursive_check {
532+ return Ok ( ( ) ) ;
533+ }
533534 }
534535 let path = & self . path ;
535536 ref_tracking. track ( place, || {
@@ -598,16 +599,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
598599 }
599600 Ok ( true )
600601 }
601- ty:: Ref ( _, ty, mutbl) => {
602- if self . ctfe_mode . is_some_and ( |c| !c. may_contain_mutable_ref ( ) )
603- && * mutbl == Mutability :: Mut
604- {
605- let layout = self . ecx . layout_of ( * ty) ?;
606- if !layout. is_zst ( ) {
607- throw_validation_failure ! ( self . path, MutableRefInConst ) ;
608- }
609- }
610- self . check_safe_pointer ( value, PointerKind :: Ref ) ?;
602+ ty:: Ref ( _, _ty, mutbl) => {
603+ self . check_safe_pointer ( value, PointerKind :: Ref ( * mutbl) ) ?;
611604 Ok ( true )
612605 }
613606 ty:: FnPtr ( _sig) => {
0 commit comments