From 4f5b049559d69c9c696c6534302ecbcff30126d5 Mon Sep 17 00:00:00 2001 From: Nathan Sashihara <21227491+n8sh@users.noreply.github.com> Date: Wed, 20 Jun 2018 12:29:06 -0400 Subject: [PATCH] Fix Issue 19009 - core.internal.hash.hashOf default hash (absent `toHash`) should be `@nogc` --- src/core/internal/convert.d | 86 +++++++++++++++++++++++++------------ src/core/internal/hash.d | 10 ++--- 2 files changed, 64 insertions(+), 32 deletions(-) diff --git a/src/core/internal/convert.d b/src/core/internal/convert.d index 0d35e0523ae..d19deaadc95 100644 --- a/src/core/internal/convert.d +++ b/src/core/internal/convert.d @@ -10,13 +10,36 @@ module core.internal.convert; import core.internal.traits : Unqual; -@trusted pure nothrow +/+ +A @nogc function can allocate memory during CTFE. ++/ +@nogc nothrow pure @trusted +private ubyte[] ctfe_alloc()(size_t n) +{ + if (!__ctfe) + { + assert(0, "CTFE only"); + } + else + { + static ubyte[] alloc(size_t x) nothrow pure + { + if (__ctfe) // Needed to prevent _d_newarray from appearing in compiled prorgam. + return new ubyte[x]; + else + assert(0); + } + return (cast(ubyte[] function(size_t) @nogc nothrow pure) &alloc)(n); + } +} + +@trusted pure nothrow @nogc const(ubyte)[] toUbyte(T)(ref T val) if(is(Unqual!T == float) || is(Unqual!T == double) || is(Unqual!T == real) || is(Unqual!T == ifloat) || is(Unqual!T == idouble) || is(Unqual!T == ireal)) { static const(ubyte)[] reverse_(const(ubyte)[] arr) { - ubyte[] buff = new ubyte[arr.length]; + ubyte[] buff = ctfe_alloc(arr.length); foreach(k, v; arr) { buff[$-k-1] = v; @@ -31,7 +54,7 @@ const(ubyte)[] toUbyte(T)(ref T val) if(is(Unqual!T == float) || is(Unqual!T == uint exp = parsed.exponent; uint sign = parsed.sign; - ubyte[T.sizeof] buff; + ubyte[] buff = ctfe_alloc(T.sizeof); size_t off_bytes = 0; size_t off_bits = 0; @@ -60,7 +83,7 @@ const(ubyte)[] toUbyte(T)(ref T val) if(is(Unqual!T == float) || is(Unqual!T == version(LittleEndian) { - return buff.dup; + return buff; } else { @@ -73,13 +96,13 @@ const(ubyte)[] toUbyte(T)(ref T val) if(is(Unqual!T == float) || is(Unqual!T == } } -@safe pure nothrow +@safe pure nothrow @nogc private Float parse(bool is_denormalized = false, T)(T x) if(is(Unqual!T == ifloat) || is(Unqual!T == idouble) || is(Unqual!T == ireal)) { return parse(x.im); } -@safe pure nothrow +@safe pure nothrow @nogc private Float parse(bool is_denormalized = false, T:real)(T x_) if(floatFormat!T != FloatFormat.Real80) { Unqual!T x = x_; @@ -116,7 +139,7 @@ private Float parse(bool is_denormalized = false, T:real)(T x_) if(floatFormat!T return Float(mant, exp, sign); } -@safe pure nothrow +@safe pure nothrow @nogc private Float parse(bool _ = false, T:real)(T x_) if(floatFormat!T == FloatFormat.Real80) { Unqual!T x = x_; @@ -228,10 +251,10 @@ private template FloatTraits(T) if(floatFormat!T == FloatFormat.Quadruple) //Uns } -@safe pure nothrow +@safe pure nothrow @nogc private real binPow2(int pow) { - static real binPosPow2(int pow) @safe pure nothrow + static real binPosPow2(int pow) @safe pure nothrow @nogc { assert(pow > 0); @@ -256,13 +279,13 @@ private real binPow2(int pow) //Need in CTFE, because CTFE float and double expressions computed more precisely that run-time expressions. -@safe pure nothrow +@safe pure nothrow @nogc private ulong shiftrRound(ulong x) { return (x >> 1) + (x & 1); } -@safe pure nothrow +@safe pure nothrow @nogc private uint binLog2(T)(T x) { assert(x > 0); @@ -290,7 +313,7 @@ private uint binLog2(T)(T x) return max; } -@safe pure nothrow +@safe pure nothrow @nogc private ulong denormalizedMantissa(T)(T x) if(floatFormat!T == FloatFormat.Real80) { x *= 2.0L^^FloatTraits!T.MANTISSA; @@ -299,7 +322,7 @@ private ulong denormalizedMantissa(T)(T x) if(floatFormat!T == FloatFormat.Real8 return fl.mantissa >> pow; } -@safe pure nothrow +@safe pure nothrow @nogc private ulong denormalizedMantissa(T)(T x) if(floatFormat!T != FloatFormat.Real80) { x *= 2.0L^^FloatTraits!T.MANTISSA; @@ -475,21 +498,23 @@ template floatFormat(T) if(is(T:real) || is(T:ireal)) } // all toUbyte functions must be evaluable at compile time -@trusted pure nothrow +@trusted pure nothrow @nogc const(ubyte)[] toUbyte(T)(T[] arr) if (T.sizeof == 1) { return cast(const(ubyte)[])arr; } -@trusted pure nothrow +@trusted pure nothrow @nogc const(ubyte)[] toUbyte(T)(T[] arr) if ((is(typeof(toUbyte(arr[0])) == const(ubyte)[])) && (T.sizeof > 1)) { if (__ctfe) { - const(ubyte)[] ret; + ubyte[] ret = ctfe_alloc(T.sizeof * arr.length); + size_t offset = 0; foreach (cur; arr) { - ret ~= toUbyte(cur); + ret[offset .. offset + T.sizeof] = toUbyte(cur)[0 .. T.sizeof]; + offset += T.sizeof; } return ret; } @@ -499,14 +524,16 @@ const(ubyte)[] toUbyte(T)(T[] arr) if ((is(typeof(toUbyte(arr[0])) == const(ubyt } } -@trusted pure nothrow +@trusted pure nothrow @nogc const(ubyte)[] toUbyte(T)(ref T val) if (__traits(isIntegral, T) && !is(T == enum)) { static if (T.sizeof == 1) { if (__ctfe) { - return cast(const(ubyte)[])[val]; + ubyte[] result = ctfe_alloc(1); + result[0] = cast(ubyte) val; + return result; } else { @@ -515,7 +542,7 @@ const(ubyte)[] toUbyte(T)(ref T val) if (__traits(isIntegral, T) && !is(T == enu } else if (__ctfe) { - ubyte[T.sizeof] tmp; + ubyte[] tmp = ctfe_alloc(T.sizeof); Unqual!T val_ = val; for (size_t i = 0; i < T.sizeof; ++i) { @@ -525,7 +552,7 @@ const(ubyte)[] toUbyte(T)(ref T val) if (__traits(isIntegral, T) && !is(T == enu tmp[idx] = cast(ubyte)(val_&0xff); val_ >>= 8; } - return tmp[].dup; + return tmp; } else { @@ -533,14 +560,19 @@ const(ubyte)[] toUbyte(T)(ref T val) if (__traits(isIntegral, T) && !is(T == enu } } -@trusted pure nothrow +@trusted pure nothrow @nogc const(ubyte)[] toUbyte(T)(ref T val) if (is(Unqual!T == cfloat) || is(Unqual!T == cdouble) ||is(Unqual!T == creal)) { if (__ctfe) { auto re = val.re; auto im = val.im; - return (re.toUbyte() ~ im.toUbyte()); + auto a = re.toUbyte(); + auto b = im.toUbyte(); + ubyte[] result = ctfe_alloc(a.length + b.length); + result[0 .. a.length] = a[0 .. a.length]; + result[a.length .. $] = b[0 .. b.length]; + return result; } else { @@ -548,7 +580,7 @@ const(ubyte)[] toUbyte(T)(ref T val) if (is(Unqual!T == cfloat) || is(Unqual!T = } } -@trusted pure nothrow +@trusted pure nothrow @nogc const(ubyte)[] toUbyte(T)(ref T val) if (is(T == enum) && is(typeof(toUbyte(cast(V)val)) == const(ubyte)[])) { if (__ctfe) @@ -605,12 +637,12 @@ private bool isNonReferenceStruct(T)() if (is(T == struct) || is(T == union)) return true; } -@trusted pure nothrow +@trusted pure nothrow @nogc const(ubyte)[] toUbyte(T)(ref T val) if (is(T == struct) || is(T == union)) { if (__ctfe) { - ubyte[T.sizeof] bytes; + ubyte[] bytes = ctfe_alloc(T.sizeof); foreach (key, cur; val.tupleof) { alias CUR_TYPE = typeof(cur); @@ -629,7 +661,7 @@ const(ubyte)[] toUbyte(T)(ref T val) if (is(T == struct) || is(T == union)) assert(0, "Unable to compute byte representation of "~typeof(CUR_TYPE).stringof~" field at compile time"); } } - return bytes[].dup; + return bytes; } else { diff --git a/src/core/internal/hash.d b/src/core/internal/hash.d index fb360ee2430..4a71038b81f 100644 --- a/src/core/internal/hash.d +++ b/src/core/internal/hash.d @@ -72,14 +72,14 @@ if (!is(T == enum) && !is(T : typeof(null)) && is(T S: S[]) && !__traits(isStati const _ = hashOf("abc"); } -nothrow pure @system unittest +@nogc nothrow pure @system unittest { void*[] val; const _ = hashOf(val); // Check a PR doesn't break this. } //arithmetic type hash -@trusted nothrow pure +@trusted @nogc nothrow pure size_t hashOf(T)(auto ref T val, size_t seed = 0) if (!is(T == enum) && __traits(isArithmetic, T)) { static if(__traits(isFloating, val)) @@ -94,14 +94,14 @@ size_t hashOf(T)(auto ref T val, size_t seed = 0) if (!is(T == enum) && __traits } //typeof(null) hash. CTFE supported -@trusted nothrow pure +@trusted @nogc nothrow pure size_t hashOf(T)(auto ref T val, size_t seed = 0) if (!is(T == enum) && is(T : typeof(null))) { return hashOf(cast(void*)null, seed); } //Pointers hash. CTFE unsupported if not null -@trusted nothrow pure +@trusted @nogc nothrow pure size_t hashOf(T)(auto ref T val, size_t seed = 0) if (!is(T == enum) && is(T V : V*) && !is(T : typeof(null)) && !is(T == struct) && !is(T == class) && !is(T == union)) @@ -155,7 +155,7 @@ nothrow pure @safe unittest // issue 18925 } //delegate hash. CTFE unsupported -@trusted nothrow pure +@trusted @nogc nothrow pure size_t hashOf(T)(auto ref T val, size_t seed = 0) if (!is(T == enum) && is(T == delegate)) { assert(!__ctfe, "unable to compute hash of "~T.stringof);