summaryrefslogtreecommitdiff
path: root/libphobos/src/std/sumtype.d
diff options
context:
space:
mode:
Diffstat (limited to 'libphobos/src/std/sumtype.d')
-rw-r--r--libphobos/src/std/sumtype.d108
1 files changed, 94 insertions, 14 deletions
diff --git a/libphobos/src/std/sumtype.d b/libphobos/src/std/sumtype.d
index 5e35a6b9cd5..0dd636ea67b 100644
--- a/libphobos/src/std/sumtype.d
+++ b/libphobos/src/std/sumtype.d
@@ -533,15 +533,35 @@ public:
/**
* Assigns a value to a `SumType`.
*
- * Assigning to a `SumType` is `@system` if any of the
- * `SumType`'s members contain pointers or references, since
- * those members may be reachable through external references,
- * and overwriting them could therefore lead to memory
- * corruption.
+ * If any of the `SumType`'s members other than the one being assigned
+ * to contain pointers or references, it is possible for the assignment
+ * to cause memory corruption (see the
+ * ["Memory corruption" example](#memory-corruption) below for an
+ * illustration of how). Therefore, such assignments are considered
+ * `@system`.
*
* An individual assignment can be `@trusted` if the caller can
- * guarantee that there are no outstanding references to $(I any)
- * of the `SumType`'s members when the assignment occurs.
+ * guarantee that there are no outstanding references to any `SumType`
+ * members that contain pointers or references at the time the
+ * assignment occurs.
+ *
+ * Examples:
+ *
+ * $(DIVID memory-corruption, $(H3 Memory corruption))
+ *
+ * This example shows how assignment to a `SumType` can be used to
+ * cause memory corruption in `@system` code. In `@safe` code, the
+ * assignment `s = 123` would not be allowed.
+ *
+ * ---
+ * SumType!(int*, int) s = new int;
+ * s.tryMatch!(
+ * (ref int* p) {
+ * s = 123; // overwrites `p`
+ * return *p; // undefined behavior
+ * }
+ * );
+ * ---
*/
ref SumType opAssign(T rhs);
}
@@ -553,14 +573,35 @@ public:
/**
* Assigns a value to a `SumType`.
*
- * Assigning to a `SumType` is `@system` if any of the `SumType`'s
- * $(I other) members contain pointers or references, since those
- * members may be reachable through external references, and
- * overwriting them could therefore lead to memory corruption.
+ * If any of the `SumType`'s members other than the one being assigned
+ * to contain pointers or references, it is possible for the assignment
+ * to cause memory corruption (see the
+ * ["Memory corruption" example](#memory-corruption) below for an
+ * illustration of how). Therefore, such assignments are considered
+ * `@system`.
*
* An individual assignment can be `@trusted` if the caller can
- * guarantee that, when the assignment occurs, there are no
- * outstanding references to any such members.
+ * guarantee that there are no outstanding references to any `SumType`
+ * members that contain pointers or references at the time the
+ * assignment occurs.
+ *
+ * Examples:
+ *
+ * $(DIVID memory-corruption, $(H3 Memory corruption))
+ *
+ * This example shows how assignment to a `SumType` can be used to
+ * cause memory corruption in `@system` code. In `@safe` code, the
+ * assignment `s = 123` would not be allowed.
+ *
+ * ---
+ * SumType!(int*, int) s = new int;
+ * s.tryMatch!(
+ * (ref int* p) {
+ * s = 123; // overwrites `p`
+ * return *p; // undefined behavior
+ * }
+ * );
+ * ---
*/
ref SumType opAssign(T rhs)
{
@@ -1528,7 +1569,27 @@ private enum bool isSumTypeInstance(T) = is(T == SumType!Args, Args...);
}
/// True if `T` is a [SumType] or implicitly converts to one, otherwise false.
-enum bool isSumType(T) = is(T : SumType!Args, Args...);
+template isSumType(T)
+{
+ static if (is(T : SumType!Args, Args...))
+ {
+ enum isSumType = true;
+ }
+ else static if (is(T == struct) && __traits(getAliasThis, T).length > 0)
+ {
+ // Workaround for https://issues.dlang.org/show_bug.cgi?id=21975
+ import std.traits : ReturnType;
+
+ alias AliasThisType = ReturnType!((T t) =>
+ __traits(getMember, t, __traits(getAliasThis, T)[0])
+ );
+ enum isSumType = .isSumType!AliasThisType;
+ }
+ else
+ {
+ enum isSumType = false;
+ }
+}
///
@safe unittest
@@ -1549,6 +1610,25 @@ enum bool isSumType(T) = is(T : SumType!Args, Args...);
assert(!isSumType!ContainsSumType);
}
+@safe unittest
+{
+ static struct AliasThisVar(T)
+ {
+ SumType!T payload;
+ alias payload this;
+ }
+
+ static struct AliasThisFunc(T)
+ {
+ SumType!T payload;
+ ref get() { return payload; }
+ alias get this;
+ }
+
+ static assert(isSumType!(AliasThisVar!int));
+ static assert(isSumType!(AliasThisFunc!int));
+}
+
/**
* Calls a type-appropriate function with the value held in a [SumType].
*