Remove rustc_mir dependency from rustc_borrowck

This commit is contained in:
Matthew Jasper 2019-06-29 17:36:46 +01:00
parent 4bb6b4a5ed
commit be085d7c0f
15 changed files with 229 additions and 2046 deletions

View File

@ -2954,7 +2954,6 @@ dependencies = [
"rustc 0.0.0",
"rustc_data_structures 0.0.0",
"rustc_errors 0.0.0",
"rustc_mir 0.0.0",
"syntax 0.0.0",
"syntax_pos 0.0.0",
]

View File

@ -1,6 +1,4 @@
use crate::ich::StableHashingContext;
use crate::hir::HirId;
use crate::util::nodemap::FxHashSet;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
StableHasherResult};
@ -18,7 +16,6 @@ impl_stable_hash_for!(enum self::SignalledError { SawSomeError, NoErrorsSeen });
#[derive(Debug, Default, RustcEncodable, RustcDecodable)]
pub struct BorrowCheckResult {
pub used_mut_nodes: FxHashSet<HirId>,
pub signalled_any_error: SignalledError,
}
@ -27,10 +24,8 @@ impl<'a> HashStable<StableHashingContext<'a>> for BorrowCheckResult {
hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) {
let BorrowCheckResult {
ref used_mut_nodes,
ref signalled_any_error,
} = *self;
used_mut_nodes.hash_stable(hcx, hasher);
signalled_any_error.hash_stable(hcx, hasher);
}
}

View File

@ -66,7 +66,6 @@ use crate::hir::def::{CtorOf, Res, DefKind, CtorKind};
use crate::ty::adjustment;
use crate::ty::{self, DefIdTree, Ty, TyCtxt};
use crate::ty::fold::TypeFoldable;
use crate::ty::layout::VariantIdx;
use crate::hir::{MutImmutable, MutMutable, PatKind};
use crate::hir::pat_util::EnumerateAndAdjustIterator;
@ -79,7 +78,6 @@ use std::borrow::Cow;
use std::fmt;
use std::hash::{Hash, Hasher};
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::indexed_vec::Idx;
use std::rc::Rc;
use crate::util::nodemap::ItemLocalSet;
@ -198,79 +196,6 @@ pub struct cmt_<'tcx> {
pub type cmt<'tcx> = Rc<cmt_<'tcx>>;
pub enum ImmutabilityBlame<'tcx> {
ImmLocal(hir::HirId),
ClosureEnv(LocalDefId),
LocalDeref(hir::HirId),
AdtFieldDeref(&'tcx ty::AdtDef, &'tcx ty::FieldDef)
}
impl<'tcx> cmt_<'tcx> {
fn resolve_field(&self, field_index: usize) -> Option<(&'tcx ty::AdtDef, &'tcx ty::FieldDef)>
{
let adt_def = match self.ty.sty {
ty::Adt(def, _) => def,
ty::Tuple(..) => return None,
// closures get `Categorization::Upvar` rather than `Categorization::Interior`
_ => bug!("interior cmt {:?} is not an ADT", self)
};
let variant_def = match self.cat {
Categorization::Downcast(_, variant_did) => {
adt_def.variant_with_id(variant_did)
}
_ => {
assert_eq!(adt_def.variants.len(), 1);
&adt_def.variants[VariantIdx::new(0)]
}
};
Some((adt_def, &variant_def.fields[field_index]))
}
pub fn immutability_blame(&self) -> Option<ImmutabilityBlame<'tcx>> {
match self.cat {
Categorization::Deref(ref base_cmt, BorrowedPtr(ty::ImmBorrow, _)) => {
// try to figure out where the immutable reference came from
match base_cmt.cat {
Categorization::Local(hir_id) =>
Some(ImmutabilityBlame::LocalDeref(hir_id)),
Categorization::Interior(ref base_cmt, InteriorField(field_index)) => {
base_cmt.resolve_field(field_index.0).map(|(adt_def, field_def)| {
ImmutabilityBlame::AdtFieldDeref(adt_def, field_def)
})
}
Categorization::Upvar(Upvar { id, .. }) => {
if let NoteClosureEnv(..) = self.note {
Some(ImmutabilityBlame::ClosureEnv(id.closure_expr_id))
} else {
None
}
}
_ => None
}
}
Categorization::Local(hir_id) => {
Some(ImmutabilityBlame::ImmLocal(hir_id))
}
Categorization::Rvalue(..) |
Categorization::Upvar(..) |
Categorization::Deref(_, UnsafePtr(..)) => {
// This should not be reachable up to inference limitations.
None
}
Categorization::Interior(ref base_cmt, _) |
Categorization::Downcast(ref base_cmt, _) |
Categorization::Deref(ref base_cmt, _) => {
base_cmt.immutability_blame()
}
Categorization::ThreadLocal(..) |
Categorization::StaticItem => {
// Do we want to do something here?
None
}
}
}
}
pub trait HirNode {
fn hir_id(&self) -> hir::HirId;
fn span(&self) -> Span;

View File

@ -1,11 +1,11 @@
[package]
authors = ["The Rust Project Developers"]
name = "rustc_borrowck"
name = "rustc_ast_borrowck"
version = "0.0.0"
edition = "2018"
[lib]
name = "rustc_borrowck"
name = "rustc_ast_borrowck"
path = "lib.rs"
test = false
doctest = false
@ -18,6 +18,5 @@ syntax_pos = { path = "../libsyntax_pos" }
# refers to the borrowck-specific graphviz adapter traits.
dot = { path = "../libgraphviz", package = "graphviz" }
rustc = { path = "../librustc" }
rustc_mir = { path = "../librustc_mir" }
errors = { path = "../librustc_errors", package = "rustc_errors" }
rustc_data_structures = { path = "../librustc_data_structures" }

View File

@ -7,8 +7,6 @@
// 3. assignments do not affect things loaned out as immutable
// 4. moves do not affect things loaned out in any way
use UseError::*;
use crate::borrowck::*;
use crate::borrowck::InteriorKind::{InteriorElement, InteriorField};
use rustc::middle::expr_use_visitor as euv;
@ -20,7 +18,6 @@ use rustc::ty::{self, TyCtxt, RegionKind};
use syntax_pos::Span;
use rustc::hir;
use rustc::hir::Node;
use rustc_mir::util::borrowck_errors::{BorrowckErrors, Origin};
use log::debug;
use std::rc::Rc;
@ -89,13 +86,12 @@ struct CheckLoanCtxt<'a, 'tcx> {
impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {
fn consume(&mut self,
consume_id: hir::HirId,
consume_span: Span,
_: Span,
cmt: &mc::cmt_<'tcx>,
mode: euv::ConsumeMode) {
debug!("consume(consume_id={}, cmt={:?}, mode={:?})",
consume_id, cmt, mode);
debug!("consume(consume_id={}, cmt={:?})", consume_id, cmt);
self.consume_common(consume_id.local_id, consume_span, cmt, mode);
self.consume_common(consume_id.local_id, cmt, mode);
}
fn matched_pat(&mut self,
@ -107,12 +103,9 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {
consume_pat: &hir::Pat,
cmt: &mc::cmt_<'tcx>,
mode: euv::ConsumeMode) {
debug!("consume_pat(consume_pat={:?}, cmt={:?}, mode={:?})",
consume_pat,
cmt,
mode);
debug!("consume_pat(consume_pat={:?}, cmt={:?})", consume_pat, cmt);
self.consume_common(consume_pat.hir_id.local_id, consume_pat.span, cmt, mode);
self.consume_common(consume_pat.hir_id.local_id, cmt, mode);
}
fn borrow(&mut self,
@ -129,11 +122,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {
bk, loan_cause);
if let Some(lp) = opt_loan_path(cmt) {
let moved_value_use_kind = match loan_cause {
euv::ClosureCapture(_) => MovedInCapture,
_ => MovedInUse,
};
self.check_if_path_is_moved(borrow_id.local_id, borrow_span, moved_value_use_kind, &lp);
self.check_if_path_is_moved(borrow_id.local_id, &lp);
}
self.check_for_conflicting_loans(borrow_id.local_id);
@ -143,7 +132,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {
fn mutate(&mut self,
assignment_id: hir::HirId,
assignment_span: Span,
_: Span,
assignee_cmt: &mc::cmt_<'tcx>,
mode: euv::MutateMode)
{
@ -157,23 +146,18 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {
// have to be *FULLY* initialized, but we still
// must be careful lest it contains derefs of
// pointers.
self.check_if_assigned_path_is_moved(assignee_cmt.hir_id.local_id,
assignment_span,
MovedInUse,
&lp);
self.check_if_assigned_path_is_moved(assignee_cmt.hir_id.local_id, &lp);
}
MutateMode::WriteAndRead => {
// In a case like `path += 1`, then path must be
// fully initialized, since we will read it before
// we write it.
self.check_if_path_is_moved(assignee_cmt.hir_id.local_id,
assignment_span,
MovedInUse,
&lp);
}
}
}
self.check_assignment(assignment_id.local_id, assignment_span, assignee_cmt);
self.check_assignment(assignment_id.local_id, assignee_cmt);
}
fn decl_without_init(&mut self, _id: hir::HirId, _span: Span) { }
@ -218,12 +202,6 @@ pub fn check_loans<'a, 'tcx>(
.consume_body(body);
}
#[derive(PartialEq)]
enum UseError<'tcx> {
UseOk,
UseWhileBorrowed(/*loan*/Rc<LoanPath<'tcx>>, /*loan*/Span)
}
fn compatible_borrow_kinds(borrow_kind1: ty::BorrowKind,
borrow_kind2: ty::BorrowKind)
-> bool {
@ -433,15 +411,9 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
return;
}
if let Some(yield_span) = self.bccx
.region_scope_tree
.yield_in_scope_for_expr(scope,
cmt.hir_id,
self.bccx.body)
if let Some(_) = self.bccx.region_scope_tree
.yield_in_scope_for_expr(scope, cmt.hir_id, self.bccx.body)
{
self.bccx.cannot_borrow_across_generator_yield(borrow_span,
yield_span,
Origin::Ast).emit();
self.bccx.signal_error();
}
}
@ -478,10 +450,11 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
}
}
pub fn report_error_if_loans_conflict(&self,
old_loan: &Loan<'tcx>,
new_loan: &Loan<'tcx>)
-> bool {
pub fn report_error_if_loans_conflict(
&self,
old_loan: &Loan<'tcx>,
new_loan: &Loan<'tcx>,
) -> bool {
//! Checks whether `old_loan` and `new_loan` can safely be issued
//! simultaneously.
@ -493,266 +466,87 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
assert!(self.bccx.region_scope_tree.scopes_intersect(old_loan.kill_scope,
new_loan.kill_scope));
let err_old_new = self.report_error_if_loan_conflicts_with_restriction(
old_loan, new_loan, old_loan, new_loan).err();
let err_new_old = self.report_error_if_loan_conflicts_with_restriction(
new_loan, old_loan, old_loan, new_loan).err();
match (err_old_new, err_new_old) {
(Some(mut err), None) | (None, Some(mut err)) => {
err.emit();
self.bccx.signal_error();
}
(Some(mut err_old), Some(mut err_new)) => {
err_old.emit();
self.bccx.signal_error();
err_new.cancel();
}
(None, None) => return true,
}
false
self.report_error_if_loan_conflicts_with_restriction(
old_loan, new_loan)
&& self.report_error_if_loan_conflicts_with_restriction(
new_loan, old_loan)
}
pub fn report_error_if_loan_conflicts_with_restriction(&self,
loan1: &Loan<'tcx>,
loan2: &Loan<'tcx>,
old_loan: &Loan<'tcx>,
new_loan: &Loan<'tcx>)
-> Result<(), DiagnosticBuilder<'a>> {
pub fn report_error_if_loan_conflicts_with_restriction(
&self,
loan1: &Loan<'tcx>,
loan2: &Loan<'tcx>,
) -> bool {
//! Checks whether the restrictions introduced by `loan1` would
//! prohibit `loan2`. Returns false if an error is reported.
//! prohibit `loan2`.
debug!("report_error_if_loan_conflicts_with_restriction(\
loan1={:?}, loan2={:?})",
loan1,
loan2);
if compatible_borrow_kinds(loan1.kind, loan2.kind) {
return Ok(());
return true;
}
let loan2_base_path = owned_ptr_base_path_rc(&loan2.loan_path);
for restr_path in &loan1.restricted_paths {
if *restr_path != loan2_base_path { continue; }
// If new_loan is something like `x.a`, and old_loan is something like `x.b`, we would
// normally generate a rather confusing message (in this case, for multiple mutable
// borrows):
//
// error: cannot borrow `x.b` as mutable more than once at a time
// note: previous borrow of `x.a` occurs here; the mutable borrow prevents
// subsequent moves, borrows, or modification of `x.a` until the borrow ends
//
// What we want to do instead is get the 'common ancestor' of the two borrow paths and
// use that for most of the message instead, giving is something like this:
//
// error: cannot borrow `x` as mutable more than once at a time
// note: previous borrow of `x` occurs here (through borrowing `x.a`); the mutable
// borrow prevents subsequent moves, borrows, or modification of `x` until the
// borrow ends
let common = new_loan.loan_path.common(&old_loan.loan_path);
let (nl, ol, new_loan_msg, old_loan_msg) = {
if new_loan.loan_path.has_fork(&old_loan.loan_path) && common.is_some() {
let nl = self.bccx.loan_path_to_string(&common.unwrap());
let ol = nl.clone();
let new_loan_msg = self.bccx.loan_path_to_string(&new_loan.loan_path);
let old_loan_msg = self.bccx.loan_path_to_string(&old_loan.loan_path);
(nl, ol, new_loan_msg, old_loan_msg)
} else {
(self.bccx.loan_path_to_string(&new_loan.loan_path),
self.bccx.loan_path_to_string(&old_loan.loan_path),
String::new(),
String::new())
}
};
let ol_pronoun = if new_loan.loan_path == old_loan.loan_path {
"it".to_string()
} else {
format!("`{}`", ol)
};
// We want to assemble all the relevant locations for the error.
//
// 1. Where did the new loan occur.
// - if due to closure creation, where was the variable used in closure?
// 2. Where did old loan occur.
// 3. Where does old loan expire.
let previous_end_span =
Some(self.tcx().sess.source_map().end_point(
old_loan.kill_scope.span(self.tcx(), &self.bccx.region_scope_tree)));
let mut err = match (new_loan.kind, old_loan.kind) {
(ty::MutBorrow, ty::MutBorrow) =>
self.bccx.cannot_mutably_borrow_multiply(
new_loan.span, &nl, &new_loan_msg, old_loan.span, &old_loan_msg,
previous_end_span, Origin::Ast),
(ty::UniqueImmBorrow, ty::UniqueImmBorrow) =>
self.bccx.cannot_uniquely_borrow_by_two_closures(
new_loan.span, &nl, old_loan.span, previous_end_span, Origin::Ast),
(ty::UniqueImmBorrow, _) =>
self.bccx.cannot_uniquely_borrow_by_one_closure(
new_loan.span, "closure", &nl, &new_loan_msg,
old_loan.span, &ol_pronoun, &old_loan_msg, previous_end_span, Origin::Ast),
(_, ty::UniqueImmBorrow) => {
let new_loan_str = &new_loan.kind.to_user_str();
self.bccx.cannot_reborrow_already_uniquely_borrowed(
new_loan.span, "closure", &nl, &new_loan_msg, new_loan_str,
old_loan.span, &old_loan_msg, previous_end_span, "", Origin::Ast)
}
(..) =>
self.bccx.cannot_reborrow_already_borrowed(
new_loan.span,
&nl, &new_loan_msg, &new_loan.kind.to_user_str(),
old_loan.span, &ol_pronoun, &old_loan.kind.to_user_str(), &old_loan_msg,
previous_end_span, Origin::Ast)
};
match new_loan.cause {
euv::ClosureCapture(span) => {
err.span_label(
span,
format!("borrow occurs due to use of `{}` in closure", nl));
}
_ => { }
}
match old_loan.cause {
euv::ClosureCapture(span) => {
err.span_label(
span,
format!("previous borrow occurs due to use of `{}` in closure",
ol));
}
_ => { }
}
return Err(err);
self.bccx.signal_error();
return false;
}
Ok(())
true
}
fn consume_common(&self,
id: hir::ItemLocalId,
span: Span,
cmt: &mc::cmt_<'tcx>,
mode: euv::ConsumeMode) {
fn consume_common(
&self,
id: hir::ItemLocalId,
cmt: &mc::cmt_<'tcx>,
mode: euv::ConsumeMode,
) {
if let Some(lp) = opt_loan_path(cmt) {
let moved_value_use_kind = match mode {
match mode {
euv::Copy => {
self.check_for_copy_of_frozen_path(id, span, &lp);
MovedInUse
self.check_for_copy_of_frozen_path(id, &lp);
}
euv::Move(_) => {
match self.move_data.kind_of_move_of_path(id, &lp) {
None => {
// Sometimes moves don't have a move kind;
// this either means that the original move
// was from something illegal to move,
// or was moved from referent of an unsafe
// pointer or something like that.
MovedInUse
}
Some(move_kind) => {
self.check_for_move_of_borrowed_path(id, span,
&lp, move_kind);
if move_kind == move_data::Captured {
MovedInCapture
} else {
MovedInUse
}
}
// Sometimes moves aren't from a move path;
// this either means that the original move
// was from something illegal to move,
// or was moved from referent of an unsafe
// pointer or something like that.
if self.move_data.is_move_path(id, &lp) {
self.check_for_move_of_borrowed_path(id, &lp);
}
}
};
self.check_if_path_is_moved(id, span, moved_value_use_kind, &lp);
}
self.check_if_path_is_moved(id, &lp);
}
}
fn check_for_copy_of_frozen_path(&self,
id: hir::ItemLocalId,
span: Span,
copy_path: &LoanPath<'tcx>) {
match self.analyze_restrictions_on_use(id, copy_path, ty::ImmBorrow) {
UseOk => { }
UseWhileBorrowed(loan_path, loan_span) => {
let desc = self.bccx.loan_path_to_string(copy_path);
self.bccx.cannot_use_when_mutably_borrowed(
span, &desc,
loan_span, &self.bccx.loan_path_to_string(&loan_path),
Origin::Ast)
.emit();
self.bccx.signal_error();
}
}
self.analyze_restrictions_on_use(id, copy_path, ty::ImmBorrow);
}
fn check_for_move_of_borrowed_path(&self,
id: hir::ItemLocalId,
span: Span,
move_path: &LoanPath<'tcx>,
move_kind: move_data::MoveKind) {
move_path: &LoanPath<'tcx>) {
// We want to detect if there are any loans at all, so we search for
// any loans incompatible with MutBorrrow, since all other kinds of
// loans are incompatible with that.
match self.analyze_restrictions_on_use(id, move_path, ty::MutBorrow) {
UseOk => { }
UseWhileBorrowed(loan_path, loan_span) => {
let mut err = match move_kind {
move_data::Captured => {
let mut err = self.bccx.cannot_move_into_closure(
span, &self.bccx.loan_path_to_string(move_path), Origin::Ast);
err.span_label(
loan_span,
format!("borrow of `{}` occurs here",
&self.bccx.loan_path_to_string(&loan_path))
);
err.span_label(
span,
"move into closure occurs here"
);
err
}
move_data::Declared |
move_data::MoveExpr |
move_data::MovePat => {
let desc = self.bccx.loan_path_to_string(move_path);
let mut err = self.bccx.cannot_move_when_borrowed(span, &desc, Origin::Ast);
err.span_label(
loan_span,
format!("borrow of `{}` occurs here",
&self.bccx.loan_path_to_string(&loan_path))
);
err.span_label(
span,
format!("move out of `{}` occurs here",
&self.bccx.loan_path_to_string(move_path))
);
err
}
};
err.emit();
self.bccx.signal_error();
}
}
self.analyze_restrictions_on_use(id, move_path, ty::MutBorrow);
}
pub fn analyze_restrictions_on_use(&self,
fn analyze_restrictions_on_use(&self,
expr_id: hir::ItemLocalId,
use_path: &LoanPath<'tcx>,
borrow_kind: ty::BorrowKind)
-> UseError<'tcx> {
borrow_kind: ty::BorrowKind) {
debug!("analyze_restrictions_on_use(expr_id={:?}, use_path={:?})",
expr_id, use_path);
let mut ret = UseOk;
let scope = region::Scope {
id: expr_id,
data: region::ScopeData::Node
@ -760,38 +554,28 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
self.each_in_scope_loan_affecting_path(
scope, use_path, |loan| {
if !compatible_borrow_kinds(loan.kind, borrow_kind) {
ret = UseWhileBorrowed(loan.loan_path.clone(), loan.span);
self.bccx.signal_error();
false
} else {
true
}
});
return ret;
}
/// Reports an error if `expr` (which should be a path)
/// is using a moved/uninitialized value
fn check_if_path_is_moved(&self,
id: hir::ItemLocalId,
span: Span,
use_kind: MovedValueUseKind,
lp: &Rc<LoanPath<'tcx>>) {
debug!("check_if_path_is_moved(id={:?}, use_kind={:?}, lp={:?})",
id, use_kind, lp);
debug!("check_if_path_is_moved(id={:?}, lp={:?})", id, lp);
// FIXME: if you find yourself tempted to cut and paste
// the body below and then specializing the error reporting,
// consider refactoring this instead!
let base_lp = owned_ptr_base_path_rc(lp);
self.move_data.each_move_of(id, &base_lp, |the_move, moved_lp| {
self.bccx.report_use_of_moved_value(
span,
use_kind,
&lp,
the_move,
moved_lp);
self.move_data.each_move_of(id, &base_lp, |_, _| {
self.bccx.signal_error();
false
});
}
@ -820,8 +604,6 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
/// ```
fn check_if_assigned_path_is_moved(&self,
id: hir::ItemLocalId,
span: Span,
use_kind: MovedValueUseKind,
lp: &Rc<LoanPath<'tcx>>)
{
match lp.kind {
@ -830,8 +612,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
}
LpDowncast(ref lp_base, _) => {
// assigning to `(P->Variant).f` is ok if assigning to `P` is ok
self.check_if_assigned_path_is_moved(id, span,
use_kind, lp_base);
self.check_if_assigned_path_is_moved(id, lp_base);
}
LpExtend(ref lp_base, _, LpInterior(_, InteriorField(_))) => {
match lp_base.to_type().sty {
@ -845,9 +626,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
let loan_path = owned_ptr_base_path_rc(lp_base);
self.move_data.each_move_of(id, &loan_path, |_, _| {
self.bccx
.report_partial_reinitialization_of_uninitialized_structure(
span,
&loan_path);
.signal_error();
false
});
return;
@ -856,21 +635,19 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
}
// assigning to `P.f` is ok if assigning to `P` is ok
self.check_if_assigned_path_is_moved(id, span,
use_kind, lp_base);
self.check_if_assigned_path_is_moved(id, lp_base);
}
LpExtend(ref lp_base, _, LpInterior(_, InteriorElement)) |
LpExtend(ref lp_base, _, LpDeref(_)) => {
// assigning to `P[i]` requires `P` is initialized
// assigning to `(*P)` requires `P` is initialized
self.check_if_path_is_moved(id, span, use_kind, lp_base);
self.check_if_path_is_moved(id, lp_base);
}
}
}
fn check_assignment(&self,
assignment_id: hir::ItemLocalId,
assignment_span: Span,
assignee_cmt: &mc::cmt_<'tcx>) {
debug!("check_assignment(assignee_cmt={:?})", assignee_cmt);
@ -880,8 +657,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
id: assignment_id,
data: region::ScopeData::Node
};
self.each_in_scope_loan_affecting_path(scope, &loan_path, |loan| {
self.report_illegal_mutation(assignment_span, &loan_path, loan);
self.each_in_scope_loan_affecting_path(scope, &loan_path, |_| {
self.bccx.signal_error();
false
});
}
@ -889,30 +666,15 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
// Check for reassignments to (immutable) local variables. This
// needs to be done here instead of in check_loans because we
// depend on move data.
if let Categorization::Local(hir_id) = assignee_cmt.cat {
if let Categorization::Local(_) = assignee_cmt.cat {
let lp = opt_loan_path(assignee_cmt).unwrap();
self.move_data.each_assignment_of(assignment_id, &lp, |assign| {
if assignee_cmt.mutbl.is_mutable() {
self.bccx.used_mut_nodes.borrow_mut().insert(hir_id);
} else {
self.bccx.report_reassigned_immutable_variable(
assignment_span,
&lp,
assign);
self.move_data.each_assignment_of(assignment_id, &lp, |_| {
if !assignee_cmt.mutbl.is_mutable() {
self.bccx.signal_error();
}
false
});
return
}
}
pub fn report_illegal_mutation(&self,
span: Span,
loan_path: &LoanPath<'tcx>,
loan: &Loan<'_>) {
self.bccx.cannot_assign_to_borrowed(
span, loan.span, &self.bccx.loan_path_to_string(loan_path), Origin::Ast)
.emit();
self.bccx.signal_error();
}
}

View File

@ -1,10 +1,7 @@
//! Computes moves.
use crate::borrowck::*;
use crate::borrowck::gather_loans::move_error::MovePlace;
use crate::borrowck::gather_loans::move_error::{MoveError, MoveErrorCollector};
use crate::borrowck::move_data::*;
use rustc::middle::expr_use_visitor as euv;
use rustc::middle::mem_categorization as mc;
use rustc::middle::mem_categorization::Categorization;
use rustc::middle::mem_categorization::InteriorOffsetKind as Kind;
@ -12,56 +9,11 @@ use rustc::ty::{self, Ty};
use std::rc::Rc;
use syntax_pos::Span;
use rustc::hir::*;
use rustc::hir::Node;
use log::debug;
struct GatherMoveInfo<'c, 'tcx> {
id: hir::ItemLocalId,
kind: MoveKind,
cmt: &'c mc::cmt_<'tcx>,
span_path_opt: Option<MovePlace<'tcx>>,
}
/// Represents the kind of pattern
#[derive(Debug, Clone, Copy)]
pub enum PatternSource<'tcx> {
MatchExpr(&'tcx Expr),
LetDecl(&'tcx Local),
Other,
}
/// Analyzes the context where the pattern appears to determine the
/// kind of hint we want to give. In particular, if the pattern is in a `match`
/// or nested within other patterns, we want to suggest a `ref` binding:
///
/// let (a, b) = v[0]; // like the `a` and `b` patterns here
/// match v[0] { a => ... } // or the `a` pattern here
///
/// But if the pattern is the outermost pattern in a `let`, we would rather
/// suggest that the author add a `&` to the initializer:
///
/// let x = v[0]; // suggest `&v[0]` here
///
/// In this latter case, this function will return `PatternSource::LetDecl`
/// with a reference to the let
fn get_pattern_source<'tcx>(tcx: TyCtxt<'tcx>, pat: &Pat) -> PatternSource<'tcx> {
let parent = tcx.hir().get_parent_node(pat.hir_id);
match tcx.hir().get(parent) {
Node::Expr(ref e) => {
// the enclosing expression must be a `match` or something else
assert!(match e.node {
ExprKind::Match(..) => true,
_ => return PatternSource::Other,
});
PatternSource::MatchExpr(e)
}
Node::Local(local) => PatternSource::LetDecl(local),
_ => return PatternSource::Other,
}
}
pub fn gather_decl<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
@ -69,82 +21,54 @@ pub fn gather_decl<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
var_id: hir::HirId,
var_ty: Ty<'tcx>) {
let loan_path = Rc::new(LoanPath::new(LpVar(var_id), var_ty));
move_data.add_move(bccx.tcx, loan_path, var_id.local_id, Declared);
move_data.add_move(bccx.tcx, loan_path, var_id.local_id);
}
pub fn gather_move_from_expr<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
move_data: &MoveData<'tcx>,
move_error_collector: &mut MoveErrorCollector<'tcx>,
move_expr_id: hir::ItemLocalId,
cmt: &mc::cmt_<'tcx>,
move_reason: euv::MoveReason) {
let kind = match move_reason {
euv::DirectRefMove | euv::PatBindingMove => MoveExpr,
euv::CaptureMove => Captured
};
cmt: &mc::cmt_<'tcx>) {
let move_info = GatherMoveInfo {
id: move_expr_id,
kind,
cmt,
span_path_opt: None,
};
gather_move(bccx, move_data, move_error_collector, move_info);
gather_move(bccx, move_data, move_info);
}
pub fn gather_move_from_pat<'a, 'c, 'tcx>(
bccx: &BorrowckCtxt<'a, 'tcx>,
move_data: &MoveData<'tcx>,
move_error_collector: &mut MoveErrorCollector<'tcx>,
move_pat: &hir::Pat,
cmt: &'c mc::cmt_<'tcx>,
) {
let source = get_pattern_source(bccx.tcx,move_pat);
let pat_span_path_opt = match move_pat.node {
PatKind::Binding(_, _, ident, _) => {
Some(MovePlace {
span: move_pat.span,
name: ident.name,
pat_source: source,
})
}
_ => None,
};
let move_info = GatherMoveInfo {
id: move_pat.hir_id.local_id,
kind: MovePat,
cmt,
span_path_opt: pat_span_path_opt,
};
debug!("gather_move_from_pat: move_pat={:?} source={:?}",
move_pat,
source);
debug!("gather_move_from_pat: move_pat={:?}", move_pat);
gather_move(bccx, move_data, move_error_collector, move_info);
gather_move(bccx, move_data, move_info);
}
fn gather_move<'a, 'c, 'tcx>(
bccx: &BorrowckCtxt<'a, 'tcx>,
move_data: &MoveData<'tcx>,
move_error_collector: &mut MoveErrorCollector<'tcx>,
move_info: GatherMoveInfo<'c, 'tcx>,
) {
debug!("gather_move(move_id={:?}, cmt={:?})",
move_info.id, move_info.cmt);
let potentially_illegal_move = check_and_get_illegal_move_origin(bccx, move_info.cmt);
if let Some(illegal_move_origin) = potentially_illegal_move {
debug!("illegal_move_origin={:?}", illegal_move_origin);
let error = MoveError::with_move_info(Rc::new(illegal_move_origin),
move_info.span_path_opt);
move_error_collector.add_error(error);
if let Some(_) = potentially_illegal_move {
bccx.signal_error();
return;
}
match opt_loan_path(&move_info.cmt) {
Some(loan_path) => {
move_data.add_move(bccx.tcx, loan_path,
move_info.id, move_info.kind);
move_info.id);
}
None => {
// move from rvalue or raw pointer, hence ok

View File

@ -3,21 +3,17 @@
use crate::borrowck::*;
use rustc::hir::HirId;
use rustc::middle::expr_use_visitor as euv;
use rustc::middle::mem_categorization as mc;
use rustc::middle::mem_categorization::Categorization;
use rustc::middle::region;
use rustc::ty;
use syntax_pos::Span;
use log::debug;
type R = Result<(),()>;
pub fn guarantee_lifetime<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
item_scope: region::Scope,
span: Span,
cause: euv::LoanCause,
cmt: &'a mc::cmt_<'tcx>,
loan_region: ty::Region<'tcx>)
-> Result<(),()> {
@ -26,12 +22,7 @@ pub fn guarantee_lifetime<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
//! and is scope of `cmt` otherwise.
debug!("guarantee_lifetime(cmt={:?}, loan_region={:?})",
cmt, loan_region);
let ctxt = GuaranteeLifetimeContext {bccx: bccx,
item_scope,
span,
cause,
loan_region,
cmt_original: cmt};
let ctxt = GuaranteeLifetimeContext { bccx, item_scope, loan_region };
ctxt.check(cmt, None)
}
@ -44,10 +35,7 @@ struct GuaranteeLifetimeContext<'a, 'tcx> {
// the scope of the function body for the enclosing item
item_scope: region::Scope,
span: Span,
cause: euv::LoanCause,
loan_region: ty::Region<'tcx>,
cmt_original: &'a mc::cmt_<'tcx>
}
impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> {
@ -85,7 +73,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> {
//! Reports an error if `loan_region` is larger than `max_scope`
if !self.bccx.is_subregion_of(self.loan_region, max_scope) {
Err(self.report_error(err_out_of_scope(max_scope, self.loan_region, self.cause)))
Err(self.bccx.signal_error())
} else {
Ok(())
}
@ -122,11 +110,4 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> {
}
}
}
fn report_error(&self, code: bckerr_code<'tcx>) {
self.bccx.report(BckError { cmt: self.cmt_original,
span: self.span,
cause: BorrowViolation(self.cause),
code: code });
}
}

View File

@ -23,7 +23,6 @@ use restrictions::RestrictionResult;
mod lifetime;
mod restrictions;
mod gather_moves;
mod move_error;
pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
body: hir::BodyId)
@ -38,7 +37,6 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
data: region::ScopeData::Node
},
move_data: MoveData::default(),
move_error_collector: move_error::MoveErrorCollector::new(),
};
let rvalue_promotable_map = bccx.tcx.rvalue_promotable_map(def_id);
@ -51,7 +49,6 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
Some(rvalue_promotable_map))
.consume_body(bccx.body);
glcx.report_potential_errors();
let GatherLoanCtxt { all_loans, move_data, .. } = glcx;
(all_loans, move_data)
}
@ -59,7 +56,6 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
struct GatherLoanCtxt<'a, 'tcx> {
bccx: &'a BorrowckCtxt<'a, 'tcx>,
move_data: move_data::MoveData<'tcx>,
move_error_collector: move_error::MoveErrorCollector<'tcx>,
all_loans: Vec<Loan<'tcx>>,
/// `item_ub` is used as an upper-bound on the lifetime whenever we
/// ask for the scope of an expression categorized as an upvar.
@ -76,10 +72,10 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> {
consume_id, cmt, mode);
match mode {
euv::Move(move_reason) => {
euv::Move(_) => {
gather_moves::gather_move_from_expr(
self.bccx, &self.move_data, &mut self.move_error_collector,
consume_id.local_id, cmt, move_reason);
self.bccx, &self.move_data,
consume_id.local_id, cmt);
}
euv::Copy => { }
}
@ -110,13 +106,13 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> {
}
gather_moves::gather_move_from_pat(
self.bccx, &self.move_data, &mut self.move_error_collector,
self.bccx, &self.move_data,
consume_pat, cmt);
}
fn borrow(&mut self,
borrow_id: hir::HirId,
borrow_span: Span,
_: Span,
cmt: &mc::cmt_<'tcx>,
loan_region: ty::Region<'tcx>,
bk: ty::BorrowKind,
@ -128,11 +124,9 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> {
bk, loan_cause);
self.guarantee_valid(borrow_id.local_id,
borrow_span,
cmt,
bk,
loan_region,
loan_cause);
loan_region);
}
fn mutate(&mut self,
@ -174,8 +168,6 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> {
/// Implements the A-* rules in README.md.
fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
borrow_span: Span,
loan_cause: AliasableViolationKind,
cmt: &mc::cmt_<'tcx>,
req_kind: ty::BorrowKind)
-> Result<(),()> {
@ -198,13 +190,9 @@ fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
// user knows what they're doing in these cases.
Ok(())
}
(mc::Aliasability::FreelyAliasable(alias_cause), ty::UniqueImmBorrow) |
(mc::Aliasability::FreelyAliasable(alias_cause), ty::MutBorrow) => {
bccx.report_aliasability_violation(
borrow_span,
loan_cause,
alias_cause,
cmt);
(mc::Aliasability::FreelyAliasable(_), ty::UniqueImmBorrow) |
(mc::Aliasability::FreelyAliasable(_), ty::MutBorrow) => {
bccx.signal_error();
Err(())
}
(..) => {
@ -215,13 +203,10 @@ fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
/// Implements the M-* rules in README.md.
fn check_mutability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
borrow_span: Span,
cause: AliasableViolationKind,
cmt: &mc::cmt_<'tcx>,
req_kind: ty::BorrowKind)
-> Result<(),()> {
debug!("check_mutability(cause={:?} cmt={:?} req_kind={:?}",
cause, cmt, req_kind);
debug!("check_mutability(cmt={:?} req_kind={:?}", cmt, req_kind);
match req_kind {
ty::UniqueImmBorrow | ty::ImmBorrow => {
match cmt.mutbl {
@ -239,10 +224,7 @@ fn check_mutability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
ty::MutBorrow => {
// Only mutable data can be lent as mutable.
if !cmt.mutbl.is_mutable() {
Err(bccx.report(BckError { span: borrow_span,
cause,
cmt,
code: err_mutbl }))
Err(bccx.signal_error())
} else {
Ok(())
}
@ -268,26 +250,18 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
// mutable - this is checked in check_loans.
} else {
// Check that we don't allow assignments to non-mutable data.
if check_mutability(self.bccx, assignment_span, MutabilityViolation,
cmt, ty::MutBorrow).is_err() {
if check_mutability(self.bccx, cmt, ty::MutBorrow).is_err() {
return; // reported an error, no sense in reporting more.
}
}
// Check that we don't allow assignments to aliasable data
if check_aliasability(self.bccx, assignment_span, MutabilityViolation,
cmt, ty::MutBorrow).is_err() {
if check_aliasability(self.bccx, cmt, ty::MutBorrow).is_err() {
return; // reported an error, no sense in reporting more.
}
match opt_lp {
Some(lp) => {
if let Categorization::Local(..) = cmt.cat {
// Only re-assignments to locals require it to be
// mutable - this is checked in check_loans.
} else {
self.mark_loan_path_as_mutated(&lp);
}
gather_moves::gather_assignment(self.bccx, &self.move_data,
assignment_id.local_id,
assignment_span,
@ -306,11 +280,9 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
/// `req_loan_map`.
fn guarantee_valid(&mut self,
borrow_id: hir::ItemLocalId,
borrow_span: Span,
cmt: &mc::cmt_<'tcx>,
req_kind: ty::BorrowKind,
loan_region: ty::Region<'tcx>,
cause: euv::LoanCause) {
loan_region: ty::Region<'tcx>) {
debug!("guarantee_valid(borrow_id={:?}, cmt={:?}, \
req_mutbl={:?}, loan_region={:?})",
borrow_id,
@ -326,27 +298,23 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
// Check that the lifetime of the borrow does not exceed
// the lifetime of the data being borrowed.
if lifetime::guarantee_lifetime(self.bccx, self.item_ub,
borrow_span, cause, cmt, loan_region).is_err() {
if lifetime::guarantee_lifetime(self.bccx, self.item_ub, cmt, loan_region).is_err() {
return; // reported an error, no sense in reporting more.
}
// Check that we don't allow mutable borrows of non-mutable data.
if check_mutability(self.bccx, borrow_span, BorrowViolation(cause),
cmt, req_kind).is_err() {
if check_mutability(self.bccx, cmt, req_kind).is_err() {
return; // reported an error, no sense in reporting more.
}
// Check that we don't allow mutable borrows of aliasable data.
if check_aliasability(self.bccx, borrow_span, BorrowViolation(cause),
cmt, req_kind).is_err() {
if check_aliasability(self.bccx, cmt, req_kind).is_err() {
return; // reported an error, no sense in reporting more.
}
// Compute the restrictions that are required to enforce the
// loan is safe.
let restr = restrictions::compute_restrictions(
self.bccx, borrow_span, cause, &cmt, loan_region);
let restr = restrictions::compute_restrictions(self.bccx, &cmt, loan_region);
debug!("guarantee_valid(): restrictions={:?}", restr);
@ -395,19 +363,13 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
let kill_scope = self.compute_kill_scope(loan_scope, &loan_path);
debug!("kill_scope = {:?}", kill_scope);
if req_kind == ty::MutBorrow {
self.mark_loan_path_as_mutated(&loan_path);
}
Loan {
index: self.all_loans.len(),
loan_path,
kind: req_kind,
gen_scope,
kill_scope,
span: borrow_span,
restricted_paths,
cause,
}
}
};
@ -419,70 +381,6 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
// let loan_gen_scope = loan.gen_scope;
// let loan_kill_scope = loan.kill_scope;
self.all_loans.push(loan);
// if loan_gen_scope != borrow_id {
// FIXME(https://github.com/rust-lang/rfcs/issues/811) Nested method calls
//
// Typically, the scope of the loan includes the point at
// which the loan is originated. This
// This is a subtle case. See the test case
// <compile-fail/borrowck-bad-nested-calls-free.rs>
// to see what we are guarding against.
//let restr = restrictions::compute_restrictions(
// self.bccx, borrow_span, cmt, RESTR_EMPTY);
//let loan = {
// Loan {
// index: self.all_loans.len(),
// loan_path,
// cmt,
// mutbl: ConstMutability,
// gen_scope: borrow_id,
// kill_scope,
// span: borrow_span,
// restrictions,
// }
// }
}
pub fn mark_loan_path_as_mutated(&self, loan_path: &LoanPath<'_>) {
//! For mutable loans of content whose mutability derives
//! from a local variable, mark the mutability decl as necessary.
let mut wrapped_path = Some(loan_path);
let mut through_borrow = false;
while let Some(current_path) = wrapped_path {
wrapped_path = match current_path.kind {
LpVar(hir_id) => {
if !through_borrow {
self.bccx.used_mut_nodes.borrow_mut().insert(hir_id);
}
None
}
LpUpvar(ty::UpvarId{ var_path: ty::UpvarPath { hir_id }, closure_expr_id: _ }) => {
self.bccx.used_mut_nodes.borrow_mut().insert(hir_id);
None
}
LpExtend(ref base, mc::McInherited, LpDeref(pointer_kind)) |
LpExtend(ref base, mc::McDeclared, LpDeref(pointer_kind)) => {
if pointer_kind != mc::Unique {
through_borrow = true;
}
Some(base)
}
LpDowncast(ref base, _) |
LpExtend(ref base, mc::McInherited, _) |
LpExtend(ref base, mc::McDeclared, _) => {
Some(base)
}
LpExtend(_, mc::McImmutable, _) => {
// Nothing to do.
None
}
}
}
}
pub fn compute_gen_scope(&self,
@ -532,8 +430,4 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
loan_scope
}
}
pub fn report_potential_errors(&self) {
self.move_error_collector.report_potential_errors(self.bccx);
}
}

View File

@ -1,186 +0,0 @@
use crate::borrowck::BorrowckCtxt;
use rustc::middle::mem_categorization as mc;
use rustc::middle::mem_categorization::Categorization;
use rustc::middle::mem_categorization::NoteClosureEnv;
use rustc::middle::mem_categorization::InteriorOffsetKind as Kind;
use rustc::ty;
use rustc_mir::util::borrowck_errors::{BorrowckErrors, Origin};
use syntax::ast;
use syntax_pos;
use errors::{DiagnosticBuilder, Applicability};
use crate::borrowck::gather_loans::gather_moves::PatternSource;
use log::debug;
pub struct MoveErrorCollector<'tcx> {
errors: Vec<MoveError<'tcx>>
}
impl<'tcx> MoveErrorCollector<'tcx> {
pub fn new() -> MoveErrorCollector<'tcx> {
MoveErrorCollector {
errors: Vec::new()
}
}
pub fn add_error(&mut self, error: MoveError<'tcx>) {
self.errors.push(error);
}
pub fn report_potential_errors<'a>(&self, bccx: &BorrowckCtxt<'a, 'tcx>) {
report_move_errors(bccx, &self.errors)
}
}
pub struct MoveError<'tcx> {
move_from: mc::cmt<'tcx>,
move_to: Option<MovePlace<'tcx>>
}
impl<'tcx> MoveError<'tcx> {
pub fn with_move_info(move_from: mc::cmt<'tcx>,
move_to: Option<MovePlace<'tcx>>)
-> MoveError<'tcx> {
MoveError {
move_from,
move_to,
}
}
}
#[derive(Clone)]
pub struct MovePlace<'tcx> {
pub span: syntax_pos::Span,
pub name: ast::Name,
pub pat_source: PatternSource<'tcx>,
}
pub struct GroupedMoveErrors<'tcx> {
move_from: mc::cmt<'tcx>,
move_to_places: Vec<MovePlace<'tcx>>
}
fn report_move_errors<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, errors: &[MoveError<'tcx>]) {
let grouped_errors = group_errors_with_same_origin(errors);
for error in &grouped_errors {
let mut err = report_cannot_move_out_of(bccx, error.move_from.clone());
let mut is_first_note = true;
match error.move_to_places.get(0) {
Some(&MovePlace { pat_source: PatternSource::LetDecl(ref e), .. }) => {
// ignore patterns that are found at the top-level of a `let`;
// see `get_pattern_source()` for details
let initializer =
e.init.as_ref().expect("should have an initializer to get an error");
if let Ok(snippet) = bccx.tcx.sess.source_map().span_to_snippet(initializer.span) {
err.span_suggestion(
initializer.span,
"consider using a reference instead",
format!("&{}", snippet),
Applicability::MaybeIncorrect // using a reference may not be the right fix
);
}
}
_ => {
for move_to in &error.move_to_places {
err = note_move_destination(err, move_to.span, move_to.name, is_first_note);
is_first_note = false;
}
}
}
if let NoteClosureEnv(upvar_id) = error.move_from.note {
err.span_label(bccx.tcx.hir().span(upvar_id.var_path.hir_id),
"captured outer variable");
}
err.emit();
bccx.signal_error();
}
}
fn group_errors_with_same_origin<'tcx>(errors: &[MoveError<'tcx>])
-> Vec<GroupedMoveErrors<'tcx>> {
let mut grouped_errors = Vec::new();
for error in errors {
append_to_grouped_errors(&mut grouped_errors, error)
}
return grouped_errors;
fn append_to_grouped_errors<'tcx>(grouped_errors: &mut Vec<GroupedMoveErrors<'tcx>>,
error: &MoveError<'tcx>) {
let move_from_id = error.move_from.hir_id;
debug!("append_to_grouped_errors(move_from_id={:?})", move_from_id);
let move_to = if error.move_to.is_some() {
vec![error.move_to.clone().unwrap()]
} else {
Vec::new()
};
for ge in &mut *grouped_errors {
if move_from_id == ge.move_from.hir_id && error.move_to.is_some() {
debug!("appending move_to to list");
ge.move_to_places.extend(move_to);
return
}
}
debug!("found a new move from location");
grouped_errors.push(GroupedMoveErrors {
move_from: error.move_from.clone(),
move_to_places: move_to
})
}
}
// (keep in sync with gather_moves::check_and_get_illegal_move_origin )
fn report_cannot_move_out_of<'a, 'tcx>(bccx: &'a BorrowckCtxt<'a, 'tcx>,
move_from: mc::cmt<'tcx>)
-> DiagnosticBuilder<'a> {
match move_from.cat {
Categorization::Deref(_, mc::BorrowedPtr(..)) |
Categorization::Deref(_, mc::UnsafePtr(..)) |
Categorization::Deref(_, mc::Unique) |
Categorization::ThreadLocal(..) |
Categorization::StaticItem => {
bccx.cannot_move_out_of(
move_from.span, &move_from.descriptive_string(bccx.tcx), Origin::Ast)
}
Categorization::Interior(ref b, mc::InteriorElement(ik)) => {
bccx.cannot_move_out_of_interior_noncopy(
move_from.span, b.ty, Some(ik == Kind::Index), Origin::Ast)
}
Categorization::Downcast(ref b, _) |
Categorization::Interior(ref b, mc::InteriorField(_)) => {
match b.ty.sty {
ty::Adt(def, _) if def.has_dtor(bccx.tcx) => {
bccx.cannot_move_out_of_interior_of_drop(
move_from.span, b.ty, Origin::Ast)
}
_ => {
span_bug!(move_from.span, "this path should not cause illegal move");
}
}
}
Categorization::Rvalue(..) |
Categorization::Local(..) |
Categorization::Upvar(..) => {
span_bug!(move_from.span, "this path should not cause illegal move");
}
}
}
fn note_move_destination(mut err: DiagnosticBuilder<'_>,
move_to_span: syntax_pos::Span,
pat_name: ast::Name,
is_first_note: bool) -> DiagnosticBuilder<'_> {
if is_first_note {
err.span_label(
move_to_span,
format!("hint: to prevent move, use `ref {0}` or `ref mut {0}`",
pat_name));
err
} else {
err.span_label(move_to_span,
format!("...and here (use `ref {0}` or `ref mut {0}`)",
pat_name));
err
}
}

View File

@ -1,11 +1,9 @@
//! Computes the restrictions that result from a borrow.
use crate::borrowck::*;
use rustc::middle::expr_use_visitor as euv;
use rustc::middle::mem_categorization as mc;
use rustc::middle::mem_categorization::Categorization;
use rustc::ty;
use syntax_pos::Span;
use log::debug;
use crate::borrowck::ToInteriorKind;
@ -19,17 +17,10 @@ pub enum RestrictionResult<'tcx> {
}
pub fn compute_restrictions<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
span: Span,
cause: euv::LoanCause,
cmt: &mc::cmt_<'tcx>,
loan_region: ty::Region<'tcx>)
-> RestrictionResult<'tcx> {
let ctxt = RestrictionsContext {
bccx,
span,
cause,
loan_region,
};
let ctxt = RestrictionsContext { bccx, loan_region };
ctxt.restrict(cmt)
}
@ -39,9 +30,7 @@ pub fn compute_restrictions<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
struct RestrictionsContext<'a, 'tcx> {
bccx: &'a BorrowckCtxt<'a, 'tcx>,
span: Span,
loan_region: ty::Region<'tcx>,
cause: euv::LoanCause,
}
impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
@ -149,13 +138,7 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
mc::BorrowedPtr(bk, lt) => {
// R-Deref-[Mut-]Borrowed
if !self.bccx.is_subregion_of(self.loan_region, lt) {
self.bccx.report(
BckError {
span: self.span,
cause: BorrowViolation(self.cause),
cmt: &cmt_base,
code: err_borrowed_pointer_too_short(
self.loan_region, lt)});
self.bccx.signal_error();
return RestrictionResult::Safe;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,6 @@
//! Data structures used for tracking moves. Please see the extensive
//! comments in the section "Moves and initialization" in `README.md`.
pub use MoveKind::*;
use crate::dataflow::{DataFlowContext, BitwiseOperator, DataFlowOperator, KillFrom};
use crate::borrowck::*;
@ -101,13 +99,6 @@ pub struct MovePath<'tcx> {
pub next_sibling: MovePathIndex,
}
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum MoveKind {
Declared, // When declared, variables start out "moved".
MoveExpr, // Expression or binding that moves a variable
MovePat, // By-move binding
Captured // Closure creation that moves a value
}
#[derive(Copy, Clone)]
pub struct Move {
@ -117,9 +108,6 @@ pub struct Move {
/// ID of node that is doing the move.
pub id: hir::ItemLocalId,
/// Kind of move, for error messages.
pub kind: MoveKind,
/// Next node in linked list of moves from `path`, or `InvalidMoveIndex`
pub next_move: MoveIndex
}
@ -315,7 +303,6 @@ impl MoveData<'tcx> {
tcx: TyCtxt<'tcx>,
orig_lp: Rc<LoanPath<'tcx>>,
id: hir::ItemLocalId,
kind: MoveKind,
) {
// Moving one union field automatically moves all its fields. Also move siblings of
// all parent union fields, moves do not propagate upwards automatically.
@ -331,7 +318,7 @@ impl MoveData<'tcx> {
let sibling_lp_kind =
LpExtend(base_lp.clone(), mutbl, LpInterior(opt_variant_id, field));
let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, tcx.types.err));
self.add_move_helper(tcx, sibling_lp, id, kind);
self.add_move_helper(tcx, sibling_lp, id);
}
}
}
@ -339,7 +326,7 @@ impl MoveData<'tcx> {
lp = base_lp.clone();
}
self.add_move_helper(tcx, orig_lp, id, kind);
self.add_move_helper(tcx, orig_lp, id);
}
fn add_move_helper(
@ -347,12 +334,8 @@ impl MoveData<'tcx> {
tcx: TyCtxt<'tcx>,
lp: Rc<LoanPath<'tcx>>,
id: hir::ItemLocalId,
kind: MoveKind,
) {
debug!("add_move(lp={:?}, id={:?}, kind={:?})",
lp,
id,
kind);
debug!("add_move(lp={:?}, id={:?})", lp, id);
let path_index = self.move_path(tcx, lp);
let move_index = MoveIndex(self.moves.borrow().len());
@ -363,7 +346,6 @@ impl MoveData<'tcx> {
self.moves.borrow_mut().push(Move {
path: path_index,
id,
kind,
next_move,
});
}
@ -611,19 +593,16 @@ impl<'tcx> FlowedMoveData<'tcx> {
}
}
pub fn kind_of_move_of_path(&self,
id: hir::ItemLocalId,
loan_path: &Rc<LoanPath<'tcx>>)
-> Option<MoveKind> {
pub fn is_move_path(&self, id: hir::ItemLocalId, loan_path: &Rc<LoanPath<'tcx>>) -> bool {
//! Returns the kind of a move of `loan_path` by `id`, if one exists.
let mut ret = None;
let mut ret = false;
if let Some(loan_path_index) = self.move_data.path_map.borrow().get(&*loan_path) {
self.dfcx_moves.each_gen_bit(id, |move_index| {
let the_move = self.move_data.moves.borrow();
let the_move = (*the_move)[move_index];
if the_move.path == *loan_path_index {
ret = Some(the_move.kind);
ret = true;
false
} else {
true

View File

@ -1 +0,0 @@
#![allow(non_snake_case)]

View File

@ -12,8 +12,8 @@ use rustc::session::config::Input;
use rustc::ty::{self, TyCtxt};
use rustc::util::common::ErrorReported;
use rustc_interface::util::ReplaceBodyWithLoop;
use rustc_borrowck as borrowck;
use rustc_borrowck::graphviz as borrowck_dot;
use rustc_ast_borrowck as borrowck;
use rustc_ast_borrowck::graphviz as borrowck_dot;
use rustc_mir::util::{write_mir_pretty, write_mir_graphviz};
use syntax::ast;

View File

@ -1,34 +1,13 @@
use rustc::session::config::BorrowckMode;
use rustc::ty::{self, Ty, TyCtxt};
use rustc_errors::{DiagnosticBuilder, DiagnosticId};
use syntax_pos::{MultiSpan, Span};
use std::fmt;
// FIXME(chrisvittal) remove Origin entirely
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Origin {
Ast,
Mir,
}
impl fmt::Display for Origin {
fn fmt(&self, _w: &mut fmt::Formatter<'_>) -> fmt::Result {
// FIXME(chrisvittal) remove Origin entirely
// Print no origin info
Ok(())
}
}
impl Origin {
/// Whether we should emit errors for the origin in the given mode
pub fn should_emit_errors(self, mode: BorrowckMode) -> bool {
match self {
Origin::Ast => mode.use_ast(),
Origin::Mir => true,
}
}
}
pub trait BorrowckErrors<'cx>: Sized + Copy {
fn struct_span_err_with_code<S: Into<MultiSpan>>(
self,
@ -39,32 +18,19 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
fn struct_span_err<S: Into<MultiSpan>>(self, sp: S, msg: &str) -> DiagnosticBuilder<'cx>;
/// Cancels the given error if we shouldn't emit errors for a given
/// origin in the current mode.
///
/// Always make sure that the error gets passed through this function
/// before you return it.
fn cancel_if_wrong_origin(
self,
diag: DiagnosticBuilder<'cx>,
o: Origin,
) -> DiagnosticBuilder<'cx>;
fn cannot_move_when_borrowed(
self,
span: Span,
desc: &str,
o: Origin,
_: Origin,
) -> DiagnosticBuilder<'cx> {
let err = struct_span_err!(
struct_span_err!(
self,
span,
E0505,
"cannot move out of `{}` because it is borrowed{OGN}",
"cannot move out of `{}` because it is borrowed",
desc,
OGN = o
);
self.cancel_if_wrong_origin(err, o)
)
}
fn cannot_use_when_mutably_borrowed(
@ -73,15 +39,14 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
desc: &str,
borrow_span: Span,
borrow_desc: &str,
o: Origin,
_: Origin,
) -> DiagnosticBuilder<'cx> {
let mut err = struct_span_err!(
self,
span,
E0503,
"cannot use `{}` because it was mutably borrowed{OGN}",
"cannot use `{}` because it was mutably borrowed",
desc,
OGN = o
);
err.span_label(
@ -89,8 +54,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
format!("borrow of `{}` occurs here", borrow_desc),
);
err.span_label(span, format!("use of borrowed `{}`", borrow_desc));
self.cancel_if_wrong_origin(err, o)
err
}
fn cannot_act_on_uninitialized_variable(
@ -98,18 +62,16 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
span: Span,
verb: &str,
desc: &str,
o: Origin,
_: Origin,
) -> DiagnosticBuilder<'cx> {
let err = struct_span_err!(
struct_span_err!(
self,
span,
E0381,
"{} of possibly uninitialized variable: `{}`{OGN}",
"{} of possibly uninitialized variable: `{}`",
verb,
desc,
OGN = o
);
self.cancel_if_wrong_origin(err, o)
)
}
fn cannot_mutably_borrow_multiply(
@ -120,7 +82,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
old_loan_span: Span,
old_opt_via: &str,
old_load_end_span: Option<Span>,
o: Origin,
_: Origin,
) -> DiagnosticBuilder<'cx> {
let via = |msg: &str|
if msg.is_empty() { msg.to_string() } else { format!(" (via `{}`)", msg) };
@ -128,10 +90,9 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
self,
new_loan_span,
E0499,
"cannot borrow `{}`{} as mutable more than once at a time{OGN}",
"cannot borrow `{}`{} as mutable more than once at a time",
desc,
via(opt_via),
OGN = o
);
if old_loan_span == new_loan_span {
// Both borrows are happening in the same place
@ -160,7 +121,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
err.span_label(old_load_end_span, "first borrow ends here");
}
}
self.cancel_if_wrong_origin(err, o)
err
}
fn cannot_uniquely_borrow_by_two_closures(
@ -169,15 +130,14 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
desc: &str,
old_loan_span: Span,
old_load_end_span: Option<Span>,
o: Origin,
_: Origin,
) -> DiagnosticBuilder<'cx> {
let mut err = struct_span_err!(
self,
new_loan_span,
E0524,
"two closures require unique access to `{}` at the same time{OGN}",
"two closures require unique access to `{}` at the same time",
desc,
OGN = o
);
if old_loan_span == new_loan_span {
err.span_label(
@ -191,7 +151,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
if let Some(old_load_end_span) = old_load_end_span {
err.span_label(old_load_end_span, "borrow from first closure ends here");
}
self.cancel_if_wrong_origin(err, o)
err
}
fn cannot_uniquely_borrow_by_one_closure(
@ -204,17 +164,16 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
noun_old: &str,
old_opt_via: &str,
previous_end_span: Option<Span>,
o: Origin,
_: Origin,
) -> DiagnosticBuilder<'cx> {
let mut err = struct_span_err!(
self,
new_loan_span,
E0500,
"closure requires unique access to `{}` but {} is already borrowed{}{OGN}",
"closure requires unique access to `{}` but {} is already borrowed{}",
desc_new,
noun_old,
old_opt_via,
OGN = o
);
err.span_label(
new_loan_span,
@ -224,7 +183,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
if let Some(previous_end_span) = previous_end_span {
err.span_label(previous_end_span, "borrow ends here");
}
self.cancel_if_wrong_origin(err, o)
err
}
fn cannot_reborrow_already_uniquely_borrowed(
@ -238,18 +197,17 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
old_opt_via: &str,
previous_end_span: Option<Span>,
second_borrow_desc: &str,
o: Origin,
_: Origin,
) -> DiagnosticBuilder<'cx> {
let mut err = struct_span_err!(
self,
new_loan_span,
E0501,
"cannot borrow `{}`{} as {} because previous closure \
requires unique access{OGN}",
requires unique access",
desc_new,
opt_via,
kind_new,
OGN = o
);
err.span_label(
new_loan_span,
@ -262,7 +220,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
if let Some(previous_end_span) = previous_end_span {
err.span_label(previous_end_span, "borrow from closure ends here");
}
self.cancel_if_wrong_origin(err, o)
err
}
fn cannot_reborrow_already_borrowed(
@ -276,7 +234,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
kind_old: &str,
msg_old: &str,
old_load_end_span: Option<Span>,
o: Origin,
_: Origin,
) -> DiagnosticBuilder<'cx> {
let via = |msg: &str|
if msg.is_empty() { msg.to_string() } else { format!(" (via `{}`)", msg) };
@ -285,14 +243,13 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
span,
E0502,
"cannot borrow `{}`{} as {} because {} is also borrowed \
as {}{}{OGN}",
as {}{}",
desc_new,
via(msg_new),
kind_new,
noun_old,
kind_old,
via(msg_old),
OGN = o
);
if msg_new == "" {
@ -317,8 +274,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
if let Some(old_load_end_span) = old_load_end_span {
err.span_label(old_load_end_span, format!("{} borrow ends here", kind_old));
}
self.cancel_if_wrong_origin(err, o)
err
}
fn cannot_assign_to_borrowed(
@ -326,15 +282,14 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
span: Span,
borrow_span: Span,
desc: &str,
o: Origin,
_: Origin,
) -> DiagnosticBuilder<'cx> {
let mut err = struct_span_err!(
self,
span,
E0506,
"cannot assign to `{}` because it is borrowed{OGN}",
"cannot assign to `{}` because it is borrowed",
desc,
OGN = o
);
err.span_label(borrow_span, format!("borrow of `{}` occurs here", desc));
@ -342,21 +297,17 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
span,
format!("assignment to borrowed `{}` occurs here", desc),
);
self.cancel_if_wrong_origin(err, o)
err
}
fn cannot_move_into_closure(self, span: Span, desc: &str, o: Origin) -> DiagnosticBuilder<'cx> {
let err = struct_span_err!(
fn cannot_move_into_closure(self, span: Span, desc: &str, _: Origin) -> DiagnosticBuilder<'cx> {
struct_span_err!(
self,
span,
E0504,
"cannot move `{}` into closure because it is borrowed{OGN}",
"cannot move `{}` into closure because it is borrowed",
desc,
OGN = o
);
self.cancel_if_wrong_origin(err, o)
)
}
fn cannot_reassign_immutable(
@ -364,29 +315,25 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
span: Span,
desc: &str,
is_arg: bool,
o: Origin,
_: Origin,
) -> DiagnosticBuilder<'cx> {
let msg = if is_arg {
"to immutable argument"
} else {
"twice to immutable variable"
};
let err = struct_span_err!(
struct_span_err!(
self,
span,
E0384,
"cannot assign {} `{}`{OGN}",
"cannot assign {} `{}`",
msg,
desc,
OGN = o
);
self.cancel_if_wrong_origin(err, o)
)
}
fn cannot_assign(self, span: Span, desc: &str, o: Origin) -> DiagnosticBuilder<'cx> {
let err = struct_span_err!(self, span, E0594, "cannot assign to {}{OGN}", desc, OGN = o);
self.cancel_if_wrong_origin(err, o)
fn cannot_assign(self, span: Span, desc: &str, _: Origin) -> DiagnosticBuilder<'cx> {
struct_span_err!(self, span, E0594, "cannot assign to {}", desc)
}
fn cannot_assign_static(self, span: Span, desc: &str, o: Origin) -> DiagnosticBuilder<'cx> {
@ -397,18 +344,15 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
self,
move_from_span: Span,
move_from_desc: &str,
o: Origin,
_: Origin,
) -> DiagnosticBuilder<'cx> {
let err = struct_span_err!(
struct_span_err!(
self,
move_from_span,
E0507,
"cannot move out of {}{OGN}",
"cannot move out of {}",
move_from_desc,
OGN = o
);
self.cancel_if_wrong_origin(err, o)
)
}
/// Signal an error due to an attempt to move out of the interior
@ -419,7 +363,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
move_from_span: Span,
ty: Ty<'_>,
is_index: Option<bool>,
o: Origin,
_: Origin,
) -> DiagnosticBuilder<'cx> {
let type_name = match (&ty.sty, is_index) {
(&ty::Array(_, _), Some(true)) | (&ty::Array(_, _), None) => "array",
@ -430,33 +374,29 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
self,
move_from_span,
E0508,
"cannot move out of type `{}`, a non-copy {}{OGN}",
"cannot move out of type `{}`, a non-copy {}",
ty,
type_name,
OGN = o
);
err.span_label(move_from_span, "cannot move out of here");
self.cancel_if_wrong_origin(err, o)
err
}
fn cannot_move_out_of_interior_of_drop(
self,
move_from_span: Span,
container_ty: Ty<'_>,
o: Origin,
_: Origin,
) -> DiagnosticBuilder<'cx> {
let mut err = struct_span_err!(
self,
move_from_span,
E0509,
"cannot move out of type `{}`, which implements the `Drop` trait{OGN}",
"cannot move out of type `{}`, which implements the `Drop` trait",
container_ty,
OGN = o
);
err.span_label(move_from_span, "cannot move out of here");
self.cancel_if_wrong_origin(err, o)
err
}
fn cannot_act_on_moved_value(
@ -465,60 +405,51 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
verb: &str,
optional_adverb_for_moved: &str,
moved_path: Option<String>,
o: Origin,
_: Origin,
) -> DiagnosticBuilder<'cx> {
let moved_path = moved_path
.map(|mp| format!(": `{}`", mp))
.unwrap_or_default();
let err = struct_span_err!(
struct_span_err!(
self,
use_span,
E0382,
"{} of {}moved value{}{OGN}",
"{} of {}moved value{}",
verb,
optional_adverb_for_moved,
moved_path,
OGN = o
);
self.cancel_if_wrong_origin(err, o)
)
}
fn cannot_partially_reinit_an_uninit_struct(
self,
span: Span,
uninit_path: &str,
o: Origin,
_: Origin,
) -> DiagnosticBuilder<'cx> {
let err = struct_span_err!(
struct_span_err!(
self,
span,
E0383,
"partial reinitialization of uninitialized structure `{}`{OGN}",
"partial reinitialization of uninitialized structure `{}`",
uninit_path,
OGN = o
);
self.cancel_if_wrong_origin(err, o)
)
}
fn closure_cannot_assign_to_borrowed(
self,
span: Span,
descr: &str,
o: Origin,
_: Origin,
) -> DiagnosticBuilder<'cx> {
let err = struct_span_err!(
struct_span_err!(
self,
span,
E0595,
"closure cannot assign to {}{OGN}",
"closure cannot assign to {}",
descr,
OGN = o
);
self.cancel_if_wrong_origin(err, o)
)
}
fn cannot_borrow_path_as_mutable_because(
@ -526,19 +457,16 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
span: Span,
path: &str,
reason: &str,
o: Origin,
_: Origin,
) -> DiagnosticBuilder<'cx> {
let err = struct_span_err!(
struct_span_err!(
self,
span,
E0596,
"cannot borrow {} as mutable{}{OGN}",
"cannot borrow {} as mutable{}",
path,
reason,
OGN = o,
);
self.cancel_if_wrong_origin(err, o)
)
}
fn cannot_borrow_path_as_mutable(
@ -556,73 +484,63 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
match_span: Span,
match_place: &str,
action: &str,
o: Origin,
_: Origin,
) -> DiagnosticBuilder<'cx> {
let mut err = struct_span_err!(
self,
mutate_span,
E0510,
"cannot {} `{}` in match guard{OGN}",
"cannot {} `{}` in match guard",
action,
match_place,
OGN = o
);
err.span_label(mutate_span, format!("cannot {}", action));
err.span_label(match_span, String::from("value is immutable in match guard"));
self.cancel_if_wrong_origin(err, o)
err
}
fn cannot_borrow_across_generator_yield(
self,
span: Span,
yield_span: Span,
o: Origin,
_: Origin,
) -> DiagnosticBuilder<'cx> {
let mut err = struct_span_err!(
self,
span,
E0626,
"borrow may still be in use when generator yields{OGN}",
OGN = o
"borrow may still be in use when generator yields",
);
err.span_label(yield_span, "possible yield occurs here");
self.cancel_if_wrong_origin(err, o)
err
}
fn cannot_borrow_across_destructor(
self,
borrow_span: Span,
o: Origin,
_: Origin,
) -> DiagnosticBuilder<'cx> {
let err = struct_span_err!(
struct_span_err!(
self,
borrow_span,
E0713,
"borrow may still be in use when destructor runs{OGN}",
OGN = o
);
self.cancel_if_wrong_origin(err, o)
"borrow may still be in use when destructor runs",
)
}
fn path_does_not_live_long_enough(
self,
span: Span,
path: &str,
o: Origin,
_: Origin,
) -> DiagnosticBuilder<'cx> {
let err = struct_span_err!(
struct_span_err!(
self,
span,
E0597,
"{} does not live long enough{OGN}",
"{} does not live long enough",
path,
OGN = o
);
self.cancel_if_wrong_origin(err, o)
)
}
fn cannot_return_reference_to_local(
@ -631,17 +549,16 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
return_kind: &str,
reference_desc: &str,
path_desc: &str,
o: Origin,
_: Origin,
) -> DiagnosticBuilder<'cx> {
let mut err = struct_span_err!(
self,
span,
E0515,
"cannot {RETURN} {REFERENCE} {LOCAL}{OGN}",
"cannot {RETURN} {REFERENCE} {LOCAL}",
RETURN=return_kind,
REFERENCE=reference_desc,
LOCAL=path_desc,
OGN = o
);
err.span_label(
@ -649,26 +566,23 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
format!("{}s a {} data owned by the current function", return_kind, reference_desc),
);
self.cancel_if_wrong_origin(err, o)
err
}
fn lifetime_too_short_for_reborrow(
self,
span: Span,
path: &str,
o: Origin,
_: Origin,
) -> DiagnosticBuilder<'cx> {
let err = struct_span_err!(
struct_span_err!(
self,
span,
E0598,
"lifetime of {} is too short to guarantee \
its contents can be safely reborrowed{OGN}",
its contents can be safely reborrowed",
path,
OGN = o
);
self.cancel_if_wrong_origin(err, o)
)
}
fn cannot_act_on_capture_in_sharable_fn(
@ -676,39 +590,35 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
span: Span,
bad_thing: &str,
help: (Span, &str),
o: Origin,
_: Origin,
) -> DiagnosticBuilder<'cx> {
let (help_span, help_msg) = help;
let mut err = struct_span_err!(
self,
span,
E0387,
"{} in a captured outer variable in an `Fn` closure{OGN}",
"{} in a captured outer variable in an `Fn` closure",
bad_thing,
OGN = o
);
err.span_help(help_span, help_msg);
self.cancel_if_wrong_origin(err, o)
err
}
fn cannot_assign_into_immutable_reference(
self,
span: Span,
bad_thing: &str,
o: Origin,
_: Origin,
) -> DiagnosticBuilder<'cx> {
let mut err = struct_span_err!(
self,
span,
E0389,
"{} in a `&` reference{OGN}",
"{} in a `&` reference",
bad_thing,
OGN = o
);
err.span_label(span, "assignment into an immutable reference");
self.cancel_if_wrong_origin(err, o)
err
}
fn cannot_capture_in_long_lived_closure(
@ -716,7 +626,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
closure_span: Span,
borrowed_path: &str,
capture_span: Span,
o: Origin,
_: Origin,
) -> DiagnosticBuilder<'cx> {
let mut err = struct_span_err!(
self,
@ -724,67 +634,56 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
E0373,
"closure may outlive the current function, \
but it borrows {}, \
which is owned by the current function{OGN}",
which is owned by the current function",
borrowed_path,
OGN = o
);
err.span_label(capture_span, format!("{} is borrowed here", borrowed_path))
.span_label(
closure_span,
format!("may outlive borrowed value {}", borrowed_path),
);
self.cancel_if_wrong_origin(err, o)
err
}
fn borrowed_data_escapes_closure(
self,
escape_span: Span,
escapes_from: &str,
o: Origin,
_: Origin,
) -> DiagnosticBuilder<'cx> {
let err = struct_span_err!(
struct_span_err!(
self,
escape_span,
E0521,
"borrowed data escapes outside of {}{OGN}",
"borrowed data escapes outside of {}",
escapes_from,
OGN = o
);
self.cancel_if_wrong_origin(err, o)
)
}
fn thread_local_value_does_not_live_long_enough(
self,
span: Span,
o: Origin,
_: Origin,
) -> DiagnosticBuilder<'cx> {
let err = struct_span_err!(
struct_span_err!(
self,
span,
E0712,
"thread-local variable borrowed past end of function{OGN}",
OGN = o
);
self.cancel_if_wrong_origin(err, o)
"thread-local variable borrowed past end of function",
)
}
fn temporary_value_borrowed_for_too_long(
self,
span: Span,
o: Origin,
_: Origin,
) -> DiagnosticBuilder<'cx> {
let err = struct_span_err!(
struct_span_err!(
self,
span,
E0716,
"temporary value dropped while borrowed{OGN}",
OGN = o
);
self.cancel_if_wrong_origin(err, o)
"temporary value dropped while borrowed",
)
}
}
@ -801,15 +700,4 @@ impl BorrowckErrors<'tcx> for TyCtxt<'tcx> {
fn struct_span_err<S: Into<MultiSpan>>(self, sp: S, msg: &str) -> DiagnosticBuilder<'tcx> {
self.sess.struct_span_err(sp, msg)
}
fn cancel_if_wrong_origin(
self,
mut diag: DiagnosticBuilder<'tcx>,
o: Origin,
) -> DiagnosticBuilder<'tcx> {
if !o.should_emit_errors(self.borrowck_mode()) {
self.sess.diagnostic().cancel(&mut diag);
}
diag
}
}