mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-20 02:43:45 +00:00
auto merge of #17434 : P1start/rust/borrowck-messages, r=nikomatsakis
This was originally part of #17215. Closes #15506. Closes #15630. Closes #17263. This also partially implements #15838.
This commit is contained in:
commit
84a4a07bbd
@ -400,50 +400,82 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
||||
for restr_path in loan1.restricted_paths.iter() {
|
||||
if *restr_path != loan2_base_path { continue; }
|
||||
|
||||
let old_pronoun = if new_loan.loan_path == old_loan.loan_path {
|
||||
// If new_loan is something like `x.a`, and old_loan is something like `x.b`, we would
|
||||
// normally generate a rather confusing message (in this case, for multiple mutable
|
||||
// borrows):
|
||||
//
|
||||
// error: cannot borrow `x.b` as mutable more than once at a time
|
||||
// note: previous borrow of `x.a` occurs here; the mutable borrow prevents
|
||||
// subsequent moves, borrows, or modification of `x.a` until the borrow ends
|
||||
//
|
||||
// What we want to do instead is get the 'common ancestor' of the two borrow paths and
|
||||
// use that for most of the message instead, giving is something like this:
|
||||
//
|
||||
// error: cannot borrow `x` as mutable more than once at a time
|
||||
// note: previous borrow of `x` occurs here (through borrowing `x.a`); the mutable
|
||||
// borrow prevents subsequent moves, borrows, or modification of `x` until the
|
||||
// borrow ends
|
||||
|
||||
let common = new_loan.loan_path.common(&*old_loan.loan_path);
|
||||
let (nl, ol, new_loan_msg, old_loan_msg) =
|
||||
if new_loan.loan_path.has_fork(&*old_loan.loan_path) && common.is_some() {
|
||||
let nl = self.bccx.loan_path_to_string(&common.unwrap());
|
||||
let ol = nl.clone();
|
||||
let new_loan_msg = format!(" (here through borrowing `{}`)",
|
||||
self.bccx.loan_path_to_string(
|
||||
&*new_loan.loan_path));
|
||||
let old_loan_msg = format!(" (through borrowing `{}`)",
|
||||
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!("`{}`",
|
||||
self.bccx.loan_path_to_string(&*old_loan.loan_path))
|
||||
format!("`{}`", ol)
|
||||
};
|
||||
|
||||
match (new_loan.kind, old_loan.kind) {
|
||||
(ty::MutBorrow, ty::MutBorrow) => {
|
||||
self.bccx.span_err(
|
||||
new_loan.span,
|
||||
format!("cannot borrow `{}` as mutable \
|
||||
format!("cannot borrow `{}`{} as mutable \
|
||||
more than once at a time",
|
||||
self.bccx.loan_path_to_string(
|
||||
&*new_loan.loan_path)).as_slice());
|
||||
nl, new_loan_msg).as_slice())
|
||||
}
|
||||
|
||||
(ty::UniqueImmBorrow, _) => {
|
||||
self.bccx.span_err(
|
||||
new_loan.span,
|
||||
format!("closure requires unique access to `{}` \
|
||||
but {} is already borrowed",
|
||||
self.bccx.loan_path_to_string(&*new_loan.loan_path),
|
||||
old_pronoun).as_slice());
|
||||
but {} is already borrowed{}",
|
||||
nl, ol_pronoun, old_loan_msg).as_slice());
|
||||
}
|
||||
|
||||
(_, ty::UniqueImmBorrow) => {
|
||||
self.bccx.span_err(
|
||||
new_loan.span,
|
||||
format!("cannot borrow `{}` as {} because \
|
||||
format!("cannot borrow `{}`{} as {} because \
|
||||
previous closure requires unique access",
|
||||
self.bccx.loan_path_to_string(&*new_loan.loan_path),
|
||||
new_loan.kind.to_user_str()).as_slice());
|
||||
nl, new_loan_msg, new_loan.kind.to_user_str()).as_slice());
|
||||
}
|
||||
|
||||
(_, _) => {
|
||||
self.bccx.span_err(
|
||||
new_loan.span,
|
||||
format!("cannot borrow `{}` as {} because \
|
||||
{} is also borrowed as {}",
|
||||
self.bccx.loan_path_to_string(&*new_loan.loan_path),
|
||||
format!("cannot borrow `{}`{} as {} because \
|
||||
{} is also borrowed as {}{}",
|
||||
nl,
|
||||
new_loan_msg,
|
||||
new_loan.kind.to_user_str(),
|
||||
old_pronoun,
|
||||
old_loan.kind.to_user_str()).as_slice());
|
||||
ol_pronoun,
|
||||
old_loan.kind.to_user_str(),
|
||||
old_loan_msg).as_slice());
|
||||
}
|
||||
}
|
||||
|
||||
@ -452,8 +484,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
||||
self.bccx.span_note(
|
||||
span,
|
||||
format!("borrow occurs due to use of `{}` in closure",
|
||||
self.bccx.loan_path_to_string(
|
||||
&*new_loan.loan_path)).as_slice());
|
||||
nl).as_slice());
|
||||
}
|
||||
_ => { }
|
||||
}
|
||||
@ -463,30 +494,29 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
||||
format!("the mutable borrow prevents subsequent \
|
||||
moves, borrows, or modification of `{0}` \
|
||||
until the borrow ends",
|
||||
self.bccx.loan_path_to_string(
|
||||
&*old_loan.loan_path))
|
||||
ol)
|
||||
}
|
||||
|
||||
ty::ImmBorrow => {
|
||||
format!("the immutable borrow prevents subsequent \
|
||||
moves or mutable borrows of `{0}` \
|
||||
until the borrow ends",
|
||||
self.bccx.loan_path_to_string(&*old_loan.loan_path))
|
||||
ol)
|
||||
}
|
||||
|
||||
ty::UniqueImmBorrow => {
|
||||
format!("the unique capture prevents subsequent \
|
||||
moves or borrows of `{0}` \
|
||||
until the borrow ends",
|
||||
self.bccx.loan_path_to_string(&*old_loan.loan_path))
|
||||
ol)
|
||||
}
|
||||
};
|
||||
|
||||
let borrow_summary = match old_loan.cause {
|
||||
euv::ClosureCapture(_) => {
|
||||
format!("previous borrow of `{}` occurs here due to \
|
||||
format!("previous borrow of `{}` occurs here{} due to \
|
||||
use in closure",
|
||||
self.bccx.loan_path_to_string(&*old_loan.loan_path))
|
||||
ol, old_loan_msg)
|
||||
}
|
||||
|
||||
euv::OverloadedOperator(..) |
|
||||
@ -496,8 +526,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
||||
euv::ForLoop(..) |
|
||||
euv::RefBinding(..) |
|
||||
euv::MatchDiscriminant(..) => {
|
||||
format!("previous borrow of `{}` occurs here",
|
||||
self.bccx.loan_path_to_string(&*old_loan.loan_path))
|
||||
format!("previous borrow of `{}` occurs here{}",
|
||||
ol, old_loan_msg)
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -298,6 +298,51 @@ impl LoanPath {
|
||||
LpExtend(ref base, _, _) => base.kill_scope(tcx),
|
||||
}
|
||||
}
|
||||
|
||||
fn has_fork(&self, other: &LoanPath) -> bool {
|
||||
match (self, other) {
|
||||
(&LpExtend(ref base, _, LpInterior(id)), &LpExtend(ref base2, _, LpInterior(id2))) =>
|
||||
if id == id2 {
|
||||
base.has_fork(&**base2)
|
||||
} else {
|
||||
true
|
||||
},
|
||||
(&LpExtend(ref base, _, LpDeref(_)), _) => base.has_fork(other),
|
||||
(_, &LpExtend(ref base, _, LpDeref(_))) => self.has_fork(&**base),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn depth(&self) -> uint {
|
||||
match *self {
|
||||
LpExtend(ref base, _, LpDeref(_)) => base.depth(),
|
||||
LpExtend(ref base, _, LpInterior(_)) => base.depth() + 1,
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn common(&self, other: &LoanPath) -> Option<LoanPath> {
|
||||
match (self, other) {
|
||||
(&LpExtend(ref base, a, LpInterior(id)), &LpExtend(ref base2, _, LpInterior(id2))) =>
|
||||
if id == id2 {
|
||||
base.common(&**base2).map(|x| {
|
||||
let xd = x.depth();
|
||||
if base.depth() == xd && base2.depth() == xd {
|
||||
LpExtend(Rc::new(x), a, LpInterior(id))
|
||||
} else {
|
||||
x
|
||||
}
|
||||
})
|
||||
} else {
|
||||
base.common(&**base2)
|
||||
},
|
||||
(&LpExtend(ref base, _, LpDeref(_)), _) => base.common(other),
|
||||
(_, &LpExtend(ref other, _, LpDeref(_))) => self.common(&**other),
|
||||
(&LpVar(id), &LpVar(id2)) => if id == id2 { Some(LpVar(id)) } else { None },
|
||||
(&LpUpvar(id), &LpUpvar(id2)) => if id == id2 { Some(LpUpvar(id)) } else { None },
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn opt_loan_path(cmt: &mc::cmt) -> Option<Rc<LoanPath>> {
|
||||
@ -416,24 +461,58 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
MovedInCapture => "capture",
|
||||
};
|
||||
|
||||
match the_move.kind {
|
||||
let (ol, moved_lp_msg) = match the_move.kind {
|
||||
move_data::Declared => {
|
||||
self.tcx.sess.span_err(
|
||||
use_span,
|
||||
format!("{} of possibly uninitialized variable: `{}`",
|
||||
verb,
|
||||
self.loan_path_to_string(lp)).as_slice());
|
||||
(self.loan_path_to_string(moved_lp),
|
||||
String::new())
|
||||
}
|
||||
_ => {
|
||||
let partially = if lp == moved_lp {""} else {"partially "};
|
||||
// If moved_lp is something like `x.a`, and lp is something like `x.b`, we would
|
||||
// normally generate a rather confusing message:
|
||||
//
|
||||
// error: use of moved value: `x.b`
|
||||
// note: `x.a` moved here...
|
||||
//
|
||||
// What we want to do instead is get the 'common ancestor' of the two moves and
|
||||
// use that for most of the message instead, giving is something like this:
|
||||
//
|
||||
// error: use of moved value: `x`
|
||||
// note: `x` moved here (through moving `x.a`)...
|
||||
|
||||
let common = moved_lp.common(lp);
|
||||
let has_common = common.is_some();
|
||||
let has_fork = moved_lp.has_fork(lp);
|
||||
let (nl, ol, moved_lp_msg) =
|
||||
if has_fork && has_common {
|
||||
let nl = self.loan_path_to_string(&common.unwrap());
|
||||
let ol = nl.clone();
|
||||
let moved_lp_msg = format!(" (through moving `{}`)",
|
||||
self.loan_path_to_string(moved_lp));
|
||||
(nl, ol, moved_lp_msg)
|
||||
} else {
|
||||
(self.loan_path_to_string(lp),
|
||||
self.loan_path_to_string(moved_lp),
|
||||
String::new())
|
||||
};
|
||||
|
||||
let partial = moved_lp.depth() > lp.depth();
|
||||
let msg = if !has_fork && partial { "partially " }
|
||||
else if has_fork && !has_common { "collaterally "}
|
||||
else { "" };
|
||||
self.tcx.sess.span_err(
|
||||
use_span,
|
||||
format!("{} of {}moved value: `{}`",
|
||||
verb,
|
||||
partially,
|
||||
self.loan_path_to_string(lp)).as_slice());
|
||||
msg,
|
||||
nl).as_slice());
|
||||
(ol, moved_lp_msg)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
match the_move.kind {
|
||||
move_data::Declared => {}
|
||||
@ -456,8 +535,9 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
"moved by default (use `copy` to override)");
|
||||
self.tcx.sess.span_note(
|
||||
expr_span,
|
||||
format!("`{}` moved here because it has type `{}`, which is {}",
|
||||
self.loan_path_to_string(moved_lp),
|
||||
format!("`{}` moved here{} because it has type `{}`, which is {}",
|
||||
ol,
|
||||
moved_lp_msg,
|
||||
expr_ty.user_string(self.tcx),
|
||||
suggestion).as_slice());
|
||||
}
|
||||
@ -465,10 +545,11 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
move_data::MovePat => {
|
||||
let pat_ty = ty::node_id_to_type(self.tcx, the_move.id);
|
||||
self.tcx.sess.span_note(self.tcx.map.span(the_move.id),
|
||||
format!("`{}` moved here because it has type `{}`, \
|
||||
format!("`{}` moved here{} because it has type `{}`, \
|
||||
which is moved by default (use `ref` to \
|
||||
override)",
|
||||
self.loan_path_to_string(moved_lp),
|
||||
ol,
|
||||
moved_lp_msg,
|
||||
pat_ty.user_string(self.tcx)).as_slice());
|
||||
}
|
||||
|
||||
@ -491,9 +572,10 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
capture that instead to override)");
|
||||
self.tcx.sess.span_note(
|
||||
expr_span,
|
||||
format!("`{}` moved into closure environment here because it \
|
||||
format!("`{}` moved into closure environment here{} because it \
|
||||
has type `{}`, which is {}",
|
||||
self.loan_path_to_string(moved_lp),
|
||||
ol,
|
||||
moved_lp_msg,
|
||||
expr_ty.user_string(self.tcx),
|
||||
suggestion).as_slice());
|
||||
}
|
||||
@ -602,6 +684,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
span: Span,
|
||||
kind: AliasableViolationKind,
|
||||
cause: mc::AliasableReason) {
|
||||
let mut is_closure = false;
|
||||
let prefix = match kind {
|
||||
MutabilityViolation => {
|
||||
"cannot assign to data"
|
||||
@ -625,6 +708,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
}
|
||||
|
||||
BorrowViolation(euv::ClosureInvocation) => {
|
||||
is_closure = true;
|
||||
"closure invocation"
|
||||
}
|
||||
|
||||
@ -649,7 +733,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
mc::AliasableManaged => {
|
||||
self.tcx.sess.span_err(
|
||||
span,
|
||||
format!("{} in a `@` pointer", prefix).as_slice());
|
||||
format!("{} in a `Gc` pointer", prefix).as_slice());
|
||||
}
|
||||
mc::AliasableBorrowed => {
|
||||
self.tcx.sess.span_err(
|
||||
@ -657,6 +741,12 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
format!("{} in a `&` reference", prefix).as_slice());
|
||||
}
|
||||
}
|
||||
|
||||
if is_closure {
|
||||
self.tcx.sess.span_note(
|
||||
span,
|
||||
"closures behind references must be called via `&mut`");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn note_and_explain_bckerr(&self, err: BckError) {
|
||||
|
@ -59,7 +59,7 @@ use middle::subst::{VecPerParamSpace};
|
||||
use middle::ty;
|
||||
use middle::typeck::lookup_def_tcx;
|
||||
use middle::typeck::infer;
|
||||
use middle::typeck::rscope::{ExplicitRscope, RegionScope, SpecificRscope};
|
||||
use middle::typeck::rscope::{UnelidableRscope, RegionScope, SpecificRscope};
|
||||
use middle::typeck::rscope;
|
||||
use middle::typeck::TypeAndSubsts;
|
||||
use middle::typeck;
|
||||
@ -67,10 +67,11 @@ use util::ppaux::{Repr, UserString};
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
use syntax::abi;
|
||||
use syntax::{ast, ast_util};
|
||||
use std::iter::AdditiveIterator;
|
||||
use syntax::{abi, ast, ast_util};
|
||||
use syntax::codemap::Span;
|
||||
use syntax::parse::token;
|
||||
use syntax::print::pprust;
|
||||
|
||||
pub trait AstConv<'tcx> {
|
||||
fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx>;
|
||||
@ -147,10 +148,49 @@ pub fn opt_ast_region_to_region<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
|
||||
|
||||
None => {
|
||||
match rscope.anon_regions(default_span, 1) {
|
||||
Err(()) => {
|
||||
Err(v) => {
|
||||
debug!("optional region in illegal location");
|
||||
span_err!(this.tcx().sess, default_span, E0106,
|
||||
"missing lifetime specifier");
|
||||
match v {
|
||||
Some(v) => {
|
||||
let mut m = String::new();
|
||||
let len = v.len();
|
||||
for (i, (name, n)) in v.move_iter().enumerate() {
|
||||
m.push_str(if n == 1 {
|
||||
format!("`{}`", name)
|
||||
} else {
|
||||
format!("one of `{}`'s {} elided lifetimes", name, n)
|
||||
}.as_slice());
|
||||
|
||||
if len == 2 && i == 0 {
|
||||
m.push_str(" or ");
|
||||
} else if i == len - 2 {
|
||||
m.push_str(", or ");
|
||||
} else if i != len - 1 {
|
||||
m.push_str(", ");
|
||||
}
|
||||
}
|
||||
if len == 1 {
|
||||
span_note!(this.tcx().sess, default_span,
|
||||
"this function's return type contains a borrowed value, but \
|
||||
the signature does not say which {} it is borrowed from",
|
||||
m);
|
||||
} else if len == 0 {
|
||||
span_note!(this.tcx().sess, default_span,
|
||||
"this function's return type contains a borrowed value, but \
|
||||
there is no value for it to be borrowed from");
|
||||
span_note!(this.tcx().sess, default_span,
|
||||
"consider giving it a 'static lifetime");
|
||||
} else {
|
||||
span_note!(this.tcx().sess, default_span,
|
||||
"this function's return type contains a borrowed value, but \
|
||||
the signature does not say whether it is borrowed from {}",
|
||||
m);
|
||||
}
|
||||
}
|
||||
None => {},
|
||||
}
|
||||
ty::ReStatic
|
||||
}
|
||||
|
||||
@ -217,7 +257,7 @@ fn ast_path_substs<'tcx,AC,RS>(
|
||||
|
||||
match anon_regions {
|
||||
Ok(v) => v.into_iter().collect(),
|
||||
Err(()) => Vec::from_fn(expected_num_region_params,
|
||||
Err(_) => Vec::from_fn(expected_num_region_params,
|
||||
|_| ty::ReStatic) // hokey
|
||||
}
|
||||
};
|
||||
@ -1153,15 +1193,20 @@ fn ty_of_method_or_bare_fn<'tcx, AC: AstConv<'tcx>>(
|
||||
};
|
||||
|
||||
// HACK(eddyb) replace the fake self type in the AST with the actual type.
|
||||
let input_tys = if self_ty.is_some() {
|
||||
let input_params = if self_ty.is_some() {
|
||||
decl.inputs.slice_from(1)
|
||||
} else {
|
||||
decl.inputs.as_slice()
|
||||
};
|
||||
let input_tys = input_tys.iter().map(|a| ty_of_arg(this, &rb, a, None));
|
||||
let self_and_input_tys: Vec<_> =
|
||||
let input_tys = input_params.iter().map(|a| ty_of_arg(this, &rb, a, None));
|
||||
let input_pats: Vec<String> = input_params.iter()
|
||||
.map(|a| pprust::pat_to_string(&*a.pat))
|
||||
.collect();
|
||||
let self_and_input_tys: Vec<ty::t> =
|
||||
self_ty.into_iter().chain(input_tys).collect();
|
||||
|
||||
let mut lifetimes_for_params: Vec<(String, Vec<ty::Region>)> = Vec::new();
|
||||
|
||||
// Second, if there was exactly one lifetime (either a substitution or a
|
||||
// reference) in the arguments, then any anonymous regions in the output
|
||||
// have that lifetime.
|
||||
@ -1172,15 +1217,25 @@ fn ty_of_method_or_bare_fn<'tcx, AC: AstConv<'tcx>>(
|
||||
drop(self_and_input_tys_iter.next())
|
||||
}
|
||||
|
||||
let mut accumulator = Vec::new();
|
||||
for input_type in self_and_input_tys_iter {
|
||||
ty::accumulate_lifetimes_in_type(&mut accumulator, *input_type)
|
||||
for (input_type, input_pat) in self_and_input_tys_iter.zip(input_pats.into_iter()) {
|
||||
let mut accumulator = Vec::new();
|
||||
ty::accumulate_lifetimes_in_type(&mut accumulator, *input_type);
|
||||
lifetimes_for_params.push((input_pat, accumulator));
|
||||
}
|
||||
if accumulator.len() == 1 {
|
||||
implied_output_region = Some(*accumulator.get(0));
|
||||
|
||||
if lifetimes_for_params.iter().map(|&(_, ref x)| x.len()).sum() == 1 {
|
||||
implied_output_region =
|
||||
Some(lifetimes_for_params.iter()
|
||||
.filter_map(|&(_, ref x)|
|
||||
if x.len() == 1 { Some(x[0]) } else { None })
|
||||
.next().unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
let param_lifetimes: Vec<(String, uint)> = lifetimes_for_params.into_iter()
|
||||
.map(|(n, v)| (n, v.len()))
|
||||
.collect();
|
||||
|
||||
let output_ty = match decl.output.node {
|
||||
ast::TyInfer => this.ty_infer(decl.output.span),
|
||||
_ => {
|
||||
@ -1193,7 +1248,7 @@ fn ty_of_method_or_bare_fn<'tcx, AC: AstConv<'tcx>>(
|
||||
// All regions must be explicitly specified in the output
|
||||
// if the lifetime elision rules do not apply. This saves
|
||||
// the user from potentially-confusing errors.
|
||||
let rb = ExplicitRscope;
|
||||
let rb = UnelidableRscope::new(param_lifetimes);
|
||||
ast_ty_to_ty(this, &rb, &*decl.output)
|
||||
}
|
||||
}
|
||||
|
@ -1601,7 +1601,7 @@ impl<'a, 'tcx> RegionScope for infer::InferCtxt<'a, 'tcx> {
|
||||
}
|
||||
|
||||
fn anon_regions(&self, span: Span, count: uint)
|
||||
-> Result<Vec<ty::Region> , ()> {
|
||||
-> Result<Vec<ty::Region>, Option<Vec<(String, uint)>>> {
|
||||
Ok(Vec::from_fn(count, |_| {
|
||||
self.next_region_var(infer::MiscVariable(span))
|
||||
}))
|
||||
|
@ -29,7 +29,7 @@ pub trait RegionScope {
|
||||
fn anon_regions(&self,
|
||||
span: Span,
|
||||
count: uint)
|
||||
-> Result<Vec<ty::Region> , ()>;
|
||||
-> Result<Vec<ty::Region>, Option<Vec<(String, uint)>>>;
|
||||
|
||||
fn default_region_bound(&self, span: Span) -> Option<ty::Region>;
|
||||
}
|
||||
@ -46,8 +46,31 @@ impl RegionScope for ExplicitRscope {
|
||||
fn anon_regions(&self,
|
||||
_span: Span,
|
||||
_count: uint)
|
||||
-> Result<Vec<ty::Region> , ()> {
|
||||
Err(())
|
||||
-> Result<Vec<ty::Region>, Option<Vec<(String, uint)>>> {
|
||||
Err(None)
|
||||
}
|
||||
}
|
||||
|
||||
// Same as `ExplicitRscope`, but provides some extra information for diagnostics
|
||||
pub struct UnelidableRscope(Vec<(String, uint)>);
|
||||
|
||||
impl UnelidableRscope {
|
||||
pub fn new(v: Vec<(String, uint)>) -> UnelidableRscope {
|
||||
UnelidableRscope(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl RegionScope for UnelidableRscope {
|
||||
fn default_region_bound(&self, _span: Span) -> Option<ty::Region> {
|
||||
None
|
||||
}
|
||||
|
||||
fn anon_regions(&self,
|
||||
_span: Span,
|
||||
_count: uint)
|
||||
-> Result<Vec<ty::Region>, Option<Vec<(String, uint)>>> {
|
||||
let UnelidableRscope(ref v) = *self;
|
||||
Err(Some(v.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,7 +95,7 @@ impl RegionScope for SpecificRscope {
|
||||
fn anon_regions(&self,
|
||||
_span: Span,
|
||||
count: uint)
|
||||
-> Result<Vec<ty::Region> , ()>
|
||||
-> Result<Vec<ty::Region>, Option<Vec<(String, uint)>>>
|
||||
{
|
||||
Ok(Vec::from_elem(count, self.default))
|
||||
}
|
||||
@ -109,7 +132,7 @@ impl RegionScope for BindingRscope {
|
||||
fn anon_regions(&self,
|
||||
_: Span,
|
||||
count: uint)
|
||||
-> Result<Vec<ty::Region> , ()>
|
||||
-> Result<Vec<ty::Region>, Option<Vec<(String, uint)>>>
|
||||
{
|
||||
Ok(Vec::from_fn(count, |_| self.next_region()))
|
||||
}
|
||||
|
@ -31,19 +31,22 @@ struct D {
|
||||
fn copy_after_move() {
|
||||
let a = box A { x: box 0, y: 1 };
|
||||
let _x = a.x;
|
||||
let _y = a.y; //~ ERROR use of partially moved
|
||||
let _y = a.y; //~ ERROR use of moved
|
||||
//~^^ NOTE `a` moved here (through moving `a.x`)
|
||||
}
|
||||
|
||||
fn move_after_move() {
|
||||
let a = box B { x: box 0, y: box 1 };
|
||||
let _x = a.x;
|
||||
let _y = a.y; //~ ERROR use of partially moved
|
||||
let _y = a.y; //~ ERROR use of moved
|
||||
//~^^ NOTE `a` moved here (through moving `a.x`)
|
||||
}
|
||||
|
||||
fn borrow_after_move() {
|
||||
let a = box A { x: box 0, y: 1 };
|
||||
let _x = a.x;
|
||||
let _y = &a.y; //~ ERROR use of partially moved
|
||||
let _y = &a.y; //~ ERROR use of moved
|
||||
//~^^ NOTE `a` moved here (through moving `a.x`)
|
||||
}
|
||||
|
||||
fn move_after_borrow() {
|
||||
@ -79,19 +82,19 @@ fn mut_borrow_after_borrow() {
|
||||
fn copy_after_move_nested() {
|
||||
let a = box C { x: box A { x: box 0, y: 1 }, y: 2 };
|
||||
let _x = a.x.x;
|
||||
let _y = a.y; //~ ERROR use of partially moved
|
||||
let _y = a.y; //~ ERROR use of collaterally moved
|
||||
}
|
||||
|
||||
fn move_after_move_nested() {
|
||||
let a = box D { x: box A { x: box 0, y: 1 }, y: box 2 };
|
||||
let _x = a.x.x;
|
||||
let _y = a.y; //~ ERROR use of partially moved
|
||||
let _y = a.y; //~ ERROR use of collaterally moved
|
||||
}
|
||||
|
||||
fn borrow_after_move_nested() {
|
||||
let a = box C { x: box A { x: box 0, y: 1 }, y: 2 };
|
||||
let _x = a.x.x;
|
||||
let _y = &a.y; //~ ERROR use of partially moved
|
||||
let _y = &a.y; //~ ERROR use of collaterally moved
|
||||
}
|
||||
|
||||
fn move_after_borrow_nested() {
|
||||
|
@ -13,13 +13,13 @@ struct A { a: int, b: Box<int> }
|
||||
fn deref_after_move() {
|
||||
let x = A { a: 1, b: box 2 };
|
||||
drop(x.b);
|
||||
drop(*x.b); //~ ERROR use of partially moved value: `*x.b`
|
||||
drop(*x.b); //~ ERROR use of moved value: `*x.b`
|
||||
}
|
||||
|
||||
fn deref_after_fu_move() {
|
||||
let x = A { a: 1, b: box 2 };
|
||||
let y = A { a: 3, .. x };
|
||||
drop(*x.b); //~ ERROR use of partially moved value: `*x.b`
|
||||
drop(*x.b); //~ ERROR use of moved value: `*x.b`
|
||||
}
|
||||
|
||||
fn borrow_after_move() {
|
||||
|
23
src/test/compile-fail/issue-17263.rs
Normal file
23
src/test/compile-fail/issue-17263.rs
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
struct Foo { a: int, b: int }
|
||||
|
||||
fn main() {
|
||||
let mut x = box Foo { a: 1, b: 2 };
|
||||
let (a, b) = (&mut x.a, &mut x.b);
|
||||
//~^ ERROR cannot borrow `x` (here through borrowing `x.b`) as mutable more than once at a time
|
||||
//~^^ NOTE previous borrow of `x` occurs here (through borrowing `x.a`)
|
||||
|
||||
let mut foo = box Foo { a: 1, b: 2 };
|
||||
let (c, d) = (&mut foo.a, &foo.b);
|
||||
//~^ ERROR cannot borrow `foo` (here through borrowing `foo.b`) as immutable
|
||||
//~^^ NOTE previous borrow of `foo` occurs here (through borrowing `foo.a`)
|
||||
}
|
@ -10,11 +10,13 @@
|
||||
|
||||
// Lifetime annotation needed because we have no arguments.
|
||||
fn f() -> &int { //~ ERROR missing lifetime specifier
|
||||
//~^ NOTE there is no value for it to be borrowed from
|
||||
fail!()
|
||||
}
|
||||
|
||||
// Lifetime annotation needed because we have two by-reference parameters.
|
||||
fn g(_: &int, _: &int) -> &int { //~ ERROR missing lifetime specifier
|
||||
fn g(_x: &int, _y: &int) -> &int { //~ ERROR missing lifetime specifier
|
||||
//~^ NOTE the signature does not say whether it is borrowed from `_x` or `_y`
|
||||
fail!()
|
||||
}
|
||||
|
||||
@ -24,7 +26,8 @@ struct Foo<'a> {
|
||||
|
||||
// Lifetime annotation needed because we have two lifetimes: one as a parameter
|
||||
// and one on the reference.
|
||||
fn h(_: &Foo) -> &int { //~ ERROR missing lifetime specifier
|
||||
fn h(_x: &Foo) -> &int { //~ ERROR missing lifetime specifier
|
||||
//~^ NOTE the signature does not say which one of `_x`'s 2 elided lifetimes it is borrowed from
|
||||
fail!()
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,6 @@ extern crate debug;
|
||||
fn main() {
|
||||
let x = box 5i;
|
||||
let y = x;
|
||||
println!("{:?}", *x); //~ ERROR use of partially moved value: `*x`
|
||||
println!("{:?}", *x); //~ ERROR use of moved value: `*x`
|
||||
y.clone();
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ impl Drop for S {
|
||||
impl S {
|
||||
pub fn foo(self) -> int {
|
||||
self.bar();
|
||||
return self.x; //~ ERROR use of partially moved value: `self.x`
|
||||
return self.x; //~ ERROR use of moved value: `self.x`
|
||||
}
|
||||
|
||||
pub fn bar(self) {}
|
||||
|
@ -16,7 +16,7 @@ struct S {
|
||||
impl S {
|
||||
pub fn foo(self) -> int {
|
||||
self.bar();
|
||||
return *self.x; //~ ERROR use of partially moved value: `*self.x`
|
||||
return *self.x; //~ ERROR use of moved value: `*self.x`
|
||||
}
|
||||
|
||||
pub fn bar(self) {}
|
||||
|
Loading…
Reference in New Issue
Block a user