@@ -679,24 +679,31 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
679
679
}
680
680
681
681
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
+
682
688
if let BorrowKind :: Mut { .. } = kind {
683
689
// In theory, any zero-sized value could be borrowed
684
690
// mutably without consequences. However, only &mut []
685
691
// is allowed right now, and only in functions.
686
- let allow = if self . mode == Mode :: StaticMut {
692
+ if self . mode == Mode :: StaticMut {
687
693
// Inside a `static mut`, &mut [...] is also allowed.
688
694
match ty. sty {
689
- ty:: TyArray ( ..) | ty:: TySlice ( _) => true ,
690
- _ => false
695
+ ty:: TyArray ( ..) | ty:: TySlice ( _) => forbidden_mut = false ,
696
+ _ => { }
691
697
}
692
698
} 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
+ }
698
705
699
- if !allow {
706
+ if forbidden_mut {
700
707
self . add ( Qualif :: NOT_CONST ) ;
701
708
if self . mode != Mode :: Fn {
702
709
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> {
722
729
// it means that our "silent insertion of statics" could change
723
730
// initializer values (very bad).
724
731
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
726
734
// duplicate errors (from reborrowing, for example).
727
735
self . qualif = self . qualif - Qualif :: MUTABLE_INTERIOR ;
728
- self . add ( Qualif :: NOT_CONST ) ;
729
736
if self . mode != Mode :: Fn {
730
737
span_err ! ( self . tcx. sess, self . span, E0492 ,
731
738
"cannot borrow a constant which may contain \
732
739
interior mutability, create a static instead") ;
733
740
}
741
+ } else {
742
+ // We allow immutable borrows of frozen data.
743
+ forbidden_mut = false ;
734
744
}
735
745
}
736
746
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) ;
740
752
// We can only promote interior borrows of non-drop temps.
741
753
let mut place = place;
742
754
while let Place :: Projection ( ref proj) = * place {
0 commit comments