@@ -40,15 +40,29 @@ fn check_crate(tcx: ty::ctxt, method_map: method_map, crate: @crate) {
40
40
tcx. sess . abort_if_errors ( ) ;
41
41
}
42
42
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
+
43
57
fn check_expr( cx : @AltCheckCtxt , ex: @expr, & & s: ( ) , v : visit:: vt < ( ) > ) {
44
58
visit:: visit_expr ( ex, s, v) ;
45
59
match ex. node {
46
60
expr_match( scrut, ref arms) => {
47
61
// 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 ) ;
49
63
for arms. each |arm| {
50
64
check_legality_of_move_bindings( cx,
51
- is_lvalue ,
65
+ is_non_moving_lvalue ,
52
66
arm. guard. is_some( ) ,
53
67
arm. pats) ;
54
68
}
@@ -524,7 +538,7 @@ fn check_local(cx: @AltCheckCtxt, loc: @local, &&s: (), v: visit::vt<()>) {
524
538
525
539
// Check legality of move bindings.
526
540
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) ,
528
542
None => true
529
543
} ;
530
544
check_legality_of_move_bindings ( cx, is_lvalue, false , [ loc. node . pat ] ) ;
@@ -616,40 +630,98 @@ fn check_legality_of_move_bindings(cx: @AltCheckCtxt,
616
630
}
617
631
}
618
632
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
+
619
659
if !any_by_move { return ; } // pointless micro-optimization
620
660
for pats. each |pat| {
621
661
do walk_pat( * pat) |p| {
622
662
if pat_is_binding ( def_map, p) {
623
663
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
+ }
647
673
}
648
674
}
649
675
_ => { }
650
676
}
651
677
}
652
678
}
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) ;
653
725
}
654
726
}
655
727
0 commit comments