Skip to content

Commit a48ca32

Browse files
committed
auto merge of #7262 : nikomatsakis/rust/ref-bindings-in-irrefut-patterns, r=catamorphism
Correct treatment of irrefutable patterns. The old code was wrong in many, many ways. `ref` bindings didn't work, it sometimes copied when it should have moved, the borrow checker didn't even look at such patterns at all, we weren't consistent about preventing values with destructors from being pulled apart, etc. Fixes #3224. Fixes #3225. Fixes #3255. Fixes #6225. Fixes #6386. r? @catamorphism
2 parents 30c8aac + 0c6d02f commit a48ca32

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+1141
-697
lines changed

src/libextra/fileinput.rs

+9-8
Original file line numberDiff line numberDiff line change
@@ -418,8 +418,8 @@ mod test {
418418
fn make_file(path : &Path, contents: &[~str]) {
419419
let file = io::file_writer(path, [io::Create, io::Truncate]).get();
420420

421-
for contents.iter().advance |&str| {
422-
file.write_str(str);
421+
for contents.iter().advance |str| {
422+
file.write_str(*str);
423423
file.write_char('\n');
424424
}
425425
}
@@ -445,7 +445,7 @@ mod test {
445445
|i| fmt!("tmp/lib-fileinput-test-fileinput-read-byte-%u.tmp", i)), true);
446446
447447
// 3 files containing 0\n, 1\n, and 2\n respectively
448-
for filenames.iter().enumerate().advance |(i, &filename)| {
448+
for filenames.iter().enumerate().advance |(i, filename)| {
449449
make_file(filename.get_ref(), [fmt!("%u", i)]);
450450
}
451451
@@ -475,7 +475,7 @@ mod test {
475475
|i| fmt!("tmp/lib-fileinput-test-fileinput-read-%u.tmp", i)), true);
476476
477477
// 3 files containing 1\n, 2\n, and 3\n respectively
478-
for filenames.iter().enumerate().advance |(i, &filename)| {
478+
for filenames.iter().enumerate().advance |(i, filename)| {
479479
make_file(filename.get_ref(), [fmt!("%u", i)]);
480480
}
481481
@@ -495,10 +495,11 @@ mod test {
495495
3,
496496
|i| fmt!("tmp/lib-fileinput-test-input-vec-%u.tmp", i)), true);
497497

498-
for filenames.iter().enumerate().advance |(i, &filename)| {
498+
for filenames.iter().enumerate().advance |(i, filename)| {
499499
let contents =
500500
vec::from_fn(3, |j| fmt!("%u %u", i, j));
501501
make_file(filename.get_ref(), contents);
502+
debug!("contents=%?", contents);
502503
all_lines.push_all(contents);
503504
}
504505

@@ -515,7 +516,7 @@ mod test {
515516
3,
516517
|i| fmt!("tmp/lib-fileinput-test-input-vec-state-%u.tmp", i)),true);
517518

518-
for filenames.iter().enumerate().advance |(i, &filename)| {
519+
for filenames.iter().enumerate().advance |(i, filename)| {
519520
let contents =
520521
vec::from_fn(3, |j| fmt!("%u %u", i, j + 1));
521522
make_file(filename.get_ref(), contents);
@@ -579,10 +580,10 @@ mod test {
579580
3,
580581
|i| fmt!("tmp/lib-fileinput-test-next-file-%u.tmp", i)),true);
581582
582-
for filenames.iter().enumerate().advance |(i, &filename)| {
583+
for filenames.iter().enumerate().advance |(i, filename)| {
583584
let contents =
584585
vec::from_fn(3, |j| fmt!("%u %u", i, j + 1));
585-
make_file(&filename.get(), contents);
586+
make_file(filename.get_ref(), contents);
586587
}
587588
588589
let in = FileInput::from_vec(filenames);

src/libextra/num/bigint.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -1571,10 +1571,10 @@ mod biguint_tests {
15711571
fn test_to_str_radix() {
15721572
let r = to_str_pairs();
15731573
for r.iter().advance |num_pair| {
1574-
let &(n, rs) = num_pair;
1574+
let &(ref n, ref rs) = num_pair;
15751575
for rs.iter().advance |str_pair| {
1576-
let &(radix, str) = str_pair;
1577-
assert_eq!(n.to_str_radix(radix), str);
1576+
let &(ref radix, ref str) = str_pair;
1577+
assert_eq!(&n.to_str_radix(*radix), str);
15781578
}
15791579
}
15801580
}
@@ -1583,10 +1583,10 @@ mod biguint_tests {
15831583
fn test_from_str_radix() {
15841584
let r = to_str_pairs();
15851585
for r.iter().advance |num_pair| {
1586-
let &(n, rs) = num_pair;
1586+
let &(ref n, ref rs) = num_pair;
15871587
for rs.iter().advance |str_pair| {
1588-
let &(radix, str) = str_pair;
1589-
assert_eq!(&n, &FromStrRadix::from_str_radix(str, radix).get());
1588+
let &(ref radix, ref str) = str_pair;
1589+
assert_eq!(n, &FromStrRadix::from_str_radix(*str, *radix).get());
15901590
}
15911591
}
15921592

src/libextra/rc.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ impl<T> Drop for Rc<T> {
7373
if self.ptr.is_not_null() {
7474
(*self.ptr).count -= 1;
7575
if (*self.ptr).count == 0 {
76-
ptr::replace_ptr(self.ptr, intrinsics::uninit());
76+
ptr::read_ptr(self.ptr);
7777
free(self.ptr as *c_void)
7878
}
7979
}

src/libextra/term.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,8 @@ impl Terminal {
119119
pub fn reset(&self) {
120120
let mut vars = Variables::new();
121121
let s = do self.ti.strings.find_equiv(&("op"))
122-
.map_consume_default(Err(~"can't find terminfo capability `op`")) |&op| {
123-
expand(op, [], &mut vars)
122+
.map_consume_default(Err(~"can't find terminfo capability `op`")) |op| {
123+
expand(copy *op, [], &mut vars)
124124
};
125125
if s.is_ok() {
126126
self.out.write(s.unwrap());

src/libextra/terminfo/parm.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,8 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables)
8181

8282
// Copy parameters into a local vector for mutability
8383
let mut mparams = [Number(0), ..9];
84-
for mparams.mut_iter().zip(params.iter()).advance |(dst, &src)| {
85-
*dst = src;
84+
for mparams.mut_iter().zip(params.iter()).advance |(dst, src)| {
85+
*dst = copy *src;
8686
}
8787

8888
for cap.iter().transform(|&x| x).advance |c| {

src/libextra/treemap.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -773,15 +773,15 @@ mod test_treemap {
773773
map: &TreeMap<K, V>) {
774774
assert_eq!(ctrl.is_empty(), map.is_empty());
775775
for ctrl.iter().advance |x| {
776-
let &(k, v) = x;
777-
assert!(map.find(&k).unwrap() == &v)
776+
let &(ref k, ref v) = x;
777+
assert!(map.find(k).unwrap() == v)
778778
}
779779
for map.iter().advance |(map_k, map_v)| {
780780
let mut found = false;
781781
for ctrl.iter().advance |x| {
782-
let &(ctrl_k, ctrl_v) = x;
783-
if *map_k == ctrl_k {
784-
assert!(*map_v == ctrl_v);
782+
let &(ref ctrl_k, ref ctrl_v) = x;
783+
if *map_k == *ctrl_k {
784+
assert!(*map_v == *ctrl_v);
785785
found = true;
786786
break;
787787
}

src/libextra/workcache.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,8 @@ impl<D:Decoder> Decodable<D> for WorkMap {
157157
fn decode(d: &mut D) -> WorkMap {
158158
let v : ~[(WorkKey,~str)] = Decodable::decode(d);
159159
let mut w = WorkMap::new();
160-
for v.iter().advance |&(k, v)| {
161-
w.insert(copy k, copy v);
160+
for v.iter().advance |pair| {
161+
w.insert(pair.first(), pair.second());
162162
}
163163
w
164164
}

src/librustc/back/passes.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -165,10 +165,10 @@ pub fn create_standard_passes(level: OptLevel) -> ~[~str] {
165165
}
166166

167167
pub fn populate_pass_manager(sess: Session, pm: &mut PassManager, pass_list:&[~str]) {
168-
for pass_list.iter().advance |&nm| {
169-
match create_pass(nm) {
168+
for pass_list.iter().advance |nm| {
169+
match create_pass(*nm) {
170170
Some(p) => pm.add_pass(p),
171-
None => sess.warn(fmt!("Unknown pass %s", nm))
171+
None => sess.warn(fmt!("Unknown pass %s", *nm))
172172
}
173173
}
174174
}

src/librustc/driver/driver.rs

-1
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,6 @@ pub fn compile_rest(sess: Session,
314314
method_map: method_map,
315315
vtable_map: vtable_map,
316316
write_guard_map: write_guard_map,
317-
moves_map: moves_map,
318317
capture_map: capture_map
319318
};
320319

src/librustc/metadata/loader.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,9 @@ fn find_library_crate_aux(
127127
cx.diag.span_err(
128128
cx.span, fmt!("multiple matching crates for `%s`", crate_name));
129129
cx.diag.handler().note("candidates:");
130-
for matches.iter().advance |&(ident, data)| {
130+
for matches.iter().advance |pair| {
131+
let ident = pair.first();
132+
let data = pair.second();
131133
cx.diag.handler().note(fmt!("path: %s", ident));
132134
let attrs = decoder::get_crate_attributes(data);
133135
note_linkage_attrs(cx.intr, cx.diag, attrs);

src/librustc/middle/astencode.rs

+1-10
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ pub struct Maps {
5353
method_map: middle::typeck::method_map,
5454
vtable_map: middle::typeck::vtable_map,
5555
write_guard_map: middle::borrowck::write_guard_map,
56-
moves_map: middle::moves::MovesMap,
5756
capture_map: middle::moves::CaptureMap,
5857
}
5958

@@ -952,12 +951,6 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
952951
}
953952
}
954953

955-
if maps.moves_map.contains(&id) {
956-
do ebml_w.tag(c::tag_table_moves_map) |ebml_w| {
957-
ebml_w.id(id);
958-
}
959-
}
960-
961954
{
962955
let r = maps.capture_map.find(&id);
963956
for r.iter().advance |&cap_vars| {
@@ -1121,9 +1114,7 @@ fn decode_side_tables(xcx: @ExtendedDecodeContext,
11211114
xcx.dcx.tcx.sess.bug(
11221115
fmt!("unknown tag found in side tables: %x", tag));
11231116
}
1124-
Some(value) => if value == c::tag_table_moves_map {
1125-
dcx.maps.moves_map.insert(id);
1126-
} else {
1117+
Some(value) => {
11271118
let val_doc = entry_doc.get(c::tag_table_val as uint);
11281119
let mut val_dsr = reader::Decoder(val_doc);
11291120
let val_dsr = &mut val_dsr;

src/librustc/middle/borrowck/check_loans.rs

+40-51
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ pub fn check_loans(bccx: @BorrowckCtxt,
6565

6666
enum MoveError {
6767
MoveOk,
68-
MoveWhileBorrowed(/*move*/@LoanPath, /*loan*/@LoanPath, /*loan*/span)
68+
MoveWhileBorrowed(/*loan*/@LoanPath, /*loan*/span)
6969
}
7070

7171
impl<'self> CheckLoanCtxt<'self> {
@@ -348,7 +348,7 @@ impl<'self> CheckLoanCtxt<'self> {
348348
cmt = b;
349349
}
350350

351-
mc::cat_rvalue |
351+
mc::cat_rvalue(*) |
352352
mc::cat_static_item |
353353
mc::cat_implicit_self |
354354
mc::cat_copied_upvar(*) |
@@ -547,45 +547,50 @@ impl<'self> CheckLoanCtxt<'self> {
547547
self.bccx.loan_path_to_str(loan_path)));
548548
}
549549

550-
pub fn check_move_out_from_expr(&self, ex: @ast::expr) {
551-
match ex.node {
552-
ast::expr_paren(*) => {
553-
/* In the case of an expr_paren(), the expression inside
554-
* the parens will also be marked as being moved. Ignore
555-
* the parents then so as not to report duplicate errors. */
550+
fn check_move_out_from_expr(&self, expr: @ast::expr) {
551+
match expr.node {
552+
ast::expr_fn_block(*) => {
553+
// moves due to capture clauses are checked
554+
// in `check_loans_in_fn`, so that we can
555+
// give a better error message
556556
}
557557
_ => {
558-
let cmt = self.bccx.cat_expr(ex);
559-
match self.analyze_move_out_from_cmt(cmt) {
560-
MoveOk => {}
561-
MoveWhileBorrowed(move_path, loan_path, loan_span) => {
562-
self.bccx.span_err(
563-
cmt.span,
564-
fmt!("cannot move out of `%s` \
565-
because it is borrowed",
566-
self.bccx.loan_path_to_str(move_path)));
567-
self.bccx.span_note(
568-
loan_span,
569-
fmt!("borrow of `%s` occurs here",
570-
self.bccx.loan_path_to_str(loan_path)));
571-
}
558+
self.check_move_out_from_id(expr.id, expr.span)
559+
}
560+
}
561+
}
562+
563+
fn check_move_out_from_id(&self, id: ast::node_id, span: span) {
564+
for self.move_data.each_path_moved_by(id) |_, move_path| {
565+
match self.analyze_move_out_from(id, move_path) {
566+
MoveOk => {}
567+
MoveWhileBorrowed(loan_path, loan_span) => {
568+
self.bccx.span_err(
569+
span,
570+
fmt!("cannot move out of `%s` \
571+
because it is borrowed",
572+
self.bccx.loan_path_to_str(move_path)));
573+
self.bccx.span_note(
574+
loan_span,
575+
fmt!("borrow of `%s` occurs here",
576+
self.bccx.loan_path_to_str(loan_path)));
572577
}
573578
}
574579
}
575580
}
576581

577-
pub fn analyze_move_out_from_cmt(&self, cmt: mc::cmt) -> MoveError {
578-
debug!("analyze_move_out_from_cmt(cmt=%s)", cmt.repr(self.tcx()));
582+
pub fn analyze_move_out_from(&self,
583+
expr_id: ast::node_id,
584+
move_path: @LoanPath) -> MoveError {
585+
debug!("analyze_move_out_from(expr_id=%?, move_path=%s)",
586+
expr_id, move_path.repr(self.tcx()));
579587

580588
// FIXME(#4384) inadequare if/when we permit `move a.b`
581589

582590
// check for a conflicting loan:
583-
let r = opt_loan_path(cmt);
584-
for r.iter().advance |&lp| {
585-
for self.each_in_scope_restriction(cmt.id, lp) |loan, _| {
586-
// Any restriction prevents moves.
587-
return MoveWhileBorrowed(lp, loan.loan_path, loan.span);
588-
}
591+
for self.each_in_scope_restriction(expr_id, move_path) |loan, _| {
592+
// Any restriction prevents moves.
593+
return MoveWhileBorrowed(loan.loan_path, loan.span);
589594
}
590595

591596
MoveOk
@@ -652,13 +657,11 @@ fn check_loans_in_fn<'a>(fk: &visit::fn_kind,
652657
closure_id: ast::node_id,
653658
cap_var: &moves::CaptureVar) {
654659
let var_id = ast_util::def_id_of_def(cap_var.def).node;
655-
let ty = ty::node_id_to_type(this.tcx(), var_id);
656-
let cmt = this.bccx.cat_def(closure_id, cap_var.span,
657-
ty, cap_var.def);
658-
let move_err = this.analyze_move_out_from_cmt(cmt);
660+
let move_path = @LpVar(var_id);
661+
let move_err = this.analyze_move_out_from(closure_id, move_path);
659662
match move_err {
660663
MoveOk => {}
661-
MoveWhileBorrowed(move_path, loan_path, loan_span) => {
664+
MoveWhileBorrowed(loan_path, loan_span) => {
662665
this.bccx.span_err(
663666
cap_var.span,
664667
fmt!("cannot move `%s` into closure \
@@ -689,10 +692,7 @@ fn check_loans_in_expr<'a>(expr: @ast::expr,
689692
expr.repr(this.tcx()));
690693

691694
this.check_for_conflicting_loans(expr.id);
692-
693-
if this.bccx.moves_map.contains(&expr.id) {
694-
this.check_move_out_from_expr(expr);
695-
}
695+
this.check_move_out_from_expr(expr);
696696

697697
match expr.node {
698698
ast::expr_self |
@@ -742,18 +742,7 @@ fn check_loans_in_pat<'a>(pat: @ast::pat,
742742
visit::vt<@mut CheckLoanCtxt<'a>>))
743743
{
744744
this.check_for_conflicting_loans(pat.id);
745-
746-
// Note: moves out of pattern bindings are not checked by
747-
// the borrow checker, at least not directly. What happens
748-
// is that if there are any moved bindings, the discriminant
749-
// will be considered a move, and this will be checked as
750-
// normal. Then, in `middle::check_match`, we will check
751-
// that no move occurs in a binding that is underneath an
752-
// `@` or `&`. Together these give the same guarantees as
753-
// `check_move_out_from_expr()` without requiring us to
754-
// rewalk the patterns and rebuild the pattern
755-
// categorizations.
756-
745+
this.check_move_out_from_id(pat.id, pat.span);
757746
visit::visit_pat(pat, (this, vt));
758747
}
759748

0 commit comments

Comments
 (0)