diff options
Diffstat (limited to 'src/test/ui/regions')
314 files changed, 8254 insertions, 0 deletions
diff --git a/src/test/ui/regions/auxiliary/rbmtp_cross_crate_lib.rs b/src/test/ui/regions/auxiliary/rbmtp_cross_crate_lib.rs new file mode 100644 index 000000000..ce2a3a7db --- /dev/null +++ b/src/test/ui/regions/auxiliary/rbmtp_cross_crate_lib.rs @@ -0,0 +1,32 @@ +// Check that method bounds declared on traits/impls in a cross-crate +// scenario work. This is the library portion of the test. + +pub enum MaybeOwned<'a> { + Owned(isize), + Borrowed(&'a isize) +} + +pub struct Inv<'a> { // invariant w/r/t 'a + x: &'a mut &'a isize +} + +// I encountered a bug at some point with encoding the IntoMaybeOwned +// trait, so I'll use that as the template for this test. +pub trait IntoMaybeOwned<'a> { + fn into_maybe_owned(self) -> MaybeOwned<'a>; + + // Note: without this `into_inv` method, the trait is + // contravariant w/r/t `'a`, since if you look strictly at the + // interface, it only returns `'a`. This complicates the + // downstream test since it wants invariance to force an error. + // Hence we add this method. + fn into_inv(self) -> Inv<'a>; + + fn bigger_region<'b:'a>(self, b: Inv<'b>); +} + +impl<'a> IntoMaybeOwned<'a> for Inv<'a> { + fn into_maybe_owned(self) -> MaybeOwned<'a> { panic!() } + fn into_inv(self) -> Inv<'a> { panic!() } + fn bigger_region<'b:'a>(self, b: Inv<'b>) { panic!() } +} diff --git a/src/test/ui/regions/closure-in-projection-issue-97405.rs b/src/test/ui/regions/closure-in-projection-issue-97405.rs new file mode 100644 index 000000000..e567d5c27 --- /dev/null +++ b/src/test/ui/regions/closure-in-projection-issue-97405.rs @@ -0,0 +1,32 @@ +// Regression test for #97405. +// In `good_generic_fn` the param `T` ends up in the substs of closures/generators, +// but we should be able to prove `<Gen<T> as Iterator>::Item: 'static` without +// requiring `T: 'static` + +// edition:2018 +// check-fail + +fn opaque<F>(_: F) -> impl Iterator { b"".iter() } + +fn assert_static<T: 'static>(_: T) {} + +fn good_generic_fn<T>() { + // Previously, proving `<OpaqueTy<type_of(async {})> as Iterator>::Item: 'static` + // used to require `T: 'static`. + assert_static(opaque(async {}).next()); + assert_static(opaque(|| {}).next()); + assert_static(opaque(opaque(async {}).next()).next()); +} + + +// This should fail because `T` ends up in the upvars of the closure. +fn bad_generic_fn<T: Copy>(t: T) { + assert_static(opaque(async move { t; }).next()); + //~^ ERROR the associated type `<impl Iterator as Iterator>::Item` may not live long enough + assert_static(opaque(move || { t; }).next()); + //~^ ERROR the associated type `<impl Iterator as Iterator>::Item` may not live long enough + assert_static(opaque(opaque(async move { t; }).next()).next()); + //~^ ERROR the associated type `<impl Iterator as Iterator>::Item` may not live long enough +} + +fn main() {} diff --git a/src/test/ui/regions/closure-in-projection-issue-97405.stderr b/src/test/ui/regions/closure-in-projection-issue-97405.stderr new file mode 100644 index 000000000..c08f1059e --- /dev/null +++ b/src/test/ui/regions/closure-in-projection-issue-97405.stderr @@ -0,0 +1,30 @@ +error[E0310]: the associated type `<impl Iterator as Iterator>::Item` may not live long enough + --> $DIR/closure-in-projection-issue-97405.rs:24:5 + | +LL | assert_static(opaque(async move { t; }).next()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `<impl Iterator as Iterator>::Item: 'static`... + = note: ...so that the type `<impl Iterator as Iterator>::Item` will meet its required lifetime bounds + +error[E0310]: the associated type `<impl Iterator as Iterator>::Item` may not live long enough + --> $DIR/closure-in-projection-issue-97405.rs:26:5 + | +LL | assert_static(opaque(move || { t; }).next()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `<impl Iterator as Iterator>::Item: 'static`... + = note: ...so that the type `<impl Iterator as Iterator>::Item` will meet its required lifetime bounds + +error[E0310]: the associated type `<impl Iterator as Iterator>::Item` may not live long enough + --> $DIR/closure-in-projection-issue-97405.rs:28:5 + | +LL | assert_static(opaque(opaque(async move { t; }).next()).next()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `<impl Iterator as Iterator>::Item: 'static`... + = note: ...so that the type `<impl Iterator as Iterator>::Item` will meet its required lifetime bounds + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0310`. diff --git a/src/test/ui/regions/forall-wf-ref-reflexive.rs b/src/test/ui/regions/forall-wf-ref-reflexive.rs new file mode 100644 index 000000000..9c37d72d5 --- /dev/null +++ b/src/test/ui/regions/forall-wf-ref-reflexive.rs @@ -0,0 +1,18 @@ +// Test that we consider `for<'a> &'a T: 'a` to be sufficient to prove +// that `for<'a> &'a T: 'a`. +// +// FIXME. Except we don't! + +#![allow(warnings)] + +fn self_wf2<T>() +where + for<'a> &'a T: 'a, +{ + self_wf2::<T>(); + //~^ ERROR `T` does not live long enough + // + // FIXME. This ought to be accepted, presumably. +} + +fn main() {} diff --git a/src/test/ui/regions/forall-wf-ref-reflexive.stderr b/src/test/ui/regions/forall-wf-ref-reflexive.stderr new file mode 100644 index 000000000..3d059ccec --- /dev/null +++ b/src/test/ui/regions/forall-wf-ref-reflexive.stderr @@ -0,0 +1,8 @@ +error: `T` does not live long enough + --> $DIR/forall-wf-ref-reflexive.rs:12:5 + | +LL | self_wf2::<T>(); + | ^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/regions/forall-wf-reflexive.rs b/src/test/ui/regions/forall-wf-reflexive.rs new file mode 100644 index 000000000..8e6b8224b --- /dev/null +++ b/src/test/ui/regions/forall-wf-reflexive.rs @@ -0,0 +1,15 @@ +// Test that we consider `for<'a> T: 'a` to be sufficient to prove +// that `for<'a> T: 'a`. +// +// check-pass + +#![allow(warnings)] + +fn self_wf1<T>() +where + for<'a> T: 'a, +{ + self_wf1::<T>(); +} + +fn main() {} diff --git a/src/test/ui/regions/init-res-into-things.rs b/src/test/ui/regions/init-res-into-things.rs new file mode 100644 index 000000000..7f416262d --- /dev/null +++ b/src/test/ui/regions/init-res-into-things.rs @@ -0,0 +1,81 @@ +// run-pass + +#![allow(non_camel_case_types)] +#![allow(dead_code)] + +use std::cell::Cell; + +// Resources can't be copied, but storing into data structures counts +// as a move unless the stored thing is used afterwards. + +struct r<'a> { + i: &'a Cell<isize>, +} + +struct BoxR<'a> { x: r<'a> } + +impl<'a> Drop for r<'a> { + fn drop(&mut self) { + self.i.set(self.i.get() + 1) + } +} + +fn r(i: &Cell<isize>) -> r { + r { + i: i + } +} + +fn test_rec() { + let i = &Cell::new(0); + { + let _a = BoxR {x: r(i)}; + } + assert_eq!(i.get(), 1); +} + +fn test_tag() { + enum t<'a> { + t0(r<'a>), + } + + let i = &Cell::new(0); + { + let _a = t::t0(r(i)); + } + assert_eq!(i.get(), 1); +} + +fn test_tup() { + let i = &Cell::new(0); + { + let _a = (r(i), 0); + } + assert_eq!(i.get(), 1); +} + +fn test_unique() { + let i = &Cell::new(0); + { + let _a: Box<_> = Box::new(r(i)); + } + assert_eq!(i.get(), 1); +} + +fn test_unique_rec() { + let i = &Cell::new(0); + { + let _a: Box<_> = Box::new(BoxR { + x: r(i) + }); + } + assert_eq!(i.get(), 1); +} + +pub fn main() { + test_rec(); + test_tag(); + test_tup(); + test_unique(); + test_unique_rec(); +} diff --git a/src/test/ui/regions/issue-12470.rs b/src/test/ui/regions/issue-12470.rs new file mode 100644 index 000000000..d8f2abb0c --- /dev/null +++ b/src/test/ui/regions/issue-12470.rs @@ -0,0 +1,34 @@ +trait X { + fn get_i(&self) -> isize; +} + + + + +struct B { + i: isize +} + +impl X for B { + fn get_i(&self) -> isize { + self.i + } +} + +struct A<'a> { + p: &'a (dyn X + 'a) +} + +fn make_a<'a>(p: &'a dyn X) -> A<'a> { + A { p: p } +} + +fn make_make_a<'a>() -> A<'a> { + let b: Box<B> = Box::new(B { i: 1 }); + let bb: &B = &*b; + make_a(bb) //~ ERROR cannot return value referencing local data `*b` +} + +fn main() { + let _a = make_make_a(); +} diff --git a/src/test/ui/regions/issue-12470.stderr b/src/test/ui/regions/issue-12470.stderr new file mode 100644 index 000000000..c97e59195 --- /dev/null +++ b/src/test/ui/regions/issue-12470.stderr @@ -0,0 +1,11 @@ +error[E0515]: cannot return value referencing local data `*b` + --> $DIR/issue-12470.rs:29:5 + | +LL | let bb: &B = &*b; + | --- `*b` is borrowed here +LL | make_a(bb) + | ^^^^^^^^^^ returns a value referencing data owned by the current function + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/regions/issue-21520.rs b/src/test/ui/regions/issue-21520.rs new file mode 100644 index 000000000..ab4ac7237 --- /dev/null +++ b/src/test/ui/regions/issue-21520.rs @@ -0,0 +1,22 @@ +// check-pass +#![allow(dead_code)] +// Test that the requirement (in `Bar`) that `T::Bar : 'static` does +// not wind up propagating to `T`. + +// pretty-expanded FIXME #23616 + +pub trait Foo { + type Bar; + + fn foo(&self) -> Self; +} + +pub struct Static<T:'static>(T); + +struct Bar<T:Foo> + where T::Bar : 'static +{ + x: Static<Option<T::Bar>> +} + +fn main() { } diff --git a/src/test/ui/regions/issue-24085.rs b/src/test/ui/regions/issue-24085.rs new file mode 100644 index 000000000..86e94beb7 --- /dev/null +++ b/src/test/ui/regions/issue-24085.rs @@ -0,0 +1,19 @@ +// check-pass +#![allow(dead_code)] +// Regression test for #24085. Errors were occurring in region +// inference due to the requirement that `'a:b'`, which was getting +// incorrectly codegened in connection with the closure below. + +#[derive(Copy,Clone)] +struct Path<'a:'b, 'b> { + x: &'a i32, + tail: Option<&'b Path<'a, 'b>> +} + +#[allow(dead_code, unconditional_recursion)] +fn foo<'a,'b,F>(p: Path<'a, 'b>, mut f: F) + where F: for<'c> FnMut(Path<'a, 'c>) { + foo(p, |x| f(x)) +} + +fn main() { } diff --git a/src/test/ui/regions/issue-26448-1.rs b/src/test/ui/regions/issue-26448-1.rs new file mode 100644 index 000000000..7d2d75bf2 --- /dev/null +++ b/src/test/ui/regions/issue-26448-1.rs @@ -0,0 +1,13 @@ +// run-pass + +pub trait Foo<T> { + fn foo(self) -> T; +} + +impl<'a, T> Foo<T> for &'a str where &'a str: Into<T> { + fn foo(self) -> T { + panic!(); + } +} + +fn main() {} diff --git a/src/test/ui/regions/issue-26448-2.rs b/src/test/ui/regions/issue-26448-2.rs new file mode 100644 index 000000000..c60e06c3c --- /dev/null +++ b/src/test/ui/regions/issue-26448-2.rs @@ -0,0 +1,21 @@ +// check-pass + +pub struct Bar<T> { + items: Vec<&'static str>, + inner: T, +} + +pub trait IntoBar<T> { + fn into_bar(self) -> Bar<T>; +} + +impl<'a, T> IntoBar<T> for &'a str where &'a str: Into<T> { + fn into_bar(self) -> Bar<T> { + Bar { + items: Vec::new(), + inner: self.into(), + } + } +} + +fn main() {} diff --git a/src/test/ui/regions/issue-26448-3.rs b/src/test/ui/regions/issue-26448-3.rs new file mode 100644 index 000000000..d48022c09 --- /dev/null +++ b/src/test/ui/regions/issue-26448-3.rs @@ -0,0 +1,25 @@ +// check-pass + +pub struct Item { + _inner: &'static str, +} + +pub struct Bar<T> { + items: Vec<Item>, + inner: T, +} + +pub trait IntoBar<T> { + fn into_bar(self) -> Bar<T>; +} + +impl<'a, T> IntoBar<T> for &'a str where &'a str: Into<T> { + fn into_bar(self) -> Bar<T> { + Bar { + items: Vec::new(), + inner: self.into(), + } + } +} + +fn main() {} diff --git a/src/test/ui/regions/issue-2718.rs b/src/test/ui/regions/issue-2718.rs new file mode 100644 index 000000000..6449337ee --- /dev/null +++ b/src/test/ui/regions/issue-2718.rs @@ -0,0 +1,327 @@ +// run-pass +#![allow(dead_code)] +#![allow(unused_unsafe)] +#![allow(unused_imports)] +#![allow(non_camel_case_types)] + +pub type Task = isize; + +// tjc: I don't know why +pub mod pipes { + use self::state::{empty, full, blocked, terminated}; + use super::Task; + use std::mem::{forget, transmute}; + use std::mem::{replace, swap}; + use std::mem; + use std::thread; + use std::marker::Send; + + pub struct Stuff<T> { + state: state, + blocked_task: Option<Task>, + payload: Option<T> + } + + #[derive(PartialEq, Debug)] + #[repr(isize)] + pub enum state { + empty, + full, + blocked, + terminated + } + + pub struct packet<T> { + state: state, + blocked_task: Option<Task>, + payload: Option<T> + } + + unsafe impl<T:Send> Send for packet<T> {} + + pub fn packet<T:Send>() -> *const packet<T> { + unsafe { + let p: *const packet<T> = mem::transmute(Box::new(Stuff{ + state: empty, + blocked_task: None::<Task>, + payload: None::<T> + })); + p + } + } + + mod rusti { + pub fn atomic_xchg(_dst: &mut isize, _src: isize) -> isize { panic!(); } + pub fn atomic_xchg_acq(_dst: &mut isize, _src: isize) -> isize { panic!(); } + pub fn atomic_xchg_rel(_dst: &mut isize, _src: isize) -> isize { panic!(); } + } + + // We should consider moving this to ::std::unsafe, although I + // suspect graydon would want us to use void pointers instead. + pub unsafe fn uniquify<T>(x: *const T) -> Box<T> { + mem::transmute(x) + } + + pub fn swap_state_acq(dst: &mut state, src: state) -> state { + unsafe { + transmute(rusti::atomic_xchg_acq(transmute(dst), src as isize)) + } + } + + pub fn swap_state_rel(dst: &mut state, src: state) -> state { + unsafe { + transmute(rusti::atomic_xchg_rel(transmute(dst), src as isize)) + } + } + + pub fn send<T:Send>(mut p: send_packet<T>, payload: T) { + let p = p.unwrap(); + let mut p = unsafe { uniquify(p) }; + assert!((*p).payload.is_none()); + (*p).payload = Some(payload); + let old_state = swap_state_rel(&mut (*p).state, full); + match old_state { + empty => { + // Yay, fastpath. + + // The receiver will eventually clean this up. + unsafe { forget(p); } + } + full => { panic!("duplicate send") } + blocked => { + + // The receiver will eventually clean this up. + unsafe { forget(p); } + } + terminated => { + // The receiver will never receive this. Rely on drop_glue + // to clean everything up. + } + } + } + + pub fn recv<T:Send>(mut p: recv_packet<T>) -> Option<T> { + let p = p.unwrap(); + let mut p = unsafe { uniquify(p) }; + loop { + let old_state = swap_state_acq(&mut (*p).state, + blocked); + match old_state { + empty | blocked => { thread::yield_now(); } + full => { + let payload = replace(&mut p.payload, None); + return Some(payload.unwrap()) + } + terminated => { + assert_eq!(old_state, terminated); + return None; + } + } + } + } + + pub fn sender_terminate<T:Send>(p: *const packet<T>) { + let mut p = unsafe { uniquify(p) }; + match swap_state_rel(&mut (*p).state, terminated) { + empty | blocked => { + // The receiver will eventually clean up. + unsafe { forget(p) } + } + full => { + // This is impossible + panic!("you dun goofed") + } + terminated => { + // I have to clean up, use drop_glue + } + } + } + + pub fn receiver_terminate<T:Send>(p: *const packet<T>) { + let mut p = unsafe { uniquify(p) }; + match swap_state_rel(&mut (*p).state, terminated) { + empty => { + // the sender will clean up + unsafe { forget(p) } + } + blocked => { + // this shouldn't happen. + panic!("terminating a blocked packet") + } + terminated | full => { + // I have to clean up, use drop_glue + } + } + } + + pub struct send_packet<T:Send> { + p: Option<*const packet<T>>, + } + + impl<T:Send> Drop for send_packet<T> { + fn drop(&mut self) { + unsafe { + if self.p != None { + let self_p: &mut Option<*const packet<T>> = + mem::transmute(&mut self.p); + let p = replace(self_p, None); + sender_terminate(p.unwrap()) + } + } + } + } + + impl<T:Send> send_packet<T> { + pub fn unwrap(&mut self) -> *const packet<T> { + replace(&mut self.p, None).unwrap() + } + } + + pub fn send_packet<T:Send>(p: *const packet<T>) -> send_packet<T> { + send_packet { + p: Some(p) + } + } + + pub struct recv_packet<T:Send> { + p: Option<*const packet<T>>, + } + + impl<T:Send> Drop for recv_packet<T> { + fn drop(&mut self) { + unsafe { + if self.p != None { + let self_p: &mut Option<*const packet<T>> = + mem::transmute(&mut self.p); + let p = replace(self_p, None); + receiver_terminate(p.unwrap()) + } + } + } + } + + impl<T:Send> recv_packet<T> { + pub fn unwrap(&mut self) -> *const packet<T> { + replace(&mut self.p, None).unwrap() + } + } + + pub fn recv_packet<T:Send>(p: *const packet<T>) -> recv_packet<T> { + recv_packet { + p: Some(p) + } + } + + pub fn entangle<T:Send>() -> (send_packet<T>, recv_packet<T>) { + let p = packet(); + (send_packet(p), recv_packet(p)) + } +} + +pub mod pingpong { + use std::mem; + + pub struct ping(::pipes::send_packet<pong>); + + unsafe impl Send for ping {} + + pub struct pong(::pipes::send_packet<ping>); + + unsafe impl Send for pong {} + + pub fn liberate_ping(p: ping) -> ::pipes::send_packet<pong> { + unsafe { + let _addr : *const ::pipes::send_packet<pong> = match &p { + &ping(ref x) => { mem::transmute(x) } + }; + panic!() + } + } + + pub fn liberate_pong(p: pong) -> ::pipes::send_packet<ping> { + unsafe { + let _addr : *const ::pipes::send_packet<ping> = match &p { + &pong(ref x) => { mem::transmute(x) } + }; + panic!() + } + } + + pub fn init() -> (client::ping, server::ping) { + ::pipes::entangle() + } + + pub mod client { + use pingpong; + + pub type ping = ::pipes::send_packet<pingpong::ping>; + pub type pong = ::pipes::recv_packet<pingpong::pong>; + + pub fn do_ping(c: ping) -> pong { + let (sp, rp) = ::pipes::entangle(); + + ::pipes::send(c, pingpong::ping(sp)); + rp + } + + pub fn do_pong(c: pong) -> (ping, ()) { + let packet = ::pipes::recv(c); + if packet.is_none() { + panic!("sender closed the connection") + } + (pingpong::liberate_pong(packet.unwrap()), ()) + } + } + + pub mod server { + use pingpong; + + pub type ping = ::pipes::recv_packet<pingpong::ping>; + pub type pong = ::pipes::send_packet<pingpong::pong>; + + pub fn do_ping(c: ping) -> (pong, ()) { + let packet = ::pipes::recv(c); + if packet.is_none() { + panic!("sender closed the connection") + } + (pingpong::liberate_ping(packet.unwrap()), ()) + } + + pub fn do_pong(c: pong) -> ping { + let (sp, rp) = ::pipes::entangle(); + ::pipes::send(c, pingpong::pong(sp)); + rp + } + } +} + +fn client(chan: pingpong::client::ping) { + let chan = pingpong::client::do_ping(chan); + println!("Sent ping"); + let (_chan, _data) = pingpong::client::do_pong(chan); + println!("Received pong"); +} + +fn server(chan: pingpong::server::ping) { + let (chan, _data) = pingpong::server::do_ping(chan); + println!("Received ping"); + let _chan = pingpong::server::do_pong(chan); + println!("Sent pong"); +} + +pub fn main() { + /* +// Commented out because of option::get error + + let (client_, server_) = pingpong::init(); + + task::spawn {|client_| + let client__ = client_.take(); + client(client__); + }; + task::spawn {|server_| + let server__ = server_.take(); + server(server_ËŠ); + }; + */ +} diff --git a/src/test/ui/regions/issue-28848.rs b/src/test/ui/regions/issue-28848.rs new file mode 100644 index 000000000..0eb3d89c5 --- /dev/null +++ b/src/test/ui/regions/issue-28848.rs @@ -0,0 +1,14 @@ +struct Foo<'a, 'b: 'a>(&'a &'b ()); + +impl<'a, 'b> Foo<'a, 'b> { + fn xmute(a: &'b ()) -> &'a () { + unreachable!() + } +} + +pub fn foo<'a, 'b>(u: &'b ()) -> &'a () { + Foo::<'a, 'b>::xmute(u) + //~^ ERROR lifetime may not live long enough +} + +fn main() {} diff --git a/src/test/ui/regions/issue-28848.stderr b/src/test/ui/regions/issue-28848.stderr new file mode 100644 index 000000000..a29dac4c9 --- /dev/null +++ b/src/test/ui/regions/issue-28848.stderr @@ -0,0 +1,14 @@ +error: lifetime may not live long enough + --> $DIR/issue-28848.rs:10:5 + | +LL | pub fn foo<'a, 'b>(u: &'b ()) -> &'a () { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | Foo::<'a, 'b>::xmute(u) + | ^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/issue-5243.rs b/src/test/ui/regions/issue-5243.rs new file mode 100644 index 000000000..c511d45f0 --- /dev/null +++ b/src/test/ui/regions/issue-5243.rs @@ -0,0 +1,17 @@ +// run-pass +#![allow(dead_code)] +// Check that merely having lifetime parameters is not +// enough for codegen to consider this as non-monomorphic, +// which led to various assertions and failures in turn. + +// pretty-expanded FIXME #23616 + +struct S<'a> { + v: &'a isize +} + +fn f<'lt>(_s: &'lt S<'lt>) {} + +pub fn main() { + f(& S { v: &42 }); +} diff --git a/src/test/ui/regions/issue-56537-closure-uses-region-from-container.rs b/src/test/ui/regions/issue-56537-closure-uses-region-from-container.rs new file mode 100644 index 000000000..bdd1ae91f --- /dev/null +++ b/src/test/ui/regions/issue-56537-closure-uses-region-from-container.rs @@ -0,0 +1,67 @@ +// This is a collection of examples where a function's formal +// parameter has an explicit lifetime and a closure within that +// function returns that formal parameter. The closure's return type, +// to be correctly inferred, needs to include the lifetime introduced +// by the function. +// +// This works today, which precludes changing things so that closures +// follow the same lifetime-elision rules used elsehwere. See +// rust-lang/rust#56537 + +// check-pass + +fn willy_no_annot<'w>(p: &'w str, q: &str) -> &'w str { + let free_dumb = |_x| { p }; // no type annotation at all + let hello = format!("Hello"); + free_dumb(&hello) +} + +fn willy_ret_type_annot<'w>(p: &'w str, q: &str) -> &'w str { + let free_dumb = |_x| -> &str { p }; // type annotation on the return type + let hello = format!("Hello"); + free_dumb(&hello) +} + +fn willy_ret_region_annot<'w>(p: &'w str, q: &str) -> &'w str { + let free_dumb = |_x| -> &'w str { p }; // type+region annotation on return type + let hello = format!("Hello"); + free_dumb(&hello) +} + +fn willy_arg_type_ret_type_annot<'w>(p: &'w str, q: &str) -> &'w str { + let free_dumb = |_x: &str| -> &str { p }; // type annotation on arg and return types + let hello = format!("Hello"); + free_dumb(&hello) +} + +fn willy_arg_type_ret_region_annot<'w>(p: &'w str, q: &str) -> &'w str { + let free_dumb = |_x: &str| -> &'w str { p }; // fully annotated + let hello = format!("Hello"); + free_dumb(&hello) +} + +fn main() { + let world = format!("World"); + let w1: &str = { + let hello = format!("He11o"); + willy_no_annot(&world, &hello) + }; + let w2: &str = { + let hello = format!("He22o"); + willy_ret_type_annot(&world, &hello) + }; + let w3: &str = { + let hello = format!("He33o"); + willy_ret_region_annot(&world, &hello) + }; + let w4: &str = { + let hello = format!("He44o"); + willy_arg_type_ret_type_annot(&world, &hello) + }; + let w5: &str = { + let hello = format!("He55o"); + willy_arg_type_ret_region_annot(&world, &hello) + }; + assert_eq!((w1, w2, w3, w4, w5), + ("World","World","World","World","World")); +} diff --git a/src/test/ui/regions/issue-6157.rs b/src/test/ui/regions/issue-6157.rs new file mode 100644 index 000000000..b7a44ed86 --- /dev/null +++ b/src/test/ui/regions/issue-6157.rs @@ -0,0 +1,23 @@ +// run-pass +// pretty-expanded FIXME #23616 + +pub trait OpInt { fn call(&mut self, _: isize, _: isize) -> isize; } + +impl<F> OpInt for F where F: FnMut(isize, isize) -> isize { + fn call(&mut self, a:isize, b:isize) -> isize { + (*self)(a, b) + } +} + +fn squarei<'a>(x: isize, op: &'a mut dyn OpInt) -> isize { op.call(x, x) } + +fn muli(x:isize, y:isize) -> isize { x * y } + +pub fn main() { + let mut f = |x, y| muli(x, y); + { + let g = &mut f; + let h = g as &mut dyn OpInt; + squarei(3, h); + } +} diff --git a/src/test/ui/regions/issue-72051-member-region-hang.rs b/src/test/ui/regions/issue-72051-member-region-hang.rs new file mode 100644 index 000000000..b7340b79d --- /dev/null +++ b/src/test/ui/regions/issue-72051-member-region-hang.rs @@ -0,0 +1,7 @@ +// Regression test for #72051, hang when resolving regions. + +// check-pass +// edition:2018 + +pub async fn query<'a>(_: &(), _: &(), _: (&(dyn std::any::Any + 'a),) ) {} +fn main() {} diff --git a/src/test/ui/regions/issue-78262.base.stderr b/src/test/ui/regions/issue-78262.base.stderr new file mode 100644 index 000000000..7f232e4a7 --- /dev/null +++ b/src/test/ui/regions/issue-78262.base.stderr @@ -0,0 +1,14 @@ +error[E0521]: borrowed data escapes outside of closure + --> $DIR/issue-78262.rs:12:26 + | +LL | let f = |x: &dyn TT| x.func(); + | - - ^^^^^^^^ + | | | | + | | | `x` escapes the closure body here + | | | argument requires that `'1` must outlive `'static` + | | let's call the lifetime of this reference `'1` + | `x` is a reference that is only valid in the closure body + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0521`. diff --git a/src/test/ui/regions/issue-78262.polonius.stderr b/src/test/ui/regions/issue-78262.polonius.stderr new file mode 100644 index 000000000..7f232e4a7 --- /dev/null +++ b/src/test/ui/regions/issue-78262.polonius.stderr @@ -0,0 +1,14 @@ +error[E0521]: borrowed data escapes outside of closure + --> $DIR/issue-78262.rs:12:26 + | +LL | let f = |x: &dyn TT| x.func(); + | - - ^^^^^^^^ + | | | | + | | | `x` escapes the closure body here + | | | argument requires that `'1` must outlive `'static` + | | let's call the lifetime of this reference `'1` + | `x` is a reference that is only valid in the closure body + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0521`. diff --git a/src/test/ui/regions/issue-78262.rs b/src/test/ui/regions/issue-78262.rs new file mode 100644 index 000000000..642dbd7f8 --- /dev/null +++ b/src/test/ui/regions/issue-78262.rs @@ -0,0 +1,15 @@ +// revisions: base polonius +// ignore-compare-mode-polonius +// [polonius] compile-flags: -Z polonius + +trait TT {} + +impl dyn TT { + fn func(&self) {} +} + +fn main() { + let f = |x: &dyn TT| x.func(); + //[base]~^ ERROR: borrowed data escapes outside of closure + //[polonius]~^^ ERROR: borrowed data escapes outside of closure +} diff --git a/src/test/ui/regions/owned-implies-static.rs b/src/test/ui/regions/owned-implies-static.rs new file mode 100644 index 000000000..2efa8cc02 --- /dev/null +++ b/src/test/ui/regions/owned-implies-static.rs @@ -0,0 +1,8 @@ +// run-pass +// pretty-expanded FIXME #23616 + +fn f<T: 'static>(_x: T) {} + +pub fn main() { + f(Box::new(5)); +} diff --git a/src/test/ui/regions/rcvr-borrowed-to-region.rs b/src/test/ui/regions/rcvr-borrowed-to-region.rs new file mode 100644 index 000000000..7f32b8b91 --- /dev/null +++ b/src/test/ui/regions/rcvr-borrowed-to-region.rs @@ -0,0 +1,28 @@ +// run-pass + +#![allow(non_camel_case_types)] + +trait get { + fn get(self) -> isize; +} + +// Note: impl on a slice; we're checking that the pointers below +// correctly get borrowed to `&`. (similar to impling for `isize`, with +// `&self` instead of `self`.) +impl<'a> get for &'a isize { + fn get(self) -> isize { + return *self; + } +} + +pub fn main() { + let x: Box<_> = 6.into(); + let y = x.get(); + println!("y={}", y); + assert_eq!(y, 6); + + let x = &6; + let y = x.get(); + println!("y={}", y); + assert_eq!(y, 6); +} diff --git a/src/test/ui/regions/region-borrow-params-issue-29793-big.rs b/src/test/ui/regions/region-borrow-params-issue-29793-big.rs new file mode 100644 index 000000000..83b1a6eab --- /dev/null +++ b/src/test/ui/regions/region-borrow-params-issue-29793-big.rs @@ -0,0 +1,74 @@ +// 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 closure may outlive the current function + //~| ERROR closure may outlive the current function + }); + + w.handle(); // This works + // w.handle_ref(); // This doesn't +} diff --git a/src/test/ui/regions/region-borrow-params-issue-29793-big.stderr b/src/test/ui/regions/region-borrow-params-issue-29793-big.stderr new file mode 100644 index 000000000..561dd64b4 --- /dev/null +++ b/src/test/ui/regions/region-borrow-params-issue-29793-big.stderr @@ -0,0 +1,39 @@ +error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function + --> $DIR/region-borrow-params-issue-29793-big.rs:67:26 + | +LL | WrapB::new().set(|t: bool| if t { x } else { y }) // (separate errors for `x` vs `y`) + | ^^^^^^^^^ - `x` is borrowed here + | | + | may outlive borrowed value `x` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-big.rs:67:9 + | +LL | WrapB::new().set(|t: bool| if t { x } else { y }) // (separate errors for `x` vs `y`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword + | +LL | WrapB::new().set(move |t: bool| if t { x } else { y }) // (separate errors for `x` vs `y`) + | ++++ + +error[E0373]: closure may outlive the current function, but it borrows `y`, which is owned by the current function + --> $DIR/region-borrow-params-issue-29793-big.rs:67:26 + | +LL | WrapB::new().set(|t: bool| if t { x } else { y }) // (separate errors for `x` vs `y`) + | ^^^^^^^^^ - `y` is borrowed here + | | + | may outlive borrowed value `y` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-big.rs:67:9 + | +LL | WrapB::new().set(|t: bool| if t { x } else { y }) // (separate errors for `x` vs `y`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: to force the closure to take ownership of `y` (and any other referenced variables), use the `move` keyword + | +LL | WrapB::new().set(move |t: bool| if t { x } else { y }) // (separate errors for `x` vs `y`) + | ++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0373`. diff --git a/src/test/ui/regions/region-borrow-params-issue-29793-small.rs b/src/test/ui/regions/region-borrow-params-issue-29793-small.rs new file mode 100644 index 000000000..5f1c2ed08 --- /dev/null +++ b/src/test/ui/regions/region-borrow-params-issue-29793-small.rs @@ -0,0 +1,212 @@ +// 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 E0373 + //~| ERROR E0373 + 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 E0373 + //~| ERROR E0373 + 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<dyn 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<dyn 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<dyn 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<dyn 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<dyn 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<dyn 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<dyn Fn(bool) -> usize + 'a>; } + struct S; + impl T for S { + fn g<'a>(&self, x: usize, y:usize) -> Box<dyn 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<dyn Fn(bool) -> usize + 'a>; } + struct S; + impl T for S { + fn g<'a>(&self, x: usize, y:usize) -> Box<dyn 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<dyn Fn(bool) -> usize + 'a>; } + struct S; + impl T for S { + fn g<'a>(&self, x: usize, y:usize) -> Box<dyn 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<dyn 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<dyn 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<dyn 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() { } diff --git a/src/test/ui/regions/region-borrow-params-issue-29793-small.stderr b/src/test/ui/regions/region-borrow-params-issue-29793-small.stderr new file mode 100644 index 000000000..e446f2a00 --- /dev/null +++ b/src/test/ui/regions/region-borrow-params-issue-29793-small.stderr @@ -0,0 +1,363 @@ +error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function + --> $DIR/region-borrow-params-issue-29793-small.rs:9:17 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^ - `x` is borrowed here + | | + | may outlive borrowed value `x` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:12:16 + | +LL | return f; + | ^ +help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword + | +LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ++++ + +error[E0373]: closure may outlive the current function, but it borrows `y`, which is owned by the current function + --> $DIR/region-borrow-params-issue-29793-small.rs:9:17 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^ - `y` is borrowed here + | | + | may outlive borrowed value `y` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:12:16 + | +LL | return f; + | ^ +help: to force the closure to take ownership of `y` (and any other referenced variables), use the `move` keyword + | +LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ++++ + +error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function + --> $DIR/region-borrow-params-issue-29793-small.rs:24:17 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^ - `x` is borrowed here + | | + | may outlive borrowed value `x` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:27:9 + | +LL | f + | ^ +help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword + | +LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ++++ + +error[E0373]: closure may outlive the current function, but it borrows `y`, which is owned by the current function + --> $DIR/region-borrow-params-issue-29793-small.rs:24:17 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^ - `y` is borrowed here + | | + | may outlive borrowed value `y` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:27:9 + | +LL | f + | ^ +help: to force the closure to take ownership of `y` (and any other referenced variables), use the `move` keyword + | +LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ++++ + +error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function + --> $DIR/region-borrow-params-issue-29793-small.rs:55:17 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^ - `x` is borrowed here + | | + | may outlive borrowed value `x` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:58:16 + | +LL | return Box::new(f); + | ^^^^^^^^^^^ +help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword + | +LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ++++ + +error[E0373]: closure may outlive the current function, but it borrows `y`, which is owned by the current function + --> $DIR/region-borrow-params-issue-29793-small.rs:55:17 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^ - `y` is borrowed here + | | + | may outlive borrowed value `y` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:58:16 + | +LL | return Box::new(f); + | ^^^^^^^^^^^ +help: to force the closure to take ownership of `y` (and any other referenced variables), use the `move` keyword + | +LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ++++ + +error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function + --> $DIR/region-borrow-params-issue-29793-small.rs:66:17 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^ - `x` is borrowed here + | | + | may outlive borrowed value `x` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:69:9 + | +LL | Box::new(f) + | ^^^^^^^^^^^ +help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword + | +LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ++++ + +error[E0373]: closure may outlive the current function, but it borrows `y`, which is owned by the current function + --> $DIR/region-borrow-params-issue-29793-small.rs:66:17 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^ - `y` is borrowed here + | | + | may outlive borrowed value `y` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:69:9 + | +LL | Box::new(f) + | ^^^^^^^^^^^ +help: to force the closure to take ownership of `y` (and any other referenced variables), use the `move` keyword + | +LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ++++ + +error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function + --> $DIR/region-borrow-params-issue-29793-small.rs:90:21 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^ - `x` is borrowed here + | | + | may outlive borrowed value `x` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:93:20 + | +LL | return Box::new(f); + | ^^^^^^^^^^^ +help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword + | +LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ++++ + +error[E0373]: closure may outlive the current function, but it borrows `y`, which is owned by the current function + --> $DIR/region-borrow-params-issue-29793-small.rs:90:21 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^ - `y` is borrowed here + | | + | may outlive borrowed value `y` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:93:20 + | +LL | return Box::new(f); + | ^^^^^^^^^^^ +help: to force the closure to take ownership of `y` (and any other referenced variables), use the `move` keyword + | +LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ++++ + +error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function + --> $DIR/region-borrow-params-issue-29793-small.rs:104:21 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^ - `x` is borrowed here + | | + | may outlive borrowed value `x` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:107:13 + | +LL | Box::new(f) + | ^^^^^^^^^^^ +help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword + | +LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ++++ + +error[E0373]: closure may outlive the current function, but it borrows `y`, which is owned by the current function + --> $DIR/region-borrow-params-issue-29793-small.rs:104:21 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^ - `y` is borrowed here + | | + | may outlive borrowed value `y` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:107:13 + | +LL | Box::new(f) + | ^^^^^^^^^^^ +help: to force the closure to take ownership of `y` (and any other referenced variables), use the `move` keyword + | +LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ++++ + +error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function + --> $DIR/region-borrow-params-issue-29793-small.rs:132:21 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^ - `x` is borrowed here + | | + | may outlive borrowed value `x` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:135:20 + | +LL | return Box::new(f); + | ^^^^^^^^^^^ +help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword + | +LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ++++ + +error[E0373]: closure may outlive the current function, but it borrows `y`, which is owned by the current function + --> $DIR/region-borrow-params-issue-29793-small.rs:132:21 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^ - `y` is borrowed here + | | + | may outlive borrowed value `y` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:135:20 + | +LL | return Box::new(f); + | ^^^^^^^^^^^ +help: to force the closure to take ownership of `y` (and any other referenced variables), use the `move` keyword + | +LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ++++ + +error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function + --> $DIR/region-borrow-params-issue-29793-small.rs:147:21 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^ - `x` is borrowed here + | | + | may outlive borrowed value `x` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:150:13 + | +LL | Box::new(f) + | ^^^^^^^^^^^ +help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword + | +LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ++++ + +error[E0373]: closure may outlive the current function, but it borrows `y`, which is owned by the current function + --> $DIR/region-borrow-params-issue-29793-small.rs:147:21 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^ - `y` is borrowed here + | | + | may outlive borrowed value `y` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:150:13 + | +LL | Box::new(f) + | ^^^^^^^^^^^ +help: to force the closure to take ownership of `y` (and any other referenced variables), use the `move` keyword + | +LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ++++ + +error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function + --> $DIR/region-borrow-params-issue-29793-small.rs:175:21 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^ - `x` is borrowed here + | | + | may outlive borrowed value `x` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:178:20 + | +LL | return Box::new(f); + | ^^^^^^^^^^^ +help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword + | +LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ++++ + +error[E0373]: closure may outlive the current function, but it borrows `y`, which is owned by the current function + --> $DIR/region-borrow-params-issue-29793-small.rs:175:21 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^ - `y` is borrowed here + | | + | may outlive borrowed value `y` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:178:20 + | +LL | return Box::new(f); + | ^^^^^^^^^^^ +help: to force the closure to take ownership of `y` (and any other referenced variables), use the `move` keyword + | +LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ++++ + +error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function + --> $DIR/region-borrow-params-issue-29793-small.rs:189:21 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^ - `x` is borrowed here + | | + | may outlive borrowed value `x` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:192:13 + | +LL | Box::new(f) + | ^^^^^^^^^^^ +help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword + | +LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ++++ + +error[E0373]: closure may outlive the current function, but it borrows `y`, which is owned by the current function + --> $DIR/region-borrow-params-issue-29793-small.rs:189:21 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^ - `y` is borrowed here + | | + | may outlive borrowed value `y` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:192:13 + | +LL | Box::new(f) + | ^^^^^^^^^^^ +help: to force the closure to take ownership of `y` (and any other referenced variables), use the `move` keyword + | +LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ++++ + +error: aborting due to 20 previous errors + +For more information about this error, try `rustc --explain E0373`. diff --git a/src/test/ui/regions/region-bound-extra-bound-in-inherent-impl.rs b/src/test/ui/regions/region-bound-extra-bound-in-inherent-impl.rs new file mode 100644 index 000000000..72d82da45 --- /dev/null +++ b/src/test/ui/regions/region-bound-extra-bound-in-inherent-impl.rs @@ -0,0 +1,16 @@ +// Test related to #22779. In this case, the impl is an inherent impl, +// so it doesn't have to match any trait, so no error results. + +// check-pass +#![allow(dead_code)] + +struct MySlice<'a, T:'a>(&'a mut [T]); + +impl<'a, T> MySlice<'a, T> { + fn renew<'b: 'a>(self) -> &'b mut [T] where 'a: 'b { + &mut self.0[..] + } +} + + +fn main() { } diff --git a/src/test/ui/regions/region-bound-on-closure-outlives-call.rs b/src/test/ui/regions/region-bound-on-closure-outlives-call.rs new file mode 100644 index 000000000..1311d5121 --- /dev/null +++ b/src/test/ui/regions/region-bound-on-closure-outlives-call.rs @@ -0,0 +1,6 @@ +fn call_rec<F>(mut f: F) -> usize where F: FnMut(usize) -> usize { + //~^ WARN function cannot return without recursing + (|x| f(x))(call_rec(f)) //~ ERROR cannot move out of `f` +} + +fn main() {} diff --git a/src/test/ui/regions/region-bound-on-closure-outlives-call.stderr b/src/test/ui/regions/region-bound-on-closure-outlives-call.stderr new file mode 100644 index 000000000..a2396ad42 --- /dev/null +++ b/src/test/ui/regions/region-bound-on-closure-outlives-call.stderr @@ -0,0 +1,24 @@ +warning: function cannot return without recursing + --> $DIR/region-bound-on-closure-outlives-call.rs:1:1 + | +LL | fn call_rec<F>(mut f: F) -> usize where F: FnMut(usize) -> usize { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing +LL | +LL | (|x| f(x))(call_rec(f)) + | ----------- recursive call site + | + = note: `#[warn(unconditional_recursion)]` on by default + = help: a `loop` may express intention better if this is on purpose + +error[E0505]: cannot move out of `f` because it is borrowed + --> $DIR/region-bound-on-closure-outlives-call.rs:3:25 + | +LL | (|x| f(x))(call_rec(f)) + | --- - ^ move out of `f` occurs here + | | | + | | borrow occurs due to use in closure + | borrow of `f` occurs here + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0505`. diff --git a/src/test/ui/regions/region-bound-same-bounds-in-trait-and-impl.rs b/src/test/ui/regions/region-bound-same-bounds-in-trait-and-impl.rs new file mode 100644 index 000000000..68056370c --- /dev/null +++ b/src/test/ui/regions/region-bound-same-bounds-in-trait-and-impl.rs @@ -0,0 +1,17 @@ +// Test related to #22779, but where the `'a:'b` relation +// appears in the trait too. No error here. + +// check-pass + +trait Tr<'a, T> { + fn renew<'b: 'a>(self) -> &'b mut [T] where 'a: 'b; +} + +impl<'a, T> Tr<'a, T> for &'a mut [T] { + fn renew<'b: 'a>(self) -> &'b mut [T] where 'a: 'b { + &mut self[..] + } +} + + +fn main() { } diff --git a/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.rs b/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.rs new file mode 100644 index 000000000..40d2b740b --- /dev/null +++ b/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.rs @@ -0,0 +1,36 @@ +// Test related to when a region bound is required to be specified. + +trait IsStatic : 'static { } +trait IsSend : Send { } +trait Is<'a> : 'a { } +trait Is2<'a> : 'a { } +trait SomeTrait { } + +// Bounds on object types: + +struct Foo<'a,'b,'c> { //~ ERROR parameter `'c` is never used + // All of these are ok, because we can derive exactly one bound: + a: Box<dyn IsStatic>, + b: Box<dyn Is<'static>>, + c: Box<dyn Is<'a>>, + d: Box<dyn IsSend>, + e: Box<dyn Is<'a>+Send>, // we can derive two bounds, but one is 'static, so ok + f: Box<dyn SomeTrait>, // OK, defaults to 'static due to RFC 599. + g: Box<dyn SomeTrait+'a>, + + z: Box<dyn Is<'a>+'b+'c>, + //~^ ERROR only a single explicit lifetime bound is permitted + //~| ERROR lifetime bound not satisfied +} + +fn test< + 'a, + 'b, + A:IsStatic, + B:Is<'a>+Is2<'b>, // OK in a parameter, but not an object type. + C:'b+Is<'a>+Is2<'b>, + D:Is<'a>+Is2<'static>, + E:'a+'b // OK in a parameter, but not an object type. +>() { } + +fn main() { } diff --git a/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.stderr b/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.stderr new file mode 100644 index 000000000..2ec2ca49b --- /dev/null +++ b/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.stderr @@ -0,0 +1,35 @@ +error[E0226]: only a single explicit lifetime bound is permitted + --> $DIR/region-bounds-on-objects-and-type-parameters.rs:21:26 + | +LL | z: Box<dyn Is<'a>+'b+'c>, + | ^^ + +error[E0478]: lifetime bound not satisfied + --> $DIR/region-bounds-on-objects-and-type-parameters.rs:21:8 + | +LL | z: Box<dyn Is<'a>+'b+'c>, + | ^^^^^^^^^^^^^^^^^^^^^ + | +note: lifetime parameter instantiated with the lifetime `'b` as defined here + --> $DIR/region-bounds-on-objects-and-type-parameters.rs:11:15 + | +LL | struct Foo<'a,'b,'c> { + | ^^ +note: but lifetime parameter must outlive the lifetime `'a` as defined here + --> $DIR/region-bounds-on-objects-and-type-parameters.rs:11:12 + | +LL | struct Foo<'a,'b,'c> { + | ^^ + +error[E0392]: parameter `'c` is never used + --> $DIR/region-bounds-on-objects-and-type-parameters.rs:11:18 + | +LL | struct Foo<'a,'b,'c> { + | ^^ unused parameter + | + = help: consider removing `'c`, referring to it in a field, or using a marker such as `PhantomData` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0226, E0392, E0478. +For more information about an error, try `rustc --explain E0226`. diff --git a/src/test/ui/regions/region-invariant-static-error-reporting.rs b/src/test/ui/regions/region-invariant-static-error-reporting.rs new file mode 100644 index 000000000..c8288b592 --- /dev/null +++ b/src/test/ui/regions/region-invariant-static-error-reporting.rs @@ -0,0 +1,21 @@ +// This test checks that the error messages you get for this example +// at least mention `'a` and `'static`. The precise messages can drift +// over time, but this test used to exhibit some pretty bogus messages +// that were not remotely helpful. + +// error-pattern:argument requires that `'a` must outlive `'static` + +struct Invariant<'a>(Option<&'a mut &'a mut ()>); + +fn mk_static() -> Invariant<'static> { Invariant(None) } + +fn unify<'a>(x: Option<Invariant<'a>>, f: fn(Invariant<'a>)) { + let bad = if x.is_some() { + x.unwrap() //~ ERROR borrowed data escapes outside of function [E0521] + } else { + mk_static() + }; + f(bad); +} + +fn main() {} diff --git a/src/test/ui/regions/region-invariant-static-error-reporting.stderr b/src/test/ui/regions/region-invariant-static-error-reporting.stderr new file mode 100644 index 000000000..2ad39b000 --- /dev/null +++ b/src/test/ui/regions/region-invariant-static-error-reporting.stderr @@ -0,0 +1,21 @@ +error[E0521]: borrowed data escapes outside of function + --> $DIR/region-invariant-static-error-reporting.rs:14:9 + | +LL | fn unify<'a>(x: Option<Invariant<'a>>, f: fn(Invariant<'a>)) { + | -- - `x` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here +LL | let bad = if x.is_some() { +LL | x.unwrap() + | ^^^^^^^^^^ + | | + | `x` escapes the function body here + | argument requires that `'a` must outlive `'static` + | + = note: requirement occurs because of the type `Invariant<'_>`, which makes the generic argument `'_` invariant + = note: the struct `Invariant<'a>` is invariant over the parameter `'a` + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0521`. diff --git a/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.rs b/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.rs new file mode 100644 index 000000000..d364c4677 --- /dev/null +++ b/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.rs @@ -0,0 +1,30 @@ +fn a<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) where 'b: 'a { + // Note: this is legal because of the `'b:'a` declaration. + *x = *y; +} + +fn b<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) { + // Illegal now because there is no `'b:'a` declaration. + *x = *y; +} + +fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) { + // Here we try to call `foo` but do not know that `'a` and `'b` are + // related as required. + a(x, y); +} + +fn d() { + // 'a and 'b are early bound in the function `a` because they appear + // inconstraints: + let _: fn(&mut &isize, &mut &isize) = a; + //~^ ERROR mismatched types [E0308] +} + +fn e() { + // 'a and 'b are late bound in the function `b` because there are + // no constraints: + let _: fn(&mut &isize, &mut &isize) = b; +} + +fn main() { } diff --git a/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr b/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr new file mode 100644 index 000000000..48f2e1a2f --- /dev/null +++ b/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:43 + | +LL | let _: fn(&mut &isize, &mut &isize) = a; + | ^ one type is more general than the other + | + = note: expected fn pointer `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)` + found fn item `for<'r, 's> fn(&'r mut &isize, &'s mut &isize) {a::<'_, '_>}` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.rs b/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.rs new file mode 100644 index 000000000..60dafdd52 --- /dev/null +++ b/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.rs @@ -0,0 +1,32 @@ +fn a<'a, 'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) where 'b: 'a + 'c { + // Note: this is legal because of the `'b:'a` declaration. + *x = *y; + *z = *y; +} + +fn b<'a, 'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) { + // Illegal now because there is no `'b:'a` declaration. + *x = *y; + *z = *y; +} + +fn c<'a,'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) { + // Here we try to call `foo` but do not know that `'a` and `'b` are + // related as required. + a(x, y, z); +} + +fn d() { + // 'a and 'b are early bound in the function `a` because they appear + // inconstraints: + let _: fn(&mut &isize, &mut &isize, &mut &isize) = a; + //~^ ERROR E0308 +} + +fn e() { + // 'a and 'b are late bound in the function `b` because there are + // no constraints: + let _: fn(&mut &isize, &mut &isize, &mut &isize) = b; +} + +fn main() { } diff --git a/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr b/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr new file mode 100644 index 000000000..36f40cd9a --- /dev/null +++ b/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:56 + | +LL | let _: fn(&mut &isize, &mut &isize, &mut &isize) = a; + | ^ one type is more general than the other + | + = note: expected fn pointer `for<'r, 's, 't0, 't1, 't2, 't3> fn(&'r mut &'s isize, &'t0 mut &'t1 isize, &'t2 mut &'t3 isize)` + found fn item `for<'r, 's, 't0> fn(&'r mut &isize, &'s mut &isize, &'t0 mut &isize) {a::<'_, '_, '_>}` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/regions/region-object-lifetime-1.rs b/src/test/ui/regions/region-object-lifetime-1.rs new file mode 100644 index 000000000..ddf3be690 --- /dev/null +++ b/src/test/ui/regions/region-object-lifetime-1.rs @@ -0,0 +1,18 @@ +// Various tests related to testing how region inference works +// with respect to the object receivers. + +// check-pass +#![allow(warnings)] + +trait Foo { + fn borrowed<'a>(&'a self) -> &'a (); +} + +// Here the receiver and return value all have the same lifetime, +// so no error results. +fn borrowed_receiver_same_lifetime<'a>(x: &'a Foo) -> &'a () { + x.borrowed() +} + + +fn main() {} diff --git a/src/test/ui/regions/region-object-lifetime-2.rs b/src/test/ui/regions/region-object-lifetime-2.rs new file mode 100644 index 000000000..cfdb8fefe --- /dev/null +++ b/src/test/ui/regions/region-object-lifetime-2.rs @@ -0,0 +1,14 @@ +// Various tests related to testing how region inference works +// with respect to the object receivers. + +trait Foo { + fn borrowed<'a>(&'a self) -> &'a (); +} + +// Borrowed receiver but two distinct lifetimes, we get an error. +fn borrowed_receiver_different_lifetimes<'a,'b>(x: &'a dyn Foo) -> &'b () { + x.borrowed() + //~^ ERROR lifetime may not live long enough +} + +fn main() {} diff --git a/src/test/ui/regions/region-object-lifetime-2.stderr b/src/test/ui/regions/region-object-lifetime-2.stderr new file mode 100644 index 000000000..d95289f3f --- /dev/null +++ b/src/test/ui/regions/region-object-lifetime-2.stderr @@ -0,0 +1,14 @@ +error: lifetime may not live long enough + --> $DIR/region-object-lifetime-2.rs:10:5 + | +LL | fn borrowed_receiver_different_lifetimes<'a,'b>(x: &'a dyn Foo) -> &'b () { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | x.borrowed() + | ^^^^^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + | + = help: consider adding the following bound: `'a: 'b` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/region-object-lifetime-3.rs b/src/test/ui/regions/region-object-lifetime-3.rs new file mode 100644 index 000000000..0536fa2a2 --- /dev/null +++ b/src/test/ui/regions/region-object-lifetime-3.rs @@ -0,0 +1,18 @@ +// Various tests related to testing how region inference works +// with respect to the object receivers. + +// check-pass +#![allow(warnings)] + +trait Foo { + fn borrowed<'a>(&'a self) -> &'a (); +} + +// Borrowed receiver with two distinct lifetimes, but we know that +// 'b:'a, hence &'a () is permitted. +fn borrowed_receiver_related_lifetimes<'a,'b>(x: &'a (Foo+'b)) -> &'a () { + x.borrowed() +} + + +fn main() {} diff --git a/src/test/ui/regions/region-object-lifetime-4.rs b/src/test/ui/regions/region-object-lifetime-4.rs new file mode 100644 index 000000000..8f42df831 --- /dev/null +++ b/src/test/ui/regions/region-object-lifetime-4.rs @@ -0,0 +1,16 @@ +// Various tests related to testing how region inference works +// with respect to the object receivers. + +trait Foo { + fn borrowed<'a>(&'a self) -> &'a (); +} + +// Here we have two distinct lifetimes, but we try to return a pointer +// with the longer lifetime when (from the signature) we only know +// that it lives as long as the shorter lifetime. Therefore, error. +fn borrowed_receiver_related_lifetimes2<'a,'b>(x: &'a (dyn Foo + 'b)) -> &'b () { + x.borrowed() + //~^ ERROR lifetime may not live long enough +} + +fn main() {} diff --git a/src/test/ui/regions/region-object-lifetime-4.stderr b/src/test/ui/regions/region-object-lifetime-4.stderr new file mode 100644 index 000000000..fda66a241 --- /dev/null +++ b/src/test/ui/regions/region-object-lifetime-4.stderr @@ -0,0 +1,14 @@ +error: lifetime may not live long enough + --> $DIR/region-object-lifetime-4.rs:12:5 + | +LL | fn borrowed_receiver_related_lifetimes2<'a,'b>(x: &'a (dyn Foo + 'b)) -> &'b () { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | x.borrowed() + | ^^^^^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + | + = help: consider adding the following bound: `'a: 'b` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/region-object-lifetime-5.rs b/src/test/ui/regions/region-object-lifetime-5.rs new file mode 100644 index 000000000..ad3593671 --- /dev/null +++ b/src/test/ui/regions/region-object-lifetime-5.rs @@ -0,0 +1,14 @@ +// Various tests related to testing how region inference works +// with respect to the object receivers. + +trait Foo { + fn borrowed<'a>(&'a self) -> &'a (); +} + +// Here, the object is bounded by an anonymous lifetime and returned +// as `&'static`, so you get an error. +fn owned_receiver(x: Box<dyn Foo>) -> &'static () { + x.borrowed() //~ ERROR cannot return reference to local data `*x` +} + +fn main() {} diff --git a/src/test/ui/regions/region-object-lifetime-5.stderr b/src/test/ui/regions/region-object-lifetime-5.stderr new file mode 100644 index 000000000..b82b58c7a --- /dev/null +++ b/src/test/ui/regions/region-object-lifetime-5.stderr @@ -0,0 +1,9 @@ +error[E0515]: cannot return reference to local data `*x` + --> $DIR/region-object-lifetime-5.rs:11:5 + | +LL | x.borrowed() + | ^^^^^^^^^^^^ returns a reference to data owned by the current function + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.rs b/src/test/ui/regions/region-object-lifetime-in-coercion.rs new file mode 100644 index 000000000..95708de04 --- /dev/null +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.rs @@ -0,0 +1,34 @@ +// Test that attempts to implicitly coerce a value into an +// object respect the lifetime bound on the object type. + +trait Foo {} +impl<'a> Foo for &'a [u8] {} + +fn a(v: &[u8]) -> Box<dyn Foo + 'static> { + let x: Box<dyn Foo + 'static> = Box::new(v); + //~^ ERROR lifetime may not live long enough + x +} + +fn b(v: &[u8]) -> Box<dyn Foo + 'static> { + Box::new(v) + //~^ ERROR lifetime may not live long enough +} + +fn c(v: &[u8]) -> Box<dyn Foo> { + // same as previous case due to RFC 599 + + Box::new(v) + //~^ ERROR lifetime may not live long enough +} + +fn d<'a,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> { + Box::new(v) + //~^ ERROR lifetime may not live long enough +} + +fn e<'a:'b,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> { + Box::new(v) // OK, thanks to 'a:'b +} + +fn main() { } diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr new file mode 100644 index 000000000..b5bb08c73 --- /dev/null +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr @@ -0,0 +1,62 @@ +error: lifetime may not live long enough + --> $DIR/region-object-lifetime-in-coercion.rs:8:12 + | +LL | fn a(v: &[u8]) -> Box<dyn Foo + 'static> { + | - let's call the lifetime of this reference `'1` +LL | let x: Box<dyn Foo + 'static> = Box::new(v); + | ^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'1` must outlive `'static` + | +help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v` + | +LL | fn a(v: &[u8]) -> Box<dyn Foo + '_> { + | ~~ +help: alternatively, add an explicit `'static` bound to this reference + | +LL | fn a(v: &'static [u8]) -> Box<dyn Foo + 'static> { + | ~~~~~~~~~~~~~ + +error: lifetime may not live long enough + --> $DIR/region-object-lifetime-in-coercion.rs:14:5 + | +LL | fn b(v: &[u8]) -> Box<dyn Foo + 'static> { + | - let's call the lifetime of this reference `'1` +LL | Box::new(v) + | ^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static` + | +help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v` + | +LL | fn b(v: &[u8]) -> Box<dyn Foo + '_> { + | ~~ +help: alternatively, add an explicit `'static` bound to this reference + | +LL | fn b(v: &'static [u8]) -> Box<dyn Foo + 'static> { + | ~~~~~~~~~~~~~ + +error: lifetime may not live long enough + --> $DIR/region-object-lifetime-in-coercion.rs:21:5 + | +LL | fn c(v: &[u8]) -> Box<dyn Foo> { + | - let's call the lifetime of this reference `'1` +... +LL | Box::new(v) + | ^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static` + | +help: to declare that the trait object captures data from argument `v`, you can add an explicit `'_` lifetime bound + | +LL | fn c(v: &[u8]) -> Box<dyn Foo + '_> { + | ++++ + +error: lifetime may not live long enough + --> $DIR/region-object-lifetime-in-coercion.rs:26:5 + | +LL | fn d<'a,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | Box::new(v) + | ^^^^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + | + = help: consider adding the following bound: `'a: 'b` + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/regions/regions-addr-of-arg.rs b/src/test/ui/regions/regions-addr-of-arg.rs new file mode 100644 index 000000000..1805141c4 --- /dev/null +++ b/src/test/ui/regions/regions-addr-of-arg.rs @@ -0,0 +1,17 @@ +// Check that taking the address of an argument yields a lifetime +// bounded by the current function call. + +fn foo(a: isize) { + let _p: &'static isize = &a; //~ ERROR `a` does not live long enough +} + +fn bar(a: isize) { + let _q: &isize = &a; +} + +fn zed<'a>(a: isize) -> &'a isize { + &a //~ ERROR cannot return reference to function parameter `a` +} + +fn main() { +} diff --git a/src/test/ui/regions/regions-addr-of-arg.stderr b/src/test/ui/regions/regions-addr-of-arg.stderr new file mode 100644 index 000000000..e77289287 --- /dev/null +++ b/src/test/ui/regions/regions-addr-of-arg.stderr @@ -0,0 +1,20 @@ +error[E0597]: `a` does not live long enough + --> $DIR/regions-addr-of-arg.rs:5:30 + | +LL | let _p: &'static isize = &a; + | -------------- ^^ borrowed value does not live long enough + | | + | type annotation requires that `a` is borrowed for `'static` +LL | } + | - `a` dropped here while still borrowed + +error[E0515]: cannot return reference to function parameter `a` + --> $DIR/regions-addr-of-arg.rs:13:5 + | +LL | &a + | ^^ returns a reference to data owned by the current function + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0515, E0597. +For more information about an error, try `rustc --explain E0515`. diff --git a/src/test/ui/regions/regions-addr-of-interior-of-unique-box.rs b/src/test/ui/regions/regions-addr-of-interior-of-unique-box.rs new file mode 100644 index 000000000..4221ebfdf --- /dev/null +++ b/src/test/ui/regions/regions-addr-of-interior-of-unique-box.rs @@ -0,0 +1,23 @@ +// run-pass +#![allow(dead_code)] + +// pretty-expanded FIXME #23616 + +struct Point { + x: isize, + y: isize +} + +struct Character { + pos: Box<Point>, +} + +fn get_x(x: &Character) -> &isize { + // interesting case because the scope of this + // borrow of the unique pointer is in fact + // larger than the fn itself + return &x.pos.x; +} + +pub fn main() { +} diff --git a/src/test/ui/regions/regions-addr-of-ret.rs b/src/test/ui/regions/regions-addr-of-ret.rs new file mode 100644 index 000000000..e5dcd6db0 --- /dev/null +++ b/src/test/ui/regions/regions-addr-of-ret.rs @@ -0,0 +1,9 @@ +// run-pass +fn f(x: &isize) -> &isize { + return &*x; +} + +pub fn main() { + let three = &3; + println!("{}", *f(three)); +} diff --git a/src/test/ui/regions/regions-addr-of-self.rs b/src/test/ui/regions/regions-addr-of-self.rs new file mode 100644 index 000000000..23647182f --- /dev/null +++ b/src/test/ui/regions/regions-addr-of-self.rs @@ -0,0 +1,28 @@ +struct Dog { + cats_chased: usize, +} + +impl Dog { + pub fn chase_cat(&mut self) { + let p: &'static mut usize = &mut self.cats_chased; + //~^ ERROR lifetime may not live long enough + *p += 1; + } + + pub fn chase_cat_2(&mut self) { + let p: &mut usize = &mut self.cats_chased; + *p += 1; + } +} + +fn dog() -> Dog { + Dog { + cats_chased: 0 + } +} + +fn main() { + let mut d = dog(); + d.chase_cat(); + println!("cats_chased: {}", d.cats_chased); +} diff --git a/src/test/ui/regions/regions-addr-of-self.stderr b/src/test/ui/regions/regions-addr-of-self.stderr new file mode 100644 index 000000000..3d7aac74b --- /dev/null +++ b/src/test/ui/regions/regions-addr-of-self.stderr @@ -0,0 +1,10 @@ +error: lifetime may not live long enough + --> $DIR/regions-addr-of-self.rs:7:16 + | +LL | pub fn chase_cat(&mut self) { + | - let's call the lifetime of this reference `'1` +LL | let p: &'static mut usize = &mut self.cats_chased; + | ^^^^^^^^^^^^^^^^^^ type annotation requires that `'1` must outlive `'static` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-addr-of-upvar-self.rs b/src/test/ui/regions/regions-addr-of-upvar-self.rs new file mode 100644 index 000000000..171eca32e --- /dev/null +++ b/src/test/ui/regions/regions-addr-of-upvar-self.rs @@ -0,0 +1,18 @@ +struct Dog { + food: usize, +} + +impl Dog { + pub fn chase_cat(&mut self) { + let _f = || { + let p: &'static mut usize = &mut self.food; + //~^ ERROR lifetime may not live long enough + //~^^ ERROR lifetime may not live long enough + //~^^^ ERROR E0597 + *p = 3; + }; + } +} + +fn main() { +} diff --git a/src/test/ui/regions/regions-addr-of-upvar-self.stderr b/src/test/ui/regions/regions-addr-of-upvar-self.stderr new file mode 100644 index 000000000..c16a6f858 --- /dev/null +++ b/src/test/ui/regions/regions-addr-of-upvar-self.stderr @@ -0,0 +1,35 @@ +error: lifetime may not live long enough + --> $DIR/regions-addr-of-upvar-self.rs:8:20 + | +LL | let _f = || { + | -- lifetime `'1` represents this closure's body +LL | let p: &'static mut usize = &mut self.food; + | ^^^^^^^^^^^^^^^^^^ type annotation requires that `'1` must outlive `'static` + | + = note: closure implements `FnMut`, so references to captured variables can't escape the closure + +error: lifetime may not live long enough + --> $DIR/regions-addr-of-upvar-self.rs:8:20 + | +LL | pub fn chase_cat(&mut self) { + | - let's call the lifetime of this reference `'1` +LL | let _f = || { +LL | let p: &'static mut usize = &mut self.food; + | ^^^^^^^^^^^^^^^^^^ type annotation requires that `'1` must outlive `'static` + +error[E0597]: `self` does not live long enough + --> $DIR/regions-addr-of-upvar-self.rs:8:46 + | +LL | let _f = || { + | -- value captured here +LL | let p: &'static mut usize = &mut self.food; + | ------------------ ^^^^^^^^^ borrowed value does not live long enough + | | + | type annotation requires that `self` is borrowed for `'static` +... +LL | } + | - `self` dropped here while still borrowed + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/regions/regions-adjusted-lvalue-op.rs b/src/test/ui/regions/regions-adjusted-lvalue-op.rs new file mode 100644 index 000000000..5aa5a3ecb --- /dev/null +++ b/src/test/ui/regions/regions-adjusted-lvalue-op.rs @@ -0,0 +1,16 @@ +// check that we link regions in mutable place ops correctly - issue #41774 + +struct Data(i32); + +trait OhNo { + fn oh_no(&mut self, other: &Vec<Data>) { loop {} } +} + +impl OhNo for Data {} +impl OhNo for [Data] {} + +fn main() { + let mut v = vec![Data(0)]; + v[0].oh_no(&v); //~ ERROR cannot borrow `v` as immutable because + (*v).oh_no(&v); //~ ERROR cannot borrow `v` as immutable because +} diff --git a/src/test/ui/regions/regions-adjusted-lvalue-op.stderr b/src/test/ui/regions/regions-adjusted-lvalue-op.stderr new file mode 100644 index 000000000..2c5563444 --- /dev/null +++ b/src/test/ui/regions/regions-adjusted-lvalue-op.stderr @@ -0,0 +1,21 @@ +error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable + --> $DIR/regions-adjusted-lvalue-op.rs:14:16 + | +LL | v[0].oh_no(&v); + | - ----- ^^ immutable borrow occurs here + | | | + | | mutable borrow later used by call + | mutable borrow occurs here + +error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable + --> $DIR/regions-adjusted-lvalue-op.rs:15:16 + | +LL | (*v).oh_no(&v); + | - ----- ^^ immutable borrow occurs here + | | | + | | mutable borrow later used by call + | mutable borrow occurs here + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.rs b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.rs new file mode 100644 index 000000000..eb6e66818 --- /dev/null +++ b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.rs @@ -0,0 +1,41 @@ +// Test that we are imposing the requirement that every associated +// type of a bound that appears in the where clause on a struct must +// outlive the location in which the type appears, even when the +// associted type is in a supertype. Issue #22246. + +#![allow(dead_code)] + +pub trait TheTrait { + type TheAssocType; +} + +pub trait TheSubTrait : TheTrait { +} + +pub struct TheType<'b> { + m: [fn(&'b()); 0] +} + +impl<'b> TheTrait for TheType<'b> { + type TheAssocType = &'b (); +} + +impl<'b> TheSubTrait for TheType<'b> { +} + +pub struct WithAssoc<T:TheSubTrait> { + m: [T; 0] +} + +fn with_assoc<'a,'b>() { + // For this type to be valid, the rules require that all + // associated types of traits that appear in `WithAssoc` must + // outlive 'a. In this case, that means TheType<'b>::TheAssocType, + // which is &'b (), must outlive 'a. + + let _: &'a WithAssoc<TheType<'b>> = loop { }; + //~^ ERROR lifetime may not live long enough +} + +fn main() { +} diff --git a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.stderr b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.stderr new file mode 100644 index 000000000..87e33e1cc --- /dev/null +++ b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.stderr @@ -0,0 +1,15 @@ +error: lifetime may not live long enough + --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:36:12 + | +LL | fn with_assoc<'a,'b>() { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | let _: &'a WithAssoc<TheType<'b>> = loop { }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.rs b/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.rs new file mode 100644 index 000000000..575dfafe1 --- /dev/null +++ b/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.rs @@ -0,0 +1,24 @@ +// Test that the compiler checks that arbitrary region bounds declared +// in the trait must be satisfied on the impl. Issue #20890. + +trait Foo<'a> { + type Value: 'a; + fn dummy(&'a self) {} +} + +impl<'a> Foo<'a> for &'a i16 { + // OK. + type Value = &'a i32; +} + +impl<'a> Foo<'static> for &'a i32 { + type Value = &'a i32; + //~^ ERROR the type `&'a i32` does not fulfill the required lifetime +} + +impl<'a, 'b> Foo<'b> for &'a i64 { + type Value = &'a i32; + //~^ ERROR the type `&'a i32` does not fulfill the required lifetime +} + +fn main() {} diff --git a/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr b/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr new file mode 100644 index 000000000..ac6154139 --- /dev/null +++ b/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr @@ -0,0 +1,27 @@ +error[E0477]: the type `&'a i32` does not fulfill the required lifetime + --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:15:18 + | +LL | type Value = &'a i32; + | ^^^^^^^ + | +note: type must satisfy the static lifetime as required by this binding + --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:5:17 + | +LL | type Value: 'a; + | ^^ + +error[E0477]: the type `&'a i32` does not fulfill the required lifetime + --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:20:18 + | +LL | type Value = &'a i32; + | ^^^^^^^ + | +note: type must outlive the lifetime `'b` as defined here as required by this binding + --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:19:10 + | +LL | impl<'a, 'b> Foo<'b> for &'a i64 { + | ^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0477`. diff --git a/src/test/ui/regions/regions-assoc-type-region-bound.rs b/src/test/ui/regions/regions-assoc-type-region-bound.rs new file mode 100644 index 000000000..cbb7d1726 --- /dev/null +++ b/src/test/ui/regions/regions-assoc-type-region-bound.rs @@ -0,0 +1,22 @@ +// run-pass +#![allow(dead_code)] +// Test that the compiler considers the 'a bound declared in the +// trait. Issue #20890. + +// pretty-expanded FIXME #23616 + +trait Foo<'a> { + type Value: 'a; + + fn get(&self) -> &'a Self::Value; +} + +fn takes_foo<'a,F: Foo<'a>>(f: &'a F) { + // This call would be illegal, because it results in &'a F::Value, + // and the only way we know that `F::Value : 'a` is because of the + // trait declaration. + + f.get(); +} + +fn main() { } diff --git a/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.rs b/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.rs new file mode 100644 index 000000000..00100e0e9 --- /dev/null +++ b/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.rs @@ -0,0 +1,19 @@ +// Test that the compiler checks that the 'static bound declared in +// the trait must be satisfied on the impl. Issue #20890. + +trait Foo { + type Value: 'static; + fn dummy(&self) {} +} + +impl<'a> Foo for &'a i32 { + type Value = &'a i32; + //~^ ERROR the type `&'a i32` does not fulfill the required lifetime +} + +impl<'a> Foo for i32 { + // OK. + type Value = i32; +} + +fn main() {} diff --git a/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr b/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr new file mode 100644 index 000000000..a96f5612f --- /dev/null +++ b/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr @@ -0,0 +1,15 @@ +error[E0477]: the type `&'a i32` does not fulfill the required lifetime + --> $DIR/regions-assoc-type-static-bound-in-trait-not-met.rs:10:18 + | +LL | type Value = &'a i32; + | ^^^^^^^ + | +note: type must satisfy the static lifetime as required by this binding + --> $DIR/regions-assoc-type-static-bound-in-trait-not-met.rs:5:17 + | +LL | type Value: 'static; + | ^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0477`. diff --git a/src/test/ui/regions/regions-assoc-type-static-bound.rs b/src/test/ui/regions/regions-assoc-type-static-bound.rs new file mode 100644 index 000000000..1458787ea --- /dev/null +++ b/src/test/ui/regions/regions-assoc-type-static-bound.rs @@ -0,0 +1,19 @@ +// run-pass +#![allow(dead_code)] +// Test that the compiler considers the 'static bound declared in the +// trait. Issue #20890. + +// pretty-expanded FIXME #23616 + +trait Foo { + type Value: 'static; + fn dummy(&self) { } +} + +fn require_static<T: 'static>() {} + +fn takes_foo<F: Foo>() { + require_static::<F::Value>() +} + +fn main() { } diff --git a/src/test/ui/regions/regions-borrow-at.rs b/src/test/ui/regions/regions-borrow-at.rs new file mode 100644 index 000000000..152abe109 --- /dev/null +++ b/src/test/ui/regions/regions-borrow-at.rs @@ -0,0 +1,12 @@ +// run-pass + +fn foo(x: &usize) -> usize { + *x +} + +pub fn main() { + let p: Box<_> = Box::new(22); + let r = foo(&*p); + println!("r={}", r); + assert_eq!(r, 22); +} diff --git a/src/test/ui/regions/regions-borrow-evec-fixed.rs b/src/test/ui/regions/regions-borrow-evec-fixed.rs new file mode 100644 index 000000000..ed828312b --- /dev/null +++ b/src/test/ui/regions/regions-borrow-evec-fixed.rs @@ -0,0 +1,10 @@ +// run-pass + +fn foo(x: &[isize]) -> isize { + x[0] +} + +pub fn main() { + let p = &[1,2,3,4,5]; + assert_eq!(foo(p), 1); +} diff --git a/src/test/ui/regions/regions-borrow-evec-uniq.rs b/src/test/ui/regions/regions-borrow-evec-uniq.rs new file mode 100644 index 000000000..bbf7ba79e --- /dev/null +++ b/src/test/ui/regions/regions-borrow-evec-uniq.rs @@ -0,0 +1,16 @@ +// run-pass + + +fn foo(x: &[isize]) -> isize { + x[0] +} + +pub fn main() { + let p = vec![1,2,3,4,5]; + let r = foo(&p); + assert_eq!(r, 1); + + let p = vec![5,4,3,2,1]; + let r = foo(&p); + assert_eq!(r, 5); +} diff --git a/src/test/ui/regions/regions-borrow-uniq.rs b/src/test/ui/regions/regions-borrow-uniq.rs new file mode 100644 index 000000000..adc6b1939 --- /dev/null +++ b/src/test/ui/regions/regions-borrow-uniq.rs @@ -0,0 +1,11 @@ +// run-pass + +fn foo(x: &usize) -> usize { + *x +} + +pub fn main() { + let p: Box<_> = Box::new(3); + let r = foo(&*p); + assert_eq!(r, 3); +} diff --git a/src/test/ui/regions/regions-bot.rs b/src/test/ui/regions/regions-bot.rs new file mode 100644 index 000000000..580162936 --- /dev/null +++ b/src/test/ui/regions/regions-bot.rs @@ -0,0 +1,11 @@ +// run-pass +#![allow(dead_code)] +// A very limited test of the "bottom" region + + +fn produce_static<T>() -> &'static T { panic!(); } + +fn foo<T>(_x: &T) -> &usize { produce_static() } + +pub fn main() { +} diff --git a/src/test/ui/regions/regions-bound-lists-feature-gate-2.rs b/src/test/ui/regions/regions-bound-lists-feature-gate-2.rs new file mode 100644 index 000000000..2c7503799 --- /dev/null +++ b/src/test/ui/regions/regions-bound-lists-feature-gate-2.rs @@ -0,0 +1,14 @@ +// run-pass +#![allow(dead_code)] +#![allow(stable_features)] + +#![feature(issue_5723_bootstrap)] + +trait Foo { + fn dummy(&self) { } +} + +fn foo<'a, 'b, 'c:'a+'b, 'd>() { +} + +pub fn main() { } diff --git a/src/test/ui/regions/regions-bound-lists-feature-gate.rs b/src/test/ui/regions/regions-bound-lists-feature-gate.rs new file mode 100644 index 000000000..3815498f8 --- /dev/null +++ b/src/test/ui/regions/regions-bound-lists-feature-gate.rs @@ -0,0 +1,18 @@ +// run-pass +#![allow(dead_code)] +#![allow(unused_variables)] +#![allow(stable_features)] + +#![feature(issue_5723_bootstrap)] + +trait Foo { + fn dummy(&self) { } +} + +fn foo<'a>(x: Box<dyn Foo + 'a>) { +} + +fn bar<'a, T: 'a>() { +} + +pub fn main() { } diff --git a/src/test/ui/regions/regions-bounded-by-trait-requiring-static.rs b/src/test/ui/regions/regions-bounded-by-trait-requiring-static.rs new file mode 100644 index 000000000..7d02a4619 --- /dev/null +++ b/src/test/ui/regions/regions-bounded-by-trait-requiring-static.rs @@ -0,0 +1,69 @@ +// Test which of the builtin types are considered sendable. The tests +// in this file all test region bound and lifetime violations that are +// detected during type check. + +trait Dummy : 'static { } +fn assert_send<T:'static>() { } + +// lifetime pointers with 'static lifetime are ok + +fn static_lifime_ok<'a,T,U:Send>(_: &'a isize) { + assert_send::<&'static isize>(); + assert_send::<&'static str>(); + assert_send::<&'static [isize]>(); + + // whether or not they are mutable + assert_send::<&'static mut isize>(); +} + +// otherwise lifetime pointers are not ok + +fn param_not_ok<'a>(x: &'a isize) { + assert_send::<&'a isize>(); + //~^ ERROR lifetime may not live long enough +} + +fn param_not_ok1<'a>(_: &'a isize) { + assert_send::<&'a str>(); + //~^ ERROR lifetime may not live long enough +} + +fn param_not_ok2<'a>(_: &'a isize) { + assert_send::<&'a [isize]>(); + //~^ ERROR lifetime may not live long enough +} + +// boxes are ok + +fn box_ok() { + assert_send::<Box<isize>>(); + assert_send::<String>(); + assert_send::<Vec<isize>>(); +} + +// but not if they own a bad thing + +fn box_with_region_not_ok<'a>() { + assert_send::<Box<&'a isize>>(); + //~^ ERROR lifetime may not live long enough +} + +// raw pointers are ok unless they point at unsendable things + +fn unsafe_ok1<'a>(_: &'a isize) { + assert_send::<*const isize>(); + assert_send::<*mut isize>(); +} + +fn unsafe_ok2<'a>(_: &'a isize) { + assert_send::<*const &'a isize>(); + //~^ ERROR lifetime may not live long enough +} + +fn unsafe_ok3<'a>(_: &'a isize) { + assert_send::<*mut &'a isize>(); + //~^ ERROR lifetime may not live long enough +} + +fn main() { +} diff --git a/src/test/ui/regions/regions-bounded-by-trait-requiring-static.stderr b/src/test/ui/regions/regions-bounded-by-trait-requiring-static.stderr new file mode 100644 index 000000000..eea68cc8f --- /dev/null +++ b/src/test/ui/regions/regions-bounded-by-trait-requiring-static.stderr @@ -0,0 +1,50 @@ +error: lifetime may not live long enough + --> $DIR/regions-bounded-by-trait-requiring-static.rs:22:5 + | +LL | fn param_not_ok<'a>(x: &'a isize) { + | -- lifetime `'a` defined here +LL | assert_send::<&'a isize>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/regions-bounded-by-trait-requiring-static.rs:27:5 + | +LL | fn param_not_ok1<'a>(_: &'a isize) { + | -- lifetime `'a` defined here +LL | assert_send::<&'a str>(); + | ^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/regions-bounded-by-trait-requiring-static.rs:32:5 + | +LL | fn param_not_ok2<'a>(_: &'a isize) { + | -- lifetime `'a` defined here +LL | assert_send::<&'a [isize]>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/regions-bounded-by-trait-requiring-static.rs:47:5 + | +LL | fn box_with_region_not_ok<'a>() { + | -- lifetime `'a` defined here +LL | assert_send::<Box<&'a isize>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/regions-bounded-by-trait-requiring-static.rs:59:5 + | +LL | fn unsafe_ok2<'a>(_: &'a isize) { + | -- lifetime `'a` defined here +LL | assert_send::<*const &'a isize>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/regions-bounded-by-trait-requiring-static.rs:64:5 + | +LL | fn unsafe_ok3<'a>(_: &'a isize) { + | -- lifetime `'a` defined here +LL | assert_send::<*mut &'a isize>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/regions/regions-bounded-method-type-parameters-cross-crate.rs b/src/test/ui/regions/regions-bounded-method-type-parameters-cross-crate.rs new file mode 100644 index 000000000..c014b2ccf --- /dev/null +++ b/src/test/ui/regions/regions-bounded-method-type-parameters-cross-crate.rs @@ -0,0 +1,24 @@ +// aux-build:rbmtp_cross_crate_lib.rs + +// Check explicit region bounds on methods in the cross crate case. + +extern crate rbmtp_cross_crate_lib as lib; + +use lib::Inv; +use lib::MaybeOwned; +use lib::IntoMaybeOwned; + +fn call_into_maybe_owned<'x,F:IntoMaybeOwned<'x>>(f: F) { + // Exercise a code path I found to be buggy. We were not encoding + // the region parameters from the receiver correctly on trait + // methods. + f.into_maybe_owned(); +} + +fn call_bigger_region<'x, 'y>(a: Inv<'x>, b: Inv<'y>) { + // Here the value provided for 'y is 'y, and hence 'y:'x does not hold. + a.bigger_region(b) + //~^ ERROR lifetime may not live long enough +} + +fn main() { } diff --git a/src/test/ui/regions/regions-bounded-method-type-parameters-cross-crate.stderr b/src/test/ui/regions/regions-bounded-method-type-parameters-cross-crate.stderr new file mode 100644 index 000000000..6193bf02f --- /dev/null +++ b/src/test/ui/regions/regions-bounded-method-type-parameters-cross-crate.stderr @@ -0,0 +1,18 @@ +error: lifetime may not live long enough + --> $DIR/regions-bounded-method-type-parameters-cross-crate.rs:20:5 + | +LL | fn call_bigger_region<'x, 'y>(a: Inv<'x>, b: Inv<'y>) { + | -- -- lifetime `'y` defined here + | | + | lifetime `'x` defined here +LL | // Here the value provided for 'y is 'y, and hence 'y:'x does not hold. +LL | a.bigger_region(b) + | ^^^^^^^^^^^^^^^^^^ argument requires that `'y` must outlive `'x` + | + = help: consider adding the following bound: `'y: 'x` + = note: requirement occurs because of the type `Inv<'_>`, which makes the generic argument `'_` invariant + = note: the struct `Inv<'a>` is invariant over the parameter `'a` + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.rs b/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.rs new file mode 100644 index 000000000..5548cb915 --- /dev/null +++ b/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.rs @@ -0,0 +1,29 @@ +// Check that explicit region bounds are allowed on the various +// nominal types (but not on other types) and that they are type +// checked. + +struct Inv<'a> { // invariant w/r/t 'a + x: &'a mut &'a isize +} + +trait Foo<'x> { + fn method<'y:'x>(self, y: Inv<'y>); +} + +fn caller1<'a,'b,F:Foo<'a>>(a: Inv<'a>, b: Inv<'b>, f: F) { + // Here the value provided for 'y is 'a, and hence 'a:'a holds. + f.method(a); +} + +fn caller2<'a,'b,F:Foo<'a>>(a: Inv<'a>, b: Inv<'b>, f: F) { + // Here the value provided for 'y is 'b, and hence 'b:'a does not hold. + f.method(b); + //~^ ERROR lifetime may not live long enough +} + +fn caller3<'a,'b:'a,F:Foo<'a>>(a: Inv<'a>, b: Inv<'b>, f: F) { + // Here the value provided for 'y is 'b, and hence 'b:'a holds. + f.method(b); +} + +fn main() { } diff --git a/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.stderr b/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.stderr new file mode 100644 index 000000000..0e0086be9 --- /dev/null +++ b/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.stderr @@ -0,0 +1,18 @@ +error: lifetime may not live long enough + --> $DIR/regions-bounded-method-type-parameters-trait-bound.rs:20:5 + | +LL | fn caller2<'a,'b,F:Foo<'a>>(a: Inv<'a>, b: Inv<'b>, f: F) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | // Here the value provided for 'y is 'b, and hence 'b:'a does not hold. +LL | f.method(b); + | ^^^^^^^^^^^ argument requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of the type `Inv<'_>`, which makes the generic argument `'_` invariant + = note: the struct `Inv<'a>` is invariant over the parameter `'a` + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-bounded-method-type-parameters.rs b/src/test/ui/regions/regions-bounded-method-type-parameters.rs new file mode 100644 index 000000000..56e750003 --- /dev/null +++ b/src/test/ui/regions/regions-bounded-method-type-parameters.rs @@ -0,0 +1,16 @@ +// Check that explicit region bounds are allowed on the various +// nominal types (but not on other types) and that they are type +// checked. + +struct Foo; + +impl Foo { + fn some_method<A:'static>(self) { } +} + +fn caller<'a>(x: &isize) { + Foo.some_method::<&'a isize>(); + //~^ ERROR lifetime may not live long enough +} + +fn main() { } diff --git a/src/test/ui/regions/regions-bounded-method-type-parameters.stderr b/src/test/ui/regions/regions-bounded-method-type-parameters.stderr new file mode 100644 index 000000000..b6d7b8aac --- /dev/null +++ b/src/test/ui/regions/regions-bounded-method-type-parameters.stderr @@ -0,0 +1,10 @@ +error: lifetime may not live long enough + --> $DIR/regions-bounded-method-type-parameters.rs:12:9 + | +LL | fn caller<'a>(x: &isize) { + | -- lifetime `'a` defined here +LL | Foo.some_method::<&'a isize>(); + | ^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-bounds.rs b/src/test/ui/regions/regions-bounds.rs new file mode 100644 index 000000000..fd4d75ab6 --- /dev/null +++ b/src/test/ui/regions/regions-bounds.rs @@ -0,0 +1,18 @@ +// Check that explicit region bounds are allowed on the various +// nominal types (but not on other types) and that they are type +// checked. + +struct TupleStruct<'a>(&'a isize); +struct Struct<'a> { x:&'a isize } + +fn a_fn1<'a,'b>(e: TupleStruct<'a>) -> TupleStruct<'b> { + return e; + //~^ ERROR lifetime may not live long enough +} + +fn a_fn3<'a,'b>(e: Struct<'a>) -> Struct<'b> { + return e; + //~^ ERROR lifetime may not live long enough +} + +fn main() { } diff --git a/src/test/ui/regions/regions-bounds.stderr b/src/test/ui/regions/regions-bounds.stderr new file mode 100644 index 000000000..430909e54 --- /dev/null +++ b/src/test/ui/regions/regions-bounds.stderr @@ -0,0 +1,26 @@ +error: lifetime may not live long enough + --> $DIR/regions-bounds.rs:9:12 + | +LL | fn a_fn1<'a,'b>(e: TupleStruct<'a>) -> TupleStruct<'b> { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | return e; + | ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + | + = help: consider adding the following bound: `'a: 'b` + +error: lifetime may not live long enough + --> $DIR/regions-bounds.rs:14:12 + | +LL | fn a_fn3<'a,'b>(e: Struct<'a>) -> Struct<'b> { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | return e; + | ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + | + = help: consider adding the following bound: `'a: 'b` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/regions/regions-close-associated-type-into-object.rs b/src/test/ui/regions/regions-close-associated-type-into-object.rs new file mode 100644 index 000000000..428477e24 --- /dev/null +++ b/src/test/ui/regions/regions-close-associated-type-into-object.rs @@ -0,0 +1,71 @@ +trait X {} + + + +trait Iter { + type Item: X; + + fn into_item(self) -> Self::Item; + fn as_item(&self) -> &Self::Item; +} + +fn bad1<T: Iter>(v: T) -> Box<dyn X + 'static> +{ + let item = v.into_item(); + Box::new(item) //~ ERROR associated type `<T as Iter>::Item` may not live long enough +} + +fn bad2<T: Iter>(v: T) -> Box<dyn X + 'static> + where Box<T::Item> : X +{ + let item: Box<_> = Box::new(v.into_item()); + Box::new(item) //~ ERROR associated type `<T as Iter>::Item` may not live long enough +} + +fn bad3<'a, T: Iter>(v: T) -> Box<dyn X + 'a> +{ + let item = v.into_item(); + Box::new(item) //~ ERROR associated type `<T as Iter>::Item` may not live long enough +} + +fn bad4<'a, T: Iter>(v: T) -> Box<dyn X + 'a> + where Box<T::Item> : X +{ + let item: Box<_> = Box::new(v.into_item()); + Box::new(item) //~ ERROR associated type `<T as Iter>::Item` may not live long enough +} + +fn ok1<'a, T: Iter>(v: T) -> Box<dyn X + 'a> + where T::Item : 'a +{ + let item = v.into_item(); + Box::new(item) // OK, T::Item : 'a is declared +} + +fn ok2<'a, T: Iter>(v: &T, w: &'a T::Item) -> Box<dyn X + 'a> + where T::Item : Clone +{ + let item = Clone::clone(w); + Box::new(item) // OK, T::Item : 'a is implied +} + +fn ok3<'a, T: Iter>(v: &'a T) -> Box<dyn X + 'a> + where T::Item : Clone + 'a +{ + let item = Clone::clone(v.as_item()); + Box::new(item) // OK, T::Item : 'a was declared +} + +fn meh1<'a, T: Iter>(v: &'a T) -> Box<dyn X + 'a> + where T::Item : Clone +{ + // This case is kind of interesting. It's the same as `ok3` but + // without the explicit declaration. This is valid because `T: 'a + // => T::Item: 'a`, and the former we can deduce from our argument + // of type `&'a T`. + + let item = Clone::clone(v.as_item()); + Box::new(item) +} + +fn main() {} diff --git a/src/test/ui/regions/regions-close-associated-type-into-object.stderr b/src/test/ui/regions/regions-close-associated-type-into-object.stderr new file mode 100644 index 000000000..f7dcaa9d9 --- /dev/null +++ b/src/test/ui/regions/regions-close-associated-type-into-object.stderr @@ -0,0 +1,40 @@ +error[E0310]: the associated type `<T as Iter>::Item` may not live long enough + --> $DIR/regions-close-associated-type-into-object.rs:15:5 + | +LL | Box::new(item) + | ^^^^^^^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `<T as Iter>::Item: 'static`... + = note: ...so that the type `<T as Iter>::Item` will meet its required lifetime bounds + +error[E0310]: the associated type `<T as Iter>::Item` may not live long enough + --> $DIR/regions-close-associated-type-into-object.rs:22:5 + | +LL | Box::new(item) + | ^^^^^^^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `<T as Iter>::Item: 'static`... + = note: ...so that the type `<T as Iter>::Item` will meet its required lifetime bounds + +error[E0309]: the associated type `<T as Iter>::Item` may not live long enough + --> $DIR/regions-close-associated-type-into-object.rs:28:5 + | +LL | Box::new(item) + | ^^^^^^^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `<T as Iter>::Item: 'a`... + = note: ...so that the type `<T as Iter>::Item` will meet its required lifetime bounds + +error[E0309]: the associated type `<T as Iter>::Item` may not live long enough + --> $DIR/regions-close-associated-type-into-object.rs:35:5 + | +LL | Box::new(item) + | ^^^^^^^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `<T as Iter>::Item: 'a`... + = note: ...so that the type `<T as Iter>::Item` will meet its required lifetime bounds + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0309, E0310. +For more information about an error, try `rustc --explain E0309`. diff --git a/src/test/ui/regions/regions-close-object-into-object-1.rs b/src/test/ui/regions/regions-close-object-into-object-1.rs new file mode 100644 index 000000000..2dc33d567 --- /dev/null +++ b/src/test/ui/regions/regions-close-object-into-object-1.rs @@ -0,0 +1,15 @@ +#![allow(warnings)] + +trait A<T> { } + +struct B<'a, T:'a>(&'a (A<T>+'a)); + +trait X { } + +impl<'a, T> X for B<'a, T> {} + +fn f<'a, T:'static, U>(v: Box<A<T>+'static>) -> Box<X+'static> { + Box::new(B(&*v)) as Box<X> //~ ERROR cannot return value referencing local data `*v` +} + +fn main() {} diff --git a/src/test/ui/regions/regions-close-object-into-object-1.stderr b/src/test/ui/regions/regions-close-object-into-object-1.stderr new file mode 100644 index 000000000..5bfaeb295 --- /dev/null +++ b/src/test/ui/regions/regions-close-object-into-object-1.stderr @@ -0,0 +1,12 @@ +error[E0515]: cannot return value referencing local data `*v` + --> $DIR/regions-close-object-into-object-1.rs:12:5 + | +LL | Box::new(B(&*v)) as Box<X> + | ^^^^^^^^^^^---^^^^^^^^^^^^ + | | | + | | `*v` is borrowed here + | returns a value referencing data owned by the current function + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/regions/regions-close-object-into-object-2.rs b/src/test/ui/regions/regions-close-object-into-object-2.rs new file mode 100644 index 000000000..6960af72c --- /dev/null +++ b/src/test/ui/regions/regions-close-object-into-object-2.rs @@ -0,0 +1,14 @@ +trait A<T> { } + +struct B<'a, T:'a>(&'a (dyn A<T> + 'a)); + +trait X { } +impl<'a, T> X for B<'a, T> {} + +fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> { + Box::new(B(&*v)) as Box<dyn X> + //~^ ERROR lifetime may not live long enough + //~| ERROR cannot return value referencing local data `*v` [E0515] +} + +fn main() { } diff --git a/src/test/ui/regions/regions-close-object-into-object-2.stderr b/src/test/ui/regions/regions-close-object-into-object-2.stderr new file mode 100644 index 000000000..aacb5ea4e --- /dev/null +++ b/src/test/ui/regions/regions-close-object-into-object-2.stderr @@ -0,0 +1,29 @@ +error: lifetime may not live long enough + --> $DIR/regions-close-object-into-object-2.rs:9:5 + | +LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> { + | -- lifetime `'a` defined here +LL | Box::new(B(&*v)) as Box<dyn X> + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` + | +help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v` + | +LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'a> { + | ~~ +help: alternatively, add an explicit `'static` bound to this reference + | +LL | fn g<'a, T: 'static>(v: Box<(dyn A<T> + 'static)>) -> Box<dyn X + 'static> { + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error[E0515]: cannot return value referencing local data `*v` + --> $DIR/regions-close-object-into-object-2.rs:9:5 + | +LL | Box::new(B(&*v)) as Box<dyn X> + | ^^^^^^^^^^^---^^^^^^^^^^^^^^^^ + | | | + | | `*v` is borrowed here + | returns a value referencing data owned by the current function + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/regions/regions-close-object-into-object-3.rs b/src/test/ui/regions/regions-close-object-into-object-3.rs new file mode 100644 index 000000000..78d93b0ec --- /dev/null +++ b/src/test/ui/regions/regions-close-object-into-object-3.rs @@ -0,0 +1,14 @@ +#![allow(warnings)] + +trait A<T> { } + +struct B<'a, T:'a>(&'a (A<T>+'a)); + +trait X { } +impl<'a, T> X for B<'a, T> {} + +fn h<'a, T, U:'static>(v: Box<A<U>+'static>) -> Box<X+'static> { + Box::new(B(&*v)) as Box<X> //~ ERROR cannot return value referencing local data `*v` +} + +fn main() {} diff --git a/src/test/ui/regions/regions-close-object-into-object-3.stderr b/src/test/ui/regions/regions-close-object-into-object-3.stderr new file mode 100644 index 000000000..9f92c40e1 --- /dev/null +++ b/src/test/ui/regions/regions-close-object-into-object-3.stderr @@ -0,0 +1,12 @@ +error[E0515]: cannot return value referencing local data `*v` + --> $DIR/regions-close-object-into-object-3.rs:11:5 + | +LL | Box::new(B(&*v)) as Box<X> + | ^^^^^^^^^^^---^^^^^^^^^^^^ + | | | + | | `*v` is borrowed here + | returns a value referencing data owned by the current function + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/regions/regions-close-object-into-object-4.rs b/src/test/ui/regions/regions-close-object-into-object-4.rs new file mode 100644 index 000000000..3bbad9cbf --- /dev/null +++ b/src/test/ui/regions/regions-close-object-into-object-4.rs @@ -0,0 +1,19 @@ +trait A<T> { } + +struct B<'a, T:'a>(&'a (dyn A<T> + 'a)); + +trait X { } +impl<'a, T> X for B<'a, T> {} + +fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> { + Box::new(B(&*v)) as Box<dyn X> + //~^ ERROR the parameter type `U` may not live long enough [E0310] + //~| ERROR the parameter type `U` may not live long enough [E0310] + //~| ERROR the parameter type `U` may not live long enough [E0310] + //~| ERROR lifetime may not live long enough + //~| ERROR cannot return value referencing local data `*v` [E0515] + //~| ERROR the parameter type `U` may not live long enough [E0310] + +} + +fn main() {} diff --git a/src/test/ui/regions/regions-close-object-into-object-4.stderr b/src/test/ui/regions/regions-close-object-into-object-4.stderr new file mode 100644 index 000000000..7a9f1ab00 --- /dev/null +++ b/src/test/ui/regions/regions-close-object-into-object-4.stderr @@ -0,0 +1,74 @@ +error[E0310]: the parameter type `U` may not live long enough + --> $DIR/regions-close-object-into-object-4.rs:9:5 + | +LL | Box::new(B(&*v)) as Box<dyn X> + | ^^^^^^^^ ...so that the type `U` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn i<'a, T, U: 'static>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> { + | +++++++++ + +error[E0310]: the parameter type `U` may not live long enough + --> $DIR/regions-close-object-into-object-4.rs:9:5 + | +LL | Box::new(B(&*v)) as Box<dyn X> + | ^^^^^^^^^^^^^^^^ ...so that the type `U` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn i<'a, T, U: 'static>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> { + | +++++++++ + +error[E0310]: the parameter type `U` may not live long enough + --> $DIR/regions-close-object-into-object-4.rs:9:5 + | +LL | Box::new(B(&*v)) as Box<dyn X> + | ^^^^^^^^^^^^^^^^ ...so that the type `U` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn i<'a, T, U: 'static>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> { + | +++++++++ + +error: lifetime may not live long enough + --> $DIR/regions-close-object-into-object-4.rs:9:5 + | +LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> { + | -- lifetime `'a` defined here +LL | Box::new(B(&*v)) as Box<dyn X> + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` + | +help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v` + | +LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'a> { + | ~~ +help: alternatively, add an explicit `'static` bound to this reference + | +LL | fn i<'a, T, U>(v: Box<(dyn A<U> + 'static)>) -> Box<dyn X + 'static> { + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error[E0515]: cannot return value referencing local data `*v` + --> $DIR/regions-close-object-into-object-4.rs:9:5 + | +LL | Box::new(B(&*v)) as Box<dyn X> + | ^^^^^^^^^^^---^^^^^^^^^^^^^^^^ + | | | + | | `*v` is borrowed here + | returns a value referencing data owned by the current function + +error[E0310]: the parameter type `U` may not live long enough + --> $DIR/regions-close-object-into-object-4.rs:9:14 + | +LL | Box::new(B(&*v)) as Box<dyn X> + | ^^^^^^ ...so that the type `U` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn i<'a, T, U: 'static>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> { + | +++++++++ + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0310, E0515. +For more information about an error, try `rustc --explain E0310`. diff --git a/src/test/ui/regions/regions-close-object-into-object-5.rs b/src/test/ui/regions/regions-close-object-into-object-5.rs new file mode 100644 index 000000000..d534c3749 --- /dev/null +++ b/src/test/ui/regions/regions-close-object-into-object-5.rs @@ -0,0 +1,25 @@ +#![allow(warnings)] + + +trait A<T> +{ + fn get(&self) -> T { panic!() } +} + +struct B<'a, T: 'a>(&'a (A<T> + 'a)); + +trait X { fn foo(&self) {} } + +impl<'a, T> X for B<'a, T> {} + +fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> { + // oh dear! + Box::new(B(&*v)) as Box<dyn X> + //~^ ERROR the parameter type `T` may not live long enough + //~| ERROR the parameter type `T` may not live long enough + //~| ERROR the parameter type `T` may not live long enough + //~| ERROR the parameter type `T` may not live long enough + //~| ERROR cannot return value referencing local data `*v` [E0515] +} + +fn main() {} diff --git a/src/test/ui/regions/regions-close-object-into-object-5.stderr b/src/test/ui/regions/regions-close-object-into-object-5.stderr new file mode 100644 index 000000000..311e8868c --- /dev/null +++ b/src/test/ui/regions/regions-close-object-into-object-5.stderr @@ -0,0 +1,57 @@ +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/regions-close-object-into-object-5.rs:17:5 + | +LL | Box::new(B(&*v)) as Box<dyn X> + | ^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn f<'a, T: 'static, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> { + | +++++++++ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/regions-close-object-into-object-5.rs:17:5 + | +LL | Box::new(B(&*v)) as Box<dyn X> + | ^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn f<'a, T: 'static, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> { + | +++++++++ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/regions-close-object-into-object-5.rs:17:5 + | +LL | Box::new(B(&*v)) as Box<dyn X> + | ^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn f<'a, T: 'static, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> { + | +++++++++ + +error[E0515]: cannot return value referencing local data `*v` + --> $DIR/regions-close-object-into-object-5.rs:17:5 + | +LL | Box::new(B(&*v)) as Box<dyn X> + | ^^^^^^^^^^^---^^^^^^^^^^^^^^^^ + | | | + | | `*v` is borrowed here + | returns a value referencing data owned by the current function + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/regions-close-object-into-object-5.rs:17:14 + | +LL | Box::new(B(&*v)) as Box<dyn X> + | ^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn f<'a, T: 'static, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> { + | +++++++++ + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0310, E0515. +For more information about an error, try `rustc --explain E0310`. diff --git a/src/test/ui/regions/regions-close-over-type-parameter-1.rs b/src/test/ui/regions/regions-close-over-type-parameter-1.rs new file mode 100644 index 000000000..610f75745 --- /dev/null +++ b/src/test/ui/regions/regions-close-over-type-parameter-1.rs @@ -0,0 +1,24 @@ +// Test for what happens when a type parameter `A` is closed over into +// an object. This should yield errors unless `A` (and the object) +// both have suitable bounds. + +trait SomeTrait { + fn get(&self) -> isize; +} + + +fn make_object1<A: SomeTrait>(v: A) -> Box<dyn SomeTrait + 'static> { + Box::new(v) as Box<dyn SomeTrait + 'static> + //~^ ERROR the parameter type `A` may not live long enough +} + +fn make_object2<'a, A: SomeTrait + 'a>(v: A) -> Box<dyn SomeTrait + 'a> { + Box::new(v) as Box<dyn SomeTrait + 'a> +} + +fn make_object3<'a, 'b, A: SomeTrait + 'a>(v: A) -> Box<dyn SomeTrait + 'b> { + Box::new(v) as Box<dyn SomeTrait + 'b> + //~^ ERROR the parameter type `A` may not live long enough +} + +fn main() {} diff --git a/src/test/ui/regions/regions-close-over-type-parameter-1.stderr b/src/test/ui/regions/regions-close-over-type-parameter-1.stderr new file mode 100644 index 000000000..b7b557d7a --- /dev/null +++ b/src/test/ui/regions/regions-close-over-type-parameter-1.stderr @@ -0,0 +1,26 @@ +error[E0310]: the parameter type `A` may not live long enough + --> $DIR/regions-close-over-type-parameter-1.rs:11:5 + | +LL | Box::new(v) as Box<dyn SomeTrait + 'static> + | ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn make_object1<A: SomeTrait + 'static>(v: A) -> Box<dyn SomeTrait + 'static> { + | +++++++++ + +error[E0309]: the parameter type `A` may not live long enough + --> $DIR/regions-close-over-type-parameter-1.rs:20:5 + | +LL | Box::new(v) as Box<dyn SomeTrait + 'b> + | ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn make_object3<'a, 'b, A: SomeTrait + 'a + 'b>(v: A) -> Box<dyn SomeTrait + 'b> { + | ++++ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0309, E0310. +For more information about an error, try `rustc --explain E0309`. diff --git a/src/test/ui/regions/regions-close-over-type-parameter-multiple.rs b/src/test/ui/regions/regions-close-over-type-parameter-multiple.rs new file mode 100644 index 000000000..e032a94c3 --- /dev/null +++ b/src/test/ui/regions/regions-close-over-type-parameter-multiple.rs @@ -0,0 +1,24 @@ +// Various tests where we over type parameters with multiple lifetime +// bounds. + +trait SomeTrait { fn get(&self) -> isize; } + + +fn make_object_good1<'a,'b,A:SomeTrait+'a+'b>(v: A) -> Box<dyn SomeTrait + 'a> { + // A outlives 'a AND 'b... + Box::new(v) as Box<dyn SomeTrait + 'a> // ...hence this type is safe. +} + +fn make_object_good2<'a,'b,A:SomeTrait+'a+'b>(v: A) -> Box<dyn SomeTrait + 'b> { + // A outlives 'a AND 'b... + Box::new(v) as Box<dyn SomeTrait + 'b> // ...hence this type is safe. +} + +fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<dyn SomeTrait + 'c> { + // A outlives 'a AND 'b...but not 'c. + Box::new(v) as Box<dyn SomeTrait + 'a> + //~^ ERROR lifetime may not live long enough +} + +fn main() { +} diff --git a/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr b/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr new file mode 100644 index 000000000..baa0506d0 --- /dev/null +++ b/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr @@ -0,0 +1,15 @@ +error: lifetime may not live long enough + --> $DIR/regions-close-over-type-parameter-multiple.rs:19:5 + | +LL | fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<dyn SomeTrait + 'c> { + | -- -- lifetime `'c` defined here + | | + | lifetime `'a` defined here +LL | // A outlives 'a AND 'b...but not 'c. +LL | Box::new(v) as Box<dyn SomeTrait + 'a> + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'c` but it is returning data with lifetime `'a` + | + = help: consider adding the following bound: `'a: 'c` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-close-over-type-parameter-successfully.rs b/src/test/ui/regions/regions-close-over-type-parameter-successfully.rs new file mode 100644 index 000000000..48aad9481 --- /dev/null +++ b/src/test/ui/regions/regions-close-over-type-parameter-successfully.rs @@ -0,0 +1,21 @@ +// run-pass +// A test where we (successfully) close over a reference into +// an object. + +trait SomeTrait { fn get(&self) -> isize; } + +impl<'a> SomeTrait for &'a isize { + fn get(&self) -> isize { + **self + } +} + +fn make_object<'a,A:SomeTrait+'a>(v: A) -> Box<dyn SomeTrait+'a> { + Box::new(v) as Box<dyn SomeTrait+'a> +} + +fn main() { + let i: isize = 22; + let obj = make_object(&i); + assert_eq!(22, obj.get()); +} diff --git a/src/test/ui/regions/regions-close-param-into-object.rs b/src/test/ui/regions/regions-close-param-into-object.rs new file mode 100644 index 000000000..2760e5eed --- /dev/null +++ b/src/test/ui/regions/regions-close-param-into-object.rs @@ -0,0 +1,27 @@ +trait X { fn foo(&self) {} } + +fn p1<T>(v: T) -> Box<dyn X + 'static> + where T : X +{ + Box::new(v) //~ ERROR parameter type `T` may not live long enough +} + +fn p2<T>(v: Box<T>) -> Box<dyn X + 'static> + where Box<T> : X +{ + Box::new(v) //~ ERROR parameter type `T` may not live long enough +} + +fn p3<'a,T>(v: T) -> Box<dyn X + 'a> + where T : X +{ + Box::new(v) //~ ERROR parameter type `T` may not live long enough +} + +fn p4<'a,T>(v: Box<T>) -> Box<dyn X + 'a> + where Box<T> : X +{ + Box::new(v) //~ ERROR parameter type `T` may not live long enough +} + +fn main() {} diff --git a/src/test/ui/regions/regions-close-param-into-object.stderr b/src/test/ui/regions/regions-close-param-into-object.stderr new file mode 100644 index 000000000..9162be5b9 --- /dev/null +++ b/src/test/ui/regions/regions-close-param-into-object.stderr @@ -0,0 +1,48 @@ +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/regions-close-param-into-object.rs:6:5 + | +LL | Box::new(v) + | ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | where T : X + 'static + | +++++++++ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/regions-close-param-into-object.rs:12:5 + | +LL | Box::new(v) + | ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn p2<T: 'static>(v: Box<T>) -> Box<dyn X + 'static> + | +++++++++ + +error[E0309]: the parameter type `T` may not live long enough + --> $DIR/regions-close-param-into-object.rs:18:5 + | +LL | Box::new(v) + | ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | where T : X + 'a + | ++++ + +error[E0309]: the parameter type `T` may not live long enough + --> $DIR/regions-close-param-into-object.rs:24:5 + | +LL | Box::new(v) + | ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn p4<'a,T: 'a>(v: Box<T>) -> Box<dyn X + 'a> + | ++++ + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0309, E0310. +For more information about an error, try `rustc --explain E0309`. diff --git a/src/test/ui/regions/regions-copy-closure.rs b/src/test/ui/regions/regions-copy-closure.rs new file mode 100644 index 000000000..436400797 --- /dev/null +++ b/src/test/ui/regions/regions-copy-closure.rs @@ -0,0 +1,21 @@ +// run-pass +#![allow(non_camel_case_types)] + +struct closure_box<'a> { + cl: Box<dyn FnMut() + 'a>, +} + +fn box_it<'a>(x: Box<dyn FnMut() + 'a>) -> closure_box<'a> { + closure_box {cl: x} +} + +pub fn main() { + let mut i = 3; + assert_eq!(i, 3); + { + let cl = || i += 1; + let mut cl_box = box_it(Box::new(cl)); + (cl_box.cl)(); + } + assert_eq!(i, 4); +} diff --git a/src/test/ui/regions/regions-creating-enums.rs b/src/test/ui/regions/regions-creating-enums.rs new file mode 100644 index 000000000..6ed68f803 --- /dev/null +++ b/src/test/ui/regions/regions-creating-enums.rs @@ -0,0 +1,33 @@ +enum Ast<'a> { + Num(usize), + Add(&'a Ast<'a>, &'a Ast<'a>) +} + +fn build() { + let x = Ast::Num(3); + let y = Ast::Num(4); + let z = Ast::Add(&x, &y); + compute(&z); +} + +fn compute(x: &Ast) -> usize { + match *x { + Ast::Num(x) => { x } + Ast::Add(x, y) => { compute(x) + compute(y) } + } +} + +fn map_nums<'a,'b, F>(x: &Ast, f: &mut F) -> &'a Ast<'b> where F: FnMut(usize) -> usize { + match *x { + Ast::Num(x) => { + return &Ast::Num((*f)(x)); //~ ERROR cannot return reference to temporary value + } + Ast::Add(x, y) => { + let m_x = map_nums(x, f); + let m_y = map_nums(y, f); + return &Ast::Add(m_x, m_y); //~ ERROR cannot return reference to temporary value + } + } +} + +fn main() {} diff --git a/src/test/ui/regions/regions-creating-enums.stderr b/src/test/ui/regions/regions-creating-enums.stderr new file mode 100644 index 000000000..a95d84629 --- /dev/null +++ b/src/test/ui/regions/regions-creating-enums.stderr @@ -0,0 +1,21 @@ +error[E0515]: cannot return reference to temporary value + --> $DIR/regions-creating-enums.rs:23:16 + | +LL | return &Ast::Num((*f)(x)); + | ^----------------- + | || + | |temporary value created here + | returns a reference to data owned by the current function + +error[E0515]: cannot return reference to temporary value + --> $DIR/regions-creating-enums.rs:28:16 + | +LL | return &Ast::Add(m_x, m_y); + | ^------------------ + | || + | |temporary value created here + | returns a reference to data owned by the current function + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/regions/regions-creating-enums2.rs b/src/test/ui/regions/regions-creating-enums2.rs new file mode 100644 index 000000000..7b16fb1a8 --- /dev/null +++ b/src/test/ui/regions/regions-creating-enums2.rs @@ -0,0 +1,17 @@ +// run-pass +#![allow(dead_code)] +#![allow(non_camel_case_types)] + +// pretty-expanded FIXME #23616 + +enum ast<'a> { + num(usize), + add(&'a ast<'a>, &'a ast<'a>) +} + +fn mk_add_ok<'r>(x: &'r ast<'r>, y: &'r ast<'r>) -> ast<'r> { + ast::add(x, y) +} + +pub fn main() { +} diff --git a/src/test/ui/regions/regions-creating-enums3.rs b/src/test/ui/regions/regions-creating-enums3.rs new file mode 100644 index 000000000..39dbb3d8a --- /dev/null +++ b/src/test/ui/regions/regions-creating-enums3.rs @@ -0,0 +1,12 @@ +enum Ast<'a> { + Num(usize), + Add(&'a Ast<'a>, &'a Ast<'a>) +} + +fn mk_add_bad1<'a,'b>(x: &'a Ast<'a>, y: &'b Ast<'b>) -> Ast<'a> { + Ast::Add(x, y) + //~^ ERROR lifetime may not live long enough +} + +fn main() { +} diff --git a/src/test/ui/regions/regions-creating-enums3.stderr b/src/test/ui/regions/regions-creating-enums3.stderr new file mode 100644 index 000000000..41d609b56 --- /dev/null +++ b/src/test/ui/regions/regions-creating-enums3.stderr @@ -0,0 +1,14 @@ +error: lifetime may not live long enough + --> $DIR/regions-creating-enums3.rs:7:5 + | +LL | fn mk_add_bad1<'a,'b>(x: &'a Ast<'a>, y: &'b Ast<'b>) -> Ast<'a> { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | Ast::Add(x, y) + | ^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` + | + = help: consider adding the following bound: `'b: 'a` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-creating-enums4.rs b/src/test/ui/regions/regions-creating-enums4.rs new file mode 100644 index 000000000..c9eab08cb --- /dev/null +++ b/src/test/ui/regions/regions-creating-enums4.rs @@ -0,0 +1,12 @@ +enum Ast<'a> { + Num(usize), + Add(&'a Ast<'a>, &'a Ast<'a>) +} + +fn mk_add_bad2<'a,'b>(x: &'a Ast<'a>, y: &'a Ast<'a>, z: &Ast) -> Ast<'b> { + Ast::Add(x, y) + //~^ ERROR lifetime may not live long enough +} + +fn main() { +} diff --git a/src/test/ui/regions/regions-creating-enums4.stderr b/src/test/ui/regions/regions-creating-enums4.stderr new file mode 100644 index 000000000..91cf57e09 --- /dev/null +++ b/src/test/ui/regions/regions-creating-enums4.stderr @@ -0,0 +1,14 @@ +error: lifetime may not live long enough + --> $DIR/regions-creating-enums4.rs:7:5 + | +LL | fn mk_add_bad2<'a,'b>(x: &'a Ast<'a>, y: &'a Ast<'a>, z: &Ast) -> Ast<'b> { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | Ast::Add(x, y) + | ^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + | + = help: consider adding the following bound: `'a: 'b` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-creating-enums5.rs b/src/test/ui/regions/regions-creating-enums5.rs new file mode 100644 index 000000000..ad3d9748b --- /dev/null +++ b/src/test/ui/regions/regions-creating-enums5.rs @@ -0,0 +1,17 @@ +// run-pass +#![allow(dead_code)] +#![allow(non_camel_case_types)] + +// pretty-expanded FIXME #23616 + +enum ast<'a> { + num(usize), + add(&'a ast<'a>, &'a ast<'a>) +} + +fn mk_add_ok<'a>(x: &'a ast<'a>, y: &'a ast<'a>, _z: &ast) -> ast<'a> { + ast::add(x, y) +} + +pub fn main() { +} diff --git a/src/test/ui/regions/regions-debruijn-of-object.rs b/src/test/ui/regions/regions-debruijn-of-object.rs new file mode 100644 index 000000000..0b5510489 --- /dev/null +++ b/src/test/ui/regions/regions-debruijn-of-object.rs @@ -0,0 +1,22 @@ +// run-pass +#![allow(dead_code)] +#![allow(unused_variables)] +#![allow(non_camel_case_types)] + +// pretty-expanded FIXME #23616 + +struct ctxt<'tcx> { + x: &'tcx i32 +} + +trait AstConv<'tcx> { + fn tcx<'a>(&'a self) -> &'a ctxt<'tcx>; +} + +fn foo(conv: &dyn AstConv) { } + +fn bar<'tcx>(conv: &dyn AstConv<'tcx>) { + foo(conv) +} + +fn main() { } diff --git a/src/test/ui/regions/regions-dependent-addr-of.rs b/src/test/ui/regions/regions-dependent-addr-of.rs new file mode 100644 index 000000000..a6cb56e31 --- /dev/null +++ b/src/test/ui/regions/regions-dependent-addr-of.rs @@ -0,0 +1,112 @@ +// run-pass +// Test lifetimes are linked properly when we create dependent region pointers. +// Issue #3148. + +#![feature(box_patterns)] + +struct A { + value: B +} + +struct B { + v1: isize, + v2: [isize; 3], + v3: Vec<isize> , + v4: C, + v5: Box<C>, + v6: Option<C> +} + +#[derive(Copy, Clone)] +struct C { + f: isize +} + +fn get_v1(a: &A) -> &isize { + // Region inferencer must deduce that &v < L2 < L1 + let foo = &a.value; // L1 + &foo.v1 // L2 +} + +fn get_v2(a: &A, i: usize) -> &isize { + let foo = &a.value; + &foo.v2[i] +} + +fn get_v3(a: &A, i: usize) -> &isize { + let foo = &a.value; + &foo.v3[i] +} + +fn get_v4(a: &A, _i: usize) -> &isize { + let foo = &a.value; + &foo.v4.f +} + +fn get_v5(a: &A, _i: usize) -> &isize { + let foo = &a.value; + &foo.v5.f +} + +fn get_v6_a(a: &A, _i: usize) -> &isize { + match a.value.v6 { + Some(ref v) => &v.f, + None => panic!() + } +} + +fn get_v6_b(a: &A, _i: usize) -> &isize { + match *a { + A { value: B { v6: Some(ref v), .. } } => &v.f, + _ => panic!() + } +} + +fn get_v6_c(a: &A, _i: usize) -> &isize { + match a { + &A { value: B { v6: Some(ref v), .. } } => &v.f, + _ => panic!() + } +} + +fn get_v5_ref(a: &A, _i: usize) -> &isize { + match &a.value { + &B {v5: box C {f: ref v}, ..} => v + } +} + +pub fn main() { + let a = A {value: B {v1: 22, + v2: [23, 24, 25], + v3: vec![26, 27, 28], + v4: C { f: 29 }, + v5: Box::new(C { f: 30 }), + v6: Some(C { f: 31 })}}; + + let p = get_v1(&a); + assert_eq!(*p, a.value.v1); + + let p = get_v2(&a, 1); + assert_eq!(*p, a.value.v2[1]); + + let p = get_v3(&a, 1); + assert_eq!(*p, a.value.v3[1]); + + let p = get_v4(&a, 1); + assert_eq!(*p, a.value.v4.f); + + let p = get_v5(&a, 1); + assert_eq!(*p, a.value.v5.f); + + let p = get_v6_a(&a, 1); + assert_eq!(*p, a.value.v6.unwrap().f); + + let p = get_v6_b(&a, 1); + assert_eq!(*p, a.value.v6.unwrap().f); + + let p = get_v6_c(&a, 1); + assert_eq!(*p, a.value.v6.unwrap().f); + + let p = get_v5_ref(&a, 1); + assert_eq!(*p, a.value.v5.f); +} diff --git a/src/test/ui/regions/regions-dependent-autofn.rs b/src/test/ui/regions/regions-dependent-autofn.rs new file mode 100644 index 000000000..246dbb556 --- /dev/null +++ b/src/test/ui/regions/regions-dependent-autofn.rs @@ -0,0 +1,15 @@ +// run-pass +// Test lifetimes are linked properly when we autoslice a vector. +// Issue #3148. + +// pretty-expanded FIXME #23616 + +fn subslice<F>(v: F) -> F where F: FnOnce() { v } + +fn both<F>(v: F) -> F where F: FnOnce() { + subslice(subslice(v)) +} + +pub fn main() { + both(main); +} diff --git a/src/test/ui/regions/regions-dependent-autoslice.rs b/src/test/ui/regions/regions-dependent-autoslice.rs new file mode 100644 index 000000000..4c5b35ec4 --- /dev/null +++ b/src/test/ui/regions/regions-dependent-autoslice.rs @@ -0,0 +1,14 @@ +// run-pass +// Test lifetimes are linked properly when we autoslice a vector. +// Issue #3148. + +fn subslice1<'r>(v: &'r [usize]) -> &'r [usize] { v } + +fn both<'r>(v: &'r [usize]) -> &'r [usize] { + subslice1(subslice1(v)) +} + +pub fn main() { + let v = vec![1,2,3]; + both(&v); +} diff --git a/src/test/ui/regions/regions-dependent-let-ref.rs b/src/test/ui/regions/regions-dependent-let-ref.rs new file mode 100644 index 000000000..94e3df4b3 --- /dev/null +++ b/src/test/ui/regions/regions-dependent-let-ref.rs @@ -0,0 +1,12 @@ +// run-pass +// Test lifetimes are linked properly when we take reference +// to interior. + +// pretty-expanded FIXME #23616 + +struct Foo(isize); +pub fn main() { + // Here the lifetime of the `&` should be at least the + // block, since a ref binding is created to the interior. + let &Foo(ref _x) = &Foo(3); +} diff --git a/src/test/ui/regions/regions-early-bound-error-method.rs b/src/test/ui/regions/regions-early-bound-error-method.rs new file mode 100644 index 000000000..7edcc677d --- /dev/null +++ b/src/test/ui/regions/regions-early-bound-error-method.rs @@ -0,0 +1,26 @@ +// Tests that you can use a fn lifetime parameter as part of +// the value for a type parameter in a bound. + +trait GetRef<'a> { + fn get(&self) -> &'a isize; +} + +struct Box<'a> { + t: &'a isize +} + +impl<'a> GetRef<'a> for Box<'a> { + fn get(&self) -> &'a isize { + self.t + } +} + +impl<'a> Box<'a> { + fn or<'b,G:GetRef<'b>>(&self, g2: G) -> &'a isize { + g2.get() + //~^ ERROR lifetime may not live long enough + } +} + +fn main() { +} diff --git a/src/test/ui/regions/regions-early-bound-error-method.stderr b/src/test/ui/regions/regions-early-bound-error-method.stderr new file mode 100644 index 000000000..7f10c051f --- /dev/null +++ b/src/test/ui/regions/regions-early-bound-error-method.stderr @@ -0,0 +1,14 @@ +error: lifetime may not live long enough + --> $DIR/regions-early-bound-error-method.rs:20:9 + | +LL | impl<'a> Box<'a> { + | -- lifetime `'a` defined here +LL | fn or<'b,G:GetRef<'b>>(&self, g2: G) -> &'a isize { + | -- lifetime `'b` defined here +LL | g2.get() + | ^^^^^^^^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` + | + = help: consider adding the following bound: `'b: 'a` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-early-bound-error.rs b/src/test/ui/regions/regions-early-bound-error.rs new file mode 100644 index 000000000..98a69c24f --- /dev/null +++ b/src/test/ui/regions/regions-early-bound-error.rs @@ -0,0 +1,24 @@ +// Tests that you can use a fn lifetime parameter as part of +// the value for a type parameter in a bound. + +trait GetRef<'a, T> { + fn get(&self) -> &'a T; +} + +struct Box<'a, T:'a> { + t: &'a T +} + +impl<'a,T:Clone> GetRef<'a,T> for Box<'a,T> { + fn get(&self) -> &'a T { + self.t + } +} + +fn get<'a,'b,G:GetRef<'a, isize>>(g1: G, b: &'b isize) -> &'b isize { + g1.get() + //~^ ERROR lifetime may not live long enough +} + +fn main() { +} diff --git a/src/test/ui/regions/regions-early-bound-error.stderr b/src/test/ui/regions/regions-early-bound-error.stderr new file mode 100644 index 000000000..eb4cd5ca7 --- /dev/null +++ b/src/test/ui/regions/regions-early-bound-error.stderr @@ -0,0 +1,14 @@ +error: lifetime may not live long enough + --> $DIR/regions-early-bound-error.rs:19:5 + | +LL | fn get<'a,'b,G:GetRef<'a, isize>>(g1: G, b: &'b isize) -> &'b isize { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | g1.get() + | ^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + | + = help: consider adding the following bound: `'a: 'b` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-early-bound-lifetime-in-assoc-fn.rs b/src/test/ui/regions/regions-early-bound-lifetime-in-assoc-fn.rs new file mode 100644 index 000000000..fe50a7dd1 --- /dev/null +++ b/src/test/ui/regions/regions-early-bound-lifetime-in-assoc-fn.rs @@ -0,0 +1,35 @@ +// run-pass +#![allow(unused_imports)] +// Test that we are able to compile calls to associated fns like +// `decode()` where the bound on the `Self` parameter references a +// lifetime parameter of the trait. This example indicates why trait +// lifetime parameters must be early bound in the type of the +// associated item. + +// pretty-expanded FIXME #23616 + +use std::marker; + +pub enum Value<'v> { + A(&'v str), + B, +} + +pub trait Decoder<'v> { + fn read(&mut self) -> Value<'v>; +} + +pub trait Decodable<'v, D: Decoder<'v>> { + fn decode(d: &mut D) -> Self; +} + +impl<'v, D: Decoder<'v>> Decodable<'v, D> for () { + fn decode(d: &mut D) -> () { + match d.read() { + Value::A(..) => (), + Value::B => Decodable::decode(d), + } + } +} + +pub fn main() { } diff --git a/src/test/ui/regions/regions-early-bound-trait-param.rs b/src/test/ui/regions/regions-early-bound-trait-param.rs new file mode 100644 index 000000000..a28bd14ba --- /dev/null +++ b/src/test/ui/regions/regions-early-bound-trait-param.rs @@ -0,0 +1,132 @@ +// run-pass +// Tests that you can use an early-bound lifetime parameter as +// on of the generic parameters in a trait. + +trait Trait<'a> { + fn long(&'a self) -> isize; + fn short<'b>(&'b self) -> isize; +} + +fn poly_invoke<'c, T: Trait<'c>>(x: &'c T) -> (isize, isize) { + let l = x.long(); + let s = x.short(); + (l,s) +} + +fn object_invoke1<'d>(x: &'d dyn Trait<'d>) -> (isize, isize) { + let l = x.long(); + let s = x.short(); + (l,s) +} + +struct Struct1<'e> { + f: &'e (dyn Trait<'e>+'e) +} + +fn field_invoke1<'f, 'g>(x: &'g Struct1<'f>) -> (isize,isize) { + let l = x.f.long(); + let s = x.f.short(); + (l,s) +} + +struct Struct2<'h, 'i:'h> { + f: &'h (dyn Trait<'i>+'h) +} + +fn object_invoke2<'j, 'k>(x: &'k dyn Trait<'j>) -> isize { + x.short() +} + +fn field_invoke2<'l, 'm, 'n>(x: &'n Struct2<'l,'m>) -> isize { + x.f.short() +} + +trait MakerTrait { + fn mk() -> Self; +} + +fn make_val<T:MakerTrait>() -> T { + MakerTrait::mk() +} + +trait RefMakerTrait<'q> { + fn mk(_: Self) -> &'q Self; +} + +fn make_ref<'r, T:RefMakerTrait<'r>>(t:T) -> &'r T { + RefMakerTrait::mk(t) +} + +impl<'s> Trait<'s> for (isize,isize) { + fn long(&'s self) -> isize { + let &(x,_) = self; + x + } + fn short<'b>(&'b self) -> isize { + let &(_,y) = self; + y + } +} + +impl<'t> MakerTrait for Box<dyn Trait<'t>+'static> { + fn mk() -> Box<dyn Trait<'t>+'static> { + let tup: Box<(isize, isize)> = Box::new((4,5)); + tup as Box<dyn Trait> + } +} + +enum List<'l> { + Cons(isize, &'l List<'l>), + Null +} + +impl<'l> List<'l> { + fn car<'m>(&'m self) -> isize { + match self { + &List::Cons(car, _) => car, + &List::Null => panic!(), + } + } + fn cdr<'n>(&'n self) -> &'l List<'l> { + match self { + &List::Cons(_, cdr) => cdr, + &List::Null => panic!(), + } + } +} + +impl<'t> RefMakerTrait<'t> for List<'t> { + fn mk(l:List<'t>) -> &'t List<'t> { + l.cdr() + } +} + +pub fn main() { + let t = (2,3); + let o = &t as &dyn Trait; + let s1 = Struct1 { f: o }; + let s2 = Struct2 { f: o }; + assert_eq!(poly_invoke(&t), (2,3)); + assert_eq!(object_invoke1(&t), (2,3)); + assert_eq!(field_invoke1(&s1), (2,3)); + assert_eq!(object_invoke2(&t), 3); + assert_eq!(field_invoke2(&s2), 3); + + let m : Box<dyn Trait> = make_val(); + // assert_eq!(object_invoke1(&*m), (4,5)); + // ~~~~~~~~~~~~~~~~~~~ + // this call yields a compilation error; see ui/span/dropck-object-cycle.rs + // for details. + assert_eq!(object_invoke2(&*m), 5); + + // The RefMakerTrait above is pretty strange (i.e., it is strange + // to consume a value of type T and return a &T). Easiest thing + // that came to my mind: consume a cell of a linked list and + // return a reference to the list it points to. + let l0 = List::Null; + let l1 = List::Cons(1, &l0); + let l2 = List::Cons(2, &l1); + let rl1 = &l1; + let r = make_ref(l2); + assert_eq!(rl1.car(), r.car()); +} diff --git a/src/test/ui/regions/regions-early-bound-used-in-bound-method.rs b/src/test/ui/regions/regions-early-bound-used-in-bound-method.rs new file mode 100644 index 000000000..a778dae1e --- /dev/null +++ b/src/test/ui/regions/regions-early-bound-used-in-bound-method.rs @@ -0,0 +1,30 @@ +// run-pass +// Tests that you can use a fn lifetime parameter as part of +// the value for a type parameter in a bound. + + +trait GetRef<'a> { + fn get(&self) -> &'a isize; +} + +#[derive(Copy, Clone)] +struct Box<'a> { + t: &'a isize +} + +impl<'a> GetRef<'a> for Box<'a> { + fn get(&self) -> &'a isize { + self.t + } +} + +impl<'a> Box<'a> { + fn add<'b,G:GetRef<'b>>(&self, g2: G) -> isize { + *self.t + *g2.get() + } +} + +pub fn main() { + let b1 = Box { t: &3 }; + assert_eq!(b1.add(b1), 6); +} diff --git a/src/test/ui/regions/regions-early-bound-used-in-bound.rs b/src/test/ui/regions/regions-early-bound-used-in-bound.rs new file mode 100644 index 000000000..6ccc99e84 --- /dev/null +++ b/src/test/ui/regions/regions-early-bound-used-in-bound.rs @@ -0,0 +1,28 @@ +// run-pass +// Tests that you can use a fn lifetime parameter as part of +// the value for a type parameter in a bound. + + +trait GetRef<'a, T> { + fn get(&self) -> &'a T; +} + +#[derive(Copy, Clone)] +struct Box<'a, T:'a> { + t: &'a T +} + +impl<'a,T:Clone> GetRef<'a,T> for Box<'a,T> { + fn get(&self) -> &'a T { + self.t + } +} + +fn add<'a,G:GetRef<'a, isize>>(g1: G, g2: G) -> isize { + *g1.get() + *g2.get() +} + +pub fn main() { + let b1 = Box { t: &3 }; + assert_eq!(add(b1, b1), 6); +} diff --git a/src/test/ui/regions/regions-early-bound-used-in-type-param.rs b/src/test/ui/regions/regions-early-bound-used-in-type-param.rs new file mode 100644 index 000000000..d58c17ad9 --- /dev/null +++ b/src/test/ui/regions/regions-early-bound-used-in-type-param.rs @@ -0,0 +1,28 @@ +// run-pass +// Tests that you can use a fn lifetime parameter as part of +// the value for a type parameter in a bound. + + +trait Get<T> { + fn get(&self) -> T; +} + +#[derive(Copy, Clone)] +struct Box<T> { + t: T +} + +impl<T:Clone> Get<T> for Box<T> { + fn get(&self) -> T { + self.t.clone() + } +} + +fn add<'a,G:Get<&'a isize>>(g1: G, g2: G) -> isize { + *g1.get() + *g2.get() +} + +pub fn main() { + let b1 = Box { t: &3 }; + assert_eq!(add(b1, b1), 6); +} diff --git a/src/test/ui/regions/regions-escape-into-other-fn.rs b/src/test/ui/regions/regions-escape-into-other-fn.rs new file mode 100644 index 000000000..65f4c1b6a --- /dev/null +++ b/src/test/ui/regions/regions-escape-into-other-fn.rs @@ -0,0 +1,8 @@ +// run-pass +fn foo(x: &usize) -> &usize { x } +fn bar(x: &usize) -> usize { *x } + +pub fn main() { + let p: Box<_> = Box::new(3); + assert_eq!(bar(foo(&*p)), 3); +} diff --git a/src/test/ui/regions/regions-escape-method.rs b/src/test/ui/regions/regions-escape-method.rs new file mode 100644 index 000000000..69c01ae69 --- /dev/null +++ b/src/test/ui/regions/regions-escape-method.rs @@ -0,0 +1,16 @@ +// 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, F>(&self, _: F) where F: FnOnce(&i32) -> B { + } +} + +fn main() { + let s = S; + s.f(|p| p) //~ ERROR lifetime may not live long enough +} diff --git a/src/test/ui/regions/regions-escape-method.stderr b/src/test/ui/regions/regions-escape-method.stderr new file mode 100644 index 000000000..9f425125b --- /dev/null +++ b/src/test/ui/regions/regions-escape-method.stderr @@ -0,0 +1,11 @@ +error: lifetime may not live long enough + --> $DIR/regions-escape-method.rs:15:13 + | +LL | s.f(|p| p) + | -- ^ returning this value requires that `'1` must outlive `'2` + | || + | |return type of closure is &'2 i32 + | has type `&'1 i32` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-escape-via-trait-or-not.rs b/src/test/ui/regions/regions-escape-via-trait-or-not.rs new file mode 100644 index 000000000..ac0e56de4 --- /dev/null +++ b/src/test/ui/regions/regions-escape-via-trait-or-not.rs @@ -0,0 +1,22 @@ +#![allow(dead_code)] + +trait Deref { + fn get(self) -> isize; +} + +impl<'a> Deref for &'a isize { + fn get(self) -> isize { + *self + } +} + +fn with<R:Deref, F>(f: F) -> isize where F: FnOnce(&isize) -> R { + f(&3).get() +} + +fn return_it() -> isize { + with(|o| o) //~ ERROR lifetime may not live long enough +} + +fn main() { +} diff --git a/src/test/ui/regions/regions-escape-via-trait-or-not.stderr b/src/test/ui/regions/regions-escape-via-trait-or-not.stderr new file mode 100644 index 000000000..cae6c33ac --- /dev/null +++ b/src/test/ui/regions/regions-escape-via-trait-or-not.stderr @@ -0,0 +1,11 @@ +error: lifetime may not live long enough + --> $DIR/regions-escape-via-trait-or-not.rs:18:14 + | +LL | with(|o| o) + | -- ^ returning this value requires that `'1` must outlive `'2` + | || + | |return type of closure is &'2 isize + | has type `&'1 isize` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-expl-self.rs b/src/test/ui/regions/regions-expl-self.rs new file mode 100644 index 000000000..f7315d628 --- /dev/null +++ b/src/test/ui/regions/regions-expl-self.rs @@ -0,0 +1,15 @@ +// run-pass +#![allow(dead_code)] +// Test that you can insert an explicit lifetime in explicit self. + +// pretty-expanded FIXME #23616 + +struct Foo { + f: usize +} + +impl Foo { + pub fn foo<'a>(&'a self) {} +} + +pub fn main() {} diff --git a/src/test/ui/regions/regions-fn-subtyping-2.rs b/src/test/ui/regions/regions-fn-subtyping-2.rs new file mode 100644 index 000000000..83949ddba --- /dev/null +++ b/src/test/ui/regions/regions-fn-subtyping-2.rs @@ -0,0 +1,20 @@ +// run-pass +#![allow(dead_code)] +// Issue #2263. + +// Here, `f` is a function that takes a pointer `x` and a function +// `g`, where `g` requires its argument `y` to be in the same region +// that `x` is in. +// pretty-expanded FIXME #23616 + +fn has_same_region(f: Box<dyn for<'a> FnMut(&'a isize, Box<dyn FnMut(&'a isize)>)>) { + // `f` should be the type that `wants_same_region` wants, but + // right now the compiler complains that it isn't. + wants_same_region(f); +} + +fn wants_same_region(_f: Box<dyn for<'b> FnMut(&'b isize, Box<dyn FnMut(&'b isize)>)>) { +} + +pub fn main() { +} diff --git a/src/test/ui/regions/regions-fn-subtyping-return-static-fail.rs b/src/test/ui/regions/regions-fn-subtyping-return-static-fail.rs new file mode 100644 index 000000000..539221b5a --- /dev/null +++ b/src/test/ui/regions/regions-fn-subtyping-return-static-fail.rs @@ -0,0 +1,51 @@ +// In this fn, the type `F` is a function that takes a reference to a +// struct and returns another reference with the same lifetime. +// +// Meanwhile, the bare fn `foo` takes a reference to a struct with +// *ANY* lifetime and returns a reference with the 'static lifetime. +// This can safely be considered to be an instance of `F` because all +// lifetimes are sublifetimes of 'static. + +#![allow(dead_code)] +#![allow(unused_variables)] + +struct S; + +// Given 'cx, return 'cx +type F = for<'cx> fn(&'cx S) -> &'cx S; +fn want_F(f: F) {} + +// Given anything, return 'static +type G = for<'cx> fn(&'cx S) -> &'static S; +fn want_G(f: G) {} + +// Should meet both. +fn foo(x: &S) -> &'static S { + panic!() +} + +// Should meet both. +fn bar<'a, 'b>(x: &'a S) -> &'b S { + panic!() +} + +// Meets F, but not G. +fn baz(x: &S) -> &S { + panic!() +} + +fn supply_F() { + want_F(foo); + + want_F(bar); + + want_F(baz); +} + +fn supply_G() { + want_G(foo); + want_G(bar); + want_G(baz); //~ ERROR mismatched types +} + +pub fn main() {} diff --git a/src/test/ui/regions/regions-fn-subtyping-return-static-fail.stderr b/src/test/ui/regions/regions-fn-subtyping-return-static-fail.stderr new file mode 100644 index 000000000..d87d0d2f6 --- /dev/null +++ b/src/test/ui/regions/regions-fn-subtyping-return-static-fail.stderr @@ -0,0 +1,19 @@ +error[E0308]: mismatched types + --> $DIR/regions-fn-subtyping-return-static-fail.rs:48:12 + | +LL | want_G(baz); + | ------ ^^^ one type is more general than the other + | | + | arguments to this function are incorrect + | + = note: expected fn pointer `for<'cx> fn(&'cx S) -> &'static S` + found fn item `for<'r> fn(&'r S) -> &'r S {baz}` +note: function defined here + --> $DIR/regions-fn-subtyping-return-static-fail.rs:20:4 + | +LL | fn want_G(f: G) {} + | ^^^^^^ ---- + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/regions/regions-fn-subtyping-return-static.rs b/src/test/ui/regions/regions-fn-subtyping-return-static.rs new file mode 100644 index 000000000..de14d5ba8 --- /dev/null +++ b/src/test/ui/regions/regions-fn-subtyping-return-static.rs @@ -0,0 +1,48 @@ +// In this fn, the type `F` is a function that takes a reference to a +// struct and returns another reference with the same lifetime. +// +// Meanwhile, the bare fn `foo` takes a reference to a struct with +// *ANY* lifetime and returns a reference with the 'static lifetime. +// This can safely be considered to be an instance of `F` because all +// lifetimes are sublifetimes of 'static. +// +// check-pass + +#![allow(dead_code)] +#![allow(unused_variables)] +#![allow(non_snake_case)] + +struct S; + +// Given 'cx, return 'cx +type F = for<'cx> fn(&'cx S) -> &'cx S; +fn want_F(f: F) {} + +// Given anything, return 'static +type G = for<'cx> fn(&'cx S) -> &'static S; +fn want_G(f: G) {} + +// Should meet both. +fn foo(x: &S) -> &'static S { + panic!() +} + +// Should meet both. +fn bar<'a, 'b>(x: &'a S) -> &'b S { + panic!() +} + +// Meets F, but not G. +fn baz(x: &S) -> &S { + panic!() +} + +fn supply_F() { + want_F(foo); + + want_F(bar); + + want_F(baz); +} + +pub fn main() {} diff --git a/src/test/ui/regions/regions-fn-subtyping.rs b/src/test/ui/regions/regions-fn-subtyping.rs new file mode 100644 index 000000000..9570359c6 --- /dev/null +++ b/src/test/ui/regions/regions-fn-subtyping.rs @@ -0,0 +1,30 @@ +// run-pass +#![allow(dead_code)] +#![allow(unused_assignments)] +// Issue #2263. + +// pretty-expanded FIXME #23616 + +#![allow(unused_variables)] + +// Should pass region checking. +fn ok(f: Box<dyn FnMut(&usize)>) { + // Here, g is a function that can accept a usize pointer with + // lifetime r, and f is a function that can accept a usize pointer + // with any lifetime. The assignment g = f should be OK (i.e., + // f's type should be a subtype of g's type), because f can be + // used in any context that expects g's type. But this currently + // fails. + let mut g: Box<dyn for<'r> FnMut(&'r usize)> = Box::new(|x| { }); + g = f; +} + +// This version is the same as above, except that here, g's type is +// inferred. +fn ok_inferred(f: Box<dyn FnMut(&usize)>) { + let mut g: Box<dyn for<'r> FnMut(&'r usize)> = Box::new(|_| {}); + g = f; +} + +pub fn main() { +} diff --git a/src/test/ui/regions/regions-free-region-ordering-callee-4.rs b/src/test/ui/regions/regions-free-region-ordering-callee-4.rs new file mode 100644 index 000000000..de58dd0b1 --- /dev/null +++ b/src/test/ui/regions/regions-free-region-ordering-callee-4.rs @@ -0,0 +1,11 @@ +// Tests that callees correctly infer an ordering between free regions +// that appear in their parameter list. See also +// regions-free-region-ordering-caller.rs + +fn ordering4<'a, 'b, F>(a: &'a usize, b: &'b usize, x: F) where F: FnOnce(&'a &'b usize) { + //~^ ERROR reference has a longer lifetime than the data it references + // Do not infer ordering from closure argument types. + let z: Option<&'a &'b usize> = None; +} + +fn main() {} diff --git a/src/test/ui/regions/regions-free-region-ordering-callee-4.stderr b/src/test/ui/regions/regions-free-region-ordering-callee-4.stderr new file mode 100644 index 000000000..1df7ca0e3 --- /dev/null +++ b/src/test/ui/regions/regions-free-region-ordering-callee-4.stderr @@ -0,0 +1,20 @@ +error[E0491]: in type `&'a &'b usize`, reference has a longer lifetime than the data it references + --> $DIR/regions-free-region-ordering-callee-4.rs:5:68 + | +LL | fn ordering4<'a, 'b, F>(a: &'a usize, b: &'b usize, x: F) where F: FnOnce(&'a &'b usize) { + | ^^^^^^^^^^^^^^^^^^^^^ + | +note: the pointer is valid for the lifetime `'a` as defined here + --> $DIR/regions-free-region-ordering-callee-4.rs:5:14 + | +LL | fn ordering4<'a, 'b, F>(a: &'a usize, b: &'b usize, x: F) where F: FnOnce(&'a &'b usize) { + | ^^ +note: but the referenced data is only valid for the lifetime `'b` as defined here + --> $DIR/regions-free-region-ordering-callee-4.rs:5:18 + | +LL | fn ordering4<'a, 'b, F>(a: &'a usize, b: &'b usize, x: F) where F: FnOnce(&'a &'b usize) { + | ^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0491`. diff --git a/src/test/ui/regions/regions-free-region-ordering-callee.rs b/src/test/ui/regions/regions-free-region-ordering-callee.rs new file mode 100644 index 000000000..8158e81e1 --- /dev/null +++ b/src/test/ui/regions/regions-free-region-ordering-callee.rs @@ -0,0 +1,30 @@ +// Tests that callees correctly infer an ordering between free regions +// that appear in their parameter list. See also +// regions-free-region-ordering-caller.rs + +fn ordering1<'a, 'b>(x: &'a &'b usize) -> &'a usize { + // It is safe to assume that 'a <= 'b due to the type of x + let y: &'b usize = &**x; + return y; +} + +fn ordering2<'a, 'b>(x: &'a &'b usize, y: &'a usize) -> &'b usize { + // However, it is not safe to assume that 'b <= 'a + &*y + //~^ ERROR lifetime may not live long enough +} + +fn ordering3<'a, 'b>(x: &'a usize, y: &'b usize) -> &'a &'b usize { + // Do not infer an ordering from the return value. + let z: &'b usize = &*x; + //~^ ERROR lifetime may not live long enough + panic!(); +} + +// see regions-free-region-ordering-callee-4.rs + +fn ordering5<'a, 'b>(a: &'a usize, b: &'b usize, x: Option<&'a &'b usize>) { + let z: Option<&'a &'b usize> = None; +} + +fn main() {} diff --git a/src/test/ui/regions/regions-free-region-ordering-callee.stderr b/src/test/ui/regions/regions-free-region-ordering-callee.stderr new file mode 100644 index 000000000..a1b46a692 --- /dev/null +++ b/src/test/ui/regions/regions-free-region-ordering-callee.stderr @@ -0,0 +1,28 @@ +error: lifetime may not live long enough + --> $DIR/regions-free-region-ordering-callee.rs:13:5 + | +LL | fn ordering2<'a, 'b>(x: &'a &'b usize, y: &'a usize) -> &'b usize { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | // However, it is not safe to assume that 'b <= 'a +LL | &*y + | ^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + | + = help: consider adding the following bound: `'a: 'b` + +error: lifetime may not live long enough + --> $DIR/regions-free-region-ordering-callee.rs:19:12 + | +LL | fn ordering3<'a, 'b>(x: &'a usize, y: &'b usize) -> &'a &'b usize { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | // Do not infer an ordering from the return value. +LL | let z: &'b usize = &*x; + | ^^^^^^^^^ type annotation requires that `'a` must outlive `'b` + | + = help: consider adding the following bound: `'a: 'b` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/regions/regions-free-region-ordering-caller.rs b/src/test/ui/regions/regions-free-region-ordering-caller.rs new file mode 100644 index 000000000..2e83c3258 --- /dev/null +++ b/src/test/ui/regions/regions-free-region-ordering-caller.rs @@ -0,0 +1,23 @@ +// Test various ways to construct a pointer with a longer lifetime +// than the thing it points at and ensure that they result in +// errors. See also regions-free-region-ordering-callee.rs + +struct Paramd<'a> { x: &'a usize } + +fn call2<'a, 'b>(a: &'a usize, b: &'b usize) { + let z: Option<&'b &'a usize> = None; + //~^ ERROR lifetime may not live long enough +} + +fn call3<'a, 'b>(a: &'a usize, b: &'b usize) { + let y: Paramd<'a> = Paramd { x: a }; + let z: Option<&'b Paramd<'a>> = None; + //~^ ERROR lifetime may not live long enough +} + +fn call4<'a, 'b>(a: &'a usize, b: &'b usize) { + let z: Option<&'a &'b usize> = None; + //~^ ERROR lifetime may not live long enough +} + +fn main() {} diff --git a/src/test/ui/regions/regions-free-region-ordering-caller.stderr b/src/test/ui/regions/regions-free-region-ordering-caller.stderr new file mode 100644 index 000000000..c79ed50c6 --- /dev/null +++ b/src/test/ui/regions/regions-free-region-ordering-caller.stderr @@ -0,0 +1,39 @@ +error: lifetime may not live long enough + --> $DIR/regions-free-region-ordering-caller.rs:8:12 + | +LL | fn call2<'a, 'b>(a: &'a usize, b: &'b usize) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | let z: Option<&'b &'a usize> = None; + | ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'b` + | + = help: consider adding the following bound: `'a: 'b` + +error: lifetime may not live long enough + --> $DIR/regions-free-region-ordering-caller.rs:14:12 + | +LL | fn call3<'a, 'b>(a: &'a usize, b: &'b usize) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | let y: Paramd<'a> = Paramd { x: a }; +LL | let z: Option<&'b Paramd<'a>> = None; + | ^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'b` + | + = help: consider adding the following bound: `'a: 'b` + +error: lifetime may not live long enough + --> $DIR/regions-free-region-ordering-caller.rs:19:12 + | +LL | fn call4<'a, 'b>(a: &'a usize, b: &'b usize) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | let z: Option<&'a &'b usize> = None; + | ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/regions/regions-free-region-ordering-caller1.rs b/src/test/ui/regions/regions-free-region-ordering-caller1.rs new file mode 100644 index 000000000..f32455616 --- /dev/null +++ b/src/test/ui/regions/regions-free-region-ordering-caller1.rs @@ -0,0 +1,14 @@ +// Test various ways to construct a pointer with a longer lifetime +// than the thing it points at and ensure that they result in +// errors. See also regions-free-region-ordering-callee.rs + +fn call1<'a>(x: &'a usize) { + // Test that creating a pointer like + // &'a &'z usize requires that 'a <= 'z: + let y: usize = 3; + let z: &'a & usize = &(&y); + //~^ ERROR temporary value dropped while borrowed + //~^^ ERROR `y` does not live long enough +} + +fn main() {} diff --git a/src/test/ui/regions/regions-free-region-ordering-caller1.stderr b/src/test/ui/regions/regions-free-region-ordering-caller1.stderr new file mode 100644 index 000000000..8042b1740 --- /dev/null +++ b/src/test/ui/regions/regions-free-region-ordering-caller1.stderr @@ -0,0 +1,32 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/regions-free-region-ordering-caller1.rs:9:27 + | +LL | fn call1<'a>(x: &'a usize) { + | -- lifetime `'a` defined here +... +LL | let z: &'a & usize = &(&y); + | ----------- ^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'a` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0597]: `y` does not live long enough + --> $DIR/regions-free-region-ordering-caller1.rs:9:27 + | +LL | fn call1<'a>(x: &'a usize) { + | -- lifetime `'a` defined here +... +LL | let z: &'a & usize = &(&y); + | ----------- ^^^^ borrowed value does not live long enough + | | + | type annotation requires that `y` is borrowed for `'a` +... +LL | } + | - `y` dropped here while still borrowed + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0597, E0716. +For more information about an error, try `rustc --explain E0597`. diff --git a/src/test/ui/regions/regions-free-region-ordering-incorrect.rs b/src/test/ui/regions/regions-free-region-ordering-incorrect.rs new file mode 100644 index 000000000..1aee6e876 --- /dev/null +++ b/src/test/ui/regions/regions-free-region-ordering-incorrect.rs @@ -0,0 +1,22 @@ +// Test that free regions ordering only goes one way. That is, +// we have `&'a Node<'b, T>`, which implies that `'a <= 'b`, +// but not `'b <= 'a`. Hence, returning `&self.val` (which has lifetime +// `'a`) where `'b` is expected yields an error. +// +// This test began its life as a test for issue #4325. + +struct Node<'b, T: 'b> { + val: T, + next: Option<&'b Node<'b, T>> +} + +impl<'b, T> Node<'b, T> { + fn get<'a>(&'a self) -> &'b T { + match self.next { //~ ERROR lifetime may not live long enough + Some(ref next) => next.get(), + None => &self.val + } + } +} + +fn main() {} diff --git a/src/test/ui/regions/regions-free-region-ordering-incorrect.stderr b/src/test/ui/regions/regions-free-region-ordering-incorrect.stderr new file mode 100644 index 000000000..f7c75033c --- /dev/null +++ b/src/test/ui/regions/regions-free-region-ordering-incorrect.stderr @@ -0,0 +1,17 @@ +error: lifetime may not live long enough + --> $DIR/regions-free-region-ordering-incorrect.rs:15:9 + | +LL | impl<'b, T> Node<'b, T> { + | -- lifetime `'b` defined here +LL | fn get<'a>(&'a self) -> &'b T { + | -- lifetime `'a` defined here +LL | / match self.next { +LL | | Some(ref next) => next.get(), +LL | | None => &self.val +LL | | } + | |_________^ associated function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + | + = help: consider adding the following bound: `'a: 'b` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-free-region-outlives-static-outlives-free-region.rs b/src/test/ui/regions/regions-free-region-outlives-static-outlives-free-region.rs new file mode 100644 index 000000000..7c2e1aeee --- /dev/null +++ b/src/test/ui/regions/regions-free-region-outlives-static-outlives-free-region.rs @@ -0,0 +1,17 @@ +// run-pass +#![allow(dead_code)] +// Test that we recognize that if you have +// +// 'a : 'static +// +// then +// +// 'a : 'b + +fn test<'a,'b>(x: &'a i32) -> &'b i32 + where 'a: 'static //~ WARN unnecessary lifetime parameter `'a` +{ + x +} + +fn main() { } diff --git a/src/test/ui/regions/regions-free-region-outlives-static-outlives-free-region.stderr b/src/test/ui/regions/regions-free-region-outlives-static-outlives-free-region.stderr new file mode 100644 index 000000000..70ed418d5 --- /dev/null +++ b/src/test/ui/regions/regions-free-region-outlives-static-outlives-free-region.stderr @@ -0,0 +1,10 @@ +warning: unnecessary lifetime parameter `'a` + --> $DIR/regions-free-region-outlives-static-outlives-free-region.rs:12:11 + | +LL | where 'a: 'static + | ^^ + | + = help: you can use the `'static` lifetime directly, in place of `'a` + +warning: 1 warning emitted + diff --git a/src/test/ui/regions/regions-glb-free-free.rs b/src/test/ui/regions/regions-glb-free-free.rs new file mode 100644 index 000000000..0370a5192 --- /dev/null +++ b/src/test/ui/regions/regions-glb-free-free.rs @@ -0,0 +1,29 @@ +mod argparse { + pub struct Flag<'a> { + name: &'a str, + pub desc: &'a str, + max_count: usize, + value: usize + } + + pub fn flag<'r>(name: &'r str, desc: &'r str) -> Flag<'r> { + Flag { name: name, desc: desc, max_count: 1, value: 0 } + } + + impl<'a> Flag<'a> { + pub fn set_desc(self, s: &str) -> Flag<'a> { + Flag { //~ ERROR explicit lifetime required in the type of `s` [E0621] + name: self.name, + desc: s, + max_count: self.max_count, + value: self.value + } + } + } +} + +fn main () { + let f : argparse::Flag = argparse::flag("flag", "My flag"); + let updated_flag = f.set_desc("My new flag"); + assert_eq!(updated_flag.desc, "My new flag"); +} diff --git a/src/test/ui/regions/regions-glb-free-free.stderr b/src/test/ui/regions/regions-glb-free-free.stderr new file mode 100644 index 000000000..575037a0a --- /dev/null +++ b/src/test/ui/regions/regions-glb-free-free.stderr @@ -0,0 +1,16 @@ +error[E0621]: explicit lifetime required in the type of `s` + --> $DIR/regions-glb-free-free.rs:15:13 + | +LL | pub fn set_desc(self, s: &str) -> Flag<'a> { + | ---- help: add explicit lifetime `'a` to the type of `s`: `&'a str` +LL | / Flag { +LL | | name: self.name, +LL | | desc: s, +LL | | max_count: self.max_count, +LL | | value: self.value +LL | | } + | |_____________^ lifetime `'a` required + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/regions/regions-implied-bounds-projection-gap-1.rs b/src/test/ui/regions/regions-implied-bounds-projection-gap-1.rs new file mode 100644 index 000000000..38fc9c462 --- /dev/null +++ b/src/test/ui/regions/regions-implied-bounds-projection-gap-1.rs @@ -0,0 +1,30 @@ +// Illustrates the "projection gap": in this test, even though we know +// that `T::Foo: 'x`, that does not tell us that `T: 'x`, because +// there might be other ways for the caller of `func` to show that +// `T::Foo: 'x` holds (e.g., where-clause). + +trait Trait1<'x> { + type Foo; +} + +// calling this fn should trigger a check that the type argument +// supplied is well-formed. +fn wf<T>() { } + +fn func<'x, T:Trait1<'x>>(t: &'x T::Foo) +{ + wf::<&'x T>(); + //~^ ERROR the parameter type `T` may not live long enough +} + +fn caller2<'x, T:Trait1<'x>>(t: &'x T) +{ + wf::<&'x T::Foo>(); // OK +} + +fn caller3<'x, T:Trait1<'x>>(t: &'x T::Foo) +{ + wf::<&'x T::Foo>(); // OK +} + +fn main() { } diff --git a/src/test/ui/regions/regions-implied-bounds-projection-gap-1.stderr b/src/test/ui/regions/regions-implied-bounds-projection-gap-1.stderr new file mode 100644 index 000000000..7c9f40556 --- /dev/null +++ b/src/test/ui/regions/regions-implied-bounds-projection-gap-1.stderr @@ -0,0 +1,14 @@ +error[E0309]: the parameter type `T` may not live long enough + --> $DIR/regions-implied-bounds-projection-gap-1.rs:16:5 + | +LL | wf::<&'x T>(); + | ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn func<'x, T:Trait1<'x> + 'x>(t: &'x T::Foo) + | ++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0309`. diff --git a/src/test/ui/regions/regions-implied-bounds-projection-gap-2.rs b/src/test/ui/regions/regions-implied-bounds-projection-gap-2.rs new file mode 100644 index 000000000..a481a9cc5 --- /dev/null +++ b/src/test/ui/regions/regions-implied-bounds-projection-gap-2.rs @@ -0,0 +1,23 @@ +// Along with the other tests in this series, illustrates the +// "projection gap": in this test, we know that `T: 'x`, and that is +// enough to conclude that `T::Foo: 'x`. + +// check-pass +#![allow(dead_code)] +#![allow(unused_variables)] + +trait Trait1<'x> { + type Foo; +} + +// calling this fn should trigger a check that the type argument +// supplied is well-formed. +fn wf<T>() { } + +fn func<'x, T:Trait1<'x>>(t: &'x T) +{ + wf::<&'x T::Foo>(); +} + + +fn main() { } diff --git a/src/test/ui/regions/regions-implied-bounds-projection-gap-3.rs b/src/test/ui/regions/regions-implied-bounds-projection-gap-3.rs new file mode 100644 index 000000000..a627cbbd8 --- /dev/null +++ b/src/test/ui/regions/regions-implied-bounds-projection-gap-3.rs @@ -0,0 +1,23 @@ +// Along with the other tests in this series, illustrates the +// "projection gap": in this test, we know that `T::Foo: 'x`, and that +// is (naturally) enough to conclude that `T::Foo: 'x`. + +// check-pass +#![allow(dead_code)] +#![allow(unused_variables)] + +trait Trait1<'x> { + type Foo; +} + +// calling this fn should trigger a check that the type argument +// supplied is well-formed. +fn wf<T>() { } + +fn func<'x, T:Trait1<'x>>(t: &'x T::Foo) +{ + wf::<&'x T::Foo>(); +} + + +fn main() { } diff --git a/src/test/ui/regions/regions-implied-bounds-projection-gap-4.rs b/src/test/ui/regions/regions-implied-bounds-projection-gap-4.rs new file mode 100644 index 000000000..5158c2893 --- /dev/null +++ b/src/test/ui/regions/regions-implied-bounds-projection-gap-4.rs @@ -0,0 +1,23 @@ +// Along with the other tests in this series, illustrates the +// "projection gap": in this test, we know that `T: 'x`, and that +// is (naturally) enough to conclude that `T: 'x`. + +// check-pass +#![allow(dead_code)] +#![allow(unused_variables)] + +trait Trait1<'x> { + type Foo; +} + +// calling this fn should trigger a check that the type argument +// supplied is well-formed. +fn wf<T>() { } + +fn func<'x, T:Trait1<'x>>(t: &'x T) +{ + wf::<&'x T>(); +} + + +fn main() { } diff --git a/src/test/ui/regions/regions-implied-bounds-projection-gap-hr-1.rs b/src/test/ui/regions/regions-implied-bounds-projection-gap-hr-1.rs new file mode 100644 index 000000000..c1dab6086 --- /dev/null +++ b/src/test/ui/regions/regions-implied-bounds-projection-gap-hr-1.rs @@ -0,0 +1,26 @@ +// The "projection gap" is particularly "fun" around higher-ranked +// projections. This is because the current code is hard-coded to say +// that a projection that contains escaping regions, like `<T as +// Trait2<'y, 'z>>::Foo` where `'z` is bound, can only be found to +// outlive a region if all components that appear free (`'y`, where) +// outlive that region. However, we DON'T add those components to the +// implied bounds set, but rather we treat projections with escaping +// regions as opaque entities, just like projections without escaping +// regions. + +trait Trait1<T> { } + +trait Trait2<'a, 'b> { + type Foo; +} + +// As a side-effect of the conservative process above, the type of +// this argument `t` is not automatically considered well-formed, +// since for it to be WF, we would need to know that `'y: 'x`, but we +// do not infer that. +fn callee<'x, 'y, T>(t: &'x dyn for<'z> Trait1< <T as Trait2<'y, 'z>>::Foo >) + //~^ the trait bound `for<'z> T: Trait2<'y, 'z>` is not satisfied +{ +} + +fn main() { } diff --git a/src/test/ui/regions/regions-implied-bounds-projection-gap-hr-1.stderr b/src/test/ui/regions/regions-implied-bounds-projection-gap-hr-1.stderr new file mode 100644 index 000000000..6844e8665 --- /dev/null +++ b/src/test/ui/regions/regions-implied-bounds-projection-gap-hr-1.stderr @@ -0,0 +1,14 @@ +error[E0277]: the trait bound `for<'z> T: Trait2<'y, 'z>` is not satisfied + --> $DIR/regions-implied-bounds-projection-gap-hr-1.rs:21:49 + | +LL | fn callee<'x, 'y, T>(t: &'x dyn for<'z> Trait1< <T as Trait2<'y, 'z>>::Foo >) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'z> Trait2<'y, 'z>` is not implemented for `T` + | +help: consider restricting type parameter `T` + | +LL | fn callee<'x, 'y, T: for<'z> Trait2<'y, 'z>>(t: &'x dyn for<'z> Trait1< <T as Trait2<'y, 'z>>::Foo >) + | ++++++++++++++++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/regions/regions-in-enums-anon.rs b/src/test/ui/regions/regions-in-enums-anon.rs new file mode 100644 index 000000000..da65cb791 --- /dev/null +++ b/src/test/ui/regions/regions-in-enums-anon.rs @@ -0,0 +1,7 @@ +// Test that anonymous lifetimes are not permitted in enum declarations + +enum Foo { + Bar(&isize) //~ ERROR missing lifetime specifier +} + +fn main() {} diff --git a/src/test/ui/regions/regions-in-enums-anon.stderr b/src/test/ui/regions/regions-in-enums-anon.stderr new file mode 100644 index 000000000..ed547aa9c --- /dev/null +++ b/src/test/ui/regions/regions-in-enums-anon.stderr @@ -0,0 +1,15 @@ +error[E0106]: missing lifetime specifier + --> $DIR/regions-in-enums-anon.rs:4:9 + | +LL | Bar(&isize) + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL ~ enum Foo<'a> { +LL ~ Bar(&'a isize) + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/regions/regions-in-enums.rs b/src/test/ui/regions/regions-in-enums.rs new file mode 100644 index 000000000..8cf553a0f --- /dev/null +++ b/src/test/ui/regions/regions-in-enums.rs @@ -0,0 +1,20 @@ +// Test that lifetimes must be declared for use on enums. +// See also regions-undeclared.rs + +enum Yes0<'lt> { + X3(&'lt usize) +} + +enum Yes1<'a> { + X4(&'a usize) +} + +enum No0 { + X5(&'foo usize) //~ ERROR use of undeclared lifetime name `'foo` +} + +enum No1 { + X6(&'a usize) //~ ERROR use of undeclared lifetime name `'a` +} + +fn main() {} diff --git a/src/test/ui/regions/regions-in-enums.stderr b/src/test/ui/regions/regions-in-enums.stderr new file mode 100644 index 000000000..665376532 --- /dev/null +++ b/src/test/ui/regions/regions-in-enums.stderr @@ -0,0 +1,19 @@ +error[E0261]: use of undeclared lifetime name `'foo` + --> $DIR/regions-in-enums.rs:13:9 + | +LL | enum No0 { + | - help: consider introducing lifetime `'foo` here: `<'foo>` +LL | X5(&'foo usize) + | ^^^^ undeclared lifetime + +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/regions-in-enums.rs:17:9 + | +LL | enum No1 { + | - help: consider introducing lifetime `'a` here: `<'a>` +LL | X6(&'a usize) + | ^^ undeclared lifetime + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0261`. diff --git a/src/test/ui/regions/regions-in-structs-anon.rs b/src/test/ui/regions/regions-in-structs-anon.rs new file mode 100644 index 000000000..7cb2ce0db --- /dev/null +++ b/src/test/ui/regions/regions-in-structs-anon.rs @@ -0,0 +1,7 @@ +// Test that anonymous lifetimes are not permitted in struct declarations + +struct Foo { + x: &isize //~ ERROR missing lifetime specifier +} + +fn main() {} diff --git a/src/test/ui/regions/regions-in-structs-anon.stderr b/src/test/ui/regions/regions-in-structs-anon.stderr new file mode 100644 index 000000000..992d25c9f --- /dev/null +++ b/src/test/ui/regions/regions-in-structs-anon.stderr @@ -0,0 +1,15 @@ +error[E0106]: missing lifetime specifier + --> $DIR/regions-in-structs-anon.rs:4:8 + | +LL | x: &isize + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL ~ struct Foo<'a> { +LL ~ x: &'a isize + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/regions/regions-in-structs.rs b/src/test/ui/regions/regions-in-structs.rs new file mode 100644 index 000000000..71f718ba2 --- /dev/null +++ b/src/test/ui/regions/regions-in-structs.rs @@ -0,0 +1,15 @@ +struct Yes1<'a> { + x: &'a usize, +} + +struct Yes2<'a> { + x: &'a usize, +} + +struct StructDecl { + a: &'a isize, //~ ERROR use of undeclared lifetime name `'a` + b: &'a isize, //~ ERROR use of undeclared lifetime name `'a` +} + + +fn main() {} diff --git a/src/test/ui/regions/regions-in-structs.stderr b/src/test/ui/regions/regions-in-structs.stderr new file mode 100644 index 000000000..5dfdc2ee9 --- /dev/null +++ b/src/test/ui/regions/regions-in-structs.stderr @@ -0,0 +1,20 @@ +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/regions-in-structs.rs:10:9 + | +LL | struct StructDecl { + | - help: consider introducing lifetime `'a` here: `<'a>` +LL | a: &'a isize, + | ^^ undeclared lifetime + +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/regions-in-structs.rs:11:9 + | +LL | struct StructDecl { + | - help: consider introducing lifetime `'a` here: `<'a>` +LL | a: &'a isize, +LL | b: &'a isize, + | ^^ undeclared lifetime + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0261`. diff --git a/src/test/ui/regions/regions-infer-at-fn-not-param.rs b/src/test/ui/regions/regions-infer-at-fn-not-param.rs new file mode 100644 index 000000000..fb9c5d5c2 --- /dev/null +++ b/src/test/ui/regions/regions-infer-at-fn-not-param.rs @@ -0,0 +1,19 @@ +struct Parameterized1<'a> { + g: Box<dyn FnMut() + 'a> +} + +struct NotParameterized1 { + g: Box<dyn FnMut() + 'static> +} + +struct NotParameterized2 { + g: Box<dyn FnMut() + 'static> +} + +fn take1<'a>(p: Parameterized1) -> Parameterized1<'a> { p } +//~^ ERROR explicit lifetime required in the type of `p` + +fn take3(p: NotParameterized1) -> NotParameterized1 { p } +fn take4(p: NotParameterized2) -> NotParameterized2 { p } + +fn main() {} diff --git a/src/test/ui/regions/regions-infer-at-fn-not-param.stderr b/src/test/ui/regions/regions-infer-at-fn-not-param.stderr new file mode 100644 index 000000000..8cfc44f6a --- /dev/null +++ b/src/test/ui/regions/regions-infer-at-fn-not-param.stderr @@ -0,0 +1,11 @@ +error[E0621]: explicit lifetime required in the type of `p` + --> $DIR/regions-infer-at-fn-not-param.rs:13:57 + | +LL | fn take1<'a>(p: Parameterized1) -> Parameterized1<'a> { p } + | -------------- ^ lifetime `'a` required + | | + | help: add explicit lifetime `'a` to the type of `p`: `Parameterized1<'a>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/regions/regions-infer-borrow-scope-addr-of.rs b/src/test/ui/regions/regions-infer-borrow-scope-addr-of.rs new file mode 100644 index 000000000..5d8ad932e --- /dev/null +++ b/src/test/ui/regions/regions-infer-borrow-scope-addr-of.rs @@ -0,0 +1,23 @@ +// run-pass + +use std::mem::swap; + +pub fn main() { + let mut x = 4; + + for i in 0_usize..3 { + // ensure that the borrow in this alt + // does not interfere with the swap + // below. note that it would it you + // naively borrowed &x for the lifetime + // of the variable x, as we once did + match i { + i => { + let y = &x; + assert!(i < *y); + } + } + let mut y = 4; + swap(&mut y, &mut x); + } +} diff --git a/src/test/ui/regions/regions-infer-borrow-scope-too-big.rs b/src/test/ui/regions/regions-infer-borrow-scope-too-big.rs new file mode 100644 index 000000000..250b41da5 --- /dev/null +++ b/src/test/ui/regions/regions-infer-borrow-scope-too-big.rs @@ -0,0 +1,16 @@ +struct Point { + x: isize, + y: isize, +} + +fn x_coord<'r>(p: &'r Point) -> &'r isize { + return &p.x; +} + +fn foo<'a>(p: Box<Point>) -> &'a isize { + let xc = x_coord(&*p); + assert_eq!(*xc, 3); + return xc; //~ ERROR cannot return value referencing local data `*p` +} + +fn main() {} diff --git a/src/test/ui/regions/regions-infer-borrow-scope-too-big.stderr b/src/test/ui/regions/regions-infer-borrow-scope-too-big.stderr new file mode 100644 index 000000000..2c7a6e8b5 --- /dev/null +++ b/src/test/ui/regions/regions-infer-borrow-scope-too-big.stderr @@ -0,0 +1,12 @@ +error[E0515]: cannot return value referencing local data `*p` + --> $DIR/regions-infer-borrow-scope-too-big.rs:13:12 + | +LL | let xc = x_coord(&*p); + | --- `*p` is borrowed here +LL | assert_eq!(*xc, 3); +LL | return xc; + | ^^ returns a value referencing data owned by the current function + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/regions/regions-infer-borrow-scope-view.rs b/src/test/ui/regions/regions-infer-borrow-scope-view.rs new file mode 100644 index 000000000..349b52044 --- /dev/null +++ b/src/test/ui/regions/regions-infer-borrow-scope-view.rs @@ -0,0 +1,11 @@ +// run-pass + + +fn view<T>(x: &[T]) -> &[T] {x} + +pub fn main() { + let v = vec![1, 2, 3]; + let x = view(&v); + let y = view(x); + assert!((v[0] == x[0]) && (v[0] == y[0])); +} diff --git a/src/test/ui/regions/regions-infer-borrow-scope-within-loop-ok.rs b/src/test/ui/regions/regions-infer-borrow-scope-within-loop-ok.rs new file mode 100644 index 000000000..dca26742d --- /dev/null +++ b/src/test/ui/regions/regions-infer-borrow-scope-within-loop-ok.rs @@ -0,0 +1,12 @@ +// run-pass + +fn borrow<T>(x: &T) -> &T {x} + +pub fn main() { + let x: Box<_> = Box::new(3); + loop { + let y = borrow(&*x); + assert_eq!(*x, *y); + break; + } +} diff --git a/src/test/ui/regions/regions-infer-borrow-scope.rs b/src/test/ui/regions/regions-infer-borrow-scope.rs new file mode 100644 index 000000000..b4a050bf1 --- /dev/null +++ b/src/test/ui/regions/regions-infer-borrow-scope.rs @@ -0,0 +1,14 @@ +// run-pass +#![allow(dead_code)] + +struct Point {x: isize, y: isize} + +fn x_coord(p: &Point) -> &isize { + return &p.x; +} + +pub fn main() { + let p: Box<_> = Box::new(Point {x: 3, y: 4}); + let xc = x_coord(&*p); + assert_eq!(*xc, 3); +} diff --git a/src/test/ui/regions/regions-infer-bound-from-trait-self.rs b/src/test/ui/regions/regions-infer-bound-from-trait-self.rs new file mode 100644 index 000000000..d15bfffe9 --- /dev/null +++ b/src/test/ui/regions/regions-infer-bound-from-trait-self.rs @@ -0,0 +1,51 @@ +// Test that we can derive lifetime bounds on `Self` from trait +// inheritance. + +trait Static : 'static { } + +trait Is<'a> : 'a { } + +struct Inv<'a> { + x: Option<&'a mut &'a isize> +} + +fn check_bound<'a,A:'a>(x: Inv<'a>, a: A) { } + +// In these case, `Self` inherits `'static`. + +trait InheritsFromStatic : Sized + 'static { + fn foo1<'a>(self, x: Inv<'a>) { + check_bound(x, self) + } +} +trait InheritsFromStaticIndirectly : Sized + Static { + fn foo1<'a>(self, x: Inv<'a>) { + check_bound(x, self) + } +} + + +// In these case, `Self` inherits `'a`. + +trait InheritsFromIs<'a> : Sized + 'a { + fn foo(self, x: Inv<'a>) { + check_bound(x, self) + } +} + +trait InheritsFromIsIndirectly<'a> : Sized + Is<'a> { + fn foo(self, x: Inv<'a>) { + check_bound(x, self) + } +} + +// In this case, `Self` inherits nothing. + +trait InheritsFromNothing<'a> : Sized { + fn foo(self, x: Inv<'a>) { + check_bound(x, self) + //~^ ERROR parameter type `Self` may not live long enough + } +} + +fn main() { } diff --git a/src/test/ui/regions/regions-infer-bound-from-trait-self.stderr b/src/test/ui/regions/regions-infer-bound-from-trait-self.stderr new file mode 100644 index 000000000..e88f79a3a --- /dev/null +++ b/src/test/ui/regions/regions-infer-bound-from-trait-self.stderr @@ -0,0 +1,12 @@ +error[E0309]: the parameter type `Self` may not live long enough + --> $DIR/regions-infer-bound-from-trait-self.rs:46:9 + | +LL | check_bound(x, self) + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `Self: 'a`... + = note: ...so that the type `Self` will meet its required lifetime bounds + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0309`. diff --git a/src/test/ui/regions/regions-infer-bound-from-trait.rs b/src/test/ui/regions/regions-infer-bound-from-trait.rs new file mode 100644 index 000000000..610452182 --- /dev/null +++ b/src/test/ui/regions/regions-infer-bound-from-trait.rs @@ -0,0 +1,40 @@ +// Test that we can derive lifetime bounds on type parameters +// from trait inheritance. + +trait Static : 'static { } + +trait Is<'a> : 'a { } + +struct Inv<'a> { + x: Option<&'a mut &'a isize> +} + +fn check_bound<'a,A:'a>(x: Inv<'a>, a: A) { } + +// In all of these cases, we can derive a bound for A that is longer +// than 'a based on the trait bound of A: + +fn foo1<'a,A:Static>(x: Inv<'a>, a: A) { + check_bound(x, a) +} + +fn foo2<'a,A:Static>(x: Inv<'static>, a: A) { + check_bound(x, a) +} + +fn foo3<'a,A:Is<'a>>(x: Inv<'a>, a: A) { + check_bound(x, a) +} + +// In these cases, there is no trait bound, so we cannot derive any +// bound for A and we get an error: + +fn bar1<'a,A>(x: Inv<'a>, a: A) { + check_bound(x, a) //~ ERROR parameter type `A` may not live long enough +} + +fn bar2<'a,'b,A:Is<'b>>(x: Inv<'a>, y: Inv<'b>, a: A) { + check_bound(x, a) //~ ERROR parameter type `A` may not live long enough +} + +fn main() { } diff --git a/src/test/ui/regions/regions-infer-bound-from-trait.stderr b/src/test/ui/regions/regions-infer-bound-from-trait.stderr new file mode 100644 index 000000000..3ee71543d --- /dev/null +++ b/src/test/ui/regions/regions-infer-bound-from-trait.stderr @@ -0,0 +1,25 @@ +error[E0309]: the parameter type `A` may not live long enough + --> $DIR/regions-infer-bound-from-trait.rs:33:5 + | +LL | check_bound(x, a) + | ^^^^^^^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn bar1<'a,A: 'a>(x: Inv<'a>, a: A) { + | ++++ + +error[E0309]: the parameter type `A` may not live long enough + --> $DIR/regions-infer-bound-from-trait.rs:37:5 + | +LL | check_bound(x, a) + | ^^^^^^^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn bar2<'a,'b,A:Is<'b> + 'a>(x: Inv<'a>, y: Inv<'b>, a: A) { + | ++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0309`. diff --git a/src/test/ui/regions/regions-infer-call-2.rs b/src/test/ui/regions/regions-infer-call-2.rs new file mode 100644 index 000000000..a288d2e4d --- /dev/null +++ b/src/test/ui/regions/regions-infer-call-2.rs @@ -0,0 +1,15 @@ +// run-pass + +fn takes_two(x: &isize, y: &isize) -> isize { *x + *y } + +fn with<T, F>(f: F) -> T where F: FnOnce(&isize) -> T { + f(&20) +} + +fn has_one<'a>(x: &'a isize) -> isize { + with(|y| takes_two(x, y)) +} + +pub fn main() { + assert_eq!(has_one(&2), 22); +} diff --git a/src/test/ui/regions/regions-infer-call-3.rs b/src/test/ui/regions/regions-infer-call-3.rs new file mode 100644 index 000000000..063ec8428 --- /dev/null +++ b/src/test/ui/regions/regions-infer-call-3.rs @@ -0,0 +1,14 @@ +fn select<'r>(x: &'r isize, y: &'r isize) -> &'r isize { x } + +fn with<T, F>(f: F) -> T where F: FnOnce(&isize) -> T { + f(&20) +} + +fn manip<'a>(x: &'a isize) -> isize { + let z = with(|y| { select(x, y) }); + //~^ ERROR lifetime may not live long enough + *z +} + +fn main() { +} diff --git a/src/test/ui/regions/regions-infer-call-3.stderr b/src/test/ui/regions/regions-infer-call-3.stderr new file mode 100644 index 000000000..ca51555a0 --- /dev/null +++ b/src/test/ui/regions/regions-infer-call-3.stderr @@ -0,0 +1,11 @@ +error: lifetime may not live long enough + --> $DIR/regions-infer-call-3.rs:8:24 + | +LL | let z = with(|y| { select(x, y) }); + | -- ^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2` + | || + | |return type of closure is &'2 isize + | has type `&'1 isize` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-infer-call.rs b/src/test/ui/regions/regions-infer-call.rs new file mode 100644 index 000000000..248f9e923 --- /dev/null +++ b/src/test/ui/regions/regions-infer-call.rs @@ -0,0 +1,11 @@ +// run-pass + +fn takes_two(x: &isize, y: &isize) -> isize { *x + *y } + +fn has_two<'a,'b>(x: &'a isize, y: &'b isize) -> isize { + takes_two(x, y) +} + +pub fn main() { + assert_eq!(has_two(&20, &2), 22); +} diff --git a/src/test/ui/regions/regions-infer-contravariance-due-to-decl.rs b/src/test/ui/regions/regions-infer-contravariance-due-to-decl.rs new file mode 100644 index 000000000..fbc0cec56 --- /dev/null +++ b/src/test/ui/regions/regions-infer-contravariance-due-to-decl.rs @@ -0,0 +1,29 @@ +// Test that a type which is contravariant with respect to its region +// parameter yields an error when used in a covariant way. +// +// Note: see variance-regions-*.rs for the tests that check that the +// variance inference works in the first place. + +use std::marker; + +// This is contravariant with respect to 'a, meaning that +// Contravariant<'foo> <: Contravariant<'static> because +// 'foo <= 'static +struct Contravariant<'a> { + marker: marker::PhantomData<&'a()> +} + +fn use_<'short,'long>(c: Contravariant<'short>, + s: &'short isize, + l: &'long isize, + _where:Option<&'short &'long ()>) { + + // Test whether Contravariant<'short> <: Contravariant<'long>. Since + // 'short <= 'long, this would be true if the Contravariant type were + // covariant with respect to its parameter 'a. + + let _: Contravariant<'long> = c; + //~^ ERROR lifetime may not live long enough +} + +fn main() {} diff --git a/src/test/ui/regions/regions-infer-contravariance-due-to-decl.stderr b/src/test/ui/regions/regions-infer-contravariance-due-to-decl.stderr new file mode 100644 index 000000000..94b80852d --- /dev/null +++ b/src/test/ui/regions/regions-infer-contravariance-due-to-decl.stderr @@ -0,0 +1,15 @@ +error: lifetime may not live long enough + --> $DIR/regions-infer-contravariance-due-to-decl.rs:25:12 + | +LL | fn use_<'short,'long>(c: Contravariant<'short>, + | ------ ----- lifetime `'long` defined here + | | + | lifetime `'short` defined here +... +LL | let _: Contravariant<'long> = c; + | ^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'short` must outlive `'long` + | + = help: consider adding the following bound: `'short: 'long` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-infer-contravariance-due-to-ret.rs b/src/test/ui/regions/regions-infer-contravariance-due-to-ret.rs new file mode 100644 index 000000000..fbd895015 --- /dev/null +++ b/src/test/ui/regions/regions-infer-contravariance-due-to-ret.rs @@ -0,0 +1,22 @@ +// run-pass +#![allow(non_camel_case_types)] + + +struct boxed_int<'a> { + f: &'a isize, +} + +fn max<'r>(bi: &'r boxed_int, f: &'r isize) -> isize { + if *bi.f > *f {*bi.f} else {*f} +} + +fn with(bi: &boxed_int) -> isize { + let i = 22; + max(bi, &i) +} + +pub fn main() { + let g = 21; + let foo = boxed_int { f: &g }; + assert_eq!(with(&foo), 22); +} diff --git a/src/test/ui/regions/regions-infer-covariance-due-to-decl.rs b/src/test/ui/regions/regions-infer-covariance-due-to-decl.rs new file mode 100644 index 000000000..03c0e436e --- /dev/null +++ b/src/test/ui/regions/regions-infer-covariance-due-to-decl.rs @@ -0,0 +1,26 @@ +// Test that a type which is covariant with respect to its region +// parameter yields an error when used in a contravariant way. +// +// Note: see variance-regions-*.rs for the tests that check that the +// variance inference works in the first place. + +use std::marker; + +struct Covariant<'a> { + marker: marker::PhantomData<fn(&'a ())> +} + +fn use_<'short,'long>(c: Covariant<'long>, + s: &'short isize, + l: &'long isize, + _where:Option<&'short &'long ()>) { + + // Test whether Covariant<'long> <: Covariant<'short>. Since + // 'short <= 'long, this would be true if the Covariant type were + // contravariant with respect to its parameter 'a. + + let _: Covariant<'short> = c; + //~^ ERROR lifetime may not live long enough +} + +fn main() {} diff --git a/src/test/ui/regions/regions-infer-covariance-due-to-decl.stderr b/src/test/ui/regions/regions-infer-covariance-due-to-decl.stderr new file mode 100644 index 000000000..f44a0fad5 --- /dev/null +++ b/src/test/ui/regions/regions-infer-covariance-due-to-decl.stderr @@ -0,0 +1,15 @@ +error: lifetime may not live long enough + --> $DIR/regions-infer-covariance-due-to-decl.rs:22:12 + | +LL | fn use_<'short,'long>(c: Covariant<'long>, + | ------ ----- lifetime `'long` defined here + | | + | lifetime `'short` defined here +... +LL | let _: Covariant<'short> = c; + | ^^^^^^^^^^^^^^^^^ type annotation requires that `'short` must outlive `'long` + | + = help: consider adding the following bound: `'short: 'long` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-infer-invariance-due-to-decl.rs b/src/test/ui/regions/regions-infer-invariance-due-to-decl.rs new file mode 100644 index 000000000..102abc0e0 --- /dev/null +++ b/src/test/ui/regions/regions-infer-invariance-due-to-decl.rs @@ -0,0 +1,17 @@ +use std::marker; + +struct Invariant<'a> { + marker: marker::PhantomData<*mut &'a()> +} + +fn to_same_lifetime<'r>(b_isize: Invariant<'r>) { + let bj: Invariant<'r> = b_isize; +} + +fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> { + b_isize + //~^ ERROR lifetime may not live long enough +} + +fn main() { +} diff --git a/src/test/ui/regions/regions-infer-invariance-due-to-decl.stderr b/src/test/ui/regions/regions-infer-invariance-due-to-decl.stderr new file mode 100644 index 000000000..c8c7808e0 --- /dev/null +++ b/src/test/ui/regions/regions-infer-invariance-due-to-decl.stderr @@ -0,0 +1,14 @@ +error: lifetime may not live long enough + --> $DIR/regions-infer-invariance-due-to-decl.rs:12:5 + | +LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> { + | -- lifetime `'r` defined here +LL | b_isize + | ^^^^^^^ returning this value requires that `'r` must outlive `'static` + | + = note: requirement occurs because of the type `Invariant<'_>`, which makes the generic argument `'_` invariant + = note: the struct `Invariant<'a>` is invariant over the parameter `'a` + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.rs b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.rs new file mode 100644 index 000000000..c1fb41bd9 --- /dev/null +++ b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.rs @@ -0,0 +1,15 @@ +struct Invariant<'a> { + f: Box<dyn FnOnce(&mut &'a isize) + 'static>, +} + +fn to_same_lifetime<'r>(b_isize: Invariant<'r>) { + let bj: Invariant<'r> = b_isize; +} + +fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> { + b_isize + //~^ ERROR lifetime may not live long enough +} + +fn main() { +} diff --git a/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.stderr b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.stderr new file mode 100644 index 000000000..1165011c1 --- /dev/null +++ b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.stderr @@ -0,0 +1,14 @@ +error: lifetime may not live long enough + --> $DIR/regions-infer-invariance-due-to-mutability-3.rs:10:5 + | +LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> { + | -- lifetime `'r` defined here +LL | b_isize + | ^^^^^^^ returning this value requires that `'r` must outlive `'static` + | + = note: requirement occurs because of the type `Invariant<'_>`, which makes the generic argument `'_` invariant + = note: the struct `Invariant<'a>` is invariant over the parameter `'a` + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.rs b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.rs new file mode 100644 index 000000000..1078f77a0 --- /dev/null +++ b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.rs @@ -0,0 +1,15 @@ +struct Invariant<'a> { + f: Box<dyn FnOnce() -> *mut &'a isize + 'static>, +} + +fn to_same_lifetime<'r>(b_isize: Invariant<'r>) { + let bj: Invariant<'r> = b_isize; +} + +fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> { + b_isize + //~^ ERROR lifetime may not live long enough +} + +fn main() { +} diff --git a/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.stderr b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.stderr new file mode 100644 index 000000000..f3973a93b --- /dev/null +++ b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.stderr @@ -0,0 +1,14 @@ +error: lifetime may not live long enough + --> $DIR/regions-infer-invariance-due-to-mutability-4.rs:10:5 + | +LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> { + | -- lifetime `'r` defined here +LL | b_isize + | ^^^^^^^ returning this value requires that `'r` must outlive `'static` + | + = note: requirement occurs because of the type `Invariant<'_>`, which makes the generic argument `'_` invariant + = note: the struct `Invariant<'a>` is invariant over the parameter `'a` + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-infer-not-param.rs b/src/test/ui/regions/regions-infer-not-param.rs new file mode 100644 index 000000000..c3766bce1 --- /dev/null +++ b/src/test/ui/regions/regions-infer-not-param.rs @@ -0,0 +1,24 @@ +struct Direct<'a> { + f: &'a isize +} + +struct Indirect1 { + // Here the lifetime parameter of direct is bound by the fn() + g: Box<dyn FnOnce(Direct) + 'static> +} + +struct Indirect2<'a> { + // But here it is set to 'a + g: Box<dyn FnOnce(Direct<'a>) + 'static> +} + +fn take_direct<'a,'b>(p: Direct<'a>) -> Direct<'b> { p } +//~^ ERROR lifetime may not live long enough + +fn take_indirect1(p: Indirect1) -> Indirect1 { p } + +fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p } +//~^ ERROR lifetime may not live long enough +//~| ERROR lifetime may not live long enough + +fn main() {} diff --git a/src/test/ui/regions/regions-infer-not-param.stderr b/src/test/ui/regions/regions-infer-not-param.stderr new file mode 100644 index 000000000..d12f07a77 --- /dev/null +++ b/src/test/ui/regions/regions-infer-not-param.stderr @@ -0,0 +1,40 @@ +error: lifetime may not live long enough + --> $DIR/regions-infer-not-param.rs:15:54 + | +LL | fn take_direct<'a,'b>(p: Direct<'a>) -> Direct<'b> { p } + | -- -- lifetime `'b` defined here ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + | | + | lifetime `'a` defined here + | + = help: consider adding the following bound: `'a: 'b` + +error: lifetime may not live long enough + --> $DIR/regions-infer-not-param.rs:20:63 + | +LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p } + | -- -- lifetime `'b` defined here ^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` + | | + | lifetime `'a` defined here + | + = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of the type `Indirect2<'_>`, which makes the generic argument `'_` invariant + = note: the struct `Indirect2<'a>` is invariant over the parameter `'a` + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +error: lifetime may not live long enough + --> $DIR/regions-infer-not-param.rs:20:63 + | +LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p } + | -- -- lifetime `'b` defined here ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + | | + | lifetime `'a` defined here + | + = help: consider adding the following bound: `'a: 'b` + = note: requirement occurs because of the type `Indirect2<'_>`, which makes the generic argument `'_` invariant + = note: the struct `Indirect2<'a>` is invariant over the parameter `'a` + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +help: `'b` and `'a` must be the same: replace one with the other + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/regions/regions-infer-paramd-indirect.rs b/src/test/ui/regions/regions-infer-paramd-indirect.rs new file mode 100644 index 000000000..978c84e53 --- /dev/null +++ b/src/test/ui/regions/regions-infer-paramd-indirect.rs @@ -0,0 +1,27 @@ +// Check that we correctly infer that b and c must be region +// parameterized because they reference a which requires a region. + +type A<'a> = &'a isize; +type B<'a> = Box<A<'a>>; + +struct C<'a> { + f: Box<B<'a>> +} + +trait SetF<'a> { + fn set_f_ok(&mut self, b: Box<B<'a>>); + fn set_f_bad(&mut self, b: Box<B>); +} + +impl<'a> SetF<'a> for C<'a> { + fn set_f_ok(&mut self, b: Box<B<'a>>) { + self.f = b; + } + + fn set_f_bad(&mut self, b: Box<B>) { + self.f = b; + //~^ ERROR lifetime may not live long enough + } +} + +fn main() {} diff --git a/src/test/ui/regions/regions-infer-paramd-indirect.stderr b/src/test/ui/regions/regions-infer-paramd-indirect.stderr new file mode 100644 index 000000000..afabdc1de --- /dev/null +++ b/src/test/ui/regions/regions-infer-paramd-indirect.stderr @@ -0,0 +1,13 @@ +error: lifetime may not live long enough + --> $DIR/regions-infer-paramd-indirect.rs:22:9 + | +LL | impl<'a> SetF<'a> for C<'a> { + | -- lifetime `'a` defined here +... +LL | fn set_f_bad(&mut self, b: Box<B>) { + | - has type `Box<Box<&'1 isize>>` +LL | self.f = b; + | ^^^^^^ assignment requires that `'1` must outlive `'a` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-infer-proc-static-upvar.rs b/src/test/ui/regions/regions-infer-proc-static-upvar.rs new file mode 100644 index 000000000..5a64aa734 --- /dev/null +++ b/src/test/ui/regions/regions-infer-proc-static-upvar.rs @@ -0,0 +1,24 @@ +// Test that, when a variable of type `&T` is captured inside a proc, +// we correctly infer/require that its lifetime is 'static. + +fn foo<F:FnOnce()+'static>(_p: F) { } + +static i: isize = 3; + +fn capture_local() { + let x = 3; + let y = &x; //~ ERROR `x` does not live long enough + foo(move|| { + let _a = *y; + }); +} + +fn capture_static() { + // Legal because &i can have static lifetime: + let y = &i; + foo(move|| { + let _a = *y; + }); +} + +fn main() { } diff --git a/src/test/ui/regions/regions-infer-proc-static-upvar.stderr b/src/test/ui/regions/regions-infer-proc-static-upvar.stderr new file mode 100644 index 000000000..803d0d744 --- /dev/null +++ b/src/test/ui/regions/regions-infer-proc-static-upvar.stderr @@ -0,0 +1,15 @@ +error[E0597]: `x` does not live long enough + --> $DIR/regions-infer-proc-static-upvar.rs:10:13 + | +LL | let y = &x; + | ^^ borrowed value does not live long enough +LL | / foo(move|| { +LL | | let _a = *y; +LL | | }); + | |______- argument requires that `x` is borrowed for `'static` +LL | } + | - `x` dropped here while still borrowed + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/regions/regions-infer-reborrow-ref-mut-recurse.rs b/src/test/ui/regions/regions-infer-reborrow-ref-mut-recurse.rs new file mode 100644 index 000000000..31a48b4ad --- /dev/null +++ b/src/test/ui/regions/regions-infer-reborrow-ref-mut-recurse.rs @@ -0,0 +1,18 @@ +// run-pass +#![allow(dead_code)] +// Test an edge case in region inference: the lifetime of the borrow +// of `*x` must be extended to at least 'a. + +// pretty-expanded FIXME #23616 + +fn foo<'a,'b>(x: &'a &'b mut isize) -> &'a isize { + let y = &*x; // should be inferred to have type &'a &'b mut isize... + + // ...because if we inferred, say, &'x &'b mut isize where 'x <= 'a, + // this reborrow would be illegal: + &**y +} + +pub fn main() { + /* Just want to know that it compiles. */ +} diff --git a/src/test/ui/regions/regions-infer-region-in-fn-but-not-type.rs b/src/test/ui/regions/regions-infer-region-in-fn-but-not-type.rs new file mode 100644 index 000000000..6aa5d8217 --- /dev/null +++ b/src/test/ui/regions/regions-infer-region-in-fn-but-not-type.rs @@ -0,0 +1,19 @@ +// run-pass +#![allow(dead_code)] +#![allow(unused_variables)] +#![allow(non_camel_case_types)] + + +// check that the &isize here does not cause us to think that `foo` +// contains region pointers +// pretty-expanded FIXME #23616 + +struct foo(Box<dyn FnMut(&isize)+'static>); + +fn take_foo<T:'static>(x: T) {} + +fn have_foo(f: foo) { + take_foo(f); +} + +fn main() {} diff --git a/src/test/ui/regions/regions-infer-static-from-proc.rs b/src/test/ui/regions/regions-infer-static-from-proc.rs new file mode 100644 index 000000000..39501e2d6 --- /dev/null +++ b/src/test/ui/regions/regions-infer-static-from-proc.rs @@ -0,0 +1,18 @@ +// run-pass +#![allow(non_upper_case_globals)] + +// Check that the 'static bound on a proc influences lifetimes of +// region variables contained within (otherwise, region inference will +// give `x` a very short lifetime). + +// pretty-expanded FIXME #23616 + +static i: usize = 3; +fn foo<F:FnOnce()+'static>(_: F) {} +fn read(_: usize) { } +pub fn main() { + let x = &i; + foo(move|| { + read(*x); + }); +} diff --git a/src/test/ui/regions/regions-issue-21422.rs b/src/test/ui/regions/regions-issue-21422.rs new file mode 100644 index 000000000..198b71466 --- /dev/null +++ b/src/test/ui/regions/regions-issue-21422.rs @@ -0,0 +1,18 @@ +// run-pass +// Regression test for issue #21422, which was related to failing to +// add inference constraints that the operands of a binary operator +// should outlive the binary operation itself. + +// pretty-expanded FIXME #23616 + +pub struct P<'a> { + _ptr: *const &'a u8, +} + +impl <'a> PartialEq for P<'a> { + fn eq(&self, other: &P<'a>) -> bool { + (self as *const _) == (other as *const _) + } +} + +fn main() {} diff --git a/src/test/ui/regions/regions-issue-22246.rs b/src/test/ui/regions/regions-issue-22246.rs new file mode 100644 index 000000000..085883367 --- /dev/null +++ b/src/test/ui/regions/regions-issue-22246.rs @@ -0,0 +1,29 @@ +// run-pass +#![allow(unused_imports)] +// Regression test for issue #22246 -- we should be able to deduce +// that `&'a B::Owned` implies that `B::Owned : 'a`. + +// pretty-expanded FIXME #23616 + +#![allow(dead_code)] + +use std::ops::Deref; + +pub trait ToOwned: Sized { + type Owned: Borrow<Self>; + fn to_owned(&self) -> Self::Owned; +} + +pub trait Borrow<Borrowed> { + fn borrow(&self) -> &Borrowed; +} + +pub struct Foo<B:ToOwned> { + owned: B::Owned +} + +fn foo<B:ToOwned>(this: &Foo<B>) -> &B { + this.owned.borrow() +} + +fn main() { } diff --git a/src/test/ui/regions/regions-lifetime-bounds-on-fns.rs b/src/test/ui/regions/regions-lifetime-bounds-on-fns.rs new file mode 100644 index 000000000..177f52fa7 --- /dev/null +++ b/src/test/ui/regions/regions-lifetime-bounds-on-fns.rs @@ -0,0 +1,30 @@ +fn a<'a, 'b:'a>(x: &mut &'a isize, y: &mut &'b isize) { + // Note: this is legal because of the `'b:'a` declaration. + *x = *y; +} + +fn b<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) { + // Illegal now because there is no `'b:'a` declaration. + *x = *y; +} + +fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) { + // Here we try to call `foo` but do not know that `'a` and `'b` are + // related as required. + a(x, y); +} + +fn d() { + // 'a and 'b are early bound in the function `a` because they appear + // inconstraints: + let _: fn(&mut &isize, &mut &isize) = a; + //~^ ERROR mismatched types [E0308] +} + +fn e() { + // 'a and 'b are late bound in the function `b` because there are + // no constraints: + let _: fn(&mut &isize, &mut &isize) = b; +} + +fn main() { } diff --git a/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr b/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr new file mode 100644 index 000000000..a0daf58c6 --- /dev/null +++ b/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/regions-lifetime-bounds-on-fns.rs:20:43 + | +LL | let _: fn(&mut &isize, &mut &isize) = a; + | ^ one type is more general than the other + | + = note: expected fn pointer `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)` + found fn item `for<'r, 's> fn(&'r mut &isize, &'s mut &isize) {a::<'_, '_>}` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/regions/regions-lifetime-nonfree-late-bound.rs b/src/test/ui/regions/regions-lifetime-nonfree-late-bound.rs new file mode 100644 index 000000000..3852a14d9 --- /dev/null +++ b/src/test/ui/regions/regions-lifetime-nonfree-late-bound.rs @@ -0,0 +1,33 @@ +// run-pass +// This is a regression test for the ICE from issue #10846. +// +// The original issue causing the ICE: the LUB-computations during +// type inference were encountering late-bound lifetimes, and +// asserting that such lifetimes should have already been substituted +// with a concrete lifetime. +// +// However, those encounters were occurring within the lexical scope +// of the binding for the late-bound lifetime; that is, the late-bound +// lifetimes were perfectly valid. The core problem was that the type +// folding code was over-zealously passing back all lifetimes when +// doing region-folding, when really all clients of the region-folding +// case only want to see FREE lifetime variables, not bound ones. + +// pretty-expanded FIXME #23616 + +pub fn main() { + fn explicit() { + fn test<F>(_x: Option<Box<F>>) where F: FnMut(Box<dyn for<'a> FnMut(&'a isize)>) {} + test(Some(Box::new(|_f: Box<dyn for<'a> FnMut(&'a isize)>| {}))); + } + + // The code below is shorthand for the code above (and more likely + // to represent what one encounters in practice). + fn implicit() { + fn test<F>(_x: Option<Box<F>>) where F: FnMut(Box<dyn FnMut(& isize)>) {} + test(Some(Box::new(|_f: Box<dyn FnMut(& isize)>| {}))); + } + + explicit(); + implicit(); +} diff --git a/src/test/ui/regions/regions-lifetime-of-struct-or-enum-variant.rs b/src/test/ui/regions/regions-lifetime-of-struct-or-enum-variant.rs new file mode 100644 index 000000000..1b25294c7 --- /dev/null +++ b/src/test/ui/regions/regions-lifetime-of-struct-or-enum-variant.rs @@ -0,0 +1,26 @@ +// This tests verifies that unary structs and enum variants +// are treated as rvalues and their lifetime is not bounded to +// the static scope. + +fn id<T>(x: T) -> T { x } + +struct Test; + +enum MyEnum { + Variant1 +} + +fn structLifetime<'a>() -> &'a Test { + let testValue = &id(Test); + testValue + //~^ ERROR cannot return value referencing temporary value +} + +fn variantLifetime<'a>() -> &'a MyEnum { + let testValue = &id(MyEnum::Variant1); + testValue + //~^ ERROR cannot return value referencing temporary value +} + + +fn main() {} diff --git a/src/test/ui/regions/regions-lifetime-of-struct-or-enum-variant.stderr b/src/test/ui/regions/regions-lifetime-of-struct-or-enum-variant.stderr new file mode 100644 index 000000000..b4bf2ab31 --- /dev/null +++ b/src/test/ui/regions/regions-lifetime-of-struct-or-enum-variant.stderr @@ -0,0 +1,19 @@ +error[E0515]: cannot return value referencing temporary value + --> $DIR/regions-lifetime-of-struct-or-enum-variant.rs:15:3 + | +LL | let testValue = &id(Test); + | -------- temporary value created here +LL | testValue + | ^^^^^^^^^ returns a value referencing data owned by the current function + +error[E0515]: cannot return value referencing temporary value + --> $DIR/regions-lifetime-of-struct-or-enum-variant.rs:21:3 + | +LL | let testValue = &id(MyEnum::Variant1); + | -------------------- temporary value created here +LL | testValue + | ^^^^^^^^^ returns a value referencing data owned by the current function + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/regions/regions-lifetime-static-items-enclosing-scopes.rs b/src/test/ui/regions/regions-lifetime-static-items-enclosing-scopes.rs new file mode 100644 index 000000000..b6a89e29e --- /dev/null +++ b/src/test/ui/regions/regions-lifetime-static-items-enclosing-scopes.rs @@ -0,0 +1,20 @@ +// run-pass +#![allow(dead_code)] +// This test verifies that temporary lifetime is correctly computed +// for static objects in enclosing scopes. + + +use std::cmp::PartialEq; + +fn f<T:PartialEq+std::fmt::Debug>(o: &mut Option<T>) { + assert_eq!(*o, None); +} + +pub fn main() { + mod t { + enum E {V=1, A=0} + static C: E = E::V; + } + + f::<isize>(&mut None); +} diff --git a/src/test/ui/regions/regions-link-fn-args.rs b/src/test/ui/regions/regions-link-fn-args.rs new file mode 100644 index 000000000..231407b22 --- /dev/null +++ b/src/test/ui/regions/regions-link-fn-args.rs @@ -0,0 +1,15 @@ +// run-pass +// Test that region inference correctly links up the regions when a +// `ref` borrow occurs inside a fn argument. + +// pretty-expanded FIXME #23616 + +#![allow(dead_code)] + +fn with<'a, F>(_: F) where F: FnOnce(&'a Vec<isize>) -> &'a Vec<isize> { } + +fn foo() { + with(|&ref ints| ints); +} + +fn main() { } diff --git a/src/test/ui/regions/regions-lub-ref-ref-rc.rs b/src/test/ui/regions/regions-lub-ref-ref-rc.rs new file mode 100644 index 000000000..96c71b084 --- /dev/null +++ b/src/test/ui/regions/regions-lub-ref-ref-rc.rs @@ -0,0 +1,28 @@ +// run-pass +#![allow(dead_code)] +// Test a corner case of LUB coercion. In this case, one arm of the +// match requires a deref coercion and the other doesn't, and there +// is an extra `&` on the `rc`. We want to be sure that the lifetime +// assigned to this `&rc` value is not `'a` but something smaller. In +// other words, the type from `rc` is `&'a Rc<String>` and the type +// from `&rc` should be `&'x &'a Rc<String>`, where `'x` is something +// small. + +use std::rc::Rc; + +#[derive(Clone)] +enum Cached<'mir> { + Ref(&'mir String), + Owned(Rc<String>), +} + +impl<'mir> Cached<'mir> { + fn get_ref<'a>(&'a self) -> &'a String { + match *self { + Cached::Ref(r) => r, + Cached::Owned(ref rc) => &rc, + } + } +} + +fn main() { } diff --git a/src/test/ui/regions/regions-mock-codegen.rs b/src/test/ui/regions/regions-mock-codegen.rs new file mode 100644 index 000000000..9d0ca76e4 --- /dev/null +++ b/src/test/ui/regions/regions-mock-codegen.rs @@ -0,0 +1,54 @@ +// run-pass +#![allow(dead_code)] +#![allow(non_camel_case_types)] +// pretty-expanded FIXME #23616 +#![feature(allocator_api)] + +use std::alloc::{handle_alloc_error, Allocator, Global, Layout}; +use std::ptr::NonNull; + +struct arena(()); + +struct Bcx<'a> { + fcx: &'a Fcx<'a>, +} + +struct Fcx<'a> { + arena: &'a arena, + ccx: &'a Ccx, +} + +struct Ccx { + x: isize, +} + +fn allocate(_bcx: &arena) -> &Bcx<'_> { + unsafe { + let layout = Layout::new::<Bcx>(); + let ptr = Global.allocate(layout).unwrap_or_else(|_| handle_alloc_error(layout)); + &*(ptr.as_ptr() as *const _) + } +} + +fn h<'a>(bcx: &'a Bcx<'a>) -> &'a Bcx<'a> { + return allocate(bcx.fcx.arena); +} + +fn g(fcx: &Fcx) { + let bcx = Bcx { fcx }; + let bcx2 = h(&bcx); + unsafe { + Global.deallocate(NonNull::new_unchecked(bcx2 as *const _ as *mut _), Layout::new::<Bcx>()); + } +} + +fn f(ccx: &Ccx) { + let a = arena(()); + let fcx = Fcx { arena: &a, ccx }; + return g(&fcx); +} + +pub fn main() { + let ccx = Ccx { x: 0 }; + f(&ccx); +} diff --git a/src/test/ui/regions/regions-name-duplicated.rs b/src/test/ui/regions/regions-name-duplicated.rs new file mode 100644 index 000000000..f6616591a --- /dev/null +++ b/src/test/ui/regions/regions-name-duplicated.rs @@ -0,0 +1,6 @@ +struct Foo<'a, 'a> { + //~^ ERROR the name `'a` is already used for a generic parameter + x: &'a isize, +} + +fn main() {} diff --git a/src/test/ui/regions/regions-name-duplicated.stderr b/src/test/ui/regions/regions-name-duplicated.stderr new file mode 100644 index 000000000..cef73c18d --- /dev/null +++ b/src/test/ui/regions/regions-name-duplicated.stderr @@ -0,0 +1,11 @@ +error[E0403]: the name `'a` is already used for a generic parameter in this item's generic parameters + --> $DIR/regions-name-duplicated.rs:1:16 + | +LL | struct Foo<'a, 'a> { + | -- ^^ already used + | | + | first use of `'a` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0403`. diff --git a/src/test/ui/regions/regions-name-static.rs b/src/test/ui/regions/regions-name-static.rs new file mode 100644 index 000000000..da316c6ef --- /dev/null +++ b/src/test/ui/regions/regions-name-static.rs @@ -0,0 +1,6 @@ +struct Foo<'static> { + //~^ ERROR invalid lifetime parameter name: `'static` + x: &'static isize, +} + +fn main() {} diff --git a/src/test/ui/regions/regions-name-static.stderr b/src/test/ui/regions/regions-name-static.stderr new file mode 100644 index 000000000..4b7026e65 --- /dev/null +++ b/src/test/ui/regions/regions-name-static.stderr @@ -0,0 +1,9 @@ +error[E0262]: invalid lifetime parameter name: `'static` + --> $DIR/regions-name-static.rs:1:12 + | +LL | struct Foo<'static> { + | ^^^^^^^ 'static is a reserved lifetime name + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0262`. diff --git a/src/test/ui/regions/regions-name-undeclared.rs b/src/test/ui/regions/regions-name-undeclared.rs new file mode 100644 index 000000000..7b6ede193 --- /dev/null +++ b/src/test/ui/regions/regions-name-undeclared.rs @@ -0,0 +1,58 @@ +// edition:2018 +// Check that lifetime resolver enforces the lifetime name scoping +// rules correctly in various scenarios. + +struct Foo<'a> { + x: &'a isize +} + +impl<'a> Foo<'a> { + // &'a is inherited: + fn m1(&self, arg: &'a isize) { } + fn m2(&'a self) { } + fn m3(&self, arg: Foo<'a>) { } + + // &'b is not: + fn m4(&self, arg: &'b isize) { } //~ ERROR undeclared lifetime + fn m5(&'b self) { } //~ ERROR undeclared lifetime + fn m6(&self, arg: Foo<'b>) { } //~ ERROR undeclared lifetime +} + +fn bar<'a>(x: &'a isize) { + // &'a is visible to code: + let y: &'a isize = x; + + // &'a is not visible to *items*: + type X = Option<&'a isize>; //~ ERROR can't use generic parameters from outer item + enum E { + E1(&'a isize) //~ ERROR can't use generic parameters from outer item + } + struct S { + f: &'a isize //~ ERROR can't use generic parameters from outer item + } + fn f(a: &'a isize) { } //~ ERROR can't use generic parameters from outer item + + // &'a CAN be declared on functions and used then: + fn g<'a>(a: &'a isize) { } // OK + fn h(a: Box<dyn for<'a> FnOnce(&'a isize)>) { } // OK +} + +// Test nesting of lifetimes in fn type declarations +fn fn_types(a: &'a isize, //~ ERROR undeclared lifetime + b: Box<dyn for<'a> FnOnce(&'a isize, + &'b isize, //~ ERROR undeclared lifetime + Box<dyn for<'b> FnOnce(&'a isize, + &'b isize)>, + &'b isize)>, //~ ERROR undeclared lifetime + c: &'a isize) //~ ERROR undeclared lifetime +{ +} + +struct Bug {} +impl Bug { + async fn buggy(&self) -> &'a str { //~ ERROR use of undeclared lifetime name `'a` + todo!() + } +} + +pub fn main() {} diff --git a/src/test/ui/regions/regions-name-undeclared.stderr b/src/test/ui/regions/regions-name-undeclared.stderr new file mode 100644 index 000000000..532603de5 --- /dev/null +++ b/src/test/ui/regions/regions-name-undeclared.stderr @@ -0,0 +1,156 @@ +error[E0261]: use of undeclared lifetime name `'b` + --> $DIR/regions-name-undeclared.rs:16:24 + | +LL | fn m4(&self, arg: &'b isize) { } + | ^^ undeclared lifetime + | +help: consider introducing lifetime `'b` here + | +LL | fn m4<'b>(&self, arg: &'b isize) { } + | ++++ +help: consider introducing lifetime `'b` here + | +LL | impl<'b, 'a> Foo<'a> { + | +++ + +error[E0261]: use of undeclared lifetime name `'b` + --> $DIR/regions-name-undeclared.rs:17:12 + | +LL | fn m5(&'b self) { } + | ^^ undeclared lifetime + | +help: consider introducing lifetime `'b` here + | +LL | fn m5<'b>(&'b self) { } + | ++++ +help: consider introducing lifetime `'b` here + | +LL | impl<'b, 'a> Foo<'a> { + | +++ + +error[E0261]: use of undeclared lifetime name `'b` + --> $DIR/regions-name-undeclared.rs:18:27 + | +LL | fn m6(&self, arg: Foo<'b>) { } + | ^^ undeclared lifetime + | +help: consider introducing lifetime `'b` here + | +LL | fn m6<'b>(&self, arg: Foo<'b>) { } + | ++++ +help: consider introducing lifetime `'b` here + | +LL | impl<'b, 'a> Foo<'a> { + | +++ + +error[E0401]: can't use generic parameters from outer item + --> $DIR/regions-name-undeclared.rs:26:22 + | +LL | fn bar<'a>(x: &'a isize) { + | -- lifetime parameter from outer item +... +LL | type X = Option<&'a isize>; + | - ^^ use of generic parameter from outer item + | | + | help: consider introducing lifetime `'a` here: `<'a>` + +error[E0401]: can't use generic parameters from outer item + --> $DIR/regions-name-undeclared.rs:28:13 + | +LL | fn bar<'a>(x: &'a isize) { + | -- lifetime parameter from outer item +... +LL | enum E { + | - help: consider introducing lifetime `'a` here: `<'a>` +LL | E1(&'a isize) + | ^^ use of generic parameter from outer item + +error[E0401]: can't use generic parameters from outer item + --> $DIR/regions-name-undeclared.rs:31:13 + | +LL | fn bar<'a>(x: &'a isize) { + | -- lifetime parameter from outer item +... +LL | struct S { + | - help: consider introducing lifetime `'a` here: `<'a>` +LL | f: &'a isize + | ^^ use of generic parameter from outer item + +error[E0401]: can't use generic parameters from outer item + --> $DIR/regions-name-undeclared.rs:33:14 + | +LL | fn bar<'a>(x: &'a isize) { + | -- lifetime parameter from outer item +... +LL | fn f(a: &'a isize) { } + | - ^^ use of generic parameter from outer item + | | + | help: consider introducing lifetime `'a` here: `<'a>` + +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/regions-name-undeclared.rs:41:17 + | +LL | fn fn_types(a: &'a isize, + | - ^^ undeclared lifetime + | | + | help: consider introducing lifetime `'a` here: `<'a>` + +error[E0261]: use of undeclared lifetime name `'b` + --> $DIR/regions-name-undeclared.rs:43:36 + | +LL | ... &'b isize, + | ^^ undeclared lifetime + | + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the bound lifetime-generic with a new `'b` lifetime + | +LL | b: Box<dyn for<'b, 'a> FnOnce(&'a isize, + | +++ +help: consider introducing lifetime `'b` here + | +LL | fn fn_types<'b>(a: &'a isize, + | ++++ + +error[E0261]: use of undeclared lifetime name `'b` + --> $DIR/regions-name-undeclared.rs:46:36 + | +LL | ... &'b isize)>, + | ^^ undeclared lifetime + | +help: consider making the bound lifetime-generic with a new `'b` lifetime + | +LL | b: Box<dyn for<'b, 'a> FnOnce(&'a isize, + | +++ +help: consider introducing lifetime `'b` here + | +LL | fn fn_types<'b>(a: &'a isize, + | ++++ + +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/regions-name-undeclared.rs:47:17 + | +LL | fn fn_types(a: &'a isize, + | - help: consider introducing lifetime `'a` here: `<'a>` +... +LL | c: &'a isize) + | ^^ undeclared lifetime + +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/regions-name-undeclared.rs:53:31 + | +LL | async fn buggy(&self) -> &'a str { + | ^^ undeclared lifetime + | +help: consider introducing lifetime `'a` here + | +LL | async fn buggy<'a>(&self) -> &'a str { + | ++++ +help: consider introducing lifetime `'a` here + | +LL | impl<'a> Bug { + | ++++ + +error: aborting due to 12 previous errors + +Some errors have detailed explanations: E0261, E0401. +For more information about an error, try `rustc --explain E0261`. diff --git a/src/test/ui/regions/regions-nested-fns-2.rs b/src/test/ui/regions/regions-nested-fns-2.rs new file mode 100644 index 000000000..3b3e26c45 --- /dev/null +++ b/src/test/ui/regions/regions-nested-fns-2.rs @@ -0,0 +1,12 @@ +fn ignore<F>(_f: F) where F: for<'z> FnOnce(&'z isize) -> &'z isize {} + +fn nested() { + let y = 3; + ignore( + |z| { + if false { &y } else { z } + //~^ ERROR `y` does not live long enough + }); +} + +fn main() {} diff --git a/src/test/ui/regions/regions-nested-fns-2.stderr b/src/test/ui/regions/regions-nested-fns-2.stderr new file mode 100644 index 000000000..43c8d1272 --- /dev/null +++ b/src/test/ui/regions/regions-nested-fns-2.stderr @@ -0,0 +1,17 @@ +error[E0597]: `y` does not live long enough + --> $DIR/regions-nested-fns-2.rs:7:25 + | +LL | |z| { + | --- value captured here +LL | if false { &y } else { z } + | -^ + | || + | |borrowed value does not live long enough + | returning this value requires that `y` is borrowed for `'static` +... +LL | } + | - `y` dropped here while still borrowed + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/regions/regions-nested-fns.rs b/src/test/ui/regions/regions-nested-fns.rs new file mode 100644 index 000000000..d9698ced3 --- /dev/null +++ b/src/test/ui/regions/regions-nested-fns.rs @@ -0,0 +1,24 @@ +fn ignore<T>(t: T) {} + +fn nested<'x>(x: &'x isize) { + let y = 3; + let mut ay = &y; + //~^ ERROR `y` does not live long enough [E0597] + + ignore::<Box<dyn for<'z> FnMut(&'z isize)>>(Box::new(|z| { + ay = x; + ay = &y; + //~^ ERROR `y` does not live long enough + ay = z; + //~^ ERROR borrowed data escapes outside of closure [E0521] + })); + + ignore::< Box<dyn for<'z> FnMut(&'z isize) -> &'z isize>>(Box::new(|z| { + if false { return x; } + //~^ ERROR lifetime may not live long enough + if false { return ay; } + return z; + })); +} + +fn main() {} diff --git a/src/test/ui/regions/regions-nested-fns.stderr b/src/test/ui/regions/regions-nested-fns.stderr new file mode 100644 index 000000000..bb2740310 --- /dev/null +++ b/src/test/ui/regions/regions-nested-fns.stderr @@ -0,0 +1,52 @@ +error[E0521]: borrowed data escapes outside of closure + --> $DIR/regions-nested-fns.rs:12:9 + | +LL | let mut ay = &y; + | ------ `ay` declared here, outside of the closure body +... +LL | ignore::<Box<dyn for<'z> FnMut(&'z isize)>>(Box::new(|z| { + | - `z` is a reference that is only valid in the closure body +... +LL | ay = z; + | ^^^^^^ `z` escapes the closure body here + +error[E0597]: `y` does not live long enough + --> $DIR/regions-nested-fns.rs:5:18 + | +LL | let mut ay = &y; + | ^^ borrowed value does not live long enough +... +LL | if false { return ay; } + | -- returning this value requires that `y` is borrowed for `'static` +... +LL | } + | - `y` dropped here while still borrowed + +error[E0597]: `y` does not live long enough + --> $DIR/regions-nested-fns.rs:10:15 + | +LL | ignore::<Box<dyn for<'z> FnMut(&'z isize)>>(Box::new(|z| { + | --- value captured here +LL | ay = x; +LL | ay = &y; + | ^ borrowed value does not live long enough +... +LL | if false { return ay; } + | -- returning this value requires that `y` is borrowed for `'static` +... +LL | } + | - `y` dropped here while still borrowed + +error: lifetime may not live long enough + --> $DIR/regions-nested-fns.rs:17:27 + | +LL | fn nested<'x>(x: &'x isize) { + | -- lifetime `'x` defined here +... +LL | if false { return x; } + | ^ returning this value requires that `'x` must outlive `'static` + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0521, E0597. +For more information about an error, try `rustc --explain E0521`. diff --git a/src/test/ui/regions/regions-no-bound-in-argument-cleanup.rs b/src/test/ui/regions/regions-no-bound-in-argument-cleanup.rs new file mode 100644 index 000000000..aafab5d86 --- /dev/null +++ b/src/test/ui/regions/regions-no-bound-in-argument-cleanup.rs @@ -0,0 +1,24 @@ +// run-pass +// pretty-expanded FIXME #23616 + +use std::marker; + +pub struct Foo<T>(marker::PhantomData<T>); + +impl<T> Iterator for Foo<T> { + type Item = T; + + fn next(&mut self) -> Option<T> { + None + } +} + +impl<T> Drop for Foo<T> { + fn drop(&mut self) { + self.next(); + } +} + +pub fn foo<'a>(_: Foo<&'a ()>) {} + +pub fn main() {} diff --git a/src/test/ui/regions/regions-no-variance-from-fn-generics.rs b/src/test/ui/regions/regions-no-variance-from-fn-generics.rs new file mode 100644 index 000000000..76706a827 --- /dev/null +++ b/src/test/ui/regions/regions-no-variance-from-fn-generics.rs @@ -0,0 +1,44 @@ +// run-pass +#![allow(unused_variables)] +// Issue #12856: a lifetime formal binding introduced by a generic fn +// should not upset the variance inference for actual occurrences of +// that lifetime in type expressions. + + +pub trait HasLife<'a> { + fn dummy(&'a self) { } // just to induce a variance on 'a +} + +trait UseLife01 { + fn refs<'a, H: HasLife<'a>>(&'a self) -> H; +} + +trait UseLife02 { + fn refs<'a, T: 'a, H: HasType<&'a T>>(&'a self) -> H; +} + + +pub trait HasType<T> +{ + fn dummy(&self, t: T) -> T { panic!() } +} + + +trait UseLife03<T> { + fn refs<'a, H: HasType<&'a T>>(&'a self) -> H where T: 'a; +} + + +// (The functions below were not actually a problem observed during +// fixing of #12856; they just seem like natural tests to put in to +// cover a couple more points in the testing space) + +pub fn top_refs_1<'a, H: HasLife<'a>>(_s: &'a ()) -> H { + unimplemented!() +} + +pub fn top_refs_2<'a, T: 'a, H: HasType<&'a T>>(_s: &'a ()) -> H { + unimplemented!() +} + +pub fn main() {} diff --git a/src/test/ui/regions/regions-normalize-in-where-clause-list.rs b/src/test/ui/regions/regions-normalize-in-where-clause-list.rs new file mode 100644 index 000000000..389f82e79 --- /dev/null +++ b/src/test/ui/regions/regions-normalize-in-where-clause-list.rs @@ -0,0 +1,31 @@ +// Test that we are able to normalize in the list of where-clauses, +// even if `'a: 'b` is required. + +trait Project<'a, 'b> { + type Item; +} + +impl<'a, 'b> Project<'a, 'b> for () +where + 'a: 'b, +{ + type Item = (); +} + +// No error here, we have 'a: 'b. We used to report an error here +// though, see https://github.com/rust-lang/rust/issues/45937. +fn foo<'a: 'b, 'b>() +where + <() as Project<'a, 'b>>::Item: Eq, +{ +} + +// Here we get an error: we need `'a: 'b`. +fn bar<'a, 'b>() +//~^ ERROR cannot infer +where + <() as Project<'a, 'b>>::Item: Eq, +{ +} + +fn main() {} diff --git a/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr b/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr new file mode 100644 index 000000000..567283729 --- /dev/null +++ b/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr @@ -0,0 +1,27 @@ +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements + --> $DIR/regions-normalize-in-where-clause-list.rs:24:4 + | +LL | fn bar<'a, 'b>() + | ^^^ + | +note: first, the lifetime cannot outlive the lifetime `'a` as defined here... + --> $DIR/regions-normalize-in-where-clause-list.rs:24:8 + | +LL | fn bar<'a, 'b>() + | ^^ +note: ...but the lifetime must also be valid for the lifetime `'b` as defined here... + --> $DIR/regions-normalize-in-where-clause-list.rs:24:12 + | +LL | fn bar<'a, 'b>() + | ^^ +note: ...so that the types are compatible + --> $DIR/regions-normalize-in-where-clause-list.rs:24:4 + | +LL | fn bar<'a, 'b>() + | ^^^ + = note: expected `Project<'a, 'b>` + found `Project<'_, '_>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-nullary-variant.rs b/src/test/ui/regions/regions-nullary-variant.rs new file mode 100644 index 000000000..82470af82 --- /dev/null +++ b/src/test/ui/regions/regions-nullary-variant.rs @@ -0,0 +1,15 @@ +// run-pass +#![allow(dead_code)] +#![allow(non_camel_case_types)] + +// pretty-expanded FIXME #23616 + +enum roption<'a> { + a, b(&'a usize) +} + +fn mk(cond: bool, ptr: &usize) -> roption { + if cond {roption::a} else {roption::b(ptr)} +} + +pub fn main() {} diff --git a/src/test/ui/regions/regions-outlives-nominal-type-enum-region-rev.rs b/src/test/ui/regions/regions-outlives-nominal-type-enum-region-rev.rs new file mode 100644 index 000000000..15deaba56 --- /dev/null +++ b/src/test/ui/regions/regions-outlives-nominal-type-enum-region-rev.rs @@ -0,0 +1,20 @@ +// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its +// arguments (like `'a`) outlive `'b`. +// +// Rule OutlivesNominalType from RFC 1214. + +// check-pass + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +mod rev_variant_struct_region { + struct Foo<'a> { + x: fn(&'a i32), + } + enum Bar<'a,'b> { + V(&'a Foo<'b>) + } +} + +fn main() { } diff --git a/src/test/ui/regions/regions-outlives-nominal-type-enum-region.rs b/src/test/ui/regions/regions-outlives-nominal-type-enum-region.rs new file mode 100644 index 000000000..7767c13c8 --- /dev/null +++ b/src/test/ui/regions/regions-outlives-nominal-type-enum-region.rs @@ -0,0 +1,20 @@ +// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its +// arguments (like `'a`) outlive `'b`. +// +// Rule OutlivesNominalType from RFC 1214. + +// check-pass + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +mod variant_struct_region { + struct Foo<'a> { + x: &'a i32, + } + enum Bar<'a,'b> { + V(&'a Foo<'b>) + } +} + +fn main() { } diff --git a/src/test/ui/regions/regions-outlives-nominal-type-enum-type-rev.rs b/src/test/ui/regions/regions-outlives-nominal-type-enum-type-rev.rs new file mode 100644 index 000000000..374159942 --- /dev/null +++ b/src/test/ui/regions/regions-outlives-nominal-type-enum-type-rev.rs @@ -0,0 +1,20 @@ +// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its +// arguments (like `'a`) outlive `'b`. +// +// Rule OutlivesNominalType from RFC 1214. + +// check-pass + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +mod variant_struct_type { + struct Foo<T> { + x: fn(T) + } + enum Bar<'a,'b> { + V(&'a Foo<&'b i32>) + } +} + +fn main() { } diff --git a/src/test/ui/regions/regions-outlives-nominal-type-enum-type.rs b/src/test/ui/regions/regions-outlives-nominal-type-enum-type.rs new file mode 100644 index 000000000..2e7f198d8 --- /dev/null +++ b/src/test/ui/regions/regions-outlives-nominal-type-enum-type.rs @@ -0,0 +1,20 @@ +// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its +// arguments (like `'a`) outlive `'b`. +// +// Rule OutlivesNominalType from RFC 1214. + +// check-pass + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +mod variant_struct_type { + struct Foo<T> { + x: T + } + enum Bar<'a,'b> { + V(&'a Foo<&'b i32>) + } +} + +fn main() { } diff --git a/src/test/ui/regions/regions-outlives-nominal-type-struct-region-rev.rs b/src/test/ui/regions/regions-outlives-nominal-type-struct-region-rev.rs new file mode 100644 index 000000000..45155c721 --- /dev/null +++ b/src/test/ui/regions/regions-outlives-nominal-type-struct-region-rev.rs @@ -0,0 +1,20 @@ +// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its +// arguments (like `'a`) outlive `'b`. +// +// Rule OutlivesNominalType from RFC 1214. + +// check-pass + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +mod rev_variant_struct_region { + struct Foo<'a> { + x: fn(&'a i32), + } + struct Bar<'a,'b> { + f: &'a Foo<'b> + } +} + +fn main() { } diff --git a/src/test/ui/regions/regions-outlives-nominal-type-struct-region.rs b/src/test/ui/regions/regions-outlives-nominal-type-struct-region.rs new file mode 100644 index 000000000..bba8b2445 --- /dev/null +++ b/src/test/ui/regions/regions-outlives-nominal-type-struct-region.rs @@ -0,0 +1,20 @@ +// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its +// arguments (like `'a`) outlive `'b`. +// +// Rule OutlivesNominalType from RFC 1214. + +// check-pass + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +mod variant_struct_region { + struct Foo<'a> { + x: &'a i32, + } + struct Bar<'a,'b> { + f: &'a Foo<'b> + } +} + +fn main() { } diff --git a/src/test/ui/regions/regions-outlives-nominal-type-struct-type-rev.rs b/src/test/ui/regions/regions-outlives-nominal-type-struct-type-rev.rs new file mode 100644 index 000000000..220d2e83c --- /dev/null +++ b/src/test/ui/regions/regions-outlives-nominal-type-struct-type-rev.rs @@ -0,0 +1,20 @@ +// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its +// arguments (like `'a`) outlive `'b`. +// +// Rule OutlivesNominalType from RFC 1214. + +// check-pass + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +mod rev_variant_struct_type { + struct Foo<T> { + x: fn(T) + } + struct Bar<'a,'b> { + f: &'a Foo<&'b i32> + } +} + +fn main() { } diff --git a/src/test/ui/regions/regions-outlives-nominal-type-struct-type.rs b/src/test/ui/regions/regions-outlives-nominal-type-struct-type.rs new file mode 100644 index 000000000..9ddcdb649 --- /dev/null +++ b/src/test/ui/regions/regions-outlives-nominal-type-struct-type.rs @@ -0,0 +1,20 @@ +// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its +// arguments (like `'a`) outlive `'b`. +// +// Rule OutlivesNominalType from RFC 1214. + +// check-pass + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +mod variant_struct_type { + struct Foo<T> { + x: T + } + struct Bar<'a,'b> { + f: &'a Foo<&'b i32> + } +} + +fn main() { } diff --git a/src/test/ui/regions/regions-outlives-projection-container-hrtb.rs b/src/test/ui/regions/regions-outlives-projection-container-hrtb.rs new file mode 100644 index 000000000..152eed5ac --- /dev/null +++ b/src/test/ui/regions/regions-outlives-projection-container-hrtb.rs @@ -0,0 +1,52 @@ +// Test that structs with higher-ranked where clauses don't generate +// "outlives" requirements. Issue #22246. + +#![allow(dead_code)] + +pub trait TheTrait<'b> { + type TheAssocType; +} + +pub struct TheType<'b> { + m: [fn(&'b()); 0] +} + +impl<'a,'b> TheTrait<'a> for TheType<'b> { + type TheAssocType = &'b (); +} + +pub struct WithHrAssoc<T> + where for<'a> T : TheTrait<'a> +{ + m: [T; 0] +} + +fn with_assoc<'a,'b>() { + // We get an error because 'b:'a does not hold: + + let _: &'a WithHrAssoc<TheType<'b>> = loop { }; + //~^ ERROR lifetime may not live long enough +} + +pub trait TheSubTrait : for<'a> TheTrait<'a> { +} + +impl<'b> TheSubTrait for TheType<'b> { } + +pub struct WithHrAssocSub<T> + where T : TheSubTrait +{ + m: [T; 0] +} + +fn with_assoc_sub<'a,'b>() { + // The error here is just because `'b:'a` must hold for the type + // below to be well-formed, it is not related to the HR relation. + + let _: &'a WithHrAssocSub<TheType<'b>> = loop { }; + //~^ ERROR lifetime may not live long enough +} + + +fn main() { +} diff --git a/src/test/ui/regions/regions-outlives-projection-container-hrtb.stderr b/src/test/ui/regions/regions-outlives-projection-container-hrtb.stderr new file mode 100644 index 000000000..187e9056e --- /dev/null +++ b/src/test/ui/regions/regions-outlives-projection-container-hrtb.stderr @@ -0,0 +1,28 @@ +error: lifetime may not live long enough + --> $DIR/regions-outlives-projection-container-hrtb.rs:27:12 + | +LL | fn with_assoc<'a,'b>() { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | let _: &'a WithHrAssoc<TheType<'b>> = loop { }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` + +error: lifetime may not live long enough + --> $DIR/regions-outlives-projection-container-hrtb.rs:46:12 + | +LL | fn with_assoc_sub<'a,'b>() { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | let _: &'a WithHrAssocSub<TheType<'b>> = loop { }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/regions/regions-outlives-projection-container-wc.rs b/src/test/ui/regions/regions-outlives-projection-container-wc.rs new file mode 100644 index 000000000..4fda7774b --- /dev/null +++ b/src/test/ui/regions/regions-outlives-projection-container-wc.rs @@ -0,0 +1,35 @@ +// Test that we are imposing the requirement that every associated +// type of a bound that appears in the where clause on a struct must +// outlive the location in which the type appears, even when the +// constraint is in a where clause not a bound. Issue #22246. + +#![allow(dead_code)] + +pub trait TheTrait { + type TheAssocType; +} + +pub struct TheType<'b> { + m: [fn(&'b()); 0] +} + +impl<'b> TheTrait for TheType<'b> { + type TheAssocType = &'b (); +} + +pub struct WithAssoc<T> where T : TheTrait { + m: [T; 0] +} + +fn with_assoc<'a,'b>() { + // For this type to be valid, the rules require that all + // associated types of traits that appear in `WithAssoc` must + // outlive 'a. In this case, that means TheType<'b>::TheAssocType, + // which is &'b (), must outlive 'a. + + let _: &'a WithAssoc<TheType<'b>> = loop { }; + //~^ ERROR lifetime may not live long enough +} + +fn main() { +} diff --git a/src/test/ui/regions/regions-outlives-projection-container-wc.stderr b/src/test/ui/regions/regions-outlives-projection-container-wc.stderr new file mode 100644 index 000000000..4178e951c --- /dev/null +++ b/src/test/ui/regions/regions-outlives-projection-container-wc.stderr @@ -0,0 +1,15 @@ +error: lifetime may not live long enough + --> $DIR/regions-outlives-projection-container-wc.rs:30:12 + | +LL | fn with_assoc<'a,'b>() { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | let _: &'a WithAssoc<TheType<'b>> = loop { }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-outlives-projection-container.rs b/src/test/ui/regions/regions-outlives-projection-container.rs new file mode 100644 index 000000000..7b9829cf8 --- /dev/null +++ b/src/test/ui/regions/regions-outlives-projection-container.rs @@ -0,0 +1,77 @@ +// Test that we are imposing the requirement that every associated +// type of a bound that appears in the where clause on a struct must +// outlive the location in which the type appears. Issue #22246. + +#![allow(dead_code)] +#![feature(rustc_attrs)] + +pub trait TheTrait { + type TheAssocType; +} + +pub struct TheType<'b> { + m: [fn(&'b()); 0] +} + +impl<'b> TheTrait for TheType<'b> { + type TheAssocType = &'b (); +} + +pub struct WithAssoc<T:TheTrait> { + m: [T; 0] +} + +pub struct WithoutAssoc<T> { + m: [T; 0] +} + +fn with_assoc<'a,'b>() { + // For this type to be valid, the rules require that all + // associated types of traits that appear in `WithAssoc` must + // outlive 'a. In this case, that means TheType<'b>::TheAssocType, + // which is &'b (), must outlive 'a. + + // FIXME (#54943) NLL doesn't enforce WF condition in unreachable code if + // `_x` is changed to `_` + let _x: &'a WithAssoc<TheType<'b>> = loop { }; + //~^ ERROR lifetime may not live long enough +} + +fn with_assoc1<'a,'b>() where 'b : 'a { + // For this type to be valid, the rules require that all + // associated types of traits that appear in `WithAssoc` must + // outlive 'a. In this case, that means TheType<'b>::TheAssocType, + // which is &'b (), must outlive 'a, so 'b : 'a must hold, and + // that is in the where clauses, so we're fine. + + let _x: &'a WithAssoc<TheType<'b>> = loop { }; +} + +fn without_assoc<'a,'b>() { + // Here there are no associated types but there is a requirement + // that `'b:'a` holds because the `'b` appears in `TheType<'b>`. + + let _x: &'a WithoutAssoc<TheType<'b>> = loop { }; + //~^ ERROR lifetime may not live long enough +} + +fn call_with_assoc<'a,'b>() { + // As `with_assoc`, but just checking that we impose the same rule + // on the value supplied for the type argument, even when there is + // no data. + + call::<&'a WithAssoc<TheType<'b>>>(); + //~^ ERROR lifetime may not live long enough +} + +fn call_without_assoc<'a,'b>() { + // As `without_assoc`, but in a distinct scenario. + + call::<&'a WithoutAssoc<TheType<'b>>>(); + //~^ ERROR lifetime may not live long enough +} + +fn call<T>() { } + +fn main() { +} diff --git a/src/test/ui/regions/regions-outlives-projection-container.stderr b/src/test/ui/regions/regions-outlives-projection-container.stderr new file mode 100644 index 000000000..073a31900 --- /dev/null +++ b/src/test/ui/regions/regions-outlives-projection-container.stderr @@ -0,0 +1,54 @@ +error: lifetime may not live long enough + --> $DIR/regions-outlives-projection-container.rs:36:13 + | +LL | fn with_assoc<'a,'b>() { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | let _x: &'a WithAssoc<TheType<'b>> = loop { }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` + +error: lifetime may not live long enough + --> $DIR/regions-outlives-projection-container.rs:54:13 + | +LL | fn without_assoc<'a,'b>() { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | let _x: &'a WithoutAssoc<TheType<'b>> = loop { }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` + +error: lifetime may not live long enough + --> $DIR/regions-outlives-projection-container.rs:63:5 + | +LL | fn call_with_assoc<'a,'b>() { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | call::<&'a WithAssoc<TheType<'b>>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` + +error: lifetime may not live long enough + --> $DIR/regions-outlives-projection-container.rs:70:5 + | +LL | fn call_without_assoc<'a,'b>() { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | call::<&'a WithoutAssoc<TheType<'b>>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/regions/regions-outlives-projection-hrtype.rs b/src/test/ui/regions/regions-outlives-projection-hrtype.rs new file mode 100644 index 000000000..5f9700df1 --- /dev/null +++ b/src/test/ui/regions/regions-outlives-projection-hrtype.rs @@ -0,0 +1,26 @@ +// Test for the outlives relation when applied to a projection on a +// type with bound regions. In this case, we are checking that +// `<for<'r> fn(&'r T) as TheTrait>::TheType: 'a` If we're not +// careful, we could wind up with a constraint that `'r:'a`, but since +// `'r` is bound, that leads to badness. This test checks that +// everything works. + +// check-pass +#![allow(dead_code)] + +trait TheTrait { + type TheType; +} + +fn wf<T>() { } + +type FnType<T> = for<'r> fn(&'r T); + +fn foo<'a,'b,T>() + where FnType<T>: TheTrait +{ + wf::< <FnType<T> as TheTrait>::TheType >(); +} + + +fn main() { } diff --git a/src/test/ui/regions/regions-outlives-projection-trait-def.rs b/src/test/ui/regions/regions-outlives-projection-trait-def.rs new file mode 100644 index 000000000..5c37a585a --- /dev/null +++ b/src/test/ui/regions/regions-outlives-projection-trait-def.rs @@ -0,0 +1,21 @@ +// Test that `<F as Foo<'a>>::Type: 'b`, where `trait Foo<'a> { Type: +// 'a; }`, does not require that `F: 'b`. + +// check-pass +#![allow(dead_code)] + +trait SomeTrait<'a> { + type Type: 'a; +} + +impl<'a: 'c, 'c, T> SomeTrait<'a> for &'c T where T: SomeTrait<'a> { + type Type = <T as SomeTrait<'a>>::Type; + // ~~~~~~~~~~~~~~~~~~~~~~~~~~ + // | + // Note that this type must outlive 'a, due to the trait + // definition. If we fall back to OutlivesProjectionComponents + // here, then we would require that `T:'a`, which is too strong. +} + + +fn main() { } diff --git a/src/test/ui/regions/regions-outlives-scalar.rs b/src/test/ui/regions/regions-outlives-scalar.rs new file mode 100644 index 000000000..ce34ffcc8 --- /dev/null +++ b/src/test/ui/regions/regions-outlives-scalar.rs @@ -0,0 +1,13 @@ +// Test that scalar values outlive all regions. +// Rule OutlivesScalar from RFC 1214. + +// check-pass +#![allow(dead_code)] + +struct Foo<'a> { + x: &'a i32, + y: &'static i32 +} + + +fn main() { } diff --git a/src/test/ui/regions/regions-params.rs b/src/test/ui/regions/regions-params.rs new file mode 100644 index 000000000..04f3b8eaf --- /dev/null +++ b/src/test/ui/regions/regions-params.rs @@ -0,0 +1,19 @@ +// run-pass +#![allow(unused_parens)] + + +fn region_identity(x: &usize) -> &usize { x } + +fn apply<T, F>(t: T, f: F) -> T where F: FnOnce(T) -> T { f(t) } + +fn parameterized(x: &usize) -> usize { + let z = apply(x, ({|y| + region_identity(y) + })); + *z +} + +pub fn main() { + let x = 3; + assert_eq!(parameterized(&x), 3); +} diff --git a/src/test/ui/regions/regions-pattern-typing-issue-19552.rs b/src/test/ui/regions/regions-pattern-typing-issue-19552.rs new file mode 100644 index 000000000..a64ab1c85 --- /dev/null +++ b/src/test/ui/regions/regions-pattern-typing-issue-19552.rs @@ -0,0 +1,8 @@ +fn assert_static<T: 'static>(_t: T) {} + +fn main() { + let line = String::new(); + match [&*line] { //~ ERROR `line` does not live long enough + [ word ] => { assert_static(word); } + } +} diff --git a/src/test/ui/regions/regions-pattern-typing-issue-19552.stderr b/src/test/ui/regions/regions-pattern-typing-issue-19552.stderr new file mode 100644 index 000000000..f77d94a24 --- /dev/null +++ b/src/test/ui/regions/regions-pattern-typing-issue-19552.stderr @@ -0,0 +1,14 @@ +error[E0597]: `line` does not live long enough + --> $DIR/regions-pattern-typing-issue-19552.rs:5:14 + | +LL | match [&*line] { + | ^^^^ borrowed value does not live long enough +LL | [ word ] => { assert_static(word); } + | ------------------- argument requires that `line` is borrowed for `'static` +LL | } +LL | } + | - `line` dropped here while still borrowed + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/regions/regions-pattern-typing-issue-19997.rs b/src/test/ui/regions/regions-pattern-typing-issue-19997.rs new file mode 100644 index 000000000..39190697f --- /dev/null +++ b/src/test/ui/regions/regions-pattern-typing-issue-19997.rs @@ -0,0 +1,11 @@ +fn main() { + let a0 = 0; + let f = 1; + let mut a1 = &a0; + match (&a1,) { + (&ref b0,) => { + a1 = &f; //~ ERROR cannot assign to `a1` because it is borrowed + drop(b0); + } + } +} diff --git a/src/test/ui/regions/regions-pattern-typing-issue-19997.stderr b/src/test/ui/regions/regions-pattern-typing-issue-19997.stderr new file mode 100644 index 000000000..ae60e3c0d --- /dev/null +++ b/src/test/ui/regions/regions-pattern-typing-issue-19997.stderr @@ -0,0 +1,14 @@ +error[E0506]: cannot assign to `a1` because it is borrowed + --> $DIR/regions-pattern-typing-issue-19997.rs:7:13 + | +LL | match (&a1,) { + | --- borrow of `a1` occurs here +LL | (&ref b0,) => { +LL | a1 = &f; + | ^^^^^^^ assignment to borrowed `a1` occurs here +LL | drop(b0); + | -- borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/regions/regions-proc-bound-capture.rs b/src/test/ui/regions/regions-proc-bound-capture.rs new file mode 100644 index 000000000..f79d9dc90 --- /dev/null +++ b/src/test/ui/regions/regions-proc-bound-capture.rs @@ -0,0 +1,13 @@ +fn borrowed_proc<'a>(x: &'a isize) -> Box<dyn FnMut()->(isize) + 'a> { + // This is legal, because the region bound on `proc` + // states that it captures `x`. + Box::new(move|| { *x }) +} + +fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + 'static> { + // This is illegal, because the region bound on `proc` is 'static. + Box::new(move || { *x }) + //~^ ERROR lifetime may not live long enough +} + +fn main() { } diff --git a/src/test/ui/regions/regions-proc-bound-capture.stderr b/src/test/ui/regions/regions-proc-bound-capture.stderr new file mode 100644 index 000000000..60c5246e2 --- /dev/null +++ b/src/test/ui/regions/regions-proc-bound-capture.stderr @@ -0,0 +1,20 @@ +error: lifetime may not live long enough + --> $DIR/regions-proc-bound-capture.rs:9:5 + | +LL | fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + 'static> { + | - let's call the lifetime of this reference `'1` +LL | // This is illegal, because the region bound on `proc` is 'static. +LL | Box::new(move || { *x }) + | ^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static` + | +help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `x` + | +LL | fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + '_> { + | ~~ +help: alternatively, add an explicit `'static` bound to this reference + | +LL | fn static_proc(x: &'static isize) -> Box<dyn FnMut() -> (isize) + 'static> { + | ~~~~~~~~~~~~~~ + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-reassign-let-bound-pointer.rs b/src/test/ui/regions/regions-reassign-let-bound-pointer.rs new file mode 100644 index 000000000..948b11e0f --- /dev/null +++ b/src/test/ui/regions/regions-reassign-let-bound-pointer.rs @@ -0,0 +1,18 @@ +// run-pass +#![allow(unused_assignments)] +#![allow(unused_variables)] +// Check that the type checker permits us to reassign `z` which +// started out with a longer lifetime and was reassigned to a shorter +// one (it should infer to be the intersection). + +// pretty-expanded FIXME #23616 + +fn foo(x: &isize) { + let a = 1; + let mut z = x; + z = &a; +} + +pub fn main() { + foo(&1); +} diff --git a/src/test/ui/regions/regions-reassign-match-bound-pointer.rs b/src/test/ui/regions/regions-reassign-match-bound-pointer.rs new file mode 100644 index 000000000..ca52659c4 --- /dev/null +++ b/src/test/ui/regions/regions-reassign-match-bound-pointer.rs @@ -0,0 +1,21 @@ +// run-pass +#![allow(unused_assignments)] +#![allow(unused_variables)] +// Check that the type checker permits us to reassign `z` which +// started out with a longer lifetime and was reassigned to a shorter +// one (it should infer to be the intersection). + +// pretty-expanded FIXME #23616 + +fn foo(x: &isize) { + let a = 1; + match x { + mut z => { + z = &a; + } + } +} + +pub fn main() { + foo(&1); +} diff --git a/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref-mut-ref.rs b/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref-mut-ref.rs new file mode 100644 index 000000000..57871b098 --- /dev/null +++ b/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref-mut-ref.rs @@ -0,0 +1,9 @@ +// Issue #8624. Test for reborrowing with 3 levels, not just two. + +fn copy_borrowed_ptr<'a, 'b, 'c>(p: &'a mut &'b mut &'c mut isize) -> &'b mut isize { + &mut ***p + //~^ ERROR lifetime may not live long enough +} + +fn main() { +} diff --git a/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref-mut-ref.stderr b/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref-mut-ref.stderr new file mode 100644 index 000000000..dc905d076 --- /dev/null +++ b/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref-mut-ref.stderr @@ -0,0 +1,14 @@ +error: lifetime may not live long enough + --> $DIR/regions-reborrow-from-shorter-mut-ref-mut-ref.rs:4:5 + | +LL | fn copy_borrowed_ptr<'a, 'b, 'c>(p: &'a mut &'b mut &'c mut isize) -> &'b mut isize { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | &mut ***p + | ^^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + | + = help: consider adding the following bound: `'a: 'b` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref.rs b/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref.rs new file mode 100644 index 000000000..88cc54650 --- /dev/null +++ b/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref.rs @@ -0,0 +1,16 @@ +// Issue #8624. Tests that reborrowing the contents of an `&'b mut` +// pointer which is backed by another `&'a mut` can only be done +// for `'a` (which must be a sublifetime of `'b`). + +fn copy_borrowed_ptr<'a, 'b>(p: &'a mut &'b mut isize) -> &'b mut isize { + &mut **p + //~^ ERROR lifetime may not live long enough +} + +fn main() { + let mut x = 1; + let mut y = &mut x; + let z = copy_borrowed_ptr(&mut y); + *y += 1; + *z += 1; +} diff --git a/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref.stderr b/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref.stderr new file mode 100644 index 000000000..c98ec4774 --- /dev/null +++ b/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref.stderr @@ -0,0 +1,14 @@ +error: lifetime may not live long enough + --> $DIR/regions-reborrow-from-shorter-mut-ref.rs:6:5 + | +LL | fn copy_borrowed_ptr<'a, 'b>(p: &'a mut &'b mut isize) -> &'b mut isize { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | &mut **p + | ^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + | + = help: consider adding the following bound: `'a: 'b` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-ref-in-fn-arg.rs b/src/test/ui/regions/regions-ref-in-fn-arg.rs new file mode 100644 index 000000000..3df529c9f --- /dev/null +++ b/src/test/ui/regions/regions-ref-in-fn-arg.rs @@ -0,0 +1,14 @@ +#![feature(box_patterns)] + + +fn arg_item(box ref x: Box<isize>) -> &'static isize { + x //~ ERROR cannot return value referencing function parameter +} + +fn with<R, F>(f: F) -> R where F: FnOnce(Box<isize>) -> R { f(Box::new(3)) } + +fn arg_closure() -> &'static isize { + with(|box ref x| x) //~ ERROR cannot return value referencing function parameter +} + +fn main() {} diff --git a/src/test/ui/regions/regions-ref-in-fn-arg.stderr b/src/test/ui/regions/regions-ref-in-fn-arg.stderr new file mode 100644 index 000000000..ccba6c59b --- /dev/null +++ b/src/test/ui/regions/regions-ref-in-fn-arg.stderr @@ -0,0 +1,19 @@ +error[E0515]: cannot return value referencing function parameter + --> $DIR/regions-ref-in-fn-arg.rs:5:5 + | +LL | fn arg_item(box ref x: Box<isize>) -> &'static isize { + | --------- function parameter borrowed here +LL | x + | ^ returns a value referencing data owned by the current function + +error[E0515]: cannot return value referencing function parameter + --> $DIR/regions-ref-in-fn-arg.rs:11:22 + | +LL | with(|box ref x| x) + | --------- ^ returns a value referencing data owned by the current function + | | + | function parameter borrowed here + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/regions/regions-refcell.rs b/src/test/ui/regions/regions-refcell.rs new file mode 100644 index 000000000..39ad0c53f --- /dev/null +++ b/src/test/ui/regions/regions-refcell.rs @@ -0,0 +1,45 @@ +// run-pass +// This is a regression test for something that only came up while +// attempting to bootstrap librustc with new destructor lifetime +// semantics. + + +use std::collections::HashMap; +use std::cell::RefCell; + +// This version does not yet work (associated type issues)... +#[cfg(cannot_use_this_yet)] +fn foo<'a>(map: RefCell<HashMap<&'static str, &'a [u8]>>) { + let one = [1]; + assert_eq!(map.borrow().get("one"), Some(&one[..])); +} + +#[cfg(cannot_use_this_yet_either)] +// ... and this version does not work (the lifetime of `one` is +// supposed to match the lifetime `'a`) ... +fn foo<'a>(map: RefCell<HashMap<&'static str, &'a [u8]>>) { + let one = [1]; + assert_eq!(map.borrow().get("one"), Some(&&one[..])); +} + +#[cfg(all(not(cannot_use_this_yet),not(cannot_use_this_yet_either)))] +fn foo<'a>(map: RefCell<HashMap<&'static str, &'a [u8]>>) { + // ...so instead we walk through the trivial slice and make sure + // it contains the element we expect. + + for (i, &x) in map.borrow().get("one").unwrap().iter().enumerate() { + assert_eq!((i, x), (0, 1)); + } +} + +fn main() { + let zer = [0]; + let one = [1]; + let two = [2]; + let mut map = HashMap::new(); + map.insert("zero", &zer[..]); + map.insert("one", &one[..]); + map.insert("two", &two[..]); + let map = RefCell::new(map); + foo(map); +} diff --git a/src/test/ui/regions/regions-relate-bound-regions-on-closures-to-inference-variables.rs b/src/test/ui/regions/regions-relate-bound-regions-on-closures-to-inference-variables.rs new file mode 100644 index 000000000..b1bdb813a --- /dev/null +++ b/src/test/ui/regions/regions-relate-bound-regions-on-closures-to-inference-variables.rs @@ -0,0 +1,57 @@ +// run-pass +#![allow(dead_code)] +// Test that this fairly specialized, but also reasonable, pattern +// typechecks. The pattern involves regions bound in closures that +// wind up related to inference variables. +// +// NB. Changes to the region implementations have broken this pattern +// a few times, but it happens to be used in the compiler so those +// changes were caught. However, those uses in the compiler could +// easily get changed or refactored away in the future. + +struct Ctxt<'tcx> { + x: &'tcx Vec<isize> +} + +struct Foo<'a,'tcx:'a> { + cx: &'a Ctxt<'tcx>, +} + +impl<'a,'tcx> Foo<'a,'tcx> { + fn bother(&mut self) -> isize { + self.elaborate_bounds(Box::new(|this| { + // (*) Here: type of `this` is `&'f0 Foo<&'f1, '_2>`, + // where `'f0` and `'f1` are fresh, free regions that + // result from the bound regions on the closure, and `'2` + // is a region inference variable created by the call. Due + // to the constraints on the type, we find that `'_2 : 'f1 + // + 'f2` must hold (and can be assumed by the callee). + // Region inference has to do some clever stuff to avoid + // inferring `'_2` to be `'static` in this case, because + // it is created outside the closure but then related to + // regions bound by the closure itself. See the + // `region_constraints.rs` file (and the `givens` field, in + // particular) for more details. + this.foo() + })) + } + + fn foo(&mut self) -> isize { + 22 + } + + fn elaborate_bounds( + &mut self, + mut mk_cand: Box<dyn for<'b> FnMut(&mut Foo<'b, 'tcx>) -> isize>) + -> isize + { + mk_cand(self) + } +} + +fn main() { + let v = vec![]; + let cx = Ctxt { x: &v }; + let mut foo = Foo { cx: &cx }; + assert_eq!(foo.bother(), 22); // just so the code is not dead, basically +} diff --git a/src/test/ui/regions/regions-ret-borrowed-1.rs b/src/test/ui/regions/regions-ret-borrowed-1.rs new file mode 100644 index 000000000..54630caff --- /dev/null +++ b/src/test/ui/regions/regions-ret-borrowed-1.rs @@ -0,0 +1,17 @@ +// Similar to regions-ret-borrowed.rs, but using a named lifetime. At +// some point regions-ret-borrowed reported an error but this file did +// not, due to special hardcoding around the anonymous region. + +fn with<R, F>(f: F) -> R where F: for<'a> FnOnce(&'a isize) -> R { + f(&3) +} + +fn return_it<'a>() -> &'a isize { + with(|o| o) + //~^ ERROR lifetime may not live long enough +} + +fn main() { + let x = return_it(); + println!("foo={}", *x); +} diff --git a/src/test/ui/regions/regions-ret-borrowed-1.stderr b/src/test/ui/regions/regions-ret-borrowed-1.stderr new file mode 100644 index 000000000..0784e894e --- /dev/null +++ b/src/test/ui/regions/regions-ret-borrowed-1.stderr @@ -0,0 +1,11 @@ +error: lifetime may not live long enough + --> $DIR/regions-ret-borrowed-1.rs:10:14 + | +LL | with(|o| o) + | -- ^ returning this value requires that `'1` must outlive `'2` + | || + | |return type of closure is &'2 isize + | has type `&'1 isize` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-ret-borrowed.rs b/src/test/ui/regions/regions-ret-borrowed.rs new file mode 100644 index 000000000..bdb0341c9 --- /dev/null +++ b/src/test/ui/regions/regions-ret-borrowed.rs @@ -0,0 +1,20 @@ +// Ensure that you cannot use generic types to return a region outside +// of its bound. Here, in the `return_it()` fn, we call with() but +// with R bound to &isize from the return_it. Meanwhile, with() +// provides a value that is only good within its own stack frame. This +// used to successfully compile because we failed to account for the +// fact that fn(x: &isize) rebound the region &. + +fn with<R, F>(f: F) -> R where F: FnOnce(&isize) -> R { + f(&3) +} + +fn return_it<'a>() -> &'a isize { + with(|o| o) + //~^ ERROR lifetime may not live long enough +} + +fn main() { + let x = return_it(); + println!("foo={}", *x); +} diff --git a/src/test/ui/regions/regions-ret-borrowed.stderr b/src/test/ui/regions/regions-ret-borrowed.stderr new file mode 100644 index 000000000..d9be5ef89 --- /dev/null +++ b/src/test/ui/regions/regions-ret-borrowed.stderr @@ -0,0 +1,11 @@ +error: lifetime may not live long enough + --> $DIR/regions-ret-borrowed.rs:13:14 + | +LL | with(|o| o) + | -- ^ returning this value requires that `'1` must outlive `'2` + | || + | |return type of closure is &'2 isize + | has type `&'1 isize` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-ret.rs b/src/test/ui/regions/regions-ret.rs new file mode 100644 index 000000000..580545ef8 --- /dev/null +++ b/src/test/ui/regions/regions-ret.rs @@ -0,0 +1,8 @@ +fn id<T>(x: T) -> T { x } + +fn f(_x: &isize) -> &isize { + return &id(3); //~ ERROR cannot return reference to temporary value +} + +fn main() { +} diff --git a/src/test/ui/regions/regions-ret.stderr b/src/test/ui/regions/regions-ret.stderr new file mode 100644 index 000000000..0e4875ac9 --- /dev/null +++ b/src/test/ui/regions/regions-ret.stderr @@ -0,0 +1,12 @@ +error[E0515]: cannot return reference to temporary value + --> $DIR/regions-ret.rs:4:12 + | +LL | return &id(3); + | ^----- + | || + | |temporary value created here + | returns a reference to data owned by the current function + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/regions/regions-return-interior-of-option.rs b/src/test/ui/regions/regions-return-interior-of-option.rs new file mode 100644 index 000000000..2dc91ec84 --- /dev/null +++ b/src/test/ui/regions/regions-return-interior-of-option.rs @@ -0,0 +1,24 @@ +// run-pass + +fn get<T>(opt: &Option<T>) -> &T { + match *opt { + Some(ref v) => v, + None => panic!("none") + } +} + +pub fn main() { + let mut x = Some(23); + + { + let y = get(&x); + assert_eq!(*y, 23); + } + + x = Some(24); + + { + let y = get(&x); + assert_eq!(*y, 24); + } +} diff --git a/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.rs b/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.rs new file mode 100644 index 000000000..86e759f08 --- /dev/null +++ b/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.rs @@ -0,0 +1,11 @@ +// Test that closures cannot subvert aliasing restrictions + +fn main() { + // Unboxed closure case + { + let mut x = 0; + let mut f = || &mut x; //~ ERROR captured variable cannot escape `FnMut` closure body + let x = f(); + let y = f(); + } +} diff --git a/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.stderr b/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.stderr new file mode 100644 index 000000000..b087e03b4 --- /dev/null +++ b/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.stderr @@ -0,0 +1,17 @@ +error: captured variable cannot escape `FnMut` closure body + --> $DIR/regions-return-ref-to-upvar-issue-17403.rs:7:24 + | +LL | let mut x = 0; + | ----- variable defined here +LL | let mut f = || &mut x; + | - ^^^^^- + | | | | + | | | variable captured here + | | returns a reference to a captured variable which escapes the closure body + | inferred to be a `FnMut` closure + | + = note: `FnMut` closures only have access to their captured variables while they are executing... + = note: ...therefore, they cannot allow references to captured variables to escape + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-return-stack-allocated-vec.rs b/src/test/ui/regions/regions-return-stack-allocated-vec.rs new file mode 100644 index 000000000..97fbdbf46 --- /dev/null +++ b/src/test/ui/regions/regions-return-stack-allocated-vec.rs @@ -0,0 +1,10 @@ +// Test that we cannot return a stack allocated slice + +fn function(x: isize) -> &'static [isize] { + &[x] //~ ERROR cannot return reference to temporary value +} + +fn main() { + let x = function(1); + let y = x[0]; +} diff --git a/src/test/ui/regions/regions-return-stack-allocated-vec.stderr b/src/test/ui/regions/regions-return-stack-allocated-vec.stderr new file mode 100644 index 000000000..9d87fe266 --- /dev/null +++ b/src/test/ui/regions/regions-return-stack-allocated-vec.stderr @@ -0,0 +1,12 @@ +error[E0515]: cannot return reference to temporary value + --> $DIR/regions-return-stack-allocated-vec.rs:4:5 + | +LL | &[x] + | ^--- + | || + | |temporary value created here + | returns a reference to data owned by the current function + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/regions/regions-scope-chain-example.rs b/src/test/ui/regions/regions-scope-chain-example.rs new file mode 100644 index 000000000..2beb20add --- /dev/null +++ b/src/test/ui/regions/regions-scope-chain-example.rs @@ -0,0 +1,43 @@ +// run-pass +#![allow(dead_code)] +#![allow(unused_variables)] +// This is an example where the older inference algorithm failed. The +// specifics of why it failed are somewhat, but not entirely, tailed +// to the algorithm. Ultimately the problem is that when computing the +// mutual supertype of both sides of the `if` it would be faced with a +// choice of tightening bounds or unifying variables and it took the +// wrong path. The new algorithm avoids this problem and hence this +// example typechecks correctly. + +// pretty-expanded FIXME #23616 + +enum ScopeChain<'a> { + Link(Scope<'a>), + End +} + +type Scope<'a> = &'a ScopeChain<'a>; + +struct OuterContext; + +struct Context<'a> { + foo: &'a OuterContext +} + +impl<'a> Context<'a> { + fn foo(&mut self, scope: Scope) { + let link = if 1 < 2 { + let l = ScopeChain::Link(scope); + self.take_scope(&l); + l + } else { + ScopeChain::Link(scope) + }; + self.take_scope(&link); + } + + fn take_scope(&mut self, x: Scope) { + } +} + +fn main() { } diff --git a/src/test/ui/regions/regions-self-impls.rs b/src/test/ui/regions/regions-self-impls.rs new file mode 100644 index 000000000..80b88568e --- /dev/null +++ b/src/test/ui/regions/regions-self-impls.rs @@ -0,0 +1,20 @@ +// run-pass +#![allow(non_camel_case_types)] + +struct Clam<'a> { + chowder: &'a isize +} + +trait get_chowder<'a> { + fn get_chowder(&self) -> &'a isize; +} + +impl<'a> get_chowder<'a> for Clam<'a> { + fn get_chowder(&self) -> &'a isize { return self.chowder; } +} + +pub fn main() { + let clam = Clam { chowder: &3 }; + println!("{}", *clam.get_chowder()); + clam.get_chowder(); +} diff --git a/src/test/ui/regions/regions-self-in-enums.rs b/src/test/ui/regions/regions-self-in-enums.rs new file mode 100644 index 000000000..c2e4b2ff1 --- /dev/null +++ b/src/test/ui/regions/regions-self-in-enums.rs @@ -0,0 +1,17 @@ +// run-pass +#![allow(unused_mut)] +#![allow(non_camel_case_types)] + +enum int_wrapper<'a> { + int_wrapper_ctor(&'a isize) +} + +pub fn main() { + let x = 3; + let y = int_wrapper::int_wrapper_ctor(&x); + let mut z : &isize; + match y { + int_wrapper::int_wrapper_ctor(zz) => { z = zz; } + } + println!("{}", *z); +} diff --git a/src/test/ui/regions/regions-simple.rs b/src/test/ui/regions/regions-simple.rs new file mode 100644 index 000000000..fff1b47f5 --- /dev/null +++ b/src/test/ui/regions/regions-simple.rs @@ -0,0 +1,7 @@ +// run-pass +pub fn main() { + let mut x: isize = 3; + let y: &mut isize = &mut x; + *y = 5; + println!("{}", *y); +} diff --git a/src/test/ui/regions/regions-static-bound-rpass.rs b/src/test/ui/regions/regions-static-bound-rpass.rs new file mode 100644 index 000000000..25232b455 --- /dev/null +++ b/src/test/ui/regions/regions-static-bound-rpass.rs @@ -0,0 +1,26 @@ +// run-pass + +fn invariant_id<'a,'b>(t: &'b mut &'static ()) -> &'b mut &'a () + where 'a: 'static { t } +//~^ WARN unnecessary lifetime parameter `'a` + +fn static_id<'a>(t: &'a ()) -> &'static () + where 'a: 'static { t } +//~^ WARN unnecessary lifetime parameter `'a` + +fn static_id_indirect<'a,'b>(t: &'a ()) -> &'static () + where 'a: 'b, 'b: 'static { t } +//~^ WARN unnecessary lifetime parameter `'b` + +fn ref_id<'a>(t: &'a ()) -> &'a () where 'static: 'a { t } + +static UNIT: () = (); + +fn main() +{ + let mut val : &'static () = &UNIT; + invariant_id(&mut val); + static_id(val); + static_id_indirect(val); + ref_id(val); +} diff --git a/src/test/ui/regions/regions-static-bound-rpass.stderr b/src/test/ui/regions/regions-static-bound-rpass.stderr new file mode 100644 index 000000000..9355a409d --- /dev/null +++ b/src/test/ui/regions/regions-static-bound-rpass.stderr @@ -0,0 +1,26 @@ +warning: unnecessary lifetime parameter `'a` + --> $DIR/regions-static-bound-rpass.rs:4:11 + | +LL | where 'a: 'static { t } + | ^^ + | + = help: you can use the `'static` lifetime directly, in place of `'a` + +warning: unnecessary lifetime parameter `'a` + --> $DIR/regions-static-bound-rpass.rs:8:11 + | +LL | where 'a: 'static { t } + | ^^ + | + = help: you can use the `'static` lifetime directly, in place of `'a` + +warning: unnecessary lifetime parameter `'b` + --> $DIR/regions-static-bound-rpass.rs:12:19 + | +LL | where 'a: 'b, 'b: 'static { t } + | ^^ + | + = help: you can use the `'static` lifetime directly, in place of `'b` + +warning: 3 warnings emitted + diff --git a/src/test/ui/regions/regions-static-bound.rs b/src/test/ui/regions/regions-static-bound.rs new file mode 100644 index 000000000..4d2455470 --- /dev/null +++ b/src/test/ui/regions/regions-static-bound.rs @@ -0,0 +1,21 @@ +fn static_id<'a,'b>(t: &'a ()) -> &'static () + where 'a: 'static { t } +//~^ WARN unnecessary lifetime parameter `'a` + +fn static_id_indirect<'a,'b>(t: &'a ()) -> &'static () + where 'a: 'b, 'b: 'static { t } +//~^ WARN unnecessary lifetime parameter `'b` + +fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a { + t + //~^ ERROR lifetime may not live long enough +} + +fn error(u: &(), v: &()) { + static_id(&u); + //~^ ERROR borrowed data escapes outside of function [E0521] + static_id_indirect(&v); + //~^ ERROR borrowed data escapes outside of function [E0521] +} + +fn main() {} diff --git a/src/test/ui/regions/regions-static-bound.stderr b/src/test/ui/regions/regions-static-bound.stderr new file mode 100644 index 000000000..2886ec3ea --- /dev/null +++ b/src/test/ui/regions/regions-static-bound.stderr @@ -0,0 +1,54 @@ +warning: unnecessary lifetime parameter `'a` + --> $DIR/regions-static-bound.rs:2:11 + | +LL | where 'a: 'static { t } + | ^^ + | + = help: you can use the `'static` lifetime directly, in place of `'a` + +warning: unnecessary lifetime parameter `'b` + --> $DIR/regions-static-bound.rs:6:19 + | +LL | where 'a: 'b, 'b: 'static { t } + | ^^ + | + = help: you can use the `'static` lifetime directly, in place of `'b` + +error: lifetime may not live long enough + --> $DIR/regions-static-bound.rs:10:5 + | +LL | fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a { + | -- lifetime `'a` defined here +LL | t + | ^ returning this value requires that `'a` must outlive `'static` + +error[E0521]: borrowed data escapes outside of function + --> $DIR/regions-static-bound.rs:15:5 + | +LL | fn error(u: &(), v: &()) { + | - - let's call the lifetime of this reference `'1` + | | + | `u` is a reference that is only valid in the function body +LL | static_id(&u); + | ^^^^^^^^^^^^^ + | | + | `u` escapes the function body here + | argument requires that `'1` must outlive `'static` + +error[E0521]: borrowed data escapes outside of function + --> $DIR/regions-static-bound.rs:17:5 + | +LL | fn error(u: &(), v: &()) { + | - - let's call the lifetime of this reference `'2` + | | + | `v` is a reference that is only valid in the function body +... +LL | static_id_indirect(&v); + | ^^^^^^^^^^^^^^^^^^^^^^ + | | + | `v` escapes the function body here + | argument requires that `'2` must outlive `'static` + +error: aborting due to 3 previous errors; 2 warnings emitted + +For more information about this error, try `rustc --explain E0521`. diff --git a/src/test/ui/regions/regions-static-closure.rs b/src/test/ui/regions/regions-static-closure.rs new file mode 100644 index 000000000..09cd56220 --- /dev/null +++ b/src/test/ui/regions/regions-static-closure.rs @@ -0,0 +1,19 @@ +// run-pass +#![allow(non_camel_case_types)] + +struct closure_box<'a> { + cl: Box<dyn FnMut() + 'a>, +} + +fn box_it<'a>(x: Box<dyn FnMut() + 'a>) -> closure_box<'a> { + closure_box {cl: x} +} + +fn call_static_closure(mut cl: closure_box<'static>) { + (cl.cl)(); +} + +pub fn main() { + let cl_box = box_it(Box::new(|| println!("Hello, world!"))); + call_static_closure(cl_box); +} diff --git a/src/test/ui/regions/regions-steal-closure.rs b/src/test/ui/regions/regions-steal-closure.rs new file mode 100644 index 000000000..83e93522c --- /dev/null +++ b/src/test/ui/regions/regions-steal-closure.rs @@ -0,0 +1,17 @@ +#![feature(fn_traits)] + +struct ClosureBox<'a> { + cl: Box<dyn FnMut() + 'a>, +} + +fn box_it<'r>(x: Box<dyn FnMut() + 'r>) -> ClosureBox<'r> { + ClosureBox {cl: x} +} + +fn main() { + let mut cl_box = { + let mut i = 3; + box_it(Box::new(|| i += 1)) //~ ERROR `i` does not live long enough + }; + cl_box.cl.call_mut(()); +} diff --git a/src/test/ui/regions/regions-steal-closure.stderr b/src/test/ui/regions/regions-steal-closure.stderr new file mode 100644 index 000000000..5b0efaf95 --- /dev/null +++ b/src/test/ui/regions/regions-steal-closure.stderr @@ -0,0 +1,16 @@ +error[E0597]: `i` does not live long enough + --> $DIR/regions-steal-closure.rs:14:28 + | +LL | let mut cl_box = { + | ---------- borrow later stored here +LL | let mut i = 3; +LL | box_it(Box::new(|| i += 1)) + | -- ^ borrowed value does not live long enough + | | + | value captured here +LL | }; + | - `i` dropped here while still borrowed + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/regions/regions-trait-1.rs b/src/test/ui/regions/regions-trait-1.rs new file mode 100644 index 000000000..b6dab1c32 --- /dev/null +++ b/src/test/ui/regions/regions-trait-1.rs @@ -0,0 +1,33 @@ +// check-pass + +struct Ctxt { + v: usize, +} + +trait GetCtxt { + // Here the `&` is bound in the method definition: + fn get_ctxt(&self) -> &Ctxt; +} + +struct HasCtxt<'a> { + c: &'a Ctxt, +} + +impl<'a> GetCtxt for HasCtxt<'a> { + // Ok: Have implied bound of WF(&'b HasCtxt<'a>) + // so know 'a: 'b + // so know &'a Ctxt <: &'b Ctxt + fn get_ctxt<'b>(&'b self) -> &'a Ctxt { + self.c + } +} + +fn get_v(gc: Box<dyn GetCtxt + '_>) -> usize { + gc.get_ctxt().v +} + +fn main() { + let ctxt = Ctxt { v: 22 }; + let hc = HasCtxt { c: &ctxt }; + assert_eq!(get_v(Box::new(hc) as Box<dyn GetCtxt>), 22); +} diff --git a/src/test/ui/regions/regions-trait-object-1.rs b/src/test/ui/regions/regions-trait-object-1.rs new file mode 100644 index 000000000..e2520d978 --- /dev/null +++ b/src/test/ui/regions/regions-trait-object-1.rs @@ -0,0 +1,35 @@ +// run-pass +// This is a regression test for something that only came up while +// attempting to bootstrap librustc_ast; it is adapted from +// `rustc_ast::ext::tt::generic_extension`. + + +pub struct E<'a> { + pub f: &'a u8, +} +impl<'b> E<'b> { + pub fn m(&self) -> &'b u8 { self.f } +} + +pub struct P<'c> { + pub g: &'c u8, +} +pub trait M { + fn n(&self) -> u8; +} +impl<'d> M for P<'d> { + fn n(&self) -> u8 { *self.g } +} + +fn extension<'e>(x: &'e E<'e>) -> Box<dyn M+'e> { + loop { + let p = P { g: x.m() }; + return Box::new(p) as Box<dyn M+'e>; + } +} + +fn main() { + let w = E { f: &10 }; + let o = extension(&w); + assert_eq!(o.n(), 10); +} diff --git a/src/test/ui/regions/regions-trait-object-subtyping.rs b/src/test/ui/regions/regions-trait-object-subtyping.rs new file mode 100644 index 000000000..1d7a766de --- /dev/null +++ b/src/test/ui/regions/regions-trait-object-subtyping.rs @@ -0,0 +1,26 @@ +trait Dummy { fn dummy(&self); } + +fn foo1<'a:'b,'b>(x: &'a mut (dyn Dummy+'a)) -> &'b mut (dyn Dummy+'b) { + // Here, we are able to coerce + x +} + +fn foo2<'a:'b,'b>(x: &'b mut (dyn Dummy+'a)) -> &'b mut (dyn Dummy+'b) { + // Here, we are able to coerce + x +} + +fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy { + // Without knowing 'a:'b, we can't coerce + x + //~^ ERROR lifetime may not live long enough +} + +struct Wrapper<T>(T); +fn foo4<'a:'b,'b>(x: Wrapper<&'a mut dyn Dummy>) -> Wrapper<&'b mut dyn Dummy> { + // We can't coerce because it is packed in `Wrapper` + x + //~^ ERROR lifetime may not live long enough +} + +fn main() {} diff --git a/src/test/ui/regions/regions-trait-object-subtyping.stderr b/src/test/ui/regions/regions-trait-object-subtyping.stderr new file mode 100644 index 000000000..1b3a116d5 --- /dev/null +++ b/src/test/ui/regions/regions-trait-object-subtyping.stderr @@ -0,0 +1,34 @@ +error: lifetime may not live long enough + --> $DIR/regions-trait-object-subtyping.rs:15:5 + | +LL | fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | // Without knowing 'a:'b, we can't coerce +LL | x + | ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + | + = help: consider adding the following bound: `'a: 'b` + = note: requirement occurs because of a mutable reference to `dyn Dummy` + = note: mutable references are invariant over their type parameter + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +error: lifetime may not live long enough + --> $DIR/regions-trait-object-subtyping.rs:22:5 + | +LL | fn foo4<'a:'b,'b>(x: Wrapper<&'a mut dyn Dummy>) -> Wrapper<&'b mut dyn Dummy> { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | // We can't coerce because it is packed in `Wrapper` +LL | x + | ^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` + | + = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of a mutable reference to `dyn Dummy` + = note: mutable references are invariant over their type parameter + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/regions/regions-trait-variance.rs b/src/test/ui/regions/regions-trait-variance.rs new file mode 100644 index 000000000..94ffb85c9 --- /dev/null +++ b/src/test/ui/regions/regions-trait-variance.rs @@ -0,0 +1,44 @@ +// Issue #12470. + +trait X { + fn get_i(&self) -> isize; +} + +struct B { + i: isize +} + +impl X for B { + fn get_i(&self) -> isize { + self.i + } +} + +impl Drop for B { + fn drop(&mut self) { + println!("drop"); + } +} + +struct A<'r> { + p: &'r (dyn X + 'r) +} + +fn make_a(p: &dyn X) -> A { + A{p:p} +} + +fn make_make_a<'a>() -> A<'a> { + + let b: Box<B> = Box::new(B { + i: 1, + }); + + let bb: &B = &*b; + make_a(bb) //~ ERROR cannot return value referencing local data `*b` +} + +fn main() { + let a = make_make_a(); + println!("{}", a.p.get_i()); +} diff --git a/src/test/ui/regions/regions-trait-variance.stderr b/src/test/ui/regions/regions-trait-variance.stderr new file mode 100644 index 000000000..56c9f89e1 --- /dev/null +++ b/src/test/ui/regions/regions-trait-variance.stderr @@ -0,0 +1,11 @@ +error[E0515]: cannot return value referencing local data `*b` + --> $DIR/regions-trait-variance.rs:38:5 + | +LL | let bb: &B = &*b; + | --- `*b` is borrowed here +LL | make_a(bb) + | ^^^^^^^^^^ returns a value referencing data owned by the current function + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/regions/regions-undeclared.rs b/src/test/ui/regions/regions-undeclared.rs new file mode 100644 index 000000000..1edd998aa --- /dev/null +++ b/src/test/ui/regions/regions-undeclared.rs @@ -0,0 +1,13 @@ +static c_x: &'blk isize = &22; //~ ERROR use of undeclared lifetime name `'blk` + +enum EnumDecl { + Foo(&'a isize), //~ ERROR use of undeclared lifetime name `'a` + Bar(&'a isize), //~ ERROR use of undeclared lifetime name `'a` +} + +fn fnDecl(x: &'a isize, //~ ERROR use of undeclared lifetime name `'a` + y: &'a isize) //~ ERROR use of undeclared lifetime name `'a` +{} + +fn main() { +} diff --git a/src/test/ui/regions/regions-undeclared.stderr b/src/test/ui/regions/regions-undeclared.stderr new file mode 100644 index 000000000..6bfde5524 --- /dev/null +++ b/src/test/ui/regions/regions-undeclared.stderr @@ -0,0 +1,42 @@ +error[E0261]: use of undeclared lifetime name `'blk` + --> $DIR/regions-undeclared.rs:1:14 + | +LL | static c_x: &'blk isize = &22; + | ^^^^ undeclared lifetime + +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/regions-undeclared.rs:4:10 + | +LL | enum EnumDecl { + | - help: consider introducing lifetime `'a` here: `<'a>` +LL | Foo(&'a isize), + | ^^ undeclared lifetime + +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/regions-undeclared.rs:5:10 + | +LL | enum EnumDecl { + | - help: consider introducing lifetime `'a` here: `<'a>` +LL | Foo(&'a isize), +LL | Bar(&'a isize), + | ^^ undeclared lifetime + +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/regions-undeclared.rs:8:15 + | +LL | fn fnDecl(x: &'a isize, + | - ^^ undeclared lifetime + | | + | help: consider introducing lifetime `'a` here: `<'a>` + +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/regions-undeclared.rs:9:15 + | +LL | fn fnDecl(x: &'a isize, + | - help: consider introducing lifetime `'a` here: `<'a>` +LL | y: &'a isize) + | ^^ undeclared lifetime + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0261`. diff --git a/src/test/ui/regions/regions-var-type-out-of-scope.rs b/src/test/ui/regions/regions-var-type-out-of-scope.rs new file mode 100644 index 000000000..aba55e9df --- /dev/null +++ b/src/test/ui/regions/regions-var-type-out-of-scope.rs @@ -0,0 +1,14 @@ +fn id<T>(x: T) -> T { x } + +fn foo(cond: bool) { + // Here we will infer a type that uses the + // region of the if stmt then block: + let mut x; + + if cond { + x = &id(3); //~ ERROR temporary value dropped while borrowed + assert_eq!(*x, 3); + } +} + +fn main() {} diff --git a/src/test/ui/regions/regions-var-type-out-of-scope.stderr b/src/test/ui/regions/regions-var-type-out-of-scope.stderr new file mode 100644 index 000000000..476e82f04 --- /dev/null +++ b/src/test/ui/regions/regions-var-type-out-of-scope.stderr @@ -0,0 +1,15 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/regions-var-type-out-of-scope.rs:9:14 + | +LL | x = &id(3); + | ^^^^^- temporary value is freed at the end of this statement + | | + | creates a temporary which is freed while still in use +LL | assert_eq!(*x, 3); + | ----------------- borrow later used here + | + = note: consider using a `let` binding to create a longer lived value + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/regions/regions-variance-contravariant-use-contravariant.rs b/src/test/ui/regions/regions-variance-contravariant-use-contravariant.rs new file mode 100644 index 000000000..e63778670 --- /dev/null +++ b/src/test/ui/regions/regions-variance-contravariant-use-contravariant.rs @@ -0,0 +1,27 @@ +// run-pass +#![allow(dead_code)] +#![allow(unused_variables)] +// Test that a type which is contravariant with respect to its region +// parameter compiles successfully when used in a contravariant way. +// +// Note: see ui/variance/variance-regions-*.rs for the tests that check that the +// variance inference works in the first place. + +// pretty-expanded FIXME #23616 + +struct Contravariant<'a> { + f: &'a isize +} + +fn use_<'a>(c: Contravariant<'a>) { + let x = 3; + + // 'b winds up being inferred to this call. + // Contravariant<'a> <: Contravariant<'call> is true + // if 'call <= 'a, which is true, so no error. + collapse(&x, c); + + fn collapse<'b>(x: &'b isize, c: Contravariant<'b>) { } +} + +pub fn main() {} diff --git a/src/test/ui/regions/regions-variance-contravariant-use-covariant-in-second-position.rs b/src/test/ui/regions/regions-variance-contravariant-use-covariant-in-second-position.rs new file mode 100644 index 000000000..f23ca537f --- /dev/null +++ b/src/test/ui/regions/regions-variance-contravariant-use-covariant-in-second-position.rs @@ -0,0 +1,29 @@ +// Test that a type which is covariant with respect to its region +// parameter yields an error when used in a contravariant way. +// +// Note: see variance-regions-*.rs for the tests that check that the +// variance inference works in the first place. + +// `S` is contravariant with respect to both parameters. +struct S<'a, 'b> { + f: &'a isize, + g: &'b isize, +} + +fn use_<'short,'long>(c: S<'long, 'short>, + s: &'short isize, + l: &'long isize, + _where:Option<&'short &'long ()>) { + + let _: S<'long, 'short> = c; // OK + let _: S<'short, 'short> = c; // OK + + // Test whether S<_,'short> <: S<_,'long>. Since + // 'short <= 'long, this would be true if the Contravariant type were + // covariant with respect to its parameter 'a. + + let _: S<'long, 'long> = c; + //~^ ERROR lifetime may not live long enough +} + +fn main() {} diff --git a/src/test/ui/regions/regions-variance-contravariant-use-covariant-in-second-position.stderr b/src/test/ui/regions/regions-variance-contravariant-use-covariant-in-second-position.stderr new file mode 100644 index 000000000..5352be430 --- /dev/null +++ b/src/test/ui/regions/regions-variance-contravariant-use-covariant-in-second-position.stderr @@ -0,0 +1,15 @@ +error: lifetime may not live long enough + --> $DIR/regions-variance-contravariant-use-covariant-in-second-position.rs:25:12 + | +LL | fn use_<'short,'long>(c: S<'long, 'short>, + | ------ ----- lifetime `'long` defined here + | | + | lifetime `'short` defined here +... +LL | let _: S<'long, 'long> = c; + | ^^^^^^^^^^^^^^^ type annotation requires that `'short` must outlive `'long` + | + = help: consider adding the following bound: `'short: 'long` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-variance-contravariant-use-covariant.rs b/src/test/ui/regions/regions-variance-contravariant-use-covariant.rs new file mode 100644 index 000000000..c73577cb3 --- /dev/null +++ b/src/test/ui/regions/regions-variance-contravariant-use-covariant.rs @@ -0,0 +1,27 @@ +// Test that a type which is covariant with respect to its region +// parameter yields an error when used in a contravariant way. +// +// Note: see variance-regions-*.rs for the tests that check that the +// variance inference works in the first place. + +// This is contravariant with respect to 'a, meaning that +// Contravariant<'long> <: Contravariant<'short> iff +// 'short <= 'long +struct Contravariant<'a> { + f: &'a isize +} + +fn use_<'short,'long>(c: Contravariant<'short>, + s: &'short isize, + l: &'long isize, + _where:Option<&'short &'long ()>) { + + // Test whether Contravariant<'short> <: Contravariant<'long>. Since + // 'short <= 'long, this would be true if the Contravariant type were + // covariant with respect to its parameter 'a. + + let _: Contravariant<'long> = c; + //~^ ERROR lifetime may not live long enough +} + +fn main() {} diff --git a/src/test/ui/regions/regions-variance-contravariant-use-covariant.stderr b/src/test/ui/regions/regions-variance-contravariant-use-covariant.stderr new file mode 100644 index 000000000..22c9b915b --- /dev/null +++ b/src/test/ui/regions/regions-variance-contravariant-use-covariant.stderr @@ -0,0 +1,15 @@ +error: lifetime may not live long enough + --> $DIR/regions-variance-contravariant-use-covariant.rs:23:12 + | +LL | fn use_<'short,'long>(c: Contravariant<'short>, + | ------ ----- lifetime `'long` defined here + | | + | lifetime `'short` defined here +... +LL | let _: Contravariant<'long> = c; + | ^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'short` must outlive `'long` + | + = help: consider adding the following bound: `'short: 'long` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-variance-covariant-use-contravariant.rs b/src/test/ui/regions/regions-variance-covariant-use-contravariant.rs new file mode 100644 index 000000000..a2183b491 --- /dev/null +++ b/src/test/ui/regions/regions-variance-covariant-use-contravariant.rs @@ -0,0 +1,27 @@ +// Test that a type which is covariant with respect to its region +// parameter yields an error when used in a contravariant way. +// +// Note: see variance-regions-*.rs for the tests that check that the +// variance inference works in the first place. + +// This is covariant with respect to 'a, meaning that +// Covariant<'foo> <: Covariant<'static> because +// 'foo <= 'static +struct Covariant<'a> { + f: extern "Rust" fn(&'a isize) +} + +fn use_<'short,'long>(c: Covariant<'long>, + s: &'short isize, + l: &'long isize, + _where:Option<&'short &'long ()>) { + + // Test whether Covariant<'long> <: Covariant<'short>. Since + // 'short <= 'long, this would be true if the Covariant type were + // contravariant with respect to its parameter 'a. + + let _: Covariant<'short> = c; + //~^ ERROR lifetime may not live long enough +} + +fn main() {} diff --git a/src/test/ui/regions/regions-variance-covariant-use-contravariant.stderr b/src/test/ui/regions/regions-variance-covariant-use-contravariant.stderr new file mode 100644 index 000000000..a07181ad5 --- /dev/null +++ b/src/test/ui/regions/regions-variance-covariant-use-contravariant.stderr @@ -0,0 +1,15 @@ +error: lifetime may not live long enough + --> $DIR/regions-variance-covariant-use-contravariant.rs:23:12 + | +LL | fn use_<'short,'long>(c: Covariant<'long>, + | ------ ----- lifetime `'long` defined here + | | + | lifetime `'short` defined here +... +LL | let _: Covariant<'short> = c; + | ^^^^^^^^^^^^^^^^^ type annotation requires that `'short` must outlive `'long` + | + = help: consider adding the following bound: `'short: 'long` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-variance-covariant-use-covariant.rs b/src/test/ui/regions/regions-variance-covariant-use-covariant.rs new file mode 100644 index 000000000..c5c80ce54 --- /dev/null +++ b/src/test/ui/regions/regions-variance-covariant-use-covariant.rs @@ -0,0 +1,23 @@ +// run-pass +#![allow(dead_code)] +// Test that a type which is covariant with respect to its region +// parameter is successful when used in a covariant way. +// +// Note: see ui/variance/variance-regions-*.rs for the tests that +// check that the variance inference works in the first place. + +// This is covariant with respect to 'a, meaning that +// Covariant<'foo> <: Covariant<'static> because +// 'foo <= 'static +// pretty-expanded FIXME #23616 + +struct Covariant<'a> { + f: extern "Rust" fn(&'a isize) +} + +fn use_<'a>(c: Covariant<'a>) { + // OK Because Covariant<'a> <: Covariant<'static> iff 'a <= 'static + let _: Covariant<'static> = c; +} + +pub fn main() {} diff --git a/src/test/ui/regions/regions-variance-invariant-use-contravariant.rs b/src/test/ui/regions/regions-variance-invariant-use-contravariant.rs new file mode 100644 index 000000000..a81aaa9c7 --- /dev/null +++ b/src/test/ui/regions/regions-variance-invariant-use-contravariant.rs @@ -0,0 +1,24 @@ +// Test that an invariant region parameter used in a contravariant way +// yields an error. +// +// Note: see variance-regions-*.rs for the tests that check that the +// variance inference works in the first place. + +struct Invariant<'a> { + f: &'a mut &'a isize +} + +fn use_<'short,'long>(c: Invariant<'long>, + s: &'short isize, + l: &'long isize, + _where:Option<&'short &'long ()>) { + + // Test whether Invariant<'long> <: Invariant<'short>. Since + // 'short <= 'long, this would be true if the Invariant type were + // contravariant with respect to its parameter 'a. + + let _: Invariant<'short> = c; + //~^ ERROR lifetime may not live long enough +} + +fn main() { } diff --git a/src/test/ui/regions/regions-variance-invariant-use-contravariant.stderr b/src/test/ui/regions/regions-variance-invariant-use-contravariant.stderr new file mode 100644 index 000000000..b35a2cb90 --- /dev/null +++ b/src/test/ui/regions/regions-variance-invariant-use-contravariant.stderr @@ -0,0 +1,18 @@ +error: lifetime may not live long enough + --> $DIR/regions-variance-invariant-use-contravariant.rs:20:12 + | +LL | fn use_<'short,'long>(c: Invariant<'long>, + | ------ ----- lifetime `'long` defined here + | | + | lifetime `'short` defined here +... +LL | let _: Invariant<'short> = c; + | ^^^^^^^^^^^^^^^^^ type annotation requires that `'short` must outlive `'long` + | + = help: consider adding the following bound: `'short: 'long` + = note: requirement occurs because of the type `Invariant<'_>`, which makes the generic argument `'_` invariant + = note: the struct `Invariant<'a>` is invariant over the parameter `'a` + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-variance-invariant-use-covariant.rs b/src/test/ui/regions/regions-variance-invariant-use-covariant.rs new file mode 100644 index 000000000..ab6a82ee7 --- /dev/null +++ b/src/test/ui/regions/regions-variance-invariant-use-covariant.rs @@ -0,0 +1,21 @@ +// Test that a type which is invariant with respect to its region +// parameter used in a covariant way yields an error. +// +// Note: see variance-regions-*.rs for the tests that check that the +// variance inference works in the first place. + +struct Invariant<'a> { + f: &'a mut &'a isize +} + +fn use_<'b>(c: Invariant<'b>) { + + // For this assignment to be legal, Invariant<'b> <: Invariant<'static>. + // Since 'b <= 'static, this would be true if Invariant were covariant + // with respect to its parameter 'a. + + let _: Invariant<'static> = c; + //~^ ERROR lifetime may not live long enough +} + +fn main() { } diff --git a/src/test/ui/regions/regions-variance-invariant-use-covariant.stderr b/src/test/ui/regions/regions-variance-invariant-use-covariant.stderr new file mode 100644 index 000000000..761e78d17 --- /dev/null +++ b/src/test/ui/regions/regions-variance-invariant-use-covariant.stderr @@ -0,0 +1,15 @@ +error: lifetime may not live long enough + --> $DIR/regions-variance-invariant-use-covariant.rs:17:12 + | +LL | fn use_<'b>(c: Invariant<'b>) { + | -- lifetime `'b` defined here +... +LL | let _: Invariant<'static> = c; + | ^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'static` + | + = note: requirement occurs because of the type `Invariant<'_>`, which makes the generic argument `'_` invariant + = note: the struct `Invariant<'a>` is invariant over the parameter `'a` + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-wf-trait-object.rs b/src/test/ui/regions/regions-wf-trait-object.rs new file mode 100644 index 000000000..d0053b202 --- /dev/null +++ b/src/test/ui/regions/regions-wf-trait-object.rs @@ -0,0 +1,10 @@ +// Check that the explicit lifetime bound (`'b`, in this example) must +// outlive all the superbound from the trait (`'a`, in this example). + +trait TheTrait<'t>: 't { } + +struct Foo<'a,'b> { + x: Box<dyn TheTrait<'a>+'b> //~ ERROR E0478 +} + +fn main() { } diff --git a/src/test/ui/regions/regions-wf-trait-object.stderr b/src/test/ui/regions/regions-wf-trait-object.stderr new file mode 100644 index 000000000..f6006ca04 --- /dev/null +++ b/src/test/ui/regions/regions-wf-trait-object.stderr @@ -0,0 +1,20 @@ +error[E0478]: lifetime bound not satisfied + --> $DIR/regions-wf-trait-object.rs:7:8 + | +LL | x: Box<dyn TheTrait<'a>+'b> + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: lifetime parameter instantiated with the lifetime `'b` as defined here + --> $DIR/regions-wf-trait-object.rs:6:15 + | +LL | struct Foo<'a,'b> { + | ^^ +note: but lifetime parameter must outlive the lifetime `'a` as defined here + --> $DIR/regions-wf-trait-object.rs:6:12 + | +LL | struct Foo<'a,'b> { + | ^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0478`. diff --git a/src/test/ui/regions/type-param-outlives-reempty-issue-74429-2.rs b/src/test/ui/regions/type-param-outlives-reempty-issue-74429-2.rs new file mode 100644 index 000000000..a65c17e0e --- /dev/null +++ b/src/test/ui/regions/type-param-outlives-reempty-issue-74429-2.rs @@ -0,0 +1,66 @@ +// Regression test for #74429, where we didn't think that a type parameter +// outlived `ReEmpty`. + +// check-pass + +use std::marker::PhantomData; +use std::ptr::NonNull; + +pub unsafe trait RawData { + type Elem; +} + +unsafe impl<A> RawData for OwnedRepr<A> { + type Elem = A; +} + +unsafe impl<'a, A> RawData for ViewRepr<&'a A> { + type Elem = A; +} + +pub struct OwnedRepr<A> { + ptr: PhantomData<A>, +} + +// these Copy impls are not necessary for the repro, but allow the code to compile without error +// on 1.44.1 +#[derive(Copy, Clone)] +pub struct ViewRepr<A> { + life: PhantomData<A>, +} + +#[derive(Copy, Clone)] +pub struct ArrayBase<S> +where + S: RawData, +{ + ptr: NonNull<S::Elem>, +} + +pub type Array<A> = ArrayBase<OwnedRepr<A>>; + +pub type ArrayView<'a, A> = ArrayBase<ViewRepr<&'a A>>; + +impl<A, S> ArrayBase<S> +where + S: RawData<Elem = A>, +{ + pub fn index_axis(&self) -> ArrayView<'_, A> { + unimplemented!() + } + + pub fn axis_iter<'a>(&'a self) -> std::iter::Empty<&'a A> { + unimplemented!() + } +} + +pub fn x<T: Copy>(a: Array<T>) { + // drop just avoids a must_use warning + drop((0..1).filter(|_| true)); + let y = a.index_axis(); + a.axis_iter().for_each(|_| { + drop(y); + }); +} + +fn main() {} diff --git a/src/test/ui/regions/type-param-outlives-reempty-issue-74429.rs b/src/test/ui/regions/type-param-outlives-reempty-issue-74429.rs new file mode 100644 index 000000000..d463f311c --- /dev/null +++ b/src/test/ui/regions/type-param-outlives-reempty-issue-74429.rs @@ -0,0 +1,35 @@ +// Regression test for #74429, where we didn't think that a type parameter +// outlived `ReEmpty`. + +// check-pass + +use std::marker::PhantomData; + +fn apply<T, F: FnOnce(T)>(_: T, _: F) {} + +#[derive(Clone, Copy)] +struct Invariant<T> { + t: T, + p: PhantomData<fn(T) -> T>, +} + +fn verify_reempty<T>(x: T) { + // r is inferred to have type `Invariant<&ReEmpty(U0) T>` + let r = Invariant { t: &x, p: PhantomData }; + // Creates a new universe, all variables from now on are in `U1`, say. + let _: fn(&()) = |_| {}; + // Closure parameter is of type `&ReEmpty(U1) T`, so the closure has an implied + // bound of `T: ReEmpty(U1)` + apply(&x, |_| { + // Requires `typeof(r)` is well-formed, i.e. `T: ReEmpty(U0)`. If we + // only have the implied bound from the closure parameter to use this + // requires `ReEmpty(U1): ReEmpty(U0)`, which isn't true so we reported + // an error. + // + // This doesn't happen any more because we ensure that `T: ReEmpty(U0)` + // is an implicit bound for all type parameters. + drop(r); + }); +} + +fn main() {} diff --git a/src/test/ui/regions/wf-bound-region-in-object-type.rs b/src/test/ui/regions/wf-bound-region-in-object-type.rs new file mode 100644 index 000000000..7c4dd3ec8 --- /dev/null +++ b/src/test/ui/regions/wf-bound-region-in-object-type.rs @@ -0,0 +1,22 @@ +// run-pass + +#![allow(dead_code)] +#![allow(unused_variables)] +// Test that the `wf` checker properly handles bound regions in object +// types. Compiling this code used to trigger an ICE. + +// pretty-expanded FIXME #23616 + +pub struct Context<'tcx> { + vec: &'tcx Vec<isize> +} + +pub type Cmd<'a> = &'a isize; + +pub type DecodeInlinedItem<'a> = + Box<dyn for<'tcx> FnMut(Cmd, &Context<'tcx>) -> Result<&'tcx isize, ()> + 'a>; + +fn foo(d: DecodeInlinedItem) { +} + +fn main() { } |