Auto merge of #68804 - ecstatic-morse:qualif-cursor-lazy, r=estebank
Always use lazy qualif getters during const-checking `has_mut_interior_eager_seek` was needed to work around an overly restrictive bound on the `per_local` argument to the `Qualif` trait. This PR makes that bound `FnMut` instead of `Fn` so we can seek cursors inside of it, resolving a FIXME in the const-checking code.
This commit is contained in:
commit
bae3d0dfc7
4 changed files with 35 additions and 52 deletions
|
@ -34,7 +34,7 @@ pub trait Qualif {
|
|||
|
||||
fn in_projection_structurally(
|
||||
cx: &ConstCx<'_, 'tcx>,
|
||||
per_local: &impl Fn(Local) -> bool,
|
||||
per_local: &mut impl FnMut(Local) -> bool,
|
||||
place: PlaceRef<'_, 'tcx>,
|
||||
) -> bool {
|
||||
if let [proj_base @ .., elem] = place.projection {
|
||||
|
@ -66,7 +66,7 @@ pub trait Qualif {
|
|||
|
||||
fn in_projection(
|
||||
cx: &ConstCx<'_, 'tcx>,
|
||||
per_local: &impl Fn(Local) -> bool,
|
||||
per_local: &mut impl FnMut(Local) -> bool,
|
||||
place: PlaceRef<'_, 'tcx>,
|
||||
) -> bool {
|
||||
Self::in_projection_structurally(cx, per_local, place)
|
||||
|
@ -74,7 +74,7 @@ pub trait Qualif {
|
|||
|
||||
fn in_place(
|
||||
cx: &ConstCx<'_, 'tcx>,
|
||||
per_local: &impl Fn(Local) -> bool,
|
||||
per_local: &mut impl FnMut(Local) -> bool,
|
||||
place: PlaceRef<'_, 'tcx>,
|
||||
) -> bool {
|
||||
match place {
|
||||
|
@ -85,7 +85,7 @@ pub trait Qualif {
|
|||
|
||||
fn in_operand(
|
||||
cx: &ConstCx<'_, 'tcx>,
|
||||
per_local: &impl Fn(Local) -> bool,
|
||||
per_local: &mut impl FnMut(Local) -> bool,
|
||||
operand: &Operand<'tcx>,
|
||||
) -> bool {
|
||||
match *operand {
|
||||
|
@ -126,7 +126,7 @@ pub trait Qualif {
|
|||
|
||||
fn in_rvalue_structurally(
|
||||
cx: &ConstCx<'_, 'tcx>,
|
||||
per_local: &impl Fn(Local) -> bool,
|
||||
per_local: &mut impl FnMut(Local) -> bool,
|
||||
rvalue: &Rvalue<'tcx>,
|
||||
) -> bool {
|
||||
match *rvalue {
|
||||
|
@ -170,7 +170,7 @@ pub trait Qualif {
|
|||
|
||||
fn in_rvalue(
|
||||
cx: &ConstCx<'_, 'tcx>,
|
||||
per_local: &impl Fn(Local) -> bool,
|
||||
per_local: &mut impl FnMut(Local) -> bool,
|
||||
rvalue: &Rvalue<'tcx>,
|
||||
) -> bool {
|
||||
Self::in_rvalue_structurally(cx, per_local, rvalue)
|
||||
|
@ -178,7 +178,7 @@ pub trait Qualif {
|
|||
|
||||
fn in_call(
|
||||
cx: &ConstCx<'_, 'tcx>,
|
||||
_per_local: &impl Fn(Local) -> bool,
|
||||
_per_local: &mut impl FnMut(Local) -> bool,
|
||||
_callee: &Operand<'tcx>,
|
||||
_args: &[Operand<'tcx>],
|
||||
return_ty: Ty<'tcx>,
|
||||
|
@ -208,7 +208,7 @@ impl Qualif for HasMutInterior {
|
|||
|
||||
fn in_rvalue(
|
||||
cx: &ConstCx<'_, 'tcx>,
|
||||
per_local: &impl Fn(Local) -> bool,
|
||||
per_local: &mut impl FnMut(Local) -> bool,
|
||||
rvalue: &Rvalue<'tcx>,
|
||||
) -> bool {
|
||||
match *rvalue {
|
||||
|
@ -249,7 +249,7 @@ impl Qualif for NeedsDrop {
|
|||
|
||||
fn in_rvalue(
|
||||
cx: &ConstCx<'_, 'tcx>,
|
||||
per_local: &impl Fn(Local) -> bool,
|
||||
per_local: &mut impl FnMut(Local) -> bool,
|
||||
rvalue: &Rvalue<'tcx>,
|
||||
) -> bool {
|
||||
if let Rvalue::Aggregate(ref kind, _) = *rvalue {
|
||||
|
|
|
@ -71,8 +71,13 @@ where
|
|||
return_place: &mir::Place<'tcx>,
|
||||
) {
|
||||
let return_ty = return_place.ty(*self.item.body, self.item.tcx).ty;
|
||||
let qualif =
|
||||
Q::in_call(self.item, &|l| self.qualifs_per_local.contains(l), func, args, return_ty);
|
||||
let qualif = Q::in_call(
|
||||
self.item,
|
||||
&mut |l| self.qualifs_per_local.contains(l),
|
||||
func,
|
||||
args,
|
||||
return_ty,
|
||||
);
|
||||
if !return_place.is_indirect() {
|
||||
self.assign_qualif_direct(return_place, qualif);
|
||||
}
|
||||
|
@ -105,7 +110,7 @@ where
|
|||
rvalue: &mir::Rvalue<'tcx>,
|
||||
location: Location,
|
||||
) {
|
||||
let qualif = Q::in_rvalue(self.item, &|l| self.qualifs_per_local.contains(l), rvalue);
|
||||
let qualif = Q::in_rvalue(self.item, &mut |l| self.qualifs_per_local.contains(l), rvalue);
|
||||
if !place.is_indirect() {
|
||||
self.assign_qualif_direct(place, qualif);
|
||||
}
|
||||
|
@ -120,7 +125,8 @@ where
|
|||
// here; that occurs in `apply_call_return_effect`.
|
||||
|
||||
if let mir::TerminatorKind::DropAndReplace { value, location: dest, .. } = kind {
|
||||
let qualif = Q::in_operand(self.item, &|l| self.qualifs_per_local.contains(l), value);
|
||||
let qualif =
|
||||
Q::in_operand(self.item, &mut |l| self.qualifs_per_local.contains(l), value);
|
||||
if !dest.is_indirect() {
|
||||
self.assign_qualif_direct(dest, qualif);
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ impl Qualifs<'a, 'mir, 'tcx> {
|
|||
/// Returns `true` if `local` is `NeedsDrop` at the given `Location`.
|
||||
///
|
||||
/// Only updates the cursor if absolutely necessary
|
||||
fn needs_drop_lazy_seek(&mut self, local: Local, location: Location) -> bool {
|
||||
fn needs_drop(&mut self, local: Local, location: Location) -> bool {
|
||||
if !self.needs_drop.in_any_value_of_ty.contains(local) {
|
||||
return false;
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ impl Qualifs<'a, 'mir, 'tcx> {
|
|||
/// Returns `true` if `local` is `HasMutInterior` at the given `Location`.
|
||||
///
|
||||
/// Only updates the cursor if absolutely necessary.
|
||||
fn has_mut_interior_lazy_seek(&mut self, local: Local, location: Location) -> bool {
|
||||
fn has_mut_interior(&mut self, local: Local, location: Location) -> bool {
|
||||
if !self.has_mut_interior.in_any_value_of_ty.contains(local) {
|
||||
return false;
|
||||
}
|
||||
|
@ -86,17 +86,6 @@ impl Qualifs<'a, 'mir, 'tcx> {
|
|||
|| self.indirectly_mutable(local, location)
|
||||
}
|
||||
|
||||
/// Returns `true` if `local` is `HasMutInterior`, but requires the `has_mut_interior` and
|
||||
/// `indirectly_mutable` cursors to be updated beforehand.
|
||||
fn has_mut_interior_eager_seek(&self, local: Local) -> bool {
|
||||
if !self.has_mut_interior.in_any_value_of_ty.contains(local) {
|
||||
return false;
|
||||
}
|
||||
|
||||
self.has_mut_interior.cursor.get().contains(local)
|
||||
|| self.indirectly_mutable.get().contains(local)
|
||||
}
|
||||
|
||||
fn in_return_place(&mut self, item: &Item<'_, 'tcx>) -> ConstQualifs {
|
||||
// Find the `Return` terminator if one exists.
|
||||
//
|
||||
|
@ -120,8 +109,8 @@ impl Qualifs<'a, 'mir, 'tcx> {
|
|||
let return_loc = item.body.terminator_loc(return_block);
|
||||
|
||||
ConstQualifs {
|
||||
needs_drop: self.needs_drop_lazy_seek(RETURN_PLACE, return_loc),
|
||||
has_mut_interior: self.has_mut_interior_lazy_seek(RETURN_PLACE, return_loc),
|
||||
needs_drop: self.needs_drop(RETURN_PLACE, return_loc),
|
||||
has_mut_interior: self.has_mut_interior(RETURN_PLACE, return_loc),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -244,23 +233,6 @@ impl Validator<'a, 'mir, 'tcx> {
|
|||
self.check_op_spanned(ops::StaticAccess, span)
|
||||
}
|
||||
}
|
||||
|
||||
fn check_immutable_borrow_like(&mut self, location: Location, place: &Place<'tcx>) {
|
||||
// FIXME: Change the `in_*` methods to take a `FnMut` so we don't have to manually
|
||||
// seek the cursors beforehand.
|
||||
self.qualifs.has_mut_interior.cursor.seek_before(location);
|
||||
self.qualifs.indirectly_mutable.seek(location);
|
||||
|
||||
let borrowed_place_has_mut_interior = HasMutInterior::in_place(
|
||||
&self.item,
|
||||
&|local| self.qualifs.has_mut_interior_eager_seek(local),
|
||||
place.as_ref(),
|
||||
);
|
||||
|
||||
if borrowed_place_has_mut_interior {
|
||||
self.check_op(ops::CellBorrow);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
|
||||
|
@ -366,12 +338,17 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
|
|||
Rvalue::AddressOf(Mutability::Mut, _) => self.check_op(ops::MutAddressOf),
|
||||
|
||||
Rvalue::Ref(_, BorrowKind::Shared, ref place)
|
||||
| Rvalue::Ref(_, BorrowKind::Shallow, ref place) => {
|
||||
self.check_immutable_borrow_like(location, place)
|
||||
}
|
||||
| Rvalue::Ref(_, BorrowKind::Shallow, ref place)
|
||||
| Rvalue::AddressOf(Mutability::Not, ref place) => {
|
||||
let borrowed_place_has_mut_interior = HasMutInterior::in_place(
|
||||
&self.item,
|
||||
&mut |local| self.qualifs.has_mut_interior(local, location),
|
||||
place.as_ref(),
|
||||
);
|
||||
|
||||
Rvalue::AddressOf(Mutability::Not, ref place) => {
|
||||
self.check_immutable_borrow_like(location, place)
|
||||
if borrowed_place_has_mut_interior {
|
||||
self.check_op(ops::CellBorrow);
|
||||
}
|
||||
}
|
||||
|
||||
Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => {
|
||||
|
@ -571,7 +548,7 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
|
|||
let needs_drop = if let Some(local) = dropped_place.as_local() {
|
||||
// Use the span where the local was declared as the span of the drop error.
|
||||
err_span = self.body.local_decls[local].source_info.span;
|
||||
self.qualifs.needs_drop_lazy_seek(local, location)
|
||||
self.qualifs.needs_drop(local, location)
|
||||
} else {
|
||||
true
|
||||
};
|
||||
|
|
|
@ -407,7 +407,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||
|
||||
// FIXME(eddyb) maybe cache this?
|
||||
fn qualif_local<Q: qualifs::Qualif>(&self, local: Local) -> bool {
|
||||
let per_local = &|l| self.qualif_local::<Q>(l);
|
||||
let per_local = &mut |l| self.qualif_local::<Q>(l);
|
||||
|
||||
if let TempState::Defined { location: loc, .. } = self.temps[local] {
|
||||
let num_stmts = self.body[loc.block].statements.len();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue