Skip to content

Commit 8a3b811

Browse files
committed
---
yaml --- r: 39404 b: refs/heads/incoming c: bdb2d65 h: refs/heads/master v: v3
1 parent 9c2860d commit 8a3b811

File tree

3 files changed

+122
-27
lines changed

3 files changed

+122
-27
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ refs/heads/try: 3d5418789064fdb463e872a4e651af1c628a3650
66
refs/tags/release-0.1: 1f5c5126e96c79d22cb7862f75304136e204f105
77
refs/heads/ndm: f3868061cd7988080c30d6d5bf352a5a5fe2460b
88
refs/heads/try2: a810c03263670238bccd64cabb12a23a46e3a278
9-
refs/heads/incoming: e67190a0d2ce04ab1647205a8ff7a5ddf5d6e8d6
9+
refs/heads/incoming: bdb2d659aec65c7f39b7f58dc917d61d51bb0f97
1010
refs/heads/dist-snap: 22efa39382d41b084fde1719df7ae8ce5697d8c9
1111
refs/tags/release-0.2: c870d2dffb391e14efb05aa27898f1f6333a9596
1212
refs/tags/release-0.3: b5f0d0f648d9a6153664837026ba1be43d3e2503

branches/incoming/src/librustc/middle/check_alt.rs

Lines changed: 98 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,29 @@ fn check_crate(tcx: ty::ctxt, method_map: method_map, crate: @crate) {
4040
tcx.sess.abort_if_errors();
4141
}
4242

43+
fn expr_is_non_moving_lvalue(cx: @AltCheckCtxt, expr: @expr) -> bool {
44+
if !ty::expr_is_lval(cx.tcx, cx.method_map, expr) {
45+
return false;
46+
}
47+
48+
match cx.tcx.value_modes.find(expr.id) {
49+
Some(MoveValue) => return false,
50+
Some(CopyValue) | Some(ReadValue) => return true,
51+
None => {
52+
cx.tcx.sess.span_bug(expr.span, ~"no entry in value mode map");
53+
}
54+
}
55+
}
56+
4357
fn check_expr(cx: @AltCheckCtxt, ex: @expr, &&s: (), v: visit::vt<()>) {
4458
visit::visit_expr(ex, s, v);
4559
match ex.node {
4660
expr_match(scrut, ref arms) => {
4761
// First, check legality of move bindings.
48-
let is_lvalue = ty::expr_is_lval(cx.tcx, cx.method_map, scrut);
62+
let is_non_moving_lvalue = expr_is_non_moving_lvalue(cx, ex);
4963
for arms.each |arm| {
5064
check_legality_of_move_bindings(cx,
51-
is_lvalue,
65+
is_non_moving_lvalue,
5266
arm.guard.is_some(),
5367
arm.pats);
5468
}
@@ -524,7 +538,7 @@ fn check_local(cx: @AltCheckCtxt, loc: @local, &&s: (), v: visit::vt<()>) {
524538

525539
// Check legality of move bindings.
526540
let is_lvalue = match loc.node.init {
527-
Some(init) => ty::expr_is_lval(cx.tcx, cx.method_map, init),
541+
Some(init) => expr_is_non_moving_lvalue(cx, init),
528542
None => true
529543
};
530544
check_legality_of_move_bindings(cx, is_lvalue, false, [ loc.node.pat ]);
@@ -616,40 +630,98 @@ fn check_legality_of_move_bindings(cx: @AltCheckCtxt,
616630
}
617631
}
618632

633+
let check_move: &fn(@pat, Option<@pat>) = |p, sub| {
634+
// check legality of moving out of the enum
635+
if sub.is_some() {
636+
tcx.sess.span_err(
637+
p.span,
638+
~"cannot bind by-move with sub-bindings");
639+
} else if has_guard {
640+
tcx.sess.span_err(
641+
p.span,
642+
~"cannot bind by-move into a pattern guard");
643+
} else if by_ref_span.is_some() {
644+
tcx.sess.span_err(
645+
p.span,
646+
~"cannot bind by-move and by-ref \
647+
in the same pattern");
648+
tcx.sess.span_note(
649+
by_ref_span.get(),
650+
~"by-ref binding occurs here");
651+
} else if is_lvalue {
652+
tcx.sess.span_err(
653+
p.span,
654+
~"cannot bind by-move when \
655+
matching an lvalue");
656+
}
657+
};
658+
619659
if !any_by_move { return; } // pointless micro-optimization
620660
for pats.each |pat| {
621661
do walk_pat(*pat) |p| {
622662
if pat_is_binding(def_map, p) {
623663
match p.node {
624-
pat_ident(bind_by_move, _, sub) => {
625-
// check legality of moving out of the enum
626-
if sub.is_some() {
627-
tcx.sess.span_err(
628-
p.span,
629-
~"cannot bind by-move with sub-bindings");
630-
} else if has_guard {
631-
tcx.sess.span_err(
632-
p.span,
633-
~"cannot bind by-move into a pattern guard");
634-
} else if by_ref_span.is_some() {
635-
tcx.sess.span_err(
636-
p.span,
637-
~"cannot bind by-move and by-ref \
638-
in the same pattern");
639-
tcx.sess.span_note(
640-
by_ref_span.get(),
641-
~"by-ref binding occurs here");
642-
} else if is_lvalue {
643-
tcx.sess.span_err(
644-
p.span,
645-
~"cannot bind by-move when \
646-
matching an lvalue");
664+
pat_ident(bind_by_move, _, sub) => check_move(p, sub),
665+
pat_ident(bind_infer, _, sub) => {
666+
match tcx.value_modes.find(p.id) {
667+
Some(MoveValue) => check_move(p, sub),
668+
Some(CopyValue) | Some(ReadValue) => {}
669+
None => {
670+
cx.tcx.sess.span_bug(
671+
pat.span, ~"no mode for pat binding");
672+
}
647673
}
648674
}
649675
_ => {}
650676
}
651677
}
652678
}
679+
680+
// Now check to ensure that any move binding is not behind an @ or &.
681+
// This is always illegal.
682+
let vt = visit::mk_vt(@{
683+
visit_pat: |pat, behind_bad_pointer, v| {
684+
let error_out = || {
685+
cx.tcx.sess.span_err(pat.span, ~"by-move pattern \
686+
bindings may not occur \
687+
behind @ or & bindings");
688+
};
689+
match pat.node {
690+
pat_ident(binding_mode, _, sub) => {
691+
debug!("(check legality of move) checking pat \
692+
ident with behind_bad_pointer %?",
693+
behind_bad_pointer);
694+
match binding_mode {
695+
bind_by_move if behind_bad_pointer => error_out(),
696+
bind_infer if behind_bad_pointer => {
697+
match cx.tcx.value_modes.find(pat.id) {
698+
Some(MoveValue) => error_out(),
699+
Some(CopyValue) |
700+
Some(ReadValue) => {}
701+
None => {
702+
cx.tcx.sess.span_bug(pat.span,
703+
~"no mode for pat binding");
704+
}
705+
}
706+
}
707+
_ => {}
708+
}
709+
match sub {
710+
None => {}
711+
Some(subpat) => {
712+
(v.visit_pat)(subpat, behind_bad_pointer, v);
713+
}
714+
}
715+
}
716+
pat_box(subpat) | pat_region(subpat) => {
717+
(v.visit_pat)(subpat, true, v);
718+
}
719+
_ => visit::visit_pat(pat, behind_bad_pointer, v)
720+
}
721+
},
722+
.. *visit::default_visitor::<bool>()
723+
});
724+
(vt.visit_pat)(*pat, false, vt);
653725
}
654726
}
655727

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
enum E {
2+
Foo,
3+
Bar(~str)
4+
}
5+
6+
struct S {
7+
x: E
8+
}
9+
10+
fn f(x: ~str) {}
11+
12+
fn main() {
13+
let s = S { x: Bar(~"hello") };
14+
match &s.x {
15+
&Foo => {}
16+
&Bar(identifier) => f(copy identifier) //~ ERROR by-move pattern bindings may not occur
17+
};
18+
match &s.x {
19+
&Foo => {}
20+
&Bar(ref identifier) => io::println(*identifier)
21+
};
22+
}
23+

0 commit comments

Comments
 (0)