Simplify mem_categorization

* `Place` is no longer recursive.
* The `cmt` type alias is removed
* `Upvar` places no longer include the dereferences of the environment
  closure or of by reference captures.
* All non-dereference projections are combined to a single variant.
* Various unnecessary types and methods have been removed.
This commit is contained in:
Matthew Jasper 2019-11-08 22:54:00 +00:00
parent a5b8a3088a
commit 1d53e43744
8 changed files with 375 additions and 1260 deletions

View File

@ -13,7 +13,6 @@ use crate::middle::mem_categorization as mc;
use crate::ty::{self, TyCtxt, adjustment};
use crate::hir::{self, PatKind};
use std::rc::Rc;
use syntax_pos::Span;
///////////////////////////////////////////////////////////////////////////
@ -136,12 +135,9 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
let param_ty = return_if_err!(self.mc.pat_ty_adjusted(&param.pat));
debug!("consume_body: param_ty = {:?}", param_ty);
let param_cmt = Rc::new(self.mc.cat_rvalue(
param.hir_id,
param.pat.span,
param_ty));
let param_place = self.mc.cat_rvalue(param.hir_id, param.pat.span, param_ty);
self.walk_irrefutable_pat(param_cmt, &param.pat);
self.walk_irrefutable_pat(&param_place, &param.pat);
}
self.consume_expr(&body.value);
@ -234,12 +230,12 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
}
hir::ExprKind::Match(ref discr, ref arms, _) => {
let discr_cmt = Rc::new(return_if_err!(self.mc.cat_expr(&discr)));
let discr_cmt = return_if_err!(self.mc.cat_expr(&discr));
self.borrow_expr(&discr, ty::ImmBorrow);
// treatment of the discriminant is handled while walking the arms.
for arm in arms {
self.walk_arm(discr_cmt.clone(), arm);
self.walk_arm(&discr_cmt, arm);
}
}
@ -385,8 +381,8 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
// "assigns", which is handled by
// `walk_pat`:
self.walk_expr(&expr);
let init_cmt = Rc::new(return_if_err!(self.mc.cat_expr(&expr)));
self.walk_irrefutable_pat(init_cmt, &local.pat);
let init_cmt = return_if_err!(self.mc.cat_expr(&expr));
self.walk_irrefutable_pat(&init_cmt, &local.pat);
}
}
@ -417,11 +413,11 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
None => { return; }
};
let with_cmt = Rc::new(return_if_err!(self.mc.cat_expr(&with_expr)));
let with_place = return_if_err!(self.mc.cat_expr(&with_expr));
// Select just those fields of the `with`
// expression that will actually be used
match with_cmt.ty.kind {
match with_place.ty.kind {
ty::Adt(adt, substs) if adt.is_struct() => {
// Consume those fields of the with expression that are needed.
for (f_index, with_field) in adt.non_enum_variant().fields.iter().enumerate() {
@ -429,14 +425,12 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
self.tcx().field_index(f.hir_id, self.mc.tables) == f_index
});
if !is_mentioned {
let cmt_field = self.mc.cat_field(
let field_place = self.mc.cat_projection(
&*with_expr,
with_cmt.clone(),
f_index,
with_field.ident,
with_field.ty(self.tcx(), substs)
with_place.clone(),
with_field.ty(self.tcx(), substs),
);
self.delegate_consume(&cmt_field);
self.delegate_consume(&field_place);
}
}
}
@ -522,8 +516,8 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
}
}
fn walk_arm(&mut self, discr_cmt: mc::cmt<'tcx>, arm: &hir::Arm) {
self.walk_pat(discr_cmt.clone(), &arm.pat);
fn walk_arm(&mut self, discr_place: &mc::Place<'tcx>, arm: &hir::Arm) {
self.walk_pat(discr_place, &arm.pat);
if let Some(hir::Guard::If(ref e)) = arm.guard {
self.consume_expr(e)
@ -534,22 +528,22 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
/// Walks a pat that occurs in isolation (i.e., top-level of fn argument or
/// let binding, and *not* a match arm or nested pat.)
fn walk_irrefutable_pat(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &hir::Pat) {
self.walk_pat(cmt_discr, pat);
fn walk_irrefutable_pat(&mut self, discr_place: &mc::Place<'tcx>, pat: &hir::Pat) {
self.walk_pat(discr_place, pat);
}
/// The core driver for walking a pattern
fn walk_pat(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &hir::Pat) {
debug!("walk_pat(cmt_discr={:?}, pat={:?})", cmt_discr, pat);
fn walk_pat(&mut self, discr_place: &mc::Place<'tcx>, pat: &hir::Pat) {
debug!("walk_pat(discr_place={:?}, pat={:?})", discr_place, pat);
let tcx = self.tcx();
let ExprUseVisitor { ref mc, ref mut delegate } = *self;
return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |cmt_pat, pat| {
return_if_err!(mc.cat_pattern(discr_place.clone(), pat, |place, pat| {
if let PatKind::Binding(_, canonical_id, ..) = pat.kind {
debug!(
"walk_pat: binding cmt_pat={:?} pat={:?}",
cmt_pat,
"walk_pat: binding place={:?} pat={:?}",
place,
pat,
);
if let Some(&bm) = mc.tables.pat_binding_modes().get(pat.hir_id) {
@ -570,12 +564,12 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
match bm {
ty::BindByReference(m) => {
let bk = ty::BorrowKind::from_mutbl(m);
delegate.borrow(&cmt_pat, bk);
delegate.borrow(place, bk);
}
ty::BindByValue(..) => {
let mode = copy_or_move(mc, &cmt_pat);
let mode = copy_or_move(mc, place);
debug!("walk_pat binding consuming pat");
delegate.consume(&cmt_pat, mode);
delegate.consume(place, mode);
}
}
} else {

File diff suppressed because it is too large Load Diff

View File

@ -75,7 +75,6 @@
use crate::check::dropck;
use crate::check::FnCtxt;
use crate::middle::mem_categorization as mc;
use crate::middle::mem_categorization::Categorization;
use crate::middle::region;
use rustc::hir::def_id::DefId;
use rustc::infer::outlives::env::OutlivesEnvironment;
@ -88,7 +87,6 @@ use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc::hir::{self, PatKind};
use std::mem;
use std::ops::Deref;
use std::rc::Rc;
use syntax_pos::Span;
// a variation on try that just returns unit
@ -898,10 +896,6 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> {
}
cmt = self.with_mc(|mc| mc.cat_expr_adjusted(expr, cmt, &adjustment))?;
if let Categorization::Deref(_, mc::BorrowedPtr(_, r_ptr)) = cmt.cat {
self.mk_subregion_due_to_dereference(expr.span, expr_region, r_ptr);
}
}
Ok(cmt)
@ -920,16 +914,22 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> {
)
}
fn check_safety_of_rvalue_destructor_if_necessary(&mut self, cmt: &mc::Place<'tcx>, span: Span) {
if let Categorization::Rvalue = cmt.cat {
let typ = self.resolve_type(cmt.ty);
let body_id = self.body_id;
let _ = dropck::check_drop_obligations(
self,
typ,
span,
body_id,
);
fn check_safety_of_rvalue_destructor_if_necessary(
&mut self,
place: &mc::Place<'tcx>,
span: Span,
) {
if let mc::PlaceBase::Rvalue = place.base {
if place.projections.is_empty() {
let typ = self.resolve_type(place.ty);
let body_id = self.body_id;
let _ = dropck::check_drop_obligations(
self,
typ,
span,
body_id,
);
}
}
}
@ -1034,7 +1034,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> {
}
Some(ref expr) => &**expr,
};
let discr_cmt = Rc::new(ignore_err!(self.with_mc(|mc| mc.cat_expr(init_expr))));
let discr_cmt = ignore_err!(self.with_mc(|mc| mc.cat_expr(init_expr)));
self.link_pattern(discr_cmt, &local.pat);
}
@ -1043,7 +1043,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> {
/// linked to the lifetime of its guarantor (if any).
fn link_match(&self, discr: &hir::Expr, arms: &[hir::Arm]) {
debug!("regionck::for_match()");
let discr_cmt = Rc::new(ignore_err!(self.with_mc(|mc| mc.cat_expr(discr))));
let discr_cmt = ignore_err!(self.with_mc(|mc| mc.cat_expr(discr)));
debug!("discr_cmt={:?}", discr_cmt);
for arm in arms {
self.link_pattern(discr_cmt.clone(), &arm.pat);
@ -1057,7 +1057,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> {
for param in params {
let param_ty = self.node_ty(param.hir_id);
let param_cmt = self.with_mc(|mc| {
Rc::new(mc.cat_rvalue(param.hir_id, param.pat.span, param_ty))
mc.cat_rvalue(param.hir_id, param.pat.span, param_ty)
});
debug!("param_ty={:?} param_cmt={:?} param={:?}", param_ty, param_cmt, param);
self.link_pattern(param_cmt, &param.pat);
@ -1066,7 +1066,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> {
/// Link lifetimes of any ref bindings in `root_pat` to the pointers found
/// in the discriminant, if needed.
fn link_pattern(&self, discr_cmt: mc::cmt<'tcx>, root_pat: &hir::Pat) {
fn link_pattern(&self, discr_cmt: mc::Place<'tcx>, root_pat: &hir::Pat) {
debug!(
"link_pattern(discr_cmt={:?}, root_pat={:?})",
discr_cmt, root_pat
@ -1152,61 +1152,35 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> {
span: Span,
borrow_region: ty::Region<'tcx>,
borrow_kind: ty::BorrowKind,
borrow_cmt: &mc::Place<'tcx>,
borrow_place: &mc::Place<'tcx>,
) {
let origin = infer::DataBorrowed(borrow_cmt.ty, span);
self.type_must_outlive(origin, borrow_cmt.ty, borrow_region);
let origin = infer::DataBorrowed(borrow_place.ty, span);
self.type_must_outlive(origin, borrow_place.ty, borrow_region);
let mut borrow_kind = borrow_kind;
let mut borrow_cmt_cat = borrow_cmt.cat.clone();
loop {
for pointer_ty in borrow_place.deref_tys() {
debug!(
"link_region(borrow_region={:?}, borrow_kind={:?}, borrow_cmt={:?})",
borrow_region, borrow_kind, borrow_cmt
"link_region(borrow_region={:?}, borrow_kind={:?}, pointer_ty={:?})",
borrow_region, borrow_kind, borrow_place
);
match borrow_cmt_cat {
Categorization::Deref(ref_cmt, mc::BorrowedPtr(ref_kind, ref_region)) => {
match self.link_reborrowed_region(
match pointer_ty.kind {
ty::RawPtr(_) => return,
ty::Ref(ref_region, _, ref_mutability) => {
if self.link_reborrowed_region(
span,
borrow_region,
borrow_kind,
ref_cmt,
ref_region,
ref_kind,
borrow_cmt.note,
ref_mutability,
) {
Some((c, k)) => {
borrow_cmt_cat = c.cat.clone();
borrow_kind = k;
}
None => {
return;
}
return;
}
}
Categorization::Downcast(cmt_base, _)
| Categorization::Deref(cmt_base, mc::Unique)
| Categorization::Interior(cmt_base, _) => {
// Borrowing interior or owned data requires the base
// to be valid and borrowable in the same fashion.
borrow_cmt_cat = cmt_base.cat.clone();
borrow_kind = borrow_kind;
}
Categorization::Deref(_, mc::UnsafePtr(..))
| Categorization::StaticItem
| Categorization::Upvar(..)
| Categorization::Local(..)
| Categorization::ThreadLocal
| Categorization::Rvalue => {
// These are all "base cases" with independent lifetimes
// that are not subject to inference
return;
}
_ => assert!(pointer_ty.is_box(), "unexpected built-in deref type {}", pointer_ty)
}
}
if let mc::PlaceBase::Upvar(upvar_id) = borrow_place.base {
self.link_upvar_region(span, borrow_region, upvar_id);
}
}
/// This is the most complicated case: the path being borrowed is
@ -1230,83 +1204,28 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> {
///
/// Here `bk` stands for some borrow-kind (e.g., `mut`, `uniq`, etc).
///
/// Unfortunately, there are some complications beyond the simple
/// scenario I just painted:
/// There is a complication beyond the simple scenario I just painted: there
/// may in fact be more levels of reborrowing. In the example, I said the
/// borrow was like `&'z *r`, but it might in fact be a borrow like
/// `&'z **q` where `q` has type `&'a &'b mut T`. In that case, we want to
/// ensure that `'z <= 'a` and `'z <= 'b`.
///
/// 1. The reference `r` might in fact be a "by-ref" upvar. In that
/// case, we have two jobs. First, we are inferring whether this reference
/// should be an `&T`, `&mut T`, or `&uniq T` reference, and we must
/// adjust that based on this borrow (e.g., if this is an `&mut` borrow,
/// then `r` must be an `&mut` reference). Second, whenever we link
/// two regions (here, `'z <= 'a`), we supply a *cause*, and in this
/// case we adjust the cause to indicate that the reference being
/// "reborrowed" is itself an upvar. This provides a nicer error message
/// should something go wrong.
/// The return value of this function indicates whether we *don't* need to
/// the recurse to the next reference up.
///
/// 2. There may in fact be more levels of reborrowing. In the
/// example, I said the borrow was like `&'z *r`, but it might
/// in fact be a borrow like `&'z **q` where `q` has type `&'a
/// &'b mut T`. In that case, we want to ensure that `'z <= 'a`
/// and `'z <= 'b`. This is explained more below.
///
/// The return value of this function indicates whether we need to
/// recurse and process `ref_cmt` (see case 2 above).
/// This is explained more below.
fn link_reborrowed_region(
&self,
span: Span,
borrow_region: ty::Region<'tcx>,
borrow_kind: ty::BorrowKind,
ref_cmt: mc::cmt<'tcx>,
ref_region: ty::Region<'tcx>,
mut ref_kind: ty::BorrowKind,
note: mc::Note,
) -> Option<(mc::cmt<'tcx>, ty::BorrowKind)> {
// Possible upvar ID we may need later to create an entry in the
// maybe link map.
// Detect by-ref upvar `x`:
let cause = match note {
mc::NoteUpvarRef(ref upvar_id) => {
match self.tables.borrow().upvar_capture_map.get(upvar_id) {
Some(&ty::UpvarCapture::ByRef(ref upvar_borrow)) => {
// The mutability of the upvar may have been modified
// by the above adjustment, so update our local variable.
ref_kind = upvar_borrow.kind;
infer::ReborrowUpvar(span, *upvar_id)
}
_ => {
span_bug!(span, "Illegal upvar id: {:?}", upvar_id);
}
}
}
mc::NoteClosureEnv(ref upvar_id) => {
// We don't have any mutability changes to propagate, but
// we do want to note that an upvar reborrow caused this
// link
infer::ReborrowUpvar(span, *upvar_id)
}
_ => infer::Reborrow(span),
};
ref_mutability: hir::Mutability,
) -> bool {
debug!(
"link_reborrowed_region: {:?} <= {:?}",
borrow_region, ref_region
);
self.sub_regions(cause, borrow_region, ref_region);
// If we end up needing to recurse and establish a region link
// with `ref_cmt`, calculate what borrow kind we will end up
// needing. This will be used below.
//
// One interesting twist is that we can weaken the borrow kind
// when we recurse: to reborrow an `&mut` referent as mutable,
// borrowck requires a unique path to the `&mut` reference but not
// necessarily a *mutable* path.
let new_borrow_kind = match borrow_kind {
ty::ImmBorrow => ty::ImmBorrow,
ty::MutBorrow | ty::UniqueImmBorrow => ty::UniqueImmBorrow,
};
self.sub_regions(infer::Reborrow(span), borrow_region, ref_region);
// Decide whether we need to recurse and link any regions within
// the `ref_cmt`. This is concerned for the case where the value
@ -1335,24 +1254,83 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> {
// (Note that since we have not examined `ref_cmt.cat`, we don't
// know whether this scenario has occurred; but I wanted to show
// how all the types get adjusted.)
match ref_kind {
ty::ImmBorrow => {
match ref_mutability {
hir::Mutability::Immutable => {
// The reference being reborrowed is a shareable ref of
// type `&'a T`. In this case, it doesn't matter where we
// *found* the `&T` pointer, the memory it references will
// be valid and immutable for `'a`. So we can stop here.
//
// (Note that the `borrow_kind` must also be ImmBorrow or
// else the user is borrowed imm memory as mut memory,
// which means they'll get an error downstream in borrowck
// anyhow.)
return None;
true
}
ty::MutBorrow | ty::UniqueImmBorrow => {
// The reference being reborrowed is either an `&mut T` or
// `&uniq T`. This is the case where recursion is needed.
return Some((ref_cmt, new_borrow_kind));
hir::Mutability::Mutable => {
// The reference being reborrowed is either an `&mut T`. This is
// the case where recursion is needed.
false
}
}
}
/// An upvar may be behind up to 2 references:
///
/// * One can come from the reference to a "by-reference" upvar.
/// * Another one can come from the reference to the closure itself if it's
/// a `FnMut` or `Fn` closure.
///
/// This function links the lifetimes of those references to the lifetime
/// of the borrow that's provided. See [link_reborrowed_region] for some
/// more explanation of this in the general case.
///
/// We also supply a *cause*, and in this case we set the cause to
/// indicate that the reference being "reborrowed" is itself an upvar. This
/// provides a nicer error message should something go wrong.
fn link_upvar_region(
&self,
span: Span,
borrow_region: ty::Region<'tcx>,
upvar_id: ty::UpvarId,
) {
debug!("link_upvar_region(borrorw_region={:?}, upvar_id={:?}", borrow_region, upvar_id);
// A by-reference upvar can't be borrowed for longer than the
// upvar is borrowed from the environment.
match self.tables.borrow().upvar_capture(upvar_id) {
ty::UpvarCapture::ByRef(upvar_borrow) => {
self.sub_regions(
infer::ReborrowUpvar(span, upvar_id),
borrow_region,
upvar_borrow.region,
);
if let ty::ImmBorrow = upvar_borrow.kind {
debug!("link_upvar_region: capture by shared ref");
return;
}
}
ty::UpvarCapture::ByValue => {}
}
let fn_hir_id = self.tcx.hir().local_def_id_to_hir_id(upvar_id.closure_expr_id);
let ty = self.resolve_node_type(fn_hir_id);
debug!("link_upvar_region: ty={:?}", ty);
// A closure capture can't be borrowed for longer than the
// reference to the closure.
if let ty::Closure(closure_def_id, substs) = ty.kind {
match self.infcx.closure_kind(closure_def_id, substs) {
Some(ty::ClosureKind::Fn) | Some(ty::ClosureKind::FnMut) => {
// Region of environment pointer
let env_region = self.tcx.mk_region(ty::ReFree(ty::FreeRegion {
scope: upvar_id.closure_expr_id.to_def_id(),
bound_region: ty::BrEnv
}));
self.sub_regions(
infer::ReborrowUpvar(span, upvar_id),
borrow_region,
env_region,
);
}
Some(ty::ClosureKind::FnOnce) => {}
None => {
span_bug!(span, "Have not inferred closure kind before regionck");
}
}
}
}

View File

@ -34,7 +34,7 @@ use super::FnCtxt;
use crate::middle::expr_use_visitor as euv;
use crate::middle::mem_categorization as mc;
use crate::middle::mem_categorization::Categorization;
use crate::middle::mem_categorization::PlaceBase;
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::hir::def_id::LocalDefId;
@ -76,6 +76,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InferBorrowKindVisitor<'a, 'tcx> {
}
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Analysis starting point.
fn analyze_closure(
&self,
closure_hir_id: hir::HirId,
@ -83,9 +84,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
body: &hir::Body,
capture_clause: hir::CaptureBy,
) {
/*!
* Analysis starting point.
*/
debug!(
"analyze_closure(id={:?}, body.id={:?})",
@ -310,13 +308,10 @@ struct InferBorrowKind<'a, 'tcx> {
impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
fn adjust_upvar_borrow_kind_for_consume(
&mut self,
cmt: &mc::Place<'tcx>,
place: &mc::Place<'tcx>,
mode: euv::ConsumeMode,
) {
debug!(
"adjust_upvar_borrow_kind_for_consume(cmt={:?}, mode={:?})",
cmt, mode
);
debug!("adjust_upvar_borrow_kind_for_consume(place={:?}, mode={:?})", place, mode);
// we only care about moves
match mode {
@ -327,132 +322,68 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
}
let tcx = self.fcx.tcx;
let upvar_id = if let PlaceBase::Upvar(upvar_id) = place.base {
upvar_id
} else {
return;
};
// watch out for a move of the deref of a borrowed pointer;
// for that to be legal, the upvar would have to be borrowed
// by value instead
let guarantor = cmt.guarantor();
debug!(
"adjust_upvar_borrow_kind_for_consume: guarantor={:?}",
guarantor
debug!("adjust_upvar_borrow_kind_for_consume: upvar={:?}", upvar_id);
// To move out of an upvar, this must be a FnOnce closure
self.adjust_closure_kind(
upvar_id.closure_expr_id,
ty::ClosureKind::FnOnce,
place.span,
var_name(tcx, upvar_id.var_path.hir_id),
);
debug!(
"adjust_upvar_borrow_kind_for_consume: guarantor.cat={:?}",
guarantor.cat
);
if let Categorization::Deref(_, mc::BorrowedPtr(..)) = guarantor.cat {
debug!(
"adjust_upvar_borrow_kind_for_consume: found deref with note {:?}",
cmt.note
);
match guarantor.note {
mc::NoteUpvarRef(upvar_id) => {
debug!(
"adjust_upvar_borrow_kind_for_consume: \
setting upvar_id={:?} to by value",
upvar_id
);
// to move out of an upvar, this must be a FnOnce closure
self.adjust_closure_kind(
upvar_id.closure_expr_id,
ty::ClosureKind::FnOnce,
guarantor.span,
var_name(tcx, upvar_id.var_path.hir_id),
);
self.adjust_upvar_captures
.insert(upvar_id, ty::UpvarCapture::ByValue);
}
mc::NoteClosureEnv(upvar_id) => {
// we get just a closureenv ref if this is a
// `move` closure, or if the upvar has already
// been inferred to by-value. In any case, we
// must still adjust the kind of the closure
// to be a FnOnce closure to permit moves out
// of the environment.
self.adjust_closure_kind(
upvar_id.closure_expr_id,
ty::ClosureKind::FnOnce,
guarantor.span,
var_name(tcx, upvar_id.var_path.hir_id),
);
}
mc::NoteIndex | mc::NoteNone => {}
}
}
self.adjust_upvar_captures.insert(upvar_id, ty::UpvarCapture::ByValue);
}
/// Indicates that `cmt` is being directly mutated (e.g., assigned
/// to). If cmt contains any by-ref upvars, this implies that
/// those upvars must be borrowed using an `&mut` borrow.
fn adjust_upvar_borrow_kind_for_mut(&mut self, cmt: &mc::Place<'tcx>) {
debug!("adjust_upvar_borrow_kind_for_mut(cmt={:?})", cmt);
/// to). If the place is based on a by-ref upvar, this implies that
/// the upvar must be borrowed using an `&mut` borrow.
fn adjust_upvar_borrow_kind_for_mut(&mut self, place: &mc::Place<'tcx>) {
debug!("adjust_upvar_borrow_kind_for_mut(place={:?})", place);
match cmt.cat.clone() {
Categorization::Deref(base, mc::Unique)
| Categorization::Interior(base, _)
| Categorization::Downcast(base, _) => {
// Interior or owned data is mutable if base is
// mutable, so iterate to the base.
self.adjust_upvar_borrow_kind_for_mut(&base);
}
Categorization::Deref(base, mc::BorrowedPtr(..)) => {
if !self.try_adjust_upvar_deref(cmt, ty::MutBorrow) {
if let PlaceBase::Upvar(upvar_id) = place.base {
let mut borrow_kind = ty::MutBorrow;
for pointer_ty in place.deref_tys() {
match pointer_ty.kind {
// Raw pointers don't inherit mutability.
ty::RawPtr(_) => return,
// assignment to deref of an `&mut`
// borrowed pointer implies that the
// pointer itself must be unique, but not
// necessarily *mutable*
self.adjust_upvar_borrow_kind_for_unique(&base);
ty::Ref(.., hir::Mutability::Mutable) => borrow_kind = ty::UniqueImmBorrow,
_ => (),
}
}
self.adjust_upvar_deref(upvar_id, place.span, borrow_kind);
}
}
Categorization::Deref(_, mc::UnsafePtr(..))
| Categorization::StaticItem
| Categorization::ThreadLocal
| Categorization::Rvalue
| Categorization::Local(_)
| Categorization::Upvar(..) => {
fn adjust_upvar_borrow_kind_for_unique(&mut self, place: &mc::Place<'tcx>) {
debug!("adjust_upvar_borrow_kind_for_unique(place={:?})", place);
if let PlaceBase::Upvar(upvar_id) = place.base {
if place.deref_tys().any(ty::TyS::is_unsafe_ptr) {
// Raw pointers don't inherit mutability.
return;
}
// for a borrowed pointer to be unique, its base must be unique
self.adjust_upvar_deref(upvar_id, place.span, ty::UniqueImmBorrow);
}
}
fn adjust_upvar_borrow_kind_for_unique(&mut self, cmt: &mc::Place<'tcx>) {
debug!("adjust_upvar_borrow_kind_for_unique(cmt={:?})", cmt);
match cmt.cat.clone() {
Categorization::Deref(base, mc::Unique)
| Categorization::Interior(base, _)
| Categorization::Downcast(base, _) => {
// Interior or owned data is unique if base is
// unique.
self.adjust_upvar_borrow_kind_for_unique(&base);
}
Categorization::Deref(base, mc::BorrowedPtr(..)) => {
if !self.try_adjust_upvar_deref(cmt, ty::UniqueImmBorrow) {
// for a borrowed pointer to be unique, its
// base must be unique
self.adjust_upvar_borrow_kind_for_unique(&base);
}
}
Categorization::Deref(_, mc::UnsafePtr(..))
| Categorization::StaticItem
| Categorization::ThreadLocal
| Categorization::Rvalue
| Categorization::Local(_)
| Categorization::Upvar(..) => {}
}
}
fn try_adjust_upvar_deref(
fn adjust_upvar_deref(
&mut self,
cmt: &mc::Place<'tcx>,
upvar_id: ty::UpvarId,
place_span: Span,
borrow_kind: ty::BorrowKind,
) -> bool {
) {
assert!(match borrow_kind {
ty::MutBorrow => true,
ty::UniqueImmBorrow => true,
@ -463,39 +394,19 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
let tcx = self.fcx.tcx;
match cmt.note {
mc::NoteUpvarRef(upvar_id) => {
// if this is an implicit deref of an
// upvar, then we need to modify the
// borrow_kind of the upvar to make sure it
// is inferred to mutable if necessary
self.adjust_upvar_borrow_kind(upvar_id, borrow_kind);
// if this is an implicit deref of an
// upvar, then we need to modify the
// borrow_kind of the upvar to make sure it
// is inferred to mutable if necessary
self.adjust_upvar_borrow_kind(upvar_id, borrow_kind);
// also need to be in an FnMut closure since this is not an ImmBorrow
self.adjust_closure_kind(
upvar_id.closure_expr_id,
ty::ClosureKind::FnMut,
cmt.span,
var_name(tcx, upvar_id.var_path.hir_id),
);
true
}
mc::NoteClosureEnv(upvar_id) => {
// this kind of deref occurs in a `move` closure, or
// for a by-value upvar; in either case, to mutate an
// upvar, we need to be an FnMut closure
self.adjust_closure_kind(
upvar_id.closure_expr_id,
ty::ClosureKind::FnMut,
cmt.span,
var_name(tcx, upvar_id.var_path.hir_id),
);
true
}
mc::NoteIndex | mc::NoteNone => false,
}
// also need to be in an FnMut closure since this is not an ImmBorrow
self.adjust_closure_kind(
upvar_id.closure_expr_id,
ty::ClosureKind::FnMut,
place_span,
var_name(tcx, upvar_id.var_path.hir_id),
);
}
/// We infer the borrow_kind with which to borrow upvars in a stack closure.
@ -507,7 +418,7 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
let upvar_capture = self
.adjust_upvar_captures
.get(&upvar_id)
.cloned()
.copied()
.unwrap_or_else(|| self.fcx.tables.borrow().upvar_capture(upvar_id));
debug!(
"adjust_upvar_borrow_kind(upvar_id={:?}, upvar_capture={:?}, kind={:?})",
@ -584,29 +495,29 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
}
impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
fn consume(&mut self, cmt: &mc::Place<'tcx>,mode: euv::ConsumeMode) {
debug!("consume(cmt={:?},mode={:?})", cmt, mode);
self.adjust_upvar_borrow_kind_for_consume(cmt, mode);
fn consume(&mut self, place: &mc::Place<'tcx>,mode: euv::ConsumeMode) {
debug!("consume(place={:?},mode={:?})", place, mode);
self.adjust_upvar_borrow_kind_for_consume(place, mode);
}
fn borrow(&mut self, cmt: &mc::Place<'tcx>, bk: ty::BorrowKind) {
debug!("borrow(cmt={:?}, bk={:?})", cmt, bk);
fn borrow(&mut self, place: &mc::Place<'tcx>, bk: ty::BorrowKind) {
debug!("borrow(place={:?}, bk={:?})", place, bk);
match bk {
ty::ImmBorrow => {}
ty::UniqueImmBorrow => {
self.adjust_upvar_borrow_kind_for_unique(cmt);
self.adjust_upvar_borrow_kind_for_unique(place);
}
ty::MutBorrow => {
self.adjust_upvar_borrow_kind_for_mut(cmt);
self.adjust_upvar_borrow_kind_for_mut(place);
}
}
}
fn mutate(&mut self, assignee_cmt: &mc::Place<'tcx>) {
debug!("mutate(assignee_cmt={:?})", assignee_cmt);
fn mutate(&mut self, assignee_place: &mc::Place<'tcx>) {
debug!("mutate(assignee_place={:?})", assignee_place);
self.adjust_upvar_borrow_kind_for_mut(assignee_cmt);
self.adjust_upvar_borrow_kind_for_mut(assignee_place);
}
}

View File

@ -4,8 +4,7 @@ fn id<T>(t: T) -> T { t }
fn f<'r, T>(v: &'r T) -> Box<dyn FnMut() -> T + 'r> {
id(Box::new(|| *v))
//~^ ERROR E0373
//~| ERROR E0507
//~^ ERROR E0507
}
fn main() {

View File

@ -6,25 +6,6 @@ LL | fn f<'r, T>(v: &'r T) -> Box<dyn FnMut() -> T + 'r> {
LL | id(Box::new(|| *v))
| ^^ move occurs because `*v` has type `T`, which does not implement the `Copy` trait
error[E0373]: closure may outlive the current function, but it borrows `v`, which is owned by the current function
--> $DIR/issue-4335.rs:6:17
|
LL | id(Box::new(|| *v))
| ^^ - `v` is borrowed here
| |
| may outlive borrowed value `v`
|
note: closure is returned here
--> $DIR/issue-4335.rs:6:5
|
LL | id(Box::new(|| *v))
| ^^^^^^^^^^^^^^^^^^^
help: to force the closure to take ownership of `v` (and any other referenced variables), use the `move` keyword
|
LL | id(Box::new(move || *v))
| ^^^^^^^
error: aborting due to previous error
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0373, E0507.
For more information about an error, try `rustc --explain E0373`.
For more information about this error, try `rustc --explain E0507`.

View File

@ -9,7 +9,7 @@ note: first, the lifetime cannot outlive the lifetime `'_` as defined on the bod
|
LL | let _f = || {
| ^^
note: ...so that reference does not outlive borrowed content
note: ...so that closure can access `self`
--> $DIR/regions-addr-of-upvar-self.rs:10:41
|
LL | let p: &'static mut usize = &mut self.food;

View File

@ -2,7 +2,7 @@ error[E0525]: expected a closure that implements the `Fn` trait, but this closur
--> $DIR/unboxed-closures-infer-fn-once-move-from-projection.rs:14:13
|
LL | let c = || drop(y.0);
| ^^^^^^^^-^^^
| ^^^^^^^^---^
| | |
| | closure is `FnOnce` because it moves the variable `y` out of its environment
| this closure implements `FnOnce`, not `Fn`