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
This commit is contained in:
commit
ccf1d9ca93
4 changed files with 93 additions and 16 deletions
|
@ -97,6 +97,36 @@ struct TransferFunction<'a, 'mir, 'tcx> {
|
||||||
param_env: ty::ParamEnv<'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> {
|
impl<'tcx> Visitor<'tcx> for TransferFunction<'_, '_, 'tcx> {
|
||||||
fn visit_rvalue(
|
fn visit_rvalue(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -104,21 +134,7 @@ impl<'tcx> Visitor<'tcx> for TransferFunction<'_, '_, 'tcx> {
|
||||||
location: Location,
|
location: Location,
|
||||||
) {
|
) {
|
||||||
if let mir::Rvalue::Ref(_, kind, ref borrowed_place) = *rvalue {
|
if let mir::Rvalue::Ref(_, kind, ref borrowed_place) = *rvalue {
|
||||||
let is_mut = match kind {
|
if self.borrow_allows_mutation(kind, borrowed_place) {
|
||||||
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 {
|
|
||||||
match borrowed_place.base {
|
match borrowed_place.base {
|
||||||
mir::PlaceBase::Local(borrowed_local) if !borrowed_place.is_indirect()
|
mir::PlaceBase::Local(borrowed_local) if !borrowed_place.is_indirect()
|
||||||
=> self.trans.gen(borrowed_local),
|
=> self.trans.gen(borrowed_local),
|
||||||
|
|
|
@ -137,7 +137,7 @@ pub fn compute_indirectly_mutable_locals<'mir, 'tcx>(
|
||||||
item.tcx,
|
item.tcx,
|
||||||
item.body,
|
item.body,
|
||||||
item.def_id,
|
item.def_id,
|
||||||
&[],
|
&item.tcx.get_attrs(item.def_id),
|
||||||
&dead_unwinds,
|
&dead_unwinds,
|
||||||
old_dataflow::IndirectlyMutableLocals::new(item.tcx, item.body, item.param_env),
|
old_dataflow::IndirectlyMutableLocals::new(item.tcx, item.body, item.param_env),
|
||||||
|_, local| old_dataflow::DebugFormatted::new(&local),
|
|_, local| old_dataflow::DebugFormatted::new(&local),
|
||||||
|
|
31
src/test/ui/consts/const-eval/generic-slice.rs
Normal file
31
src/test/ui/consts/const-eval/generic-slice.rs
Normal file
|
@ -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() {}
|
30
src/test/ui/consts/const-eval/generic-slice.stderr
Normal file
30
src/test/ui/consts/const-eval/generic-slice.stderr
Normal file
|
@ -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`.
|
Loading…
Add table
Add a link
Reference in a new issue