|  | 
| 11 | 11 | use middle::const_eval::{compare_const_vals, const_bool, const_float, const_nil, const_val}; | 
| 12 | 12 | use middle::const_eval::{const_expr_to_pat, eval_const_expr, lookup_const_by_id}; | 
| 13 | 13 | use middle::def::*; | 
|  | 14 | +use middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, Init}; | 
|  | 15 | +use middle::expr_use_visitor::{JustWrite, LoanCause, MutateMode}; | 
|  | 16 | +use middle::expr_use_visitor::{WriteAndRead}; | 
|  | 17 | +use middle::mem_categorization::cmt; | 
| 14 | 18 | use middle::pat_util::*; | 
| 15 | 19 | use middle::ty::*; | 
| 16 | 20 | use middle::ty; | 
| @@ -143,7 +147,16 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &Expr) { | 
| 143 | 147 |                                                 arm.pats.as_slice()); | 
| 144 | 148 |             } | 
| 145 | 149 | 
 | 
| 146 |  | -            // Second, check for unreachable arms. | 
|  | 150 | +            // Second, if there is a guard on each arm, make sure it isn't | 
|  | 151 | +            // assigning or borrowing anything mutably. | 
|  | 152 | +            for arm in arms.iter() { | 
|  | 153 | +                match arm.guard { | 
|  | 154 | +                    Some(guard) => check_for_mutation_in_guard(cx, &*guard), | 
|  | 155 | +                    None => {} | 
|  | 156 | +                } | 
|  | 157 | +            } | 
|  | 158 | + | 
|  | 159 | +            // Third, check for unreachable arms. | 
| 147 | 160 |             check_arms(cx, arms.as_slice()); | 
| 148 | 161 | 
 | 
| 149 | 162 |             // Finally, check if the whole match expression is exhaustive. | 
| @@ -903,3 +916,53 @@ fn check_legality_of_move_bindings(cx: &MatchCheckCtxt, | 
| 903 | 916 |         }); | 
| 904 | 917 |     } | 
| 905 | 918 | } | 
|  | 919 | + | 
|  | 920 | +/// Ensures that a pattern guard doesn't borrow by mutable reference or | 
|  | 921 | +/// assign. | 
|  | 922 | +fn check_for_mutation_in_guard<'a>(cx: &'a MatchCheckCtxt<'a>, guard: &Expr) { | 
|  | 923 | +    let mut checker = MutationChecker { | 
|  | 924 | +        cx: cx, | 
|  | 925 | +    }; | 
|  | 926 | +    let mut visitor = ExprUseVisitor::new(&mut checker, checker.cx.tcx); | 
|  | 927 | +    visitor.walk_expr(guard); | 
|  | 928 | +} | 
|  | 929 | + | 
|  | 930 | +struct MutationChecker<'a> { | 
|  | 931 | +    cx: &'a MatchCheckCtxt<'a>, | 
|  | 932 | +} | 
|  | 933 | + | 
|  | 934 | +impl<'a> Delegate for MutationChecker<'a> { | 
|  | 935 | +    fn consume(&mut self, _: NodeId, _: Span, _: cmt, _: ConsumeMode) {} | 
|  | 936 | +    fn consume_pat(&mut self, _: &Pat, _: cmt, _: ConsumeMode) {} | 
|  | 937 | +    fn borrow(&mut self, | 
|  | 938 | +              _: NodeId, | 
|  | 939 | +              span: Span, | 
|  | 940 | +              _: cmt, | 
|  | 941 | +              _: Region, | 
|  | 942 | +              kind: BorrowKind, | 
|  | 943 | +              _: LoanCause) { | 
|  | 944 | +        match kind { | 
|  | 945 | +            MutBorrow => { | 
|  | 946 | +                self.cx | 
|  | 947 | +                    .tcx | 
|  | 948 | +                    .sess | 
|  | 949 | +                    .span_err(span, | 
|  | 950 | +                              "cannot mutably borrow in a pattern guard") | 
|  | 951 | +            } | 
|  | 952 | +            ImmBorrow | UniqueImmBorrow => {} | 
|  | 953 | +        } | 
|  | 954 | +    } | 
|  | 955 | +    fn decl_without_init(&mut self, _: NodeId, _: Span) {} | 
|  | 956 | +    fn mutate(&mut self, _: NodeId, span: Span, _: cmt, mode: MutateMode) { | 
|  | 957 | +        match mode { | 
|  | 958 | +            JustWrite | WriteAndRead => { | 
|  | 959 | +                self.cx | 
|  | 960 | +                    .tcx | 
|  | 961 | +                    .sess | 
|  | 962 | +                    .span_err(span, "cannot assign in a pattern guard") | 
|  | 963 | +            } | 
|  | 964 | +            Init => {} | 
|  | 965 | +        } | 
|  | 966 | +    } | 
|  | 967 | +} | 
|  | 968 | + | 
0 commit comments