At present, enums with a base type that has a copy constructor, postblit constructor, overloaded assignment operator, and/or destructor completely ignore those functions. E.G.
---
void main()
{
import std.traits;
static struct S
{
int i;
void opAssign()(auto ref S rhs)
{
this.i = rhs.i;
}
this(this)
{
}
~this()
{
}
}
enum E : S
{
a = S(42)
}
static assert(hasElaborateAssign!S);
static assert(hasElaborateCopyConstructor!S);
static assert(hasElaborateDestructor!S);
// These pass but should not
static assert(!hasElaborateAssign!E);
static assert(!hasElaborateCopyConstructor!E);
static assert(!hasElaborateDestructor!E);
}
---
This is fundamentally broken, because any type that has any of those functions clearly was designed to have them and almost certainly will not work correctly if they are not called. I do not really see any real argument for why the current behavior is reasonable, and I expect that it's an oversight in the enum implementation, and it hasn't come up more simply because it's not very common in D to declare enums which are structs.
The spec does currently mention that they are not called - https://dlang.org/spec/enum.html#enum_copying_and_assignment. However, as I understand it, that's simply because Paul Backus decided to document the current behavior rather than it being purposefully decided by someone like Walter.
Now, there are obviously some complications with these functions and enum types (particularly the assignment operator) given that they're written to deal with the base type, not the enum type, requiring conversions. So, I don't know how reasonable it is to support them with enums. However, if it's not reasonable to support them, then IMHO, such structs should simply be disallowed as the base type of enums, since they cannot function properly if those functions are not called properly like they would be with the base type.
A related issue is: https://issues.dlang.org/show_bug.cgi?id=24225
Comment #1 by issues.dlang — 2024-11-23T04:20:34Z
I would note that this is also a memory safety issue, since it's quite possible for the assignment operator, copy / postblit constructor, or destructor (or move constructor once we get those) to be doing something with regards to memory safety, and @trusted code within a type could depend on those functions being called. For instance, skipping these functions would screw up reference counting and potentially result in memory being freed prematurely - thus leading to freed memory being accessed.
Related: https://issues.dlang.org/show_bug.cgi?id=24874
Comment #2 by robert.schadek — 2024-12-13T19:38:17Z