Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

librustc: Disallow mutation and assignment in pattern guards, and modify #15989

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions src/libfmt_macros/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
41 changes: 23 additions & 18 deletions src/librustc/middle/cfg/construct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
65 changes: 64 additions & 1 deletion src/librustc/middle/check_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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 => {}
}
}
}

2 changes: 1 addition & 1 deletion src/librustc/middle/expr_use_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
22 changes: 12 additions & 10 deletions src/librustdoc/html/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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, "<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>"));
}
_ => {}
}
Expand Down
Loading