rustc_mir: focus const-checking logic on whether mutation is forbidden.
This commit is contained in:
parent
4fec5ef81a
commit
22275f46b2
1 changed files with 26 additions and 14 deletions
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue