Bug 16104 – Unions should allow fields with destructors, postblits, and invariants

Status
RESOLVED
Resolution
WORKSFORME
Severity
enhancement
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
x86_64
OS
Linux
Creation time
2016-05-31T03:04:00Z
Last change time
2017-07-02T13:24:08Z
Assigned to
nobody
Creator
andrei
See also
https://issues.dlang.org/show_bug.cgi?id=2665, https://issues.dlang.org/show_bug.cgi?id=4144

Comments

Comment #0 by andrei — 2016-05-31T03:04:44Z
Consider https://dpaste.dzfl.pl/4897efa2f3e0, also copied here: struct A1 { this(int) immutable {} //~this(); } struct A2 { this(int) immutable {} } struct B { union { A1 a1; A2 a2; } bool itsA2; this(int x) immutable { if (x < 0) { a1 = immutable(A1)(x); } else { a2 = immutable(A2)(x); itsA2 = true; } } } Here B is able to offer an immutable constructor because the typechecker converts the first field assignment a1 = expr into a constructor call (not an assignment). Then all we need to do is provide immutable constructors for A1 and A2. Neat. Unfortunately, it all comes unglued if either or both A1 and A2 also offers a destructor. In that case they can't be members of a union any longer, and the consequence of that is, oddly, that objects with unions cannot offer immutable constructors. E.g. uncommenting the dtor in A1 causes the error: struct std.experimental.rc.B destructors, postblits and invariants are not allowed in overlapping fields a1 and a2 This is an interesting example of interacting language features. The solution is to allow literally any D type in a union. ALL TYPES. The very point of the union is "put the layout here but enforce no guarantees about the content; surrounding code will take care of that". So types with destructors, postblits, and invariants should be gleefully allowed in unions. There would be of course no calls to any of those. This is a blocker for RCStr.
Comment #1 by bugzilla — 2016-05-31T03:40:25Z
In C++: struct S { ~S(); }; union U { S s; }; g++ -c foo.cpp foo.cpp:2:14: error: member 'S U::s' with destructor not allowed in union union U { S s; }; ^ foo.cpp:2:14: note: unrestricted unions only available with -std=c++11 or -std=gnu++11 What was C++11's rationale?
Comment #2 by bugzilla — 2016-05-31T03:48:58Z
Consider: struct S { ~this(); } struct T { S s; } The compiler will automatically create a destructor for T that will call the destructor for s, or will add code to do that to the destructor for T. union U { S1 a; S2 b; } U u; What happens to RIAA with this?
Comment #3 by andrei — 2016-05-31T04:05:23Z
(In reply to Walter Bright from comment #1) > In C++: > > struct S { ~S(); }; > union U { S s; }; > > g++ -c foo.cpp > foo.cpp:2:14: error: member 'S U::s' with destructor not allowed in union > union U { S s; }; > ^ > foo.cpp:2:14: note: unrestricted unions only available with -std=c++11 or > -std=gnu++11 > > > What was C++11's rationale? Forgot to mention Lois Goldthwaite's work on this: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf. It's a great fix of C++ without which implementing things like variant types portably was next to impossible.
Comment #4 by andrei — 2016-05-31T04:08:01Z
(In reply to Walter Bright from comment #2) > Consider: > > struct S { ~this(); } > struct T { S s; } > > The compiler will automatically create a destructor for T that will call the > destructor for s, or will add code to do that to the destructor for T. > > union U { S1 a; S2 b; } > U u; > > What happens to RIAA with this? You mean RAII? There's none of it in unions. As I said, putting data in unions automatically disables all automatic calls. Putting stuff in unions is purely layout definition and manipulation. All calls must be inserted by the code using the union (which is usually encapsulated in a struct wrapping the union and providing discrimination).
Comment #5 by dlang-bugzilla — 2017-07-02T13:24:08Z
I believe this was fixed in https://github.com/dlang/dmd/pull/5830. BTW, the example in the description has a non-trivial history: .. before 2.063 : test.d(24): Error: mutable method test.A1.opAssign is not callable using a immutable object Fixed by: https://github.com/dlang/dmd/pull/2665 (issue 9665) 2.064 ... 2.066 : works Broken by: https://github.com/dlang/dmd/pull/4144 (issue 4421) 2.067 ... 2.071 : test.d(12): Error: struct test.B destructors, postblits and invariants are not allowed in overlapping fields a1 and a2 Fixed by: https://github.com/dlang/dmd/pull/5830 2.072 ... now : works