diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 3fb128b1881f..8030275ef303 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -373,6 +373,16 @@ fn parse_region_(st: &mut PState, conv: &mut F) -> ty::Region where fn parse_scope(st: &mut PState) -> region::CodeExtent { match next(st) { + 'P' => { + assert_eq!(next(st), '['); + let fn_id = parse_uint(st) as ast::NodeId; + assert_eq!(next(st), '|'); + let body_id = parse_uint(st) as ast::NodeId; + assert_eq!(next(st), ']'); + region::CodeExtent::ParameterScope { + fn_id: fn_id, body_id: body_id + } + } 'M' => { let node_id = parse_uint(st) as ast::NodeId; region::CodeExtent::Misc(node_id) @@ -382,8 +392,11 @@ fn parse_scope(st: &mut PState) -> region::CodeExtent { region::CodeExtent::DestructionScope(node_id) } 'B' => { + assert_eq!(next(st), '['); let node_id = parse_uint(st) as ast::NodeId; + assert_eq!(next(st), '|'); let first_stmt_index = parse_uint(st); + assert_eq!(next(st), ']'); let block_remainder = region::BlockRemainder { block: node_id, first_statement_index: first_stmt_index, }; diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 7a2df4966283..90a905f18407 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -275,9 +275,11 @@ pub fn enc_region(w: &mut Encoder, cx: &ctxt, r: ty::Region) { fn enc_scope(w: &mut Encoder, _cx: &ctxt, scope: region::CodeExtent) { match scope { + region::CodeExtent::ParameterScope { + fn_id, body_id } => mywrite!(w, "P[{}|{}]", fn_id, body_id), region::CodeExtent::Misc(node_id) => mywrite!(w, "M{}", node_id), region::CodeExtent::Remainder(region::BlockRemainder { - block: b, first_statement_index: i }) => mywrite!(w, "B{}{}", b, i), + block: b, first_statement_index: i }) => mywrite!(w, "B[{}|{}]", b, i), region::CodeExtent::DestructionScope(node_id) => mywrite!(w, "D{}", node_id), } } diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 652f66132520..727a1dcdfb31 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -95,7 +95,15 @@ use syntax::visit::{Visitor, FnKind}; RustcDecodable, Debug, Copy)] pub enum CodeExtent { Misc(ast::NodeId), - DestructionScope(ast::NodeId), // extent of destructors for temporaries of node-id + + // extent of parameters passed to a function or closure (they + // outlive its body) + ParameterScope { fn_id: ast::NodeId, body_id: ast::NodeId }, + + // extent of destructors for temporaries of node-id + DestructionScope(ast::NodeId), + + // extent of code following a `let id = expr;` binding in a block Remainder(BlockRemainder) } @@ -153,15 +161,19 @@ impl CodeExtent { pub fn node_id(&self) -> ast::NodeId { match *self { CodeExtent::Misc(node_id) => node_id, + + // These cases all return rough approximations to the + // precise extent denoted by `self`. CodeExtent::Remainder(br) => br.block, CodeExtent::DestructionScope(node_id) => node_id, + CodeExtent::ParameterScope { fn_id: _, body_id } => body_id, } } /// Maps this scope to a potentially new one according to the /// NodeId transformer `f_id`. pub fn map_id(&self, f_id: F) -> CodeExtent where - F: FnOnce(ast::NodeId) -> ast::NodeId, + F: Fn(ast::NodeId) -> ast::NodeId, { match *self { CodeExtent::Misc(node_id) => CodeExtent::Misc(f_id(node_id)), @@ -170,6 +182,8 @@ impl CodeExtent { block: f_id(br.block), first_statement_index: br.first_statement_index }), CodeExtent::DestructionScope(node_id) => CodeExtent::DestructionScope(f_id(node_id)), + CodeExtent::ParameterScope { fn_id, body_id } => + CodeExtent::ParameterScope { fn_id: f_id(fn_id), body_id: f_id(body_id) }, } } @@ -180,6 +194,7 @@ impl CodeExtent { match ast_map.find(self.node_id()) { Some(ast_map::NodeBlock(ref blk)) => { match *self { + CodeExtent::ParameterScope { .. } | CodeExtent::Misc(_) | CodeExtent::DestructionScope(_) => Some(blk.span), @@ -277,6 +292,7 @@ enum InnermostDeclaringBlock { Block(ast::NodeId), Statement(DeclaringStatementContext), Match(ast::NodeId), + FnDecl { fn_id: ast::NodeId, body_id: ast::NodeId }, } impl InnermostDeclaringBlock { @@ -285,6 +301,8 @@ impl InnermostDeclaringBlock { InnermostDeclaringBlock::None => { return Option::None; } + InnermostDeclaringBlock::FnDecl { fn_id, body_id } => + CodeExtent::ParameterScope { fn_id: fn_id, body_id: body_id }, InnermostDeclaringBlock::Block(id) | InnermostDeclaringBlock::Match(id) => CodeExtent::from_node_id(id), InnermostDeclaringBlock::Statement(s) => s.to_code_extent(), @@ -1198,13 +1216,20 @@ fn resolve_fn(visitor: &mut RegionResolutionVisitor, body.id, visitor.cx.parent); + // This scope covers the function body, which includes the + // bindings introduced by let statements as well as temporaries + // created by the fn's tail expression (if any). It does *not* + // include the fn parameters (see below). let body_scope = CodeExtent::from_node_id(body.id); visitor.region_maps.mark_as_terminating_scope(body_scope); let dtor_scope = CodeExtent::DestructionScope(body.id); visitor.region_maps.record_encl_scope(body_scope, dtor_scope); - record_superlifetime(visitor, dtor_scope, body.span); + let fn_decl_scope = CodeExtent::ParameterScope { fn_id: id, body_id: body.id }; + visitor.region_maps.record_encl_scope(dtor_scope, fn_decl_scope); + + record_superlifetime(visitor, fn_decl_scope, body.span); if let Some(root_id) = visitor.cx.root_id { visitor.region_maps.record_fn_parent(body.id, root_id); @@ -1212,11 +1237,13 @@ fn resolve_fn(visitor: &mut RegionResolutionVisitor, let outer_cx = visitor.cx; - // The arguments and `self` are parented to the body of the fn. + // The arguments and `self` are parented to the fn. visitor.cx = Context { root_id: Some(body.id), - parent: InnermostEnclosingExpr::Some(body.id), - var_parent: InnermostDeclaringBlock::Block(body.id) + parent: InnermostEnclosingExpr::None, + var_parent: InnermostDeclaringBlock::FnDecl { + fn_id: id, body_id: body.id + }, }; visit::walk_fn_decl(visitor, decl); diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 60b422b3769d..7358b4cc0f6e 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -113,6 +113,9 @@ pub fn explain_region_and_span(cx: &ctxt, region: ty::Region) }; let scope_decorated_tag = match scope { region::CodeExtent::Misc(_) => tag, + region::CodeExtent::ParameterScope { .. } => { + "scope of parameters for function" + } region::CodeExtent::DestructionScope(_) => { new_string = format!("destruction scope surrounding {}", tag); &*new_string @@ -952,6 +955,8 @@ impl<'tcx> Repr<'tcx> for ty::FreeRegion { impl<'tcx> Repr<'tcx> for region::CodeExtent { fn repr(&self, _tcx: &ctxt) -> String { match *self { + region::CodeExtent::ParameterScope { fn_id, body_id } => + format!("ParameterScope({}, {})", fn_id, body_id), region::CodeExtent::Misc(node_id) => format!("Misc({})", node_id), region::CodeExtent::DestructionScope(node_id) =>