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

Ensure borrows of fn/closure params do not outlive invocations #30341

Merged
merged 2 commits into from
Dec 17, 2015
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
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 @@ -1466,10 +1466,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 @@ -172,20 +172,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 @@ -236,12 +236,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 @@ -437,7 +431,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 @@ -461,14 +455,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 @@ -488,7 +481,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 @@ -559,8 +553,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 @@ -604,7 +601,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 @@ -622,8 +619,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 @@ -711,7 +710,7 @@ impl<'a> LifetimeContext<'a> {

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

Expand Down Expand Up @@ -864,7 +863,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