diff options
| author | Eduard-Mihai Burtescu <edy.burt@gmail.com> | 2018-05-16 14:15:29 +0300 |
|---|---|---|
| committer | Eduard-Mihai Burtescu <edy.burt@gmail.com> | 2018-05-16 14:19:47 +0300 |
| commit | 22275f46b2b6a9efe50c5a4485ed766fce3ac10a (patch) | |
| tree | a833374f789ba3249fd60ba1c2b5e20d213471f2 | |
| parent | 4fec5ef81a24481dbe6f9637e772c0cc6c53568e (diff) | |
| download | rust-22275f46b2b6a9efe50c5a4485ed766fce3ac10a.tar.gz rust-22275f46b2b6a9efe50c5a4485ed766fce3ac10a.zip | |
rustc_mir: focus const-checking logic on whether mutation is forbidden.
| -rw-r--r-- | src/librustc_mir/transform/qualify_consts.rs | 40 |
1 files changed, 26 insertions, 14 deletions
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 544f122f25a..6f90794ed89 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 { |
