Remove rustc_mir dependency from rustc_borrowck
This commit is contained in:
parent
4bb6b4a5ed
commit
be085d7c0f
15 changed files with 229 additions and 2046 deletions
|
@ -2954,7 +2954,6 @@ dependencies = [
|
||||||
"rustc 0.0.0",
|
"rustc 0.0.0",
|
||||||
"rustc_data_structures 0.0.0",
|
"rustc_data_structures 0.0.0",
|
||||||
"rustc_errors 0.0.0",
|
"rustc_errors 0.0.0",
|
||||||
"rustc_mir 0.0.0",
|
|
||||||
"syntax 0.0.0",
|
"syntax 0.0.0",
|
||||||
"syntax_pos 0.0.0",
|
"syntax_pos 0.0.0",
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
use crate::ich::StableHashingContext;
|
use crate::ich::StableHashingContext;
|
||||||
use crate::hir::HirId;
|
|
||||||
use crate::util::nodemap::FxHashSet;
|
|
||||||
|
|
||||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
|
use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
|
||||||
StableHasherResult};
|
StableHasherResult};
|
||||||
|
@ -18,7 +16,6 @@ impl_stable_hash_for!(enum self::SignalledError { SawSomeError, NoErrorsSeen });
|
||||||
|
|
||||||
#[derive(Debug, Default, RustcEncodable, RustcDecodable)]
|
#[derive(Debug, Default, RustcEncodable, RustcDecodable)]
|
||||||
pub struct BorrowCheckResult {
|
pub struct BorrowCheckResult {
|
||||||
pub used_mut_nodes: FxHashSet<HirId>,
|
|
||||||
pub signalled_any_error: SignalledError,
|
pub signalled_any_error: SignalledError,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,10 +24,8 @@ impl<'a> HashStable<StableHashingContext<'a>> for BorrowCheckResult {
|
||||||
hcx: &mut StableHashingContext<'a>,
|
hcx: &mut StableHashingContext<'a>,
|
||||||
hasher: &mut StableHasher<W>) {
|
hasher: &mut StableHasher<W>) {
|
||||||
let BorrowCheckResult {
|
let BorrowCheckResult {
|
||||||
ref used_mut_nodes,
|
|
||||||
ref signalled_any_error,
|
ref signalled_any_error,
|
||||||
} = *self;
|
} = *self;
|
||||||
used_mut_nodes.hash_stable(hcx, hasher);
|
|
||||||
signalled_any_error.hash_stable(hcx, hasher);
|
signalled_any_error.hash_stable(hcx, hasher);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,7 +66,6 @@ use crate::hir::def::{CtorOf, Res, DefKind, CtorKind};
|
||||||
use crate::ty::adjustment;
|
use crate::ty::adjustment;
|
||||||
use crate::ty::{self, DefIdTree, Ty, TyCtxt};
|
use crate::ty::{self, DefIdTree, Ty, TyCtxt};
|
||||||
use crate::ty::fold::TypeFoldable;
|
use crate::ty::fold::TypeFoldable;
|
||||||
use crate::ty::layout::VariantIdx;
|
|
||||||
|
|
||||||
use crate::hir::{MutImmutable, MutMutable, PatKind};
|
use crate::hir::{MutImmutable, MutMutable, PatKind};
|
||||||
use crate::hir::pat_util::EnumerateAndAdjustIterator;
|
use crate::hir::pat_util::EnumerateAndAdjustIterator;
|
||||||
|
@ -79,7 +78,6 @@ use std::borrow::Cow;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use rustc_data_structures::fx::FxIndexMap;
|
use rustc_data_structures::fx::FxIndexMap;
|
||||||
use rustc_data_structures::indexed_vec::Idx;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use crate::util::nodemap::ItemLocalSet;
|
use crate::util::nodemap::ItemLocalSet;
|
||||||
|
|
||||||
|
@ -198,79 +196,6 @@ pub struct cmt_<'tcx> {
|
||||||
|
|
||||||
pub type cmt<'tcx> = Rc<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 {
|
pub trait HirNode {
|
||||||
fn hir_id(&self) -> hir::HirId;
|
fn hir_id(&self) -> hir::HirId;
|
||||||
fn span(&self) -> Span;
|
fn span(&self) -> Span;
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
[package]
|
[package]
|
||||||
authors = ["The Rust Project Developers"]
|
authors = ["The Rust Project Developers"]
|
||||||
name = "rustc_borrowck"
|
name = "rustc_ast_borrowck"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "rustc_borrowck"
|
name = "rustc_ast_borrowck"
|
||||||
path = "lib.rs"
|
path = "lib.rs"
|
||||||
test = false
|
test = false
|
||||||
doctest = false
|
doctest = false
|
||||||
|
@ -18,6 +18,5 @@ syntax_pos = { path = "../libsyntax_pos" }
|
||||||
# refers to the borrowck-specific graphviz adapter traits.
|
# refers to the borrowck-specific graphviz adapter traits.
|
||||||
dot = { path = "../libgraphviz", package = "graphviz" }
|
dot = { path = "../libgraphviz", package = "graphviz" }
|
||||||
rustc = { path = "../librustc" }
|
rustc = { path = "../librustc" }
|
||||||
rustc_mir = { path = "../librustc_mir" }
|
|
||||||
errors = { path = "../librustc_errors", package = "rustc_errors" }
|
errors = { path = "../librustc_errors", package = "rustc_errors" }
|
||||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||||
|
|
|
@ -7,8 +7,6 @@
|
||||||
// 3. assignments do not affect things loaned out as immutable
|
// 3. assignments do not affect things loaned out as immutable
|
||||||
// 4. moves do not affect things loaned out in any way
|
// 4. moves do not affect things loaned out in any way
|
||||||
|
|
||||||
use UseError::*;
|
|
||||||
|
|
||||||
use crate::borrowck::*;
|
use crate::borrowck::*;
|
||||||
use crate::borrowck::InteriorKind::{InteriorElement, InteriorField};
|
use crate::borrowck::InteriorKind::{InteriorElement, InteriorField};
|
||||||
use rustc::middle::expr_use_visitor as euv;
|
use rustc::middle::expr_use_visitor as euv;
|
||||||
|
@ -20,7 +18,6 @@ use rustc::ty::{self, TyCtxt, RegionKind};
|
||||||
use syntax_pos::Span;
|
use syntax_pos::Span;
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
use rustc::hir::Node;
|
use rustc::hir::Node;
|
||||||
use rustc_mir::util::borrowck_errors::{BorrowckErrors, Origin};
|
|
||||||
use log::debug;
|
use log::debug;
|
||||||
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
@ -89,13 +86,12 @@ struct CheckLoanCtxt<'a, 'tcx> {
|
||||||
impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {
|
impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {
|
||||||
fn consume(&mut self,
|
fn consume(&mut self,
|
||||||
consume_id: hir::HirId,
|
consume_id: hir::HirId,
|
||||||
consume_span: Span,
|
_: Span,
|
||||||
cmt: &mc::cmt_<'tcx>,
|
cmt: &mc::cmt_<'tcx>,
|
||||||
mode: euv::ConsumeMode) {
|
mode: euv::ConsumeMode) {
|
||||||
debug!("consume(consume_id={}, cmt={:?}, mode={:?})",
|
debug!("consume(consume_id={}, cmt={:?})", consume_id, cmt);
|
||||||
consume_id, cmt, mode);
|
|
||||||
|
|
||||||
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,
|
fn matched_pat(&mut self,
|
||||||
|
@ -107,12 +103,9 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {
|
||||||
consume_pat: &hir::Pat,
|
consume_pat: &hir::Pat,
|
||||||
cmt: &mc::cmt_<'tcx>,
|
cmt: &mc::cmt_<'tcx>,
|
||||||
mode: euv::ConsumeMode) {
|
mode: euv::ConsumeMode) {
|
||||||
debug!("consume_pat(consume_pat={:?}, cmt={:?}, mode={:?})",
|
debug!("consume_pat(consume_pat={:?}, cmt={:?})", consume_pat, cmt);
|
||||||
consume_pat,
|
|
||||||
cmt,
|
|
||||||
mode);
|
|
||||||
|
|
||||||
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,
|
fn borrow(&mut self,
|
||||||
|
@ -129,11 +122,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {
|
||||||
bk, loan_cause);
|
bk, loan_cause);
|
||||||
|
|
||||||
if let Some(lp) = opt_loan_path(cmt) {
|
if let Some(lp) = opt_loan_path(cmt) {
|
||||||
let moved_value_use_kind = match loan_cause {
|
self.check_if_path_is_moved(borrow_id.local_id, &lp);
|
||||||
euv::ClosureCapture(_) => MovedInCapture,
|
|
||||||
_ => MovedInUse,
|
|
||||||
};
|
|
||||||
self.check_if_path_is_moved(borrow_id.local_id, borrow_span, moved_value_use_kind, &lp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.check_for_conflicting_loans(borrow_id.local_id);
|
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,
|
fn mutate(&mut self,
|
||||||
assignment_id: hir::HirId,
|
assignment_id: hir::HirId,
|
||||||
assignment_span: Span,
|
_: Span,
|
||||||
assignee_cmt: &mc::cmt_<'tcx>,
|
assignee_cmt: &mc::cmt_<'tcx>,
|
||||||
mode: euv::MutateMode)
|
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
|
// have to be *FULLY* initialized, but we still
|
||||||
// must be careful lest it contains derefs of
|
// must be careful lest it contains derefs of
|
||||||
// pointers.
|
// pointers.
|
||||||
self.check_if_assigned_path_is_moved(assignee_cmt.hir_id.local_id,
|
self.check_if_assigned_path_is_moved(assignee_cmt.hir_id.local_id, &lp);
|
||||||
assignment_span,
|
|
||||||
MovedInUse,
|
|
||||||
&lp);
|
|
||||||
}
|
}
|
||||||
MutateMode::WriteAndRead => {
|
MutateMode::WriteAndRead => {
|
||||||
// In a case like `path += 1`, then path must be
|
// In a case like `path += 1`, then path must be
|
||||||
// fully initialized, since we will read it before
|
// fully initialized, since we will read it before
|
||||||
// we write it.
|
// we write it.
|
||||||
self.check_if_path_is_moved(assignee_cmt.hir_id.local_id,
|
self.check_if_path_is_moved(assignee_cmt.hir_id.local_id,
|
||||||
assignment_span,
|
|
||||||
MovedInUse,
|
|
||||||
&lp);
|
&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) { }
|
fn decl_without_init(&mut self, _id: hir::HirId, _span: Span) { }
|
||||||
|
@ -218,12 +202,6 @@ pub fn check_loans<'a, 'tcx>(
|
||||||
.consume_body(body);
|
.consume_body(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
|
||||||
enum UseError<'tcx> {
|
|
||||||
UseOk,
|
|
||||||
UseWhileBorrowed(/*loan*/Rc<LoanPath<'tcx>>, /*loan*/Span)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compatible_borrow_kinds(borrow_kind1: ty::BorrowKind,
|
fn compatible_borrow_kinds(borrow_kind1: ty::BorrowKind,
|
||||||
borrow_kind2: ty::BorrowKind)
|
borrow_kind2: ty::BorrowKind)
|
||||||
-> bool {
|
-> bool {
|
||||||
|
@ -433,15 +411,9 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(yield_span) = self.bccx
|
if let Some(_) = self.bccx.region_scope_tree
|
||||||
.region_scope_tree
|
.yield_in_scope_for_expr(scope, cmt.hir_id, self.bccx.body)
|
||||||
.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();
|
self.bccx.signal_error();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -478,10 +450,11 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn report_error_if_loans_conflict(&self,
|
pub fn report_error_if_loans_conflict(
|
||||||
old_loan: &Loan<'tcx>,
|
&self,
|
||||||
new_loan: &Loan<'tcx>)
|
old_loan: &Loan<'tcx>,
|
||||||
-> bool {
|
new_loan: &Loan<'tcx>,
|
||||||
|
) -> bool {
|
||||||
//! Checks whether `old_loan` and `new_loan` can safely be issued
|
//! Checks whether `old_loan` and `new_loan` can safely be issued
|
||||||
//! simultaneously.
|
//! simultaneously.
|
||||||
|
|
||||||
|
@ -493,266 +466,87 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
||||||
assert!(self.bccx.region_scope_tree.scopes_intersect(old_loan.kill_scope,
|
assert!(self.bccx.region_scope_tree.scopes_intersect(old_loan.kill_scope,
|
||||||
new_loan.kill_scope));
|
new_loan.kill_scope));
|
||||||
|
|
||||||
let err_old_new = self.report_error_if_loan_conflicts_with_restriction(
|
self.report_error_if_loan_conflicts_with_restriction(
|
||||||
old_loan, new_loan, old_loan, new_loan).err();
|
old_loan, new_loan)
|
||||||
let err_new_old = self.report_error_if_loan_conflicts_with_restriction(
|
&& self.report_error_if_loan_conflicts_with_restriction(
|
||||||
new_loan, old_loan, old_loan, new_loan).err();
|
new_loan, old_loan)
|
||||||
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn report_error_if_loan_conflicts_with_restriction(&self,
|
pub fn report_error_if_loan_conflicts_with_restriction(
|
||||||
loan1: &Loan<'tcx>,
|
&self,
|
||||||
loan2: &Loan<'tcx>,
|
loan1: &Loan<'tcx>,
|
||||||
old_loan: &Loan<'tcx>,
|
loan2: &Loan<'tcx>,
|
||||||
new_loan: &Loan<'tcx>)
|
) -> bool {
|
||||||
-> Result<(), DiagnosticBuilder<'a>> {
|
|
||||||
//! Checks whether the restrictions introduced by `loan1` would
|
//! 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(\
|
debug!("report_error_if_loan_conflicts_with_restriction(\
|
||||||
loan1={:?}, loan2={:?})",
|
loan1={:?}, loan2={:?})",
|
||||||
loan1,
|
loan1,
|
||||||
loan2);
|
loan2);
|
||||||
|
|
||||||
if compatible_borrow_kinds(loan1.kind, loan2.kind) {
|
if compatible_borrow_kinds(loan1.kind, loan2.kind) {
|
||||||
return Ok(());
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let loan2_base_path = owned_ptr_base_path_rc(&loan2.loan_path);
|
let loan2_base_path = owned_ptr_base_path_rc(&loan2.loan_path);
|
||||||
for restr_path in &loan1.restricted_paths {
|
for restr_path in &loan1.restricted_paths {
|
||||||
if *restr_path != loan2_base_path { continue; }
|
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
|
self.bccx.signal_error();
|
||||||
// normally generate a rather confusing message (in this case, for multiple mutable
|
return false;
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consume_common(&self,
|
fn consume_common(
|
||||||
id: hir::ItemLocalId,
|
&self,
|
||||||
span: Span,
|
id: hir::ItemLocalId,
|
||||||
cmt: &mc::cmt_<'tcx>,
|
cmt: &mc::cmt_<'tcx>,
|
||||||
mode: euv::ConsumeMode) {
|
mode: euv::ConsumeMode,
|
||||||
|
) {
|
||||||
if let Some(lp) = opt_loan_path(cmt) {
|
if let Some(lp) = opt_loan_path(cmt) {
|
||||||
let moved_value_use_kind = match mode {
|
match mode {
|
||||||
euv::Copy => {
|
euv::Copy => {
|
||||||
self.check_for_copy_of_frozen_path(id, span, &lp);
|
self.check_for_copy_of_frozen_path(id, &lp);
|
||||||
MovedInUse
|
|
||||||
}
|
}
|
||||||
euv::Move(_) => {
|
euv::Move(_) => {
|
||||||
match self.move_data.kind_of_move_of_path(id, &lp) {
|
// Sometimes moves aren't from a move path;
|
||||||
None => {
|
// this either means that the original move
|
||||||
// Sometimes moves don't have a move kind;
|
// was from something illegal to move,
|
||||||
// this either means that the original move
|
// or was moved from referent of an unsafe
|
||||||
// was from something illegal to move,
|
// pointer or something like that.
|
||||||
// or was moved from referent of an unsafe
|
if self.move_data.is_move_path(id, &lp) {
|
||||||
// pointer or something like that.
|
self.check_for_move_of_borrowed_path(id, &lp);
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
self.check_if_path_is_moved(id, &lp);
|
||||||
self.check_if_path_is_moved(id, span, moved_value_use_kind, &lp);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_for_copy_of_frozen_path(&self,
|
fn check_for_copy_of_frozen_path(&self,
|
||||||
id: hir::ItemLocalId,
|
id: hir::ItemLocalId,
|
||||||
span: Span,
|
|
||||||
copy_path: &LoanPath<'tcx>) {
|
copy_path: &LoanPath<'tcx>) {
|
||||||
match self.analyze_restrictions_on_use(id, copy_path, ty::ImmBorrow) {
|
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_for_move_of_borrowed_path(&self,
|
fn check_for_move_of_borrowed_path(&self,
|
||||||
id: hir::ItemLocalId,
|
id: hir::ItemLocalId,
|
||||||
span: Span,
|
move_path: &LoanPath<'tcx>) {
|
||||||
move_path: &LoanPath<'tcx>,
|
|
||||||
move_kind: move_data::MoveKind) {
|
|
||||||
// We want to detect if there are any loans at all, so we search for
|
// 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
|
// any loans incompatible with MutBorrrow, since all other kinds of
|
||||||
// loans are incompatible with that.
|
// loans are incompatible with that.
|
||||||
match self.analyze_restrictions_on_use(id, move_path, ty::MutBorrow) {
|
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn analyze_restrictions_on_use(&self,
|
fn analyze_restrictions_on_use(&self,
|
||||||
expr_id: hir::ItemLocalId,
|
expr_id: hir::ItemLocalId,
|
||||||
use_path: &LoanPath<'tcx>,
|
use_path: &LoanPath<'tcx>,
|
||||||
borrow_kind: ty::BorrowKind)
|
borrow_kind: ty::BorrowKind) {
|
||||||
-> UseError<'tcx> {
|
|
||||||
debug!("analyze_restrictions_on_use(expr_id={:?}, use_path={:?})",
|
debug!("analyze_restrictions_on_use(expr_id={:?}, use_path={:?})",
|
||||||
expr_id, use_path);
|
expr_id, use_path);
|
||||||
|
|
||||||
let mut ret = UseOk;
|
|
||||||
|
|
||||||
let scope = region::Scope {
|
let scope = region::Scope {
|
||||||
id: expr_id,
|
id: expr_id,
|
||||||
data: region::ScopeData::Node
|
data: region::ScopeData::Node
|
||||||
|
@ -760,38 +554,28 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
||||||
self.each_in_scope_loan_affecting_path(
|
self.each_in_scope_loan_affecting_path(
|
||||||
scope, use_path, |loan| {
|
scope, use_path, |loan| {
|
||||||
if !compatible_borrow_kinds(loan.kind, borrow_kind) {
|
if !compatible_borrow_kinds(loan.kind, borrow_kind) {
|
||||||
ret = UseWhileBorrowed(loan.loan_path.clone(), loan.span);
|
self.bccx.signal_error();
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reports an error if `expr` (which should be a path)
|
/// Reports an error if `expr` (which should be a path)
|
||||||
/// is using a moved/uninitialized value
|
/// is using a moved/uninitialized value
|
||||||
fn check_if_path_is_moved(&self,
|
fn check_if_path_is_moved(&self,
|
||||||
id: hir::ItemLocalId,
|
id: hir::ItemLocalId,
|
||||||
span: Span,
|
|
||||||
use_kind: MovedValueUseKind,
|
|
||||||
lp: &Rc<LoanPath<'tcx>>) {
|
lp: &Rc<LoanPath<'tcx>>) {
|
||||||
debug!("check_if_path_is_moved(id={:?}, use_kind={:?}, lp={:?})",
|
debug!("check_if_path_is_moved(id={:?}, lp={:?})", id, lp);
|
||||||
id, use_kind, lp);
|
|
||||||
|
|
||||||
// FIXME: if you find yourself tempted to cut and paste
|
// FIXME: if you find yourself tempted to cut and paste
|
||||||
// the body below and then specializing the error reporting,
|
// the body below and then specializing the error reporting,
|
||||||
// consider refactoring this instead!
|
// consider refactoring this instead!
|
||||||
|
|
||||||
let base_lp = owned_ptr_base_path_rc(lp);
|
let base_lp = owned_ptr_base_path_rc(lp);
|
||||||
self.move_data.each_move_of(id, &base_lp, |the_move, moved_lp| {
|
self.move_data.each_move_of(id, &base_lp, |_, _| {
|
||||||
self.bccx.report_use_of_moved_value(
|
self.bccx.signal_error();
|
||||||
span,
|
|
||||||
use_kind,
|
|
||||||
&lp,
|
|
||||||
the_move,
|
|
||||||
moved_lp);
|
|
||||||
false
|
false
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -820,8 +604,6 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
||||||
/// ```
|
/// ```
|
||||||
fn check_if_assigned_path_is_moved(&self,
|
fn check_if_assigned_path_is_moved(&self,
|
||||||
id: hir::ItemLocalId,
|
id: hir::ItemLocalId,
|
||||||
span: Span,
|
|
||||||
use_kind: MovedValueUseKind,
|
|
||||||
lp: &Rc<LoanPath<'tcx>>)
|
lp: &Rc<LoanPath<'tcx>>)
|
||||||
{
|
{
|
||||||
match lp.kind {
|
match lp.kind {
|
||||||
|
@ -830,8 +612,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
LpDowncast(ref lp_base, _) => {
|
LpDowncast(ref lp_base, _) => {
|
||||||
// assigning to `(P->Variant).f` is ok if assigning to `P` is ok
|
// assigning to `(P->Variant).f` is ok if assigning to `P` is ok
|
||||||
self.check_if_assigned_path_is_moved(id, span,
|
self.check_if_assigned_path_is_moved(id, lp_base);
|
||||||
use_kind, lp_base);
|
|
||||||
}
|
}
|
||||||
LpExtend(ref lp_base, _, LpInterior(_, InteriorField(_))) => {
|
LpExtend(ref lp_base, _, LpInterior(_, InteriorField(_))) => {
|
||||||
match lp_base.to_type().sty {
|
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);
|
let loan_path = owned_ptr_base_path_rc(lp_base);
|
||||||
self.move_data.each_move_of(id, &loan_path, |_, _| {
|
self.move_data.each_move_of(id, &loan_path, |_, _| {
|
||||||
self.bccx
|
self.bccx
|
||||||
.report_partial_reinitialization_of_uninitialized_structure(
|
.signal_error();
|
||||||
span,
|
|
||||||
&loan_path);
|
|
||||||
false
|
false
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
@ -856,21 +635,19 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// assigning to `P.f` is ok if assigning to `P` is ok
|
// assigning to `P.f` is ok if assigning to `P` is ok
|
||||||
self.check_if_assigned_path_is_moved(id, span,
|
self.check_if_assigned_path_is_moved(id, lp_base);
|
||||||
use_kind, lp_base);
|
|
||||||
}
|
}
|
||||||
LpExtend(ref lp_base, _, LpInterior(_, InteriorElement)) |
|
LpExtend(ref lp_base, _, LpInterior(_, InteriorElement)) |
|
||||||
LpExtend(ref lp_base, _, LpDeref(_)) => {
|
LpExtend(ref lp_base, _, LpDeref(_)) => {
|
||||||
// assigning to `P[i]` requires `P` is initialized
|
// assigning to `P[i]` requires `P` is initialized
|
||||||
// assigning to `(*P)` 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,
|
fn check_assignment(&self,
|
||||||
assignment_id: hir::ItemLocalId,
|
assignment_id: hir::ItemLocalId,
|
||||||
assignment_span: Span,
|
|
||||||
assignee_cmt: &mc::cmt_<'tcx>) {
|
assignee_cmt: &mc::cmt_<'tcx>) {
|
||||||
debug!("check_assignment(assignee_cmt={:?})", assignee_cmt);
|
debug!("check_assignment(assignee_cmt={:?})", assignee_cmt);
|
||||||
|
|
||||||
|
@ -880,8 +657,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
||||||
id: assignment_id,
|
id: assignment_id,
|
||||||
data: region::ScopeData::Node
|
data: region::ScopeData::Node
|
||||||
};
|
};
|
||||||
self.each_in_scope_loan_affecting_path(scope, &loan_path, |loan| {
|
self.each_in_scope_loan_affecting_path(scope, &loan_path, |_| {
|
||||||
self.report_illegal_mutation(assignment_span, &loan_path, loan);
|
self.bccx.signal_error();
|
||||||
false
|
false
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -889,30 +666,15 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
||||||
// Check for reassignments to (immutable) local variables. This
|
// Check for reassignments to (immutable) local variables. This
|
||||||
// needs to be done here instead of in check_loans because we
|
// needs to be done here instead of in check_loans because we
|
||||||
// depend on move data.
|
// 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();
|
let lp = opt_loan_path(assignee_cmt).unwrap();
|
||||||
self.move_data.each_assignment_of(assignment_id, &lp, |assign| {
|
self.move_data.each_assignment_of(assignment_id, &lp, |_| {
|
||||||
if assignee_cmt.mutbl.is_mutable() {
|
if !assignee_cmt.mutbl.is_mutable() {
|
||||||
self.bccx.used_mut_nodes.borrow_mut().insert(hir_id);
|
self.bccx.signal_error();
|
||||||
} else {
|
|
||||||
self.bccx.report_reassigned_immutable_variable(
|
|
||||||
assignment_span,
|
|
||||||
&lp,
|
|
||||||
assign);
|
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
});
|
});
|
||||||
return
|
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
//! Computes moves.
|
//! Computes moves.
|
||||||
|
|
||||||
use crate::borrowck::*;
|
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 crate::borrowck::move_data::*;
|
||||||
use rustc::middle::expr_use_visitor as euv;
|
|
||||||
use rustc::middle::mem_categorization as mc;
|
use rustc::middle::mem_categorization as mc;
|
||||||
use rustc::middle::mem_categorization::Categorization;
|
use rustc::middle::mem_categorization::Categorization;
|
||||||
use rustc::middle::mem_categorization::InteriorOffsetKind as Kind;
|
use rustc::middle::mem_categorization::InteriorOffsetKind as Kind;
|
||||||
|
@ -12,56 +9,11 @@ use rustc::ty::{self, Ty};
|
||||||
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use syntax_pos::Span;
|
use syntax_pos::Span;
|
||||||
use rustc::hir::*;
|
|
||||||
use rustc::hir::Node;
|
|
||||||
use log::debug;
|
use log::debug;
|
||||||
|
|
||||||
struct GatherMoveInfo<'c, 'tcx> {
|
struct GatherMoveInfo<'c, 'tcx> {
|
||||||
id: hir::ItemLocalId,
|
id: hir::ItemLocalId,
|
||||||
kind: MoveKind,
|
|
||||||
cmt: &'c mc::cmt_<'tcx>,
|
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>,
|
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_id: hir::HirId,
|
||||||
var_ty: Ty<'tcx>) {
|
var_ty: Ty<'tcx>) {
|
||||||
let loan_path = Rc::new(LoanPath::new(LpVar(var_id), var_ty));
|
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>,
|
pub fn gather_move_from_expr<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
|
||||||
move_data: &MoveData<'tcx>,
|
move_data: &MoveData<'tcx>,
|
||||||
move_error_collector: &mut MoveErrorCollector<'tcx>,
|
|
||||||
move_expr_id: hir::ItemLocalId,
|
move_expr_id: hir::ItemLocalId,
|
||||||
cmt: &mc::cmt_<'tcx>,
|
cmt: &mc::cmt_<'tcx>) {
|
||||||
move_reason: euv::MoveReason) {
|
|
||||||
let kind = match move_reason {
|
|
||||||
euv::DirectRefMove | euv::PatBindingMove => MoveExpr,
|
|
||||||
euv::CaptureMove => Captured
|
|
||||||
};
|
|
||||||
let move_info = GatherMoveInfo {
|
let move_info = GatherMoveInfo {
|
||||||
id: move_expr_id,
|
id: move_expr_id,
|
||||||
kind,
|
|
||||||
cmt,
|
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>(
|
pub fn gather_move_from_pat<'a, 'c, 'tcx>(
|
||||||
bccx: &BorrowckCtxt<'a, 'tcx>,
|
bccx: &BorrowckCtxt<'a, 'tcx>,
|
||||||
move_data: &MoveData<'tcx>,
|
move_data: &MoveData<'tcx>,
|
||||||
move_error_collector: &mut MoveErrorCollector<'tcx>,
|
|
||||||
move_pat: &hir::Pat,
|
move_pat: &hir::Pat,
|
||||||
cmt: &'c mc::cmt_<'tcx>,
|
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 {
|
let move_info = GatherMoveInfo {
|
||||||
id: move_pat.hir_id.local_id,
|
id: move_pat.hir_id.local_id,
|
||||||
kind: MovePat,
|
|
||||||
cmt,
|
cmt,
|
||||||
span_path_opt: pat_span_path_opt,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
debug!("gather_move_from_pat: move_pat={:?} source={:?}",
|
debug!("gather_move_from_pat: move_pat={:?}", move_pat);
|
||||||
move_pat,
|
|
||||||
source);
|
|
||||||
|
|
||||||
gather_move(bccx, move_data, move_error_collector, move_info);
|
gather_move(bccx, move_data, move_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gather_move<'a, 'c, 'tcx>(
|
fn gather_move<'a, 'c, 'tcx>(
|
||||||
bccx: &BorrowckCtxt<'a, 'tcx>,
|
bccx: &BorrowckCtxt<'a, 'tcx>,
|
||||||
move_data: &MoveData<'tcx>,
|
move_data: &MoveData<'tcx>,
|
||||||
move_error_collector: &mut MoveErrorCollector<'tcx>,
|
|
||||||
move_info: GatherMoveInfo<'c, 'tcx>,
|
move_info: GatherMoveInfo<'c, 'tcx>,
|
||||||
) {
|
) {
|
||||||
debug!("gather_move(move_id={:?}, cmt={:?})",
|
debug!("gather_move(move_id={:?}, cmt={:?})",
|
||||||
move_info.id, move_info.cmt);
|
move_info.id, move_info.cmt);
|
||||||
|
|
||||||
let potentially_illegal_move = check_and_get_illegal_move_origin(bccx, 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 {
|
if let Some(_) = potentially_illegal_move {
|
||||||
debug!("illegal_move_origin={:?}", illegal_move_origin);
|
bccx.signal_error();
|
||||||
let error = MoveError::with_move_info(Rc::new(illegal_move_origin),
|
|
||||||
move_info.span_path_opt);
|
|
||||||
move_error_collector.add_error(error);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
match opt_loan_path(&move_info.cmt) {
|
match opt_loan_path(&move_info.cmt) {
|
||||||
Some(loan_path) => {
|
Some(loan_path) => {
|
||||||
move_data.add_move(bccx.tcx, loan_path,
|
move_data.add_move(bccx.tcx, loan_path,
|
||||||
move_info.id, move_info.kind);
|
move_info.id);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
// move from rvalue or raw pointer, hence ok
|
// move from rvalue or raw pointer, hence ok
|
||||||
|
|
|
@ -3,21 +3,17 @@
|
||||||
|
|
||||||
use crate::borrowck::*;
|
use crate::borrowck::*;
|
||||||
use rustc::hir::HirId;
|
use rustc::hir::HirId;
|
||||||
use rustc::middle::expr_use_visitor as euv;
|
|
||||||
use rustc::middle::mem_categorization as mc;
|
use rustc::middle::mem_categorization as mc;
|
||||||
use rustc::middle::mem_categorization::Categorization;
|
use rustc::middle::mem_categorization::Categorization;
|
||||||
use rustc::middle::region;
|
use rustc::middle::region;
|
||||||
use rustc::ty;
|
use rustc::ty;
|
||||||
|
|
||||||
use syntax_pos::Span;
|
|
||||||
use log::debug;
|
use log::debug;
|
||||||
|
|
||||||
type R = Result<(),()>;
|
type R = Result<(),()>;
|
||||||
|
|
||||||
pub fn guarantee_lifetime<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
|
pub fn guarantee_lifetime<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
|
||||||
item_scope: region::Scope,
|
item_scope: region::Scope,
|
||||||
span: Span,
|
|
||||||
cause: euv::LoanCause,
|
|
||||||
cmt: &'a mc::cmt_<'tcx>,
|
cmt: &'a mc::cmt_<'tcx>,
|
||||||
loan_region: ty::Region<'tcx>)
|
loan_region: ty::Region<'tcx>)
|
||||||
-> Result<(),()> {
|
-> Result<(),()> {
|
||||||
|
@ -26,12 +22,7 @@ pub fn guarantee_lifetime<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
|
||||||
//! and is scope of `cmt` otherwise.
|
//! and is scope of `cmt` otherwise.
|
||||||
debug!("guarantee_lifetime(cmt={:?}, loan_region={:?})",
|
debug!("guarantee_lifetime(cmt={:?}, loan_region={:?})",
|
||||||
cmt, loan_region);
|
cmt, loan_region);
|
||||||
let ctxt = GuaranteeLifetimeContext {bccx: bccx,
|
let ctxt = GuaranteeLifetimeContext { bccx, item_scope, loan_region };
|
||||||
item_scope,
|
|
||||||
span,
|
|
||||||
cause,
|
|
||||||
loan_region,
|
|
||||||
cmt_original: cmt};
|
|
||||||
ctxt.check(cmt, None)
|
ctxt.check(cmt, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,10 +35,7 @@ struct GuaranteeLifetimeContext<'a, 'tcx> {
|
||||||
// the scope of the function body for the enclosing item
|
// the scope of the function body for the enclosing item
|
||||||
item_scope: region::Scope,
|
item_scope: region::Scope,
|
||||||
|
|
||||||
span: Span,
|
|
||||||
cause: euv::LoanCause,
|
|
||||||
loan_region: ty::Region<'tcx>,
|
loan_region: ty::Region<'tcx>,
|
||||||
cmt_original: &'a mc::cmt_<'tcx>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> GuaranteeLifetimeContext<'a, '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`
|
//! Reports an error if `loan_region` is larger than `max_scope`
|
||||||
|
|
||||||
if !self.bccx.is_subregion_of(self.loan_region, 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 {
|
} else {
|
||||||
Ok(())
|
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 });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,6 @@ use restrictions::RestrictionResult;
|
||||||
mod lifetime;
|
mod lifetime;
|
||||||
mod restrictions;
|
mod restrictions;
|
||||||
mod gather_moves;
|
mod gather_moves;
|
||||||
mod move_error;
|
|
||||||
|
|
||||||
pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
|
pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
|
||||||
body: hir::BodyId)
|
body: hir::BodyId)
|
||||||
|
@ -38,7 +37,6 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
|
||||||
data: region::ScopeData::Node
|
data: region::ScopeData::Node
|
||||||
},
|
},
|
||||||
move_data: MoveData::default(),
|
move_data: MoveData::default(),
|
||||||
move_error_collector: move_error::MoveErrorCollector::new(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let rvalue_promotable_map = bccx.tcx.rvalue_promotable_map(def_id);
|
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))
|
Some(rvalue_promotable_map))
|
||||||
.consume_body(bccx.body);
|
.consume_body(bccx.body);
|
||||||
|
|
||||||
glcx.report_potential_errors();
|
|
||||||
let GatherLoanCtxt { all_loans, move_data, .. } = glcx;
|
let GatherLoanCtxt { all_loans, move_data, .. } = glcx;
|
||||||
(all_loans, move_data)
|
(all_loans, move_data)
|
||||||
}
|
}
|
||||||
|
@ -59,7 +56,6 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
|
||||||
struct GatherLoanCtxt<'a, 'tcx> {
|
struct GatherLoanCtxt<'a, 'tcx> {
|
||||||
bccx: &'a BorrowckCtxt<'a, 'tcx>,
|
bccx: &'a BorrowckCtxt<'a, 'tcx>,
|
||||||
move_data: move_data::MoveData<'tcx>,
|
move_data: move_data::MoveData<'tcx>,
|
||||||
move_error_collector: move_error::MoveErrorCollector<'tcx>,
|
|
||||||
all_loans: Vec<Loan<'tcx>>,
|
all_loans: Vec<Loan<'tcx>>,
|
||||||
/// `item_ub` is used as an upper-bound on the lifetime whenever we
|
/// `item_ub` is used as an upper-bound on the lifetime whenever we
|
||||||
/// ask for the scope of an expression categorized as an upvar.
|
/// 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);
|
consume_id, cmt, mode);
|
||||||
|
|
||||||
match mode {
|
match mode {
|
||||||
euv::Move(move_reason) => {
|
euv::Move(_) => {
|
||||||
gather_moves::gather_move_from_expr(
|
gather_moves::gather_move_from_expr(
|
||||||
self.bccx, &self.move_data, &mut self.move_error_collector,
|
self.bccx, &self.move_data,
|
||||||
consume_id.local_id, cmt, move_reason);
|
consume_id.local_id, cmt);
|
||||||
}
|
}
|
||||||
euv::Copy => { }
|
euv::Copy => { }
|
||||||
}
|
}
|
||||||
|
@ -110,13 +106,13 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
gather_moves::gather_move_from_pat(
|
gather_moves::gather_move_from_pat(
|
||||||
self.bccx, &self.move_data, &mut self.move_error_collector,
|
self.bccx, &self.move_data,
|
||||||
consume_pat, cmt);
|
consume_pat, cmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn borrow(&mut self,
|
fn borrow(&mut self,
|
||||||
borrow_id: hir::HirId,
|
borrow_id: hir::HirId,
|
||||||
borrow_span: Span,
|
_: Span,
|
||||||
cmt: &mc::cmt_<'tcx>,
|
cmt: &mc::cmt_<'tcx>,
|
||||||
loan_region: ty::Region<'tcx>,
|
loan_region: ty::Region<'tcx>,
|
||||||
bk: ty::BorrowKind,
|
bk: ty::BorrowKind,
|
||||||
|
@ -128,11 +124,9 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> {
|
||||||
bk, loan_cause);
|
bk, loan_cause);
|
||||||
|
|
||||||
self.guarantee_valid(borrow_id.local_id,
|
self.guarantee_valid(borrow_id.local_id,
|
||||||
borrow_span,
|
|
||||||
cmt,
|
cmt,
|
||||||
bk,
|
bk,
|
||||||
loan_region,
|
loan_region);
|
||||||
loan_cause);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mutate(&mut self,
|
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.
|
/// Implements the A-* rules in README.md.
|
||||||
fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
|
fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
|
||||||
borrow_span: Span,
|
|
||||||
loan_cause: AliasableViolationKind,
|
|
||||||
cmt: &mc::cmt_<'tcx>,
|
cmt: &mc::cmt_<'tcx>,
|
||||||
req_kind: ty::BorrowKind)
|
req_kind: ty::BorrowKind)
|
||||||
-> Result<(),()> {
|
-> Result<(),()> {
|
||||||
|
@ -198,13 +190,9 @@ fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
|
||||||
// user knows what they're doing in these cases.
|
// user knows what they're doing in these cases.
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
(mc::Aliasability::FreelyAliasable(alias_cause), ty::UniqueImmBorrow) |
|
(mc::Aliasability::FreelyAliasable(_), ty::UniqueImmBorrow) |
|
||||||
(mc::Aliasability::FreelyAliasable(alias_cause), ty::MutBorrow) => {
|
(mc::Aliasability::FreelyAliasable(_), ty::MutBorrow) => {
|
||||||
bccx.report_aliasability_violation(
|
bccx.signal_error();
|
||||||
borrow_span,
|
|
||||||
loan_cause,
|
|
||||||
alias_cause,
|
|
||||||
cmt);
|
|
||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
(..) => {
|
(..) => {
|
||||||
|
@ -215,13 +203,10 @@ fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
|
||||||
|
|
||||||
/// Implements the M-* rules in README.md.
|
/// Implements the M-* rules in README.md.
|
||||||
fn check_mutability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
|
fn check_mutability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
|
||||||
borrow_span: Span,
|
|
||||||
cause: AliasableViolationKind,
|
|
||||||
cmt: &mc::cmt_<'tcx>,
|
cmt: &mc::cmt_<'tcx>,
|
||||||
req_kind: ty::BorrowKind)
|
req_kind: ty::BorrowKind)
|
||||||
-> Result<(),()> {
|
-> Result<(),()> {
|
||||||
debug!("check_mutability(cause={:?} cmt={:?} req_kind={:?}",
|
debug!("check_mutability(cmt={:?} req_kind={:?}", cmt, req_kind);
|
||||||
cause, cmt, req_kind);
|
|
||||||
match req_kind {
|
match req_kind {
|
||||||
ty::UniqueImmBorrow | ty::ImmBorrow => {
|
ty::UniqueImmBorrow | ty::ImmBorrow => {
|
||||||
match cmt.mutbl {
|
match cmt.mutbl {
|
||||||
|
@ -239,10 +224,7 @@ fn check_mutability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
|
||||||
ty::MutBorrow => {
|
ty::MutBorrow => {
|
||||||
// Only mutable data can be lent as mutable.
|
// Only mutable data can be lent as mutable.
|
||||||
if !cmt.mutbl.is_mutable() {
|
if !cmt.mutbl.is_mutable() {
|
||||||
Err(bccx.report(BckError { span: borrow_span,
|
Err(bccx.signal_error())
|
||||||
cause,
|
|
||||||
cmt,
|
|
||||||
code: err_mutbl }))
|
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -268,26 +250,18 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
|
||||||
// mutable - this is checked in check_loans.
|
// mutable - this is checked in check_loans.
|
||||||
} else {
|
} else {
|
||||||
// Check that we don't allow assignments to non-mutable data.
|
// Check that we don't allow assignments to non-mutable data.
|
||||||
if check_mutability(self.bccx, assignment_span, MutabilityViolation,
|
if check_mutability(self.bccx, cmt, ty::MutBorrow).is_err() {
|
||||||
cmt, ty::MutBorrow).is_err() {
|
|
||||||
return; // reported an error, no sense in reporting more.
|
return; // reported an error, no sense in reporting more.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that we don't allow assignments to aliasable data
|
// Check that we don't allow assignments to aliasable data
|
||||||
if check_aliasability(self.bccx, assignment_span, MutabilityViolation,
|
if check_aliasability(self.bccx, cmt, ty::MutBorrow).is_err() {
|
||||||
cmt, ty::MutBorrow).is_err() {
|
|
||||||
return; // reported an error, no sense in reporting more.
|
return; // reported an error, no sense in reporting more.
|
||||||
}
|
}
|
||||||
|
|
||||||
match opt_lp {
|
match opt_lp {
|
||||||
Some(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,
|
gather_moves::gather_assignment(self.bccx, &self.move_data,
|
||||||
assignment_id.local_id,
|
assignment_id.local_id,
|
||||||
assignment_span,
|
assignment_span,
|
||||||
|
@ -306,11 +280,9 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
|
||||||
/// `req_loan_map`.
|
/// `req_loan_map`.
|
||||||
fn guarantee_valid(&mut self,
|
fn guarantee_valid(&mut self,
|
||||||
borrow_id: hir::ItemLocalId,
|
borrow_id: hir::ItemLocalId,
|
||||||
borrow_span: Span,
|
|
||||||
cmt: &mc::cmt_<'tcx>,
|
cmt: &mc::cmt_<'tcx>,
|
||||||
req_kind: ty::BorrowKind,
|
req_kind: ty::BorrowKind,
|
||||||
loan_region: ty::Region<'tcx>,
|
loan_region: ty::Region<'tcx>) {
|
||||||
cause: euv::LoanCause) {
|
|
||||||
debug!("guarantee_valid(borrow_id={:?}, cmt={:?}, \
|
debug!("guarantee_valid(borrow_id={:?}, cmt={:?}, \
|
||||||
req_mutbl={:?}, loan_region={:?})",
|
req_mutbl={:?}, loan_region={:?})",
|
||||||
borrow_id,
|
borrow_id,
|
||||||
|
@ -326,27 +298,23 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
// Check that the lifetime of the borrow does not exceed
|
// Check that the lifetime of the borrow does not exceed
|
||||||
// the lifetime of the data being borrowed.
|
// the lifetime of the data being borrowed.
|
||||||
if lifetime::guarantee_lifetime(self.bccx, self.item_ub,
|
if lifetime::guarantee_lifetime(self.bccx, self.item_ub, cmt, loan_region).is_err() {
|
||||||
borrow_span, cause, cmt, loan_region).is_err() {
|
|
||||||
return; // reported an error, no sense in reporting more.
|
return; // reported an error, no sense in reporting more.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that we don't allow mutable borrows of non-mutable data.
|
// Check that we don't allow mutable borrows of non-mutable data.
|
||||||
if check_mutability(self.bccx, borrow_span, BorrowViolation(cause),
|
if check_mutability(self.bccx, cmt, req_kind).is_err() {
|
||||||
cmt, req_kind).is_err() {
|
|
||||||
return; // reported an error, no sense in reporting more.
|
return; // reported an error, no sense in reporting more.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that we don't allow mutable borrows of aliasable data.
|
// Check that we don't allow mutable borrows of aliasable data.
|
||||||
if check_aliasability(self.bccx, borrow_span, BorrowViolation(cause),
|
if check_aliasability(self.bccx, cmt, req_kind).is_err() {
|
||||||
cmt, req_kind).is_err() {
|
|
||||||
return; // reported an error, no sense in reporting more.
|
return; // reported an error, no sense in reporting more.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute the restrictions that are required to enforce the
|
// Compute the restrictions that are required to enforce the
|
||||||
// loan is safe.
|
// loan is safe.
|
||||||
let restr = restrictions::compute_restrictions(
|
let restr = restrictions::compute_restrictions(self.bccx, &cmt, loan_region);
|
||||||
self.bccx, borrow_span, cause, &cmt, loan_region);
|
|
||||||
|
|
||||||
debug!("guarantee_valid(): restrictions={:?}", restr);
|
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);
|
let kill_scope = self.compute_kill_scope(loan_scope, &loan_path);
|
||||||
debug!("kill_scope = {:?}", kill_scope);
|
debug!("kill_scope = {:?}", kill_scope);
|
||||||
|
|
||||||
if req_kind == ty::MutBorrow {
|
|
||||||
self.mark_loan_path_as_mutated(&loan_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
Loan {
|
Loan {
|
||||||
index: self.all_loans.len(),
|
index: self.all_loans.len(),
|
||||||
loan_path,
|
loan_path,
|
||||||
kind: req_kind,
|
kind: req_kind,
|
||||||
gen_scope,
|
gen_scope,
|
||||||
kill_scope,
|
kill_scope,
|
||||||
span: borrow_span,
|
|
||||||
restricted_paths,
|
restricted_paths,
|
||||||
cause,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -419,70 +381,6 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
|
||||||
// let loan_gen_scope = loan.gen_scope;
|
// let loan_gen_scope = loan.gen_scope;
|
||||||
// let loan_kill_scope = loan.kill_scope;
|
// let loan_kill_scope = loan.kill_scope;
|
||||||
self.all_loans.push(loan);
|
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,
|
pub fn compute_gen_scope(&self,
|
||||||
|
@ -532,8 +430,4 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
|
||||||
loan_scope
|
loan_scope
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn report_potential_errors(&self) {
|
|
||||||
self.move_error_collector.report_potential_errors(self.bccx);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +1,9 @@
|
||||||
//! Computes the restrictions that result from a borrow.
|
//! Computes the restrictions that result from a borrow.
|
||||||
|
|
||||||
use crate::borrowck::*;
|
use crate::borrowck::*;
|
||||||
use rustc::middle::expr_use_visitor as euv;
|
|
||||||
use rustc::middle::mem_categorization as mc;
|
use rustc::middle::mem_categorization as mc;
|
||||||
use rustc::middle::mem_categorization::Categorization;
|
use rustc::middle::mem_categorization::Categorization;
|
||||||
use rustc::ty;
|
use rustc::ty;
|
||||||
use syntax_pos::Span;
|
|
||||||
use log::debug;
|
use log::debug;
|
||||||
|
|
||||||
use crate::borrowck::ToInteriorKind;
|
use crate::borrowck::ToInteriorKind;
|
||||||
|
@ -19,17 +17,10 @@ pub enum RestrictionResult<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compute_restrictions<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
|
pub fn compute_restrictions<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
|
||||||
span: Span,
|
|
||||||
cause: euv::LoanCause,
|
|
||||||
cmt: &mc::cmt_<'tcx>,
|
cmt: &mc::cmt_<'tcx>,
|
||||||
loan_region: ty::Region<'tcx>)
|
loan_region: ty::Region<'tcx>)
|
||||||
-> RestrictionResult<'tcx> {
|
-> RestrictionResult<'tcx> {
|
||||||
let ctxt = RestrictionsContext {
|
let ctxt = RestrictionsContext { bccx, loan_region };
|
||||||
bccx,
|
|
||||||
span,
|
|
||||||
cause,
|
|
||||||
loan_region,
|
|
||||||
};
|
|
||||||
|
|
||||||
ctxt.restrict(cmt)
|
ctxt.restrict(cmt)
|
||||||
}
|
}
|
||||||
|
@ -39,9 +30,7 @@ pub fn compute_restrictions<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
|
||||||
|
|
||||||
struct RestrictionsContext<'a, 'tcx> {
|
struct RestrictionsContext<'a, 'tcx> {
|
||||||
bccx: &'a BorrowckCtxt<'a, 'tcx>,
|
bccx: &'a BorrowckCtxt<'a, 'tcx>,
|
||||||
span: Span,
|
|
||||||
loan_region: ty::Region<'tcx>,
|
loan_region: ty::Region<'tcx>,
|
||||||
cause: euv::LoanCause,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
|
impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
|
||||||
|
@ -149,13 +138,7 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
|
||||||
mc::BorrowedPtr(bk, lt) => {
|
mc::BorrowedPtr(bk, lt) => {
|
||||||
// R-Deref-[Mut-]Borrowed
|
// R-Deref-[Mut-]Borrowed
|
||||||
if !self.bccx.is_subregion_of(self.loan_region, lt) {
|
if !self.bccx.is_subregion_of(self.loan_region, lt) {
|
||||||
self.bccx.report(
|
self.bccx.signal_error();
|
||||||
BckError {
|
|
||||||
span: self.span,
|
|
||||||
cause: BorrowViolation(self.cause),
|
|
||||||
cmt: &cmt_base,
|
|
||||||
code: err_borrowed_pointer_too_short(
|
|
||||||
self.loan_region, lt)});
|
|
||||||
return RestrictionResult::Safe;
|
return RestrictionResult::Safe;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,8 +1,6 @@
|
||||||
//! Data structures used for tracking moves. Please see the extensive
|
//! Data structures used for tracking moves. Please see the extensive
|
||||||
//! comments in the section "Moves and initialization" in `README.md`.
|
//! comments in the section "Moves and initialization" in `README.md`.
|
||||||
|
|
||||||
pub use MoveKind::*;
|
|
||||||
|
|
||||||
use crate::dataflow::{DataFlowContext, BitwiseOperator, DataFlowOperator, KillFrom};
|
use crate::dataflow::{DataFlowContext, BitwiseOperator, DataFlowOperator, KillFrom};
|
||||||
|
|
||||||
use crate::borrowck::*;
|
use crate::borrowck::*;
|
||||||
|
@ -101,13 +99,6 @@ pub struct MovePath<'tcx> {
|
||||||
pub next_sibling: MovePathIndex,
|
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)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct Move {
|
pub struct Move {
|
||||||
|
@ -117,9 +108,6 @@ pub struct Move {
|
||||||
/// ID of node that is doing the move.
|
/// ID of node that is doing the move.
|
||||||
pub id: hir::ItemLocalId,
|
pub id: hir::ItemLocalId,
|
||||||
|
|
||||||
/// Kind of move, for error messages.
|
|
||||||
pub kind: MoveKind,
|
|
||||||
|
|
||||||
/// Next node in linked list of moves from `path`, or `InvalidMoveIndex`
|
/// Next node in linked list of moves from `path`, or `InvalidMoveIndex`
|
||||||
pub next_move: MoveIndex
|
pub next_move: MoveIndex
|
||||||
}
|
}
|
||||||
|
@ -315,7 +303,6 @@ impl MoveData<'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
orig_lp: Rc<LoanPath<'tcx>>,
|
orig_lp: Rc<LoanPath<'tcx>>,
|
||||||
id: hir::ItemLocalId,
|
id: hir::ItemLocalId,
|
||||||
kind: MoveKind,
|
|
||||||
) {
|
) {
|
||||||
// Moving one union field automatically moves all its fields. Also move siblings of
|
// Moving one union field automatically moves all its fields. Also move siblings of
|
||||||
// all parent union fields, moves do not propagate upwards automatically.
|
// all parent union fields, moves do not propagate upwards automatically.
|
||||||
|
@ -331,7 +318,7 @@ impl MoveData<'tcx> {
|
||||||
let sibling_lp_kind =
|
let sibling_lp_kind =
|
||||||
LpExtend(base_lp.clone(), mutbl, LpInterior(opt_variant_id, field));
|
LpExtend(base_lp.clone(), mutbl, LpInterior(opt_variant_id, field));
|
||||||
let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, tcx.types.err));
|
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();
|
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(
|
fn add_move_helper(
|
||||||
|
@ -347,12 +334,8 @@ impl MoveData<'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
lp: Rc<LoanPath<'tcx>>,
|
lp: Rc<LoanPath<'tcx>>,
|
||||||
id: hir::ItemLocalId,
|
id: hir::ItemLocalId,
|
||||||
kind: MoveKind,
|
|
||||||
) {
|
) {
|
||||||
debug!("add_move(lp={:?}, id={:?}, kind={:?})",
|
debug!("add_move(lp={:?}, id={:?})", lp, id);
|
||||||
lp,
|
|
||||||
id,
|
|
||||||
kind);
|
|
||||||
|
|
||||||
let path_index = self.move_path(tcx, lp);
|
let path_index = self.move_path(tcx, lp);
|
||||||
let move_index = MoveIndex(self.moves.borrow().len());
|
let move_index = MoveIndex(self.moves.borrow().len());
|
||||||
|
@ -363,7 +346,6 @@ impl MoveData<'tcx> {
|
||||||
self.moves.borrow_mut().push(Move {
|
self.moves.borrow_mut().push(Move {
|
||||||
path: path_index,
|
path: path_index,
|
||||||
id,
|
id,
|
||||||
kind,
|
|
||||||
next_move,
|
next_move,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -611,19 +593,16 @@ impl<'tcx> FlowedMoveData<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn kind_of_move_of_path(&self,
|
pub fn is_move_path(&self, id: hir::ItemLocalId, loan_path: &Rc<LoanPath<'tcx>>) -> bool {
|
||||||
id: hir::ItemLocalId,
|
|
||||||
loan_path: &Rc<LoanPath<'tcx>>)
|
|
||||||
-> Option<MoveKind> {
|
|
||||||
//! Returns the kind of a move of `loan_path` by `id`, if one exists.
|
//! 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) {
|
if let Some(loan_path_index) = self.move_data.path_map.borrow().get(&*loan_path) {
|
||||||
self.dfcx_moves.each_gen_bit(id, |move_index| {
|
self.dfcx_moves.each_gen_bit(id, |move_index| {
|
||||||
let the_move = self.move_data.moves.borrow();
|
let the_move = self.move_data.moves.borrow();
|
||||||
let the_move = (*the_move)[move_index];
|
let the_move = (*the_move)[move_index];
|
||||||
if the_move.path == *loan_path_index {
|
if the_move.path == *loan_path_index {
|
||||||
ret = Some(the_move.kind);
|
ret = true;
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
true
|
true
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
#![allow(non_snake_case)]
|
|
|
@ -12,8 +12,8 @@ use rustc::session::config::Input;
|
||||||
use rustc::ty::{self, TyCtxt};
|
use rustc::ty::{self, TyCtxt};
|
||||||
use rustc::util::common::ErrorReported;
|
use rustc::util::common::ErrorReported;
|
||||||
use rustc_interface::util::ReplaceBodyWithLoop;
|
use rustc_interface::util::ReplaceBodyWithLoop;
|
||||||
use rustc_borrowck as borrowck;
|
use rustc_ast_borrowck as borrowck;
|
||||||
use rustc_borrowck::graphviz as borrowck_dot;
|
use rustc_ast_borrowck::graphviz as borrowck_dot;
|
||||||
use rustc_mir::util::{write_mir_pretty, write_mir_graphviz};
|
use rustc_mir::util::{write_mir_pretty, write_mir_graphviz};
|
||||||
|
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
|
|
|
@ -1,34 +1,13 @@
|
||||||
use rustc::session::config::BorrowckMode;
|
|
||||||
use rustc::ty::{self, Ty, TyCtxt};
|
use rustc::ty::{self, Ty, TyCtxt};
|
||||||
use rustc_errors::{DiagnosticBuilder, DiagnosticId};
|
use rustc_errors::{DiagnosticBuilder, DiagnosticId};
|
||||||
use syntax_pos::{MultiSpan, Span};
|
use syntax_pos::{MultiSpan, Span};
|
||||||
|
|
||||||
use std::fmt;
|
// FIXME(chrisvittal) remove Origin entirely
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
pub enum Origin {
|
pub enum Origin {
|
||||||
Ast,
|
|
||||||
Mir,
|
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 {
|
pub trait BorrowckErrors<'cx>: Sized + Copy {
|
||||||
fn struct_span_err_with_code<S: Into<MultiSpan>>(
|
fn struct_span_err_with_code<S: Into<MultiSpan>>(
|
||||||
self,
|
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>;
|
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(
|
fn cannot_move_when_borrowed(
|
||||||
self,
|
self,
|
||||||
span: Span,
|
span: Span,
|
||||||
desc: &str,
|
desc: &str,
|
||||||
o: Origin,
|
_: Origin,
|
||||||
) -> DiagnosticBuilder<'cx> {
|
) -> DiagnosticBuilder<'cx> {
|
||||||
let err = struct_span_err!(
|
struct_span_err!(
|
||||||
self,
|
self,
|
||||||
span,
|
span,
|
||||||
E0505,
|
E0505,
|
||||||
"cannot move out of `{}` because it is borrowed{OGN}",
|
"cannot move out of `{}` because it is borrowed",
|
||||||
desc,
|
desc,
|
||||||
OGN = o
|
)
|
||||||
);
|
|
||||||
self.cancel_if_wrong_origin(err, o)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cannot_use_when_mutably_borrowed(
|
fn cannot_use_when_mutably_borrowed(
|
||||||
|
@ -73,15 +39,14 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
|
||||||
desc: &str,
|
desc: &str,
|
||||||
borrow_span: Span,
|
borrow_span: Span,
|
||||||
borrow_desc: &str,
|
borrow_desc: &str,
|
||||||
o: Origin,
|
_: Origin,
|
||||||
) -> DiagnosticBuilder<'cx> {
|
) -> DiagnosticBuilder<'cx> {
|
||||||
let mut err = struct_span_err!(
|
let mut err = struct_span_err!(
|
||||||
self,
|
self,
|
||||||
span,
|
span,
|
||||||
E0503,
|
E0503,
|
||||||
"cannot use `{}` because it was mutably borrowed{OGN}",
|
"cannot use `{}` because it was mutably borrowed",
|
||||||
desc,
|
desc,
|
||||||
OGN = o
|
|
||||||
);
|
);
|
||||||
|
|
||||||
err.span_label(
|
err.span_label(
|
||||||
|
@ -89,8 +54,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
|
||||||
format!("borrow of `{}` occurs here", borrow_desc),
|
format!("borrow of `{}` occurs here", borrow_desc),
|
||||||
);
|
);
|
||||||
err.span_label(span, format!("use of borrowed `{}`", borrow_desc));
|
err.span_label(span, format!("use of borrowed `{}`", borrow_desc));
|
||||||
|
err
|
||||||
self.cancel_if_wrong_origin(err, o)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cannot_act_on_uninitialized_variable(
|
fn cannot_act_on_uninitialized_variable(
|
||||||
|
@ -98,18 +62,16 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
|
||||||
span: Span,
|
span: Span,
|
||||||
verb: &str,
|
verb: &str,
|
||||||
desc: &str,
|
desc: &str,
|
||||||
o: Origin,
|
_: Origin,
|
||||||
) -> DiagnosticBuilder<'cx> {
|
) -> DiagnosticBuilder<'cx> {
|
||||||
let err = struct_span_err!(
|
struct_span_err!(
|
||||||
self,
|
self,
|
||||||
span,
|
span,
|
||||||
E0381,
|
E0381,
|
||||||
"{} of possibly uninitialized variable: `{}`{OGN}",
|
"{} of possibly uninitialized variable: `{}`",
|
||||||
verb,
|
verb,
|
||||||
desc,
|
desc,
|
||||||
OGN = o
|
)
|
||||||
);
|
|
||||||
self.cancel_if_wrong_origin(err, o)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cannot_mutably_borrow_multiply(
|
fn cannot_mutably_borrow_multiply(
|
||||||
|
@ -120,7 +82,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
|
||||||
old_loan_span: Span,
|
old_loan_span: Span,
|
||||||
old_opt_via: &str,
|
old_opt_via: &str,
|
||||||
old_load_end_span: Option<Span>,
|
old_load_end_span: Option<Span>,
|
||||||
o: Origin,
|
_: Origin,
|
||||||
) -> DiagnosticBuilder<'cx> {
|
) -> DiagnosticBuilder<'cx> {
|
||||||
let via = |msg: &str|
|
let via = |msg: &str|
|
||||||
if msg.is_empty() { msg.to_string() } else { format!(" (via `{}`)", msg) };
|
if msg.is_empty() { msg.to_string() } else { format!(" (via `{}`)", msg) };
|
||||||
|
@ -128,10 +90,9 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
|
||||||
self,
|
self,
|
||||||
new_loan_span,
|
new_loan_span,
|
||||||
E0499,
|
E0499,
|
||||||
"cannot borrow `{}`{} as mutable more than once at a time{OGN}",
|
"cannot borrow `{}`{} as mutable more than once at a time",
|
||||||
desc,
|
desc,
|
||||||
via(opt_via),
|
via(opt_via),
|
||||||
OGN = o
|
|
||||||
);
|
);
|
||||||
if old_loan_span == new_loan_span {
|
if old_loan_span == new_loan_span {
|
||||||
// Both borrows are happening in the same place
|
// 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");
|
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(
|
fn cannot_uniquely_borrow_by_two_closures(
|
||||||
|
@ -169,15 +130,14 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
|
||||||
desc: &str,
|
desc: &str,
|
||||||
old_loan_span: Span,
|
old_loan_span: Span,
|
||||||
old_load_end_span: Option<Span>,
|
old_load_end_span: Option<Span>,
|
||||||
o: Origin,
|
_: Origin,
|
||||||
) -> DiagnosticBuilder<'cx> {
|
) -> DiagnosticBuilder<'cx> {
|
||||||
let mut err = struct_span_err!(
|
let mut err = struct_span_err!(
|
||||||
self,
|
self,
|
||||||
new_loan_span,
|
new_loan_span,
|
||||||
E0524,
|
E0524,
|
||||||
"two closures require unique access to `{}` at the same time{OGN}",
|
"two closures require unique access to `{}` at the same time",
|
||||||
desc,
|
desc,
|
||||||
OGN = o
|
|
||||||
);
|
);
|
||||||
if old_loan_span == new_loan_span {
|
if old_loan_span == new_loan_span {
|
||||||
err.span_label(
|
err.span_label(
|
||||||
|
@ -191,7 +151,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
|
||||||
if let Some(old_load_end_span) = old_load_end_span {
|
if let Some(old_load_end_span) = old_load_end_span {
|
||||||
err.span_label(old_load_end_span, "borrow from first closure ends here");
|
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(
|
fn cannot_uniquely_borrow_by_one_closure(
|
||||||
|
@ -204,17 +164,16 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
|
||||||
noun_old: &str,
|
noun_old: &str,
|
||||||
old_opt_via: &str,
|
old_opt_via: &str,
|
||||||
previous_end_span: Option<Span>,
|
previous_end_span: Option<Span>,
|
||||||
o: Origin,
|
_: Origin,
|
||||||
) -> DiagnosticBuilder<'cx> {
|
) -> DiagnosticBuilder<'cx> {
|
||||||
let mut err = struct_span_err!(
|
let mut err = struct_span_err!(
|
||||||
self,
|
self,
|
||||||
new_loan_span,
|
new_loan_span,
|
||||||
E0500,
|
E0500,
|
||||||
"closure requires unique access to `{}` but {} is already borrowed{}{OGN}",
|
"closure requires unique access to `{}` but {} is already borrowed{}",
|
||||||
desc_new,
|
desc_new,
|
||||||
noun_old,
|
noun_old,
|
||||||
old_opt_via,
|
old_opt_via,
|
||||||
OGN = o
|
|
||||||
);
|
);
|
||||||
err.span_label(
|
err.span_label(
|
||||||
new_loan_span,
|
new_loan_span,
|
||||||
|
@ -224,7 +183,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
|
||||||
if let Some(previous_end_span) = previous_end_span {
|
if let Some(previous_end_span) = previous_end_span {
|
||||||
err.span_label(previous_end_span, "borrow ends here");
|
err.span_label(previous_end_span, "borrow ends here");
|
||||||
}
|
}
|
||||||
self.cancel_if_wrong_origin(err, o)
|
err
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cannot_reborrow_already_uniquely_borrowed(
|
fn cannot_reborrow_already_uniquely_borrowed(
|
||||||
|
@ -238,18 +197,17 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
|
||||||
old_opt_via: &str,
|
old_opt_via: &str,
|
||||||
previous_end_span: Option<Span>,
|
previous_end_span: Option<Span>,
|
||||||
second_borrow_desc: &str,
|
second_borrow_desc: &str,
|
||||||
o: Origin,
|
_: Origin,
|
||||||
) -> DiagnosticBuilder<'cx> {
|
) -> DiagnosticBuilder<'cx> {
|
||||||
let mut err = struct_span_err!(
|
let mut err = struct_span_err!(
|
||||||
self,
|
self,
|
||||||
new_loan_span,
|
new_loan_span,
|
||||||
E0501,
|
E0501,
|
||||||
"cannot borrow `{}`{} as {} because previous closure \
|
"cannot borrow `{}`{} as {} because previous closure \
|
||||||
requires unique access{OGN}",
|
requires unique access",
|
||||||
desc_new,
|
desc_new,
|
||||||
opt_via,
|
opt_via,
|
||||||
kind_new,
|
kind_new,
|
||||||
OGN = o
|
|
||||||
);
|
);
|
||||||
err.span_label(
|
err.span_label(
|
||||||
new_loan_span,
|
new_loan_span,
|
||||||
|
@ -262,7 +220,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
|
||||||
if let Some(previous_end_span) = previous_end_span {
|
if let Some(previous_end_span) = previous_end_span {
|
||||||
err.span_label(previous_end_span, "borrow from closure ends here");
|
err.span_label(previous_end_span, "borrow from closure ends here");
|
||||||
}
|
}
|
||||||
self.cancel_if_wrong_origin(err, o)
|
err
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cannot_reborrow_already_borrowed(
|
fn cannot_reborrow_already_borrowed(
|
||||||
|
@ -276,7 +234,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
|
||||||
kind_old: &str,
|
kind_old: &str,
|
||||||
msg_old: &str,
|
msg_old: &str,
|
||||||
old_load_end_span: Option<Span>,
|
old_load_end_span: Option<Span>,
|
||||||
o: Origin,
|
_: Origin,
|
||||||
) -> DiagnosticBuilder<'cx> {
|
) -> DiagnosticBuilder<'cx> {
|
||||||
let via = |msg: &str|
|
let via = |msg: &str|
|
||||||
if msg.is_empty() { msg.to_string() } else { format!(" (via `{}`)", msg) };
|
if msg.is_empty() { msg.to_string() } else { format!(" (via `{}`)", msg) };
|
||||||
|
@ -285,14 +243,13 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
|
||||||
span,
|
span,
|
||||||
E0502,
|
E0502,
|
||||||
"cannot borrow `{}`{} as {} because {} is also borrowed \
|
"cannot borrow `{}`{} as {} because {} is also borrowed \
|
||||||
as {}{}{OGN}",
|
as {}{}",
|
||||||
desc_new,
|
desc_new,
|
||||||
via(msg_new),
|
via(msg_new),
|
||||||
kind_new,
|
kind_new,
|
||||||
noun_old,
|
noun_old,
|
||||||
kind_old,
|
kind_old,
|
||||||
via(msg_old),
|
via(msg_old),
|
||||||
OGN = o
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if msg_new == "" {
|
if msg_new == "" {
|
||||||
|
@ -317,8 +274,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
|
||||||
if let Some(old_load_end_span) = old_load_end_span {
|
if let Some(old_load_end_span) = old_load_end_span {
|
||||||
err.span_label(old_load_end_span, format!("{} borrow ends here", kind_old));
|
err.span_label(old_load_end_span, format!("{} borrow ends here", kind_old));
|
||||||
}
|
}
|
||||||
|
err
|
||||||
self.cancel_if_wrong_origin(err, o)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cannot_assign_to_borrowed(
|
fn cannot_assign_to_borrowed(
|
||||||
|
@ -326,15 +282,14 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
|
||||||
span: Span,
|
span: Span,
|
||||||
borrow_span: Span,
|
borrow_span: Span,
|
||||||
desc: &str,
|
desc: &str,
|
||||||
o: Origin,
|
_: Origin,
|
||||||
) -> DiagnosticBuilder<'cx> {
|
) -> DiagnosticBuilder<'cx> {
|
||||||
let mut err = struct_span_err!(
|
let mut err = struct_span_err!(
|
||||||
self,
|
self,
|
||||||
span,
|
span,
|
||||||
E0506,
|
E0506,
|
||||||
"cannot assign to `{}` because it is borrowed{OGN}",
|
"cannot assign to `{}` because it is borrowed",
|
||||||
desc,
|
desc,
|
||||||
OGN = o
|
|
||||||
);
|
);
|
||||||
|
|
||||||
err.span_label(borrow_span, format!("borrow of `{}` occurs here", desc));
|
err.span_label(borrow_span, format!("borrow of `{}` occurs here", desc));
|
||||||
|
@ -342,21 +297,17 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
|
||||||
span,
|
span,
|
||||||
format!("assignment to borrowed `{}` occurs here", desc),
|
format!("assignment to borrowed `{}` occurs here", desc),
|
||||||
);
|
);
|
||||||
|
err
|
||||||
self.cancel_if_wrong_origin(err, o)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cannot_move_into_closure(self, span: Span, desc: &str, o: Origin) -> DiagnosticBuilder<'cx> {
|
fn cannot_move_into_closure(self, span: Span, desc: &str, _: Origin) -> DiagnosticBuilder<'cx> {
|
||||||
let err = struct_span_err!(
|
struct_span_err!(
|
||||||
self,
|
self,
|
||||||
span,
|
span,
|
||||||
E0504,
|
E0504,
|
||||||
"cannot move `{}` into closure because it is borrowed{OGN}",
|
"cannot move `{}` into closure because it is borrowed",
|
||||||
desc,
|
desc,
|
||||||
OGN = o
|
)
|
||||||
);
|
|
||||||
|
|
||||||
self.cancel_if_wrong_origin(err, o)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cannot_reassign_immutable(
|
fn cannot_reassign_immutable(
|
||||||
|
@ -364,29 +315,25 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
|
||||||
span: Span,
|
span: Span,
|
||||||
desc: &str,
|
desc: &str,
|
||||||
is_arg: bool,
|
is_arg: bool,
|
||||||
o: Origin,
|
_: Origin,
|
||||||
) -> DiagnosticBuilder<'cx> {
|
) -> DiagnosticBuilder<'cx> {
|
||||||
let msg = if is_arg {
|
let msg = if is_arg {
|
||||||
"to immutable argument"
|
"to immutable argument"
|
||||||
} else {
|
} else {
|
||||||
"twice to immutable variable"
|
"twice to immutable variable"
|
||||||
};
|
};
|
||||||
let err = struct_span_err!(
|
struct_span_err!(
|
||||||
self,
|
self,
|
||||||
span,
|
span,
|
||||||
E0384,
|
E0384,
|
||||||
"cannot assign {} `{}`{OGN}",
|
"cannot assign {} `{}`",
|
||||||
msg,
|
msg,
|
||||||
desc,
|
desc,
|
||||||
OGN = o
|
)
|
||||||
);
|
|
||||||
|
|
||||||
self.cancel_if_wrong_origin(err, o)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cannot_assign(self, span: Span, desc: &str, o: Origin) -> DiagnosticBuilder<'cx> {
|
fn cannot_assign(self, span: Span, desc: &str, _: Origin) -> DiagnosticBuilder<'cx> {
|
||||||
let err = struct_span_err!(self, span, E0594, "cannot assign to {}{OGN}", desc, OGN = o);
|
struct_span_err!(self, span, E0594, "cannot assign to {}", desc)
|
||||||
self.cancel_if_wrong_origin(err, o)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cannot_assign_static(self, span: Span, desc: &str, o: Origin) -> DiagnosticBuilder<'cx> {
|
fn cannot_assign_static(self, span: Span, desc: &str, o: Origin) -> DiagnosticBuilder<'cx> {
|
||||||
|
@ -397,18 +344,15 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
|
||||||
self,
|
self,
|
||||||
move_from_span: Span,
|
move_from_span: Span,
|
||||||
move_from_desc: &str,
|
move_from_desc: &str,
|
||||||
o: Origin,
|
_: Origin,
|
||||||
) -> DiagnosticBuilder<'cx> {
|
) -> DiagnosticBuilder<'cx> {
|
||||||
let err = struct_span_err!(
|
struct_span_err!(
|
||||||
self,
|
self,
|
||||||
move_from_span,
|
move_from_span,
|
||||||
E0507,
|
E0507,
|
||||||
"cannot move out of {}{OGN}",
|
"cannot move out of {}",
|
||||||
move_from_desc,
|
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
|
/// 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,
|
move_from_span: Span,
|
||||||
ty: Ty<'_>,
|
ty: Ty<'_>,
|
||||||
is_index: Option<bool>,
|
is_index: Option<bool>,
|
||||||
o: Origin,
|
_: Origin,
|
||||||
) -> DiagnosticBuilder<'cx> {
|
) -> DiagnosticBuilder<'cx> {
|
||||||
let type_name = match (&ty.sty, is_index) {
|
let type_name = match (&ty.sty, is_index) {
|
||||||
(&ty::Array(_, _), Some(true)) | (&ty::Array(_, _), None) => "array",
|
(&ty::Array(_, _), Some(true)) | (&ty::Array(_, _), None) => "array",
|
||||||
|
@ -430,33 +374,29 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
|
||||||
self,
|
self,
|
||||||
move_from_span,
|
move_from_span,
|
||||||
E0508,
|
E0508,
|
||||||
"cannot move out of type `{}`, a non-copy {}{OGN}",
|
"cannot move out of type `{}`, a non-copy {}",
|
||||||
ty,
|
ty,
|
||||||
type_name,
|
type_name,
|
||||||
OGN = o
|
|
||||||
);
|
);
|
||||||
err.span_label(move_from_span, "cannot move out of here");
|
err.span_label(move_from_span, "cannot move out of here");
|
||||||
|
err
|
||||||
self.cancel_if_wrong_origin(err, o)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cannot_move_out_of_interior_of_drop(
|
fn cannot_move_out_of_interior_of_drop(
|
||||||
self,
|
self,
|
||||||
move_from_span: Span,
|
move_from_span: Span,
|
||||||
container_ty: Ty<'_>,
|
container_ty: Ty<'_>,
|
||||||
o: Origin,
|
_: Origin,
|
||||||
) -> DiagnosticBuilder<'cx> {
|
) -> DiagnosticBuilder<'cx> {
|
||||||
let mut err = struct_span_err!(
|
let mut err = struct_span_err!(
|
||||||
self,
|
self,
|
||||||
move_from_span,
|
move_from_span,
|
||||||
E0509,
|
E0509,
|
||||||
"cannot move out of type `{}`, which implements the `Drop` trait{OGN}",
|
"cannot move out of type `{}`, which implements the `Drop` trait",
|
||||||
container_ty,
|
container_ty,
|
||||||
OGN = o
|
|
||||||
);
|
);
|
||||||
err.span_label(move_from_span, "cannot move out of here");
|
err.span_label(move_from_span, "cannot move out of here");
|
||||||
|
err
|
||||||
self.cancel_if_wrong_origin(err, o)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cannot_act_on_moved_value(
|
fn cannot_act_on_moved_value(
|
||||||
|
@ -465,60 +405,51 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
|
||||||
verb: &str,
|
verb: &str,
|
||||||
optional_adverb_for_moved: &str,
|
optional_adverb_for_moved: &str,
|
||||||
moved_path: Option<String>,
|
moved_path: Option<String>,
|
||||||
o: Origin,
|
_: Origin,
|
||||||
) -> DiagnosticBuilder<'cx> {
|
) -> DiagnosticBuilder<'cx> {
|
||||||
let moved_path = moved_path
|
let moved_path = moved_path
|
||||||
.map(|mp| format!(": `{}`", mp))
|
.map(|mp| format!(": `{}`", mp))
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
let err = struct_span_err!(
|
struct_span_err!(
|
||||||
self,
|
self,
|
||||||
use_span,
|
use_span,
|
||||||
E0382,
|
E0382,
|
||||||
"{} of {}moved value{}{OGN}",
|
"{} of {}moved value{}",
|
||||||
verb,
|
verb,
|
||||||
optional_adverb_for_moved,
|
optional_adverb_for_moved,
|
||||||
moved_path,
|
moved_path,
|
||||||
OGN = o
|
)
|
||||||
);
|
|
||||||
|
|
||||||
self.cancel_if_wrong_origin(err, o)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cannot_partially_reinit_an_uninit_struct(
|
fn cannot_partially_reinit_an_uninit_struct(
|
||||||
self,
|
self,
|
||||||
span: Span,
|
span: Span,
|
||||||
uninit_path: &str,
|
uninit_path: &str,
|
||||||
o: Origin,
|
_: Origin,
|
||||||
) -> DiagnosticBuilder<'cx> {
|
) -> DiagnosticBuilder<'cx> {
|
||||||
let err = struct_span_err!(
|
struct_span_err!(
|
||||||
self,
|
self,
|
||||||
span,
|
span,
|
||||||
E0383,
|
E0383,
|
||||||
"partial reinitialization of uninitialized structure `{}`{OGN}",
|
"partial reinitialization of uninitialized structure `{}`",
|
||||||
uninit_path,
|
uninit_path,
|
||||||
OGN = o
|
)
|
||||||
);
|
|
||||||
|
|
||||||
self.cancel_if_wrong_origin(err, o)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn closure_cannot_assign_to_borrowed(
|
fn closure_cannot_assign_to_borrowed(
|
||||||
self,
|
self,
|
||||||
span: Span,
|
span: Span,
|
||||||
descr: &str,
|
descr: &str,
|
||||||
o: Origin,
|
_: Origin,
|
||||||
) -> DiagnosticBuilder<'cx> {
|
) -> DiagnosticBuilder<'cx> {
|
||||||
let err = struct_span_err!(
|
struct_span_err!(
|
||||||
self,
|
self,
|
||||||
span,
|
span,
|
||||||
E0595,
|
E0595,
|
||||||
"closure cannot assign to {}{OGN}",
|
"closure cannot assign to {}",
|
||||||
descr,
|
descr,
|
||||||
OGN = o
|
)
|
||||||
);
|
|
||||||
|
|
||||||
self.cancel_if_wrong_origin(err, o)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cannot_borrow_path_as_mutable_because(
|
fn cannot_borrow_path_as_mutable_because(
|
||||||
|
@ -526,19 +457,16 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
|
||||||
span: Span,
|
span: Span,
|
||||||
path: &str,
|
path: &str,
|
||||||
reason: &str,
|
reason: &str,
|
||||||
o: Origin,
|
_: Origin,
|
||||||
) -> DiagnosticBuilder<'cx> {
|
) -> DiagnosticBuilder<'cx> {
|
||||||
let err = struct_span_err!(
|
struct_span_err!(
|
||||||
self,
|
self,
|
||||||
span,
|
span,
|
||||||
E0596,
|
E0596,
|
||||||
"cannot borrow {} as mutable{}{OGN}",
|
"cannot borrow {} as mutable{}",
|
||||||
path,
|
path,
|
||||||
reason,
|
reason,
|
||||||
OGN = o,
|
)
|
||||||
);
|
|
||||||
|
|
||||||
self.cancel_if_wrong_origin(err, o)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cannot_borrow_path_as_mutable(
|
fn cannot_borrow_path_as_mutable(
|
||||||
|
@ -556,73 +484,63 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
|
||||||
match_span: Span,
|
match_span: Span,
|
||||||
match_place: &str,
|
match_place: &str,
|
||||||
action: &str,
|
action: &str,
|
||||||
o: Origin,
|
_: Origin,
|
||||||
) -> DiagnosticBuilder<'cx> {
|
) -> DiagnosticBuilder<'cx> {
|
||||||
let mut err = struct_span_err!(
|
let mut err = struct_span_err!(
|
||||||
self,
|
self,
|
||||||
mutate_span,
|
mutate_span,
|
||||||
E0510,
|
E0510,
|
||||||
"cannot {} `{}` in match guard{OGN}",
|
"cannot {} `{}` in match guard",
|
||||||
action,
|
action,
|
||||||
match_place,
|
match_place,
|
||||||
OGN = o
|
|
||||||
);
|
);
|
||||||
err.span_label(mutate_span, format!("cannot {}", action));
|
err.span_label(mutate_span, format!("cannot {}", action));
|
||||||
err.span_label(match_span, String::from("value is immutable in match guard"));
|
err.span_label(match_span, String::from("value is immutable in match guard"));
|
||||||
|
err
|
||||||
self.cancel_if_wrong_origin(err, o)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cannot_borrow_across_generator_yield(
|
fn cannot_borrow_across_generator_yield(
|
||||||
self,
|
self,
|
||||||
span: Span,
|
span: Span,
|
||||||
yield_span: Span,
|
yield_span: Span,
|
||||||
o: Origin,
|
_: Origin,
|
||||||
) -> DiagnosticBuilder<'cx> {
|
) -> DiagnosticBuilder<'cx> {
|
||||||
let mut err = struct_span_err!(
|
let mut err = struct_span_err!(
|
||||||
self,
|
self,
|
||||||
span,
|
span,
|
||||||
E0626,
|
E0626,
|
||||||
"borrow may still be in use when generator yields{OGN}",
|
"borrow may still be in use when generator yields",
|
||||||
OGN = o
|
|
||||||
);
|
);
|
||||||
err.span_label(yield_span, "possible yield occurs here");
|
err.span_label(yield_span, "possible yield occurs here");
|
||||||
|
err
|
||||||
self.cancel_if_wrong_origin(err, o)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cannot_borrow_across_destructor(
|
fn cannot_borrow_across_destructor(
|
||||||
self,
|
self,
|
||||||
borrow_span: Span,
|
borrow_span: Span,
|
||||||
o: Origin,
|
_: Origin,
|
||||||
) -> DiagnosticBuilder<'cx> {
|
) -> DiagnosticBuilder<'cx> {
|
||||||
let err = struct_span_err!(
|
struct_span_err!(
|
||||||
self,
|
self,
|
||||||
borrow_span,
|
borrow_span,
|
||||||
E0713,
|
E0713,
|
||||||
"borrow may still be in use when destructor runs{OGN}",
|
"borrow may still be in use when destructor runs",
|
||||||
OGN = o
|
)
|
||||||
);
|
|
||||||
|
|
||||||
self.cancel_if_wrong_origin(err, o)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn path_does_not_live_long_enough(
|
fn path_does_not_live_long_enough(
|
||||||
self,
|
self,
|
||||||
span: Span,
|
span: Span,
|
||||||
path: &str,
|
path: &str,
|
||||||
o: Origin,
|
_: Origin,
|
||||||
) -> DiagnosticBuilder<'cx> {
|
) -> DiagnosticBuilder<'cx> {
|
||||||
let err = struct_span_err!(
|
struct_span_err!(
|
||||||
self,
|
self,
|
||||||
span,
|
span,
|
||||||
E0597,
|
E0597,
|
||||||
"{} does not live long enough{OGN}",
|
"{} does not live long enough",
|
||||||
path,
|
path,
|
||||||
OGN = o
|
)
|
||||||
);
|
|
||||||
|
|
||||||
self.cancel_if_wrong_origin(err, o)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cannot_return_reference_to_local(
|
fn cannot_return_reference_to_local(
|
||||||
|
@ -631,17 +549,16 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
|
||||||
return_kind: &str,
|
return_kind: &str,
|
||||||
reference_desc: &str,
|
reference_desc: &str,
|
||||||
path_desc: &str,
|
path_desc: &str,
|
||||||
o: Origin,
|
_: Origin,
|
||||||
) -> DiagnosticBuilder<'cx> {
|
) -> DiagnosticBuilder<'cx> {
|
||||||
let mut err = struct_span_err!(
|
let mut err = struct_span_err!(
|
||||||
self,
|
self,
|
||||||
span,
|
span,
|
||||||
E0515,
|
E0515,
|
||||||
"cannot {RETURN} {REFERENCE} {LOCAL}{OGN}",
|
"cannot {RETURN} {REFERENCE} {LOCAL}",
|
||||||
RETURN=return_kind,
|
RETURN=return_kind,
|
||||||
REFERENCE=reference_desc,
|
REFERENCE=reference_desc,
|
||||||
LOCAL=path_desc,
|
LOCAL=path_desc,
|
||||||
OGN = o
|
|
||||||
);
|
);
|
||||||
|
|
||||||
err.span_label(
|
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),
|
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(
|
fn lifetime_too_short_for_reborrow(
|
||||||
self,
|
self,
|
||||||
span: Span,
|
span: Span,
|
||||||
path: &str,
|
path: &str,
|
||||||
o: Origin,
|
_: Origin,
|
||||||
) -> DiagnosticBuilder<'cx> {
|
) -> DiagnosticBuilder<'cx> {
|
||||||
let err = struct_span_err!(
|
struct_span_err!(
|
||||||
self,
|
self,
|
||||||
span,
|
span,
|
||||||
E0598,
|
E0598,
|
||||||
"lifetime of {} is too short to guarantee \
|
"lifetime of {} is too short to guarantee \
|
||||||
its contents can be safely reborrowed{OGN}",
|
its contents can be safely reborrowed",
|
||||||
path,
|
path,
|
||||||
OGN = o
|
)
|
||||||
);
|
|
||||||
|
|
||||||
self.cancel_if_wrong_origin(err, o)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cannot_act_on_capture_in_sharable_fn(
|
fn cannot_act_on_capture_in_sharable_fn(
|
||||||
|
@ -676,39 +590,35 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
|
||||||
span: Span,
|
span: Span,
|
||||||
bad_thing: &str,
|
bad_thing: &str,
|
||||||
help: (Span, &str),
|
help: (Span, &str),
|
||||||
o: Origin,
|
_: Origin,
|
||||||
) -> DiagnosticBuilder<'cx> {
|
) -> DiagnosticBuilder<'cx> {
|
||||||
let (help_span, help_msg) = help;
|
let (help_span, help_msg) = help;
|
||||||
let mut err = struct_span_err!(
|
let mut err = struct_span_err!(
|
||||||
self,
|
self,
|
||||||
span,
|
span,
|
||||||
E0387,
|
E0387,
|
||||||
"{} in a captured outer variable in an `Fn` closure{OGN}",
|
"{} in a captured outer variable in an `Fn` closure",
|
||||||
bad_thing,
|
bad_thing,
|
||||||
OGN = o
|
|
||||||
);
|
);
|
||||||
err.span_help(help_span, help_msg);
|
err.span_help(help_span, help_msg);
|
||||||
|
err
|
||||||
self.cancel_if_wrong_origin(err, o)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cannot_assign_into_immutable_reference(
|
fn cannot_assign_into_immutable_reference(
|
||||||
self,
|
self,
|
||||||
span: Span,
|
span: Span,
|
||||||
bad_thing: &str,
|
bad_thing: &str,
|
||||||
o: Origin,
|
_: Origin,
|
||||||
) -> DiagnosticBuilder<'cx> {
|
) -> DiagnosticBuilder<'cx> {
|
||||||
let mut err = struct_span_err!(
|
let mut err = struct_span_err!(
|
||||||
self,
|
self,
|
||||||
span,
|
span,
|
||||||
E0389,
|
E0389,
|
||||||
"{} in a `&` reference{OGN}",
|
"{} in a `&` reference",
|
||||||
bad_thing,
|
bad_thing,
|
||||||
OGN = o
|
|
||||||
);
|
);
|
||||||
err.span_label(span, "assignment into an immutable reference");
|
err.span_label(span, "assignment into an immutable reference");
|
||||||
|
err
|
||||||
self.cancel_if_wrong_origin(err, o)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cannot_capture_in_long_lived_closure(
|
fn cannot_capture_in_long_lived_closure(
|
||||||
|
@ -716,7 +626,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
|
||||||
closure_span: Span,
|
closure_span: Span,
|
||||||
borrowed_path: &str,
|
borrowed_path: &str,
|
||||||
capture_span: Span,
|
capture_span: Span,
|
||||||
o: Origin,
|
_: Origin,
|
||||||
) -> DiagnosticBuilder<'cx> {
|
) -> DiagnosticBuilder<'cx> {
|
||||||
let mut err = struct_span_err!(
|
let mut err = struct_span_err!(
|
||||||
self,
|
self,
|
||||||
|
@ -724,67 +634,56 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
|
||||||
E0373,
|
E0373,
|
||||||
"closure may outlive the current function, \
|
"closure may outlive the current function, \
|
||||||
but it borrows {}, \
|
but it borrows {}, \
|
||||||
which is owned by the current function{OGN}",
|
which is owned by the current function",
|
||||||
borrowed_path,
|
borrowed_path,
|
||||||
OGN = o
|
|
||||||
);
|
);
|
||||||
err.span_label(capture_span, format!("{} is borrowed here", borrowed_path))
|
err.span_label(capture_span, format!("{} is borrowed here", borrowed_path))
|
||||||
.span_label(
|
.span_label(
|
||||||
closure_span,
|
closure_span,
|
||||||
format!("may outlive borrowed value {}", borrowed_path),
|
format!("may outlive borrowed value {}", borrowed_path),
|
||||||
);
|
);
|
||||||
|
err
|
||||||
self.cancel_if_wrong_origin(err, o)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn borrowed_data_escapes_closure(
|
fn borrowed_data_escapes_closure(
|
||||||
self,
|
self,
|
||||||
escape_span: Span,
|
escape_span: Span,
|
||||||
escapes_from: &str,
|
escapes_from: &str,
|
||||||
o: Origin,
|
_: Origin,
|
||||||
) -> DiagnosticBuilder<'cx> {
|
) -> DiagnosticBuilder<'cx> {
|
||||||
let err = struct_span_err!(
|
struct_span_err!(
|
||||||
self,
|
self,
|
||||||
escape_span,
|
escape_span,
|
||||||
E0521,
|
E0521,
|
||||||
"borrowed data escapes outside of {}{OGN}",
|
"borrowed data escapes outside of {}",
|
||||||
escapes_from,
|
escapes_from,
|
||||||
OGN = o
|
)
|
||||||
);
|
|
||||||
|
|
||||||
self.cancel_if_wrong_origin(err, o)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn thread_local_value_does_not_live_long_enough(
|
fn thread_local_value_does_not_live_long_enough(
|
||||||
self,
|
self,
|
||||||
span: Span,
|
span: Span,
|
||||||
o: Origin,
|
_: Origin,
|
||||||
) -> DiagnosticBuilder<'cx> {
|
) -> DiagnosticBuilder<'cx> {
|
||||||
let err = struct_span_err!(
|
struct_span_err!(
|
||||||
self,
|
self,
|
||||||
span,
|
span,
|
||||||
E0712,
|
E0712,
|
||||||
"thread-local variable borrowed past end of function{OGN}",
|
"thread-local variable borrowed past end of function",
|
||||||
OGN = o
|
)
|
||||||
);
|
|
||||||
|
|
||||||
self.cancel_if_wrong_origin(err, o)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn temporary_value_borrowed_for_too_long(
|
fn temporary_value_borrowed_for_too_long(
|
||||||
self,
|
self,
|
||||||
span: Span,
|
span: Span,
|
||||||
o: Origin,
|
_: Origin,
|
||||||
) -> DiagnosticBuilder<'cx> {
|
) -> DiagnosticBuilder<'cx> {
|
||||||
let err = struct_span_err!(
|
struct_span_err!(
|
||||||
self,
|
self,
|
||||||
span,
|
span,
|
||||||
E0716,
|
E0716,
|
||||||
"temporary value dropped while borrowed{OGN}",
|
"temporary value dropped while borrowed",
|
||||||
OGN = o
|
)
|
||||||
);
|
|
||||||
|
|
||||||
self.cancel_if_wrong_origin(err, o)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -801,15 +700,4 @@ impl BorrowckErrors<'tcx> for TyCtxt<'tcx> {
|
||||||
fn struct_span_err<S: Into<MultiSpan>>(self, sp: S, msg: &str) -> DiagnosticBuilder<'tcx> {
|
fn struct_span_err<S: Into<MultiSpan>>(self, sp: S, msg: &str) -> DiagnosticBuilder<'tcx> {
|
||||||
self.sess.struct_span_err(sp, msg)
|
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue