rustconstantsdestructor

Cannot match on Result in const fn due to "destructor cannot be evaluated at compile-time" even when value isn't dropped


I tried to match on a generic Result<&mut T, T> inside of a const fn, but the compiler did not let me. It would require being able to drop the value at the end of the scope, which is currently not possible inside of a const fn.

I truncated my code a bit and finally landed on this snipped. It still gives the same error, with the same reason, but is no longer generic.

struct Dummy;

impl Drop for Dummy {
    fn drop(&mut self) {
        println!("dropped");
    }
}

const fn const_match(result: Result<Dummy, ()>) -> Result<Dummy, ()> {
    match result { //^^^^^^ the destructor for this type cannot be evaluated in constant functions
        Ok(ok) => Ok(ok),
        Err(err) => Err(err),
    }
} // <- value is dropped here

The compiler gives me the following error message:

error[E0493]: destructor of `Result<Dummy, ()>` cannot be evaluated at compile-time
  --> <source>:9:22
   |
9  | const fn const_match(result: Result<Dummy, ()>) -> Result<Dummy, ()> {
   |                      ^^^^^^ the destructor for this type cannot be evaluated in constant functions
...
14 | }
   | - value is dropped here

By removing the const everything compiles flawlessly, so I created a test to check if the value really ever gets dropped inside of this function.

struct Dummy;

impl Drop for Dummy {
    fn drop(&mut self) {
        println!("dropped");
    }
}

fn const_match(result: Result<Dummy, ()>) -> Result<Dummy, ()> {
    match result {
        Ok(ok) => Ok(ok),
        Err(err) => Err(err),
    }
}

fn main() {
    let dummy = const_match(Ok(Dummy));
    let err = const_match(Err(()));

    std::mem::forget(dummy);
}

Here's the godbolt link to an identical code sample. As expected it produces no output, so the destructor never gets run inside of const_match.

Why does the destructor need to be able to run?


Solution

  • It seems const evaluation still has growing pains. There is a tracking issue for more precise drop analysis in const contexts; if you compile this code on +nightly with:

    #![feature(const_precise_live_drops)]
    

    then it passes (playground).

    The feature appears functional for simple cases but from the issue comments it may not have been stabilized yet in favor of a more complete solution. Since the core of the problem seems to be around destructuring patterns, I'm not sure there's a workaround on +stable.