// { 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); }