-
Notifications
You must be signed in to change notification settings - Fork 12.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
307 additions
and
0 deletions.
There are no files selected for viewing
84 changes: 84 additions & 0 deletions
84
src/test/compile-fail/region-borrow-params-issue-29793-big.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 changes: 223 additions & 0 deletions
223
src/test/compile-fail/region-borrow-params-issue-29793-small.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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() { } | ||
|