Induce an empty loan for the value being matched in match expressions

This is to make sure it hadn't been moved if there are no bindings
in any of the arms.

Fixes #17385.
This commit is contained in:
Jakub Wieczorek 2014-09-20 19:32:18 +02:00
parent 5d335c94bd
commit 7b08827f2d
6 changed files with 50 additions and 7 deletions

View File

@ -494,7 +494,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
euv::AutoRef(..) | euv::AutoRef(..) |
euv::ClosureInvocation(..) | euv::ClosureInvocation(..) |
euv::ForLoop(..) | euv::ForLoop(..) |
euv::RefBinding(..) => { euv::RefBinding(..) |
euv::MatchDiscriminant(..) => {
format!("previous borrow of `{}` occurs here", format!("previous borrow of `{}` occurs here",
self.bccx.loan_path_to_string(&*old_loan.loan_path)) self.bccx.loan_path_to_string(&*old_loan.loan_path))
} }

View File

@ -648,7 +648,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
euv::AddrOf | euv::AddrOf |
euv::RefBinding | euv::RefBinding |
euv::AutoRef | euv::AutoRef |
euv::ForLoop => { euv::ForLoop |
euv::MatchDiscriminant => {
format!("cannot borrow {} as mutable", descr) format!("cannot borrow {} as mutable", descr)
} }
euv::ClosureInvocation => { euv::ClosureInvocation => {
@ -702,7 +703,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
BorrowViolation(euv::OverloadedOperator) | BorrowViolation(euv::OverloadedOperator) |
BorrowViolation(euv::AddrOf) | BorrowViolation(euv::AddrOf) |
BorrowViolation(euv::AutoRef) | BorrowViolation(euv::AutoRef) |
BorrowViolation(euv::RefBinding) => { BorrowViolation(euv::RefBinding) |
BorrowViolation(euv::MatchDiscriminant) => {
"cannot borrow data mutably" "cannot borrow data mutably"
} }

View File

@ -82,6 +82,7 @@ pub enum LoanCause {
OverloadedOperator, OverloadedOperator,
ClosureInvocation, ClosureInvocation,
ForLoop, ForLoop,
MatchDiscriminant
} }
#[deriving(PartialEq,Show)] #[deriving(PartialEq,Show)]
@ -374,10 +375,10 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,TYPER> {
} }
ast::ExprMatch(ref discr, ref arms) => { ast::ExprMatch(ref discr, ref arms) => {
// treatment of the discriminant is handled while
// walking the arms:
self.walk_expr(&**discr);
let discr_cmt = return_if_err!(self.mc.cat_expr(&**discr)); let discr_cmt = return_if_err!(self.mc.cat_expr(&**discr));
self.borrow_expr(&**discr, ty::ReEmpty, ty::ImmBorrow, MatchDiscriminant);
// treatment of the discriminant is handled while walking the arms.
for arm in arms.iter() { for arm in arms.iter() {
self.walk_arm(discr_cmt.clone(), arm); self.walk_arm(discr_cmt.clone(), arm);
} }

View File

@ -3308,7 +3308,7 @@ pub fn ty_region(tcx: &ctxt,
ref s => { ref s => {
tcx.sess.span_bug( tcx.sess.span_bug(
span, span,
format!("ty_region() invoked on in appropriate ty: {:?}", format!("ty_region() invoked on an inappropriate ty: {:?}",
s).as_slice()); s).as_slice());
} }
} }

View File

@ -0,0 +1,39 @@
// 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.
struct X(int);
enum Enum {
Variant1,
Variant2
}
impl Drop for X {
fn drop(&mut self) {}
}
impl Drop for Enum {
fn drop(&mut self) {}
}
fn main() {
let foo = X(1i);
drop(foo);
match foo { //~ ERROR use of moved value
X(1i) => (),
_ => unreachable!()
}
let e = Variant2;
drop(e);
match e { //~ ERROR use of moved value
Variant1 => unreachable!(),
Variant2 => ()
}
}