Drop rules for temporaries in final expression

Just curious about the reasoning behind drop rule for temporaries in place context. There's a similar open github issue, but no direct answer.

  1. why rust decides to destroy the temp of the final expression under place context at last? why not just do regular reverse order drop?
  2. why drop rule cannot be as simple as C++'s? no distinguish between lvalue and rvalue, just call destructor in reverse order for lvalue or destruct temp at the end of statement.

The temporary scope of an expression is the scope that is used for the temporary variable that holds the result of that expression when used in a place context, unless it is promoted.

Temporaries that are created in the final expression of a function body are dropped after any named variables bound in the function body, as there is no smaller enclosing temporary scope.

struct PrintOnDrop(&'static str);

impl Drop for PrintOnDrop {
    fn drop(&mut self) {
        println!("{}", self.0);
    }
}

fn demo() -> &'static str {
    let local = PrintOnDrop("first");
    println!("ignore me {}", local.0);
    PrintOnDrop("second").0
}

fn main() {
    demo();
}

output

first
second

Shouldn't reverse destroy be more intuitive? For example, the result can be

second
first

playground

This is a follow up of my previous thread:

if the temp is dropped as same order as regular named variables, i.e., reverse order,

use std::cell::RefCell;

// Definition for a binary tree node.
#[derive(Debug, PartialEq, Eq)]
pub struct Foo {
    pub val: i32,
}

pub fn demo() -> i32 {
    let x = RefCell::new(Foo{ val: 10 });
    x.borrow().val
} 
// x should be dropped at here so that return is valid. 
// But compiler says no

code above can compile. The issue here is that compiler lets x.borrow() to be dropped after x, which causes trouble. If x.borrow() is dropped right after use, there won't be such trouble.

I don't get what's wrong with the Playground you posted. The expression with "local" in it is a temporary inside a statement that is not the last statement of the block, so the special rules don't apply to it. It is in a statement that is before another one, and in this case its only parent is its immediate enclosing statement, it's only natural that it gets dropped at the end of that statement.

Furthermore, in the second (last) statement, there's only one value whose dropping you observe, and the function has no named variables declared in its body, so the rule you cited doesn't even apply (or at least it can't be observed or demonstrated by the code in the playground above).

I guess this was a mistake/typo. If you make it actual local, the same "unintuitive" order can be observed:

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=c0022e3b986b0426fdd2439ae1296268

1 Like

@krdln thanks for fixing this.

Just fixed the playground example. Sorry for any confusion.