mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-05 03:23:25 +00:00
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:
parent
a5b8a3088a
commit
1d53e43744
@ -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(¶m.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, ¶m.pat);
|
||||
self.walk_irrefutable_pat(¶m_place, ¶m.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
@ -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, ¶m.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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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`.
|
||||
|
@ -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;
|
||||
|
@ -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`
|
||||
|
Loading…
Reference in New Issue
Block a user