about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2014-11-13 21:20:01 -0500
committerNiko Matsakis <niko@alum.mit.edu>2014-11-19 06:20:20 -0500
commit0b6ec701974096b68e666693b8a750fb6a5d65c6 (patch)
tree42239d8fb7370a51d598c7482e767620729afc63
parentcf7df1e6382e239619a8447719c3c19787d7b60d (diff)
downloadrust-0b6ec701974096b68e666693b8a750fb6a5d65c6.tar.gz
rust-0b6ec701974096b68e666693b8a750fb6a5d65c6.zip
Ensure that the type parameters passed to methods outlive the call expression. Fixes #18899.
-rw-r--r--src/librustc/middle/typeck/check/method/confirm.rs13
-rw-r--r--src/librustc/middle/typeck/check/method/mod.rs10
-rw-r--r--src/librustc/middle/typeck/check/mod.rs19
-rw-r--r--src/test/compile-fail/regions-escape-method.rs26
4 files changed, 54 insertions, 14 deletions
diff --git a/src/librustc/middle/typeck/check/method/confirm.rs b/src/librustc/middle/typeck/check/method/confirm.rs
index af8ef09d2a0..c53befcc10d 100644
--- a/src/librustc/middle/typeck/check/method/confirm.rs
+++ b/src/librustc/middle/typeck/check/method/confirm.rs
@@ -31,6 +31,7 @@ struct ConfirmContext<'a, 'tcx:'a> {
     fcx: &'a FnCtxt<'a, 'tcx>,
     span: Span,
     self_expr: &'a ast::Expr,
+    call_expr: &'a ast::Expr,
 }
 
 struct InstantiatedMethodSig<'tcx> {
@@ -56,6 +57,7 @@ struct InstantiatedMethodSig<'tcx> {
 pub fn confirm<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                          span: Span,
                          self_expr: &ast::Expr,
+                         call_expr: &ast::Expr,
                          unadjusted_self_ty: Ty<'tcx>,
                          pick: probe::Pick<'tcx>,
                          supplied_method_types: Vec<Ty<'tcx>>)
@@ -66,17 +68,18 @@ pub fn confirm<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
            pick.repr(fcx.tcx()),
            supplied_method_types.repr(fcx.tcx()));
 
-    let mut confirm_cx = ConfirmContext::new(fcx, span, self_expr);
+    let mut confirm_cx = ConfirmContext::new(fcx, span, self_expr, call_expr);
     confirm_cx.confirm(unadjusted_self_ty, pick, supplied_method_types)
 }
 
 impl<'a,'tcx> ConfirmContext<'a,'tcx> {
     fn new(fcx: &'a FnCtxt<'a, 'tcx>,
            span: Span,
-           self_expr: &'a ast::Expr)
+           self_expr: &'a ast::Expr,
+           call_expr: &'a ast::Expr)
            -> ConfirmContext<'a, 'tcx>
     {
-        ConfirmContext { fcx: fcx, span: span, self_expr: self_expr }
+        ConfirmContext { fcx: fcx, span: span, self_expr: self_expr, call_expr: call_expr }
     }
 
     fn confirm(&mut self,
@@ -469,6 +472,10 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
             traits::ObligationCause::misc(self.span),
             method_bounds_substs,
             method_bounds);
+
+        self.fcx.add_default_region_param_bounds(
+            method_bounds_substs,
+            self.call_expr);
     }
 
     ///////////////////////////////////////////////////////////////////////////
diff --git a/src/librustc/middle/typeck/check/method/mod.rs b/src/librustc/middle/typeck/check/method/mod.rs
index 411948ed6b4..0f4152644ad 100644
--- a/src/librustc/middle/typeck/check/method/mod.rs
+++ b/src/librustc/middle/typeck/check/method/mod.rs
@@ -79,7 +79,7 @@ pub fn lookup<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                         method_name: ast::Name,
                         self_ty: Ty<'tcx>,
                         supplied_method_types: Vec<Ty<'tcx>>,
-                        call_expr_id: ast::NodeId,
+                        call_expr: &ast::Expr,
                         self_expr: &ast::Expr)
                         -> Result<MethodCallee<'tcx>, MethodError>
 {
@@ -100,14 +100,14 @@ pub fn lookup<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
      * - `self_expr`:             the self expression (`foo`)
      */
 
-    debug!("lookup(method_name={}, self_ty={}, call_expr_id={}, self_expr={})",
+    debug!("lookup(method_name={}, self_ty={}, call_expr={}, self_expr={})",
            method_name.repr(fcx.tcx()),
            self_ty.repr(fcx.tcx()),
-           call_expr_id,
+           call_expr.repr(fcx.tcx()),
            self_expr.repr(fcx.tcx()));
 
-    let pick = try!(probe::probe(fcx, span, method_name, self_ty, call_expr_id));
-    Ok(confirm::confirm(fcx, span, self_expr, self_ty, pick, supplied_method_types))
+    let pick = try!(probe::probe(fcx, span, method_name, self_ty, call_expr.id));
+    Ok(confirm::confirm(fcx, span, self_expr, call_expr, self_ty, pick, supplied_method_types))
 }
 
 pub fn lookup_in_trait<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>,
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index 543eb44697c..266b105efc2 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -2050,6 +2050,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
+    pub fn add_default_region_param_bounds(&self,
+                                           substs: &Substs<'tcx>,
+                                           expr: &ast::Expr)
+    {
+        for &ty in substs.types.iter() {
+            let default_bound = ty::ReScope(expr.id);
+            let origin = infer::RelateDefaultParamBound(expr.span, ty);
+            self.register_region_obligation(origin, ty, default_bound);
+        }
+    }
+
     pub fn add_obligations_for_parameters(&self,
                                           cause: traits::ObligationCause<'tcx>,
                                           substs: &Substs<'tcx>,
@@ -3180,7 +3191,7 @@ fn check_expr_with_unifier<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                          method_name.node.name,
                                          expr_t,
                                          tps,
-                                         expr.id,
+                                         expr,
                                          rcvr) {
             Ok(method) => {
                 let method_ty = method.ty;
@@ -4693,11 +4704,7 @@ fn constrain_path_type_parameters(fcx: &FnCtxt,
                                   expr: &ast::Expr)
 {
     fcx.opt_node_ty_substs(expr.id, |item_substs| {
-        for &ty in item_substs.substs.types.iter() {
-            let default_bound = ty::ReScope(expr.id);
-            let origin = infer::RelateDefaultParamBound(expr.span, ty);
-            fcx.register_region_obligation(origin, ty, default_bound);
-        }
+        fcx.add_default_region_param_bounds(&item_substs.substs, expr);
     });
 }
 
diff --git a/src/test/compile-fail/regions-escape-method.rs b/src/test/compile-fail/regions-escape-method.rs
new file mode 100644
index 00000000000..f92c264784a
--- /dev/null
+++ b/src/test/compile-fail/regions-escape-method.rs
@@ -0,0 +1,26 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test a method call where the parameter `B` would (illegally) be
+// inferred to a region bound in the method argument. If this program
+// were accepted, then the closure passed to `s.f` could escape its
+// argument.
+
+struct S;
+
+impl S {
+    fn f<B>(&self, _: |&i32| -> B) {
+    }
+}
+
+fn main() {
+    let s = S;
+    s.f(|p| p) //~ ERROR cannot infer
+}