Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.

Commit 753239f

Browse files
authored
Merge pull request #2228 from n8sh/hash-nogc
Fix Issue 19009 - core.internal.hash.hashOf default hash (absent `toHash`) should be `@nogc` merged-on-behalf-of: Steven Schveighoffer <schveiguy@users.noreply.github.com>
2 parents 0c92d13 + 4f5b049 commit 753239f

File tree

2 files changed

+64
-32
lines changed

2 files changed

+64
-32
lines changed

src/core/internal/convert.d

Lines changed: 59 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,36 @@
1010
module core.internal.convert;
1111
import core.internal.traits : Unqual;
1212

13-
@trusted pure nothrow
13+
/+
14+
A @nogc function can allocate memory during CTFE.
15+
+/
16+
@nogc nothrow pure @trusted
17+
private ubyte[] ctfe_alloc()(size_t n)
18+
{
19+
if (!__ctfe)
20+
{
21+
assert(0, "CTFE only");
22+
}
23+
else
24+
{
25+
static ubyte[] alloc(size_t x) nothrow pure
26+
{
27+
if (__ctfe) // Needed to prevent _d_newarray from appearing in compiled prorgam.
28+
return new ubyte[x];
29+
else
30+
assert(0);
31+
}
32+
return (cast(ubyte[] function(size_t) @nogc nothrow pure) &alloc)(n);
33+
}
34+
}
35+
36+
@trusted pure nothrow @nogc
1437
const(ubyte)[] toUbyte(T)(ref T val) if(is(Unqual!T == float) || is(Unqual!T == double) || is(Unqual!T == real) ||
1538
is(Unqual!T == ifloat) || is(Unqual!T == idouble) || is(Unqual!T == ireal))
1639
{
1740
static const(ubyte)[] reverse_(const(ubyte)[] arr)
1841
{
19-
ubyte[] buff = new ubyte[arr.length];
42+
ubyte[] buff = ctfe_alloc(arr.length);
2043
foreach(k, v; arr)
2144
{
2245
buff[$-k-1] = v;
@@ -31,7 +54,7 @@ const(ubyte)[] toUbyte(T)(ref T val) if(is(Unqual!T == float) || is(Unqual!T ==
3154
uint exp = parsed.exponent;
3255
uint sign = parsed.sign;
3356

34-
ubyte[T.sizeof] buff;
57+
ubyte[] buff = ctfe_alloc(T.sizeof);
3558
size_t off_bytes = 0;
3659
size_t off_bits = 0;
3760

@@ -60,7 +83,7 @@ const(ubyte)[] toUbyte(T)(ref T val) if(is(Unqual!T == float) || is(Unqual!T ==
6083

6184
version(LittleEndian)
6285
{
63-
return buff.dup;
86+
return buff;
6487
}
6588
else
6689
{
@@ -73,13 +96,13 @@ const(ubyte)[] toUbyte(T)(ref T val) if(is(Unqual!T == float) || is(Unqual!T ==
7396
}
7497
}
7598

76-
@safe pure nothrow
99+
@safe pure nothrow @nogc
77100
private Float parse(bool is_denormalized = false, T)(T x) if(is(Unqual!T == ifloat) || is(Unqual!T == idouble) || is(Unqual!T == ireal))
78101
{
79102
return parse(x.im);
80103
}
81104

82-
@safe pure nothrow
105+
@safe pure nothrow @nogc
83106
private Float parse(bool is_denormalized = false, T:real)(T x_) if(floatFormat!T != FloatFormat.Real80)
84107
{
85108
Unqual!T x = x_;
@@ -116,7 +139,7 @@ private Float parse(bool is_denormalized = false, T:real)(T x_) if(floatFormat!T
116139
return Float(mant, exp, sign);
117140
}
118141

119-
@safe pure nothrow
142+
@safe pure nothrow @nogc
120143
private Float parse(bool _ = false, T:real)(T x_) if(floatFormat!T == FloatFormat.Real80)
121144
{
122145
Unqual!T x = x_;
@@ -228,10 +251,10 @@ private template FloatTraits(T) if(floatFormat!T == FloatFormat.Quadruple) //Uns
228251
}
229252

230253

231-
@safe pure nothrow
254+
@safe pure nothrow @nogc
232255
private real binPow2(int pow)
233256
{
234-
static real binPosPow2(int pow) @safe pure nothrow
257+
static real binPosPow2(int pow) @safe pure nothrow @nogc
235258
{
236259
assert(pow > 0);
237260

@@ -256,13 +279,13 @@ private real binPow2(int pow)
256279

257280

258281
//Need in CTFE, because CTFE float and double expressions computed more precisely that run-time expressions.
259-
@safe pure nothrow
282+
@safe pure nothrow @nogc
260283
private ulong shiftrRound(ulong x)
261284
{
262285
return (x >> 1) + (x & 1);
263286
}
264287

265-
@safe pure nothrow
288+
@safe pure nothrow @nogc
266289
private uint binLog2(T)(T x)
267290
{
268291
assert(x > 0);
@@ -290,7 +313,7 @@ private uint binLog2(T)(T x)
290313
return max;
291314
}
292315

293-
@safe pure nothrow
316+
@safe pure nothrow @nogc
294317
private ulong denormalizedMantissa(T)(T x) if(floatFormat!T == FloatFormat.Real80)
295318
{
296319
x *= 2.0L^^FloatTraits!T.MANTISSA;
@@ -299,7 +322,7 @@ private ulong denormalizedMantissa(T)(T x) if(floatFormat!T == FloatFormat.Real8
299322
return fl.mantissa >> pow;
300323
}
301324

302-
@safe pure nothrow
325+
@safe pure nothrow @nogc
303326
private ulong denormalizedMantissa(T)(T x) if(floatFormat!T != FloatFormat.Real80)
304327
{
305328
x *= 2.0L^^FloatTraits!T.MANTISSA;
@@ -475,21 +498,23 @@ template floatFormat(T) if(is(T:real) || is(T:ireal))
475498
}
476499

477500
// all toUbyte functions must be evaluable at compile time
478-
@trusted pure nothrow
501+
@trusted pure nothrow @nogc
479502
const(ubyte)[] toUbyte(T)(T[] arr) if (T.sizeof == 1)
480503
{
481504
return cast(const(ubyte)[])arr;
482505
}
483506

484-
@trusted pure nothrow
507+
@trusted pure nothrow @nogc
485508
const(ubyte)[] toUbyte(T)(T[] arr) if ((is(typeof(toUbyte(arr[0])) == const(ubyte)[])) && (T.sizeof > 1))
486509
{
487510
if (__ctfe)
488511
{
489-
const(ubyte)[] ret;
512+
ubyte[] ret = ctfe_alloc(T.sizeof * arr.length);
513+
size_t offset = 0;
490514
foreach (cur; arr)
491515
{
492-
ret ~= toUbyte(cur);
516+
ret[offset .. offset + T.sizeof] = toUbyte(cur)[0 .. T.sizeof];
517+
offset += T.sizeof;
493518
}
494519
return ret;
495520
}
@@ -499,14 +524,16 @@ const(ubyte)[] toUbyte(T)(T[] arr) if ((is(typeof(toUbyte(arr[0])) == const(ubyt
499524
}
500525
}
501526

502-
@trusted pure nothrow
527+
@trusted pure nothrow @nogc
503528
const(ubyte)[] toUbyte(T)(ref T val) if (__traits(isIntegral, T) && !is(T == enum))
504529
{
505530
static if (T.sizeof == 1)
506531
{
507532
if (__ctfe)
508533
{
509-
return cast(const(ubyte)[])[val];
534+
ubyte[] result = ctfe_alloc(1);
535+
result[0] = cast(ubyte) val;
536+
return result;
510537
}
511538
else
512539
{
@@ -515,7 +542,7 @@ const(ubyte)[] toUbyte(T)(ref T val) if (__traits(isIntegral, T) && !is(T == enu
515542
}
516543
else if (__ctfe)
517544
{
518-
ubyte[T.sizeof] tmp;
545+
ubyte[] tmp = ctfe_alloc(T.sizeof);
519546
Unqual!T val_ = val;
520547
for (size_t i = 0; i < T.sizeof; ++i)
521548
{
@@ -525,30 +552,35 @@ const(ubyte)[] toUbyte(T)(ref T val) if (__traits(isIntegral, T) && !is(T == enu
525552
tmp[idx] = cast(ubyte)(val_&0xff);
526553
val_ >>= 8;
527554
}
528-
return tmp[].dup;
555+
return tmp;
529556
}
530557
else
531558
{
532559
return (cast(const(ubyte)*)(&val))[0 .. T.sizeof];
533560
}
534561
}
535562

536-
@trusted pure nothrow
563+
@trusted pure nothrow @nogc
537564
const(ubyte)[] toUbyte(T)(ref T val) if (is(Unqual!T == cfloat) || is(Unqual!T == cdouble) ||is(Unqual!T == creal))
538565
{
539566
if (__ctfe)
540567
{
541568
auto re = val.re;
542569
auto im = val.im;
543-
return (re.toUbyte() ~ im.toUbyte());
570+
auto a = re.toUbyte();
571+
auto b = im.toUbyte();
572+
ubyte[] result = ctfe_alloc(a.length + b.length);
573+
result[0 .. a.length] = a[0 .. a.length];
574+
result[a.length .. $] = b[0 .. b.length];
575+
return result;
544576
}
545577
else
546578
{
547579
return (cast(const(ubyte)*)&val)[0 .. T.sizeof];
548580
}
549581
}
550582

551-
@trusted pure nothrow
583+
@trusted pure nothrow @nogc
552584
const(ubyte)[] toUbyte(T)(ref T val) if (is(T == enum) && is(typeof(toUbyte(cast(V)val)) == const(ubyte)[]))
553585
{
554586
if (__ctfe)
@@ -605,12 +637,12 @@ private bool isNonReferenceStruct(T)() if (is(T == struct) || is(T == union))
605637
return true;
606638
}
607639

608-
@trusted pure nothrow
640+
@trusted pure nothrow @nogc
609641
const(ubyte)[] toUbyte(T)(ref T val) if (is(T == struct) || is(T == union))
610642
{
611643
if (__ctfe)
612644
{
613-
ubyte[T.sizeof] bytes;
645+
ubyte[] bytes = ctfe_alloc(T.sizeof);
614646
foreach (key, cur; val.tupleof)
615647
{
616648
alias CUR_TYPE = typeof(cur);
@@ -629,7 +661,7 @@ const(ubyte)[] toUbyte(T)(ref T val) if (is(T == struct) || is(T == union))
629661
assert(0, "Unable to compute byte representation of "~typeof(CUR_TYPE).stringof~" field at compile time");
630662
}
631663
}
632-
return bytes[].dup;
664+
return bytes;
633665
}
634666
else
635667
{

src/core/internal/hash.d

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,14 +72,14 @@ if (!is(T == enum) && !is(T : typeof(null)) && is(T S: S[]) && !__traits(isStati
7272
const _ = hashOf("abc");
7373
}
7474

75-
nothrow pure @system unittest
75+
@nogc nothrow pure @system unittest
7676
{
7777
void*[] val;
7878
const _ = hashOf(val); // Check a PR doesn't break this.
7979
}
8080

8181
//arithmetic type hash
82-
@trusted nothrow pure
82+
@trusted @nogc nothrow pure
8383
size_t hashOf(T)(auto ref T val, size_t seed = 0) if (!is(T == enum) && __traits(isArithmetic, T))
8484
{
8585
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
9494
}
9595

9696
//typeof(null) hash. CTFE supported
97-
@trusted nothrow pure
97+
@trusted @nogc nothrow pure
9898
size_t hashOf(T)(auto ref T val, size_t seed = 0) if (!is(T == enum) && is(T : typeof(null)))
9999
{
100100
return hashOf(cast(void*)null, seed);
101101
}
102102

103103
//Pointers hash. CTFE unsupported if not null
104-
@trusted nothrow pure
104+
@trusted @nogc nothrow pure
105105
size_t hashOf(T)(auto ref T val, size_t seed = 0)
106106
if (!is(T == enum) && is(T V : V*) && !is(T : typeof(null))
107107
&& !is(T == struct) && !is(T == class) && !is(T == union))
@@ -155,7 +155,7 @@ nothrow pure @safe unittest // issue 18925
155155
}
156156

157157
//delegate hash. CTFE unsupported
158-
@trusted nothrow pure
158+
@trusted @nogc nothrow pure
159159
size_t hashOf(T)(auto ref T val, size_t seed = 0) if (!is(T == enum) && is(T == delegate))
160160
{
161161
assert(!__ctfe, "unable to compute hash of "~T.stringof);

0 commit comments

Comments
 (0)