I would expect it to work due to non-lexical lifetimes—after all, _y is never used and could go out of scope immediately. Even more confusing is the fact that if I either
Also if you assign to _ it will just drop it immediately.
And the reason for this is that _ is not an identifier name - it's a reserved token used in patterns, and the pattern is specifying that you don't wish to bind the value in the pattern, causing it to be dropped immediately.
This is the piece I was missing, thank you. Would it be correct to say that under non-lexical lifetimes, _y can go out of scope at any point in a block, but the actual drop call only ever happens at the end of a block? Which would mean that if the drop method is nontrivial, _y has to live to the end of the block so that drop still has it available when it needs to do its thing.
Under NLL, the borrow (i.e., just a compile-time property) is released as soon as it is no longer used.
The variable holding the pointer (runtime representation of the reference) is, however, still dropped at the end of its lexical scope.
Thus, if the variable holding the borrow has Drop (glue), the borrow may be accessed / used when the variable is drop-ped, meaning that the no longer used moment happens after the end of the lexical scope, rendering NLL useless in this case indeed.
This can be avoided with the unsafe (and unstable) #[may_dangle] attribute:
#![feature(dropck_eyepatch)]
pub
struct Foo<'a, T> /* = */ (&'a mut T);
unsafe impl<#[may_dangle] 'a, T : 'a>
Drop for Foo<'a, T>
{
fn drop (self: &'_ mut Self)
{
// this does not dereference self.0 (it just prints the raw address of the pointee), so it is fine
println!("Dropping Foo({:p})", self.0);
}
}
fn main ()
{
let mut x = 5;
println!("x at {:p}", &x);
let foo = Foo(&mut x);
println!("Created Foo(&mut x = {:p})", foo.0);
println!("Accessing x directly: {}", x);
}