about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-10-02 18:24:38 +0200
committerGitHub <noreply@github.com>2019-10-02 18:24:38 +0200
commitccf1d9ca93e3a1f757efa42929d59080c8d7efac (patch)
tree109af38b77e51277e6fa0ab1199d18f80f6dc142 /src
parent475f5d4a5cf64af6a713b09907d2ffabb49b7fbe (diff)
parent4eeedd0953a86258c3b3379e0905ab9569eb3af6 (diff)
downloadrust-ccf1d9ca93e3a1f757efa42929d59080c8d7efac.tar.gz
rust-ccf1d9ca93e3a1f757efa42929d59080c8d7efac.zip
Rollup merge of #64967 - ecstatic-morse:issue-64945, r=oli-obk
Don't mark borrows of zero-sized arrays as indirectly mutable

Resolves #64945

r? @oli-obk
Diffstat (limited to 'src')
-rw-r--r--src/librustc_mir/dataflow/impls/indirect_mutation.rs46
-rw-r--r--src/librustc_mir/transform/check_consts/validation.rs2
-rw-r--r--src/test/ui/consts/const-eval/generic-slice.rs31
-rw-r--r--src/test/ui/consts/const-eval/generic-slice.stderr30
4 files changed, 93 insertions, 16 deletions
diff --git a/src/librustc_mir/dataflow/impls/indirect_mutation.rs b/src/librustc_mir/dataflow/impls/indirect_mutation.rs
index 535b803b85f..990425c3252 100644
--- a/src/librustc_mir/dataflow/impls/indirect_mutation.rs
+++ b/src/librustc_mir/dataflow/impls/indirect_mutation.rs
@@ -97,6 +97,36 @@ struct TransferFunction<'a, 'mir, 'tcx> {
     param_env: ty::ParamEnv<'tcx>,
 }
 
+impl<'tcx> TransferFunction<'_, '_, 'tcx> {
+    /// Returns `true` if this borrow would allow mutation of the `borrowed_place`.
+    fn borrow_allows_mutation(
+        &self,
+        kind: mir::BorrowKind,
+        borrowed_place: &mir::Place<'tcx>,
+    ) -> bool {
+        let borrowed_ty = borrowed_place.ty(self.body, self.tcx).ty;
+
+        // Zero-sized types cannot be mutated, since there is nothing inside to mutate.
+        //
+        // FIXME: For now, we only exempt arrays of length zero. We need to carefully
+        // consider the effects before extending this to all ZSTs.
+        if let ty::Array(_, len) = borrowed_ty.kind {
+            if len.try_eval_usize(self.tcx, self.param_env) == Some(0) {
+                return false;
+            }
+        }
+
+        match kind {
+            mir::BorrowKind::Mut { .. } => true,
+
+            | mir::BorrowKind::Shared
+            | mir::BorrowKind::Shallow
+            | mir::BorrowKind::Unique
+            => !borrowed_ty.is_freeze(self.tcx, self.param_env, DUMMY_SP),
+        }
+    }
+}
+
 impl<'tcx> Visitor<'tcx> for TransferFunction<'_, '_, 'tcx> {
     fn visit_rvalue(
         &mut self,
@@ -104,21 +134,7 @@ impl<'tcx> Visitor<'tcx> for TransferFunction<'_, '_, 'tcx> {
         location: Location,
     ) {
         if let mir::Rvalue::Ref(_, kind, ref borrowed_place) = *rvalue {
-            let is_mut = match kind {
-                mir::BorrowKind::Mut { .. } => true,
-
-                | mir::BorrowKind::Shared
-                | mir::BorrowKind::Shallow
-                | mir::BorrowKind::Unique
-                => {
-                    !borrowed_place
-                        .ty(self.body, self.tcx)
-                        .ty
-                        .is_freeze(self.tcx, self.param_env, DUMMY_SP)
-                }
-            };
-
-            if is_mut {
+            if self.borrow_allows_mutation(kind, borrowed_place) {
                 match borrowed_place.base {
                     mir::PlaceBase::Local(borrowed_local) if !borrowed_place.is_indirect()
                         => self.trans.gen(borrowed_local),
diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs
index 3045239d7a7..2d7b215b13c 100644
--- a/src/librustc_mir/transform/check_consts/validation.rs
+++ b/src/librustc_mir/transform/check_consts/validation.rs
@@ -137,7 +137,7 @@ pub fn compute_indirectly_mutable_locals<'mir, 'tcx>(
         item.tcx,
         item.body,
         item.def_id,
-        &[],
+        &item.tcx.get_attrs(item.def_id),
         &dead_unwinds,
         old_dataflow::IndirectlyMutableLocals::new(item.tcx, item.body, item.param_env),
         |_, local| old_dataflow::DebugFormatted::new(&local),
diff --git a/src/test/ui/consts/const-eval/generic-slice.rs b/src/test/ui/consts/const-eval/generic-slice.rs
new file mode 100644
index 00000000000..21360a1c471
--- /dev/null
+++ b/src/test/ui/consts/const-eval/generic-slice.rs
@@ -0,0 +1,31 @@
+// Several variants of #64945.
+
+// This struct is not important, we just use it to put `T` and `'a` in scope for our associated
+// consts.
+struct Generic<'a, T>(std::marker::PhantomData<&'a T>);
+
+impl<'a, T: 'static> Generic<'a, T> {
+    const EMPTY_SLICE: &'a [T] = {
+        let x: &'a [T] = &[];
+        x
+    };
+
+    const EMPTY_SLICE_REF: &'a &'static [T] = {
+        let x: &'static [T] = &[];
+        &x
+        //~^ ERROR `x` does not live long enough
+    };
+}
+
+static mut INTERIOR_MUT_AND_DROP: &'static [std::cell::RefCell<Vec<i32>>] = {
+    let x: &[_] = &[];
+    x
+};
+
+static mut INTERIOR_MUT_AND_DROP_REF: &'static &'static [std::cell::RefCell<Vec<i32>>] = {
+    let x: &[_] = &[];
+    &x
+    //~^ ERROR `x` does not live long enough
+};
+
+fn main() {}
diff --git a/src/test/ui/consts/const-eval/generic-slice.stderr b/src/test/ui/consts/const-eval/generic-slice.stderr
new file mode 100644
index 00000000000..c38088df4d8
--- /dev/null
+++ b/src/test/ui/consts/const-eval/generic-slice.stderr
@@ -0,0 +1,30 @@
+error[E0597]: `x` does not live long enough
+  --> $DIR/generic-slice.rs:15:9
+   |
+LL | impl<'a, T: 'static> Generic<'a, T> {
+   |      -- lifetime `'a` defined here
+...
+LL |         &x
+   |         ^^
+   |         |
+   |         borrowed value does not live long enough
+   |         using this value as a constant requires that `x` is borrowed for `'a`
+LL |
+LL |     };
+   |     - `x` dropped here while still borrowed
+
+error[E0597]: `x` does not live long enough
+  --> $DIR/generic-slice.rs:27:5
+   |
+LL |     &x
+   |     ^^
+   |     |
+   |     borrowed value does not live long enough
+   |     using this value as a static requires that `x` is borrowed for `'static`
+LL |
+LL | };
+   | - `x` dropped here while still borrowed
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.