From 8f8979ebe15adf6ef82c3f43b81388a61be99700 Mon Sep 17 00:00:00 2001 From: Dicebot Date: Thu, 10 Nov 2016 19:19:59 +0200 Subject: [PATCH 01/12] Revert "Merge pull request #4790 from JackStouffer/uni-private" This reverts commit 1a7914a48cd7929373bb628f4938a8224de2167c, reversing changes made to d38727771b559828d50f01c70815f913e653b706. Fixes issue 16663 --- std/uni.d | 68 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 52 insertions(+), 16 deletions(-) diff --git a/std/uni.d b/std/uni.d index 8b7fa32fdcb..30025318927 100644 --- a/std/uni.d +++ b/std/uni.d @@ -1898,27 +1898,23 @@ public alias CodepointSet = InversionList!GcPolicy; */ public struct CodepointInterval { - uint[2] tuple; - alias tuple this; +pure: + uint[2] _tuple; + alias _tuple this; @safe pure nothrow @nogc: - /// Constructor + this(uint low, uint high) { - tuple[0] = low; - tuple[1] = high; + _tuple[0] = low; + _tuple[1] = high; } - - /// Support for equality testing bool opEquals(T)(T val) const { return this[0] == val[0] && this[1] == val[1]; } - - /// Access to the interval members - @property ref inout(uint) a() inout { return tuple[0]; } - /// ditto - @property ref inout(uint) b() inout { return tuple[1]; } + @property ref inout(uint) a() inout { return _tuple[0]; } + @property ref inout(uint) b() inout { return _tuple[1]; } } /** @@ -7962,7 +7958,7 @@ version(std_uni_bootstrap) { // old version used for bootstrapping of gen_uni.d that generates // up to date optimal versions of all of isXXX functions - package @safe pure nothrow @nogc bool isWhite(dchar c) + @safe pure nothrow @nogc public bool isWhite(dchar c) { import std.ascii : isWhite; return isWhite(c) || @@ -8303,7 +8299,7 @@ auto asUpperCase(Range)(Range str) assert("hEllo".asUpperCase.equal("HELLO")); } -/// ditto +// explicitly undocumented auto asLowerCase(Range)(auto ref Range str) if (isConvertibleToString!Range) { @@ -8311,7 +8307,7 @@ auto asLowerCase(Range)(auto ref Range str) return asLowerCase!(StringTypeOf!Range)(str); } -/// ditto +// explicitly undocumented auto asUpperCase(Range)(auto ref Range str) if (isConvertibleToString!Range) { @@ -8500,7 +8496,6 @@ auto asCapitalized(Range)(Range str) assert("hEllo".asCapitalized.equal("Hello")); } -/// ditto auto asCapitalized(Range)(auto ref Range str) if (isConvertibleToString!Range) { @@ -8823,6 +8818,16 @@ void toLowerInPlace(C)(ref C[] s) @trusted pure { toCaseInPlace!(LowerTriple)(s); } +// overloads for the most common cases to reduce compile time +@safe pure /*TODO nothrow*/ +{ + void toLowerInPlace(ref char[] s) + { toLowerInPlace!char(s); } + void toLowerInPlace(ref wchar[] s) + { toLowerInPlace!wchar(s); } + void toLowerInPlace(ref dchar[] s) + { toLowerInPlace!dchar(s); } +} /++ Converts $(D s) to uppercase (by performing Unicode uppercase mapping) in place. @@ -8835,6 +8840,16 @@ void toUpperInPlace(C)(ref C[] s) @trusted pure { toCaseInPlace!(UpperTriple)(s); } +// overloads for the most common cases to reduce compile time/code size +@safe pure /*TODO nothrow*/ +{ + void toUpperInPlace(ref char[] s) + { toUpperInPlace!char(s); } + void toUpperInPlace(ref wchar[] s) + { toUpperInPlace!wchar(s); } + void toUpperInPlace(ref dchar[] s) + { toUpperInPlace!dchar(s); } +} /++ If $(D c) is a Unicode uppercase $(CHARACTER), then its lowercase equivalent @@ -8874,6 +8889,17 @@ S toLower(S)(S s) @trusted pure static import std.ascii; return toCase!(LowerTriple, std.ascii.toLower)(s); } +// overloads for the most common cases to reduce compile time +@safe pure /*TODO nothrow*/ +{ + string toLower(string s) + { return toLower!string(s); } + wstring toLower(wstring s) + { return toLower!wstring(s); } + dstring toLower(dstring s) + { return toLower!dstring(s); } +} + @system unittest //@@@BUG std.format is not @safe { @@ -9029,6 +9055,16 @@ S toUpper(S)(S s) @trusted pure static import std.ascii; return toCase!(UpperTriple, std.ascii.toUpper)(s); } +// overloads for the most common cases to reduce compile time +@safe pure /*TODO nothrow*/ +{ + string toUpper(string s) + { return toUpper!string(s); } + wstring toUpper(wstring s) + { return toUpper!wstring(s); } + dstring toUpper(dstring s) + { return toUpper!dstring(s); } +} @safe unittest { From 11a9c58a8e86f57fd58b59f6c45bdd47095e4f20 Mon Sep 17 00:00:00 2001 From: anonymous Date: Sun, 13 Nov 2016 01:25:25 +0100 Subject: [PATCH 02/12] XREF -> REF Removing the one that refers to std.algorithm.setops.SetUnion, because that is not documented anymore (it's deprecated). --- std/algorithm/setops.d | 2 +- std/algorithm/sorting.d | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/std/algorithm/setops.d b/std/algorithm/setops.d index 6819fb659a0..0d855925e7d 100644 --- a/std/algorithm/setops.d +++ b/std/algorithm/setops.d @@ -1293,7 +1293,7 @@ Returns: A range containing the unique union of the given ranges. See_Also: - $(XREF algorithm, sorting, merge) + $(REF merge, std,algorithm,sorting) */ auto setUnion(alias less = "a < b", Rs...) (Rs rs) diff --git a/std/algorithm/sorting.d b/std/algorithm/sorting.d index e638b501b59..fb3fd1b3f61 100644 --- a/std/algorithm/sorting.d +++ b/std/algorithm/sorting.d @@ -1055,9 +1055,6 @@ Params: Returns: A range containing the union of the given ranges. - -See_Also: - $(XREF algorithm, setops, SetUnion) */ struct Merge(alias less = "a < b", Rs...) if (allSatisfy!(isInputRange, Rs)) { From 2f27e58b0e498aeecfdbce5178ad0bb700ab779c Mon Sep 17 00:00:00 2001 From: Dicebot Date: Thu, 10 Nov 2016 19:48:08 +0200 Subject: [PATCH 03/12] Add regression test for issue 16663 --- std/uni.d | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/std/uni.d b/std/uni.d index 30025318927..218dbaf2e86 100644 --- a/std/uni.d +++ b/std/uni.d @@ -8898,6 +8898,22 @@ S toLower(S)(S s) @trusted pure { return toLower!wstring(s); } dstring toLower(dstring s) { return toLower!dstring(s); } + + unittest + { + // https://issues.dlang.org/show_bug.cgi?id=16663 + + static struct String + { + string data; + alias data this; + } + + void foo() + { + auto u = toLower(String("")); + } + } } @@ -9064,6 +9080,22 @@ S toUpper(S)(S s) @trusted pure { return toUpper!wstring(s); } dstring toUpper(dstring s) { return toUpper!dstring(s); } + + unittest + { + // https://issues.dlang.org/show_bug.cgi?id=16663 + + static struct String + { + string data; + alias data this; + } + + void foo() + { + auto u = toUpper(String("")); + } + } } @safe unittest From 73b699de123a3f8d2e38f0d63735865fa78c03ce Mon Sep 17 00:00:00 2001 From: Dicebot Date: Tue, 15 Nov 2016 12:44:16 +0200 Subject: [PATCH 04/12] Revert "Merge pull request #4789 from JackStouffer/package2" This reverts commit c940f5a4182f018901bf6d933fc65c74f817c71a, reversing changes made to aaf31b531c735d09e2527a5213fcf6634d77086e. Fixes issue 16682 --- std/stdio.d | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/std/stdio.d b/std/stdio.d index cf3e195b725..fdc5065145f 100644 --- a/std/stdio.d +++ b/std/stdio.d @@ -88,7 +88,6 @@ else version (Posix) else static assert(0); -private: version(Windows) { // core.stdc.stdio.fopen expects file names to be @@ -247,7 +246,6 @@ version(HAS_GETDELIM) extern(C) nothrow @nogc ptrdiff_t getline(char**, size_t*, FILE*); } - //------------------------------------------------------------------------------ struct ByRecord(Fields...) { @@ -312,7 +310,6 @@ template byRecord(Fields...) } } -public: /** Encapsulates a $(D FILE*). Generally D does not attempt to provide thin wrappers over equivalent functions in the C standard library, but @@ -650,7 +647,6 @@ Throws: $(D ErrnoException) in case of error. version(StdDdoc) void windowsHandleOpen(HANDLE handle, in char[] stdioOpenmode); - /// ditto version(Windows) void windowsHandleOpen(HANDLE handle, in char[] stdioOpenmode) { @@ -1862,7 +1858,6 @@ Returns the underlying operating system $(D HANDLE) (Windows only). version(StdDdoc) @property HANDLE windowsHandle(); - /// ditto version(Windows) @property HANDLE windowsHandle() { @@ -1879,7 +1874,7 @@ Range that reads one line at a time. Returned by $(LREF byLine). Allows to directly use range operations on lines of a file. */ - private struct ByLine(Char, Terminator) + struct ByLine(Char, Terminator) { private: import std.typecons : RefCounted, RefCountedAutoInitialize; @@ -2400,7 +2395,7 @@ $(REF readText, std,file) /* * Range that reads a chunk at a time. */ - private struct ByChunk + struct ByChunk { private: File file_; @@ -2602,7 +2597,7 @@ $(D StdioException). /* $(D Range) that locks the file and allows fast writing to it. */ - private struct LockingTextWriter + struct LockingTextWriter { private: import std.range.primitives : ElementType, isInfinite, isInputRange; @@ -2779,7 +2774,7 @@ See $(LREF byChunk) for an example. // An output range which optionally locks the file and puts it into // binary mode (similar to rawWrite). Because it needs to restore // the file mode on destruction, it is RefCounted on Windows. - private struct BinaryWriterImpl(bool locking) + struct BinaryWriterImpl(bool locking) { import std.traits : hasIndirections; private: @@ -3194,7 +3189,7 @@ enum LockType readWrite } -private struct LockingTextReader +struct LockingTextReader { private File _f; private char _front; @@ -3914,7 +3909,6 @@ struct lines this.terminator = terminator; } - /// Implements `opApply` `foreach` support int opApply(D)(scope D dg) { import std.traits : Parameters; @@ -3958,8 +3952,8 @@ struct lines return opApplyRaw(dg); } } - - private int opApplyRaw(D)(scope D dg) + // no UTF checking + int opApplyRaw(D)(scope D dg) { import std.conv : to; import std.exception : assumeUnique; @@ -4317,7 +4311,7 @@ Initialize with a message and an error code. } } -package extern(C) void std_stdio_static_this() +extern(C) void std_stdio_static_this() { static import core.stdc.stdio; //Bind stdin, stdout, stderr From ce85fd60a9fe3819907857b487f65bd977ca1f26 Mon Sep 17 00:00:00 2001 From: Martin Nowak Date: Wed, 16 Nov 2016 19:41:57 +0100 Subject: [PATCH 05/12] fix Issue 16661 - failing dstring/wstring format string - fix incorrect pointer diff computation introduced by PR #4427 commit 2be035584f31131ebd3e2123b19f457c326d070d --- std/format.d | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/std/format.d b/std/format.d index fa1a11690ec..9fe11de106f 100644 --- a/std/format.d +++ b/std/format.d @@ -6479,6 +6479,13 @@ immutable(Char)[] format(Char, Args...)(in Char[] fmt, Args args) if (isSomeChar assert(is(typeof(format("happy"d)) == dstring)); } +// https://issues.dlang.org/show_bug.cgi?id=16661 +@safe unittest +{ + assert(format("%.2f"d, 0.4) == "0.40"); + assert("%02d"d.format(1) == "01"d); +} + /***************************************************** * Format arguments into buffer $(I buf) which must be large * enough to hold the result. Throws RangeError if it is not. @@ -6570,7 +6577,7 @@ char[] sformat(Char, Args...)(char[] buf, in Char[] fmt, Args args) * the difference between the starts of the arrays */ @trusted private pure nothrow @nogc - ptrdiff_t arrayPtrDiff(const void[] array1, const void[] array2) + ptrdiff_t arrayPtrDiff(T)(const T[] array1, const T[] array2) { return array1.ptr - array2.ptr; } From 0556bf138ed4678cb5ad870367065324fd4a5b4f Mon Sep 17 00:00:00 2001 From: Martin Nowak Date: Wed, 16 Nov 2016 20:05:29 +0100 Subject: [PATCH 06/12] fix Issue 16667 - wrong @safe unittest compilation error --- std/conv.d | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/std/conv.d b/std/conv.d index 092aa5d4361..d3a4a16750f 100644 --- a/std/conv.d +++ b/std/conv.d @@ -5554,7 +5554,7 @@ template castFrom(From) } /// - @safe unittest + @system unittest { // Regular cast, which has been verified to be legal by the programmer: { @@ -5588,6 +5588,19 @@ template castFrom(From) } } +// instantiate the documenting unittest in the castFrom template +unittest +{ + alias castFromI = castFrom!long; +} + +// https://issues.dlang.org/show_bug.cgi?id=16667 +unittest +{ + ubyte[] a = ['a', 'b', 'c']; + assert(castFrom!(ubyte[]).to!(string)(a) == "abc"); +} + /** Check the correctness of a string for $(D hexString). The result is true if and only if the input string is composed of whitespace From 74acd69f8be866b2b32b7f9de63948989eecbba1 Mon Sep 17 00:00:00 2001 From: anonymous Date: Fri, 18 Nov 2016 23:46:48 +0100 Subject: [PATCH 07/12] remove pointless LREFs The LREFs were broken. Could fix that with underscores, but the links would just point back at the current section. There's no point in having such links. --- std/algorithm/sorting.d | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/std/algorithm/sorting.d b/std/algorithm/sorting.d index fb3fd1b3f61..22d4ad8706d 100644 --- a/std/algorithm/sorting.d +++ b/std/algorithm/sorting.d @@ -145,11 +145,11 @@ Checks whether a forward range is sorted according to the comparison operation $(D less). Performs $(BIGOH r.length) evaluations of $(D less). -Unlike $(LREF isSorted), $(LREF isStrictlyMonotonic) does not allow for equal values, +Unlike isSorted, isStrictlyMonotonic does not allow for equal values, i.e. values for which both `less(a, b)` and `less(b, a)` are false. With either function, the predicate must be a strict ordering just like with -$(LREF isSorted). For example, using `"a <= b"` instead of `"a < b"` is +isSorted. For example, using `"a <= b"` instead of `"a < b"` is incorrect and will cause failed assertions. Params: @@ -157,8 +157,8 @@ Params: r = Forward range to check for sortedness. Returns: - `true` if the range is sorted, false otherwise. $(LREF isSorted) allows - duplicates, $(LREF isStrictlyMonotonic) not. + `true` if the range is sorted, false otherwise. isSorted allows + duplicates, isStrictlyMonotonic not. */ bool isSorted(alias less = "a < b", Range)(Range r) if (isForwardRange!(Range)) { From a7597df60ed7f78988e875d25b6d48b48189cc33 Mon Sep 17 00:00:00 2001 From: Petar Kirov Date: Sun, 20 Nov 2016 17:57:39 +0200 Subject: [PATCH 08/12] Fix issue 16705 - TaskPool.reduce fails to compile "cannot get frame pointer to D main" --- std/parallelism.d | 46 ++++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/std/parallelism.d b/std/parallelism.d index 3acdc01cfbc..9643c0616a2 100644 --- a/std/parallelism.d +++ b/std/parallelism.d @@ -33,12 +33,21 @@ Warning: Unless marked as $(D @trusted) or $(D @safe), artifacts in this module allow implicit data sharing between threads and cannot guarantee that client code is free from low level data races. -Synopsis: +Source: $(PHOBOSSRC std/_parallelism.d) +Author: David Simcha +Copyright: Copyright (c) 2009-2011, David Simcha. +License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0) +*/ +module std.parallelism; ---- -import std.algorithm, std.parallelism, std.range; +/// +unittest +{ + import std.algorithm : map; + import std.range : iota; + import std.math : approxEqual; + import std.parallelism : taskPool; -void main() { // Parallel reduce can be combined with // std.algorithm.map to interesting effect. // The following example (thanks to Russel Winder) @@ -47,32 +56,25 @@ void main() { // getTerm is evaluated in parallel as needed by // TaskPool.reduce. // - // Timings on an Athlon 64 X2 dual core machine: + // Timings on an Intel i5-3450 quad core machine + // for n = 1_000_000_000: // - // TaskPool.reduce: 12.170 s - // std.algorithm.reduce: 24.065 s + // TaskPool.reduce: 4.011 s + // std.algorithm.reduce: 1.067 s - immutable n = 1_000_000_000; - immutable delta = 1.0 / n; + enum n = 1_000_000; + enum delta = 1.0 / n; - real getTerm(int i) + alias getTerm = (int i) { immutable x = ( i - 0.5 ) * delta; return delta / ( 1.0 + x * x ) ; - } + }; - immutable pi = 4.0 * taskPool.reduce!"a + b"( - std.algorithm.map!getTerm(iota(n)) - ); -} ---- + immutable pi = 4.0 * taskPool.reduce!"a + b"(n.iota.map!getTerm); -Source: $(PHOBOSSRC std/_parallelism.d) -Author: David Simcha -Copyright: Copyright (c) 2009-2011, David Simcha. -License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0) -*/ -module std.parallelism; + assert(pi.approxEqual(3.1415926)); +} import core.atomic; import core.exception; From ea55c96c43989945bff6b593a0568b95f173167f Mon Sep 17 00:00:00 2001 From: Martin Nowak Date: Sun, 20 Nov 2016 23:27:37 +0100 Subject: [PATCH 09/12] move unittest outside of template --- std/conv.d | 60 ++++++++++++++++++++++++------------------------------ 1 file changed, 27 insertions(+), 33 deletions(-) diff --git a/std/conv.d b/std/conv.d index d3a4a16750f..b3e164d5303 100644 --- a/std/conv.d +++ b/std/conv.d @@ -5552,48 +5552,42 @@ template castFrom(From) return cast(To) value; } +} - /// - @system unittest +/// +@system unittest +{ + // Regular cast, which has been verified to be legal by the programmer: { - // Regular cast, which has been verified to be legal by the programmer: - { - long x; - auto y = cast(int) x; - } + long x; + auto y = cast(int) x; + } - // However this will still compile if 'x' is changed to be a pointer: - { - long* x; - auto y = cast(int) x; - } + // However this will still compile if 'x' is changed to be a pointer: + { + long* x; + auto y = cast(int) x; + } - // castFrom provides a more reliable alternative to casting: - { - long x; - auto y = castFrom!long.to!int(x); - } + // castFrom provides a more reliable alternative to casting: + { + long x; + auto y = castFrom!long.to!int(x); + } - // Changing the type of 'x' will now issue a compiler error, - // allowing bad casts to be caught before it's too late: - { - long* x; - static assert ( - !__traits(compiles, castFrom!long.to!int(x)) - ); + // Changing the type of 'x' will now issue a compiler error, + // allowing bad casts to be caught before it's too late: + { + long* x; + static assert ( + !__traits(compiles, castFrom!long.to!int(x)) + ); - // if cast is still needed, must be changed to: - auto y = castFrom!(long*).to!int(x); - } + // if cast is still needed, must be changed to: + auto y = castFrom!(long*).to!int(x); } } -// instantiate the documenting unittest in the castFrom template -unittest -{ - alias castFromI = castFrom!long; -} - // https://issues.dlang.org/show_bug.cgi?id=16667 unittest { From dfebb1f5ff9da3abfd4f77e4b7b7b01f4fafe1ca Mon Sep 17 00:00:00 2001 From: anonymous Date: Mon, 21 Nov 2016 13:05:53 +0100 Subject: [PATCH 10/12] [Ddoc] backticks around isSorted and isStrictlyMonotonic DDOX doesn't do auto-highlighting, but the symbols need to be formatted as code there, too. --- std/algorithm/sorting.d | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/std/algorithm/sorting.d b/std/algorithm/sorting.d index 22d4ad8706d..d33a0d92052 100644 --- a/std/algorithm/sorting.d +++ b/std/algorithm/sorting.d @@ -145,11 +145,11 @@ Checks whether a forward range is sorted according to the comparison operation $(D less). Performs $(BIGOH r.length) evaluations of $(D less). -Unlike isSorted, isStrictlyMonotonic does not allow for equal values, +Unlike `isSorted`, `isStrictlyMonotonic` does not allow for equal values, i.e. values for which both `less(a, b)` and `less(b, a)` are false. With either function, the predicate must be a strict ordering just like with -isSorted. For example, using `"a <= b"` instead of `"a < b"` is +`isSorted`. For example, using `"a <= b"` instead of `"a < b"` is incorrect and will cause failed assertions. Params: @@ -157,8 +157,8 @@ Params: r = Forward range to check for sortedness. Returns: - `true` if the range is sorted, false otherwise. isSorted allows - duplicates, isStrictlyMonotonic not. + `true` if the range is sorted, false otherwise. `isSorted` allows + duplicates, `isStrictlyMonotonic` not. */ bool isSorted(alias less = "a < b", Range)(Range r) if (isForwardRange!(Range)) { From b44fb6bea2dc7807e10958f9b47ac7d9c011b230 Mon Sep 17 00:00:00 2001 From: ZombineDev Date: Tue, 22 Nov 2016 10:09:38 +0200 Subject: [PATCH 11/12] Fix typo introduced in PR #4915 --- std/parallelism.d | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/std/parallelism.d b/std/parallelism.d index 9643c0616a2..ae268a0ef7a 100644 --- a/std/parallelism.d +++ b/std/parallelism.d @@ -59,8 +59,8 @@ unittest // Timings on an Intel i5-3450 quad core machine // for n = 1_000_000_000: // - // TaskPool.reduce: 4.011 s - // std.algorithm.reduce: 1.067 s + // TaskPool.reduce: 1.067 s + // std.algorithm.reduce: 4.011 s enum n = 1_000_000; enum delta = 1.0 / n; From c8a123f4d0f2cc9b611545f5c3055cfcc31fcb05 Mon Sep 17 00:00:00 2001 From: anonymous Date: Sun, 4 Dec 2016 22:14:15 +0100 Subject: [PATCH 12/12] fix issue 16948 - broken links in std.stdio due to inccorrect use of WEB macro --- std/stdio.d | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/std/stdio.d b/std/stdio.d index fdc5065145f..a3c71d2ca34 100644 --- a/std/stdio.d +++ b/std/stdio.d @@ -4333,7 +4333,7 @@ __gshared { /** The standard input stream. Bugs: - Due to $(WEB https://issues.dlang.org/show_bug.cgi?id=15768, bug 15768), + Due to $(LINK2 https://issues.dlang.org/show_bug.cgi?id=15768, bug 15768), it is thread un-safe to reassign `stdin` to a different `File` instance than the default. */ @@ -4357,7 +4357,7 @@ __gshared /** The standard output stream. Bugs: - Due to $(WEB https://issues.dlang.org/show_bug.cgi?id=15768, bug 15768), + Due to $(LINK2 https://issues.dlang.org/show_bug.cgi?id=15768, bug 15768), it is thread un-safe to reassign `stdout` to a different `File` instance than the default. */ @@ -4365,7 +4365,7 @@ __gshared /** The standard error stream. Bugs: - Due to $(WEB https://issues.dlang.org/show_bug.cgi?id=15768, bug 15768), + Due to $(LINK2 https://issues.dlang.org/show_bug.cgi?id=15768, bug 15768), it is thread un-safe to reassign `stderr` to a different `File` instance than the default. */