Open frank-king opened 1 month ago
I dag into rustc_trait_selection
for a while but didn't find a clear answer. Is it because the trait obligation selection is based on lexical scopes instead of non-lexical lifetimes?
This isn't anything to do with trait selection. I believe this has to do with the temporary that we create on the autoderef when calling the .len()
method. Here's a minimal example:
async fn yield_point() {}
struct Lock;
impl Lock {
fn borrow(&self) -> LockGuard<'_> { todo!() }
}
struct LockGuard<'a>(*mut (), &'a ());
impl std::ops::Deref for LockGuard<'_> {
type Target = Inner;
fn deref(&self) -> &Self::Target { todo!() }
}
struct Inner;
impl Inner {
fn foo(&self) -> i32 { 0 }
}
fn main() {
let lock = Lock;
fn is_send(_: impl Send) {}
is_send(async {
let guard = lock.borrow();
let _len = guard.foo(); // Comment this out and it works.
drop(guard);
yield_point().await;
});
}
Actually, here's a more minimal example:
#![feature(coroutines)]
struct S(*mut ());
impl S {
fn do_something(&self) {}
}
fn main() {
fn is_send(_: impl Send) {}
is_send(#[coroutine] static || {
// Make a new `S`.
let s = S::new();
// Borrow it by calling a method on it.
s.do_something();
// Drop `s` by moving it.
drop(s);
// Closure analysis keeps thinking that it's live since it has been
// borrowed and there's no `StorageDrop` on `s`'s local.
yield;
});
}
It seems to do with the fact that we don't consider the variable s
to be dead even though it's unconditionally moved from.
cc #112279 which fixes this
@rustbot labels +AsyncAwait-Triaged
We discussed this in our meeting today. Looks like it's being fixed.
I tried this code: (playground)
I expected to see this happen: the code passes compilation.
Instead, this happened:
However, this code works fine: (playground)
Meta: nightly rust (1.81.0-nightly 2024-07-12) and stable rust (1.79.0) behave similarly.
I have constructed a minimum reproducible version: