Const fn that consumes `self` by value?

I've got code like the following:

struct Foo<T>(T);

impl<T> Foo<T> {
    const fn into_t(self) -> T {
        let Foo(t) = self;
        t
    }
}

I get the following error:

error[E0493]: destructors cannot be evaluated at compile-time
 --> src/lib.rs:4:21
  |
4 |     const fn into_t(self) -> T {
  |                     ^^^^ constant functions cannot evaluate destructors
...
7 |     }
  |     - value is dropped here

IIUC, there can never be any drop code called here because Foo doesn't implement Drop, and the A (which could implement Drop) is not dropped.

Is there any way to convince the compiler that no drop is happening?

2 Likes

I don't think so. Rust doesn't do "negative reasoning" about generic types.

Can you take &mut self and .take() from Option<T>?

Womp womp.

So Foo is an existing API with a lot of other functionality, and I'd prefer not to have to change it to store an Option<T> (and then .unwrap() all over the place, which has runtime costs as well as costs in terms of code cleanliness, likelihood of introducing future bugs, etc) just to support this use case. If there's a way that allows me to leave the type definition as is, that'd be a lot better.

On that note: Assuming that the only way to do this is using unsafe, any thoughts on what the least-unsafe approach would be?

Oh, actually, there's a bit of negative reasoning for Drop: T: Copy.

If you can't make it Copy, then maybe ManuallyDrop<T>? But you'd have to still take &mut self and teach Foo not to drop it twice. Basically, reinvent Option::take anyway.

1 Like

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.