[Issue 24835] New: hasElaborateAssign is true for structs where opAssign is disabled if a member variable has elaborate assignment
d-bugmail at puremagic.com
d-bugmail at puremagic.com
Fri Oct 25 22:03:24 UTC 2024
https://issues.dlang.org/show_bug.cgi?id=24835
Issue ID: 24835
Summary: hasElaborateAssign is true for structs where opAssign
is disabled if a member variable has elaborate
assignment
Product: D
Version: D2
Hardware: All
OS: All
Status: NEW
Severity: normal
Priority: P1
Component: druntime
Assignee: nobody at puremagic.com
Reporter: issues.dlang at jmdavisProg.com
std.traits.hasElaborateAssign (and therefore
core.internal.traits.hasElaborateAssign, since one uses the other) is
inconsistent with regards to the answer it gives when @disable is used on
opAssign. In particular, it differs based on whether a member variable has a
non-disabled opAssign or not.
This code
---
void main()
{
import std.traits;
static struct S
{
void opAssign(S) {}
}
pragma(msg, "Has elaborate assignment: " ~ hasElaborateAssign!S.stringof);
S s;
S s2;
s = s2;
}
---
compiles and prints out
---
Has elaborate assignment: true
---
This code
---
void main()
{
import std.traits;
static struct S
{
@disable void opAssign(S) {}
}
pragma(msg, "Has elaborate assignment: " ~ hasElaborateAssign!S.stringof);
S s;
S s2;
s = s2;
}
---
fails to compile and prints out
---
Has elaborate assignment: false
q.d(13): Error: function `q.main.S.opAssign` cannot be used because it is
annotated with `@disable`
---
So far, so good.
This code
---
void main()
{
import std.traits;
static struct Member
{
void opAssign(Member) {}
}
static assert(hasElaborateAssign!Member);
static struct S
{
Member member;
}
pragma(msg, "Has elaborate assignment: " ~ hasElaborateAssign!S.stringof);
S s;
S s2;
s = s2;
}
---
compiles and prints out
---
Has elaborate assignment: true
---
The compiler generates an opAssign because of the member variable with an
opAssign, so that's fine.
And if we provide an explicit opAssign
---
void main()
{
import std.traits;
static struct Member
{
void opAssign(Member) {}
}
static assert(hasElaborateAssign!Member);
static struct S
{
Member member;
void opAssign(S) {}
}
pragma(msg, "Has elaborate assignment: " ~ hasElaborateAssign!S.stringof);
S s;
S s2;
s = s2;
}
---
we once again get
---
Has elaborate assignment: true
---
However, what about if we disable that opAssign?
---
void main()
{
import std.traits;
static struct Member
{
void opAssign(Member) {}
}
static assert(hasElaborateAssign!Member);
static struct S
{
Member member;
@disable void opAssign(S) {}
}
pragma(msg, "Has elaborate assignment: " ~ hasElaborateAssign!S.stringof);
S s;
S s2;
s = s2;
}
---
That fails to compile, giving
---
Has elaborate assignment: true
q.d(20): Error: function `q.main.S.opAssign` cannot be used because it is
annotated with `@disable`
---
Note however that whereas disabling opAssign when there were no member
variables with an opAssign resulted in hasElaborateAssign!S being false, in
this case, it's reported as true.
And to round things out, we have the case where the member variable has a
disabled opAssign, and S doesn't explicitly declare one
---
void main()
{
import std.traits;
static struct Member
{
@disable void opAssign(Member) {}
}
static assert(!hasElaborateAssign!Member);
static struct S
{
Member member;
}
pragma(msg, "Has elaborate assignment: " ~ hasElaborateAssign!S.stringof);
S s;
S s2;
s = s2;
}
---
This fails to compile, giving
---
Has elaborate assignment: false
q.d(18): Error: generated function `q.main.S.opAssign` cannot be used because
it is annotated with `@disable`
---
So, it looks like as a general rule, hasElaborateAssign is false if opAssign is
disabled (which I guess highlights a weird situation where we're arguably
dealing with a trinary state rather than binary, since the possible states we
have are default assignment, elaborate assignment, and disabled assignment, and
hasElaborateAssign is basically just saying whether there's elaborate
assignment). However, in the case where a member variable has opAssign, and
that opAssign isn't disabled, the struct containing it is considered to have
elaborate assignment regardless of whether that struct disables assignment. And
given hasElaborateAssign acts in the other cases, I'd consider that a bug.
--
More information about the Digitalmars-d-bugs
mailing list