std.variant unions cannot have postblit or destructors

This commit is contained in:
Walter Bright 2014-11-15 15:04:57 -08:00
parent b049c00bbe
commit 196ef0c7a5

View file

@ -779,13 +779,22 @@ public:
@property T get(T)() if (!is(T == const)) @property T get(T)() if (!is(T == const))
{ {
union Buf
{
TypeInfo info;
T result;
}
auto p = *cast(T**) &store; auto p = *cast(T**) &store;
Buf buf = { typeid(T) };
/* handler(OpID.get, ) expects the TypeInfo for T in the same buffer it
* writes the result to afterwards. Because T might have a non-trivial
* destructor, postblit or invariant, we cannot use a union.
*/
struct Buf
{
T result;
// Make sure Buf.sizeof is big enough to store a TypeInfo in
void[T.sizeof < TypeInfo.sizeof ? TypeInfo.sizeof - T.sizeof : 0] init = void;
}
TypeInfo info = typeid(T);
Buf buf;
memcpy(&buf, &info, info.sizeof);
if (fptr(OpID.get, &store, &buf)) if (fptr(OpID.get, &store, &buf))
{ {
throw new VariantException(type, typeid(T)); throw new VariantException(type, typeid(T));
@ -795,16 +804,26 @@ public:
@property T get(T)() const if (is(T == const)) @property T get(T)() const if (is(T == const))
{ {
union Buf auto p = *cast(T**) &store;
/* handler(OpID.get, ) expects the TypeInfo for T in the same buffer it
* writes the result to afterwards. Because T might have a non-trivial
* destructor, postblit or invariant, we cannot use a union.
*/
struct Buf
{ {
TypeInfo info;
static if (is(T == shared)) static if (is(T == shared))
shared(Unqual!T) result; shared(Unqual!T) result;
else else
Unqual!T result; Unqual!T result;
// Make sure Buf.sizeof is big enough to store a TypeInfo in
void[T.sizeof < TypeInfo.sizeof ? TypeInfo.sizeof - T.sizeof : 0] init = void;
} }
auto p = *cast(T**) &store; TypeInfo info = typeid(T);
Buf buf = { typeid(T) }; Buf buf;
memcpy(&buf, &info, info.sizeof);
if (fptr(OpID.get, cast(ubyte[size]*) &store, &buf)) if (fptr(OpID.get, cast(ubyte[size]*) &store, &buf))
{ {
throw new VariantException(type, typeid(T)); throw new VariantException(type, typeid(T));