Change:
Code shows a case where doesn't stay borrowed for long enough allowing it to be mutated while a reference to it exists. I think treating generators as if they implement would fix this, but I'm not sure if this will end up causing incorrect errors in other places.

Discussion:
.map(|ty| dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty)) .collect(), <del> ty::TyGenerator(def_id, substs, _) => { // Note that the interior types are ignored here. // Any type reachable inside the interior must also be reachable // through the upvars. substs .upvar_tys(def_id, tcx) .map(|ty| dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty)) .collect() </del> <ins> ty::TyGenerator(def_id, substs, _interior) => { // rust-lang/rust#49918: types can be constructed, stored // in the interior, and sit idle when generator yields // (and is subsequently dropped). // // It would be nice to descend into interior of a // generator to determine what effects dropping it might // 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) </ins> } ty::TyAdt(def, substs) => {

<del> error: compilation successful --> $DIR/borrowing.rs:15:1 </del> <ins> error[E0597]: `a` does not live long enough --> $DIR/borrowing.rs:18:18 </ins> | <del> LL | / fn main() { #![rustc_error] // rust-lang/rust#49855 LL | |     let _b = { LL | |         let a = 3; LL | |         unsafe { (|| yield &a).resume() } ...  | LL | |     }; LL | | } | |_^ </del> <ins> LL |         unsafe { (|| yield &a).resume() } |                  ^^^^^^^^^^^^^ |                  | |                  borrowed value does not live long enough |                  borrow may end up in a temporary, created here LL |         //~^ ERROR: `a` does not live long enough LL |     }; |     -- temporary later dropped here, potentially using the reference |     | |     borrowed value only lives until here </ins> <del> error: aborting due to previous error </del> <ins> 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`. </ins>

// option. This file may not be copied, modified, or distributed // except according to those terms. <del> #![feature(generators, generator_trait, rustc_attrs)] </del> <ins> #![feature(generators, generator_trait)] </ins> use std::ops::Generator; <del> fn main() { #![rustc_error] // rust-lang/rust#49855 </del> <ins> fn main() { </ins> let _b = { let a = 3; unsafe { (|| yield &a).resume() }

<del> error: compilation successful --> $DIR/dropck.rs:16:1 </del> <ins> error[E0597]: `ref_` does not live long enough --> $DIR/dropck.rs:22:11 </ins> | <del> LL | / fn main() { #![rustc_error] // rust-lang/rust#49855 LL | |     let (cell, mut gen); LL | |     cell = Box::new(RefCell::new(0)); LL | |     let ref_ = Box::leak(Box::new(Some(cell.borrow_mut()))); ...  | LL | |     // drops the RefCell and then the Ref, leading to use-after-free LL | | } | |_^ </del> <ins> LL |       gen = || { |  ___________^ LL | |         // but the generator can use it to drop a `Ref<'a, i32>`. LL | |         let _d = ref_.take(); //~ ERROR `ref_` does not live long enough LL | |         yield; LL | |     }; | |_____^ borrowed value does not live long enough ... LL |   } |   - |   | |   borrowed value only lives until here |   borrow later used here, when `gen` is dropped </ins> error: aborting due to previous error <ins> For more information about this error, try `rustc --explain E0597`. </ins>

// option. This file may not be copied, modified, or distributed // except according to those terms. <del> #![feature(generators, generator_trait, box_leak, rustc_attrs)] </del> <ins> #![feature(generators, generator_trait, box_leak)] </ins> use std::cell::RefCell; use std::ops::Generator; <del> fn main() { #![rustc_error] // rust-lang/rust#49855 </del> <ins> fn main() { </ins> let (cell, mut gen); cell = Box::new(RefCell::new(0)); let ref_ = Box::leak(Box::new(Some(cell.borrow_mut()))); <ins> //~^ ERROR `*cell` does not live long enough [E0597] </ins> // the upvar is the non-dropck `&mut Option<Ref<'a, i32>>`. gen = || { // but the generator can use it to drop a `Ref<'a, i32>`.

<ins> 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 </ins> error[E0597]: `ref_` does not live long enough <del> --> $DIR/dropck.rs:23:18 </del> <ins> --> $DIR/dropck.rs:24:18 </ins> | LL |     gen = || { |           -- capture occurs here

| = note: values in a scope are dropped in the opposite order they are created <del> error: aborting due to previous error </del> <ins> error: aborting due to 2 previous errors </ins> For more information about this error, try `rustc --explain E0597`.

error[E0597]: `b` does not live long enough --> $DIR/ref-escapes-but-not-over-yield.rs:24:13 | <del> 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 </del> <ins> LL |       let mut b = move || { |  _________________- LL | |         yield(); LL | |         let b = 5; 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 </ins> error: aborting due to previous error