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:
commit
0191b4983e
@ -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]
|
||||
|
@ -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]
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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>,
|
||||
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
|
26
src/test/compile-fail/regions-escape-method.rs
Normal file
26
src/test/compile-fail/regions-escape-method.rs
Normal 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
|
||||
}
|
Loading…
Reference in New Issue
Block a user