Issue 24225 - @safe cast from base type to enum bypasses copy ctor, identity opAssign
Summary: @safe cast from base type to enum bypasses copy ctor, identity opAssign
Status: NEW
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: All All
: P1 normal
Assignee: No Owner
URL:
Keywords: safe
Depends on:
Blocks:
 
Reported: 2023-11-03 23:25 UTC by Paul Backus
Modified: 2023-11-03 23:25 UTC (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description Paul Backus 2023-11-03 23:25:36 UTC
Enum types in D always have trivial copy and assignment operations, regardless of their base type. Normally this is ok, because enum members are required to be compile-time constants, and cannot own any resources that require lifetime management at runtime.

However, this means that casting a value from the base type to the enum type allows any user-defined copy constructors and assignment operators (including @disabled ones) to be completely bypassed.

Currently, this is allowed in @safe code, as the example program below demonstrates:

---
import std.stdio;

struct UniqueInt
{
    @system int n;

    this(int n) @safe
    {
        writefln("Construct UniqueInt(%d)", n);
        this.n = n;
    }

    @disable this(ref inout UniqueInt) inout;

    ~this() @trusted
    {
        writefln("Destroy UniqueInt(%d)", this.n);
        this.n = 0;
    }
}

enum E : UniqueInt { _ = UniqueInt.init }

void main() @safe
{
    import core.lifetime;

    UniqueInt n = 12345;
    E en = cast(E) n;
    UniqueInt n2 = move(en);
}
---

When compiled (with -preview=systemVariables) and run, it produces the following output:

---
Construct UniqueInt(12345)
Destroy UniqueInt(12345)
Destroy UniqueInt(12345)
Destroy UniqueInt(12345)
---

The same UniqueInt is destroyed 3 times, even though only one instance is ever constructed.

To prevent @safe code from bypassing user-defined assignment and copy operations, which may be relied on to maintain an object's safety invariants, casting from an enum's base type to the enum type should be made @system.