Skip to content

Commit dbae169

Browse files
committed
rustc_typeck: do not leak late-bound lifetimes from bounds to closures.
1 parent 74c6788 commit dbae169

File tree

3 files changed

+61
-4
lines changed

3 files changed

+61
-4
lines changed

src/librustc/middle/region.rs

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,14 @@ impl CodeExtentData {
198198

199199
/// The region maps encode information about region relationships.
200200
pub struct RegionMaps<'tcx> {
201+
/// If not empty, this body is the root of this region hierarchy.
202+
root_body: Option<hir::BodyId>,
203+
204+
/// The parent of the root body owner, if the latter is an
205+
/// an associated const or method, as impls/traits can also
206+
/// have lifetime parameters free in this body.
207+
root_parent: Option<ast::NodeId>,
208+
201209
/// `scope_map` maps from a scope id to the enclosing scope id;
202210
/// this is usually corresponding to the lexical nesting, though
203211
/// in the case of closures the parent scope is the innermost
@@ -295,6 +303,8 @@ struct RegionResolutionVisitor<'a, 'tcx: 'a> {
295303
impl<'tcx> RegionMaps<'tcx> {
296304
pub fn new() -> Self {
297305
RegionMaps {
306+
root_body: None,
307+
root_parent: None,
298308
scope_map: FxHashMap(),
299309
destruction_scopes: FxHashMap(),
300310
var_map: NodeMap(),
@@ -600,8 +610,39 @@ impl<'tcx> RegionMaps<'tcx> {
600610
/// returns the outermost `CodeExtent` that the region outlives.
601611
pub fn free_extent<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, fr: &ty::FreeRegion)
602612
-> CodeExtent<'tcx> {
603-
let scope_id = tcx.hir.as_local_node_id(fr.scope).unwrap();
604-
tcx.call_site_extent(scope_id)
613+
let param_owner = match fr.bound_region {
614+
ty::BoundRegion::BrNamed(def_id, _) => {
615+
tcx.parent_def_id(def_id).unwrap()
616+
}
617+
_ => fr.scope
618+
};
619+
620+
let param_owner_id = tcx.hir.as_local_node_id(param_owner).unwrap();
621+
let body_id = tcx.hir.maybe_body_owned_by(param_owner_id)
622+
.map(|body| {
623+
assert_eq!(param_owner, fr.scope);
624+
body
625+
})
626+
.unwrap_or_else(|| {
627+
let root = tcx.hir.as_local_node_id(fr.scope).unwrap();
628+
629+
assert_eq!(Some(param_owner_id), self.root_parent,
630+
"free_extent: {:?} not recognized by the region maps for {:?}",
631+
param_owner, fr.scope);
632+
633+
let root_body = tcx.hir.body_owned_by(root);
634+
635+
assert!(Some(root_body) == self.root_body,
636+
"free_extent: {:?} not inside {:?}",
637+
param_owner, self.root_body.map(|body| tcx.hir.body_owner_def_id(body)));
638+
639+
root_body
640+
});
641+
642+
tcx.intern_code_extent(CodeExtentData::CallSiteScope {
643+
fn_id: tcx.hir.body_owner(body_id),
644+
body_id: body_id.node_id
645+
})
605646
}
606647
}
607648

@@ -1167,6 +1208,19 @@ fn region_maps<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
11671208

11681209
let id = tcx.hir.as_local_node_id(def_id).unwrap();
11691210
if let Some(body) = tcx.hir.maybe_body_owned_by(id) {
1211+
maps.root_body = Some(body);
1212+
1213+
// If the item is an associated const or a method,
1214+
// record its impl/trait parent, as it can also have
1215+
// lifetime parameters free in this body.
1216+
match tcx.hir.get(id) {
1217+
hir::map::NodeImplItem(_) |
1218+
hir::map::NodeTraitItem(_) => {
1219+
maps.root_parent = Some(tcx.hir.get_parent(id));
1220+
}
1221+
_ => {}
1222+
}
1223+
11701224
let mut visitor = RegionResolutionVisitor {
11711225
tcx: tcx,
11721226
region_maps: &mut maps,

src/librustc/ty/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2386,11 +2386,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
23862386
/// free parameters. Since we currently represent bound/free type
23872387
/// parameters in the same way, this only has an effect on regions.
23882388
pub fn construct_free_substs(self, def_id: DefId) -> &'gcx Substs<'gcx> {
2389-
2389+
let scope = self.closure_base_def_id(def_id);
23902390
let substs = Substs::for_item(self.global_tcx(), def_id, |def, _| {
23912391
// map bound 'a => free 'a
23922392
self.global_tcx().mk_region(ReFree(FreeRegion {
2393-
scope: def_id,
2393+
scope,
23942394
bound_region: def.to_bound_region()
23952395
}))
23962396
}, |def, _| {

src/librustc_typeck/check/closure.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
6060
decl,
6161
Abi::RustCall,
6262
expected_sig);
63+
// `deduce_expectations_from_expected_type` introduces late-bound
64+
// lifetimes defined elsewhere, which we need to anonymize away.
65+
let sig = self.tcx.anonymize_late_bound_regions(&sig);
6366

6467
// Create type variables (for now) to represent the transformed
6568
// types of upvars. These will be unified during the upvar

0 commit comments

Comments
 (0)