From 0ed8847e310209ddd1d5beb4bdee2140480dcf4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Ludwig?= Date: Fri, 26 Jun 2020 22:36:44 +0200 Subject: [PATCH] Add forceNothrowPostblit attribute. Enforces that TaggedUnion's postblit constructor is nothrow, raising an assertion error otherwise. --- source/taggedalgebraic/taggedunion.d | 35 ++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/source/taggedalgebraic/taggedunion.d b/source/taggedalgebraic/taggedunion.d index f3db2c7..6351783 100644 --- a/source/taggedalgebraic/taggedunion.d +++ b/source/taggedalgebraic/taggedunion.d @@ -14,7 +14,7 @@ alias visit = taggedalgebraic.visit.visit; import std.algorithm.mutation : move, swap; import std.meta; import std.range : isOutputRange; -import std.traits : EnumMembers, FieldNameTuple, Unqual, isInstanceOf; +import std.traits : EnumMembers, FieldNameTuple, Unqual, hasUDA, isInstanceOf; /** Implements a generic tagged union type. @@ -117,7 +117,12 @@ align(commonAlignment!(UnionKindTypes!(UnionFieldEnum!U))) struct TaggedUnion static if (hasElaborateCopyConstructor!T) { case __traits(getMember, Kind, tname): - typeid(T).postblit(cast(void*)&trustedGet!T()); + static if (hasUDA!(U, typeof(forceNothrowPostblit()))) { + try typeid(T).postblit(cast(void*)&trustedGet!T()); + catch (Exception e) assert(false, e.msg); + } else { + typeid(T).postblit(cast(void*)&trustedGet!T()); + } return; } } @@ -542,6 +547,32 @@ unittest { // support trailing underscores properly assert(val.intValue == 20); } + +@property auto forceNothrowPostblit() +{ + if (!__ctfe) assert(false, "@forceNothrowPostblit must only be used as a UDA."); + static struct R {} + return R.init; +} + +nothrow unittest { + static struct S { + this(this) nothrow {} + } + + @forceNothrowPostblit + struct U { + S s; + } + + alias TU = TaggedUnion!U; + + TU tu, tv; + tu = S.init; + tv = tu; +} + + enum isUnitType(T) = is(T == Void) || is(T == void) || is(T == typeof(null));