diff options
| author | Niko Matsakis <niko@alum.mit.edu> | 2014-11-13 21:20:01 -0500 |
|---|---|---|
| committer | Niko Matsakis <niko@alum.mit.edu> | 2014-11-19 06:20:20 -0500 |
| commit | 0b6ec701974096b68e666693b8a750fb6a5d65c6 (patch) | |
| tree | 42239d8fb7370a51d598c7482e767620729afc63 | |
| parent | cf7df1e6382e239619a8447719c3c19787d7b60d (diff) | |
| download | rust-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.rs | 13 | ||||
| -rw-r--r-- | src/librustc/middle/typeck/check/method/mod.rs | 10 | ||||
| -rw-r--r-- | src/librustc/middle/typeck/check/mod.rs | 19 | ||||
| -rw-r--r-- | src/test/compile-fail/regions-escape-method.rs | 26 |
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 +} |
