diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs
index 62547b6669f7a..3350d8f548a86 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 4f6885f05ed16..9cd46067c107b 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 e458b82f03634..4d10676a5892e 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 7995317d49fd1..605811555a168 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 eed058878e082..45af6debe05b0 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -1730,17 +1730,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, "
Fields
\n"));
- for field in fields {
- try!(write!(w, "\
- {stab}{name} | ",
- stab = ConciseStability(&field.stability),
- name = field.name.get_ref().as_slice()));
- try!(document(w, field));
- try!(write!(w, " |
"));
+ doctree::Plain => {
+ if fields.peek().is_some() {
+ try!(write!(w, "Fields
\n"));
+ for field in fields {
+ try!(write!(w, "\
+ {stab}{name} | ",
+ stab = ConciseStability(&field.stability),
+ name = field.name.get_ref().as_slice()));
+ try!(document(w, field));
+ try!(write!(w, " |
"));
+ }
+ try!(write!(w, "
"));
}
- try!(write!(w, "
"));
}
_ => {}
}
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 0116518d537a7..878994369d0d4 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 c6020df2bc2ea..049bec3d37bef 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 0000000000000..8a904a3b5fb89
--- /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 or the MIT license
+// , 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 251798fc7ed88..f0907d8d708f2 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 2be43dcaa7b66..dbfa4dd6fe92c 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;
}