Regression tests for Issue 29793.
This commit is contained in:
parent
c00574848b
commit
5299441954
@ -0,0 +1,84 @@
|
||||
// Copyright 2015 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.
|
||||
|
||||
// Issue #29793, big regression test: do not let borrows of
|
||||
// parameters to ever be returned (expanded with exploration of
|
||||
// variations).
|
||||
//
|
||||
// This is the version of the test that actually exposed unsound
|
||||
// behavior (because the improperly accepted closure was actually
|
||||
// able to be invoked).
|
||||
|
||||
struct WrapA<F>(Option<F>);
|
||||
|
||||
impl<F> WrapA<F> {
|
||||
fn new() -> WrapA<F> {
|
||||
WrapA(None)
|
||||
}
|
||||
fn set(mut self, f: F) -> Self {
|
||||
self.0 = Some(f);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
struct WrapB<F>(Option<F>);
|
||||
|
||||
impl<F> WrapB<F> {
|
||||
fn new() -> WrapB<F> {
|
||||
WrapB(None)
|
||||
}
|
||||
fn set(mut self, f: F) -> Self {
|
||||
self.0 = Some(f);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
trait DoStuff : Sized {
|
||||
fn handle(self);
|
||||
}
|
||||
|
||||
impl<F, T> DoStuff for WrapA<F>
|
||||
where F: FnMut(usize, usize) -> T, T: DoStuff {
|
||||
fn handle(mut self) {
|
||||
if let Some(ref mut f) = self.0 {
|
||||
let x = f(1, 2);
|
||||
let _foo = [0usize; 16];
|
||||
x.handle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> DoStuff for WrapB<F> where F: FnMut(bool) -> usize {
|
||||
fn handle(mut self) {
|
||||
if let Some(ref mut f) = self.0 {
|
||||
println!("{}", f(true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, T> WrapA<F>
|
||||
where F: FnMut(usize, usize) -> T, T: DoStuff {
|
||||
fn handle_ref(&mut self) {
|
||||
if let Some(ref mut f) = self.0 {
|
||||
let x = f(1, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut w = WrapA::new().set(|x: usize, y: usize| {
|
||||
WrapB::new().set(|t: bool| if t { x } else { y }) // (separate errors for `x` vs `y`)
|
||||
//~^ ERROR `x` does not live long enough
|
||||
//~| ERROR `y` does not live long enough
|
||||
});
|
||||
|
||||
w.handle(); // This works
|
||||
// w.handle_ref(); // This doesn't
|
||||
}
|
223
src/test/compile-fail/region-borrow-params-issue-29793-small.rs
Normal file
223
src/test/compile-fail/region-borrow-params-issue-29793-small.rs
Normal file
@ -0,0 +1,223 @@
|
||||
// Copyright 2015 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.
|
||||
|
||||
// Issue #29793, small regression tests: do not let borrows of
|
||||
// parameters to ever be returned (expanded with exploration of
|
||||
// variations).
|
||||
|
||||
// CLOSURES
|
||||
|
||||
fn escaping_borrow_of_closure_params_1() {
|
||||
let g = |x: usize, y:usize| {
|
||||
let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`)
|
||||
//~^ ERROR `x` does not live long enough
|
||||
//~| ERROR `y` does not live long enough
|
||||
return f;
|
||||
};
|
||||
|
||||
// We delberately do not call `g`; this small version of the test,
|
||||
// after adding such a call, was (properly) rejected even when the
|
||||
// system still suffered from issue #29793.
|
||||
|
||||
// g(10, 20)(true);
|
||||
}
|
||||
|
||||
fn escaping_borrow_of_closure_params_2() {
|
||||
let g = |x: usize, y:usize| {
|
||||
let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`)
|
||||
//~^ ERROR `x` does not live long enough
|
||||
//~| ERROR `y` does not live long enough
|
||||
f
|
||||
};
|
||||
|
||||
// (we don't call `g`; see above)
|
||||
}
|
||||
|
||||
fn move_of_closure_params() {
|
||||
let g = |x: usize, y:usize| {
|
||||
let f = move |t: bool| if t { x } else { y };
|
||||
f;
|
||||
};
|
||||
// (this code is fine, so lets go ahead and ensure rustc accepts call of `g`)
|
||||
(g(1,2));
|
||||
}
|
||||
|
||||
fn ok_borrow_of_fn_params(a: usize, b:usize) {
|
||||
let g = |x: usize, y:usize| {
|
||||
let f = |t: bool| if t { a } else { b };
|
||||
return f;
|
||||
};
|
||||
// (this code is fine, so lets go ahead and ensure rustc accepts call of `g`)
|
||||
(g(1,2))(true);
|
||||
}
|
||||
|
||||
// TOP-LEVEL FN'S
|
||||
|
||||
fn escaping_borrow_of_fn_params_1() {
|
||||
fn g<'a>(x: usize, y:usize) -> Box<Fn(bool) -> usize + 'a> {
|
||||
let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`)
|
||||
//~^ ERROR E0373
|
||||
//~| ERROR E0373
|
||||
return Box::new(f);
|
||||
};
|
||||
|
||||
// (we don't call `g`; see above)
|
||||
}
|
||||
|
||||
fn escaping_borrow_of_fn_params_2() {
|
||||
fn g<'a>(x: usize, y:usize) -> Box<Fn(bool) -> usize + 'a> {
|
||||
let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`)
|
||||
//~^ ERROR E0373
|
||||
//~| ERROR E0373
|
||||
Box::new(f)
|
||||
};
|
||||
|
||||
// (we don't call `g`; see above)
|
||||
}
|
||||
|
||||
fn move_of_fn_params() {
|
||||
fn g<'a>(x: usize, y:usize) -> Box<Fn(bool) -> usize + 'a> {
|
||||
let f = move |t: bool| if t { x } else { y };
|
||||
return Box::new(f);
|
||||
};
|
||||
// (this code is fine, so lets go ahead and ensure rustc accepts call of `g`)
|
||||
(g(1,2))(true);
|
||||
}
|
||||
|
||||
// INHERENT METHODS
|
||||
|
||||
fn escaping_borrow_of_method_params_1() {
|
||||
struct S;
|
||||
impl S {
|
||||
fn g<'a>(&self, x: usize, y:usize) -> Box<Fn(bool) -> usize + 'a> {
|
||||
let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`)
|
||||
//~^ ERROR E0373
|
||||
//~| ERROR E0373
|
||||
return Box::new(f);
|
||||
}
|
||||
}
|
||||
|
||||
// (we don't call `g`; see above)
|
||||
}
|
||||
|
||||
fn escaping_borrow_of_method_params_2() {
|
||||
struct S;
|
||||
impl S {
|
||||
fn g<'a>(&self, x: usize, y:usize) -> Box<Fn(bool) -> usize + 'a> {
|
||||
let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`)
|
||||
//~^ ERROR E0373
|
||||
//~| ERROR E0373
|
||||
Box::new(f)
|
||||
}
|
||||
}
|
||||
// (we don't call `g`; see above)
|
||||
}
|
||||
|
||||
fn move_of_method_params() {
|
||||
struct S;
|
||||
impl S {
|
||||
fn g<'a>(&self, x: usize, y:usize) -> Box<Fn(bool) -> usize + 'a> {
|
||||
let f = move |t: bool| if t { x } else { y };
|
||||
return Box::new(f);
|
||||
}
|
||||
}
|
||||
// (this code is fine, so lets go ahead and ensure rustc accepts call of `g`)
|
||||
(S.g(1,2))(true);
|
||||
}
|
||||
|
||||
// TRAIT IMPL METHODS
|
||||
|
||||
fn escaping_borrow_of_trait_impl_params_1() {
|
||||
trait T { fn g<'a>(&self, x: usize, y:usize) -> Box<Fn(bool) -> usize + 'a>; }
|
||||
struct S;
|
||||
impl T for S {
|
||||
fn g<'a>(&self, x: usize, y:usize) -> Box<Fn(bool) -> usize + 'a> {
|
||||
let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`)
|
||||
//~^ ERROR E0373
|
||||
//~| ERROR E0373
|
||||
return Box::new(f);
|
||||
}
|
||||
}
|
||||
|
||||
// (we don't call `g`; see above)
|
||||
}
|
||||
|
||||
fn escaping_borrow_of_trait_impl_params_2() {
|
||||
trait T { fn g<'a>(&self, x: usize, y:usize) -> Box<Fn(bool) -> usize + 'a>; }
|
||||
struct S;
|
||||
impl T for S {
|
||||
fn g<'a>(&self, x: usize, y:usize) -> Box<Fn(bool) -> usize + 'a> {
|
||||
let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`)
|
||||
//~^ ERROR E0373
|
||||
//~| ERROR E0373
|
||||
Box::new(f)
|
||||
}
|
||||
}
|
||||
// (we don't call `g`; see above)
|
||||
}
|
||||
|
||||
fn move_of_trait_impl_params() {
|
||||
trait T { fn g<'a>(&self, x: usize, y:usize) -> Box<Fn(bool) -> usize + 'a>; }
|
||||
struct S;
|
||||
impl T for S {
|
||||
fn g<'a>(&self, x: usize, y:usize) -> Box<Fn(bool) -> usize + 'a> {
|
||||
let f = move |t: bool| if t { x } else { y };
|
||||
return Box::new(f);
|
||||
}
|
||||
}
|
||||
// (this code is fine, so lets go ahead and ensure rustc accepts call of `g`)
|
||||
(S.g(1,2))(true);
|
||||
}
|
||||
|
||||
// TRAIT DEFAULT METHODS
|
||||
|
||||
fn escaping_borrow_of_trait_default_params_1() {
|
||||
struct S;
|
||||
trait T {
|
||||
fn g<'a>(&self, x: usize, y:usize) -> Box<Fn(bool) -> usize + 'a> {
|
||||
let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`)
|
||||
//~^ ERROR E0373
|
||||
//~| ERROR E0373
|
||||
return Box::new(f);
|
||||
}
|
||||
}
|
||||
impl T for S {}
|
||||
// (we don't call `g`; see above)
|
||||
}
|
||||
|
||||
fn escaping_borrow_of_trait_default_params_2() {
|
||||
struct S;
|
||||
trait T {
|
||||
fn g<'a>(&self, x: usize, y:usize) -> Box<Fn(bool) -> usize + 'a> {
|
||||
let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`)
|
||||
//~^ ERROR E0373
|
||||
//~| ERROR E0373
|
||||
Box::new(f)
|
||||
}
|
||||
}
|
||||
impl T for S {}
|
||||
// (we don't call `g`; see above)
|
||||
}
|
||||
|
||||
fn move_of_trait_default_params() {
|
||||
struct S;
|
||||
trait T {
|
||||
fn g<'a>(&self, x: usize, y:usize) -> Box<Fn(bool) -> usize + 'a> {
|
||||
let f = move |t: bool| if t { x } else { y };
|
||||
return Box::new(f);
|
||||
}
|
||||
}
|
||||
impl T for S {}
|
||||
// (this code is fine, so lets go ahead and ensure rustc accepts call of `g`)
|
||||
(S.g(1,2))(true);
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
|
Loading…
x
Reference in New Issue
Block a user