Skip to content

Commit ede7f94

Browse files
committed
Auto merge of #49822 - matthewjasper:dropck-closures, r=nikomatsakis
Access individual fields of tuples, closures and generators on drop. Fixes #48623, by extending the change in #47917 to closures. Also does this for tuples and generators for consistency. Enums are unchanged because there is now way to borrow `*enum.field` without borrowing `enum.field` at the moment, so any error would be reported when the enum goes out of scope. Unions aren't changed because unions they don't automatically drop their fields. r? @nikomatsakis
2 parents 686d0ae + 902bc0f commit ede7f94

File tree

5 files changed

+102
-40
lines changed

5 files changed

+102
-40
lines changed

src/librustc_mir/borrow_check/mod.rs

+30-10
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use rustc::ty::maps::Providers;
2020
use rustc::mir::{AssertMessage, BasicBlock, BorrowKind, Location, Place};
2121
use rustc::mir::{Mir, Mutability, Operand, Projection, ProjectionElem, Rvalue};
2222
use rustc::mir::{Field, Statement, StatementKind, Terminator, TerminatorKind};
23-
use rustc::mir::ClosureRegionRequirements;
23+
use rustc::mir::{ClosureRegionRequirements, Local};
2424

2525
use rustc_data_structures::control_flow_graph::dominators::Dominators;
2626
use rustc_data_structures::fx::FxHashSet;
@@ -729,6 +729,17 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
729729
erased_drop_place_ty: ty::Ty<'gcx>,
730730
span: Span,
731731
) {
732+
let gcx = self.tcx.global_tcx();
733+
let drop_field = |
734+
mir: &mut MirBorrowckCtxt<'cx, 'gcx, 'tcx>,
735+
(index, field): (usize, ty::Ty<'gcx>),
736+
| {
737+
let field_ty = gcx.normalize_erasing_regions(mir.param_env, field);
738+
let place = drop_place.clone().field(Field::new(index), field_ty);
739+
740+
mir.visit_terminator_drop(loc, term, flow_state, &place, field_ty, span);
741+
};
742+
732743
match erased_drop_place_ty.sty {
733744
// When a struct is being dropped, we need to check
734745
// whether it has a destructor, if it does, then we can
@@ -737,22 +748,31 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
737748
// destructor but `bar` does not, we will only check for
738749
// borrows of `x.foo` and not `x.bar`. See #47703.
739750
ty::TyAdt(def, substs) if def.is_struct() && !def.has_dtor(self.tcx) => {
740-
for (index, field) in def.all_fields().enumerate() {
741-
let gcx = self.tcx.global_tcx();
742-
let field_ty = field.ty(gcx, substs);
743-
let field_ty = gcx.normalize_erasing_regions(self.param_env, field_ty);
744-
let place = drop_place.clone().field(Field::new(index), field_ty);
745-
746-
self.visit_terminator_drop(loc, term, flow_state, &place, field_ty, span);
747-
}
751+
def.all_fields()
752+
.map(|field| field.ty(gcx, substs))
753+
.enumerate()
754+
.for_each(|field| drop_field(self, field));
755+
}
756+
// Same as above, but for tuples.
757+
ty::TyTuple(tys) => {
758+
tys.iter().cloned().enumerate()
759+
.for_each(|field| drop_field(self, field));
760+
}
761+
// Closures and generators also have disjoint fields, but they are only
762+
// directly accessed in the body of the closure/generator.
763+
ty::TyClosure(def, substs)
764+
| ty::TyGenerator(def, substs, ..)
765+
if *drop_place == Place::Local(Local::new(1)) && !self.mir.upvar_decls.is_empty()
766+
=> {
767+
substs.upvar_tys(def, self.tcx).enumerate()
768+
.for_each(|field| drop_field(self, field));
748769
}
749770
_ => {
750771
// We have now refined the type of the value being
751772
// dropped (potentially) to just the type of a
752773
// subfield; so check whether that field's type still
753774
// "needs drop". If so, we assume that the destructor
754775
// may access any data it likes (i.e., a Deep Write).
755-
let gcx = self.tcx.global_tcx();
756776
if erased_drop_place_ty.needs_drop(gcx, self.param_env) {
757777
self.access_place(
758778
ContextKind::Drop.new(loc),
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2012 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+
#![feature(nll)]
12+
13+
struct WithDrop;
14+
15+
impl Drop for WithDrop {
16+
fn drop(&mut self) {}
17+
}
18+
19+
fn consume(x: (&mut (), WithDrop)) -> &mut () { x.0 }
20+
21+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2012 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+
#![feature(nll)]
12+
13+
struct WithDrop;
14+
15+
impl Drop for WithDrop {
16+
fn drop(&mut self) {}
17+
}
18+
19+
fn reborrow_from_closure(r: &mut ()) -> &mut () {
20+
let d = WithDrop;
21+
(move || { d; &mut *r })()
22+
}
23+
24+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright 2012 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+
#![feature(nll)]
12+
#![feature(generators, generator_trait)]
13+
14+
struct WithDrop;
15+
16+
impl Drop for WithDrop {
17+
fn drop(&mut self) {}
18+
}
19+
20+
fn reborrow_from_generator(r: &mut ()) {
21+
let d = WithDrop;
22+
move || { d; yield; &mut *r };
23+
}
24+
25+
fn main() {}

src/test/ui/generator/yield-while-iterating.nll.stderr

+2-30
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,6 @@ LL | for p in &x { //~ ERROR
66
LL | yield();
77
| ------- possible yield occurs here
88

9-
error[E0597]: borrowed value does not live long enough
10-
--> $DIR/yield-while-iterating.rs:50:17
11-
|
12-
LL | let mut b = || {
13-
| _________________^
14-
LL | | for p in &mut x {
15-
LL | | yield p;
16-
LL | | }
17-
LL | | };
18-
| | ^
19-
| | |
20-
| |_____temporary value only lives until here
21-
| temporary value does not live long enough
22-
239
error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
2410
--> $DIR/yield-while-iterating.rs:67:20
2511
|
@@ -35,21 +21,7 @@ LL | println!("{}", x[0]); //~ ERROR
3521
LL | b.resume();
3622
| - borrow later used here
3723

38-
error[E0597]: borrowed value does not live long enough
39-
--> $DIR/yield-while-iterating.rs:62:17
40-
|
41-
LL | let mut b = || {
42-
| _________________^
43-
LL | | for p in &mut x {
44-
LL | | yield p;
45-
LL | | }
46-
LL | | };
47-
| | ^
48-
| | |
49-
| |_____temporary value only lives until here
50-
| temporary value does not live long enough
51-
52-
error: aborting due to 4 previous errors
24+
error: aborting due to 2 previous errors
5325

54-
Some errors occurred: E0502, E0597, E0626.
26+
Some errors occurred: E0502, E0626.
5527
For more information about an error, try `rustc --explain E0502`.

0 commit comments

Comments
 (0)