Skip to content

Commit

Permalink
rustc_mir: focus const-checking logic on whether mutation is forbidden.
Browse files Browse the repository at this point in the history
  • Loading branch information
eddyb committed May 16, 2018
1 parent 4fec5ef commit 22275f4
Showing 1 changed file with 26 additions and 14 deletions.
40 changes: 26 additions & 14 deletions src/librustc_mir/transform/qualify_consts.rs
Expand Up @@ -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,
Expand All @@ -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 {
Expand Down

0 comments on commit 22275f4

Please sign in to comment.