Skip to content

Commit 22275f4

Browse files
committed
rustc_mir: focus const-checking logic on whether mutation is forbidden.
1 parent 4fec5ef commit 22275f4

File tree

1 file changed

+26
-14
lines changed

1 file changed

+26
-14
lines changed

src/librustc_mir/transform/qualify_consts.rs

+26-14
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)