Confusing const fn "destructor cannot be evaluated at compile-time"

Hello, i currently want to construct a struct in a constant, because it does not need to change, but somehow the ..Struct::DEFAULT gives me a destructor of "Struct" cannot be evaluated at compile-time.

but when trying to create a reproduction of a similar struct it works without problems:

re-creation of the struct:

struct Test {
    somefield: usize,
    somesecondfield: f32,
}

impl Test {
    pub const DEFAULT: Test = Test {
        somefield: 0,
        somesecondfield: 1.0
    };
}

const fn const_fn() -> Test {
    return Test {
        somefield: 100,
        ..Test::DEFAULT // <-- no error?
    }
}

fn main() {
    let _ = const_fn();
}

actual code:

const fn const_fn() -> taffy::style::Style {
    return taffy::style::Style {
        flex_grow: 1.0,
        ..taffy::style::Style::DEFAULT // <-- error
    }
}

fn main() {
    let _ = const_fn();
}

full error:

error[E0493]: destructor of `taffy::prelude::Style` cannot be evaluated at compile-time
  --> src/main.rs:15:6
   |
15 |             ..taffy::style::Style::DEFAULT
   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the destructor for this type cannot be evaluated in constant functions
16 |         };
   |          - value is dropped here

(taffy source)

PS: i am unsure of what the .. syntax is called here, is it StructBase, destructor, or spread or something else?

1 Like

AFAIK it is called struct update syntax.

Your example compiles, because Test has no drop glue (i.e. it does not implement Drop, nor does one of its fields), whereas your real world struct has. I.e. this won't compile either:

struct Test {
    somefield: usize,
    somesecondfield: f32,
}

impl Drop for Test {
    fn drop(&mut self) {}
}

impl Test {
    pub const DEFAULT: Test = Test {
        somefield: 0,
        somesecondfield: 1.0
    };
}

const fn const_fn() -> Test {
    return Test {
        somefield: 100,
        ..Test::DEFAULT // <-- error, because `Test` implements `Drop`
    }
}

fn main() {
    let _ = const_fn();
}

Playground.

Note that there is not actually any significant destruction/dropping required in the code, since you are only replacing one number and keeping all the other fields. The reason for the error is that the compiler is being cautious about not making a mistake. Future versions of the compiler (that is, those after const_precise_live_drops stabilizes) may allow this code.

In the mean time, you can work around this problem by using assignment instead of struct updates:

const fn const_fn() -> taffy::style::Style {
    let mut style = taffy::style::Style::DEFAULT;
    style.flex_grow = 1.0;
    style
}

(There are other cases where this is impossible; for example, Option::unwrap() cannot yet be const, because no matter how you try to implement it there will always be one fewer Option value afterward, which will always result in the error.)

4 Likes

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.