|
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