diff options
| author | Michael Goulet <michael@errs.io> | 2024-10-03 00:44:14 -0400 |
|---|---|---|
| committer | Michael Goulet <michael@errs.io> | 2024-10-31 01:35:14 +0000 |
| commit | c1457798db03ffb7f207eaf208d8d4d77ba01563 (patch) | |
| tree | f971a769db7432ffdc4a0628c5481518e97f18eb /tests/ui/impl-trait/precise-capturing | |
| parent | e093b82a41906c8c228643314e2f799568b37ee9 (diff) | |
| download | rust-c1457798db03ffb7f207eaf208d8d4d77ba01563.tar.gz rust-c1457798db03ffb7f207eaf208d8d4d77ba01563.zip | |
Try to point out when edition 2024 lifetime capture rules cause borrowck issues
Diffstat (limited to 'tests/ui/impl-trait/precise-capturing')
5 files changed, 521 insertions, 0 deletions
diff --git a/tests/ui/impl-trait/precise-capturing/auxiliary/foreign.rs b/tests/ui/impl-trait/precise-capturing/auxiliary/foreign.rs new file mode 100644 index 00000000000..49015bc48ba --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/auxiliary/foreign.rs @@ -0,0 +1,6 @@ +//@ edition: 2024 +//@ compile-flags: -Zunstable-options + +use std::fmt::Display; + +pub fn hello(x: &Vec<i32>) -> impl Display { 0 } diff --git a/tests/ui/impl-trait/precise-capturing/foreign-2021.rs b/tests/ui/impl-trait/precise-capturing/foreign-2021.rs new file mode 100644 index 00000000000..aee412ff7f1 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/foreign-2021.rs @@ -0,0 +1,15 @@ +//@ aux-build: foreign.rs + +extern crate foreign; + +fn main() { + let mut x = vec![]; + let h = foreign::hello(&x); + //~^ NOTE this call may capture more lifetimes than intended + //~| NOTE immutable borrow occurs here + x.push(0); + //~^ ERROR cannot borrow `x` as mutable + //~| NOTE mutable borrow occurs here + println!("{h}"); + //~^ NOTE immutable borrow later used here +} diff --git a/tests/ui/impl-trait/precise-capturing/foreign-2021.stderr b/tests/ui/impl-trait/precise-capturing/foreign-2021.stderr new file mode 100644 index 00000000000..2a17ef72912 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/foreign-2021.stderr @@ -0,0 +1,26 @@ +error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable + --> $DIR/foreign-2021.rs:10:5 + | +LL | let h = foreign::hello(&x); + | -- immutable borrow occurs here +... +LL | x.push(0); + | ^^^^^^^^^ mutable borrow occurs here +... +LL | println!("{h}"); + | --- immutable borrow later used here + | +note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules + --> $DIR/foreign-2021.rs:7:13 + | +LL | let h = foreign::hello(&x); + | ^^^^^^^^^^^^^^^^^^ +help: if you can modify this crate, add a precise capturing bound to avoid overcapturing: `+ use<>` + --> $DIR/auxiliary/foreign.rs:6:31 + | +LL | pub fn hello(x: &Vec<i32>) -> impl Display { 0 } + | ^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0502`. diff --git a/tests/ui/impl-trait/precise-capturing/migration-note.rs b/tests/ui/impl-trait/precise-capturing/migration-note.rs new file mode 100644 index 00000000000..a5bade4ddc5 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/migration-note.rs @@ -0,0 +1,190 @@ +//@ edition: 2024 +//@ compile-flags: -Zunstable-options + +use std::fmt::Display; + +fn display_len<T>(x: &Vec<T>) -> impl Display { + //~^ NOTE in this expansion of desugaring of `impl Trait` + //~| NOTE in this expansion of desugaring of `impl Trait` + //~| NOTE in this expansion of desugaring of `impl Trait` + //~| NOTE in this expansion of desugaring of `impl Trait` + //~| NOTE in this expansion of desugaring of `impl Trait` + x.len() +} + +fn conflicting_borrow() { + let mut x = vec![]; + let a = display_len(&x); + //~^ NOTE this call may capture more lifetimes than intended + //~| NOTE immutable borrow occurs here + x.push(1); + //~^ ERROR cannot borrow `x` as mutable because it is also borrowed as immutable + //~| NOTE mutable borrow occurs here + println!("{a}"); + //~^ NOTE immutable borrow later used here +} + +fn needs_static() { + let x = vec![1]; + //~^ NOTE binding `x` declared here + let a = display_len(&x); + //~^ ERROR `x` does not live long enough + //~| NOTE this call may capture more lifetimes than intended + //~| NOTE argument requires that `x` is borrowed for `'static` + //~| NOTE borrowed value does not live long enoug + + fn needs_static(_: impl Sized + 'static) {} + needs_static(a); +} +//~^ NOTE `x` dropped here while still borrowed + +fn is_moved() { + let x = vec![1]; + //~^ NOTE binding `x` declared here + let a = display_len(&x); + //~^ NOTE this call may capture more lifetimes than intended + //~| NOTE borrow of `x` occurs here + + fn mv(_: impl Sized) {} + mv(x); + //~^ ERROR cannot move out of `x` because it is borrowed + //~| NOTE move out of `x` occurs here +} +//~^ NOTE borrow might be used here, when `a` is dropped + +fn display_len_mut<T>(x: &mut Vec<T>) -> impl Display { + //~^ NOTE in this expansion of desugaring of `impl Trait` + //~| NOTE in this expansion of desugaring of `impl Trait` + //~| NOTE in this expansion of desugaring of `impl Trait` + x.len() +} + +fn conflicting_borrow_mut() { + let mut x = vec![]; + let a = display_len_mut(&mut x); + //~^ NOTE this call may capture more lifetimes than intended + //~| NOTE first mutable borrow occurs here + x.push(1); + //~^ ERROR cannot borrow `x` as mutable more than once + //~| NOTE second mutable borrow occurs here + println!("{a}"); + //~^ NOTE first borrow later used here +} + +fn needs_static_mut() { + let mut x = vec![1]; + //~^ NOTE binding `x` declared here + let a = display_len_mut(&mut x); + //~^ ERROR `x` does not live long enough + //~| NOTE this call may capture more lifetimes than intended + //~| NOTE argument requires that `x` is borrowed for `'static` + //~| NOTE borrowed value does not live long enough + + fn needs_static(_: impl Sized + 'static) {} + needs_static(a); +} +//~^ NOTE `x` dropped here while still borrowed + +fn is_move_mut() { + let mut x = vec![1]; + //~^ NOTE binding `x` declared here + let a = display_len_mut(&mut x); + //~^ NOTE this call may capture more lifetimes than intended + //~| NOTE borrow of `x` occurs here + + fn mv(_: impl Sized) {} + mv(x); + //~^ ERROR cannot move out of `x` because it is borrowed + //~| NOTE move out of `x` occurs here +} +//~^ NOTE borrow might be used here, when `a` is dropped + +struct S { f: i32 } + +fn display_field<T: Copy + Display>(t: &T) -> impl Display { + //~^ NOTE in this expansion of desugaring of `impl Trait` + //~| NOTE in this expansion of desugaring of `impl Trait` + //~| NOTE in this expansion of desugaring of `impl Trait` + *t +} + +fn conflicting_borrow_field() { + let mut s = S { f: 0 }; + let a = display_field(&s.f); + //~^ NOTE this call may capture more lifetimes than intended + //~| NOTE `s.f` is borrowed here + s.f = 1; + //~^ ERROR cannot assign to `s.f` because it is borrowed + //~| NOTE `s.f` is assigned to here but it was already borrowed + println!("{a}"); + //~^ NOTE borrow later used here +} + +fn display_field_mut<T: Copy + Display>(t: &mut T) -> impl Display { + *t +} + +fn conflicting_borrow_field_mut() { + let mut s = S { f: 0 }; + let a = display_field(&mut s.f); + //~^ NOTE this call may capture more lifetimes than intended + //~| NOTE `s.f` is borrowed here + s.f = 1; + //~^ ERROR cannot assign to `s.f` because it is borrowed + //~| NOTE `s.f` is assigned to here but it was already borrowed + println!("{a}"); + //~^ NOTE borrow later used here +} + +fn field_move() { + let mut s = S { f: 0 }; + let a = display_field(&mut s.f); + //~^ NOTE this call may capture more lifetimes than intended + //~| NOTE `s.f` is borrowed here + s.f; + //~^ ERROR cannot use `s.f` because it was mutably borrowed + //~| NOTE use of borrowed `s.f` + println!("{a}"); + //~^ NOTE borrow later used here +} + +struct Z { + f: Vec<i32>, +} + +fn live_long() { + let x; + { + let z = Z { f: vec![1] }; + //~^ NOTE binding `z` declared here + x = display_len(&z.f); + //~^ ERROR `z.f` does not live long enough + //~| NOTE this call may capture more lifetimes than intended + //~| NOTE values in a scope are dropped in the opposite order they are defined + //~| NOTE borrowed value does not live long enough + } + //~^ NOTE `z.f` dropped here while still borrowed +} +//~^ NOTE borrow might be used here, when `x` is dropped + +fn temp() { + let x = { let x = display_len(&mut vec![0]); x }; + //~^ ERROR temporary value dropped while borrowed + //~| NOTE this call may capture more lifetimes than intended + //~| NOTE consider using a `let` binding to create a longer lived value + //~| NOTE borrow later used here + //~| NOTE temporary value is freed at the end of this statement +} + +// FIXME: This doesn't display a useful Rust 2024 suggestion :( +fn returned() -> impl Sized { + let x = vec![0]; + //~^ NOTE binding `x` declared here + display_len(&x) + //~^ ERROR `x` does not live long enough + //~| NOTE borrowed value does not live long enough + //~| NOTE argument requires that `x` is borrowed for `'static` +} +//~^ NOTE `x` dropped here while still borrowed + +fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/migration-note.stderr b/tests/ui/impl-trait/precise-capturing/migration-note.stderr new file mode 100644 index 00000000000..3ac47ed1bcd --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/migration-note.stderr @@ -0,0 +1,284 @@ +error[E0597]: `x` does not live long enough + --> $DIR/migration-note.rs:183:17 + | +LL | let x = vec![0]; + | - binding `x` declared here +LL | +LL | display_len(&x) + | ------------^^- + | | | + | | borrowed value does not live long enough + | argument requires that `x` is borrowed for `'static` +... +LL | } + | - `x` dropped here while still borrowed + +error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable + --> $DIR/migration-note.rs:20:5 + | +LL | let a = display_len(&x); + | -- immutable borrow occurs here +... +LL | x.push(1); + | ^^^^^^^^^ mutable borrow occurs here +... +LL | println!("{a}"); + | --- immutable borrow later used here + | +note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules + --> $DIR/migration-note.rs:17:13 + | +LL | let a = display_len(&x); + | ^^^^^^^^^^^^^^^ +help: add a precise capturing bound to avoid overcapturing + | +LL | fn display_len<T>(x: &Vec<T>) -> impl Display + use<T> { + | ++++++++ + +error[E0597]: `x` does not live long enough + --> $DIR/migration-note.rs:30:25 + | +LL | let x = vec![1]; + | - binding `x` declared here +LL | +LL | let a = display_len(&x); + | ------------^^- + | | | + | | borrowed value does not live long enough + | argument requires that `x` is borrowed for `'static` +... +LL | } + | - `x` dropped here while still borrowed + | +note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules + --> $DIR/migration-note.rs:30:13 + | +LL | let a = display_len(&x); + | ^^^^^^^^^^^^^^^ +help: add a precise capturing bound to avoid overcapturing + | +LL | fn display_len<T>(x: &Vec<T>) -> impl Display + use<T> { + | ++++++++ + +error[E0505]: cannot move out of `x` because it is borrowed + --> $DIR/migration-note.rs:49:8 + | +LL | let x = vec![1]; + | - binding `x` declared here +LL | +LL | let a = display_len(&x); + | -- borrow of `x` occurs here +... +LL | mv(x); + | ^ move out of `x` occurs here +... +LL | } + | - borrow might be used here, when `a` is dropped and runs the destructor for type `impl std::fmt::Display` + | +note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules + --> $DIR/migration-note.rs:44:13 + | +LL | let a = display_len(&x); + | ^^^^^^^^^^^^^^^ +help: add a precise capturing bound to avoid overcapturing + | +LL | fn display_len<T>(x: &Vec<T>) -> impl Display + use<T> { + | ++++++++ +help: consider cloning the value if the performance cost is acceptable + | +LL | let a = display_len(&x.clone()); + | ++++++++ + +error[E0499]: cannot borrow `x` as mutable more than once at a time + --> $DIR/migration-note.rs:67:5 + | +LL | let a = display_len_mut(&mut x); + | ------ first mutable borrow occurs here +... +LL | x.push(1); + | ^ second mutable borrow occurs here +... +LL | println!("{a}"); + | --- first borrow later used here + | +note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules + --> $DIR/migration-note.rs:64:13 + | +LL | let a = display_len_mut(&mut x); + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: add a precise capturing bound to avoid overcapturing + | +LL | fn display_len_mut<T>(x: &mut Vec<T>) -> impl Display + use<T> { + | ++++++++ + +error[E0597]: `x` does not live long enough + --> $DIR/migration-note.rs:77:29 + | +LL | let mut x = vec![1]; + | ----- binding `x` declared here +LL | +LL | let a = display_len_mut(&mut x); + | ----------------^^^^^^- + | | | + | | borrowed value does not live long enough + | argument requires that `x` is borrowed for `'static` +... +LL | } + | - `x` dropped here while still borrowed + | +note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules + --> $DIR/migration-note.rs:77:13 + | +LL | let a = display_len_mut(&mut x); + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: add a precise capturing bound to avoid overcapturing + | +LL | fn display_len_mut<T>(x: &mut Vec<T>) -> impl Display + use<T> { + | ++++++++ + +error[E0505]: cannot move out of `x` because it is borrowed + --> $DIR/migration-note.rs:96:8 + | +LL | let mut x = vec![1]; + | ----- binding `x` declared here +LL | +LL | let a = display_len_mut(&mut x); + | ------ borrow of `x` occurs here +... +LL | mv(x); + | ^ move out of `x` occurs here +... +LL | } + | - borrow might be used here, when `a` is dropped and runs the destructor for type `impl std::fmt::Display` + | +note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules + --> $DIR/migration-note.rs:91:13 + | +LL | let a = display_len_mut(&mut x); + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: add a precise capturing bound to avoid overcapturing + | +LL | fn display_len_mut<T>(x: &mut Vec<T>) -> impl Display + use<T> { + | ++++++++ +help: consider cloning the value if the performance cost is acceptable + | +LL | let a = display_len_mut(&mut x.clone()); + | ++++++++ + +error[E0506]: cannot assign to `s.f` because it is borrowed + --> $DIR/migration-note.rs:116:5 + | +LL | let a = display_field(&s.f); + | ---- `s.f` is borrowed here +... +LL | s.f = 1; + | ^^^^^^^ `s.f` is assigned to here but it was already borrowed +... +LL | println!("{a}"); + | --- borrow later used here + | +note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules + --> $DIR/migration-note.rs:113:13 + | +LL | let a = display_field(&s.f); + | ^^^^^^^^^^^^^^^^^^^ +help: add a precise capturing bound to avoid overcapturing + | +LL | fn display_field<T: Copy + Display>(t: &T) -> impl Display + use<T> { + | ++++++++ + +error[E0506]: cannot assign to `s.f` because it is borrowed + --> $DIR/migration-note.rs:132:5 + | +LL | let a = display_field(&mut s.f); + | -------- `s.f` is borrowed here +... +LL | s.f = 1; + | ^^^^^^^ `s.f` is assigned to here but it was already borrowed +... +LL | println!("{a}"); + | --- borrow later used here + | +note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules + --> $DIR/migration-note.rs:129:13 + | +LL | let a = display_field(&mut s.f); + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: add a precise capturing bound to avoid overcapturing + | +LL | fn display_field<T: Copy + Display>(t: &T) -> impl Display + use<T> { + | ++++++++ + +error[E0503]: cannot use `s.f` because it was mutably borrowed + --> $DIR/migration-note.rs:144:5 + | +LL | let a = display_field(&mut s.f); + | -------- `s.f` is borrowed here +... +LL | s.f; + | ^^^ use of borrowed `s.f` +... +LL | println!("{a}"); + | --- borrow later used here + | +note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules + --> $DIR/migration-note.rs:141:13 + | +LL | let a = display_field(&mut s.f); + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: add a precise capturing bound to avoid overcapturing + | +LL | fn display_field<T: Copy + Display>(t: &T) -> impl Display + use<T> { + | ++++++++ + +error[E0597]: `z.f` does not live long enough + --> $DIR/migration-note.rs:160:25 + | +LL | let z = Z { f: vec![1] }; + | - binding `z` declared here +LL | +LL | x = display_len(&z.f); + | ^^^^ borrowed value does not live long enough +... +LL | } + | - `z.f` dropped here while still borrowed +LL | +LL | } + | - borrow might be used here, when `x` is dropped and runs the destructor for type `impl std::fmt::Display` + | + = note: values in a scope are dropped in the opposite order they are defined +note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules + --> $DIR/migration-note.rs:160:13 + | +LL | x = display_len(&z.f); + | ^^^^^^^^^^^^^^^^^ +help: add a precise capturing bound to avoid overcapturing + | +LL | fn display_len<T>(x: &Vec<T>) -> impl Display + use<T> { + | ++++++++ + +error[E0716]: temporary value dropped while borrowed + --> $DIR/migration-note.rs:171:40 + | +LL | let x = { let x = display_len(&mut vec![0]); x }; + | ^^^^^^^ - - borrow later used here + | | | + | | temporary value is freed at the end of this statement + | creates a temporary value which is freed while still in use + | + = note: consider using a `let` binding to create a longer lived value +note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules + --> $DIR/migration-note.rs:171:23 + | +LL | let x = { let x = display_len(&mut vec![0]); x }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) +help: add a precise capturing bound to avoid overcapturing + | +LL | fn display_len<T>(x: &Vec<T>) -> impl Display + use<T> { + | ++++++++ + +error: aborting due to 12 previous errors + +Some errors have detailed explanations: E0499, E0502, E0503, E0505, E0506, E0597, E0716. +For more information about an error, try `rustc --explain E0499`. |
