Skip to content

Commit 507a46a

Browse files
committed
Auto merge of #47917 - davidtwco:issue-47703, r=nikomatsakis
Fixes NLL: error from URL crate Fixes #47703. r? @nikomatsakis
2 parents 554fe71 + 98904c2 commit 507a46a

File tree

3 files changed

+134
-7
lines changed

3 files changed

+134
-7
lines changed

src/librustc_mir/borrow_check/mod.rs

+73-7
Original file line numberDiff line numberDiff line change
@@ -463,13 +463,20 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
463463
target: _,
464464
unwind: _,
465465
} => {
466-
self.access_place(
467-
ContextKind::Drop.new(loc),
468-
(drop_place, span),
469-
(Deep, Write(WriteKind::StorageDeadOrDrop)),
470-
LocalMutationIsAllowed::Yes,
471-
flow_state,
472-
);
466+
let gcx = self.tcx.global_tcx();
467+
468+
// Compute the type with accurate region information.
469+
let drop_place_ty = drop_place.ty(self.mir, self.tcx);
470+
471+
// Erase the regions.
472+
let drop_place_ty = self.tcx.erase_regions(&drop_place_ty).to_ty(self.tcx);
473+
474+
// "Lift" into the gcx -- once regions are erased, this type should be in the
475+
// global arenas; this "lift" operation basically just asserts that is true, but
476+
// that is useful later.
477+
let drop_place_ty = gcx.lift(&drop_place_ty).unwrap();
478+
479+
self.visit_terminator_drop(loc, term, flow_state, drop_place, drop_place_ty, span);
473480
}
474481
TerminatorKind::DropAndReplace {
475482
location: ref drop_place,
@@ -717,6 +724,65 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
717724
self.tcx.sess.opts.debugging_opts.two_phase_beyond_autoref)
718725
}
719726

727+
/// Invokes `access_place` as appropriate for dropping the value
728+
/// at `drop_place`. Note that the *actual* `Drop` in the MIR is
729+
/// always for a variable (e.g., `Drop(x)`) -- but we recursively
730+
/// break this variable down into subpaths (e.g., `Drop(x.foo)`)
731+
/// to indicate more precisely which fields might actually be
732+
/// accessed by a destructor.
733+
fn visit_terminator_drop(
734+
&mut self,
735+
loc: Location,
736+
term: &Terminator<'tcx>,
737+
flow_state: &Flows<'cx, 'gcx, 'tcx>,
738+
drop_place: &Place<'tcx>,
739+
erased_drop_place_ty: ty::Ty<'gcx>,
740+
span: Span,
741+
) {
742+
match erased_drop_place_ty.sty {
743+
// When a struct is being dropped, we need to check
744+
// whether it has a destructor, if it does, then we can
745+
// call it, if it does not then we need to check the
746+
// individual fields instead. This way if `foo` has a
747+
// destructor but `bar` does not, we will only check for
748+
// borrows of `x.foo` and not `x.bar`. See #47703.
749+
ty::TyAdt(def, substs) if def.is_struct() && !def.has_dtor(self.tcx) => {
750+
for (index, field) in def.all_fields().enumerate() {
751+
let gcx = self.tcx.global_tcx();
752+
let field_ty = field.ty(gcx, substs);
753+
let field_ty = gcx.normalize_associated_type_in_env(&field_ty, self.param_env);
754+
let place = drop_place.clone().field(Field::new(index), field_ty);
755+
756+
self.visit_terminator_drop(
757+
loc,
758+
term,
759+
flow_state,
760+
&place,
761+
field_ty,
762+
span,
763+
);
764+
}
765+
},
766+
_ => {
767+
// We have now refined the type of the value being
768+
// dropped (potentially) to just the type of a
769+
// subfield; so check whether that field's type still
770+
// "needs drop". If so, we assume that the destructor
771+
// may access any data it likes (i.e., a Deep Write).
772+
let gcx = self.tcx.global_tcx();
773+
if erased_drop_place_ty.needs_drop(gcx, self.param_env) {
774+
self.access_place(
775+
ContextKind::Drop.new(loc),
776+
(drop_place, span),
777+
(Deep, Write(WriteKind::StorageDeadOrDrop)),
778+
LocalMutationIsAllowed::Yes,
779+
flow_state,
780+
);
781+
}
782+
},
783+
}
784+
}
785+
720786
/// Checks an access to the given place to see if it is allowed. Examines the set of borrows
721787
/// that are in scope, as well as which paths have been initialized, to ensure that (a) the
722788
/// place is initialized and (b) it is not borrowed in some way that would prevent this

src/test/run-pass/issue-47703-1.rs

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
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 AtomicRefMut<'a> {
14+
value: &'a mut i32,
15+
borrow: AtomicBorrowRefMut,
16+
}
17+
18+
struct AtomicBorrowRefMut {
19+
}
20+
21+
impl Drop for AtomicBorrowRefMut {
22+
fn drop(&mut self) {
23+
}
24+
}
25+
26+
fn map(orig: AtomicRefMut) -> AtomicRefMut {
27+
AtomicRefMut {
28+
value: orig.value,
29+
borrow: orig.borrow,
30+
}
31+
}
32+
33+
fn main() {}

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

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
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 MyStruct<'a> {
14+
field: &'a mut (),
15+
field2: WithDrop
16+
}
17+
18+
struct WithDrop;
19+
20+
impl Drop for WithDrop {
21+
fn drop(&mut self) {}
22+
}
23+
24+
impl<'a> MyStruct<'a> {
25+
fn consume(self) -> &'a mut () { self.field }
26+
}
27+
28+
fn main() {}

0 commit comments

Comments
 (0)