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(
|
fn in_projection_structurally(
|
||||||
cx: &ConstCx<'_, 'tcx>,
|
cx: &ConstCx<'_, 'tcx>,
|
||||||
per_local: &impl Fn(Local) -> bool,
|
per_local: &mut impl FnMut(Local) -> bool,
|
||||||
place: PlaceRef<'_, 'tcx>,
|
place: PlaceRef<'_, 'tcx>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if let [proj_base @ .., elem] = place.projection {
|
if let [proj_base @ .., elem] = place.projection {
|
||||||
|
@ -66,7 +66,7 @@ pub trait Qualif {
|
||||||
|
|
||||||
fn in_projection(
|
fn in_projection(
|
||||||
cx: &ConstCx<'_, 'tcx>,
|
cx: &ConstCx<'_, 'tcx>,
|
||||||
per_local: &impl Fn(Local) -> bool,
|
per_local: &mut impl FnMut(Local) -> bool,
|
||||||
place: PlaceRef<'_, 'tcx>,
|
place: PlaceRef<'_, 'tcx>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
Self::in_projection_structurally(cx, per_local, place)
|
Self::in_projection_structurally(cx, per_local, place)
|
||||||
|
@ -74,7 +74,7 @@ pub trait Qualif {
|
||||||
|
|
||||||
fn in_place(
|
fn in_place(
|
||||||
cx: &ConstCx<'_, 'tcx>,
|
cx: &ConstCx<'_, 'tcx>,
|
||||||
per_local: &impl Fn(Local) -> bool,
|
per_local: &mut impl FnMut(Local) -> bool,
|
||||||
place: PlaceRef<'_, 'tcx>,
|
place: PlaceRef<'_, 'tcx>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
match place {
|
match place {
|
||||||
|
@ -85,7 +85,7 @@ pub trait Qualif {
|
||||||
|
|
||||||
fn in_operand(
|
fn in_operand(
|
||||||
cx: &ConstCx<'_, 'tcx>,
|
cx: &ConstCx<'_, 'tcx>,
|
||||||
per_local: &impl Fn(Local) -> bool,
|
per_local: &mut impl FnMut(Local) -> bool,
|
||||||
operand: &Operand<'tcx>,
|
operand: &Operand<'tcx>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
match *operand {
|
match *operand {
|
||||||
|
@ -126,7 +126,7 @@ pub trait Qualif {
|
||||||
|
|
||||||
fn in_rvalue_structurally(
|
fn in_rvalue_structurally(
|
||||||
cx: &ConstCx<'_, 'tcx>,
|
cx: &ConstCx<'_, 'tcx>,
|
||||||
per_local: &impl Fn(Local) -> bool,
|
per_local: &mut impl FnMut(Local) -> bool,
|
||||||
rvalue: &Rvalue<'tcx>,
|
rvalue: &Rvalue<'tcx>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
match *rvalue {
|
match *rvalue {
|
||||||
|
@ -170,7 +170,7 @@ pub trait Qualif {
|
||||||
|
|
||||||
fn in_rvalue(
|
fn in_rvalue(
|
||||||
cx: &ConstCx<'_, 'tcx>,
|
cx: &ConstCx<'_, 'tcx>,
|
||||||
per_local: &impl Fn(Local) -> bool,
|
per_local: &mut impl FnMut(Local) -> bool,
|
||||||
rvalue: &Rvalue<'tcx>,
|
rvalue: &Rvalue<'tcx>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
Self::in_rvalue_structurally(cx, per_local, rvalue)
|
Self::in_rvalue_structurally(cx, per_local, rvalue)
|
||||||
|
@ -178,7 +178,7 @@ pub trait Qualif {
|
||||||
|
|
||||||
fn in_call(
|
fn in_call(
|
||||||
cx: &ConstCx<'_, 'tcx>,
|
cx: &ConstCx<'_, 'tcx>,
|
||||||
_per_local: &impl Fn(Local) -> bool,
|
_per_local: &mut impl FnMut(Local) -> bool,
|
||||||
_callee: &Operand<'tcx>,
|
_callee: &Operand<'tcx>,
|
||||||
_args: &[Operand<'tcx>],
|
_args: &[Operand<'tcx>],
|
||||||
return_ty: Ty<'tcx>,
|
return_ty: Ty<'tcx>,
|
||||||
|
@ -208,7 +208,7 @@ impl Qualif for HasMutInterior {
|
||||||
|
|
||||||
fn in_rvalue(
|
fn in_rvalue(
|
||||||
cx: &ConstCx<'_, 'tcx>,
|
cx: &ConstCx<'_, 'tcx>,
|
||||||
per_local: &impl Fn(Local) -> bool,
|
per_local: &mut impl FnMut(Local) -> bool,
|
||||||
rvalue: &Rvalue<'tcx>,
|
rvalue: &Rvalue<'tcx>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
match *rvalue {
|
match *rvalue {
|
||||||
|
@ -249,7 +249,7 @@ impl Qualif for NeedsDrop {
|
||||||
|
|
||||||
fn in_rvalue(
|
fn in_rvalue(
|
||||||
cx: &ConstCx<'_, 'tcx>,
|
cx: &ConstCx<'_, 'tcx>,
|
||||||
per_local: &impl Fn(Local) -> bool,
|
per_local: &mut impl FnMut(Local) -> bool,
|
||||||
rvalue: &Rvalue<'tcx>,
|
rvalue: &Rvalue<'tcx>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if let Rvalue::Aggregate(ref kind, _) = *rvalue {
|
if let Rvalue::Aggregate(ref kind, _) = *rvalue {
|
||||||
|
|
|
@ -71,8 +71,13 @@ where
|
||||||
return_place: &mir::Place<'tcx>,
|
return_place: &mir::Place<'tcx>,
|
||||||
) {
|
) {
|
||||||
let return_ty = return_place.ty(*self.item.body, self.item.tcx).ty;
|
let return_ty = return_place.ty(*self.item.body, self.item.tcx).ty;
|
||||||
let qualif =
|
let qualif = Q::in_call(
|
||||||
Q::in_call(self.item, &|l| self.qualifs_per_local.contains(l), func, args, return_ty);
|
self.item,
|
||||||
|
&mut |l| self.qualifs_per_local.contains(l),
|
||||||
|
func,
|
||||||
|
args,
|
||||||
|
return_ty,
|
||||||
|
);
|
||||||
if !return_place.is_indirect() {
|
if !return_place.is_indirect() {
|
||||||
self.assign_qualif_direct(return_place, qualif);
|
self.assign_qualif_direct(return_place, qualif);
|
||||||
}
|
}
|
||||||
|
@ -105,7 +110,7 @@ where
|
||||||
rvalue: &mir::Rvalue<'tcx>,
|
rvalue: &mir::Rvalue<'tcx>,
|
||||||
location: Location,
|
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() {
|
if !place.is_indirect() {
|
||||||
self.assign_qualif_direct(place, qualif);
|
self.assign_qualif_direct(place, qualif);
|
||||||
}
|
}
|
||||||
|
@ -120,7 +125,8 @@ where
|
||||||
// here; that occurs in `apply_call_return_effect`.
|
// here; that occurs in `apply_call_return_effect`.
|
||||||
|
|
||||||
if let mir::TerminatorKind::DropAndReplace { value, location: dest, .. } = kind {
|
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() {
|
if !dest.is_indirect() {
|
||||||
self.assign_qualif_direct(dest, qualif);
|
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`.
|
/// Returns `true` if `local` is `NeedsDrop` at the given `Location`.
|
||||||
///
|
///
|
||||||
/// Only updates the cursor if absolutely necessary
|
/// 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) {
|
if !self.needs_drop.in_any_value_of_ty.contains(local) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ impl Qualifs<'a, 'mir, 'tcx> {
|
||||||
/// Returns `true` if `local` is `HasMutInterior` at the given `Location`.
|
/// Returns `true` if `local` is `HasMutInterior` at the given `Location`.
|
||||||
///
|
///
|
||||||
/// Only updates the cursor if absolutely necessary.
|
/// 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) {
|
if !self.has_mut_interior.in_any_value_of_ty.contains(local) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -86,17 +86,6 @@ impl Qualifs<'a, 'mir, 'tcx> {
|
||||||
|| self.indirectly_mutable(local, location)
|
|| 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 {
|
fn in_return_place(&mut self, item: &Item<'_, 'tcx>) -> ConstQualifs {
|
||||||
// Find the `Return` terminator if one exists.
|
// 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);
|
let return_loc = item.body.terminator_loc(return_block);
|
||||||
|
|
||||||
ConstQualifs {
|
ConstQualifs {
|
||||||
needs_drop: self.needs_drop_lazy_seek(RETURN_PLACE, return_loc),
|
needs_drop: self.needs_drop(RETURN_PLACE, return_loc),
|
||||||
has_mut_interior: self.has_mut_interior_lazy_seek(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)
|
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> {
|
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::AddressOf(Mutability::Mut, _) => self.check_op(ops::MutAddressOf),
|
||||||
|
|
||||||
Rvalue::Ref(_, BorrowKind::Shared, ref place)
|
Rvalue::Ref(_, BorrowKind::Shared, ref place)
|
||||||
| Rvalue::Ref(_, BorrowKind::Shallow, ref place) => {
|
| Rvalue::Ref(_, BorrowKind::Shallow, ref place)
|
||||||
self.check_immutable_borrow_like(location, 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) => {
|
if borrowed_place_has_mut_interior {
|
||||||
self.check_immutable_borrow_like(location, place)
|
self.check_op(ops::CellBorrow);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => {
|
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() {
|
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.
|
// 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;
|
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 {
|
} else {
|
||||||
true
|
true
|
||||||
};
|
};
|
||||||
|
|
|
@ -407,7 +407,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
||||||
|
|
||||||
// FIXME(eddyb) maybe cache this?
|
// FIXME(eddyb) maybe cache this?
|
||||||
fn qualif_local<Q: qualifs::Qualif>(&self, local: Local) -> bool {
|
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] {
|
if let TempState::Defined { location: loc, .. } = self.temps[local] {
|
||||||
let num_stmts = self.body[loc.block].statements.len();
|
let num_stmts = self.body[loc.block].statements.len();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue