about summary refs log tree commit diff
path: root/tests/ui/impl-trait/precise-capturing
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2024-10-03 00:44:14 -0400
committerMichael Goulet <michael@errs.io>2024-10-31 01:35:14 +0000
commitc1457798db03ffb7f207eaf208d8d4d77ba01563 (patch)
treef971a769db7432ffdc4a0628c5481518e97f18eb /tests/ui/impl-trait/precise-capturing
parente093b82a41906c8c228643314e2f799568b37ee9 (diff)
downloadrust-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')
-rw-r--r--tests/ui/impl-trait/precise-capturing/auxiliary/foreign.rs6
-rw-r--r--tests/ui/impl-trait/precise-capturing/foreign-2021.rs15
-rw-r--r--tests/ui/impl-trait/precise-capturing/foreign-2021.stderr26
-rw-r--r--tests/ui/impl-trait/precise-capturing/migration-note.rs190
-rw-r--r--tests/ui/impl-trait/precise-capturing/migration-note.stderr284
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`.