Skip to content

Commit 75af9df

Browse files
committed
Auto merge of #52620 - mikhail-m1:51351, r=nikomatsakis
fix simple case of issue #51351 and #52133 r? @nikomatsakis
2 parents 2a9dc24 + bb66d70 commit 75af9df

19 files changed

+218
-48
lines changed

src/librustc_mir/borrow_check/nll/region_infer/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1155,8 +1155,8 @@ impl<'gcx, 'tcx> ClosureRegionRequirementsExt<'gcx, 'tcx> for ClosureRegionRequi
11551155
// Extract the values of the free regions in `user_closure_ty`
11561156
// into a vector. These are the regions that we will be
11571157
// relating to one another.
1158-
let closure_mapping =
1159-
&UniversalRegions::closure_mapping(tcx, user_closure_ty, self.num_external_vids);
1158+
let closure_mapping = &UniversalRegions::closure_mapping(
1159+
tcx, user_closure_ty, self.num_external_vids, tcx.closure_base_def_id(closure_def_id));
11601160
debug!("apply_requirements: closure_mapping={:?}", closure_mapping);
11611161

11621162
// Create the predicates.

src/librustc_mir/borrow_check/nll/universal_regions.rs

+77
Original file line numberDiff line numberDiff line change
@@ -270,13 +270,17 @@ impl<'tcx> UniversalRegions<'tcx> {
270270
tcx: TyCtxt<'_, '_, 'tcx>,
271271
closure_ty: Ty<'tcx>,
272272
expected_num_vars: usize,
273+
closure_base_def_id: DefId,
273274
) -> IndexVec<RegionVid, ty::Region<'tcx>> {
274275
let mut region_mapping = IndexVec::with_capacity(expected_num_vars);
275276
region_mapping.push(tcx.types.re_static);
276277
tcx.for_each_free_region(&closure_ty, |fr| {
277278
region_mapping.push(fr);
278279
});
279280

281+
for_each_late_bound_region_defined_on(
282+
tcx, closure_base_def_id, |r| { region_mapping.push(r); });
283+
280284
assert_eq!(
281285
region_mapping.len(),
282286
expected_num_vars,
@@ -479,6 +483,20 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> {
479483
let mut indices = self.compute_indices(fr_static, defining_ty);
480484
debug!("build: indices={:?}", indices);
481485

486+
let closure_base_def_id = self.infcx.tcx.closure_base_def_id(self.mir_def_id);
487+
488+
// If this is a closure or generator, then the late-bound regions from the enclosing
489+
// function are actually external regions to us. For example, here, 'a is not local
490+
// to the closure c (although it is local to the fn foo):
491+
// fn foo<'a>() {
492+
// let c = || { let x: &'a u32 = ...; }
493+
// }
494+
if self.mir_def_id != closure_base_def_id {
495+
self.infcx.replace_late_bound_regions_with_nll_infer_vars(
496+
self.mir_def_id,
497+
&mut indices)
498+
}
499+
482500
let bound_inputs_and_output = self.compute_inputs_and_output(&indices, defining_ty);
483501

484502
// "Liberate" the late-bound regions. These correspond to
@@ -490,6 +508,14 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> {
490508
&bound_inputs_and_output,
491509
&mut indices,
492510
);
511+
// Converse of above, if this is a function then the late-bound regions declared on its
512+
// signature are local to the fn.
513+
if self.mir_def_id == closure_base_def_id {
514+
self.infcx.replace_late_bound_regions_with_nll_infer_vars(
515+
self.mir_def_id,
516+
&mut indices);
517+
}
518+
493519
let fr_fn_body = self.infcx.next_nll_region_var(FR).to_region_vid();
494520
let num_universals = self.infcx.num_region_vars();
495521

@@ -782,6 +808,13 @@ trait InferCtxtExt<'tcx> {
782808
) -> T
783809
where
784810
T: TypeFoldable<'tcx>;
811+
812+
813+
fn replace_late_bound_regions_with_nll_infer_vars(
814+
&self,
815+
mir_def_id: DefId,
816+
indices: &mut UniversalRegionIndices<'tcx>
817+
);
785818
}
786819

787820
impl<'cx, 'gcx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'gcx, 'tcx> {
@@ -827,6 +860,28 @@ impl<'cx, 'gcx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'gcx, 'tcx> {
827860
});
828861
value
829862
}
863+
864+
/// Finds late-bound regions that do not appear in the parameter listing and adds them to the
865+
/// indices vector. Typically, we identify late-bound regions as we process the inputs and
866+
/// outputs of the closure/function. However, sometimes there are late-bound regions which do
867+
/// not appear in the fn parameters but which are nonetheless in scope. The simplest case of
868+
/// this are unused functions, like fn foo<'a>() { } (see eg., #51351). Despite not being used,
869+
/// users can still reference these regions (e.g., let x: &'a u32 = &22;), so we need to create
870+
/// entries for them and store them in the indices map. This code iterates over the complete
871+
/// set of late-bound regions and checks for any that we have not yet seen, adding them to the
872+
/// inputs vector.
873+
fn replace_late_bound_regions_with_nll_infer_vars(
874+
&self,
875+
mir_def_id: DefId,
876+
indices: &mut UniversalRegionIndices<'tcx>,
877+
) {
878+
let closure_base_def_id = self.tcx.closure_base_def_id(mir_def_id);
879+
for_each_late_bound_region_defined_on(self.tcx, closure_base_def_id, |r| {
880+
if !indices.indices.contains_key(&r) {
881+
let region_vid = self.next_nll_region_var(FR);
882+
indices.insert_late_bound_region(r, region_vid.to_region_vid());
883+
}});
884+
}
830885
}
831886

832887
impl<'tcx> UniversalRegionIndices<'tcx> {
@@ -882,3 +937,25 @@ impl<'tcx> FreeRegionRelations<'tcx> for UniversalRegions<'tcx> {
882937
self.outlives(longer, shorter)
883938
}
884939
}
940+
941+
/// Iterates over the late-bound regions defined on fn_def_id and
942+
/// invokes `f` with the liberated form of each one.
943+
fn for_each_late_bound_region_defined_on<'tcx>(
944+
tcx: TyCtxt<'_, '_, 'tcx>,
945+
fn_def_id: DefId,
946+
mut f: impl FnMut(ty::Region<'tcx>)
947+
) {
948+
if let Some(late_bounds) = tcx.is_late_bound_map(fn_def_id.index) {
949+
for late_bound in late_bounds.iter() {
950+
let hir_id = HirId{ owner: fn_def_id.index, local_id: *late_bound };
951+
let region_node_id = tcx.hir.hir_to_node_id(hir_id);
952+
let name = tcx.hir.name(region_node_id).as_interned_str();
953+
let region_def_id = tcx.hir.local_def_id(region_node_id);
954+
let liberated_region = tcx.mk_region(ty::ReFree(ty::FreeRegion {
955+
scope: fn_def_id,
956+
bound_region: ty::BoundRegion::BrNamed(region_def_id, name),
957+
}));
958+
f(liberated_region);
959+
}
960+
}
961+
}

src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ LL | | });
2020
i16,
2121
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>))
2222
]
23-
= note: number of external vids: 3
23+
= note: number of external vids: 5
2424
= note: where '_#1r: '_#2r
2525

2626
error[E0623]: lifetime mismatch

src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ LL | | });
2020
i16,
2121
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>))
2222
]
23-
= note: number of external vids: 2
23+
= note: number of external vids: 4
2424
= note: where '_#1r: '_#0r
2525

2626
error: borrowed data escapes outside of function

src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ LL | | });
2020
i16,
2121
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>))
2222
]
23-
= note: number of external vids: 3
23+
= note: number of external vids: 5
2424
= note: where '_#1r: '_#0r
2525

2626
error: borrowed data escapes outside of function

src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ LL | | });
2020
i16,
2121
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>))
2222
]
23-
= note: number of external vids: 3
23+
= note: number of external vids: 5
2424
= note: where '_#1r: '_#2r
2525

2626
error[E0623]: lifetime mismatch

src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ LL | | },
1818
i16,
1919
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>))
2020
]
21-
= note: number of external vids: 3
21+
= note: number of external vids: 4
2222
= note: where '_#1r: '_#2r
2323

2424
note: No external requirements

src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ LL | | });
2323
i32,
2424
extern "rust-call" fn((T,))
2525
]
26-
= note: number of external vids: 2
26+
= note: number of external vids: 3
2727
= note: where T: '_#1r
2828

2929
error[E0309]: the parameter type `T` may not live long enough

src/test/ui/nll/issue-51351.rs

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
//
11+
// Regression test for #51351 and #52133: In the case of #51351,
12+
// late-bound regions (like 'a) that were unused within the arguments of
13+
// a function were overlooked and could case an ICE. In the case of #52133,
14+
// LBR defined on the creator function needed to be added to the free regions
15+
// of the closure, as they were not present in the closure's generic
16+
// declarations otherwise.
17+
//
18+
// compile-pass
19+
20+
#![feature(nll)]
21+
22+
fn creash<'a>() {
23+
let x: &'a () = &();
24+
}
25+
26+
fn produce<'a>() {
27+
move || {
28+
let x: &'a () = &();
29+
};
30+
}
31+
32+
fn main() {}

src/test/ui/nll/issue-52133.rs

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
//
11+
12+
#![allow(warnings)]
13+
#![feature(nll)]
14+
15+
trait Bazinga { }
16+
impl<F> Bazinga for F { }
17+
18+
fn produce1<'a>(data: &'a u32) -> impl Bazinga + 'a {
19+
let x = move || {
20+
let _data: &'a u32 = data;
21+
};
22+
x
23+
}
24+
25+
fn produce2<'a>(data: &'a mut Vec<&'a u32>, value: &'a u32) -> impl Bazinga + 'a {
26+
let x = move || {
27+
let value: &'a u32 = value;
28+
data.push(value);
29+
};
30+
x
31+
}
32+
33+
34+
fn produce3<'a, 'b: 'a>(data: &'a mut Vec<&'a u32>, value: &'b u32) -> impl Bazinga + 'a {
35+
let x = move || {
36+
let value: &'a u32 = value;
37+
data.push(value);
38+
};
39+
x
40+
}
41+
42+
fn produce_err<'a, 'b: 'a>(data: &'b mut Vec<&'b u32>, value: &'a u32) -> impl Bazinga + 'b {
43+
let x = move || { //~ ERROR lifetime mismatch
44+
let value: &'a u32 = value;
45+
data.push(value);
46+
};
47+
x
48+
}
49+
50+
fn main() { }

src/test/ui/nll/issue-52133.stderr

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0623]: lifetime mismatch
2+
--> $DIR/issue-52133.rs:43:9
3+
|
4+
LL | fn produce_err<'a, 'b: 'a>(data: &'b mut Vec<&'b u32>, value: &'a u32) -> impl Bazinga + 'b {
5+
| -------------------- ------- these two types are declared with different lifetimes...
6+
LL | let x = move || { //~ ERROR lifetime mismatch
7+
| ^ ...but data from `value` flows into `data` here
8+
9+
error: aborting due to previous error
10+
11+
For more information about this error, try `rustc --explain E0623`.

src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ LL | with_signature(x, |mut y| Box::new(y.next()))
2222
i32,
2323
extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#2r)>
2424
]
25-
= note: number of external vids: 3
25+
= note: number of external vids: 4
2626
= note: where <T as std::iter::Iterator>::Item: '_#2r
2727

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

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

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

142142
note: No external requirements

src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t));
2828
i32,
2929
extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T))
3030
]
31-
= note: number of external vids: 3
31+
= note: number of external vids: 5
3232
= note: where T: '_#2r
3333
= note: where '_#1r: '_#2r
3434

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

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

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

0 commit comments

Comments
 (0)