Skip to content

Commit 69c58bc

Browse files
committed
auto merge of #16185 : luqmana/rust/match-drop, r=pcwalton
Fixes #15571. Fixes #16151. r? @pcwalton
2 parents d4d608f + 71df8e6 commit 69c58bc

File tree

8 files changed

+232
-12
lines changed

8 files changed

+232
-12
lines changed

src/librustc/metadata/common.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,9 +140,10 @@ pub enum astencode_tag { // Reserves 0x40 -- 0x5f
140140
tag_table_moves_map = 0x52,
141141
tag_table_capture_map = 0x53,
142142
tag_table_unboxed_closure_type = 0x54,
143+
tag_table_upvar_borrow_map = 0x55,
143144
}
144145
static first_astencode_tag: uint = tag_ast as uint;
145-
static last_astencode_tag: uint = tag_table_unboxed_closure_type as uint;
146+
static last_astencode_tag: uint = tag_table_upvar_borrow_map as uint;
146147
impl astencode_tag {
147148
pub fn from_uint(value : uint) -> Option<astencode_tag> {
148149
let is_a_tag = first_astencode_tag <= value && value <= last_astencode_tag;

src/librustc/middle/astencode.rs

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use driver::session::Session;
1818
use metadata::decoder;
1919
use middle::def;
2020
use e = metadata::encoder;
21+
use middle::freevars;
2122
use middle::freevars::freevar_entry;
2223
use middle::region;
2324
use metadata::tydecode;
@@ -551,6 +552,15 @@ impl tr for freevar_entry {
551552
}
552553
}
553554

555+
impl tr for ty::UpvarBorrow {
556+
fn tr(&self, xcx: &ExtendedDecodeContext) -> ty::UpvarBorrow {
557+
ty::UpvarBorrow {
558+
kind: self.kind,
559+
region: self.region.tr(xcx)
560+
}
561+
}
562+
}
563+
554564
// ______________________________________________________________________
555565
// Encoding and decoding of MethodCallee
556566

@@ -1061,7 +1071,29 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
10611071
Ok(encode_freevar_entry(rbml_w, fv_entry))
10621072
});
10631073
})
1064-
})
1074+
});
1075+
1076+
for freevar in fv.iter() {
1077+
match freevars::get_capture_mode(tcx, id) {
1078+
freevars::CaptureByRef => {
1079+
rbml_w.tag(c::tag_table_upvar_borrow_map, |rbml_w| {
1080+
rbml_w.id(id);
1081+
rbml_w.tag(c::tag_table_val, |rbml_w| {
1082+
let var_id = freevar.def.def_id().node;
1083+
let upvar_id = ty::UpvarId {
1084+
var_id: var_id,
1085+
closure_expr_id: id
1086+
};
1087+
let upvar_borrow = tcx.upvar_borrow_map.borrow()
1088+
.get_copy(&upvar_id);
1089+
var_id.encode(rbml_w);
1090+
upvar_borrow.encode(rbml_w);
1091+
})
1092+
})
1093+
}
1094+
_ => {}
1095+
}
1096+
}
10651097
}
10661098

10671099
let lid = ast::DefId { krate: ast::LOCAL_CRATE, node: id };
@@ -1468,6 +1500,15 @@ fn decode_side_tables(xcx: &ExtendedDecodeContext,
14681500
}).unwrap().move_iter().collect();
14691501
dcx.tcx.freevars.borrow_mut().insert(id, fv_info);
14701502
}
1503+
c::tag_table_upvar_borrow_map => {
1504+
let var_id: ast::NodeId = Decodable::decode(val_dsr).unwrap();
1505+
let upvar_id = ty::UpvarId {
1506+
var_id: xcx.tr_id(var_id),
1507+
closure_expr_id: id
1508+
};
1509+
let ub: ty::UpvarBorrow = Decodable::decode(val_dsr).unwrap();
1510+
dcx.tcx.upvar_borrow_map.borrow_mut().insert(upvar_id, ub.tr(xcx));
1511+
}
14711512
c::tag_table_tcache => {
14721513
let pty = val_dsr.read_polytype(xcx);
14731514
let lid = ast::DefId { krate: ast::LOCAL_CRATE, node: id };

src/librustc/middle/freevars.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#![allow(non_camel_case_types)]
1515

1616
use middle::def;
17+
use middle::mem_categorization::Typer;
1718
use middle::resolve;
1819
use middle::ty;
1920
use util::nodemap::{DefIdSet, NodeMap, NodeSet};
@@ -147,11 +148,8 @@ pub fn with_freevars<T>(tcx: &ty::ctxt, fid: ast::NodeId, f: |&[freevar_entry]|
147148
}
148149
}
149150

150-
pub fn get_capture_mode(tcx: &ty::ctxt,
151-
closure_expr_id: ast::NodeId)
152-
-> CaptureMode
153-
{
154-
let fn_ty = ty::node_id_to_type(tcx, closure_expr_id);
151+
pub fn get_capture_mode<T: Typer>(tcx: &T, closure_expr_id: ast::NodeId) -> CaptureMode {
152+
let fn_ty = tcx.node_ty(closure_expr_id).ok().expect("couldn't find closure ty?");
155153
match ty::ty_closure_store(fn_ty) {
156154
ty::RegionTraitStore(..) => CaptureByRef,
157155
ty::UniqTraitStore => CaptureByValue

src/librustc/middle/trans/_match.rs

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,9 @@
189189
#![allow(non_camel_case_types)]
190190

191191
use back::abi;
192+
use mc = middle::mem_categorization;
192193
use driver::config::FullDebugInfo;
194+
use euv = middle::expr_use_visitor;
193195
use llvm;
194196
use llvm::{ValueRef, BasicBlockRef};
195197
use middle::const_eval;
@@ -1292,13 +1294,58 @@ pub fn trans_match<'a>(
12921294
trans_match_inner(bcx, match_expr.id, discr_expr, arms, dest)
12931295
}
12941296

1295-
fn create_bindings_map(bcx: &Block, pat: Gc<ast::Pat>) -> BindingsMap {
1297+
/// Checks whether the binding in `discr` is assigned to anywhere in the expression `body`
1298+
fn is_discr_reassigned(bcx: &Block, discr: &ast::Expr, body: &ast::Expr) -> bool {
1299+
match discr.node {
1300+
ast::ExprPath(..) => match bcx.def(discr.id) {
1301+
def::DefArg(vid, _) | def::DefBinding(vid, _) |
1302+
def::DefLocal(vid, _) | def::DefUpvar(vid, _, _, _) => {
1303+
let mut rc = ReassignmentChecker {
1304+
node: vid,
1305+
reassigned: false
1306+
};
1307+
{
1308+
let mut visitor = euv::ExprUseVisitor::new(&mut rc, bcx);
1309+
visitor.walk_expr(body);
1310+
}
1311+
rc.reassigned
1312+
}
1313+
_ => false
1314+
},
1315+
_ => false
1316+
}
1317+
}
1318+
1319+
struct ReassignmentChecker {
1320+
node: ast::NodeId,
1321+
reassigned: bool
1322+
}
1323+
1324+
impl euv::Delegate for ReassignmentChecker {
1325+
fn consume(&mut self, _: ast::NodeId, _: Span, _: mc::cmt, _: euv::ConsumeMode) {}
1326+
fn consume_pat(&mut self, _: &ast::Pat, _: mc::cmt, _: euv::ConsumeMode) {}
1327+
fn borrow(&mut self, _: ast::NodeId, _: Span, _: mc::cmt, _: ty::Region,
1328+
_: ty::BorrowKind, _: euv::LoanCause) {}
1329+
fn decl_without_init(&mut self, _: ast::NodeId, _: Span) {}
1330+
1331+
fn mutate(&mut self, _: ast::NodeId, _: Span, cmt: mc::cmt, _: euv::MutateMode) {
1332+
match cmt.cat {
1333+
mc::cat_copied_upvar(mc::CopiedUpvar { upvar_id: vid, .. }) |
1334+
mc::cat_arg(vid) | mc::cat_local(vid) => self.reassigned = self.node == vid,
1335+
_ => {}
1336+
}
1337+
}
1338+
}
1339+
1340+
fn create_bindings_map(bcx: &Block, pat: Gc<ast::Pat>,
1341+
discr: &ast::Expr, body: &ast::Expr) -> BindingsMap {
12961342
// Create the bindings map, which is a mapping from each binding name
12971343
// to an alloca() that will be the value for that local variable.
12981344
// Note that we use the names because each binding will have many ids
12991345
// from the various alternatives.
13001346
let ccx = bcx.ccx();
13011347
let tcx = bcx.tcx();
1348+
let reassigned = is_discr_reassigned(bcx, discr, body);
13021349
let mut bindings_map = HashMap::new();
13031350
pat_bindings(&tcx.def_map, &*pat, |bm, p_id, span, path1| {
13041351
let ident = path1.node;
@@ -1310,7 +1357,7 @@ fn create_bindings_map(bcx: &Block, pat: Gc<ast::Pat>) -> BindingsMap {
13101357
let trmode;
13111358
match bm {
13121359
ast::BindByValue(_)
1313-
if !ty::type_moves_by_default(tcx, variable_ty) => {
1360+
if !ty::type_moves_by_default(tcx, variable_ty) || reassigned => {
13141361
llmatch = alloca_no_lifetime(bcx,
13151362
llvariable_ty.ptr_to(),
13161363
"__llmatch");
@@ -1371,7 +1418,7 @@ fn trans_match_inner<'a>(scope_cx: &'a Block<'a>,
13711418
let arm_datas: Vec<ArmData> = arms.iter().map(|arm| ArmData {
13721419
bodycx: fcx.new_id_block("case_body", arm.body.id),
13731420
arm: arm,
1374-
bindings_map: create_bindings_map(bcx, *arm.pats.get(0))
1421+
bindings_map: create_bindings_map(bcx, *arm.pats.get(0), discr_expr, &*arm.body)
13751422
}).collect();
13761423

13771424
let mut static_inliner = StaticInliner { tcx: scope_cx.tcx() };

src/librustc/middle/trans/common.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use driver::session::Session;
1616
use llvm;
1717
use llvm::{ValueRef, BasicBlockRef, BuilderRef};
1818
use llvm::{True, False, Bool};
19+
use mc = middle::mem_categorization;
1920
use middle::def;
2021
use middle::lang_items::LangItem;
2122
use middle::subst;
@@ -481,6 +482,36 @@ impl<'a> Block<'a> {
481482
}
482483
}
483484

485+
impl<'a> mc::Typer for Block<'a> {
486+
fn tcx<'a>(&'a self) -> &'a ty::ctxt {
487+
self.tcx()
488+
}
489+
490+
fn node_ty(&self, id: ast::NodeId) -> mc::McResult<ty::t> {
491+
Ok(node_id_type(self, id))
492+
}
493+
494+
fn node_method_ty(&self, method_call: typeck::MethodCall) -> Option<ty::t> {
495+
self.tcx().method_map.borrow().find(&method_call).map(|method| method.ty)
496+
}
497+
498+
fn adjustments<'a>(&'a self) -> &'a RefCell<NodeMap<ty::AutoAdjustment>> {
499+
&self.tcx().adjustments
500+
}
501+
502+
fn is_method_call(&self, id: ast::NodeId) -> bool {
503+
self.tcx().method_map.borrow().contains_key(&typeck::MethodCall::expr(id))
504+
}
505+
506+
fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<ast::NodeId> {
507+
self.tcx().region_maps.temporary_scope(rvalue_id)
508+
}
509+
510+
fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> ty::UpvarBorrow {
511+
self.tcx().upvar_borrow_map.borrow().get_copy(&upvar_id)
512+
}
513+
}
514+
484515
pub struct Result<'a> {
485516
pub bcx: &'a Block<'a>,
486517
pub val: ValueRef

src/librustc/middle/ty.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,7 @@ pub struct UpvarId {
539539
pub closure_expr_id: ast::NodeId,
540540
}
541541

542-
#[deriving(Clone, PartialEq, Eq, Hash, Show)]
542+
#[deriving(Clone, PartialEq, Eq, Hash, Show, Encodable, Decodable)]
543543
pub enum BorrowKind {
544544
/// Data must be immutable and is aliasable.
545545
ImmBorrow,
@@ -634,7 +634,7 @@ pub enum BorrowKind {
634634
* the closure, so sometimes it is necessary for them to be larger
635635
* than the closure lifetime itself.
636636
*/
637-
#[deriving(PartialEq, Clone)]
637+
#[deriving(PartialEq, Clone, Encodable, Decodable)]
638638
pub struct UpvarBorrow {
639639
pub kind: BorrowKind,
640640
pub region: ty::Region,

src/test/run-pass/issue-15571.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn match_on_local() {
12+
let mut foo = Some(box 5i);
13+
match foo {
14+
None => {},
15+
Some(x) => {
16+
foo = Some(x);
17+
}
18+
}
19+
println!("'{}'", foo.unwrap());
20+
}
21+
22+
fn match_on_arg(mut foo: Option<Box<int>>) {
23+
match foo {
24+
None => {}
25+
Some(x) => {
26+
foo = Some(x);
27+
}
28+
}
29+
println!("'{}'", foo.unwrap());
30+
}
31+
32+
fn match_on_binding() {
33+
match Some(box 7i) {
34+
mut foo => {
35+
match foo {
36+
None => {},
37+
Some(x) => {
38+
foo = Some(x);
39+
}
40+
}
41+
println!("'{}'", foo.unwrap());
42+
}
43+
}
44+
}
45+
46+
fn match_on_upvar() {
47+
let mut foo = Some(box 8i);
48+
(proc() {
49+
match foo {
50+
None => {},
51+
Some(x) => {
52+
foo = Some(x);
53+
}
54+
}
55+
println!("'{}'", foo.unwrap());
56+
})();
57+
}
58+
59+
fn main() {
60+
match_on_local();
61+
match_on_arg(Some(box 6i));
62+
match_on_binding();
63+
match_on_upvar();
64+
}

src/test/run-pass/issue-16151.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use std::mem;
12+
13+
static mut DROP_COUNT: uint = 0;
14+
15+
struct Fragment;
16+
17+
impl Drop for Fragment {
18+
fn drop(&mut self) {
19+
unsafe {
20+
DROP_COUNT += 1;
21+
}
22+
}
23+
}
24+
25+
fn main() {
26+
{
27+
let mut fragments = vec![Fragment, Fragment, Fragment];
28+
let _new_fragments: Vec<Fragment> = mem::replace(&mut fragments, vec![])
29+
.move_iter()
30+
.skip_while(|_fragment| {
31+
true
32+
}).collect();
33+
}
34+
unsafe {
35+
assert_eq!(DROP_COUNT, 3);
36+
}
37+
}
38+

0 commit comments

Comments
 (0)