From 1f1a80d0a0cb7e61cea174a708436d44fab391c4 Mon Sep 17 00:00:00 2001 From: FeepingCreature <540727+FeepingCreature@users.noreply.github.com> Date: Mon, 17 Aug 2020 19:02:05 +0200 Subject: [PATCH 1/3] Fix issue 21129: Make `OnlyResult` store the actual types passed to it as a tuple, instead of a static array of CommonType. (#7584) Remove the unittest that verifies that `OnlyResult` doesn't depend on argument order - since it now does. Add unittest for issue 21129. --- std/range/package.d | 84 +++++++++++++++++++++++++++++++-------------- 1 file changed, 58 insertions(+), 26 deletions(-) diff --git a/std/range/package.d b/std/range/package.d index b58737f76..c797c1d1b 100644 --- a/std/range/package.d +++ b/std/range/package.d @@ -9744,11 +9744,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; } @@ -9757,10 +9760,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() @@ -9769,10 +9772,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() @@ -9793,12 +9796,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() @@ -9830,16 +9836,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() { @@ -9903,7 +9909,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 {} @@ -9953,7 +9959,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); } /// @@ -9977,17 +9983,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 { @@ -10161,6 +10156,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. From 255f9496d1ef72876613d27341dee483e364aa3d Mon Sep 17 00:00:00 2001 From: MoonlightSentinel Date: Fri, 21 Aug 2020 13:07:57 +0200 Subject: [PATCH 2/3] Fix Issue 21183 - schwartzSort does not strip const Fixed by using the unqualified type if possible --- std/algorithm/sorting.d | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/std/algorithm/sorting.d b/std/algorithm/sorting.d index 97f5cdc87..f2909f4df 100644 --- a/std/algorithm/sorting.d +++ b/std/algorithm/sorting.d @@ -2981,18 +2981,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; @@ -3168,6 +3175,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]` From d38ba1e51f95a49abe1e159bd3b7befbd994d9a7 Mon Sep 17 00:00:00 2001 From: Steven Schveighoffer Date: Sat, 8 Aug 2020 00:24:05 -0400 Subject: [PATCH 3/3] Add makefile target for testing with no autodecode. This is so CI can run a valid target without failing. --- posix.mak | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/posix.mak b/posix.mak index 672f96ba4..34ea55bed 100644 --- a/posix.mak +++ b/posix.mak @@ -150,6 +150,10 @@ ifdef ENABLE_COVERAGE override DFLAGS += -cov endif +ifdef NO_AUTODECODE +override DFLAGS += -version=NoAutodecodeStrings +endif + UDFLAGS=-unittest -version=StdUnittest # Set DOTOBJ and DOTEXE @@ -235,6 +239,10 @@ PACKAGE_std_windows = charset registry syserror # Modules in std (including those in packages) STD_MODULES=$(call P2MODULES,$(STD_PACKAGES)) +# NoAutodecode test modules. +# List all modules whose unittests are known to work without autodecode enabled. +NO_AUTODECODE_MODULES= + # Other D modules that aren't under std/ EXTRA_MODULES_COMMON := $(addprefix etc/c/,curl odbc/sql odbc/sqlext \ odbc/sqltypes odbc/sqlucode sqlite3 zlib) @@ -677,4 +685,7 @@ endif .PHONY: buildkite-test buildkite-test: unittest betterc +.PHONY: autodecode-test +autodecode-test: $(addsuffix .test,$(NO_AUTODECODE_MODULES)) + .DELETE_ON_ERROR: # GNU Make directive (delete output files on error)