]> git.lizzy.rs Git - rust.git/commitdiff
rustc_mir: focus const-checking logic on whether mutation is forbidden.
authorEduard-Mihai Burtescu <edy.burt@gmail.com>
Wed, 16 May 2018 11:15:29 +0000 (14:15 +0300)
committerEduard-Mihai Burtescu <edy.burt@gmail.com>
Wed, 16 May 2018 11:19:47 +0000 (14:19 +0300)
src/librustc_mir/transform/qualify_consts.rs

index 544f122f25ae33ef1a4d1f7c96f65f2efe82392c..6f90794ed896bc30e9f6e4c48ec56896dbf390ac 100644 (file)
@@ -679,24 +679,31 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
                 }
 
                 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 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
                     // 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 {