diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index 785f810d94159..8488277600f4f 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -366,6 +366,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// (Panics if `r` is not a registered universal region.) pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid { self.universal_regions.to_region_vid(r) + .unwrap_or_else(|_| { + bug!("cannot convert to region_vid: {:?}", r) + }) } /// Adds annotations for `#[rustc_regions]`; see `UniversalRegions::annotate`. diff --git a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs index 1a72205ad7ae1..9e5e5ddda87db 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs @@ -125,6 +125,13 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> { .to_region_vid() } else { self.universal_regions.to_region_vid(r) + .unwrap_or_else(|_| { + // (Generally unsound to approximate with 'static, + // so force eventual ICE via delay_span_bug.) + self.tcx.sess.delay_span_bug( + DUMMY_SP, &format!("cannot convert to region_vid: {:?}", r)); + self.universal_regions.fr_static + }) } } diff --git a/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs b/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs index 3b663ef6dad61..6d7d2a7a8f4df 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs @@ -335,8 +335,14 @@ impl UniversalRegionRelationsBuilder<'cx, 'gcx, 'tcx> { match outlives_bound { OutlivesBound::RegionSubRegion(r1, r2) => { // The bound says that `r1 <= r2`; we store `r2: r1`. - let r1 = self.universal_regions.to_region_vid(r1); - let r2 = self.universal_regions.to_region_vid(r2); + let r1 = self.universal_regions.to_region_vid(r1) + .unwrap_or_else(|_| { + bug!("cannot convert to region_vid r1: {:?}", r1) + }); + let r2 = self.universal_regions.to_region_vid(r2) + .unwrap_or_else(|_| { + bug!("cannot convert to region_vid r2: {:?}", r2) + }); self.relations.relate_universal_regions(r2, r1); } diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs index 4a0b4b7c205c6..a6a05268a6b64 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs @@ -534,7 +534,10 @@ impl LivenessContext<'_, '_, '_, '_, 'tcx> { let borrowck_context = typeck.borrowck_context.as_mut().unwrap(); let live_region_vid = borrowck_context .universal_regions - .to_region_vid(live_region); + .to_region_vid(live_region) + .unwrap_or_else(|_| { + bug!("cannot convert to region_vid live_region: {:?}", live_region) + }); borrowck_context .constraints .liveness_constraints diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 4202d10aa63d0..9a4747b83ae00 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -1471,7 +1471,11 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { if let Some(ref mut borrowck_context) = self.borrowck_context { let region_vid = borrowck_context .universal_regions - .to_region_vid(late_bound_region); + .to_region_vid(late_bound_region) + .unwrap_or_else(|_| { + bug!("cannot convert to region_vid late_bound_region: {:?}", + late_bound_region); + }); borrowck_context .constraints .liveness_constraints @@ -2281,8 +2285,14 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { match k1.unpack() { UnpackedKind::Lifetime(r1) => { // constraint is r1: r2 - let r1_vid = borrowck_context.universal_regions.to_region_vid(r1); - let r2_vid = borrowck_context.universal_regions.to_region_vid(r2); + let r1_vid = borrowck_context.universal_regions.to_region_vid(r1) + .unwrap_or_else(|_| { + bug!("cannot convert to region_vid r1: {:?}", r1); + }); + let r2_vid = borrowck_context.universal_regions.to_region_vid(r2) + .unwrap_or_else(|_| { + bug!("cannot convert to region_vid r2: {:?}", r2); + }); let outlives_requirements = &closure_region_requirements.outlives_requirements[idx]; Some(( diff --git a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs index 28835b959d76f..6781118f755b8 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs @@ -93,8 +93,14 @@ impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, '_, 'tcx> { fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) { if let Some(borrowck_context) = &mut self.borrowck_context { - let sub = borrowck_context.universal_regions.to_region_vid(sub); - let sup = borrowck_context.universal_regions.to_region_vid(sup); + let sub = borrowck_context.universal_regions.to_region_vid(sub) + .unwrap_or_else(|_| { + bug!("cannot convert to region_vid sub: {:?}", sub) + }); + let sup = borrowck_context.universal_regions.to_region_vid(sup) + .unwrap_or_else(|_| { + bug!("cannot convert to region_vid sup: {:?}", sup) + }); borrowck_context .constraints .outlives_constraints diff --git a/src/librustc_mir/borrow_check/nll/universal_regions.rs b/src/librustc_mir/borrow_check/nll/universal_regions.rs index 4d9a3775b3123..6edb6912ccde4 100644 --- a/src/librustc_mir/borrow_check/nll/universal_regions.rs +++ b/src/librustc_mir/borrow_check/nll/universal_regions.rs @@ -298,7 +298,7 @@ impl<'tcx> UniversalRegions<'tcx> { } /// See `UniversalRegionIndices::to_region_vid`. - pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid { + pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> Result { self.indices.to_region_vid(r) } @@ -325,8 +325,10 @@ impl<'tcx> UniversalRegions<'tcx> { let closure_base_def_id = tcx.closure_base_def_id(def_id); for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| { err.note(&format!( - "late-bound region is {:?}", - self.to_region_vid(r), + "late-bound region is {}", + self.to_region_vid(r) + .map(|rv| format!("{:?}", rv)) + .unwrap_or_else(|_| format!("{:?}", r)) )); }); } @@ -736,13 +738,14 @@ impl<'tcx> UniversalRegionIndices<'tcx> { /// reference those regions from the `ParamEnv`. It is also used /// during initialization. Relies on the `indices` map having been /// fully initialized. - pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid { + pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> Result { if let ty::ReVar(..) = r { - r.to_region_vid() + Ok(r.to_region_vid()) } else { - *self.indices + self.indices .get(&r) - .unwrap_or_else(|| bug!("cannot convert `{:?}` to a region vid", r)) + .map(|p|*p) + .ok_or(()) } } @@ -753,7 +756,10 @@ impl<'tcx> UniversalRegionIndices<'tcx> { T: TypeFoldable<'tcx>, { tcx.fold_regions(value, &mut false, |region, _| { - tcx.mk_region(ty::ReVar(self.to_region_vid(region))) + tcx.mk_region(ty::ReVar(self.to_region_vid(region) + .unwrap_or_else(|_| { + bug!("cannot convert {:?} to region_vid", region) + }))) }) } } diff --git a/src/test/ui/issues/issue-57464-avoid-eager-conversion-to-region-vid.ast.stderr b/src/test/ui/issues/issue-57464-avoid-eager-conversion-to-region-vid.ast.stderr new file mode 100644 index 0000000000000..544cebcaadc1f --- /dev/null +++ b/src/test/ui/issues/issue-57464-avoid-eager-conversion-to-region-vid.ast.stderr @@ -0,0 +1,15 @@ +error[E0373]: closure may outlive the current function, but it borrows `local`, which is owned by the current function + --> $DIR/issue-57464-avoid-eager-conversion-to-region-vid.rs:45:13 + | +LL | let m = |_: ()| poll_fn(|| { local; }); + | ^^^^^^^ ----- `local` is borrowed here + | | + | may outlive borrowed value `local` +help: to force the closure to take ownership of `local` (and any other referenced variables), use the `move` keyword + | +LL | let m = move |_: ()| poll_fn(|| { local; }); + | ^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0373`. diff --git a/src/test/ui/issues/issue-57464-avoid-eager-conversion-to-region-vid.mig.stderr b/src/test/ui/issues/issue-57464-avoid-eager-conversion-to-region-vid.mig.stderr new file mode 100644 index 0000000000000..74e25951c2b75 --- /dev/null +++ b/src/test/ui/issues/issue-57464-avoid-eager-conversion-to-region-vid.mig.stderr @@ -0,0 +1,14 @@ +error[E0373]: closure may outlive the current function, but it borrows `local`, which is owned by the current function + --> $DIR/issue-57464-avoid-eager-conversion-to-region-vid.rs:46:13 + | +LL | let m = |_: ()| poll_fn(|| { local; }); + | ^^^^^^^ ----- `local` is borrowed here + | | + | may outlive borrowed value `local` +help: to force the closure to take ownership of `local` (and any other referenced variables), use the `move` keyword + | +LL | let m = move |_: ()| poll_fn(|| { local; }); + | ^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-57464-avoid-eager-conversion-to-region-vid.nll.stderr b/src/test/ui/issues/issue-57464-avoid-eager-conversion-to-region-vid.nll.stderr new file mode 100644 index 0000000000000..9690adbd05f1d --- /dev/null +++ b/src/test/ui/issues/issue-57464-avoid-eager-conversion-to-region-vid.nll.stderr @@ -0,0 +1,21 @@ +error[E0373]: closure may outlive the current function, but it borrows `local`, which is owned by the current function + --> $DIR/issue-57464-avoid-eager-conversion-to-region-vid.rs:45:13 + | +LL | let m = |_: ()| poll_fn(|| { local; }); + | ^^^^^^^ ----- `local` is borrowed here + | | + | may outlive borrowed value `local` + | +note: closure is returned here + --> $DIR/issue-57464-avoid-eager-conversion-to-region-vid.rs:51:5 + | +LL | and_then(f) + | ^^^^^^^^^^^ +help: to force the closure to take ownership of `local` (and any other referenced variables), use the `move` keyword + | +LL | let m = move |_: ()| poll_fn(|| { local; }); + | ^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0373`. diff --git a/src/test/ui/issues/issue-57464-avoid-eager-conversion-to-region-vid.rs b/src/test/ui/issues/issue-57464-avoid-eager-conversion-to-region-vid.rs new file mode 100644 index 0000000000000..c140338e831dd --- /dev/null +++ b/src/test/ui/issues/issue-57464-avoid-eager-conversion-to-region-vid.rs @@ -0,0 +1,52 @@ +// This test managed to tickle a part of the compiler where a region +// representing a static scope (a call-site scope, to be precise) was +// leaking the where clause of a type underlying an `impl Trait`. This +// caused an ICE in spots where we assume that all regions must be +// region_vid's (unique representatives used in NLL) and then +// attempted to eagerly convert the region to its region_vid, which +// does not work for scopes which do not have region_vids (apart from +// the 'static region). +// +// This regression test is just meant to check that we do not ICE, +// regardless of whether NLL is turned on or not. + +// revisions: ast nll +//[ast]compile-flags: -Z borrowck=ast +//[mig]compile-flags: -Z borrowck=migrate -Z two-phase-borrows +//[nll]compile-flags: -Z borrowck=mir -Z two-phase-borrows + +// don't worry about the --compare-mode=nll on this test. +// ignore-compare-mode-nll + +pub struct AndThen(B, F); +fn and_then(_: F) -> AndThen where F: FnOnce() -> B { unimplemented!() } + +pub trait Trait { } +impl Trait for AndThen { } + +pub struct JoinAll where I: Iterator { _elem: std::marker::PhantomData } +pub fn join_all(_i: I) -> JoinAll where I: Iterator { unimplemented!() } + +pub struct PollFn(F, std::marker::PhantomData T>); +pub fn poll_fn(_f: F) -> PollFn where F: FnMut() -> T { unimplemented!() } + +impl Iterator for Map where F: FnMut(I::Item) -> B { + type Item = B; + fn next(&mut self) -> Option { unimplemented!() } +} + +struct Map { iter: I, f: F } + +fn main() { let _b: Box = Box::new(graphql()); } + +fn graphql() -> impl Trait +{ + let local = (); + let m = |_: ()| poll_fn(|| { local; }); + //[ast]~^ ERROR closure may outlive the current function, but it borrows `local` + //[mig]~^^ ERROR closure may outlive the current function, but it borrows `local` + //[nll]~^^^ ERROR closure may outlive the current function, but it borrows `local` + let v = Map { iter: std::iter::once(()), f: m }; + let f = || join_all(v); + and_then(f) +}