Skip to content

Commit

Permalink
Rollup merge of #64967 - ecstatic-morse:issue-64945, r=oli-obk
Browse files Browse the repository at this point in the history
Don't mark borrows of zero-sized arrays as indirectly mutable

Resolves #64945

r? @oli-obk
  • Loading branch information
Centril authored Oct 1, 2019
2 parents 8e870a5 + 7a65fe3 commit 74586e2
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 16 deletions.
46 changes: 31 additions & 15 deletions src/librustc_mir/dataflow/impls/indirect_mutation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,28 +97,44 @@ 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,
rvalue: &mir::Rvalue<'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),
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/transform/check_consts/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
31 changes: 31 additions & 0 deletions src/test/ui/consts/const-eval/generic-slice.rs
Original file line number Diff line number Diff line change
@@ -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() {}

0 comments on commit 74586e2

Please sign in to comment.