From 0b6ec701974096b68e666693b8a750fb6a5d65c6 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 13 Nov 2014 21:20:01 -0500 Subject: [PATCH 1/2] Ensure that the type parameters passed to methods outlive the call expression. Fixes #18899. --- .../middle/typeck/check/method/confirm.rs | 13 +++++++--- .../middle/typeck/check/method/mod.rs | 10 +++---- src/librustc/middle/typeck/check/mod.rs | 19 +++++++++----- .../compile-fail/regions-escape-method.rs | 26 +++++++++++++++++++ 4 files changed, 54 insertions(+), 14 deletions(-) create mode 100644 src/test/compile-fail/regions-escape-method.rs 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>) @@ -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>, - call_expr_id: ast::NodeId, + call_expr: &ast::Expr, self_expr: &ast::Expr) -> Result, 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 or the MIT license +// , 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(&self, _: |&i32| -> B) { + } +} + +fn main() { + let s = S; + s.f(|p| p) //~ ERROR cannot infer +} From 2477bc4451dc93b9e89c3e1e1621b4333675d94b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 14 Nov 2014 05:55:10 -0500 Subject: [PATCH 2/2] Update libcollections tests to pass the new type rules. They used to return a pointer to the value they were modifying, but this should not have been legal, since that pointer would have to outlive the closure, and the closure continues to modify the value during the execution. This return value was just passed to `black_box` so as to convince llvm that the value was live, so rather than returning a pointer, modify to just call `black_box` directly inside the fn. --- src/libcollections/bit.rs | 28 ++++++++++++++-------------- src/libcollections/slice.rs | 6 +++--- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/libcollections/bit.rs b/src/libcollections/bit.rs index 0529bb8904a..64abc78daf3 100644 --- a/src/libcollections/bit.rs +++ b/src/libcollections/bit.rs @@ -1678,10 +1678,10 @@ impl<'a> Iterator 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] diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 132a07af6b6..5e341ba8b04 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -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 = vec![]; b.iter(|| { vec.push(0); - &vec - }) + black_box(&vec); + }); } #[bench]