about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/metadata/tydecode.rs13
-rw-r--r--src/librustc/metadata/tyencode.rs4
-rw-r--r--src/librustc/middle/region.rs39
-rw-r--r--src/librustc/util/ppaux.rs5
4 files changed, 54 insertions, 7 deletions
diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs
index 3fb128b1881..8030275ef30 100644
--- a/src/librustc/metadata/tydecode.rs
+++ b/src/librustc/metadata/tydecode.rs
@@ -373,6 +373,16 @@ fn parse_region_<F>(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 7a2df496628..90a905f1840 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 652f6613252..727a1dcdfb3 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<F>(&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 60b422b3769..7358b4cc0f6 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) =>