Skip to content

Commit 82beb8a

Browse files
committed
Issue #4715: Give a better error message when move results from a binding
Fixes #4715.
1 parent 8a4bffc commit 82beb8a

File tree

8 files changed

+172
-160
lines changed

8 files changed

+172
-160
lines changed

src/librustc/middle/check_match.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -803,7 +803,7 @@ pub fn check_legality_of_move_bindings(cx: @MatchCheckCtxt,
803803

804804
if !any_by_move { return; } // pointless micro-optimization
805805
for pats.each |pat| {
806-
do walk_pat(*pat) |p| {
806+
for walk_pat(*pat) |p| {
807807
if pat_is_binding(def_map, p) {
808808
match p.node {
809809
pat_ident(_, _, sub) => {

src/librustc/middle/dataflow.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -824,7 +824,7 @@ impl<'self, O:DataFlowOperator> PropagationContext<'self, O> {
824824
debug!("DataFlowContext::walk_pat(pat=%s, in_out=%s)",
825825
pat.repr(self.dfcx.tcx), bits_to_str(reslice(in_out)));
826826

827-
do ast_util::walk_pat(pat) |p| {
827+
for ast_util::walk_pat(pat) |p| {
828828
debug!(" p.id=%? in_out=%s", p.id, bits_to_str(reslice(in_out)));
829829
self.merge_with_entry_set(p.id, in_out);
830830
self.dfcx.apply_gen_kill(p.id, in_out);

src/librustc/middle/liveness.rs

+65-72
Original file line numberDiff line numberDiff line change
@@ -1443,10 +1443,10 @@ fn check_expr(expr: @expr, this: @Liveness, vt: vt<@Liveness>) {
14431443

14441444
match this.ir.variable_moves_map.find(&expr.id) {
14451445
None => {}
1446-
Some(&entire_expr) => {
1446+
Some(&reason) => {
14471447
debug!("(checking expr) is a move: `%s`",
14481448
expr_to_str(expr, this.tcx.sess.intr()));
1449-
this.check_move_from_var(ln, *var, entire_expr);
1449+
this.check_move_from_var(ln, *var, reason);
14501450
}
14511451
}
14521452
}
@@ -1459,7 +1459,7 @@ fn check_expr(expr: @expr, this: @Liveness, vt: vt<@Liveness>) {
14591459
for caps.each |cap| {
14601460
let var = this.variable(cap.var_nid, expr.span);
14611461
if cap.is_move {
1462-
this.check_move_from_var(cap.ln, var, expr);
1462+
this.check_move_from_var(cap.ln, var, moves::MovedByExpr(expr));
14631463
}
14641464
}
14651465

@@ -1549,24 +1549,20 @@ pub impl Liveness {
15491549
fn check_move_from_var(&self,
15501550
ln: LiveNode,
15511551
var: Variable,
1552-
move_expr: @expr) {
1552+
move_reason: moves::Reason) {
15531553
/*!
15541554
* Checks whether `var` is live on entry to any of the
15551555
* successors of `ln`. If it is, report an error.
1556-
* `move_expr` is the expression which caused the variable
1556+
* `move_reason` is the reason which caused the variable
15571557
* to be moved.
1558-
*
1559-
* Note that `move_expr` is not necessarily a reference to the
1560-
* variable. It might be an expression like `x.f` which could
1561-
* cause a move of the variable `x`, or a closure creation.
15621558
*/
15631559

15641560
debug!("check_move_from_var(%s, %s)",
15651561
ln.to_str(), var.to_str());
15661562

15671563
match self.live_on_exit(ln, var) {
15681564
None => {}
1569-
Some(lnk) => self.report_illegal_move(lnk, var, move_expr)
1565+
Some(lnk) => self.report_illegal_move(lnk, var, move_reason)
15701566
}
15711567
}
15721568

@@ -1640,82 +1636,79 @@ pub impl Liveness {
16401636

16411637
fn report_illegal_move(&self, lnk: LiveNodeKind,
16421638
var: Variable,
1643-
move_expr: @expr) {
1644-
// the only time that it is possible to have a moved variable
1645-
// used by ExitNode would be arguments or fields in a ctor.
1646-
// we give a slightly different error message in those cases.
1647-
if lnk == ExitNode {
1648-
// FIXME #4715: this seems like it should be reported in the
1649-
// borrow checker
1650-
let vk = self.ir.var_kinds[*var];
1651-
match vk {
1652-
Arg(_, name) => {
1653-
self.tcx.sess.span_err(
1654-
move_expr.span,
1655-
fmt!("illegal move from argument `%s`, which is not \
1656-
copy or move mode", *self.tcx.sess.str_of(name)));
1657-
return;
1658-
}
1659-
Local(*) | ImplicitRet => {
1660-
self.tcx.sess.span_bug(
1661-
move_expr.span,
1662-
fmt!("illegal reader (%?) for `%?`",
1663-
lnk, vk));
1664-
}
1639+
move_reason: moves::Reason) {
1640+
match move_reason {
1641+
moves::MovedByExpr(move_expr) => {
1642+
match move_expr.node {
1643+
expr_fn_block(*) => {
1644+
self.report_illegal_read(
1645+
move_expr.span, lnk, var, MovedValue);
1646+
let name = self.ir.variable_name(var);
1647+
self.tcx.sess.span_note(
1648+
move_expr.span,
1649+
fmt!("`%s` moved into closure environment here \
1650+
because its type is moved by default",
1651+
*name));
1652+
}
1653+
expr_path(*) => {
1654+
self.report_illegal_read(
1655+
move_expr.span, lnk, var, MovedValue);
1656+
self.report_move_location(
1657+
move_expr.id, move_expr.span, var,
1658+
"", "it", "copy");
1659+
}
1660+
expr_field(*) => {
1661+
self.report_illegal_read(
1662+
move_expr.span, lnk, var, PartiallyMovedValue);
1663+
self.report_move_location(
1664+
move_expr.id, move_expr.span, var,
1665+
"field of ", "the field", "copy");
1666+
}
1667+
expr_index(*) => {
1668+
self.report_illegal_read(
1669+
move_expr.span, lnk, var, PartiallyMovedValue);
1670+
self.report_move_location(
1671+
move_expr.id, move_expr.span, var,
1672+
"element of ", "the element", "copy");
1673+
}
1674+
_ => {
1675+
self.report_illegal_read(
1676+
move_expr.span, lnk, var, PartiallyMovedValue);
1677+
self.report_move_location(
1678+
move_expr.id, move_expr.span, var,
1679+
"subcomponent of ", "the subcomponent", "copy");
1680+
}
1681+
}
16651682
}
1666-
}
16671683

1668-
match move_expr.node {
1669-
expr_fn_block(*) => {
1670-
self.report_illegal_read(
1671-
move_expr.span, lnk, var, MovedValue);
1672-
let name = self.ir.variable_name(var);
1673-
self.tcx.sess.span_note(
1674-
move_expr.span,
1675-
fmt!("`%s` moved into closure environment here \
1676-
because its type is moved by default",
1677-
*name));
1678-
}
1679-
expr_path(*) => {
1680-
self.report_illegal_read(
1681-
move_expr.span, lnk, var, MovedValue);
1682-
self.report_move_location(
1683-
move_expr, var, "", "it");
1684-
}
1685-
expr_field(*) => {
1686-
self.report_illegal_read(
1687-
move_expr.span, lnk, var, PartiallyMovedValue);
1688-
self.report_move_location(
1689-
move_expr, var, "field of ", "the field");
1690-
}
1691-
expr_index(*) => {
1692-
self.report_illegal_read(
1693-
move_expr.span, lnk, var, PartiallyMovedValue);
1694-
self.report_move_location(
1695-
move_expr, var, "element of ", "the element");
1696-
}
1697-
_ => {
1684+
moves::MovedByPat(move_binding) => {
16981685
self.report_illegal_read(
1699-
move_expr.span, lnk, var, PartiallyMovedValue);
1686+
move_binding.span, lnk, var, PartiallyMovedValue);
17001687
self.report_move_location(
1701-
move_expr, var, "subcomponent of ", "the subcomponent");
1688+
move_binding.id, move_binding.span, var,
1689+
"", "the binding", "ref");
17021690
}
17031691
};
17041692
}
17051693

17061694
fn report_move_location(&self,
1707-
move_expr: @expr,
1695+
move_loc_id: node_id,
1696+
move_loc_span: span,
17081697
var: Variable,
17091698
expr_descr: &str,
1710-
pronoun: &str) {
1711-
let move_expr_ty = ty::expr_ty(self.tcx, move_expr);
1699+
pronoun: &str,
1700+
override: &str) {
1701+
let move_expr_ty = ty::node_id_to_type(self.tcx, move_loc_id);
17121702
let name = self.ir.variable_name(var);
17131703
self.tcx.sess.span_note(
1714-
move_expr.span,
1704+
move_loc_span,
17151705
fmt!("%s`%s` moved here because %s has type %s, \
1716-
which is moved by default (use `copy` to override)",
1717-
expr_descr, *name, pronoun,
1718-
ty_to_str(self.tcx, move_expr_ty)));
1706+
which is moved by default (use `%s` to override)",
1707+
expr_descr,
1708+
*name,
1709+
pronoun,
1710+
ty_to_str(self.tcx, move_expr_ty),
1711+
override));
17191712
}
17201713

17211714
fn report_illegal_read(&self,

0 commit comments

Comments
 (0)