From 7b08827f2ddef8e80c176baa8d9f12561a06f1ee Mon Sep 17 00:00:00 2001 From: Jakub Wieczorek Date: Sat, 20 Sep 2014 19:32:18 +0200 Subject: [PATCH] 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. --- src/librustc/middle/borrowck/check_loans.rs | 3 +- src/librustc/middle/borrowck/mod.rs | 6 ++- src/librustc/middle/expr_use_visitor.rs | 7 ++-- src/librustc/middle/ty.rs | 2 +- .../{issue13359.rs => issue-13359.rs} | 0 src/test/compile-fail/issue-17385.rs | 39 +++++++++++++++++++ 6 files changed, 50 insertions(+), 7 deletions(-) rename src/test/compile-fail/{issue13359.rs => issue-13359.rs} (100%) create mode 100644 src/test/compile-fail/issue-17385.rs diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index 95009bc2dbfc..e9be87758f95 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -494,7 +494,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { euv::AutoRef(..) | euv::ClosureInvocation(..) | euv::ForLoop(..) | - euv::RefBinding(..) => { + euv::RefBinding(..) | + euv::MatchDiscriminant(..) => { format!("previous borrow of `{}` occurs here", self.bccx.loan_path_to_string(&*old_loan.loan_path)) } diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index e1e37b3d371a..7d734323ee82 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -648,7 +648,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { euv::AddrOf | euv::RefBinding | euv::AutoRef | - euv::ForLoop => { + euv::ForLoop | + euv::MatchDiscriminant => { format!("cannot borrow {} as mutable", descr) } euv::ClosureInvocation => { @@ -702,7 +703,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { BorrowViolation(euv::OverloadedOperator) | BorrowViolation(euv::AddrOf) | BorrowViolation(euv::AutoRef) | - BorrowViolation(euv::RefBinding) => { + BorrowViolation(euv::RefBinding) | + BorrowViolation(euv::MatchDiscriminant) => { "cannot borrow data mutably" } diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 0b4f661a16ab..81994ee64a8c 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -82,6 +82,7 @@ pub enum LoanCause { OverloadedOperator, ClosureInvocation, ForLoop, + MatchDiscriminant } #[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) => { - // 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)); + self.borrow_expr(&**discr, ty::ReEmpty, ty::ImmBorrow, MatchDiscriminant); + + // treatment of the discriminant is handled while walking the arms. for arm in arms.iter() { self.walk_arm(discr_cmt.clone(), arm); } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 33ade80afd3c..469cdad076da 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -3308,7 +3308,7 @@ pub fn ty_region(tcx: &ctxt, ref s => { tcx.sess.span_bug( span, - format!("ty_region() invoked on in appropriate ty: {:?}", + format!("ty_region() invoked on an inappropriate ty: {:?}", s).as_slice()); } } diff --git a/src/test/compile-fail/issue13359.rs b/src/test/compile-fail/issue-13359.rs similarity index 100% rename from src/test/compile-fail/issue13359.rs rename to src/test/compile-fail/issue-13359.rs diff --git a/src/test/compile-fail/issue-17385.rs b/src/test/compile-fail/issue-17385.rs new file mode 100644 index 000000000000..bc1495ac4543 --- /dev/null +++ b/src/test/compile-fail/issue-17385.rs @@ -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 or the MIT license +// , 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 => () + } +}