rollup merge of #18940: nikomatsakis/issue-18899

Ensure that the type parameters passed to methods outlive the call expression.

Fixes #18899.

This is yet another case of forgotten to consistently enforce the constraints in every instance where they apply. Might be nice to try and refactor to make this whole thing more DRY, but for now here's a targeted fix.

r? @pcwalton
This commit is contained in:
Jakub Bukaj 2014-11-19 22:37:11 +01:00
commit 0191b4983e
6 changed files with 71 additions and 31 deletions

View File

@ -1678,10 +1678,10 @@ impl<'a> Iterator<uint> for TwoBitPositions<'a> {
mod tests {
use std::prelude::*;
use std::iter::range_step;
use std::u32;
use std::rand;
use std::rand::Rng;
use test::Bencher;
use std::u32;
use test::{Bencher, black_box};
use super::{Bitv, BitvSet, from_fn, from_bytes};
use bitv;
@ -2676,8 +2676,8 @@ mod tests {
for _ in range(0u, 100) {
bitv |= 1 << ((r.next_u32() as uint) % u32::BITS);
}
&bitv
})
black_box(&bitv)
});
}
#[bench]
@ -2688,8 +2688,8 @@ mod tests {
for _ in range(0u, 100) {
bitv.set((r.next_u32() as uint) % BENCH_BITS, true);
}
&bitv
})
black_box(&bitv)
});
}
#[bench]
@ -2700,8 +2700,8 @@ mod tests {
for _ in range(0u, 100) {
bitv.set((r.next_u32() as uint) % BENCH_BITS, r.gen());
}
&bitv
})
black_box(&bitv);
});
}
#[bench]
@ -2712,8 +2712,8 @@ mod tests {
for _ in range(0u, 100) {
bitv.set((r.next_u32() as uint) % u32::BITS, true);
}
&bitv
})
black_box(&bitv);
});
}
#[bench]
@ -2724,8 +2724,8 @@ mod tests {
for _ in range(0u, 100) {
bitv.insert((r.next_u32() as uint) % u32::BITS);
}
&bitv
})
black_box(&bitv);
});
}
#[bench]
@ -2736,8 +2736,8 @@ mod tests {
for _ in range(0u, 100) {
bitv.insert((r.next_u32() as uint) % BENCH_BITS);
}
&bitv
})
black_box(&bitv);
});
}
#[bench]

View File

@ -2084,7 +2084,7 @@ mod bench {
use std::rand::{weak_rng, Rng};
use std::mem;
use std::ptr;
use test::Bencher;
use test::{Bencher, black_box};
use vec::Vec;
@ -2140,8 +2140,8 @@ mod bench {
let mut vec: Vec<uint> = vec![];
b.iter(|| {
vec.push(0);
&vec
})
black_box(&vec);
});
}
#[bench]

View 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 @@ 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);
}
///////////////////////////////////////////////////////////////////////////

View 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>,

View File

@ -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);
});
}

View File

@ -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
}