Auto merge of #49943 - pnkfelix:fix-issue-49918, r=nikomatsakis
Treat generators as if they have an arbitrary destructor Conservatively assume dropping a generator touches its upvars, via locals' destructors. Fix #49918
This commit is contained in:
commit
d40a0b3dc1
7 changed files with 106 additions and 40 deletions
|
@ -193,14 +193,38 @@ fn dtorck_constraint_for_ty<'a, 'gcx, 'tcx>(
|
||||||
.map(|ty| dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty))
|
.map(|ty| dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty))
|
||||||
.collect(),
|
.collect(),
|
||||||
|
|
||||||
ty::TyGenerator(def_id, substs, _) => {
|
ty::TyGenerator(def_id, substs, _interior) => {
|
||||||
// Note that the interior types are ignored here.
|
// rust-lang/rust#49918: types can be constructed, stored
|
||||||
// Any type reachable inside the interior must also be reachable
|
// in the interior, and sit idle when generator yields
|
||||||
// through the upvars.
|
// (and is subsequently dropped).
|
||||||
substs
|
//
|
||||||
.upvar_tys(def_id, tcx)
|
// It would be nice to descend into interior of a
|
||||||
.map(|ty| dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty))
|
// generator to determine what effects dropping it might
|
||||||
.collect()
|
// have (by looking at any drop effects associated with
|
||||||
|
// its interior).
|
||||||
|
//
|
||||||
|
// However, the interior's representation uses things like
|
||||||
|
// TyGeneratorWitness that explicitly assume they are not
|
||||||
|
// traversed in such a manner. So instead, we will
|
||||||
|
// simplify things for now by treating all generators as
|
||||||
|
// if they were like trait objects, where its upvars must
|
||||||
|
// all be alive for the generator's (potential)
|
||||||
|
// destructor.
|
||||||
|
//
|
||||||
|
// In particular, skipping over `_interior` is safe
|
||||||
|
// because any side-effects from dropping `_interior` can
|
||||||
|
// only take place through references with lifetimes
|
||||||
|
// derived from lifetimes attached to the upvars, and we
|
||||||
|
// *do* incorporate the upvars here.
|
||||||
|
|
||||||
|
let constraint = DtorckConstraint {
|
||||||
|
outlives: substs.upvar_tys(def_id, tcx).map(|t| t.into()).collect(),
|
||||||
|
dtorck_types: vec![],
|
||||||
|
overflows: vec![],
|
||||||
|
};
|
||||||
|
debug!("dtorck_constraint: generator {:?} => {:?}", def_id, constraint);
|
||||||
|
|
||||||
|
Ok(constraint)
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::TyAdt(def, substs) => {
|
ty::TyAdt(def, substs) => {
|
||||||
|
|
|
@ -1,14 +1,30 @@
|
||||||
error: compilation successful
|
error[E0597]: `a` does not live long enough
|
||||||
--> $DIR/borrowing.rs:15:1
|
--> $DIR/borrowing.rs:18:18
|
||||||
|
|
|
|
||||||
LL | / fn main() { #![rustc_error] // rust-lang/rust#49855
|
LL | unsafe { (|| yield &a).resume() }
|
||||||
LL | | let _b = {
|
| ^^^^^^^^^^^^^
|
||||||
LL | | let a = 3;
|
| |
|
||||||
LL | | unsafe { (|| yield &a).resume() }
|
| borrowed value does not live long enough
|
||||||
... |
|
| borrow may end up in a temporary, created here
|
||||||
LL | | };
|
LL | //~^ ERROR: `a` does not live long enough
|
||||||
LL | | }
|
LL | };
|
||||||
| |_^
|
| -- temporary later dropped here, potentially using the reference
|
||||||
|
| |
|
||||||
|
| borrowed value only lives until here
|
||||||
|
|
||||||
error: aborting due to previous error
|
error[E0597]: `a` does not live long enough
|
||||||
|
--> $DIR/borrowing.rs:24:9
|
||||||
|
|
|
||||||
|
LL | / || {
|
||||||
|
LL | | yield &a
|
||||||
|
LL | | //~^ ERROR: `a` does not live long enough
|
||||||
|
LL | | }
|
||||||
|
| |_________^ borrowed value does not live long enough
|
||||||
|
LL | };
|
||||||
|
| - borrowed value only lives until here
|
||||||
|
LL | }
|
||||||
|
| - borrow later used here, when `_b` is dropped
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0597`.
|
||||||
|
|
|
@ -8,11 +8,11 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
#![feature(generators, generator_trait, rustc_attrs)]
|
#![feature(generators, generator_trait)]
|
||||||
|
|
||||||
use std::ops::Generator;
|
use std::ops::Generator;
|
||||||
|
|
||||||
fn main() { #![rustc_error] // rust-lang/rust#49855
|
fn main() {
|
||||||
let _b = {
|
let _b = {
|
||||||
let a = 3;
|
let a = 3;
|
||||||
unsafe { (|| yield &a).resume() }
|
unsafe { (|| yield &a).resume() }
|
||||||
|
|
|
@ -1,14 +1,20 @@
|
||||||
error: compilation successful
|
error[E0597]: `ref_` does not live long enough
|
||||||
--> $DIR/dropck.rs:16:1
|
--> $DIR/dropck.rs:22:11
|
||||||
|
|
|
|
||||||
LL | / fn main() { #![rustc_error] // rust-lang/rust#49855
|
LL | gen = || {
|
||||||
LL | | let (cell, mut gen);
|
| ___________^
|
||||||
LL | | cell = Box::new(RefCell::new(0));
|
LL | | // but the generator can use it to drop a `Ref<'a, i32>`.
|
||||||
LL | | let ref_ = Box::leak(Box::new(Some(cell.borrow_mut())));
|
LL | | let _d = ref_.take(); //~ ERROR `ref_` does not live long enough
|
||||||
... |
|
LL | | yield;
|
||||||
LL | | // drops the RefCell and then the Ref, leading to use-after-free
|
LL | | };
|
||||||
LL | | }
|
| |_____^ borrowed value does not live long enough
|
||||||
| |_^
|
...
|
||||||
|
LL | }
|
||||||
|
| -
|
||||||
|
| |
|
||||||
|
| borrowed value only lives until here
|
||||||
|
| borrow later used here, when `gen` is dropped
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0597`.
|
||||||
|
|
|
@ -8,15 +8,16 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
#![feature(generators, generator_trait, box_leak, rustc_attrs)]
|
#![feature(generators, generator_trait, box_leak)]
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::ops::Generator;
|
use std::ops::Generator;
|
||||||
|
|
||||||
fn main() { #![rustc_error] // rust-lang/rust#49855
|
fn main() {
|
||||||
let (cell, mut gen);
|
let (cell, mut gen);
|
||||||
cell = Box::new(RefCell::new(0));
|
cell = Box::new(RefCell::new(0));
|
||||||
let ref_ = Box::leak(Box::new(Some(cell.borrow_mut())));
|
let ref_ = Box::leak(Box::new(Some(cell.borrow_mut())));
|
||||||
|
//~^ ERROR `*cell` does not live long enough [E0597]
|
||||||
// the upvar is the non-dropck `&mut Option<Ref<'a, i32>>`.
|
// the upvar is the non-dropck `&mut Option<Ref<'a, i32>>`.
|
||||||
gen = || {
|
gen = || {
|
||||||
// but the generator can use it to drop a `Ref<'a, i32>`.
|
// but the generator can use it to drop a `Ref<'a, i32>`.
|
||||||
|
|
|
@ -1,5 +1,16 @@
|
||||||
|
error[E0597]: `*cell` does not live long enough
|
||||||
|
--> $DIR/dropck.rs:19:40
|
||||||
|
|
|
||||||
|
LL | let ref_ = Box::leak(Box::new(Some(cell.borrow_mut())));
|
||||||
|
| ^^^^ borrowed value does not live long enough
|
||||||
|
...
|
||||||
|
LL | }
|
||||||
|
| - `*cell` dropped here while still borrowed
|
||||||
|
|
|
||||||
|
= note: values in a scope are dropped in the opposite order they are created
|
||||||
|
|
||||||
error[E0597]: `ref_` does not live long enough
|
error[E0597]: `ref_` does not live long enough
|
||||||
--> $DIR/dropck.rs:23:18
|
--> $DIR/dropck.rs:24:18
|
||||||
|
|
|
|
||||||
LL | gen = || {
|
LL | gen = || {
|
||||||
| -- capture occurs here
|
| -- capture occurs here
|
||||||
|
@ -12,6 +23,6 @@ LL | }
|
||||||
|
|
|
|
||||||
= note: values in a scope are dropped in the opposite order they are created
|
= note: values in a scope are dropped in the opposite order they are created
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0597`.
|
For more information about this error, try `rustc --explain E0597`.
|
||||||
|
|
|
@ -1,11 +1,19 @@
|
||||||
error[E0597]: `b` does not live long enough
|
error[E0597]: `b` does not live long enough
|
||||||
--> $DIR/ref-escapes-but-not-over-yield.rs:24:13
|
--> $DIR/ref-escapes-but-not-over-yield.rs:24:13
|
||||||
|
|
|
|
||||||
LL | a = &b;
|
LL | let mut b = move || {
|
||||||
| ^^ borrowed value does not live long enough
|
| _________________-
|
||||||
LL | //~^ ERROR `b` does not live long enough
|
LL | | yield();
|
||||||
LL | };
|
LL | | let b = 5;
|
||||||
| - borrowed value only lives until here
|
LL | | a = &b;
|
||||||
|
| | ^^ borrowed value does not live long enough
|
||||||
|
LL | | //~^ ERROR `b` does not live long enough
|
||||||
|
LL | | };
|
||||||
|
| | -
|
||||||
|
| | |
|
||||||
|
| | borrowed value only lives until here
|
||||||
|
| |_____temporary later dropped here, potentially using the reference
|
||||||
|
| borrow may end up in a temporary, created here
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue