From db4d68e4dff1995ead6e6de0b92d3de1ef35389e Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Sat, 3 Sep 2016 23:46:51 -0700 Subject: [PATCH 1/2] fix Issue 14439 - aa's keys, values, byKey, byValue not usable in @safe context --- src/object.d | 62 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 43 insertions(+), 19 deletions(-) diff --git a/src/object.d b/src/object.d index 8e176e60f3..c87e7ed31b 100644 --- a/src/object.d +++ b/src/object.d @@ -1938,7 +1938,13 @@ extern (C) // alias _dg2_t = extern(D) int delegate(void*, void*); // int _aaApply2(void* aa, size_t keysize, _dg2_t dg); - private struct AARange { void* impl; size_t idx; } + private struct AARange + { + private: + this(void* impl, size_t idx) { this.impl = impl; this.idx = idx; } + void* impl; + size_t idx; + } AARange _aaRange(void* aa) pure nothrow @nogc; bool _aaRangeEmpty(AARange r) pure nothrow @nogc; void* _aaRangeFrontKey(AARange r) pure nothrow @nogc; @@ -2039,7 +2045,7 @@ V[K] dup(T : V[K], K, V)(T* aa) return (*aa).dup; } -auto byKey(T : V[K], K, V)(T aa) pure nothrow @nogc +auto byKey(K, V)(const(V[K]) aa) pure nothrow @nogc { import core.internal.traits : substInout; @@ -2047,22 +2053,22 @@ auto byKey(T : V[K], K, V)(T aa) pure nothrow @nogc { AARange r; - pure nothrow @nogc: + pure nothrow @nogc @trusted: @property bool empty() { return _aaRangeEmpty(r); } @property ref front() { return *cast(substInout!K*)_aaRangeFrontKey(r); } void popFront() { _aaRangePopFront(r); } @property Result save() { return this; } } - return Result(_aaRange(cast(void*)aa)); + return Result(((typeof(aa) aa) @trusted => _aaRange(cast(void*)aa))(aa)); } -auto byKey(T : V[K], K, V)(T* aa) pure nothrow @nogc +auto byKey(T : V[K], K, V)(T* aa) { return (*aa).byKey(); } -auto byValue(T : V[K], K, V)(T aa) pure nothrow @nogc +auto byValue(K, V)(const(V[K]) aa) pure nothrow @nogc { import core.internal.traits : substInout; @@ -2070,22 +2076,22 @@ auto byValue(T : V[K], K, V)(T aa) pure nothrow @nogc { AARange r; - pure nothrow @nogc: + pure nothrow @nogc @trusted: @property bool empty() { return _aaRangeEmpty(r); } - @property ref front() { return *cast(substInout!V*)_aaRangeFrontValue(r); } + @property ref front() { return *cast(const(V)*)_aaRangeFrontValue(r); } void popFront() { _aaRangePopFront(r); } @property Result save() { return this; } } - return Result(_aaRange(cast(void*)aa)); + return Result(((typeof(aa) aa) @trusted => _aaRange(cast(void*)aa))(aa)); } -auto byValue(T : V[K], K, V)(T* aa) pure nothrow @nogc +auto byValue(T : V[K], K, V)(T* aa) { return (*aa).byValue(); } -auto byKeyValue(T : V[K], K, V)(T aa) pure nothrow @nogc +auto byKeyValue(K, V)(const(V[K]) aa) pure nothrow @nogc { import core.internal.traits : substInout; @@ -2093,7 +2099,7 @@ auto byKeyValue(T : V[K], K, V)(T aa) pure nothrow @nogc { AARange r; - pure nothrow @nogc: + pure nothrow @nogc @trusted: @property bool empty() { return _aaRangeEmpty(r); } @property auto front() @trusted { @@ -2114,7 +2120,7 @@ auto byKeyValue(T : V[K], K, V)(T aa) pure nothrow @nogc @property Result save() { return this; } } - return Result(_aaRange(cast(void*)aa)); + return Result(((typeof(aa) aa) @trusted => _aaRange(cast(void*)aa))(aa)); } auto byKeyValue(T : V[K], K, V)(T* aa) pure nothrow @nogc @@ -2122,10 +2128,12 @@ auto byKeyValue(T : V[K], K, V)(T* aa) pure nothrow @nogc return (*aa).byKeyValue(); } -Key[] keys(T : Value[Key], Value, Key)(T aa) @property +Key[] keys(Value, Key)(Value[Key] aa) @property { - auto a = cast(void[])_aaKeys(cast(inout(void)*)aa, Key.sizeof, typeid(Key[])); - auto res = *cast(Key[]*)&a; + auto res = () @trusted { + auto voidRes = _aaKeys(cast(void*)aa, Key.sizeof, typeid(Key[])); + return *cast(Key[]*)&voidRes; + }(); _doPostblit(res); return res; } @@ -2135,10 +2143,12 @@ Key[] keys(T : Value[Key], Value, Key)(T *aa) @property return (*aa).keys; } -Value[] values(T : Value[Key], Value, Key)(T aa) @property +Value[] values(Value, Key)(Value[Key] aa) @property { - auto a = cast(void[])_aaValues(cast(inout(void)*)aa, Key.sizeof, Value.sizeof, typeid(Value[])); - auto res = *cast(Value[]*)&a; + auto res = () @trusted { + auto voidRes = _aaValues(cast(void*)aa, Key.sizeof, Value.sizeof, typeid(Key[])); + return *cast(Value[]*)&voidRes; + }(); _doPostblit(res); return res; } @@ -2175,6 +2185,20 @@ unittest assert(T.count == 2); } +@safe pure unittest +{ + string[string] saa = ["a" : "1", "b" : "2"]; + string s = saa["a"]; + saa["c"] = "3"; + if ("c" in saa) {} + size_t l = saa.length; + foreach(k; saa.keys) {} + foreach(k; saa.byKey) {} + foreach(v; saa.values) {} + foreach(v; saa.byValue) {} + foreach(k, v; saa) {} +} + inout(V) get(K, V)(inout(V[K]) aa, K key, lazy inout(V) defaultValue) { auto p = key in aa; From 6bc34e6d64614e11a9a1dc9661a7c6d6abfb5b15 Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Thu, 6 Oct 2016 03:24:43 -0700 Subject: [PATCH 2/2] Walter's version --- src/object.d | 85 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 57 insertions(+), 28 deletions(-) diff --git a/src/object.d b/src/object.d index c87e7ed31b..5f14858852 100644 --- a/src/object.d +++ b/src/object.d @@ -1923,12 +1923,13 @@ class __cpp_type_info_ptr extern (C) { // from druntime/src/rt/aaA.d + private: // size_t _aaLen(in void* p) pure nothrow @nogc; - private void* _aaGetY(void** paa, const TypeInfo_AssociativeArray ti, in size_t valuesize, in void* pkey) pure nothrow; + void* _aaGetY(void** paa, const TypeInfo_AssociativeArray ti, in size_t valuesize, in void* pkey) pure nothrow; // inout(void)* _aaGetRvalueX(inout void* p, in TypeInfo keyti, in size_t valuesize, in void* pkey); - inout(void)[] _aaValues(inout void* p, in size_t keysize, in size_t valuesize, const TypeInfo tiValArray) pure nothrow; - inout(void)[] _aaKeys(inout void* p, in size_t keysize, const TypeInfo tiKeyArray) pure nothrow; + inout(void)[] _aaValues(inout void* p, in size_t keysize, in size_t valuesize, const TypeInfo tiValArray) pure nothrow @trusted; + inout(void)[] _aaKeys(inout void* p, in size_t keysize, const TypeInfo tiKeyArray) pure nothrow @trusted; void* _aaRehash(void** pp, in TypeInfo keyti) pure nothrow; void _aaClear(void* p) pure nothrow; @@ -1938,10 +1939,10 @@ extern (C) // alias _dg2_t = extern(D) int delegate(void*, void*); // int _aaApply2(void* aa, size_t keysize, _dg2_t dg); - private struct AARange + struct AARange { private: - this(void* impl, size_t idx) { this.impl = impl; this.idx = idx; } + this(void *impl) { this.impl = impl; } void* impl; size_t idx; } @@ -2045,7 +2046,7 @@ V[K] dup(T : V[K], K, V)(T* aa) return (*aa).dup; } -auto byKey(K, V)(const(V[K]) aa) pure nothrow @nogc +auto byKey(T : V[K], K, V)(T aa) pure nothrow @nogc @trusted { import core.internal.traits : substInout; @@ -2055,20 +2056,21 @@ auto byKey(K, V)(const(V[K]) aa) pure nothrow @nogc pure nothrow @nogc @trusted: @property bool empty() { return _aaRangeEmpty(r); } - @property ref front() { return *cast(substInout!K*)_aaRangeFrontKey(r); } - void popFront() { _aaRangePopFront(r); } + @property ref front() { assert(!empty); return *cast(substInout!K*)_aaRangeFrontKey(r); } + void popFront() { assert(!empty); _aaRangePopFront(r); } @property Result save() { return this; } } - return Result(((typeof(aa) aa) @trusted => _aaRange(cast(void*)aa))(aa)); + static assert(!__traits(compiles, __traits(getAliasThis, T)), "cannot have alias this of associative array"); + return Result(_aaRange(cast(void*)aa)); } -auto byKey(T : V[K], K, V)(T* aa) +auto byKey(T : V[K], K, V)(T* aa) pure nothrow @nogc { return (*aa).byKey(); } -auto byValue(K, V)(const(V[K]) aa) pure nothrow @nogc +auto byValue(T : V[K], K, V)(T aa) pure nothrow @nogc @trusted { import core.internal.traits : substInout; @@ -2078,20 +2080,21 @@ auto byValue(K, V)(const(V[K]) aa) pure nothrow @nogc pure nothrow @nogc @trusted: @property bool empty() { return _aaRangeEmpty(r); } - @property ref front() { return *cast(const(V)*)_aaRangeFrontValue(r); } - void popFront() { _aaRangePopFront(r); } + @property ref front() { assert(!empty); return *cast(substInout!V*)_aaRangeFrontValue(r); } + void popFront() { assert(!empty); _aaRangePopFront(r); } @property Result save() { return this; } } - return Result(((typeof(aa) aa) @trusted => _aaRange(cast(void*)aa))(aa)); + static assert(!__traits(compiles, __traits(getAliasThis, T)), "cannot have alias this of associative array"); + return Result(_aaRange(cast(void*)aa)); } -auto byValue(T : V[K], K, V)(T* aa) +auto byValue(T : V[K], K, V)(T* aa) pure nothrow @nogc { return (*aa).byValue(); } -auto byKeyValue(K, V)(const(V[K]) aa) pure nothrow @nogc +auto byKeyValue(T : V[K], K, V)(T aa) pure nothrow @nogc @trusted { import core.internal.traits : substInout; @@ -2120,7 +2123,8 @@ auto byKeyValue(K, V)(const(V[K]) aa) pure nothrow @nogc @property Result save() { return this; } } - return Result(((typeof(aa) aa) @trusted => _aaRange(cast(void*)aa))(aa)); + static assert(!__traits(compiles, __traits(getAliasThis, T)), "cannot have alias this of associative array"); + return Result(_aaRange(cast(void*)aa)); } auto byKeyValue(T : V[K], K, V)(T* aa) pure nothrow @nogc @@ -2128,12 +2132,17 @@ auto byKeyValue(T : V[K], K, V)(T* aa) pure nothrow @nogc return (*aa).byKeyValue(); } -Key[] keys(Value, Key)(Value[Key] aa) @property +Key[] keys(T : Value[Key], Value, Key)(T aa) @property { - auto res = () @trusted { - auto voidRes = _aaKeys(cast(void*)aa, Key.sizeof, typeid(Key[])); - return *cast(Key[]*)&voidRes; - }(); + static assert(!__traits(compiles, __traits(getAliasThis, T)), "cannot have alias this of associative array"); + void* trustedCastVoid(T aa) @trusted { return cast(void*)aa; } + void* p = trustedCastVoid(aa); + + void[] a = _aaKeys(p, Key.sizeof, typeid(Key[])); + + Key[] trustedCastKeyArray(ref void[] a) @trusted { return *cast(Key[]*)&a; } + auto res = trustedCastKeyArray(a); + _doPostblit(res); return res; } @@ -2143,12 +2152,17 @@ Key[] keys(T : Value[Key], Value, Key)(T *aa) @property return (*aa).keys; } -Value[] values(Value, Key)(Value[Key] aa) @property +Value[] values(T : Value[Key], Value, Key)(T aa) @property { - auto res = () @trusted { - auto voidRes = _aaValues(cast(void*)aa, Key.sizeof, Value.sizeof, typeid(Key[])); - return *cast(Value[]*)&voidRes; - }(); + static assert(!__traits(compiles, __traits(getAliasThis, T)), "cannot have alias this of associative array"); + void* trustedCastVoid(T aa) @trusted { return cast(void*)aa; } + void* p = trustedCastVoid(aa); + + auto a = _aaValues(p, Key.sizeof, Value.sizeof, typeid(Value[])); + + Value[] trustedCastValueArray(ref void[] a) @trusted { return *cast(Value[]*)&a; } + auto res = trustedCastValueArray(a); + _doPostblit(res); return res; } @@ -2185,7 +2199,7 @@ unittest assert(T.count == 2); } -@safe pure unittest +@safe unittest { string[string] saa = ["a" : "1", "b" : "2"]; string s = saa["a"]; @@ -2504,6 +2518,21 @@ unittest static assert(is(typeof(caa.byValue().front) == const int)); } +unittest +{ + static struct Foo { + int[int] aa; + auto opCast() pure nothrow @nogc { *cast(uint*)0xdeadbeef = 0xcafebabe; return null; } + alias aa this; + } + + static void test() @safe { + Foo f; + static assert(!__traits(compiles, { int i = !f.byKey.empty; })); + } +} + + private void _destructRecurse(S)(ref S s) if (is(S == struct)) {