diff --git a/src/librustc_mir/dataflow/impls/indirect_mutation.rs b/src/librustc_mir/dataflow/impls/indirect_mutation.rs index 535b803b85f35..990425c3252e0 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 3045239d7a770..2d7b215b13c45 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 0000000000000..21360a1c471f6 --- /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>] = { + let x: &[_] = &[]; + x +}; + +static mut INTERIOR_MUT_AND_DROP_REF: &'static &'static [std::cell::RefCell>] = { + let x: &[_] = &[]; + &x + //~^ ERROR `x` does not live long enough +}; + +fn main() {}