diff --git a/posix.mak b/posix.mak index 908786806..0df2b8fc7 100644 --- a/posix.mak +++ b/posix.mak @@ -154,6 +154,10 @@ ifdef NO_AUTODECODE override DFLAGS += -version=NoAutodecodeStrings endif +ifdef NO_AUTODECODE +override DFLAGS += -version=NoAutodecodeStrings +endif + UDFLAGS=-unittest -version=StdUnittest # Set DOTOBJ and DOTEXE diff --git a/std/algorithm/sorting.d b/std/algorithm/sorting.d index edcd52149..ed8345b05 100644 --- a/std/algorithm/sorting.d +++ b/std/algorithm/sorting.d @@ -3059,18 +3059,25 @@ if (isRandomAccessRange!R && hasLength!R && hasSwappableElements!R && static if (is(typeof(unaryFun!transform(r.front)))) { alias transformFun = unaryFun!transform; - alias T = typeof(transformFun(r.front)); + alias TB = typeof(transformFun(r.front)); enum isBinary = false; } else static if (is(typeof(binaryFun!transform(r.front, 0)))) { alias transformFun = binaryFun!transform; - alias T = typeof(transformFun(r.front, 0)); + alias TB = typeof(transformFun(r.front, 0)); enum isBinary = true; } else static assert(false, "unsupported `transform` alias"); + // The `transform` function might return a qualified type, e.g. const(int). + // Strip qualifiers if possible s.t. the temporary array is sortable. + static if (is(TB : Unqual!TB)) + alias T = Unqual!TB; + else + static assert(false, "`transform` returns an unsortable qualified type: " ~ TB.stringof); + static trustedMalloc(size_t len) @trusted { import core.checkedint : mulu; @@ -3246,6 +3253,35 @@ if (isRandomAccessRange!R && hasLength!R && hasSwappableElements!R) assert(arr.isSorted()); } +// https://issues.dlang.org/show_bug.cgi?id=21183 +@safe unittest +{ + static T get(T)(int) { return T.init; } + + // There's no need to actually sort, just checking type interference + if (false) + { + int[] arr; + + // Fine because there are no indirections + arr.schwartzSort!(get!(const int)); + + // Fine because it decays to immutable(int)* + arr.schwartzSort!(get!(immutable int*)); + + // Disallowed because it would require a non-const reference + static assert(!__traits(compiles, arr.schwartzSort!(get!(const Object)))); + + static struct Wrapper + { + int* ptr; + } + + // Disallowed because Wrapper.ptr would become mutable + static assert(!__traits(compiles, arr.schwartzSort!(get!(const Wrapper)))); + } +} + // partialSort /** Reorders the random-access range `r` such that the range `r[0 .. mid]` diff --git a/std/range/package.d b/std/range/package.d index 212c1dd66..bf3a13c37 100644 --- a/std/range/package.d +++ b/std/range/package.d @@ -9736,11 +9736,14 @@ public: assert([1].map!(x => x).slide(2).equal!equal([[1]])); } -private struct OnlyResult(T, size_t arity) +private struct OnlyResult(Values...) +if (Values.length > 1) { - private this(Values...)(return scope auto ref Values values) + private enum arity = Values.length; + + private this(return scope ref Values values) { - this.data = [values]; + this.values = values; this.backIndex = arity; } @@ -9749,10 +9752,10 @@ private struct OnlyResult(T, size_t arity) return frontIndex >= backIndex; } - T front() @property + CommonType!Values front() @property { assert(!empty, "Attempting to fetch the front of an empty Only range"); - return data[frontIndex]; + return this[0]; } void popFront() @@ -9761,10 +9764,10 @@ private struct OnlyResult(T, size_t arity) ++frontIndex; } - T back() @property + CommonType!Values back() @property { assert(!empty, "Attempting to fetch the back of an empty Only range"); - return data[backIndex - 1]; + return this[$ - 1]; } void popBack() @@ -9785,12 +9788,15 @@ private struct OnlyResult(T, size_t arity) alias opDollar = length; - T opIndex(size_t idx) + CommonType!Values opIndex(size_t idx) { // when i + idx points to elements popped // with popBack assert(idx < length, "Attempting to fetch an out of bounds index from an Only range"); - return data[frontIndex + idx]; + final switch (frontIndex + idx) + static foreach (i, T; Values) + case i: + return values[i]; } OnlyResult opSlice() @@ -9822,16 +9828,16 @@ private struct OnlyResult(T, size_t arity) { import std.traits : hasElaborateAssign; static if (hasElaborateAssign!T) - private T[arity] data; + private Values values; else - private T[arity] data = void; + private Values values = void; } else - private T[arity] data; + private Values values; } // Specialize for single-element results -private struct OnlyResult(T, size_t arity : 1) +private struct OnlyResult(T) { @property T front() { @@ -9895,7 +9901,7 @@ private struct OnlyResult(T, size_t arity : 1) } // Specialize for the empty range -private struct OnlyResult(T, size_t arity : 0) +private struct OnlyResult() { private static struct EmptyElementType {} @@ -9945,7 +9951,7 @@ See_Also: $(LREF chain) to chain ranges auto only(Values...)(return scope Values values) if (!is(CommonType!Values == void) || Values.length == 0) { - return OnlyResult!(CommonType!Values, Values.length)(values); + return OnlyResult!Values(values); } /// @@ -9969,17 +9975,6 @@ if (!is(CommonType!Values == void) || Values.length == 0) .equal("T.D.P.L")); } -@safe unittest -{ - // Verify that the same common type and same arity - // results in the same template instantiation - static assert(is(typeof(only(byte.init, int.init)) == - typeof(only(int.init, byte.init)))); - - static assert(is(typeof(only((const(char)[]).init, string.init)) == - typeof(only((const(char)[]).init, (const(char)[]).init)))); -} - // https://issues.dlang.org/show_bug.cgi?id=20314 @safe unittest { @@ -10153,6 +10148,43 @@ if (!is(CommonType!Values == void) || Values.length == 0) cast(void) only(test, test); // Works with mutable indirection } +// https://issues.dlang.org/show_bug.cgi?id=21129 +@safe unittest +{ + auto range = () @safe { + const(char)[5] staticStr = "Hello"; + + // `only` must store a char[5] - not a char[]! + return only(staticStr, " World"); + } (); + + assert(range.join == "Hello World"); +} + +// https://issues.dlang.org/show_bug.cgi?id=21129 +@safe unittest +{ + struct AliasedString + { + const(char)[5] staticStr = "Hello"; + + @property const(char)[] slice() const + { + return staticStr[]; + } + alias slice this; + } + + auto range = () @safe { + auto hello = AliasedString(); + + // a copy of AliasedString is stored in the range. + return only(hello, " World"); + } (); + + assert(range.join == "Hello World"); +} + /** Iterate over `range` with an attached index variable.