diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 4dd8d245d3bea..5c7061abbb660 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -20,7 +20,7 @@ use rustc::ty::maps::Providers; use rustc::mir::{AssertMessage, BasicBlock, BorrowKind, Location, Place}; use rustc::mir::{Mir, Mutability, Operand, Projection, ProjectionElem, Rvalue}; use rustc::mir::{Field, Statement, StatementKind, Terminator, TerminatorKind}; -use rustc::mir::ClosureRegionRequirements; +use rustc::mir::{ClosureRegionRequirements, Local}; use rustc_data_structures::control_flow_graph::dominators::Dominators; use rustc_data_structures::fx::FxHashSet; @@ -729,6 +729,17 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { erased_drop_place_ty: ty::Ty<'gcx>, span: Span, ) { + let gcx = self.tcx.global_tcx(); + let drop_field = | + mir: &mut MirBorrowckCtxt<'cx, 'gcx, 'tcx>, + (index, field): (usize, ty::Ty<'gcx>), + | { + let field_ty = gcx.normalize_erasing_regions(mir.param_env, field); + let place = drop_place.clone().field(Field::new(index), field_ty); + + mir.visit_terminator_drop(loc, term, flow_state, &place, field_ty, span); + }; + match erased_drop_place_ty.sty { // When a struct is being dropped, we need to check // whether it has a destructor, if it does, then we can @@ -737,14 +748,24 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // destructor but `bar` does not, we will only check for // borrows of `x.foo` and not `x.bar`. See #47703. ty::TyAdt(def, substs) if def.is_struct() && !def.has_dtor(self.tcx) => { - for (index, field) in def.all_fields().enumerate() { - let gcx = self.tcx.global_tcx(); - let field_ty = field.ty(gcx, substs); - let field_ty = gcx.normalize_erasing_regions(self.param_env, field_ty); - let place = drop_place.clone().field(Field::new(index), field_ty); - - self.visit_terminator_drop(loc, term, flow_state, &place, field_ty, span); - } + def.all_fields() + .map(|field| field.ty(gcx, substs)) + .enumerate() + .for_each(|field| drop_field(self, field)); + } + // Same as above, but for tuples. + ty::TyTuple(tys) => { + tys.iter().cloned().enumerate() + .for_each(|field| drop_field(self, field)); + } + // Closures and generators also have disjoint fields, but they are only + // directly accessed in the body of the closure/generator. + ty::TyClosure(def, substs) + | ty::TyGenerator(def, substs, ..) + if *drop_place == Place::Local(Local::new(1)) && !self.mir.upvar_decls.is_empty() + => { + substs.upvar_tys(def, self.tcx).enumerate() + .for_each(|field| drop_field(self, field)); } _ => { // We have now refined the type of the value being @@ -752,7 +773,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // subfield; so check whether that field's type still // "needs drop". If so, we assume that the destructor // may access any data it likes (i.e., a Deep Write). - let gcx = self.tcx.global_tcx(); if erased_drop_place_ty.needs_drop(gcx, self.param_env) { self.access_place( ContextKind::Drop.new(loc), diff --git a/src/test/run-pass/issue-47703-tuple.rs b/src/test/run-pass/issue-47703-tuple.rs new file mode 100644 index 0000000000000..4fec3efc0a089 --- /dev/null +++ b/src/test/run-pass/issue-47703-tuple.rs @@ -0,0 +1,21 @@ +// Copyright 2012 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. + +#![feature(nll)] + +struct WithDrop; + +impl Drop for WithDrop { + fn drop(&mut self) {} +} + +fn consume(x: (&mut (), WithDrop)) -> &mut () { x.0 } + +fn main() {} diff --git a/src/test/run-pass/nll/issue-48623-closure.rs b/src/test/run-pass/nll/issue-48623-closure.rs new file mode 100644 index 0000000000000..08ff54a428e76 --- /dev/null +++ b/src/test/run-pass/nll/issue-48623-closure.rs @@ -0,0 +1,24 @@ +// Copyright 2012 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. + +#![feature(nll)] + +struct WithDrop; + +impl Drop for WithDrop { + fn drop(&mut self) {} +} + +fn reborrow_from_closure(r: &mut ()) -> &mut () { + let d = WithDrop; + (move || { d; &mut *r })() +} + +fn main() {} diff --git a/src/test/run-pass/nll/issue-48623-generator.rs b/src/test/run-pass/nll/issue-48623-generator.rs new file mode 100644 index 0000000000000..524837c4ba91e --- /dev/null +++ b/src/test/run-pass/nll/issue-48623-generator.rs @@ -0,0 +1,25 @@ +// Copyright 2012 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. + +#![feature(nll)] +#![feature(generators, generator_trait)] + +struct WithDrop; + +impl Drop for WithDrop { + fn drop(&mut self) {} +} + +fn reborrow_from_generator(r: &mut ()) { + let d = WithDrop; + move || { d; yield; &mut *r }; +} + +fn main() {} diff --git a/src/test/ui/generator/yield-while-iterating.nll.stderr b/src/test/ui/generator/yield-while-iterating.nll.stderr index be4852aaf06e1..af79eb7ac054f 100644 --- a/src/test/ui/generator/yield-while-iterating.nll.stderr +++ b/src/test/ui/generator/yield-while-iterating.nll.stderr @@ -6,20 +6,6 @@ LL | for p in &x { //~ ERROR LL | yield(); | ------- possible yield occurs here -error[E0597]: borrowed value does not live long enough - --> $DIR/yield-while-iterating.rs:50:17 - | -LL | let mut b = || { - | _________________^ -LL | | for p in &mut x { -LL | | yield p; -LL | | } -LL | | }; - | | ^ - | | | - | |_____temporary value only lives until here - | temporary value does not live long enough - error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable --> $DIR/yield-while-iterating.rs:67:20 | @@ -35,21 +21,7 @@ LL | println!("{}", x[0]); //~ ERROR LL | b.resume(); | - borrow later used here -error[E0597]: borrowed value does not live long enough - --> $DIR/yield-while-iterating.rs:62:17 - | -LL | let mut b = || { - | _________________^ -LL | | for p in &mut x { -LL | | yield p; -LL | | } -LL | | }; - | | ^ - | | | - | |_____temporary value only lives until here - | temporary value does not live long enough - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors -Some errors occurred: E0502, E0597, E0626. +Some errors occurred: E0502, E0626. For more information about an error, try `rustc --explain E0502`.