Skip to content

Commit

Permalink
Auto merge of #30341 - pnkfelix:call-site-scope, r=nikomatsakis
Browse files Browse the repository at this point in the history
Ensure borrows of fn/closure params do not outlive invocations.

Does this by adding a new CallSiteScope to the region (or rather code extent) hierarchy, which outlives even the ParameterScope (which in turn outlives the DestructionScope of a fn/closure's body).

Fix #29793

r? @nikomatsakis
  • Loading branch information
bors committed Dec 16, 2015
2 parents 38da1a4 + 5299441 commit 4af4278
Show file tree
Hide file tree
Showing 18 changed files with 477 additions and 96 deletions.
3 changes: 3 additions & 0 deletions src/librustc/middle/infer/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ impl<'tcx> ty::ctxt<'tcx> {
};
let scope_decorated_tag = match self.region_maps.code_extent_data(scope) {
region::CodeExtentData::Misc(_) => tag,
region::CodeExtentData::CallSiteScope { .. } => {
"scope of call-site for function"
}
region::CodeExtentData::ParameterScope { .. } => {
"scope of parameters for function"
}
Expand Down
5 changes: 3 additions & 2 deletions src/librustc/middle/liveness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1475,10 +1475,11 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
entry_ln: LiveNode,
body: &hir::Block)
{
// within the fn body, late-bound regions are liberated:
// within the fn body, late-bound regions are liberated
// and must outlive the *call-site* of the function.
let fn_ret =
self.ir.tcx.liberate_late_bound_regions(
self.ir.tcx.region_maps.item_extent(body.id),
self.ir.tcx.region_maps.call_site_extent(id, body.id),
&self.fn_ret(id));

match fn_ret {
Expand Down
29 changes: 21 additions & 8 deletions src/librustc/middle/region.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@ pub const DUMMY_CODE_EXTENT : CodeExtent = CodeExtent(1);
pub enum CodeExtentData {
Misc(ast::NodeId),

// extent of the call-site for a function or closure (outlives
// the parameters as well as the body).
CallSiteScope { fn_id: ast::NodeId, body_id: ast::NodeId },

// extent of parameters passed to a function or closure (they
// outlive its body)
ParameterScope { fn_id: ast::NodeId, body_id: ast::NodeId },
Expand All @@ -136,20 +140,20 @@ pub enum CodeExtentData {
Remainder(BlockRemainder)
}

/// extent of destructors for temporaries of node-id
/// extent of call-site for a function/method.
#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, RustcEncodable,
RustcDecodable, Debug, Copy)]
pub struct DestructionScopeData {
pub node_id: ast::NodeId
pub struct CallSiteScopeData {
pub fn_id: ast::NodeId, pub body_id: ast::NodeId,
}

impl DestructionScopeData {
pub fn new(node_id: ast::NodeId) -> DestructionScopeData {
DestructionScopeData { node_id: node_id }
}
impl CallSiteScopeData {
pub fn to_code_extent(&self, region_maps: &RegionMaps) -> CodeExtent {
region_maps.lookup_code_extent(
CodeExtentData::DestructionScope(self.node_id))
match *self {
CallSiteScopeData { fn_id, body_id } =>
CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body_id },
})
}
}

Expand Down Expand Up @@ -190,6 +194,7 @@ impl CodeExtentData {
// precise extent denoted by `self`.
CodeExtentData::Remainder(br) => br.block,
CodeExtentData::DestructionScope(node_id) => node_id,
CodeExtentData::CallSiteScope { fn_id: _, body_id } |
CodeExtentData::ParameterScope { fn_id: _, body_id } => body_id,
}
}
Expand All @@ -215,6 +220,7 @@ impl CodeExtent {
match ast_map.find(self.node_id(region_maps)) {
Some(ast_map::NodeBlock(ref blk)) => {
match region_maps.code_extent_data(*self) {
CodeExtentData::CallSiteScope { .. } |
CodeExtentData::ParameterScope { .. } |
CodeExtentData::Misc(_) |
CodeExtentData::DestructionScope(_) => Some(blk.span),
Expand Down Expand Up @@ -346,6 +352,10 @@ impl RegionMaps {
pub fn item_extent(&self, n: ast::NodeId) -> CodeExtent {
self.lookup_code_extent(CodeExtentData::DestructionScope(n))
}
pub fn call_site_extent(&self, fn_id: ast::NodeId, body_id: ast::NodeId) -> CodeExtent {
assert!(fn_id != body_id);
self.lookup_code_extent(CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body_id })
}
pub fn opt_destruction_extent(&self, n: ast::NodeId) -> Option<CodeExtent> {
self.code_extent_interner.borrow().get(&CodeExtentData::DestructionScope(n)).cloned()
}
Expand Down Expand Up @@ -1101,6 +1111,9 @@ fn resolve_fn(visitor: &mut RegionResolutionVisitor,
body.id,
visitor.cx.parent);

visitor.cx.parent = visitor.new_code_extent(
CodeExtentData::CallSiteScope { fn_id: id, body_id: body.id });

let fn_decl_scope = visitor.new_code_extent(
CodeExtentData::ParameterScope { fn_id: id, body_id: body.id });

Expand Down
61 changes: 30 additions & 31 deletions src/librustc/middle/resolve_lifetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ pub enum DefRegion {
/* lifetime decl */ ast::NodeId),
DefLateBoundRegion(ty::DebruijnIndex,
/* lifetime decl */ ast::NodeId),
DefFreeRegion(/* block scope */ region::DestructionScopeData,
DefFreeRegion(region::CallSiteScopeData,
/* lifetime decl */ ast::NodeId),
}

Expand Down Expand Up @@ -83,9 +83,9 @@ enum ScopeChain<'a> {
/// LateScope(['a, 'b, ...], s) extends s with late-bound
/// lifetimes introduced by the declaration binder_id.
LateScope(&'a Vec<hir::LifetimeDef>, Scope<'a>),
/// lifetimes introduced by items within a code block are scoped
/// to that block.
BlockScope(region::DestructionScopeData, Scope<'a>),

/// lifetimes introduced by a fn are scoped to the call-site for that fn.
FnScope { fn_id: ast::NodeId, body_id: ast::NodeId, s: Scope<'a> },
RootScope
}

Expand Down Expand Up @@ -173,20 +173,20 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
}

fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl,
b: &'v hir::Block, s: Span, _: ast::NodeId) {
b: &'v hir::Block, s: Span, fn_id: ast::NodeId) {
match fk {
FnKind::ItemFn(_, generics, _, _, _, _) => {
self.visit_early_late(subst::FnSpace, generics, |this| {
this.walk_fn(fk, fd, b, s)
this.add_scope_and_walk_fn(fk, fd, b, s, fn_id)
})
}
FnKind::Method(_, sig, _) => {
self.visit_early_late(subst::FnSpace, &sig.generics, |this| {
this.walk_fn(fk, fd, b, s)
this.add_scope_and_walk_fn(fk, fd, b, s, fn_id)
})
}
FnKind::Closure => {
self.walk_fn(fk, fd, b, s)
self.add_scope_and_walk_fn(fk, fd, b, s, fn_id)
}
}
}
Expand Down Expand Up @@ -237,12 +237,6 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
replace(&mut self.labels_in_fn, saved);
}

fn visit_block(&mut self, b: &hir::Block) {
self.with(BlockScope(region::DestructionScopeData::new(b.id),
self.scope),
|_, this| intravisit::walk_block(this, b));
}

fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) {
if lifetime_ref.name == special_idents::static_lifetime.name {
self.insert_lifetime(lifetime_ref, DefStaticRegion);
Expand Down Expand Up @@ -438,7 +432,7 @@ fn extract_labels<'v, 'a>(ctxt: &mut LifetimeContext<'a>, b: &'v hir::Block) {
label_span: Span) {
loop {
match *scope {
BlockScope(_, s) => { scope = s; }
FnScope { s, .. } => { scope = s; }
RootScope => { return; }

EarlyScope(_, lifetimes, s) |
Expand All @@ -462,14 +456,13 @@ fn extract_labels<'v, 'a>(ctxt: &mut LifetimeContext<'a>, b: &'v hir::Block) {
}

impl<'a> LifetimeContext<'a> {
// This is just like intravisit::walk_fn, except that it extracts the
// labels of the function body and swaps them in before visiting
// the function body itself.
fn walk_fn<'b>(&mut self,
fk: FnKind,
fd: &hir::FnDecl,
fb: &'b hir::Block,
_span: Span) {
fn add_scope_and_walk_fn<'b>(&mut self,
fk: FnKind,
fd: &hir::FnDecl,
fb: &'b hir::Block,
_span: Span,
fn_id: ast::NodeId) {

match fk {
FnKind::ItemFn(_, generics, _, _, _, _) => {
intravisit::walk_fn_decl(self, fd);
Expand All @@ -489,7 +482,8 @@ impl<'a> LifetimeContext<'a> {
// `self.labels_in_fn`.
extract_labels(self, fb);

self.visit_block(fb);
self.with(FnScope { fn_id: fn_id, body_id: fb.id, s: self.scope },
|_old_scope, this| this.visit_block(fb))
}

fn with<F>(&mut self, wrap_scope: ScopeChain, f: F) where
Expand Down Expand Up @@ -560,8 +554,11 @@ impl<'a> LifetimeContext<'a> {
let mut scope = self.scope;
loop {
match *scope {
BlockScope(blk_scope, s) => {
return self.resolve_free_lifetime_ref(blk_scope, lifetime_ref, s);
FnScope {fn_id, body_id, s } => {
return self.resolve_free_lifetime_ref(
region::CallSiteScopeData { fn_id: fn_id, body_id: body_id },
lifetime_ref,
s);
}

RootScope => {
Expand Down Expand Up @@ -605,7 +602,7 @@ impl<'a> LifetimeContext<'a> {
}

fn resolve_free_lifetime_ref(&mut self,
scope_data: region::DestructionScopeData,
scope_data: region::CallSiteScopeData,
lifetime_ref: &hir::Lifetime,
scope: Scope) {
debug!("resolve_free_lifetime_ref \
Expand All @@ -623,8 +620,10 @@ impl<'a> LifetimeContext<'a> {
scope_data: {:?} scope: {:?} search_result: {:?}",
scope_data, scope, search_result);
match *scope {
BlockScope(blk_scope_data, s) => {
scope_data = blk_scope_data;
FnScope { fn_id, body_id, s } => {
scope_data = region::CallSiteScopeData {
fn_id: fn_id, body_id: body_id
};
scope = s;
}

Expand Down Expand Up @@ -712,7 +711,7 @@ impl<'a> LifetimeContext<'a> {

loop {
match *old_scope {
BlockScope(_, s) => {
FnScope { s, .. } => {
old_scope = s;
}

Expand Down Expand Up @@ -865,7 +864,7 @@ impl<'a> fmt::Debug for ScopeChain<'a> {
match *self {
EarlyScope(space, defs, _) => write!(fmt, "EarlyScope({:?}, {:?})", space, defs),
LateScope(defs, _) => write!(fmt, "LateScope({:?})", defs),
BlockScope(id, _) => write!(fmt, "BlockScope({:?})", id),
FnScope { fn_id, body_id, s: _ } => write!(fmt, "FnScope({:?}, {:?})", fn_id, body_id),
RootScope => write!(fmt, "RootScope"),
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/middle/traits/object_safety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,8 @@ fn generics_require_sized_self<'tcx>(tcx: &ty::ctxt<'tcx>,
};

// Search for a predicate like `Self : Sized` amongst the trait bounds.
let free_substs = tcx.construct_free_substs(generics, ast::DUMMY_NODE_ID);
let free_substs = tcx.construct_free_substs(generics,
tcx.region_maps.node_extent(ast::DUMMY_NODE_ID));
let predicates = predicates.instantiate(tcx, &free_substs).predicates.into_vec();
elaborate_predicates(tcx, predicates)
.any(|predicate| {
Expand Down
Loading

0 comments on commit 4af4278

Please sign in to comment.