about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libfmt_macros/lib.rs9
-rw-r--r--src/librustc/middle/cfg/construct.rs41
-rw-r--r--src/librustc/middle/check_match.rs65
-rw-r--r--src/librustc/middle/expr_use_visitor.rs2
-rw-r--r--src/librustdoc/html/render.rs22
-rw-r--r--src/libsyntax/parse/parser.rs391
-rw-r--r--src/test/compile-fail/borrowck-lend-flow-match.rs27
-rw-r--r--src/test/compile-fail/borrowck-mutate-in-guard.rs33
-rw-r--r--src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot24
-rw-r--r--src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot40
10 files changed, 383 insertions, 271 deletions
diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs
index 62547b6669f..3350d8f548a 100644
--- a/src/libfmt_macros/lib.rs
+++ b/src/libfmt_macros/lib.rs
@@ -352,8 +352,13 @@ impl<'a> Parser<'a> {
             None => {
                 let tmp = self.cur.clone();
                 match self.word() {
-                    word if word.len() > 0 && self.consume('$') => {
-                        CountIsName(word)
+                    word if word.len() > 0 => {
+                        if self.consume('$') {
+                            CountIsName(word)
+                        } else {
+                            self.cur = tmp;
+                            CountImplied
+                        }
                     }
                     _ => {
                         self.cur = tmp;
diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs
index 4f6885f05ed..9cd46067c10 100644
--- a/src/librustc/middle/cfg/construct.rs
+++ b/src/librustc/middle/cfg/construct.rs
@@ -333,32 +333,37 @@ impl<'a> CFGBuilder<'a> {
                 //    [discr]
                 //       |
                 //       v 2
-                //    [guard1]
+                //    [cond1]
                 //      /  \
                 //     |    \
-                //     v 3  |
-                //  [pat1]  |
-                //     |
-                //     v 4  |
-                // [body1]  v
-                //     |  [guard2]
-                //     |    /   \
-                //     | [body2] \
-                //     |    |   ...
-                //     |    |    |
-                //     v 5  v    v
-                //   [....expr....]
+                //     v 3   \
+                //  [pat1]    \
+                //     |       |
+                //     v 4     |
+                //  [guard1]   |
+                //     |       |
+                //     |       |
+                //     v 5     v
+                //  [body1]  [cond2]
+                //     |      /  \
+                //     |    ...  ...
+                //     |     |    |
+                //     v 6   v    v
+                //  [.....expr.....]
                 //
                 let discr_exit = self.expr(discr.clone(), pred);         // 1
 
                 let expr_exit = self.add_node(expr.id, []);
-                let mut guard_exit = discr_exit;
+                let mut cond_exit = discr_exit;
                 for arm in arms.iter() {
-                    guard_exit = self.opt_expr(arm.guard, guard_exit);   // 2
+                    cond_exit = self.add_dummy_node([cond_exit]);        // 2
                     let pats_exit = self.pats_any(arm.pats.as_slice(),
-                                                  guard_exit);           // 3
-                    let body_exit = self.expr(arm.body.clone(), pats_exit); // 4
-                    self.add_contained_edge(body_exit, expr_exit);       // 5
+                                                  cond_exit);            // 3
+                    let guard_exit = self.opt_expr(arm.guard,
+                                                   pats_exit);           // 4
+                    let body_exit = self.expr(arm.body.clone(),
+                                              guard_exit);               // 5
+                    self.add_contained_edge(body_exit, expr_exit);       // 6
                 }
                 expr_exit
             }
diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs
index e458b82f036..4d10676a589 100644
--- a/src/librustc/middle/check_match.rs
+++ b/src/librustc/middle/check_match.rs
@@ -11,6 +11,10 @@
 use middle::const_eval::{compare_const_vals, const_bool, const_float, const_nil, const_val};
 use middle::const_eval::{const_expr_to_pat, eval_const_expr, lookup_const_by_id};
 use middle::def::*;
+use middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, Init};
+use middle::expr_use_visitor::{JustWrite, LoanCause, MutateMode};
+use middle::expr_use_visitor::{WriteAndRead};
+use middle::mem_categorization::cmt;
 use middle::pat_util::*;
 use middle::ty::*;
 use middle::ty;
@@ -143,7 +147,16 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &Expr) {
                                                 arm.pats.as_slice());
             }
 
-            // Second, check for unreachable arms.
+            // Second, if there is a guard on each arm, make sure it isn't
+            // assigning or borrowing anything mutably.
+            for arm in arms.iter() {
+                match arm.guard {
+                    Some(guard) => check_for_mutation_in_guard(cx, &*guard),
+                    None => {}
+                }
+            }
+
+            // Third, check for unreachable arms.
             check_arms(cx, arms.as_slice());
 
             // Finally, check if the whole match expression is exhaustive.
@@ -903,3 +916,53 @@ fn check_legality_of_move_bindings(cx: &MatchCheckCtxt,
         });
     }
 }
+
+/// Ensures that a pattern guard doesn't borrow by mutable reference or
+/// assign.
+fn check_for_mutation_in_guard<'a>(cx: &'a MatchCheckCtxt<'a>, guard: &Expr) {
+    let mut checker = MutationChecker {
+        cx: cx,
+    };
+    let mut visitor = ExprUseVisitor::new(&mut checker, checker.cx.tcx);
+    visitor.walk_expr(guard);
+}
+
+struct MutationChecker<'a> {
+    cx: &'a MatchCheckCtxt<'a>,
+}
+
+impl<'a> Delegate for MutationChecker<'a> {
+    fn consume(&mut self, _: NodeId, _: Span, _: cmt, _: ConsumeMode) {}
+    fn consume_pat(&mut self, _: &Pat, _: cmt, _: ConsumeMode) {}
+    fn borrow(&mut self,
+              _: NodeId,
+              span: Span,
+              _: cmt,
+              _: Region,
+              kind: BorrowKind,
+              _: LoanCause) {
+        match kind {
+            MutBorrow => {
+                self.cx
+                    .tcx
+                    .sess
+                    .span_err(span,
+                              "cannot mutably borrow in a pattern guard")
+            }
+            ImmBorrow | UniqueImmBorrow => {}
+        }
+    }
+    fn decl_without_init(&mut self, _: NodeId, _: Span) {}
+    fn mutate(&mut self, _: NodeId, span: Span, _: cmt, mode: MutateMode) {
+        match mode {
+            JustWrite | WriteAndRead => {
+                self.cx
+                    .tcx
+                    .sess
+                    .span_err(span, "cannot assign in a pattern guard")
+            }
+            Init => {}
+        }
+    }
+}
+
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 7995317d49f..605811555a1 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -292,7 +292,7 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> {
         self.walk_expr(expr)
     }
 
-    fn walk_expr(&mut self, expr: &ast::Expr) {
+    pub fn walk_expr(&mut self, expr: &ast::Expr) {
         debug!("walk_expr(expr={})", expr.repr(self.tcx()));
 
         self.walk_adjustment(expr);
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 95637d311d8..084ba46797e 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -1734,17 +1734,19 @@ fn item_struct(w: &mut fmt::Formatter, it: &clean::Item,
         }
     }).peekable();
     match s.struct_type {
-        doctree::Plain if fields.peek().is_some() => {
-            try!(write!(w, "<h2 class='fields'>Fields</h2>\n<table>"));
-            for field in fields {
-                try!(write!(w, "<tr><td id='structfield.{name}'>\
-                                  {stab}<code>{name}</code></td><td>",
-                              stab = ConciseStability(&field.stability),
-                              name = field.name.get_ref().as_slice()));
-                try!(document(w, field));
-                try!(write!(w, "</td></tr>"));
+        doctree::Plain => {
+            if fields.peek().is_some() {
+                try!(write!(w, "<h2 class='fields'>Fields</h2>\n<table>"));
+                for field in fields {
+                    try!(write!(w, "<tr><td id='structfield.{name}'>\
+                                      {stab}<code>{name}</code></td><td>",
+                                  stab = ConciseStability(&field.stability),
+                                  name = field.name.get_ref().as_slice()));
+                    try!(document(w, field));
+                    try!(write!(w, "</td></tr>"));
+                }
+                try!(write!(w, "</table>"));
             }
-            try!(write!(w, "</table>"));
         }
         _ => {}
     }
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 0116518d537..878994369d0 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -1954,19 +1954,6 @@ impl<'a> Parser<'a> {
             token::BINOP(token::OR) |  token::OROR => {
                 return self.parse_lambda_expr();
             },
-            _ if self.eat_keyword(keywords::Proc) => {
-                let decl = self.parse_proc_decl();
-                let body = self.parse_expr();
-                let fakeblock = P(ast::Block {
-                        view_items: Vec::new(),
-                        stmts: Vec::new(),
-                        expr: Some(body),
-                        id: ast::DUMMY_NODE_ID,
-                        rules: DefaultBlock,
-                        span: body.span,
-                    });
-                return self.mk_expr(lo, body.span.hi, ExprProc(decl, fakeblock));
-            },
             // FIXME #13626: Should be able to stick in
             // token::SELF_KEYWORD_NAME
             token::IDENT(id @ ast::Ident{
@@ -1978,48 +1965,6 @@ impl<'a> Parser<'a> {
                 ex = ExprPath(path);
                 hi = self.last_span.hi;
             }
-            _ if self.eat_keyword(keywords::If) => {
-                return self.parse_if_expr();
-            },
-            _ if self.eat_keyword(keywords::For) => {
-                return self.parse_for_expr(None);
-            },
-            _ if self.eat_keyword(keywords::While) => {
-                return self.parse_while_expr();
-            },
-            _ if Parser::token_is_lifetime(&self.token) => {
-                let lifetime = self.get_lifetime();
-                self.bump();
-                self.expect(&token::COLON);
-                if self.eat_keyword(keywords::For) {
-                    return self.parse_for_expr(Some(lifetime))
-                } else if self.eat_keyword(keywords::Loop) {
-                    return self.parse_loop_expr(Some(lifetime))
-                } else {
-                    self.fatal("expected `for` or `loop` after a label")
-                }
-            },
-            _ if self.eat_keyword(keywords::Loop) => {
-                return self.parse_loop_expr(None);
-            },
-            _ if self.eat_keyword(keywords::Continue) => {
-                let lo = self.span.lo;
-                let ex = if Parser::token_is_lifetime(&self.token) {
-                    let lifetime = self.get_lifetime();
-                    self.bump();
-                    ExprAgain(Some(lifetime))
-                } else {
-                    ExprAgain(None)
-                };
-                let hi = self.span.hi;
-                return self.mk_expr(lo, hi, ex);
-            },
-            _ if self.eat_keyword(keywords::Match) => {
-                return self.parse_match_expr();
-            },
-            _ if self.eat_keyword(keywords::Unsafe) => {
-                return self.parse_block_expr(lo, UnsafeBlock(ast::UserProvided));
-            },
             token::LBRACKET => {
                 self.bump();
 
@@ -2057,88 +2002,158 @@ impl<'a> Parser<'a> {
                 }
                 hi = self.last_span.hi;
             },
-            _ if self.eat_keyword(keywords::Return) => {
-                // RETURN expression
-                if can_begin_expr(&self.token) {
-                    let e = self.parse_expr();
-                    hi = e.span.hi;
-                    ex = ExprRet(Some(e));
-                } else { ex = ExprRet(None); }
-            },
-            _ if self.eat_keyword(keywords::Break) => {
-                // BREAK expression
+            _ => {
+                if self.eat_keyword(keywords::Proc) {
+                    let decl = self.parse_proc_decl();
+                    let body = self.parse_expr();
+                    let fakeblock = P(ast::Block {
+                            view_items: Vec::new(),
+                            stmts: Vec::new(),
+                            expr: Some(body),
+                            id: ast::DUMMY_NODE_ID,
+                            rules: DefaultBlock,
+                            span: body.span,
+                        });
+                    return self.mk_expr(lo, body.span.hi, ExprProc(decl, fakeblock));
+                }
+                if self.eat_keyword(keywords::If) {
+                    return self.parse_if_expr();
+                }
+                if self.eat_keyword(keywords::For) {
+                    return self.parse_for_expr(None);
+                }
+                if self.eat_keyword(keywords::While) {
+                    return self.parse_while_expr();
+                }
                 if Parser::token_is_lifetime(&self.token) {
                     let lifetime = self.get_lifetime();
                     self.bump();
-                    ex = ExprBreak(Some(lifetime));
-                } else {
-                    ex = ExprBreak(None);
+                    self.expect(&token::COLON);
+                    if self.eat_keyword(keywords::For) {
+                        return self.parse_for_expr(Some(lifetime))
+                    }
+                    if self.eat_keyword(keywords::Loop) {
+                        return self.parse_loop_expr(Some(lifetime))
+                    }
+                    self.fatal("expected `for` or `loop` after a label")
                 }
-                hi = self.span.hi;
-            },
-            _ if self.token == token::MOD_SEP ||
-                is_ident(&self.token) && !self.is_keyword(keywords::True) &&
-                !self.is_keyword(keywords::False) => {
-                let pth = self.parse_path(LifetimeAndTypesWithColons).path;
-
-                // `!`, as an operator, is prefix, so we know this isn't that
-                if self.token == token::NOT {
-                    // MACRO INVOCATION expression
-                    self.bump();
-
-                    let ket = token::close_delimiter_for(&self.token)
-                        .unwrap_or_else(|| self.fatal("expected open delimiter"));
-                    self.bump();
-
-                    let tts = self.parse_seq_to_end(&ket,
-                                                    seq_sep_none(),
-                                                    |p| p.parse_token_tree());
+                if self.eat_keyword(keywords::Loop) {
+                    return self.parse_loop_expr(None);
+                }
+                if self.eat_keyword(keywords::Continue) {
+                    let lo = self.span.lo;
+                    let ex = if Parser::token_is_lifetime(&self.token) {
+                        let lifetime = self.get_lifetime();
+                        self.bump();
+                        ExprAgain(Some(lifetime))
+                    } else {
+                        ExprAgain(None)
+                    };
                     let hi = self.span.hi;
+                    return self.mk_expr(lo, hi, ex);
+                }
+                if self.eat_keyword(keywords::Match) {
+                    return self.parse_match_expr();
+                }
+                if self.eat_keyword(keywords::Unsafe) {
+                    return self.parse_block_expr(
+                        lo,
+                        UnsafeBlock(ast::UserProvided));
+                }
+                if self.eat_keyword(keywords::Return) {
+                    // RETURN expression
+                    if can_begin_expr(&self.token) {
+                        let e = self.parse_expr();
+                        hi = e.span.hi;
+                        ex = ExprRet(Some(e));
+                    } else {
+                        ex = ExprRet(None);
+                    }
+                } else if self.eat_keyword(keywords::Break) {
+                    // BREAK expression
+                    if Parser::token_is_lifetime(&self.token) {
+                        let lifetime = self.get_lifetime();
+                        self.bump();
+                        ex = ExprBreak(Some(lifetime));
+                    } else {
+                        ex = ExprBreak(None);
+                    }
+                    hi = self.span.hi;
+                } else if self.token == token::MOD_SEP ||
+                        is_ident(&self.token) &&
+                        !self.is_keyword(keywords::True) &&
+                        !self.is_keyword(keywords::False) {
+                    let pth =
+                        self.parse_path(LifetimeAndTypesWithColons).path;
+
+                    // `!`, as an operator, is prefix, so we know this isn't that
+                    if self.token == token::NOT {
+                        // MACRO INVOCATION expression
+                        self.bump();
 
-                    return self.mk_mac_expr(lo, hi, MacInvocTT(pth, tts, EMPTY_CTXT));
-                } else if self.token == token::LBRACE {
-                    // This is a struct literal, unless we're prohibited from
-                    // parsing struct literals here.
-                    if self.restriction != RESTRICT_NO_STRUCT_LITERAL {
-                        // It's a struct literal.
+                        let ket = token::close_delimiter_for(&self.token)
+                            .unwrap_or_else(|| {
+                                self.fatal("expected open delimiter")
+                            });
                         self.bump();
-                        let mut fields = Vec::new();
-                        let mut base = None;
 
-                        while self.token != token::RBRACE {
-                            if self.eat(&token::DOTDOT) {
-                                base = Some(self.parse_expr());
-                                break;
+                        let tts = self.parse_seq_to_end(
+                            &ket,
+                            seq_sep_none(),
+                            |p| p.parse_token_tree());
+                        let hi = self.span.hi;
+
+                        return self.mk_mac_expr(lo,
+                                                hi,
+                                                MacInvocTT(pth,
+                                                           tts,
+                                                           EMPTY_CTXT));
+                    }
+                    if self.token == token::LBRACE {
+                        // This is a struct literal, unless we're prohibited
+                        // from parsing struct literals here.
+                        if self.restriction != RESTRICT_NO_STRUCT_LITERAL {
+                            // It's a struct literal.
+                            self.bump();
+                            let mut fields = Vec::new();
+                            let mut base = None;
+
+                            while self.token != token::RBRACE {
+                                if self.eat(&token::DOTDOT) {
+                                    base = Some(self.parse_expr());
+                                    break;
+                                }
+
+                                fields.push(self.parse_field());
+                                self.commit_expr(fields.last().unwrap().expr,
+                                                 &[token::COMMA],
+                                                 &[token::RBRACE]);
                             }
 
-                            fields.push(self.parse_field());
-                            self.commit_expr(fields.last().unwrap().expr,
-                                             &[token::COMMA], &[token::RBRACE]);
-                        }
+                            if fields.len() == 0 && base.is_none() {
+                                let last_span = self.last_span;
+                                self.span_err(last_span,
+                                              "structure literal must either \
+                                              have at least one field or use \
+                                              functional structure update \
+                                              syntax");
+                            }
 
-                        if fields.len() == 0 && base.is_none() {
-                            let last_span = self.last_span;
-                            self.span_err(last_span,
-                                          "structure literal must either have at \
-                                          least one field or use functional \
-                                          structure update syntax");
+                            hi = self.span.hi;
+                            self.expect(&token::RBRACE);
+                            ex = ExprStruct(pth, fields, base);
+                            return self.mk_expr(lo, hi, ex);
                         }
-
-                        hi = self.span.hi;
-                        self.expect(&token::RBRACE);
-                        ex = ExprStruct(pth, fields, base);
-                        return self.mk_expr(lo, hi, ex);
                     }
-                }
 
-            hi = pth.span.hi;
-            ex = ExprPath(pth);
-            },
-            _ => {
-                // other literal expression
-                let lit = self.parse_lit();
-                hi = lit.span.hi;
-                ex = ExprLit(box(GC) lit);
+                    hi = pth.span.hi;
+                    ex = ExprPath(pth);
+                } else {
+                    // other literal expression
+                    let lit = self.parse_lit();
+                    hi = lit.span.hi;
+                    ex = ExprLit(box(GC) lit);
+                }
             }
         }
 
@@ -2501,37 +2516,41 @@ impl<'a> Parser<'a> {
               }
             };
           }
-          token::IDENT(_, _) if self.is_keyword(keywords::Box) => {
-            self.bump();
+          token::IDENT(_, _) => {
+              if self.is_keyword(keywords::Box) {
+                self.bump();
 
-            // Check for a place: `box(PLACE) EXPR`.
-            if self.eat(&token::LPAREN) {
-                // Support `box() EXPR` as the default.
-                if !self.eat(&token::RPAREN) {
-                    let place = self.parse_expr();
-                    self.expect(&token::RPAREN);
-                    let subexpression = self.parse_prefix_expr();
-                    hi = subexpression.span.hi;
-                    ex = ExprBox(place, subexpression);
-                    return self.mk_expr(lo, hi, ex);
+                // Check for a place: `box(PLACE) EXPR`.
+                if self.eat(&token::LPAREN) {
+                    // Support `box() EXPR` as the default.
+                    if !self.eat(&token::RPAREN) {
+                        let place = self.parse_expr();
+                        self.expect(&token::RPAREN);
+                        let subexpression = self.parse_prefix_expr();
+                        hi = subexpression.span.hi;
+                        ex = ExprBox(place, subexpression);
+                        return self.mk_expr(lo, hi, ex);
+                    }
                 }
-            }
 
-            // Otherwise, we use the unique pointer default.
-            let subexpression = self.parse_prefix_expr();
-            hi = subexpression.span.hi;
-            // HACK: turn `box [...]` into a boxed-vec
-            ex = match subexpression.node {
-                ExprVec(..) | ExprRepeat(..) => {
-                    let last_span = self.last_span;
-                    self.obsolete(last_span, ObsoleteOwnedVector);
-                    ExprVstore(subexpression, ExprVstoreUniq)
-                }
-                ExprLit(lit) if lit_is_str(lit) => {
-                    ExprVstore(subexpression, ExprVstoreUniq)
-                }
-                _ => self.mk_unary(UnUniq, subexpression)
-            };
+                // Otherwise, we use the unique pointer default.
+                let subexpression = self.parse_prefix_expr();
+                hi = subexpression.span.hi;
+                // HACK: turn `box [...]` into a boxed-vec
+                ex = match subexpression.node {
+                    ExprVec(..) | ExprRepeat(..) => {
+                        let last_span = self.last_span;
+                        self.obsolete(last_span, ObsoleteOwnedVector);
+                        ExprVstore(subexpression, ExprVstoreUniq)
+                    }
+                    ExprLit(lit) if lit_is_str(lit) => {
+                        ExprVstore(subexpression, ExprVstoreUniq)
+                    }
+                    _ => self.mk_unary(UnUniq, subexpression)
+                };
+              } else {
+                return self.parse_dot_or_call_expr()
+              }
           }
           _ => return self.parse_dot_or_call_expr()
         }
@@ -3832,17 +3851,6 @@ impl<'a> Parser<'a> {
                 }
                 SelfStatic
             }
-            token::IDENT(..) if self.is_self_ident() => {
-                let self_ident = self.expect_self_ident();
-
-                // Determine whether this is the fully explicit form, `self:
-                // TYPE`.
-                if self.eat(&token::COLON) {
-                    SelfExplicit(self.parse_ty(false), self_ident)
-                } else {
-                    SelfValue(self_ident)
-                }
-            }
             token::BINOP(token::STAR) => {
                 // Possibly "*self" or "*mut self" -- not supported. Try to avoid
                 // emitting cryptic "unexpected token" errors.
@@ -3860,30 +3868,47 @@ impl<'a> Parser<'a> {
                 // error case, making bogus self ident:
                 SelfValue(special_idents::self_)
             }
-            _ if Parser::token_is_mutability(&self.token) &&
-                    self.look_ahead(1, |t| token::is_keyword(keywords::Self, t)) => {
-                mutbl_self = self.parse_mutability();
-                let self_ident = self.expect_self_ident();
-
-                // Determine whether this is the fully explicit form, `self:
-                // TYPE`.
-                if self.eat(&token::COLON) {
-                    SelfExplicit(self.parse_ty(false), self_ident)
+            token::IDENT(..) => {
+                if self.is_self_ident() {
+                    let self_ident = self.expect_self_ident();
+
+                    // Determine whether this is the fully explicit form, `self:
+                    // TYPE`.
+                    if self.eat(&token::COLON) {
+                        SelfExplicit(self.parse_ty(false), self_ident)
+                    } else {
+                        SelfValue(self_ident)
+                    }
+                } else if Parser::token_is_mutability(&self.token) &&
+                        self.look_ahead(1, |t| {
+                            token::is_keyword(keywords::Self, t)
+                        }) {
+                    mutbl_self = self.parse_mutability();
+                    let self_ident = self.expect_self_ident();
+
+                    // Determine whether this is the fully explicit form,
+                    // `self: TYPE`.
+                    if self.eat(&token::COLON) {
+                        SelfExplicit(self.parse_ty(false), self_ident)
+                    } else {
+                        SelfValue(self_ident)
+                    }
+                } else if Parser::token_is_mutability(&self.token) &&
+                        self.look_ahead(1, |t| *t == token::TILDE) &&
+                        self.look_ahead(2, |t| {
+                            token::is_keyword(keywords::Self, t)
+                        }) {
+                    mutbl_self = self.parse_mutability();
+                    self.bump();
+                    drop(self.expect_self_ident());
+                    let last_span = self.last_span;
+                    self.obsolete(last_span, ObsoleteOwnedSelf);
+                    SelfStatic
                 } else {
-                    SelfValue(self_ident)
+                    SelfStatic
                 }
             }
-            _ if Parser::token_is_mutability(&self.token) &&
-                    self.look_ahead(1, |t| *t == token::TILDE) &&
-                    self.look_ahead(2, |t| token::is_keyword(keywords::Self, t)) => {
-                mutbl_self = self.parse_mutability();
-                self.bump();
-                drop(self.expect_self_ident());
-                let last_span = self.last_span;
-                self.obsolete(last_span, ObsoleteOwnedSelf);
-                SelfStatic
-            }
-            _ => SelfStatic
+            _ => SelfStatic,
         };
 
         let explicit_self_sp = mk_sp(lo, self.span.hi);
diff --git a/src/test/compile-fail/borrowck-lend-flow-match.rs b/src/test/compile-fail/borrowck-lend-flow-match.rs
index c6020df2bc2..049bec3d37b 100644
--- a/src/test/compile-fail/borrowck-lend-flow-match.rs
+++ b/src/test/compile-fail/borrowck-lend-flow-match.rs
@@ -11,9 +11,6 @@
 #![allow(unused_variable)]
 #![allow(dead_assignment)]
 
-fn cond() -> bool { fail!() }
-fn link<'a>(v: &'a uint, w: &mut &'a uint) -> bool { *w = v; true }
-
 fn separate_arms() {
     // Here both arms perform assignments, but only is illegal.
 
@@ -31,28 +28,4 @@ fn separate_arms() {
     x.clone(); // just to prevent liveness warnings
 }
 
-fn guard() {
-    // Here the guard performs a borrow. This borrow "infects" all
-    // subsequent arms (but not the prior ones).
-
-    let mut a = box 3u;
-    let mut b = box 4u;
-    let mut w = &*a;
-    match 22i {
-        _ if cond() => {
-            b = box 5u;
-        }
-
-        _ if link(&*b, &mut w) => {
-            b = box 6u; //~ ERROR cannot assign
-        }
-
-        _ => {
-            b = box 7u; //~ ERROR cannot assign
-        }
-    }
-
-    b = box 8; //~ ERROR cannot assign
-}
-
 fn main() {}
diff --git a/src/test/compile-fail/borrowck-mutate-in-guard.rs b/src/test/compile-fail/borrowck-mutate-in-guard.rs
new file mode 100644
index 00000000000..8a904a3b5fb
--- /dev/null
+++ b/src/test/compile-fail/borrowck-mutate-in-guard.rs
@@ -0,0 +1,33 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+enum Enum<'a> {
+    A(&'a int),
+    B(bool),
+}
+
+fn foo() -> int {
+    let mut n = 42;
+    let mut x = A(&mut n);
+    match x {
+        A(_) if { x = B(false); false } => 1,
+        //~^ ERROR cannot assign in a pattern guard
+        A(_) if { let y = &mut x; *y = B(false); false } => 1,
+        //~^ ERROR cannot mutably borrow in a pattern guard
+        //~^^ ERROR cannot assign in a pattern guard
+        A(p) => *p,
+        B(_) => 2,
+    }
+}
+
+fn main() {
+    foo();
+}
+
diff --git a/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot
index 251798fc7ed..f0907d8d708 100644
--- a/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot
@@ -7,14 +7,15 @@ digraph block {
     N5[label="expr 7777i"];
     N6[label="expr [7i, 77i, 777i, 7777i]"];
     N7[label="expr match [7i, 77i, 777i, 7777i] { [x, y, ..] => x + y }"];
-    N8[label="local x"];
-    N9[label="local y"];
-    N10[label="pat .."];
-    N11[label="pat [x, y, ..]"];
-    N12[label="expr x"];
-    N13[label="expr y"];
-    N14[label="expr x + y"];
-    N15[label="block { match [7i, 77i, 777i, 7777i] { [x, y, ..] => x + y }; }"];
+    N8[label="(dummy_node)"];
+    N9[label="local x"];
+    N10[label="local y"];
+    N11[label="pat .."];
+    N12[label="pat [x, y, ..]"];
+    N13[label="expr x"];
+    N14[label="expr y"];
+    N15[label="expr x + y"];
+    N16[label="block { match [7i, 77i, 777i, 7777i] { [x, y, ..] => x + y }; }"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
@@ -27,7 +28,8 @@ digraph block {
     N11 -> N12;
     N12 -> N13;
     N13 -> N14;
-    N14 -> N7;
-    N7 -> N15;
-    N15 -> N1;
+    N14 -> N15;
+    N15 -> N7;
+    N7 -> N16;
+    N16 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot
index 2be43dcaa7b..dbfa4dd6fe9 100644
--- a/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot
@@ -8,18 +8,20 @@ digraph block {
     N6[label="local _y"];
     N7[label="expr x"];
     N8[label="expr match x { E13a => _y = 1, E13b(v) => _y = v + 1 }"];
-    N9[label="local E13a"];
-    N10[label="expr 1"];
-    N11[label="expr _y"];
-    N12[label="expr _y = 1"];
-    N13[label="local v"];
-    N14[label="pat E13b(v)"];
-    N15[label="expr v"];
-    N16[label="expr 1"];
-    N17[label="expr v + 1"];
-    N18[label="expr _y"];
-    N19[label="expr _y = v + 1"];
-    N20[label="block {\l    let x = E13b(13);\l    let _y;\l    match x { E13a => _y = 1, E13b(v) => _y = v + 1 }\l}\l"];
+    N9[label="(dummy_node)"];
+    N10[label="local E13a"];
+    N11[label="expr 1"];
+    N12[label="expr _y"];
+    N13[label="expr _y = 1"];
+    N14[label="(dummy_node)"];
+    N15[label="local v"];
+    N16[label="pat E13b(v)"];
+    N17[label="expr v"];
+    N18[label="expr 1"];
+    N19[label="expr v + 1"];
+    N20[label="expr _y"];
+    N21[label="expr _y = v + 1"];
+    N22[label="block {\l    let x = E13b(13);\l    let _y;\l    match x { E13a => _y = 1, E13b(v) => _y = v + 1 }\l}\l"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
@@ -30,15 +32,17 @@ digraph block {
     N9 -> N10;
     N10 -> N11;
     N11 -> N12;
-    N12 -> N8;
-    N7 -> N13;
-    N13 -> N14;
+    N12 -> N13;
+    N13 -> N8;
+    N9 -> N14;
     N14 -> N15;
     N15 -> N16;
     N16 -> N17;
     N17 -> N18;
     N18 -> N19;
-    N19 -> N8;
-    N8 -> N20;
-    N20 -> N1;
+    N19 -> N20;
+    N20 -> N21;
+    N21 -> N8;
+    N8 -> N22;
+    N22 -> N1;
 }