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

fix for issues #51351 and #52113 #52620

Merged
merged 1 commit into from
Jul 29, 2018
Merged
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
4 changes: 2 additions & 2 deletions src/librustc_mir/borrow_check/nll/region_infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1155,8 +1155,8 @@ impl<'gcx, 'tcx> ClosureRegionRequirementsExt<'gcx, 'tcx> for ClosureRegionRequi
// Extract the values of the free regions in `user_closure_ty`
// into a vector. These are the regions that we will be
// relating to one another.
let closure_mapping =
&UniversalRegions::closure_mapping(tcx, user_closure_ty, self.num_external_vids);
let closure_mapping = &UniversalRegions::closure_mapping(
tcx, user_closure_ty, self.num_external_vids, tcx.closure_base_def_id(closure_def_id));
debug!("apply_requirements: closure_mapping={:?}", closure_mapping);

// Create the predicates.
Expand Down
77 changes: 77 additions & 0 deletions src/librustc_mir/borrow_check/nll/universal_regions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,13 +270,17 @@ impl<'tcx> UniversalRegions<'tcx> {
tcx: TyCtxt<'_, '_, 'tcx>,
closure_ty: Ty<'tcx>,
expected_num_vars: usize,
closure_base_def_id: DefId,
) -> IndexVec<RegionVid, ty::Region<'tcx>> {
let mut region_mapping = IndexVec::with_capacity(expected_num_vars);
region_mapping.push(tcx.types.re_static);
tcx.for_each_free_region(&closure_ty, |fr| {
region_mapping.push(fr);
});

for_each_late_bound_region_defined_on(
tcx, closure_base_def_id, |r| { region_mapping.push(r); });

assert_eq!(
region_mapping.len(),
expected_num_vars,
Expand Down Expand Up @@ -479,6 +483,20 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> {
let mut indices = self.compute_indices(fr_static, defining_ty);
debug!("build: indices={:?}", indices);

let closure_base_def_id = self.infcx.tcx.closure_base_def_id(self.mir_def_id);

// If this is a closure or generator, then the late-bound regions from the enclosing
// function are actually external regions to us. For example, here, 'a is not local
// to the closure c (although it is local to the fn foo):
// fn foo<'a>() {
// let c = || { let x: &'a u32 = ...; }
// }
if self.mir_def_id != closure_base_def_id {
self.infcx.replace_late_bound_regions_with_nll_infer_vars(
self.mir_def_id,
&mut indices)
}

let bound_inputs_and_output = self.compute_inputs_and_output(&indices, defining_ty);

// "Liberate" the late-bound regions. These correspond to
Expand All @@ -490,6 +508,14 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> {
&bound_inputs_and_output,
&mut indices,
);
// Converse of above, if this is a function then the late-bound regions declared on its
// signature are local to the fn.
if self.mir_def_id == closure_base_def_id {
self.infcx.replace_late_bound_regions_with_nll_infer_vars(
self.mir_def_id,
&mut indices);
}

let fr_fn_body = self.infcx.next_nll_region_var(FR).to_region_vid();
let num_universals = self.infcx.num_region_vars();

Expand Down Expand Up @@ -782,6 +808,13 @@ trait InferCtxtExt<'tcx> {
) -> T
where
T: TypeFoldable<'tcx>;


fn replace_late_bound_regions_with_nll_infer_vars(
&self,
mir_def_id: DefId,
indices: &mut UniversalRegionIndices<'tcx>
);
}

impl<'cx, 'gcx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'gcx, 'tcx> {
Expand Down Expand Up @@ -827,6 +860,28 @@ impl<'cx, 'gcx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'gcx, 'tcx> {
});
value
}

/// Finds late-bound regions that do not appear in the parameter listing and adds them to the
/// indices vector. Typically, we identify late-bound regions as we process the inputs and
/// outputs of the closure/function. However, sometimes there are late-bound regions which do
/// not appear in the fn parameters but which are nonetheless in scope. The simplest case of
/// this are unused functions, like fn foo<'a>() { } (see eg., #51351). Despite not being used,
/// users can still reference these regions (e.g., let x: &'a u32 = &22;), so we need to create
/// entries for them and store them in the indices map. This code iterates over the complete
/// set of late-bound regions and checks for any that we have not yet seen, adding them to the
/// inputs vector.
fn replace_late_bound_regions_with_nll_infer_vars(
&self,
mir_def_id: DefId,
indices: &mut UniversalRegionIndices<'tcx>,
) {
let closure_base_def_id = self.tcx.closure_base_def_id(mir_def_id);
for_each_late_bound_region_defined_on(self.tcx, closure_base_def_id, |r| {
if !indices.indices.contains_key(&r) {
let region_vid = self.next_nll_region_var(FR);
indices.insert_late_bound_region(r, region_vid.to_region_vid());
}});
}
}

impl<'tcx> UniversalRegionIndices<'tcx> {
Expand Down Expand Up @@ -882,3 +937,25 @@ impl<'tcx> FreeRegionRelations<'tcx> for UniversalRegions<'tcx> {
self.outlives(longer, shorter)
}
}

/// Iterates over the late-bound regions defined on fn_def_id and
/// invokes `f` with the liberated form of each one.
fn for_each_late_bound_region_defined_on<'tcx>(
tcx: TyCtxt<'_, '_, 'tcx>,
fn_def_id: DefId,
mut f: impl FnMut(ty::Region<'tcx>)
) {
if let Some(late_bounds) = tcx.is_late_bound_map(fn_def_id.index) {
for late_bound in late_bounds.iter() {
let hir_id = HirId{ owner: fn_def_id.index, local_id: *late_bound };
let region_node_id = tcx.hir.hir_to_node_id(hir_id);
let name = tcx.hir.name(region_node_id).as_interned_str();
let region_def_id = tcx.hir.local_def_id(region_node_id);
let liberated_region = tcx.mk_region(ty::ReFree(ty::FreeRegion {
scope: fn_def_id,
bound_region: ty::BoundRegion::BrNamed(region_def_id, name),
}));
f(liberated_region);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ LL | | });
i16,
for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) u32>))
]
= note: number of external vids: 3
= note: number of external vids: 5
= note: where '_#1r: '_#2r

error[E0623]: lifetime mismatch
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ LL | | });
i16,
for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't2)) u32>))
]
= note: number of external vids: 2
= note: number of external vids: 4
= note: where '_#1r: '_#0r

error: borrowed data escapes outside of function
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ LL | | });
i16,
for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) u32>))
]
= note: number of external vids: 3
= note: number of external vids: 5
= note: where '_#1r: '_#0r

error: borrowed data escapes outside of function
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ LL | | });
i16,
for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>))
]
= note: number of external vids: 3
= note: number of external vids: 5
= note: where '_#1r: '_#2r

error[E0623]: lifetime mismatch
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ LL | | },
i16,
for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>))
]
= note: number of external vids: 3
= note: number of external vids: 4
= note: where '_#1r: '_#2r

note: No external requirements
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ LL | | });
i32,
extern "rust-call" fn((T,))
]
= note: number of external vids: 2
= note: number of external vids: 3
= note: where T: '_#1r

error[E0309]: the parameter type `T` may not live long enough
Expand Down
32 changes: 32 additions & 0 deletions src/test/ui/nll/issue-51351.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
// Regression test for #51351 and #52133: In the case of #51351,
// late-bound regions (like 'a) that were unused within the arguments of
// a function were overlooked and could case an ICE. In the case of #52133,
// LBR defined on the creator function needed to be added to the free regions
// of the closure, as they were not present in the closure's generic
// declarations otherwise.
//
// compile-pass

#![feature(nll)]

fn creash<'a>() {
let x: &'a () = &();
}

fn produce<'a>() {
move || {
let x: &'a () = &();
};
}

fn main() {}
50 changes: 50 additions & 0 deletions src/test/ui/nll/issue-52133.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//

#![allow(warnings)]
#![feature(nll)]

trait Bazinga { }
impl<F> Bazinga for F { }

fn produce1<'a>(data: &'a u32) -> impl Bazinga + 'a {
let x = move || {
let _data: &'a u32 = data;
};
x
}

fn produce2<'a>(data: &'a mut Vec<&'a u32>, value: &'a u32) -> impl Bazinga + 'a {
let x = move || {
let value: &'a u32 = value;
data.push(value);
};
x
}


fn produce3<'a, 'b: 'a>(data: &'a mut Vec<&'a u32>, value: &'b u32) -> impl Bazinga + 'a {
let x = move || {
let value: &'a u32 = value;
data.push(value);
};
x
}

fn produce_err<'a, 'b: 'a>(data: &'b mut Vec<&'b u32>, value: &'a u32) -> impl Bazinga + 'b {
let x = move || { //~ ERROR lifetime mismatch
let value: &'a u32 = value;
data.push(value);
};
x
}

fn main() { }
11 changes: 11 additions & 0 deletions src/test/ui/nll/issue-52133.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error[E0623]: lifetime mismatch
--> $DIR/issue-52133.rs:43:9
|
LL | fn produce_err<'a, 'b: 'a>(data: &'b mut Vec<&'b u32>, value: &'a u32) -> impl Bazinga + 'b {
| -------------------- ------- these two types are declared with different lifetimes...
LL | let x = move || { //~ ERROR lifetime mismatch
| ^ ...but data from `value` flows into `data` here

error: aborting due to previous error

For more information about this error, try `rustc --explain E0623`.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ LL | with_signature(x, |mut y| Box::new(y.next()))
i32,
extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#2r)>
]
= note: number of external vids: 3
= note: number of external vids: 4
= note: where <T as std::iter::Iterator>::Item: '_#2r

error[E0309]: the associated type `<T as std::iter::Iterator>::Item` may not live long enough
Expand Down Expand Up @@ -62,7 +62,7 @@ LL | with_signature(x, |mut y| Box::new(y.next()))
i32,
extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#2r)>
]
= note: number of external vids: 3
= note: number of external vids: 4
= note: where <T as std::iter::Iterator>::Item: '_#2r

note: No external requirements
Expand Down Expand Up @@ -94,7 +94,7 @@ LL | with_signature(x, |mut y| Box::new(y.next()))
i32,
extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#3r)>
]
= note: number of external vids: 4
= note: number of external vids: 5
= note: where <T as std::iter::Iterator>::Item: '_#3r

error[E0309]: the associated type `<T as std::iter::Iterator>::Item` may not live long enough
Expand Down Expand Up @@ -136,7 +136,7 @@ LL | with_signature(x, |mut y| Box::new(y.next()))
i32,
extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#3r)>
]
= note: number of external vids: 4
= note: number of external vids: 5
= note: where <T as std::iter::Iterator>::Item: '_#3r

note: No external requirements
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t));
i32,
extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T))
]
= note: number of external vids: 3
= note: number of external vids: 5
= note: where T: '_#2r
= note: where '_#1r: '_#2r

Expand Down Expand Up @@ -76,7 +76,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t));
i32,
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
]
= note: number of external vids: 4
= note: number of external vids: 5
= note: where T: '_#3r
= note: where '_#2r: '_#3r

Expand Down Expand Up @@ -125,7 +125,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t));
i32,
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
]
= note: number of external vids: 4
= note: number of external vids: 5
= note: where T: '_#3r
= note: where '_#2r: '_#3r

Expand Down Expand Up @@ -174,7 +174,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t));
i32,
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
]
= note: number of external vids: 4
= note: number of external vids: 5
= note: where T: '_#3r
= note: where '_#2r: '_#3r

Expand Down
Loading