@@ -679,24 +679,31 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
679679 }
680680
681681 let ty = place. ty ( self . mir , self . tcx ) . to_ty ( self . tcx ) ;
682+
683+ // Default to forbidding the borrow and/or its promotion,
684+ // due to the potential for direct or interior mutability,
685+ // and only proceed by setting `forbidden_mut` to `false`.
686+ let mut forbidden_mut = true ;
687+
682688 if let BorrowKind :: Mut { .. } = kind {
683689 // In theory, any zero-sized value could be borrowed
684690 // mutably without consequences. However, only &mut []
685691 // is allowed right now, and only in functions.
686- let allow = if self . mode == Mode :: StaticMut {
692+ if self . mode == Mode :: StaticMut {
687693 // Inside a `static mut`, &mut [...] is also allowed.
688694 match ty. sty {
689- ty:: TyArray ( ..) | ty:: TySlice ( _) => true ,
690- _ => false
695+ ty:: TyArray ( ..) | ty:: TySlice ( _) => forbidden_mut = false ,
696+ _ => { }
691697 }
692698 } else if let ty:: TyArray ( _, len) = ty. sty {
693- len. unwrap_usize ( self . tcx ) == 0 &&
694- self . mode == Mode :: Fn
695- } else {
696- false
697- } ;
699+ // FIXME(eddyb) the `self.mode == Mode::Fn` condition
700+ // seems unnecessary, given that this is merely a ZST.
701+ if len. unwrap_usize ( self . tcx ) == 0 && self . mode == Mode :: Fn {
702+ forbidden_mut = false ;
703+ }
704+ }
698705
699- if !allow {
706+ if forbidden_mut {
700707 self . add ( Qualif :: NOT_CONST ) ;
701708 if self . mode != Mode :: Fn {
702709 let mut err = struct_span_err ! ( self . tcx. sess, self . span, E0017 ,
@@ -722,21 +729,26 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
722729 // it means that our "silent insertion of statics" could change
723730 // initializer values (very bad).
724731 if self . qualif . intersects ( Qualif :: MUTABLE_INTERIOR ) {
725- // Replace MUTABLE_INTERIOR with NOT_CONST to avoid
732+ // A reference of a MUTABLE_INTERIOR place is instead
733+ // NOT_CONST (see `if forbidden_mut` below), to avoid
726734 // duplicate errors (from reborrowing, for example).
727735 self . qualif = self . qualif - Qualif :: MUTABLE_INTERIOR ;
728- self . add ( Qualif :: NOT_CONST ) ;
729736 if self . mode != Mode :: Fn {
730737 span_err ! ( self . tcx. sess, self . span, E0492 ,
731738 "cannot borrow a constant which may contain \
732739 interior mutability, create a static instead") ;
733740 }
741+ } else {
742+ // We allow immutable borrows of frozen data.
743+ forbidden_mut = false ;
734744 }
735745 }
736746
737- // We might have a candidate for promotion.
738- let candidate = Candidate :: Ref ( location) ;
739- if self . can_promote ( ) {
747+ if forbidden_mut {
748+ self . add ( Qualif :: NOT_CONST ) ;
749+ } else if self . can_promote ( ) {
750+ // We might have a candidate for promotion.
751+ let candidate = Candidate :: Ref ( location) ;
740752 // We can only promote interior borrows of non-drop temps.
741753 let mut place = place;
742754 while let Place :: Projection ( ref proj) = * place {
0 commit comments