October 25 [Issue 24835] New: hasElaborateAssign is true for structs where opAssign is disabled if a member variable has elaborate assignment | ||||
---|---|---|---|---|
| ||||
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@puremagic.com Reporter: issues.dlang@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. -- |
Copyright © 1999-2021 by the D Language Foundation