| // { dg-prune-output "Warning: struct HasNonConstToHash has method toHash" } |
| // { dg-prune-output "HasNonConstToHash.toHash defined here:" } |
| void main() |
| { |
| issue19562(); |
| issue15111(); |
| issues16654And16764(); |
| issue18918(); |
| issue18925(); |
| issue19005(); |
| issue19204(); |
| issue19262(); |
| issue19282(); |
| issue19332(); // Support might be removed in the future! |
| issue19568(); |
| issue19582(); |
| issue20034(); |
| issue21642(); |
| issue22024(); |
| issue22076(); |
| testTypeInfoArrayGetHash1(); |
| testTypeInfoArrayGetHash2(); |
| pr2243(); |
| } |
| |
| /// Check hashOf an array of void pointers or delegates is @safe. |
| void issue19562() @nogc nothrow pure @safe |
| { |
| void*[10] val; |
| size_t h = hashOf(val[]); |
| |
| alias D = void delegate(); |
| D[10] ds; |
| h = hashOf(ds[]); |
| } |
| |
| /// hashOf was failing for structs that had an `alias this` to a dynamic array. |
| void issue15111() |
| { |
| void testAlias(T)() |
| { |
| static struct Foo |
| { |
| T t; |
| alias t this; |
| } |
| Foo foo; |
| static assert(is(typeof(hashOf(foo)))); |
| } |
| // was fixed |
| testAlias!(int[]); |
| testAlias!(int*); |
| // was not affected |
| testAlias!int; |
| testAlias!(void delegate()); |
| testAlias!(string[string]); |
| testAlias!(int[8]); |
| } |
| |
| void issues16654And16764() |
| { |
| auto a = [1]; |
| auto b = a.dup; |
| assert(hashOf(a) == hashOf(b)); |
| } |
| |
| /// Check hashOf dynamic array of scalars is usable in @safe code. |
| void issue18918() nothrow pure @safe |
| { |
| const _ = (() @nogc => hashOf("abc"))(); |
| |
| static struct S { string array; } |
| auto s1 = S("abc"); |
| auto s2 = S(s1.array.idup); |
| assert(hashOf(s1) == hashOf(s2)); |
| enum e = hashOf(S("abc")); |
| assert(hashOf(s1) == e); |
| } |
| |
| /// Check hashOf struct of scalar fields is usable in @safe code. |
| void issue18925() @nogc nothrow pure @safe |
| { |
| |
| static struct S { int a; int b; } |
| auto h = hashOf(S.init); |
| } |
| |
| void issue19005() @nogc nothrow pure @safe |
| { |
| enum Month : ubyte |
| { |
| jan = 1 |
| } |
| static struct Date |
| { |
| short _year; |
| Month _month; |
| ubyte _day; |
| } |
| Date date; |
| auto hash = date.hashOf; |
| } |
| |
| /// Accept SIMD vectors. |
| void issue19204() @nogc nothrow pure @safe |
| { |
| version (D_SIMD) |
| { |
| static import simd = core.simd; |
| static if (is(simd.int4)) // __traits(isArithmetic) |
| {{ |
| enum simd.int4 val = [1,2,3,4]; |
| enum ctfeHash = hashOf(val); |
| simd.int4 rtVal = val; |
| auto rtHash = hashOf(rtVal); |
| assert(ctfeHash == rtHash); |
| }} |
| static if (is(simd.void16)) // non __traits(isArithmetic) |
| {{ |
| auto h = hashOf(simd.void16.init); |
| }} |
| static if (is(simd.float4)) // __traits(isArithmetic) and __traits(isFloating) |
| {{ |
| enum simd.float4 val = [1.1f, 2.2f, 3.3f, 4.4f]; |
| enum ctfeHash = hashOf(val); |
| simd.float4 rtVal = val; |
| auto rtHash = hashOf(rtVal); |
| assert(ctfeHash == rtHash); |
| }} |
| } |
| } |
| |
| /// hashOf associative array should infer nothrow |
| void issue19262() nothrow |
| { |
| int[int] aa; |
| auto h = hashOf(aa); |
| h = hashOf(aa, h); |
| } |
| |
| extern(C++) class Issue19282CppClass {} |
| |
| /// test that hashOf doesn't crash for non-null C++ objects. |
| void issue19282() |
| { |
| Issue19282CppClass c = new Issue19282CppClass(); |
| size_t h = hashOf(c); |
| h = hashOf(c, h); |
| } |
| |
| /// Ensure hashOf works for const struct that has non-const toHash & has all |
| /// fields bitwise-hashable. (Support might be removed in the future!) |
| void issue19332() |
| { |
| static struct HasNonConstToHash |
| { |
| int a; |
| size_t toHash() { return a; } |
| } |
| const HasNonConstToHash val; |
| size_t h = hashOf(val); |
| h = hashOf!(const HasNonConstToHash)(val); // Ensure doesn't match more than one overload. |
| } |
| |
| /// hashOf should not unnecessarily call a struct's fields' postblits & dtors in CTFE |
| void issue19568() |
| { |
| static struct S1 |
| { |
| @disable this(this); |
| |
| ~this() @nogc nothrow |
| { |
| import core.stdc.stdio; |
| if (mptr) puts("impure"); |
| } |
| |
| size_t[2] pad; |
| void* mptr; |
| } |
| |
| static struct S2 |
| { |
| @disable this(this); |
| |
| ~this() @nogc nothrow |
| { |
| import core.stdc.stdio; |
| if (fd != -1) puts("impure"); |
| } |
| |
| int fd = -1; |
| S1 s1; |
| } |
| |
| static struct S3 |
| { |
| private S2 s2; |
| } |
| |
| S3 s3; |
| size_t h = ((ref S3 s3) pure => hashOf(s3))(s3); |
| } |
| |
| /// Check core.internal.convert.toUbyte in CTFE for arrays works with |
| /// reference type elements and doesn't call postblits/dtors. |
| void issue19582() |
| { |
| import core.internal.convert : toUbyte; |
| final static class C : Object {} |
| enum b1 = (() @nogc nothrow pure @safe { C[10] o; return toUbyte(o[])[0]; })(); |
| |
| static struct S |
| { |
| int x; |
| @disable this(this); |
| ~this() @nogc nothrow |
| { |
| import core.stdc.stdio : puts; |
| if (x) puts("impure"); |
| } |
| } |
| enum b2 = () { |
| return ((const S[] a) @nogc nothrow pure @safe => toUbyte(a))(new S[10]); |
| }(); |
| } |
| |
| /// Check core.internal.hash.hashOf works with enums of non-scalar values |
| void issue20034() |
| { |
| enum E |
| { |
| a = "foo" |
| } |
| // should compile |
| assert(hashOf(E.a, 1)); |
| } |
| |
| /// [REG 2.084] hashOf will fail to compile for some structs/unions that recursively contain shared enums |
| void issue21642() @safe nothrow pure |
| { |
| enum C : char { _ = 1, } |
| union U { C c; void[0] _; } |
| shared union V { U u; } |
| cast(void) hashOf(V.init); |
| // Also test the underlying reason the above was failing. |
| import core.internal.convert : toUbyte; |
| shared C c; |
| assert(toUbyte(c) == [ubyte(1)]); |
| } |
| |
| /// Accept enum type whose ultimate base type is a SIMD vector. |
| void issue22024() @nogc nothrow pure @safe |
| { |
| static if (is(__vector(float[2]))) |
| { |
| enum E2 : __vector(float[2]) { a = __vector(float[2]).init, } |
| enum F2 : E2 { a = E2.init, } |
| assert(hashOf(E2.init) == hashOf(F2.init)); |
| assert(hashOf(E2.init, 1) == hashOf(F2.init, 1)); |
| } |
| static if (is(__vector(float[4]))) |
| { |
| enum E4 : __vector(float[4]) { a = __vector(float[4]).init, } |
| enum F4 : E4 { a = E4.init, } |
| assert(hashOf(E4.init) == hashOf(F4.init)); |
| assert(hashOf(E4.init, 1) == hashOf(F4.init, 1)); |
| } |
| } |
| |
| /// hashOf(S) can segfault if S.toHash is forwarded via `alias this` to a |
| /// receiver which may be null. |
| void issue22076() |
| { |
| static struct S0 { Object a; alias a this; } |
| |
| static struct S1 |
| { |
| S0 a; |
| inout(S0)* b() inout return nothrow { return &a; } |
| alias b this; |
| } |
| |
| static struct S2 |
| { |
| S0 a; |
| S1 b; |
| } |
| |
| extern(C++) static class C0 |
| { |
| int foo() { return 0; } // Need at least one function in vtable. |
| S0 a; alias a this; |
| } |
| |
| extern(C++) static class C1 |
| { |
| S1 a; |
| inout(S1)* b() inout nothrow { return &a; } |
| alias b this; |
| } |
| |
| cast(void) hashOf(S0.init); |
| cast(void) hashOf(S0.init, 0); |
| cast(void) hashOf(S1.init); |
| cast(void) hashOf(S1.init, 0); |
| cast(void) hashOf(S2.init); |
| cast(void) hashOf(S2.init, 0); |
| auto c0 = new C0(); |
| cast(void) hashOf(c0); |
| cast(void) hashOf(c0, 0); |
| auto c1 = new C1(); |
| cast(void) hashOf(c1); |
| cast(void) hashOf(c1, 0); |
| } |
| |
| /// Tests ensure TypeInfo_Array.getHash uses element hash functions instead |
| /// of hashing array data. |
| void testTypeInfoArrayGetHash1() |
| { |
| class C |
| { |
| int i; |
| this(in int i) { this.i = i; } |
| override hash_t toHash() { return 0; } |
| } |
| C[] a1 = [new C(11)], a2 = [new C(12)]; |
| assert(typeid(C[]).getHash(&a1) == typeid(C[]).getHash(&a2)); |
| } |
| |
| /// ditto |
| void testTypeInfoArrayGetHash2() |
| { |
| struct S |
| { |
| int i; |
| hash_t toHash() const @safe nothrow { return 0; } |
| } |
| S[] a1 = [S(11)], a2 = [S(12)]; |
| assert(typeid(S[]).getHash(&a1) == typeid(S[]).getHash(&a2)); |
| } |
| |
| /++ |
| Use the new `core.internal.hash.hashOf` in all `TypeInfo.getHash` instead of |
| the `old rt.util.hash.hashOf`. Also make `typeid(T).getHash(&val)` get the |
| same result as `hashOf(val)`. |
| +/ |
| void pr2243() |
| { |
| static struct Foo |
| { |
| int a = 99; |
| float b = 4.0; |
| size_t toHash() const pure @safe nothrow |
| { |
| return a; |
| } |
| } |
| |
| static struct Bar |
| { |
| char c = 'x'; |
| int a = 99; |
| float b = 4.0; |
| void* d = null; |
| } |
| |
| static struct Boom |
| { |
| char c = 'M'; |
| int* a = null; |
| } |
| |
| static struct Plain |
| { |
| int a = 1; |
| int b = 2; |
| } |
| |
| interface IBoo |
| { |
| void boo(); |
| } |
| |
| static class Boo: IBoo |
| { |
| override void boo() |
| { |
| } |
| |
| override size_t toHash() |
| { |
| return 1; |
| } |
| } |
| |
| static struct Goo |
| { |
| size_t toHash() pure @safe nothrow |
| { |
| return 1; |
| } |
| } |
| |
| enum Gun: long |
| { |
| A = 99, |
| B = 17 |
| } |
| |
| enum double dexpr = 3.14; |
| enum float fexpr = 2.71; |
| enum wstring wsexpr = "abcdef"w; |
| enum string csexpr = "abcdef"; |
| enum int iexpr = 7; |
| enum long lexpr = 42; |
| enum int[2][3] saexpr = [[1, 2], [3, 4], [5, 6]]; |
| enum int[] daexpr = [7,8,9]; |
| enum Foo thsexpr = Foo(); |
| enum Bar vsexpr = Bar(); |
| enum int[int] aaexpr = [99:2, 12:6, 45:4]; |
| enum Gun eexpr = Gun.A; |
| enum Foo[] staexpr = [Foo(), Foo(), Foo()]; |
| enum Bar[] vsaexpr = [Bar(), Bar(), Bar()]; |
| enum realexpr = 7.88; |
| enum nullexpr = null; |
| enum plstr = Plain(); |
| enum plarrstr = [Plain(), Plain(), Plain()]; |
| //No CTFE: |
| Boom rstructexpr = Boom(); |
| Boom[] rstrarrexpr = [Boom(), Boom(), Boom()]; |
| int delegate() dgexpr = (){return 78;}; |
| void* ptrexpr = &dgexpr; |
| |
| |
| //CTFE hashes |
| enum h1 = dexpr.hashOf(); |
| enum h2 = fexpr.hashOf(); |
| enum h3 = wsexpr.hashOf(); |
| enum h4 = csexpr.hashOf(); |
| enum h5 = iexpr.hashOf(); |
| enum h6 = lexpr.hashOf(); |
| enum h7 = saexpr.hashOf(); |
| enum h8 = daexpr.hashOf(); |
| enum h9 = thsexpr.hashOf(); |
| enum h10 = vsexpr.hashOf(); |
| enum h11 = aaexpr.hashOf(); |
| enum h12 = eexpr.hashOf(); |
| enum h14 = hashOf(new Boo); |
| enum h15 = staexpr.hashOf(); |
| enum h16 = hashOf([new Boo, new Boo, new Boo]); |
| enum h17 = hashOf([cast(IBoo)new Boo, cast(IBoo)new Boo, cast(IBoo)new Boo]); |
| enum h18 = hashOf(cast(IBoo)new Boo); |
| enum h19 = vsaexpr.hashOf(); |
| enum h20 = hashOf(cast(Foo[3])staexpr); |
| |
| //BUG: cannot cast [Boo(), Boo(), Boo()][0] to object.Object at compile time |
| auto h21 = hashOf(cast(Boo[3])[new Boo, new Boo, new Boo]); |
| auto h22 = hashOf(cast(IBoo[3])[cast(IBoo)new Boo, cast(IBoo)new Boo, cast(IBoo)new Boo]); |
| enum h23 = hashOf(cast(Bar[3])vsaexpr); |
| |
| //NO CTFE (Compute, but don't check correctness): |
| auto h24 = rstructexpr.hashOf(); |
| auto h25 = rstrarrexpr.hashOf(); |
| auto h26 = dgexpr.hashOf(); |
| auto h27 = ptrexpr.hashOf(); |
| |
| enum h28 = realexpr.hashOf(); |
| enum h30 = nullexpr.hashOf(); |
| enum h31 = plstr.hashOf(); |
| enum h32 = plarrstr.hashOf(); |
| enum h33 = hashOf(cast(Plain[3])plarrstr); |
| |
| auto v1 = dexpr; |
| auto v2 = fexpr; |
| auto v3 = wsexpr; |
| auto v4 = csexpr; |
| auto v5 = iexpr; |
| auto v6 = lexpr; |
| auto v7 = saexpr; |
| auto v8 = daexpr; |
| auto v9 = thsexpr; |
| auto v10 = vsexpr; |
| auto v11 = aaexpr; |
| auto v12 = eexpr; |
| auto v14 = new Boo; |
| auto v15 = staexpr; |
| auto v16 = [new Boo, new Boo, new Boo]; |
| auto v17 = [cast(IBoo)new Boo, cast(IBoo)new Boo, cast(IBoo)new Boo]; |
| auto v18 = cast(IBoo)new Boo; |
| auto v19 = vsaexpr; |
| auto v20 = cast(Foo[3])staexpr; |
| auto v21 = cast(Boo[3])[new Boo, new Boo, new Boo]; |
| auto v22 = cast(IBoo[3])[cast(IBoo)new Boo, cast(IBoo)new Boo, cast(IBoo)new Boo]; |
| auto v23 = cast(Bar[3])vsaexpr; |
| auto v30 = null; |
| auto v31 = plstr; |
| auto v32 = plarrstr; |
| auto v33 = cast(Plain[3])plarrstr; |
| |
| //NO CTFE: |
| auto v24 = rstructexpr; |
| auto v25 = rstrarrexpr; |
| auto v26 = dgexpr; |
| auto v27 = ptrexpr; |
| auto v28 = realexpr; |
| |
| //runtime hashes |
| auto rth1 = hashOf(v1); |
| auto rth2 = hashOf(v2); |
| auto rth3 = hashOf(v3); |
| auto rth4 = hashOf(v4); |
| auto rth5 = hashOf(v5); |
| auto rth6 = hashOf(v6); |
| auto rth7 = hashOf(v7); |
| auto rth8 = hashOf(v8); |
| auto rth9 = hashOf(v9); |
| auto rth10 = hashOf(v10); |
| auto rth11 = hashOf(v11); |
| auto rth12 = hashOf(v12); |
| auto rth14 = hashOf(v14); |
| auto rth15 = hashOf(v15); |
| auto rth16 = hashOf(v16); |
| auto rth17 = hashOf(v17); |
| auto rth18 = hashOf(v18); |
| auto rth19 = hashOf(v19); |
| auto rth20 = hashOf(v20); |
| auto rth21 = hashOf(v21); |
| auto rth22 = hashOf(v22); |
| auto rth23 = hashOf(v23); |
| auto rth30 = hashOf(v30); |
| //NO CTFE: |
| auto rth24 = hashOf(v24); |
| auto rth25 = hashOf(v25); |
| auto rth26 = hashOf(v26); |
| auto rth27 = hashOf(v27); |
| auto rth28 = hashOf(v28); |
| |
| auto rth31 = hashOf(v31); |
| auto rth32 = hashOf(v32); |
| auto rth33 = hashOf(v33); |
| |
| assert(h1 == rth1); |
| assert(h2 == rth2); |
| assert(h3 == rth3); |
| assert(h4 == rth4); |
| assert(h5 == rth5); |
| assert(h6 == rth6); |
| assert(h7 == rth7); |
| assert(h8 == rth8); |
| assert(h9 == rth9); |
| assert(h10 == rth10); |
| assert(h11 == rth11); |
| assert(h12 == rth12); |
| assert(h14 == rth14); |
| assert(h15 == rth15); |
| assert(h16 == rth16); |
| assert(h17 == rth17); |
| assert(h18 == rth18); |
| assert(h19 == rth19); |
| assert(h20 == rth20); |
| assert(h21 == rth21); |
| assert(h22 == rth22); |
| assert(h23 == rth23); |
| /*assert(h24 == rth24); |
| assert(h25 == rth25); |
| assert(h26 == rth26); |
| assert(h27 == rth27); |
| assert(h28 == rth28);*/ |
| assert(h30 == rth30); |
| assert(h31 == rth31); |
| assert(h32 == rth32); |
| assert(h33 == rth33); |
| |
| // https://issues.dlang.org/show_bug.cgi?id=18932 |
| assert(hashOf(null, 0) != hashOf(null, 123456789)); |
| |
| static size_t tiHashOf(T)(T var) |
| { |
| return typeid(T).getHash(&var); |
| } |
| |
| auto tih1 = tiHashOf(v1); |
| auto tih2 = tiHashOf(v2); |
| auto tih3 = tiHashOf(v3); |
| auto tih4 = tiHashOf(v4); |
| auto tih5 = tiHashOf(v5); |
| auto tih6 = tiHashOf(v6); |
| auto tih7 = tiHashOf(v7); |
| auto tih8 = tiHashOf(v8); |
| auto tih9 = tiHashOf(v9); |
| auto tih10 = tiHashOf(v10); |
| auto tih11 = tiHashOf(v11); |
| auto tih12 = tiHashOf(v12); |
| auto tih14 = tiHashOf(v14); |
| auto tih15 = tiHashOf(v15); |
| auto tih16 = tiHashOf(v16); |
| auto tih17 = tiHashOf(v17); |
| auto tih18 = tiHashOf(v18); |
| auto tih19 = tiHashOf(v19); |
| auto tih20 = tiHashOf(v20); |
| auto tih21 = tiHashOf(v21); |
| auto tih22 = tiHashOf(v22); |
| auto tih23 = tiHashOf(v23); |
| auto tih24 = tiHashOf(v24); |
| auto tih25 = tiHashOf(v25); |
| auto tih26 = tiHashOf(v26); |
| auto tih27 = tiHashOf(v27); |
| auto tih28 = tiHashOf(v28); |
| auto tih30 = tiHashOf(v30); |
| auto tih31 = tiHashOf(v31); |
| auto tih32 = tiHashOf(v32); |
| auto tih33 = tiHashOf(v33); |
| |
| assert(tih1 == rth1); |
| assert(tih2 == rth2); |
| assert(tih3 == rth3); |
| assert(tih4 == rth4); |
| assert(tih5 == rth5); |
| assert(tih6 == rth6); |
| assert(tih7 == rth7); |
| assert(tih8 == rth8); |
| assert(tih9 == rth9); |
| //assert(tih10 == rth10); // need compiler-generated __xtoHash changes |
| assert(tih11 == rth11); |
| assert(tih12 == rth12); |
| assert(tih14 == rth14); |
| assert(tih15 == rth15); |
| assert(tih16 == rth16); |
| assert(tih17 == rth17); |
| assert(tih18 == rth18); |
| //assert(tih19 == rth19); // need compiler-generated __xtoHash changes |
| assert(tih20 == rth20); |
| assert(tih21 == rth21); |
| assert(tih22 == rth22); |
| //assert(tih23 == rth23); // need compiler-generated __xtoHash changes |
| //assert(tih24 == rth24); |
| //assert(tih25 == rth25); |
| assert(tih26 == rth26); |
| assert(tih27 == rth27); |
| assert(tih28 == rth28); |
| assert(tih30 == rth30); |
| assert(tih31 == rth31); |
| assert(tih32 == rth32); |
| assert(tih33 == rth33); |
| } |