rustc_mir: focus const-checking logic on whether mutation is forbidden.

This commit is contained in:
Eduard-Mihai Burtescu 2018-05-16 14:15:29 +03:00
parent 4fec5ef81a
commit 22275f46b2

View file

@ -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 {