diff options
| author | Stuart Cook <Zalathar@users.noreply.github.com> | 2025-08-11 18:22:31 +1000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-08-11 18:22:31 +1000 |
| commit | 4e87b74810b0143bc9f138d7533d5c642a48ee4c (patch) | |
| tree | e12c603e184ed589ee9b235bd5b272fb9f8a1df3 /tests/ui/async-await | |
| parent | 64aea0027aca53b30dff64252d858a30995c6e14 (diff) | |
| parent | 560e5dcbcf776e06302ecb2fa81f77313d514306 (diff) | |
| download | rust-4e87b74810b0143bc9f138d7533d5c642a48ee4c.tar.gz rust-4e87b74810b0143bc9f138d7533d5c642a48ee4c.zip | |
Rollup merge of #144156 - compiler-errors:dtorck-upvars, r=lcnr
Check coroutine upvars in dtorck constraint Fix rust-lang/rust#144155. This PR fixes an unsoundness where we were not considering coroutine upvars as drop-live if the coroutine interior types (witness types) had nothing which required drop. In the case that the coroutine does not have any interior types that need to be dropped, then we don't need to treat all of the upvars as use-live; instead, this PR uses the same logic as closures, and descends into the upvar types to collect anything that must be drop-live. The rest of this PR is reworking the comment to explain the behavior here. r? `@lcnr` or reassign 😸 --- Just some thoughts --- a proper fix for this whole situation would be to consider `TypingMode` in the `needs_drop` function, and just calling `coroutine_ty.needs_drop(tcx, typing_env)` in the dtorck constraint check. During MIR building, we should probably use a typing mode that stalls the local coroutines and considers them to be unconditionally drop, or perhaps just stall *all* coroutines in analysis mode. Then in borrowck mode, we can re-check `needs_drop` but descend into witness types properly. https://github.com/rust-lang/rust/pull/144158 implements this experimentally. This is a pretty involved fix, and conflicts with some in-flight changes (rust-lang/rust#144157) that I have around removing coroutine witnesses altogether. I'm happy to add a FIXME to rework this whole approach, but I don't want to block this quick fix since it's obviously more correct than the status-quo.
Diffstat (limited to 'tests/ui/async-await')
| -rw-r--r-- | tests/ui/async-await/drop-live-upvar-2.may_not_dangle.stderr | 18 | ||||
| -rw-r--r-- | tests/ui/async-await/drop-live-upvar-2.rs | 37 | ||||
| -rw-r--r-- | tests/ui/async-await/drop-live-upvar.rs | 23 | ||||
| -rw-r--r-- | tests/ui/async-await/drop-live-upvar.stderr | 22 |
4 files changed, 100 insertions, 0 deletions
diff --git a/tests/ui/async-await/drop-live-upvar-2.may_not_dangle.stderr b/tests/ui/async-await/drop-live-upvar-2.may_not_dangle.stderr new file mode 100644 index 00000000000..34f6ba79246 --- /dev/null +++ b/tests/ui/async-await/drop-live-upvar-2.may_not_dangle.stderr @@ -0,0 +1,18 @@ +error[E0597]: `y` does not live long enough + --> $DIR/drop-live-upvar-2.rs:31:26 + | +LL | let y = (); + | - binding `y` declared here +LL | drop_me = Droppy(&y); + | ^^ borrowed value does not live long enough +... +LL | } + | - `y` dropped here while still borrowed +LL | } + | - borrow might be used here, when `fut` is dropped and runs the destructor for coroutine + | + = note: values in a scope are dropped in the opposite order they are defined + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/tests/ui/async-await/drop-live-upvar-2.rs b/tests/ui/async-await/drop-live-upvar-2.rs new file mode 100644 index 00000000000..605db4c8f76 --- /dev/null +++ b/tests/ui/async-await/drop-live-upvar-2.rs @@ -0,0 +1,37 @@ +//@ revisions: may_dangle may_not_dangle +//@[may_dangle] check-pass +//@ edition: 2018 + +// Ensure that if a coroutine's interior has no drop types then we don't require the upvars to +// be *use-live*, but instead require them to be *drop-live*. In this case, `Droppy<&'?0 ()>` +// does not require that `'?0` is live for drops since the parameter is `#[may_dangle]` in +// the may_dangle revision, but not in the may_not_dangle revision. + +#![feature(dropck_eyepatch)] + +struct Droppy<T>(T); + +#[cfg(may_dangle)] +unsafe impl<#[may_dangle] T> Drop for Droppy<T> { + fn drop(&mut self) { + // This does not use `T` of course. + } +} + +#[cfg(may_not_dangle)] +impl<T> Drop for Droppy<T> { + fn drop(&mut self) {} +} + +fn main() { + let drop_me; + let fut; + { + let y = (); + drop_me = Droppy(&y); + //[may_not_dangle]~^ ERROR `y` does not live long enough + fut = async { + std::mem::drop(drop_me); + }; + } +} diff --git a/tests/ui/async-await/drop-live-upvar.rs b/tests/ui/async-await/drop-live-upvar.rs new file mode 100644 index 00000000000..8e881f729b9 --- /dev/null +++ b/tests/ui/async-await/drop-live-upvar.rs @@ -0,0 +1,23 @@ +//@ edition: 2018 +// Regression test for <https://github.com/rust-lang/rust/issues/144155>. + +struct NeedsDrop<'a>(&'a Vec<i32>); + +async fn await_point() {} + +impl Drop for NeedsDrop<'_> { + fn drop(&mut self) {} +} + +fn foo() { + let v = vec![1, 2, 3]; + let x = NeedsDrop(&v); + let c = async { + std::future::ready(()).await; + drop(x); + }; + drop(v); + //~^ ERROR cannot move out of `v` because it is borrowed +} + +fn main() {} diff --git a/tests/ui/async-await/drop-live-upvar.stderr b/tests/ui/async-await/drop-live-upvar.stderr new file mode 100644 index 00000000000..f804484536b --- /dev/null +++ b/tests/ui/async-await/drop-live-upvar.stderr @@ -0,0 +1,22 @@ +error[E0505]: cannot move out of `v` because it is borrowed + --> $DIR/drop-live-upvar.rs:19:10 + | +LL | let v = vec![1, 2, 3]; + | - binding `v` declared here +LL | let x = NeedsDrop(&v); + | -- borrow of `v` occurs here +... +LL | drop(v); + | ^ move out of `v` occurs here +LL | +LL | } + | - borrow might be used here, when `c` is dropped and runs the destructor for coroutine + | +help: consider cloning the value if the performance cost is acceptable + | +LL | let x = NeedsDrop(&v.clone()); + | ++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0505`. |
