Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] avoid to_region_vid ICE during constraint conversion #58839

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/librustc_mir/borrow_check/nll/region_infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
})
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
16 changes: 13 additions & 3 deletions src/librustc_mir/borrow_check/nll/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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((
Expand Down
10 changes: 8 additions & 2 deletions src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
22 changes: 14 additions & 8 deletions src/librustc_mir/borrow_check/nll/universal_regions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<RegionVid, ()> {
self.indices.to_region_vid(r)
}

Expand All @@ -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))
));
});
}
Expand Down Expand Up @@ -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<RegionVid, ()> {
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(())
}
}

Expand All @@ -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)
})))
})
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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`.
Original file line number Diff line number Diff line change
@@ -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

Original file line number Diff line number Diff line change
@@ -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`.
Original file line number Diff line number Diff line change
@@ -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>(B, F);
fn and_then<F, B>(_: F) -> AndThen<B, F> where F: FnOnce() -> B { unimplemented!() }

pub trait Trait { }
impl<B, F> Trait for AndThen<B, F> { }

pub struct JoinAll<I> where I: Iterator { _elem: std::marker::PhantomData<I::Item> }
pub fn join_all<I>(_i: I) -> JoinAll<I> where I: Iterator { unimplemented!() }

pub struct PollFn<F, T>(F, std::marker::PhantomData<fn () -> T>);
pub fn poll_fn<T, F>(_f: F) -> PollFn<F, T> where F: FnMut() -> T { unimplemented!() }

impl<B, I: Iterator, F> Iterator for Map<I, F> where F: FnMut(I::Item) -> B {
type Item = B;
fn next(&mut self) -> Option<B> { unimplemented!() }
}

struct Map<I, F> { iter: I, f: F }

fn main() { let _b: Box<Trait + Send> = 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)
}