diff --git a/src/test/compile-fail/region-borrow-params-issue-29793-big.rs b/src/test/compile-fail/region-borrow-params-issue-29793-big.rs new file mode 100644 index 0000000000000..887f7836ee143 --- /dev/null +++ b/src/test/compile-fail/region-borrow-params-issue-29793-big.rs @@ -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 or the MIT license +// , 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(Option); + +impl WrapA { + fn new() -> WrapA { + WrapA(None) + } + fn set(mut self, f: F) -> Self { + self.0 = Some(f); + self + } +} + +struct WrapB(Option); + +impl WrapB { + fn new() -> WrapB { + WrapB(None) + } + fn set(mut self, f: F) -> Self { + self.0 = Some(f); + self + } +} + +trait DoStuff : Sized { + fn handle(self); +} + +impl DoStuff for WrapA + 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 DoStuff for WrapB where F: FnMut(bool) -> usize { + fn handle(mut self) { + if let Some(ref mut f) = self.0 { + println!("{}", f(true)); + } + } +} + +impl WrapA + 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 +} diff --git a/src/test/compile-fail/region-borrow-params-issue-29793-small.rs b/src/test/compile-fail/region-borrow-params-issue-29793-small.rs new file mode 100644 index 0000000000000..4fda8ec3f384e --- /dev/null +++ b/src/test/compile-fail/region-borrow-params-issue-29793-small.rs @@ -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 or the MIT license +// , 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 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 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 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 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 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 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 usize + 'a>; } + struct S; + impl T for S { + fn g<'a>(&self, x: usize, y:usize) -> Box 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 usize + 'a>; } + struct S; + impl T for S { + fn g<'a>(&self, x: usize, y:usize) -> Box 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 usize + 'a>; } + struct S; + impl T for S { + fn g<'a>(&self, x: usize, y:usize) -> Box 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 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 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 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() { } +