Question about dereference and temporary lifetime extension

Becuase of the temporary lifetiem extension, we can do this:

use std::ops::Deref;

struct Num(i32);
struct NumRef<'a>(&'a i32);

impl Num {
    fn get_ref(&self) -> NumRef<'_> {
        NumRef(&self.0)
    }
}

impl Deref for NumRef<'_> {
    type Target = i32;
    fn deref(&self) -> &Self::Target {
        self.0
    }
}

fn main() {
    let num = Num(1);
    let r1 = &*num.get_ref();
    println!("{r1}");
}

According to the dereference operator section of the Rust Reference, it says:

On non-pointer types *x is equivalent to *std::ops::Deref::deref(&x) in an immutable place expression context

This seems to indicate that &*num.get_ref() is equivalent to &*(Deref::deref(&num.get_ref())), but:

fn main() {
    let num = Num(1);
    let r2 = &*(Deref::deref(&num.get_ref()));
    //                        ^^^^^^^^^^^^^  - temporary value is freed at the end of this statement
    //                        |
    //                        creates a temporary value which is freed while still in use
    println!("{r2}");
}

Anything I'm missing?

Specifically, nested calls like that will drop temporaries at the end of let statement.

And for new temporary lifetime rules, it's under construction:

https://rust-lang.zulipchat.com/#narrow/stream/403629-t-lang.2Ftemporary-lifetimes-2024

Excuse me but what makes &*num.get_ref() different from &*(Deref::deref(&num.get_ref()))?

Rust should also refuse to compile &*num.get_ref() because it should be always equivalent to &*(Deref::deref(&num.get_ref())), but this is not the case.

If you've read the linked article, the answer will be found

The rules for which temporaries in a let statement get their lifetimes extended is documented in the Rust Reference, but effectively comes down to those expressions where you can tell from just the syntax that extending the lifetime is necessary, independent of any types, function signatures, or trait implementations

let a = f(&temporary()); // Not extended, because it might not be necessary.

No, I mean, the Rust Reference implies that both are the same:

On non-pointer types *x is equivalent to *std::ops::Deref::deref(&x) in an immutable place expression context

In terms of temporaries, they are not the same. &*x is a syntactical tempory lifetime extention, but the other form is not.

The Reference also describes the current behavior on temporaries too:

The temporary scopes for expressions in let statements are sometimes extended to the scope of the block containing the let statement. This is done when the usual temporary scope would be too small, based on certain syntactic rules.

Certain syntactic rule applies for &*x, but not for explicit calls. :smiley:

Expression &*x is not listed in the temporary lifetime extension section, the closest example is let x = (&*&temp(),); but obviously no Deref happens.

If a borrow, dereference, field, or tuple indexing expression has an extended temporary scope then so does its operand.

I won't reply to this post any longer, because I have no time to point out the sentence and rephrase.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.