Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Ensure that the type parameters passed to methods outlive the call ex…
…pression. Fixes #18899.
  • Loading branch information
nikomatsakis committed Nov 19, 2014
1 parent cf7df1e commit 0b6ec70
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 14 deletions.
13 changes: 10 additions & 3 deletions src/librustc/middle/typeck/check/method/confirm.rs
Expand Up @@ -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> {
Expand All @@ -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>>)
Expand All @@ -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,
Expand Down Expand Up @@ -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);
}

///////////////////////////////////////////////////////////////////////////
Expand Down
10 changes: 5 additions & 5 deletions src/librustc/middle/typeck/check/method/mod.rs
Expand Up @@ -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>
{
Expand All @@ -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>,
Expand Down
19 changes: 13 additions & 6 deletions src/librustc/middle/typeck/check/mod.rs
Expand Up @@ -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>,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
});
}

Expand Down
26 changes: 26 additions & 0 deletions 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
}

0 comments on commit 0b6ec70

Please sign in to comment.