diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 544f122f25ae..6f90794ed896 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -679,24 +679,31 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } let ty = place.ty(self.mir, self.tcx).to_ty(self.tcx); + + // Default to forbidding the borrow and/or its promotion, + // due to the potential for direct or interior mutability, + // and only proceed by setting `forbidden_mut` to `false`. + let mut forbidden_mut = true; + if let BorrowKind::Mut { .. } = kind { // In theory, any zero-sized value could be borrowed // mutably without consequences. However, only &mut [] // is allowed right now, and only in functions. - let allow = if self.mode == Mode::StaticMut { + if self.mode == Mode::StaticMut { // Inside a `static mut`, &mut [...] is also allowed. match ty.sty { - ty::TyArray(..) | ty::TySlice(_) => true, - _ => false + ty::TyArray(..) | ty::TySlice(_) => forbidden_mut = false, + _ => {} } } else if let ty::TyArray(_, len) = ty.sty { - len.unwrap_usize(self.tcx) == 0 && - self.mode == Mode::Fn - } else { - false - }; + // FIXME(eddyb) the `self.mode == Mode::Fn` condition + // seems unnecessary, given that this is merely a ZST. + if len.unwrap_usize(self.tcx) == 0 && self.mode == Mode::Fn { + forbidden_mut = false; + } + } - if !allow { + if forbidden_mut { self.add(Qualif::NOT_CONST); if self.mode != Mode::Fn { 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> { // it means that our "silent insertion of statics" could change // initializer values (very bad). if self.qualif.intersects(Qualif::MUTABLE_INTERIOR) { - // Replace MUTABLE_INTERIOR with NOT_CONST to avoid + // A reference of a MUTABLE_INTERIOR place is instead + // NOT_CONST (see `if forbidden_mut` below), to avoid // duplicate errors (from reborrowing, for example). self.qualif = self.qualif - Qualif::MUTABLE_INTERIOR; - self.add(Qualif::NOT_CONST); if self.mode != Mode::Fn { span_err!(self.tcx.sess, self.span, E0492, "cannot borrow a constant which may contain \ interior mutability, create a static instead"); } + } else { + // We allow immutable borrows of frozen data. + forbidden_mut = false; } } - // We might have a candidate for promotion. - let candidate = Candidate::Ref(location); - if self.can_promote() { + if forbidden_mut { + self.add(Qualif::NOT_CONST); + } else if self.can_promote() { + // We might have a candidate for promotion. + let candidate = Candidate::Ref(location); // We can only promote interior borrows of non-drop temps. let mut place = place; while let Place::Projection(ref proj) = *place {