]> git.lizzy.rs Git - rust.git/commitdiff
Ensure that the type parameters passed to methods outlive the call expression. Fixes...
authorNiko Matsakis <niko@alum.mit.edu>
Fri, 14 Nov 2014 02:20:01 +0000 (21:20 -0500)
committerNiko Matsakis <niko@alum.mit.edu>
Wed, 19 Nov 2014 11:20:20 +0000 (06:20 -0500)
src/librustc/middle/typeck/check/method/confirm.rs
src/librustc/middle/typeck/check/method/mod.rs
src/librustc/middle/typeck/check/mod.rs
src/test/compile-fail/regions-escape-method.rs [new file with mode: 0644]

index af8ef09d2a072865fae7816f499d68de6a32dde6..c53befcc10d6b76a1541ac3f7f5f1826a5a0abfb 100644 (file)
@@ -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 @@ fn add_obligations(&mut self,
             traits::ObligationCause::misc(self.span),
             method_bounds_substs,
             method_bounds);
+
+        self.fcx.add_default_region_param_bounds(
+            method_bounds_substs,
+            self.call_expr);
     }
 
     ///////////////////////////////////////////////////////////////////////////
index 411948ed6b4acffd44da09d70c5d84dd9d39fac7..0f4152644adafb80b968de958dcf64b25406a4fd 100644 (file)
@@ -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>,
index 543eb44697c06ce5fdaaa5c79293326b1330685c..266b105efc28cdec75fa63564ba5545a64cf08f3 100644 (file)
@@ -2050,6 +2050,17 @@ pub fn register_region_obligation(&self,
         }
     }
 
+    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_method_call(fcx: &FnCtxt,
                                          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 (file)
index 0000000..f92c264
--- /dev/null
@@ -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
+}