From dbae169ac16de632d21fd3394bc8a939b2524512 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 10 May 2017 16:59:41 +0300 Subject: [PATCH] rustc_typeck: do not leak late-bound lifetimes from bounds to closures. --- src/librustc/middle/region.rs | 58 +++++++++++++++++++++++++++- src/librustc/ty/mod.rs | 4 +- src/librustc_typeck/check/closure.rs | 3 ++ 3 files changed, 61 insertions(+), 4 deletions(-) diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 3f707ac95f7..c6565b78f61 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -198,6 +198,14 @@ pub fn span(&self, hir_map: &hir_map::Map) -> Option { /// The region maps encode information about region relationships. pub struct RegionMaps<'tcx> { + /// If not empty, this body is the root of this region hierarchy. + root_body: Option, + + /// The parent of the root body owner, if the latter is an + /// an associated const or method, as impls/traits can also + /// have lifetime parameters free in this body. + root_parent: Option, + /// `scope_map` maps from a scope id to the enclosing scope id; /// this is usually corresponding to the lexical nesting, though /// in the case of closures the parent scope is the innermost @@ -295,6 +303,8 @@ struct RegionResolutionVisitor<'a, 'tcx: 'a> { impl<'tcx> RegionMaps<'tcx> { pub fn new() -> Self { RegionMaps { + root_body: None, + root_parent: None, scope_map: FxHashMap(), destruction_scopes: FxHashMap(), var_map: NodeMap(), @@ -600,8 +610,39 @@ fn ancestors_of<'a, 'tcx>(scope_map: &FxHashMap, CodeExtent<'tc /// returns the outermost `CodeExtent` that the region outlives. pub fn free_extent<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, fr: &ty::FreeRegion) -> CodeExtent<'tcx> { - let scope_id = tcx.hir.as_local_node_id(fr.scope).unwrap(); - tcx.call_site_extent(scope_id) + let param_owner = match fr.bound_region { + ty::BoundRegion::BrNamed(def_id, _) => { + tcx.parent_def_id(def_id).unwrap() + } + _ => fr.scope + }; + + let param_owner_id = tcx.hir.as_local_node_id(param_owner).unwrap(); + let body_id = tcx.hir.maybe_body_owned_by(param_owner_id) + .map(|body| { + assert_eq!(param_owner, fr.scope); + body + }) + .unwrap_or_else(|| { + let root = tcx.hir.as_local_node_id(fr.scope).unwrap(); + + assert_eq!(Some(param_owner_id), self.root_parent, + "free_extent: {:?} not recognized by the region maps for {:?}", + param_owner, fr.scope); + + let root_body = tcx.hir.body_owned_by(root); + + assert!(Some(root_body) == self.root_body, + "free_extent: {:?} not inside {:?}", + param_owner, self.root_body.map(|body| tcx.hir.body_owner_def_id(body))); + + root_body + }); + + tcx.intern_code_extent(CodeExtentData::CallSiteScope { + fn_id: tcx.hir.body_owner(body_id), + body_id: body_id.node_id + }) } } @@ -1167,6 +1208,19 @@ fn region_maps<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) let id = tcx.hir.as_local_node_id(def_id).unwrap(); if let Some(body) = tcx.hir.maybe_body_owned_by(id) { + maps.root_body = Some(body); + + // If the item is an associated const or a method, + // record its impl/trait parent, as it can also have + // lifetime parameters free in this body. + match tcx.hir.get(id) { + hir::map::NodeImplItem(_) | + hir::map::NodeTraitItem(_) => { + maps.root_parent = Some(tcx.hir.get_parent(id)); + } + _ => {} + } + let mut visitor = RegionResolutionVisitor { tcx: tcx, region_maps: &mut maps, diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 99ee4e41d1d..8ccaf0622d7 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2386,11 +2386,11 @@ pub fn empty_parameter_environment(self) -> ParameterEnvironment<'tcx> { /// free parameters. Since we currently represent bound/free type /// parameters in the same way, this only has an effect on regions. pub fn construct_free_substs(self, def_id: DefId) -> &'gcx Substs<'gcx> { - + let scope = self.closure_base_def_id(def_id); let substs = Substs::for_item(self.global_tcx(), def_id, |def, _| { // map bound 'a => free 'a self.global_tcx().mk_region(ReFree(FreeRegion { - scope: def_id, + scope, bound_region: def.to_bound_region() })) }, |def, _| { diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 9eca2b96d62..9e4a7ed1ddc 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -60,6 +60,9 @@ fn check_closure(&self, decl, Abi::RustCall, expected_sig); + // `deduce_expectations_from_expected_type` introduces late-bound + // lifetimes defined elsewhere, which we need to anonymize away. + let sig = self.tcx.anonymize_late_bound_regions(&sig); // Create type variables (for now) to represent the transformed // types of upvars. These will be unified during the upvar -- 2.44.0