[committed,4/4] d: Merge upstream phobos 574bf883b

Message ID 20211208235820.3258786-1-ibuclaw@gdcproject.org
State Committed
Headers
Series [committed,1/4] d: Merge upstream dmd 568496d5b |

Commit Message

Iain Buclaw Dec. 8, 2021, 11:58 p.m. UTC
  Hi,

This patch merges the D run-time libraries with upstream phobos
574bf883b.

Phobos changes:

    - Import phobos v2.098.0
    - All sources are now compiled with -fpreview=fieldwise.

Bootstrapped and regression tested on x86_64-linux-gnu/-m32/-mx32, and
committed to mainline.

Regards,
Iain.

---
libphobos/ChangeLog:

	PR d/103558
	* src/MERGE: Merge upstream phobos 574bf883b.
	* src/Makefile.am (D_EXTRA_DFLAGS): Add -fpreview=fieldwise.
	* src/Makefile.in: Regenerate.
---
 libphobos/src/MERGE                           |   2 +-
 libphobos/src/Makefile.am                     |   5 +-
 libphobos/src/Makefile.in                     |   5 +-
 libphobos/src/etc/c/curl.d                    |  43 +-
 libphobos/src/{index.d => index.dd}           |   0
 libphobos/src/std/algorithm/comparison.d      | 401 +++++++---
 libphobos/src/std/algorithm/iteration.d       | 237 +++---
 libphobos/src/std/algorithm/mutation.d        |   2 +-
 libphobos/src/std/algorithm/searching.d       |   8 +-
 libphobos/src/std/algorithm/sorting.d         |  12 +-
 libphobos/src/std/array.d                     |  22 +-
 libphobos/src/std/bitmanip.d                  |   6 +-
 libphobos/src/std/concurrency.d               |  79 +-
 libphobos/src/std/container/array.d           | 206 +++--
 libphobos/src/std/datetime/systime.d          |  52 +-
 libphobos/src/std/datetime/timezone.d         |   1 +
 libphobos/src/std/digest/ripemd.d             |   2 +-
 libphobos/src/std/exception.d                 |  50 +-
 libphobos/src/std/experimental/checkedint.d   |  10 +-
 libphobos/src/std/file.d                      |  75 +-
 libphobos/src/std/format/internal/floats.d    |  12 +-
 libphobos/src/std/format/internal/write.d     | 154 ++--
 libphobos/src/std/functional.d                |  31 +-
 libphobos/src/std/getopt.d                    |  13 +-
 libphobos/src/std/internal/math/biguintcore.d |   6 -
 libphobos/src/std/internal/windows/advapi32.d |  12 +-
 libphobos/src/std/json.d                      |   6 +-
 libphobos/src/std/math/algebraic.d            |  89 +--
 libphobos/src/std/math/operations.d           |   3 +-
 libphobos/src/std/meta.d                      | 384 +++------
 libphobos/src/std/parallelism.d               |  71 +-
 libphobos/src/std/process.d                   |  27 +-
 libphobos/src/std/random.d                    |  24 +-
 libphobos/src/std/range/interfaces.d          |  51 +-
 libphobos/src/std/range/package.d             | 102 ++-
 libphobos/src/std/range/primitives.d          |  17 +
 libphobos/src/std/socket.d                    |  79 +-
 libphobos/src/std/stdio.d                     |  52 +-
 libphobos/src/std/string.d                    |  16 +-
 libphobos/src/std/system.d                    |   2 +
 libphobos/src/std/traits.d                    | 602 ++++++--------
 libphobos/src/std/typecons.d                  | 243 +++---
 libphobos/src/std/uni/package.d               |  38 +-
 libphobos/src/std/variant.d                   |   2 +-
 libphobos/src/std/windows/registry.d          |   5 -
 45 files changed, 1763 insertions(+), 1496 deletions(-)
 rename libphobos/src/{index.d => index.dd} (100%)
  

Comments

Andreas Schwab Dec. 9, 2021, 10:09 a.m. UTC | #1
Breaks aarch64:

../../../../libphobos/libdruntime/core/sys/linux/unistd.d:10:15: error: module 'core.sys.linux.syscalls' import 'SystemCall' not found
   10 | public import core.sys.linux.syscalls : SystemCall;
      |               ^

Andreas.
  
Iain Buclaw Dec. 9, 2021, 10:11 p.m. UTC | #2
Excerpts from Andreas Schwab's message of December 9, 2021 11:09 am:
> Breaks aarch64:
> 
> ../../../../libphobos/libdruntime/core/sys/linux/unistd.d:10:15: error: module 'core.sys.linux.syscalls' import 'SystemCall' not found
>    10 | public import core.sys.linux.syscalls : SystemCall;
>       |               ^
> 

Hi Andreas,

Thanks!  I've raised a revert for the change in upstream that broke
this.  Unfortunately they only considered X86 and X86_64 in the change.

Iain.
  
Iain Buclaw Dec. 10, 2021, 1:57 p.m. UTC | #3
Excerpts from Iain Buclaw's message of December 9, 2021 11:11 pm:
> Excerpts from Andreas Schwab's message of December 9, 2021 11:09 am:
>> Breaks aarch64:
>> 
>> ../../../../libphobos/libdruntime/core/sys/linux/unistd.d:10:15: error: module 'core.sys.linux.syscalls' import 'SystemCall' not found
>>    10 | public import core.sys.linux.syscalls : SystemCall;
>>       |               ^
>> 
> 
> Hi Andreas,
> 
> Thanks!  I've raised a revert for the change in upstream that broke
> this.  Unfortunately they only considered X86 and X86_64 in the change.
> 

Patch was included as part of r12-5887.

Iain.
  

Patch

diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE
index 927d3ee874a..29bcf33c01f 100644
--- a/libphobos/src/MERGE
+++ b/libphobos/src/MERGE
@@ -1,4 +1,4 @@ 
-5ab9ad2561cea35ac33ebc0452c0e6a8d762f27d
+574bf883b790340fb753d6542ec48a3ba3e6cb82
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/phobos repository.
diff --git a/libphobos/src/Makefile.am b/libphobos/src/Makefile.am
index ba1579da8d7..c584b5aec0d 100644
--- a/libphobos/src/Makefile.am
+++ b/libphobos/src/Makefile.am
@@ -19,8 +19,9 @@ 
 include $(top_srcdir)/d_rules.am
 
 # Make sure GDC can find libdruntime and libphobos include files
-D_EXTRA_DFLAGS=-fpreview=dip1000 -fpreview=dtorfields -nostdinc -I $(srcdir) \
-	-I $(top_srcdir)/libdruntime -I ../libdruntime -I .
+D_EXTRA_DFLAGS=-fpreview=dip1000 -fpreview=dtorfields -fpreview=fieldwise \
+	-nostdinc -I $(srcdir) -I $(top_srcdir)/libdruntime \
+	-I ../libdruntime -I .
 
 # D flags for compilation
 AM_DFLAGS= \
diff --git a/libphobos/src/Makefile.in b/libphobos/src/Makefile.in
index 9e61bb309f8..a4101ebf028 100644
--- a/libphobos/src/Makefile.in
+++ b/libphobos/src/Makefile.in
@@ -500,8 +500,9 @@  LTDCOMPILE = $(LIBTOOL) --tag=D $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
 # Include D build rules
 
 # Make sure GDC can find libdruntime and libphobos include files
-D_EXTRA_DFLAGS = -fpreview=dip1000 -fpreview=dtorfields -nostdinc -I $(srcdir) \
-	-I $(top_srcdir)/libdruntime -I ../libdruntime -I .
+D_EXTRA_DFLAGS = -fpreview=dip1000 -fpreview=dtorfields -fpreview=fieldwise \
+	-nostdinc -I $(srcdir) -I $(top_srcdir)/libdruntime \
+	-I ../libdruntime -I .
 
 
 # D flags for compilation
diff --git a/libphobos/src/etc/c/curl.d b/libphobos/src/etc/c/curl.d
index 98fe74af321..0c5b727944c 100644
--- a/libphobos/src/etc/c/curl.d
+++ b/libphobos/src/etc/c/curl.d
@@ -548,29 +548,36 @@  enum CurlProxy {
 alias curl_proxytype = int;
 
 ///
-enum CurlAuth : long {
-  none =         0,
-  basic =        1,  /** Basic (default) */
-  digest =       2,  /** Digest */
-  gssnegotiate = 4,  /** GSS-Negotiate */
-  ntlm =         8,  /** NTLM */
-  digest_ie =    16, /** Digest with IE flavour */
-  only =         2_147_483_648, /** used together with a single other
-                                type to force no auth or just that
-                                single type */
-  any = -17,     /* (~CURLAUTH_DIGEST_IE) */  /** all fine types set */
-  anysafe = -18  /* (~(CURLAUTH_BASIC|CURLAUTH_DIGEST_IE)) */ ///
+enum CurlAuth : ulong {
+  none =         0UL,        /** None */
+  basic =        1UL << 0,   /** Basic (default) */
+  digest =       1UL << 1,   /** Digest */
+  negotiate =    1UL << 2,   /** Negotiate (SPNEGO) */
+  gssnegotiate = negotiate,  /** GSS-Negotiate */
+  gssapi =       negotiate,  /** GSS-Negoatiate */
+  ntlm =         1UL << 3,   /** NTLM */
+  digest_ie =    1UL << 4,   /** Digest with IE flavour */
+  ntlm_WB =      1UL << 5,   /** NTML delegated to winbind helper */
+  bearer =       1UL << 6,   /** Bearer token authentication */
+  only =         1UL << 31,  /** used together with a single other
+                                 type to force no auth or just that
+                                 single type */
+  any =          ~digest_ie, /** any allows */
+  anysafe =      ~(basic | digest_ie) /** any except basic */
 }
 
 ///
 enum CurlSshAuth {
-  any       = -1,     /** all types supported by the server */
+  any       = ~0,     /** all types supported by the server */
   none      = 0,      /** none allowed, silly but complete */
-  publickey = 1, /** public/private key files */
-  password  = 2, /** password */
-  host      = 4, /** host key files */
-  keyboard  = 8, /** keyboard interactive */
-  default_  = -1 // CURLSSH_AUTH_ANY;
+  publickey = 1 << 0, /** public/private key files */
+  password  = 1 << 1, /** password */
+  host      = 1 << 2, /** host key files */
+  keyboard  = 1 << 3, /** keyboard interactive */
+  agent     = 1 << 4, /** agent (ssh-agent, pageant...) */
+  gssapi    = 1 << 5, /** gssapi (kerberos, ...) */
+
+  default_  = any // CURLSSH_AUTH_ANY;
 }
 ///
 enum CURL_ERROR_SIZE = 256;
diff --git a/libphobos/src/index.d b/libphobos/src/index.dd
similarity index 100%
rename from libphobos/src/index.d
rename to libphobos/src/index.dd
diff --git a/libphobos/src/std/algorithm/comparison.d b/libphobos/src/std/algorithm/comparison.d
index c9525445ceb..2fcc2bacd5c 100644
--- a/libphobos/src/std/algorithm/comparison.d
+++ b/libphobos/src/std/algorithm/comparison.d
@@ -58,10 +58,10 @@  T2=$(TR $(TDNW $(LREF $1)) $(TD $+))
  */
 module std.algorithm.comparison;
 
-import std.functional : unaryFun, binaryFun;
+import std.functional : unaryFun, binaryFun, lessThan, greaterThan;
 import std.range.primitives;
 import std.traits;
-import std.meta : allSatisfy;
+import std.meta : allSatisfy, anySatisfy;
 import std.typecons : tuple, Tuple, Flag, Yes;
 
 import std.internal.attributes : betterC;
@@ -247,7 +247,7 @@  auto castSwitch(choices...)(Object switchObject)
         bool result = true;
         foreach (index, choice; choices)
         {
-            result &= is(ReturnType!choice == void);
+            result &= is(ReturnType!choice : void); // void or noreturn
         }
         return result;
     }();
@@ -514,9 +514,54 @@  auto castSwitch(choices...)(Object switchObject)
     ) == "derived from I");
 }
 
-/** Clamps a value into the given bounds.
+// https://issues.dlang.org/show_bug.cgi?id=22384
+@system unittest
+{
+    // Use explicit methods to enforce return types
+    static void objectSkip(Object) {}
+    static void defaultSkip() {}
+
+    static noreturn objectError(Object) { assert(false); }
+    static noreturn defaultError() { assert(false); }
+
+    {
+        alias test = castSwitch!(objectSkip, defaultError);
+        static assert(is(ReturnType!test == void));
+    }{
+        alias test = castSwitch!(objectError, defaultSkip);
+        static assert(is(ReturnType!test == void));
+    }{
+        alias test = castSwitch!(objectError, defaultError);
+        static assert(is(ReturnType!test == noreturn));
+    }
+
+    // Also works with non-void handlers
+    static int objectValue(Object) { return 1;}
+    static int defaultValue() { return 2; }
+
+    {
+        alias test = castSwitch!(objectValue, defaultError);
+        static assert(is(ReturnType!test == int));
+    }{
+        alias test = castSwitch!(objectError, defaultValue);
+        static assert(is(ReturnType!test == int));
+    }
+
+    // No confusion w.r.t. void callbacks
+    alias FP = void function();
+    static FP objectFunc(Object) { return &defaultSkip; }
+    static FP defaultFunc() { return &defaultSkip; }
+
+    {
+        alias test = castSwitch!(objectFunc, defaultError);
+        static assert(is(ReturnType!test == FP));
+    }{
+        alias test = castSwitch!(objectError, defaultFunc);
+        static assert(is(ReturnType!test == FP));
+    }
+}
 
-This function is equivalent to `max(lower, min(upper, val))`.
+/** Clamps `val` into the given bounds. Result has the same type as `val`.
 
 Params:
     val = The value to _clamp.
@@ -524,20 +569,22 @@  Params:
     upper = The _upper bound of the _clamp.
 
 Returns:
-    Returns `val`, if it is between `lower` and `upper`.
-    Otherwise returns the nearest of the two.
-
+    `lower` if `val` is less than `lower`, `upper` if `val` is greater than
+    `upper`, and `val` in all other cases. Comparisons are made
+    correctly (using $(REF lessThan, std,functional) and the return value
+    is converted to the return type using the standard integer coversion rules
+    $(REF greaterThan, std,functional)) even if the signedness of `T1`, `T2`,
+    and `T3` are different.
 */
-auto clamp(T1, T2, T3)(T1 val, T2 lower, T3 upper)
-if (is(typeof(max(min(val, upper), lower))))
+T1 clamp(T1, T2, T3)(T1 val, T2 lower, T3 upper)
+if (is(typeof(val.lessThan(lower) ? lower : val.greaterThan(upper) ? upper : val) : T1))
 in
 {
-    import std.functional : greaterThan;
     assert(!lower.greaterThan(upper), "Lower can't be greater than upper.");
 }
 do
 {
-    return max(min(val, upper), lower);
+    return val.lessThan(lower) ? lower : val.greaterThan(upper) ? upper : val;
 }
 
 ///
@@ -550,6 +597,10 @@  do
     assert(clamp(1, 1, 1) == 1);
 
     assert(clamp(5, -1, 2u) == 2);
+
+    auto x = clamp(42, uint.max, uint.max);
+    static assert(is(typeof(x) == int));
+    assert(x == -1);
 }
 
 @safe unittest
@@ -564,7 +615,7 @@  do
     // mixed sign
     a = -5;
     uint f = 5;
-    static assert(is(typeof(clamp(f, a, b)) == int));
+    static assert(is(typeof(clamp(f, a, b)) == uint));
     assert(clamp(f, a, b) == f);
     // similar type deduction for (u)long
     static assert(is(typeof(clamp(-1L, -2L, 2UL)) == long));
@@ -874,101 +925,121 @@  nothrow pure @safe unittest
 
 // equal
 /**
-Compares two ranges for equality, as defined by predicate `pred`
+Compares two or more ranges for equality, as defined by predicate `pred`
 (which is `==` by default).
 */
 template equal(alias pred = "a == b")
 {
     /++
-    Compares two ranges for equality. The ranges may have
-    different element types, as long as `pred(r1.front, r2.front)`
-    evaluates to `bool`.
-    Performs $(BIGOH min(r1.length, r2.length)) evaluations of `pred`.
+    Compares two or more ranges for equality. The ranges may have
+    different element types, as long as all are comparable by means of
+    the `pred`.
+    Performs $(BIGOH min(rs[0].length, rs[1].length, ...)) evaluations of `pred`. However, if
+    `equal` is invoked with the default predicate, the implementation may take the liberty
+    to use faster implementations that have the theoretical worst-case
+    $(BIGOH max(rs[0].length, rs[1].length, ...)).
 
     At least one of the ranges must be finite. If one range involved is infinite, the result is
     (statically known to be) `false`.
 
-    If the two ranges are different kinds of UTF code unit (`char`, `wchar`, or
-    `dchar`), then the arrays are compared using UTF decoding to avoid
+    If the ranges have different kinds of UTF code unit (`char`, `wchar`, or
+    `dchar`), then they are compared using UTF decoding to avoid
     accidentally integer-promoting units.
 
     Params:
-        r1 = The first range to be compared.
-        r2 = The second range to be compared.
+        rs = The ranges to be compared.
 
     Returns:
-        `true` if and only if the two ranges compare _equal element
+        `true` if and only if all ranges compare _equal element
         for element, according to binary predicate `pred`.
     +/
-    bool equal(Range1, Range2)(Range1 r1, Range2 r2)
-    if (isInputRange!Range1 && isInputRange!Range2 &&
-        !(isInfinite!Range1 && isInfinite!Range2) &&
-        is(typeof(binaryFun!pred(r1.front, r2.front))))
+    bool equal(Ranges...)(Ranges rs)
+    if (rs.length > 1
+        && allSatisfy!(isInputRange, Ranges)
+        && !allSatisfy!(isInfinite, Ranges)
+        && is(typeof(binaryFun!pred(rs[0].front, rs[1].front)))
+        && (rs.length == 2 || is(typeof(equal!pred(rs[1 .. $])) == bool))
+        )
     {
-        // Use code points when comparing two ranges of UTF code units that aren't
-        // the same type. This is for backwards compatibility with autodecode
-        // strings.
-        enum useCodePoint =
-            isSomeChar!(ElementEncodingType!Range1) && isSomeChar!(ElementEncodingType!Range2) &&
-            ElementEncodingType!Range1.sizeof != ElementEncodingType!Range2.sizeof;
-
-        static if (useCodePoint)
+        alias ElementEncodingTypes = staticMap!(ElementEncodingType, Ranges);
+        enum differentSize(T) = T.sizeof != ElementEncodingTypes[0].sizeof;
+        enum useCodePoint = allSatisfy!(isSomeChar, ElementEncodingTypes) &&
+            anySatisfy!(differentSize, ElementEncodingTypes);
+        enum bool comparableWithEq(alias r) = is(typeof(rs[0] == r));
+
+        static if (anySatisfy!(isInfinite, Ranges))
         {
-            import std.utf : byDchar;
-            return equal(r1.byDchar, r2.byDchar);
+            return false;
         }
-        else
+        else static if (useCodePoint)
         {
-            static if (isInfinite!Range1 || isInfinite!Range2)
-            {
-                // No finite range can be ever equal to an infinite range.
-                return false;
-            }
-            // Detect default pred and compatible dynamic arrays.
-            else static if (is(typeof(pred) == string) && pred == "a == b" &&
-                isArray!Range1 && isArray!Range2 && is(typeof(r1 == r2)))
-            {
-                return r1 == r2;
-            }
-            // If one of the arguments is a string and the other isn't, then auto-decoding
-            // can be avoided if they have the same ElementEncodingType.
-            else static if (is(typeof(pred) == string) && pred == "a == b" &&
-                isAutodecodableString!Range1 != isAutodecodableString!Range2 &&
-                is(immutable ElementEncodingType!Range1 == immutable ElementEncodingType!Range2))
+            import std.utf : byDchar;
+            static bool allByDchar(size_t done, Ranges...)(auto ref Ranges rs)
             {
-                import std.utf : byCodeUnit;
-
-                static if (isAutodecodableString!Range1)
-                    return equal(r1.byCodeUnit, r2);
+                static if (done == rs.length)
+                    return equalLoop(rs);
                 else
-                    return equal(r2.byCodeUnit, r1);
-            }
-            // Try a fast implementation when the ranges have comparable lengths.
-            else static if (hasLength!Range1 && hasLength!Range2 && is(typeof(r1.length == r2.length)))
-            {
-                immutable len1 = r1.length;
-                immutable len2 = r2.length;
-                if (len1 != len2) return false; //Short circuit return
-
-                // Lengths are the same, so we need to do an actual comparison.
-                // Good news is we can squeeze out a bit of performance by not checking if r2 is empty.
-                for (; !r1.empty; r1.popFront(), r2.popFront())
-                {
-                    if (!binaryFun!(pred)(r1.front, r2.front)) return false;
-                }
-                return true;
+                    return allByDchar!(done + 1)(rs[0 .. done], rs[done].byDchar, rs[done + 1 .. $]);
             }
+            return allByDchar!0(rs);
+        }
+        else static if (is(typeof(pred) == string) && pred == "a == b" &&
+                allSatisfy!(isArray, Ranges) && allSatisfy!(comparableWithEq, rs))
+        {
+            static foreach (r; rs[1 .. $])
+                if (rs[0] != r)
+                    return false;
+            return true;
+        }
+        // if one of the arguments is a string and the other isn't, then auto-decoding
+        // can be avoided if they have the same ElementEncodingType
+        // TODO: generalize this
+        else static if (rs.length == 2 && is(typeof(pred) == string) && pred == "a == b" &&
+                isAutodecodableString!(Ranges[0]) != isAutodecodableString!(Ranges[1]) &&
+                is(immutable ElementEncodingType!(Ranges[0]) == immutable ElementEncodingType!(Ranges[1])))
+        {
+            import std.utf : byCodeUnit;
+            static if (isAutodecodableString!(Ranges[0]))
+                return equal(rs[0].byCodeUnit, rs[1]);
             else
+                return equal(rs[1].byCodeUnit, rs[0]);
+        }
+        else
+        {
+            static foreach (i, R; Ranges)
             {
-                //Generic case, we have to walk both ranges making sure neither is empty
-                for (; !r1.empty; r1.popFront(), r2.popFront())
+                static if (hasLength!R)
                 {
-                    if (r2.empty || !binaryFun!(pred)(r1.front, r2.front)) return false;
+                    static if (!is(typeof(firstLength)))
+                    {
+                        // Found the first range that has length
+                        auto firstLength = rs[i].length;
+                    }
+                    else
+                    {
+                        // Compare the length of the current range against the first with length
+                        if (firstLength != rs[i].length)
+                            return false;
+                    }
                 }
-                return r2.empty;
             }
+            return equalLoop(rs);
         }
     }
+
+    private bool equalLoop(Rs...)(Rs rs)
+    {
+        for (; !rs[0].empty; rs[0].popFront)
+            static foreach (r; rs[1 .. $])
+                if (r.empty || !binaryFun!pred(rs[0].front, r.front))
+                    return false;
+                else
+                    r.popFront;
+        static foreach (r; rs[1 .. $])
+            if (!r.empty)
+                return false;
+        return true;
+    }
 }
 
 ///
@@ -992,6 +1063,31 @@  template equal(alias pred = "a == b")
     assert(equal!isClose(b[], c[]));
 }
 
+@safe @nogc unittest
+{
+    import std.algorithm.comparison : equal;
+    import std.math.operations : isClose;
+
+    auto s1 = "abc", s2 = "abc"w;
+    assert(equal(s1, s2, s2));
+    assert(equal(s1, s2, s2, s1));
+    assert(!equal(s1, s2, s2[1 .. $]));
+
+    int[4] a = [ 1, 2, 4, 3 ];
+    assert(!equal(a[], a[1..$], a[]));
+    assert(equal(a[], a[], a[]));
+    assert(equal!((a, b) => a == b)(a[], a[], a[]));
+
+    // different types
+    double[4] b = [ 1.0, 2, 4, 3];
+    assert(!equal(a[], b[1..$], b[]));
+    assert(equal(a[], b[], a[], b[]));
+
+    // predicated: ensure that two vectors are approximately equal
+    double[4] c = [ 1.0000000005, 2, 4, 3];
+    assert(equal!isClose(b[], c[], b[]));
+}
+
 /++
 Tip: `equal` can itself be used as a predicate to other functions.
 This can be very useful when the element type of a range is itself a
@@ -1748,21 +1844,26 @@  store the lowest values.
 
 // mismatch
 /**
-Sequentially compares elements in `r1` and `r2` in lockstep, and
+Sequentially compares elements in `rs` in lockstep, and
 stops at the first mismatch (according to `pred`, by default
 equality). Returns a tuple with the reduced ranges that start with the
-two mismatched values. Performs $(BIGOH min(r1.length, r2.length))
+two mismatched values. Performs $(BIGOH min(r[0].length, r[1].length, ...))
 evaluations of `pred`.
 */
-Tuple!(Range1, Range2)
-mismatch(alias pred = "a == b", Range1, Range2)(Range1 r1, Range2 r2)
-if (isInputRange!(Range1) && isInputRange!(Range2))
+Tuple!(Ranges)
+mismatch(alias pred = (a, b) => a == b, Ranges...)(Ranges rs)
+if (rs.length >= 2 && allSatisfy!(isInputRange, Ranges))
 {
-    for (; !r1.empty && !r2.empty; r1.popFront(), r2.popFront())
+    loop: for (; !rs[0].empty; rs[0].popFront)
     {
-        if (!binaryFun!(pred)(r1.front, r2.front)) break;
+        static foreach (r; rs[1 .. $])
+        {
+            if (r.empty || !binaryFun!pred(rs[0].front, r.front))
+                break loop;
+            r.popFront;
+        }
     }
-    return tuple(r1, r2);
+    return tuple(rs);
 }
 
 ///
@@ -1773,6 +1874,12 @@  if (isInputRange!(Range1) && isInputRange!(Range2))
     auto m = mismatch(x[], y[]);
     assert(m[0] == x[3 .. $]);
     assert(m[1] == y[3 .. $]);
+
+    auto m2 = mismatch(x[], y[], x[], y[]);
+    assert(m2[0] == x[3 .. $]);
+    assert(m2[1] == y[3 .. $]);
+    assert(m2[2] == x[3 .. $]);
+    assert(m2[3] == y[3 .. $]);
 }
 
 @safe @nogc unittest
@@ -1925,50 +2032,91 @@  auto predSwitch(alias pred = "a == b", T, R ...)(T switchExpression, lazy R choi
 }
 
 /**
-Checks if the two ranges have the same number of elements. This function is
+Checks if two or more ranges have the same number of elements. This function is
 optimized to always take advantage of the `length` member of either range
 if it exists.
 
-If both ranges have a length member, this function is $(BIGOH 1). Otherwise,
-this function is $(BIGOH min(r1.length, r2.length)).
+If all ranges have a `length` member or at least one is infinite,
+`_isSameLength`'s complexity is $(BIGOH 1). Otherwise, complexity is
+$(BIGOH n), where `n` is the smallest of the lengths of ranges with unknown
+length.
 
-Infinite ranges are considered of the same length. An infinite range has never the same length as a
-finite range.
+Infinite ranges are considered of the same length. An infinite range has never
+the same length as a finite range.
 
 Params:
-    r1 = a finite $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
-    r2 = a finite $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
+    rs = two or more $(REF_ALTTEXT input ranges, isInputRange, std,range,primitives)
 
 Returns:
     `true` if both ranges have the same length, `false` otherwise.
 */
-bool isSameLength(Range1, Range2)(Range1 r1, Range2 r2)
-if (isInputRange!Range1 && isInputRange!Range2)
+bool isSameLength(Ranges...)(Ranges rs)
+if (allSatisfy!(isInputRange, Ranges))
 {
-    static if (isInfinite!Range1 || isInfinite!Range2)
-    {
-        return isInfinite!Range1 && isInfinite!Range2;
-    }
-    else static if (hasLength!(Range1) && hasLength!(Range2))
+    static if (anySatisfy!(isInfinite, Ranges))
     {
-        return r1.length == r2.length;
+        return allSatisfy!(isInfinite, Ranges);
     }
-    else static if (hasLength!(Range1) && !hasLength!(Range2))
+    else static if (anySatisfy!(hasLength, Ranges))
     {
-        return r2.walkLength(r1.length + 1) == r1.length;
-    }
-    else static if (!hasLength!(Range1) && hasLength!(Range2))
-    {
-        return r1.walkLength(r2.length + 1) == r2.length;
+        // Compute the O(1) length
+        auto baselineLength = size_t.max;
+        static foreach (i, R; Ranges)
+        {
+            static if (hasLength!R)
+            {
+                if (baselineLength == size_t.max)
+                    baselineLength = rs[i].length;
+                else if (rs[i].length != baselineLength)
+                    return false;
+            }
+        }
+        // Iterate all ranges without known length
+        foreach (_; 0 .. baselineLength)
+            static foreach (i, R; Ranges)
+            {
+                static if (!hasLength!R)
+                {
+                    // All must be non-empty
+                    if (rs[i].empty)
+                        return false;
+                    rs[i].popFront;
+                }
+            }
+        static foreach (i, R; Ranges)
+        {
+            static if (!hasLength!R)
+            {
+                // All must be now empty
+                if (!rs[i].empty)
+                    return false;
+            }
+        }
+        return true;
     }
     else
     {
-        for (; !r1.empty; r1.popFront, r2.popFront)
-        {
-           if (r2.empty)
-              return false;
-        }
-        return r2.empty;
+        // All have unknown length, iterate in lockstep
+        for (;;)
+            static foreach (i, r; rs)
+            {
+                if (r.empty)
+                {
+                    // One is empty, so all must be empty
+                    static if (i != 0)
+                    {
+                        return false;
+                    }
+                    else
+                    {
+                        static foreach (j, r1; rs[1 .. $])
+                            if (!r1.empty)
+                                return false;
+                        return true;
+                    }
+                }
+                r.popFront;
+            }
     }
 }
 
@@ -1976,34 +2124,42 @@  if (isInputRange!Range1 && isInputRange!Range2)
 @safe nothrow pure unittest
 {
     assert(isSameLength([1, 2, 3], [4, 5, 6]));
+    assert(isSameLength([1, 2, 3], [4, 5, 6], [7, 8, 9]));
     assert(isSameLength([0.3, 90.4, 23.7, 119.2], [42.6, 23.6, 95.5, 6.3]));
     assert(isSameLength("abc", "xyz"));
+    assert(isSameLength("abc", "xyz", [1, 2, 3]));
 
     int[] a;
     int[] b;
     assert(isSameLength(a, b));
+    assert(isSameLength(a, b, a, a, b, b, b));
 
     assert(!isSameLength([1, 2, 3], [4, 5]));
+    assert(!isSameLength([1, 2, 3], [4, 5, 6], [7, 8]));
     assert(!isSameLength([0.3, 90.4, 23.7], [42.6, 23.6, 95.5, 6.3]));
     assert(!isSameLength("abcd", "xyz"));
+    assert(!isSameLength("abcd", "xyz", "123"));
+    assert(!isSameLength("abcd", "xyz", "1234"));
 }
 
 // Test CTFE
 @safe @nogc pure @betterC unittest
 {
-    enum result1 = isSameLength([1, 2, 3], [4, 5, 6]);
-    static assert(result1);
-
-    enum result2 = isSameLength([0.3, 90.4, 23.7], [42.6, 23.6, 95.5, 6.3]);
-    static assert(!result2);
+    static assert(isSameLength([1, 2, 3], [4, 5, 6]));
+    static assert(isSameLength([1, 2, 3], [4, 5, 6], [7, 8, 9]));
+    static assert(!isSameLength([0.3, 90.4, 23.7], [42.6, 23.6, 95.5, 6.3]));
+    static assert(!isSameLength([1], [0.3, 90.4], [42]));
 }
 
 @safe @nogc pure unittest
 {
     import std.range : only;
     assert(isSameLength(only(1, 2, 3), only(4, 5, 6)));
+    assert(isSameLength(only(1, 2, 3), only(4, 5, 6), only(7, 8, 9)));
     assert(isSameLength(only(0.3, 90.4, 23.7, 119.2), only(42.6, 23.6, 95.5, 6.3)));
     assert(!isSameLength(only(1, 3, 3), only(4, 5)));
+    assert(!isSameLength(only(1, 3, 3), only(1, 3, 3), only(4, 5)));
+    assert(!isSameLength(only(1, 3, 3), only(4, 5), only(1, 3, 3)));
 }
 
 @safe nothrow pure unittest
@@ -2033,6 +2189,15 @@  if (isInputRange!Range1 && isInputRange!Range2)
     DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Input) r11;
     auto r12 = new ReferenceInputRange!int([1, 2, 3, 4, 5, 6, 7, 8]);
     assert(!isSameLength(r11, r12));
+
+    import std.algorithm.iteration : filter;
+
+    assert(isSameLength(filter!"a >= 1"([1, 2, 3]), [4, 5, 6]));
+    assert(!isSameLength(filter!"a > 1"([1, 2, 3]), [4, 5, 6]));
+
+    assert(isSameLength(filter!"a > 1"([1, 2, 3]), filter!"a > 4"([4, 5, 6])));
+    assert(isSameLength(filter!"a > 1"([1, 2, 3]),
+        filter!"a > 4"([4, 5, 6]), filter!"a >= 5"([4, 5, 6])));
 }
 
 // Still functional but not documented anymore.
diff --git a/libphobos/src/std/algorithm/iteration.d b/libphobos/src/std/algorithm/iteration.d
index c3e848760ed..9e728e4622f 100644
--- a/libphobos/src/std/algorithm/iteration.d
+++ b/libphobos/src/std/algorithm/iteration.d
@@ -77,51 +77,6 @@  import std.range.primitives;
 import std.traits;
 import std.typecons : Flag, Yes, No;
 
-private template aggregate(fun...)
-if (fun.length >= 1)
-{
-    /* --Intentionally not ddoc--
-     * Aggregates elements in each subrange of the given range of ranges using
-     * the given aggregating function(s).
-     * Params:
-     *  fun = One or more aggregating functions (binary functions that return a
-     *      single _aggregate value of their arguments).
-     *  ror = A range of ranges to be aggregated.
-     *
-     * Returns:
-     * A range representing the aggregated value(s) of each subrange
-     * of the original range. If only one aggregating function is specified,
-     * each element will be the aggregated value itself; if multiple functions
-     * are specified, each element will be a tuple of the aggregated values of
-     * each respective function.
-     */
-    auto aggregate(RoR)(RoR ror)
-        if (isInputRange!RoR && isIterable!(ElementType!RoR))
-    {
-        return ror.map!(reduce!fun);
-    }
-
-    @safe unittest
-    {
-        import std.algorithm.comparison : equal, max, min;
-
-        auto data = [[4, 2, 1, 3], [4, 9, -1, 3, 2], [3]];
-
-        // Single aggregating function
-        auto agg1 = data.aggregate!max;
-        assert(agg1.equal([4, 9, 3]));
-
-        // Multiple aggregating functions
-        import std.typecons : tuple;
-        auto agg2 = data.aggregate!(max, min);
-        assert(agg2.equal([
-            tuple(4, 1),
-            tuple(9, -1),
-            tuple(3, 3)
-        ]));
-    }
-}
-
 /++
 `cache` eagerly evaluates $(REF_ALTTEXT front, front, std,range,primitives) of `range`
 on each construction or call to $(REF_ALTTEXT popFront, popFront, std,range,primitives),
@@ -2029,23 +1984,39 @@  private struct ChunkByGroup(alias eq, Range, bool eqEquivalenceAssured)
     }
     private Range  current;
 
-    private RefCounted!(OuterRange) mothership;
+    // using union prevents RefCounted destructor from propagating @system to
+    // user code
+    union { private RefCounted!(OuterRange) mothership; }
+    private @trusted ref cargo() { return mothership.refCountedPayload; }
 
-    this(RefCounted!(OuterRange) origin)
+    private this(ref RefCounted!(OuterRange) origin)
     {
-        groupNum = origin.groupNum;
-        current = origin.current.save;
+        () @trusted { mothership = origin; }();
+        groupNum = cargo.groupNum;
+        current = cargo.current.save;
         assert(!current.empty, "Passed range 'r' must not be empty");
+
         static if (eqEquivalenceAssured)
         {
-            start = origin.current.save;
+            start = cargo.current.save;
 
             // Check for reflexivity.
             assert(eq(start.front, current.front),
                 "predicate is not reflexive");
         }
+    }
+
+    // Cannot be a copy constructor due to issue 22239
+    this(this) @trusted
+    {
+        import core.lifetime : emplace;
+        // since mothership has to be in a union, we have to manually trigger
+        // an increment to the reference count.
+        auto temp = mothership;
+        mothership = temp;
 
-        mothership = origin;
+        // prevents the reference count from falling back with brute force
+        emplace(&temp);
     }
 
     @property bool empty() { return groupNum == size_t.max; }
@@ -2073,14 +2044,14 @@  private struct ChunkByGroup(alias eq, Range, bool eqEquivalenceAssured)
 
         if (nowEmpty)
         {
-            if (groupNum == mothership.groupNum)
+            if (groupNum == cargo.groupNum)
             {
                 // If parent range hasn't moved on yet, help it along by
                 // saving location of start of next Group.
-                mothership.next = current.save;
+                cargo.next = current.save;
                 static if (!eqEquivalenceAssured)
                 {
-                    mothership.nextUpdated = true;
+                    cargo.nextUpdated = true;
                 }
             }
 
@@ -2094,6 +2065,11 @@  private struct ChunkByGroup(alias eq, Range, bool eqEquivalenceAssured)
         copy.current = current.save;
         return copy;
     }
+
+    @trusted ~this()
+    {
+        mothership.destroy;
+    }
 }
 
 private enum GroupingOpType{binaryEquivalent, binaryAny, unary}
@@ -2110,23 +2086,48 @@  if (isForwardRange!Range)
 
     static assert(isForwardRange!InnerRange);
 
-    private RefCounted!OuterRange impl;
+    // using union prevents RefCounted destructor from propagating @system to
+    // user code
+    union { private RefCounted!OuterRange _impl; }
+    private @trusted ref impl() { return _impl; }
+    private @trusted ref implPL() { return _impl.refCountedPayload; }
 
     this(Range r)
     {
-        static if (eqEquivalenceAssured)
+        import core.lifetime : move;
+
+        auto savedR = r.save;
+
+        static if (eqEquivalenceAssured) () @trusted
         {
-            impl = RefCounted!OuterRange(0, r, r.save);
-        }
-        else impl = RefCounted!OuterRange(0, r, r.save, false);
+            _impl = RefCounted!OuterRange(0, r, savedR.move);
+        }();
+        else () @trusted
+        {
+            _impl = RefCounted!OuterRange(0, r, savedR.move, false);
+        }();
+    }
+
+    // Cannot be a copy constructor due to issue 22239
+    this(this) @trusted
+    {
+        import core.lifetime : emplace;
+        // since _impl has to be in a union, we have to manually trigger
+        // an increment to the reference count.
+        auto temp = _impl;
+        _impl = temp;
+
+        // prevents the reference count from falling back with brute force
+        emplace(&temp);
     }
 
-    @property bool empty() { return impl.current.empty; }
+    @property bool empty() { return implPL.current.empty; }
 
     static if (opType == GroupingOpType.unary) @property auto front()
     {
         import std.typecons : tuple;
-        return tuple(unaryFun!pred(impl.current.front), InnerRange(impl));
+
+        return tuple(unaryFun!pred(implPL.current.front), InnerRange(impl));
     }
     else @property auto front()
     {
@@ -2138,48 +2139,53 @@  if (isForwardRange!Range)
         // Scan for next group. If we're lucky, one of our Groups would have
         // already set .next to the start of the next group, in which case the
         // loop is skipped.
-        while (!impl.next.empty && eq(impl.current.front, impl.next.front))
+        while (!implPL.next.empty && eq(implPL.current.front, implPL.next.front))
         {
-            impl.next.popFront();
+            implPL.next.popFront();
         }
 
-        impl.current = impl.next.save;
+        implPL.current = implPL.next.save;
 
         // Indicate to any remaining Groups that we have moved on.
-        impl.groupNum++;
+        implPL.groupNum++;
     }
     else void popFront()
     {
-        if (impl.nextUpdated)
+        if (implPL.nextUpdated)
         {
-            impl.current = impl.next.save;
+            implPL.current = implPL.next.save;
         }
         else while (true)
         {
-            auto prevElement = impl.current.front;
-            impl.current.popFront();
-            if (impl.current.empty) break;
-            if (!eq(prevElement, impl.current.front)) break;
+            auto prevElement = implPL.current.front;
+            implPL.current.popFront();
+            if (implPL.current.empty) break;
+            if (!eq(prevElement, implPL.current.front)) break;
         }
 
-        impl.nextUpdated = false;
+        implPL.nextUpdated = false;
         // Indicate to any remaining Groups that we have moved on.
-        impl.groupNum++;
+        implPL.groupNum++;
     }
 
     @property auto save()
     {
         // Note: the new copy of the range will be detached from any existing
         // satellite Groups, and will not benefit from the .next acceleration.
-        return typeof(this)(impl.current.save);
+        return typeof(this)(implPL.current.save);
     }
 
     static assert(isForwardRange!(typeof(this)), typeof(this).stringof
             ~ " must be a forward range");
+
+    @trusted ~this()
+    {
+        _impl.destroy;
+    }
 }
 
 //Test for https://issues.dlang.org/show_bug.cgi?id=14909
-@system unittest
+@safe unittest
 {
     import std.algorithm.comparison : equal;
     import std.typecons : tuple;
@@ -2192,8 +2198,36 @@  if (isForwardRange!Range)
     assert(u.equal!equal([[1],[2],[3]]));
 }
 
+//Testing inferring @system correctly
+@safe unittest
+{
+    struct DeadlySave
+    {
+        int front;
+        @safe void popFront(){front++;}
+        @safe bool empty(){return front >= 5;}
+        @system auto save(){return this;}
+    }
+
+    auto test1()
+    {
+        DeadlySave src;
+        return src.walkLength;
+
+    }
+
+    auto test2()
+    {
+        DeadlySave src;
+        return src.chunkBy!((a,b) => a % 2 == b % 2).walkLength;
+    }
+
+    static assert(isSafe!test1);
+    static assert(!isSafe!test2);
+}
+
 //Test for https://issues.dlang.org/show_bug.cgi?id=18751
-@system unittest
+@safe unittest
 {
     import std.algorithm.comparison : equal;
 
@@ -2205,7 +2239,7 @@  if (isForwardRange!Range)
 }
 
 //Additional test for fix for issues 14909 and 18751
-@system unittest
+@safe unittest
 {
     import std.algorithm.comparison : equal;
     auto v = [2,4,8,3,6,9,1,5,7];
@@ -2329,7 +2363,7 @@  if (isInputRange!Range)
 }
 
 /// Showing usage with binary predicate:
-/*FIXME: @safe*/ @system unittest
+@safe unittest
 {
     import std.algorithm.comparison : equal;
 
@@ -2356,7 +2390,7 @@  if (isInputRange!Range)
 }
 
 /// Showing usage with unary predicate:
-/* FIXME: pure @safe nothrow*/ @system unittest
+/* FIXME: pure nothrow*/ @safe unittest
 {
     import std.algorithm.comparison : equal;
     import std.range.primitives;
@@ -2755,7 +2789,7 @@  if (isInputRange!Range)
 
 
 // https://issues.dlang.org/show_bug.cgi?id=13805
-@system unittest
+@safe unittest
 {
     [""].map!((s) => s).chunkBy!((x, y) => true);
 }
@@ -2790,9 +2824,8 @@  if (isForwardRange!Range)
     return ChunkByImpl!(not!pred, not!pred, GroupingOpType.binaryAny, Range)(r);
 }
 
-//FIXME: these should be @safe
 ///
-nothrow pure @system unittest
+nothrow pure @safe unittest
 {
     import std.algorithm.comparison : equal;
     import std.range : dropExactly;
@@ -2816,7 +2849,7 @@  nothrow pure @system unittest
 }
 
 //ensure we don't iterate the underlying range twice
-nothrow @system unittest
+nothrow @safe unittest
 {
     import std.algorithm.comparison : equal;
     import std.math.algebraic : abs;
@@ -2827,7 +2860,7 @@  nothrow @system unittest
         static int popfrontsSoFar;
 
         auto front(){return elements[0];}
-        nothrow void popFront()
+        nothrow @safe void popFront()
         {   popfrontsSoFar++;
             elements = elements[1 .. $];
         }
@@ -2851,7 +2884,7 @@  nothrow @system unittest
 }
 
 // Issue 13595
-@system unittest
+@safe unittest
 {
     import std.algorithm.comparison : equal;
     auto r = [1, 2, 3, 4, 5, 6, 7, 8, 9].splitWhen!((x, y) => ((x*y) % 3) > 0);
@@ -2863,7 +2896,7 @@  nothrow @system unittest
     ]));
 }
 
-nothrow pure @system unittest
+nothrow pure @safe unittest
 {
     // Grouping by maximum adjacent difference:
     import std.math.algebraic : abs;
@@ -3654,10 +3687,18 @@  if (isInputRange!RoR && isInputRange!(ElementType!RoR))
         {
             @property auto save()
             {
-                auto r = Result(_items.save, _current.save);
+                // the null check is important if it is a class range, since null.save will segfault; issue #22359
+                // could not just compare x is y here without static if due to a compiler assertion failure
+                static if (is(typeof(null) : typeof(_current)))
+                    auto r = Result(_items.save, _current is null ? null : _current.save);
+                else
+                    auto r = Result(_items.save, _current.save);
                 static if (isBidirectional)
                 {
-                    r._currentBack = _currentBack.save;
+                    static if (is(typeof(null) : typeof(_currentBack)))
+                        r._currentBack = _currentBack is null ? null : _currentBack.save;
+                    else
+                        r._currentBack = _currentBack.save;
                     r.reachedFinalElement = reachedFinalElement;
                 }
                 return r;
@@ -3838,6 +3879,26 @@  if (isInputRange!RoR && isInputRange!(ElementType!RoR))
     static assert(isForwardRange!(typeof(joiner([""]))));
 }
 
+@system unittest
+{
+    // this test is system because the virtual interface call to save
+    // is flexible and thus cannot be inferred safe automatically
+
+    // https://issues.dlang.org/show_bug.cgi?id=22359
+    import std.range;
+    ForwardRange!int bug(int[][] r)
+    {
+        import std.range : inputRangeObject;
+        import std.algorithm.iteration : map, joiner;
+
+        auto range = inputRangeObject(r);
+
+        return range.map!(a =>inputRangeObject(a)).joiner.inputRangeObject;
+    }
+    auto f = bug([[]]);
+    f.save(); // should not segfault
+}
+
 @safe unittest
 {
     // Initial version of PR #6115 caused a compilation failure for
diff --git a/libphobos/src/std/algorithm/mutation.d b/libphobos/src/std/algorithm/mutation.d
index 88191bbf3f7..07cbb9b9823 100644
--- a/libphobos/src/std/algorithm/mutation.d
+++ b/libphobos/src/std/algorithm/mutation.d
@@ -1427,7 +1427,7 @@  private void moveEmplaceImpl(T)(ref scope T target, ref return scope T source)
     {
         import std.exception : doesPointTo;
         assert(!(doesPointTo(source, source) && !hasElaborateMove!T),
-            "Cannot move object with internal pointer unless `opPostMove` is defined.");
+            "Cannot move object of type " ~ T.stringof ~ " with internal pointer unless `opPostMove` is defined.");
     }
 
     static if (is(T == struct))
diff --git a/libphobos/src/std/algorithm/searching.d b/libphobos/src/std/algorithm/searching.d
index d6d02bad3bb..96352064c55 100644
--- a/libphobos/src/std/algorithm/searching.d
+++ b/libphobos/src/std/algorithm/searching.d
@@ -122,7 +122,9 @@  template all(alias pred = "a")
     if (isInputRange!Range)
     {
         static assert(is(typeof(unaryFun!pred(range.front))),
-                "`" ~ pred.stringof[1..$-1] ~ "` isn't a unary predicate function for range.front");
+                "`" ~ (isSomeString!(typeof(pred))
+                    ? pred.stringof[1..$-1] : pred.stringof)
+                ~ "` isn't a unary predicate function for range.front");
         import std.functional : not;
 
         return find!(not!(unaryFun!pred))(range).empty;
@@ -3572,6 +3574,8 @@  Params:
     r = range from which the minimal element will be selected
     seed = custom seed to use as initial element
 
+Precondition: If a seed is not given, `r` must not be empty.
+
 Returns: The minimal element of the passed-in range.
 
 Note:
@@ -3723,6 +3727,8 @@  Params:
     r = range from which the maximum element will be selected
     seed = custom seed to use as initial element
 
+Precondition: If a seed is not given, `r` must not be empty.
+
 Returns: The maximal element of the passed-in range.
 
 Note:
diff --git a/libphobos/src/std/algorithm/sorting.d b/libphobos/src/std/algorithm/sorting.d
index dbfe37f2fb0..f2877ccbdf4 100644
--- a/libphobos/src/std/algorithm/sorting.d
+++ b/libphobos/src/std/algorithm/sorting.d
@@ -2209,7 +2209,7 @@  package(std) template HeapOps(alias less, Range)
         ~ " RandomAccessRange");
     static assert(hasLength!Range, Range.stringof ~ " must have length");
     static assert(hasSwappableElements!Range || hasAssignableElements!Range,
-        Range.stringof ~ " must have swappable of assignable Elements");
+        Range.stringof ~ " must have swappable or assignable Elements");
 
     alias lessFun = binaryFun!less;
 
@@ -2329,8 +2329,8 @@  private template TimSortImpl(alias pred, R)
         ~ " RandomAccessRange");
     static assert(hasLength!R, R.stringof ~ " must have a length");
     static assert(hasSlicing!R, R.stringof ~ " must support slicing");
-    static assert(hasAssignableElements!R, R.stringof ~ " must support"
-        ~ " assigning elements");
+    static assert(hasAssignableElements!R, R.stringof ~ " must have"
+        ~ " assignable elements");
 
     alias T = ElementType!R;
 
@@ -3571,7 +3571,7 @@  void topNImpl(alias less, R)(R r, size_t n, ref bool useSampling)
 private size_t topNPartition(alias lp, R)(R r, size_t n, bool useSampling)
 {
     import std.format : format;
-    assert(r.length >= 9 && n < r.length, "length must be longer than 9"
+    assert(r.length >= 9 && n < r.length, "length must be longer than 8"
         ~ " and n must be less than r.length");
     immutable ninth = r.length / 9;
     auto pivot = ninth / 2;
@@ -4220,8 +4220,8 @@  if (isRandomAccessRange!Range && hasLength!Range &&
     Indexes.length >= 2 && Indexes.length <= 5 &&
     allSatisfy!(isUnsigned, Indexes))
 {
-    assert(r.length >= Indexes.length, "r.length must be greater equal to"
-        ~ " Indexes.length");
+    assert(r.length >= Indexes.length, "r.length must be greater than or"
+        ~ " equal to Indexes.length");
     import std.functional : binaryFun;
     alias lt = binaryFun!less;
     enum k = Indexes.length;
diff --git a/libphobos/src/std/array.d b/libphobos/src/std/array.d
index ded1196da52..ffdda8e1d4c 100644
--- a/libphobos/src/std/array.d
+++ b/libphobos/src/std/array.d
@@ -259,6 +259,19 @@  if (isPointer!Range && isIterable!(PointerTarget!Range) && !isAutodecodableStrin
     )));
 }
 
+// https://issues.dlang.org/show_bug.cgi?id=20937
+@safe pure nothrow unittest
+{
+    struct S {int* x;}
+    struct R
+    {
+        immutable(S) front;
+        bool empty;
+        @safe pure nothrow void popFront(){empty = true;}
+    }
+    R().array;
+}
+
 /**
 Convert a narrow autodecoding string to an array type that fully supports
 random access.  This is handled as a special case and always returns an array
@@ -1609,7 +1622,7 @@  private template isInputRangeOrConvertible(E)
         `true` if $(D lhs.ptr == rhs.ptr), `false` otherwise.
   +/
 @safe
-pure nothrow bool sameHead(T)(in T[] lhs, in T[] rhs)
+pure nothrow @nogc bool sameHead(T)(in T[] lhs, in T[] rhs)
 {
     return lhs.ptr == rhs.ptr;
 }
@@ -1637,7 +1650,7 @@  pure nothrow bool sameHead(T)(in T[] lhs, in T[] rhs)
         `false` otherwise.
   +/
 @trusted
-pure nothrow bool sameTail(T)(in T[] lhs, in T[] rhs)
+pure nothrow @nogc bool sameTail(T)(in T[] lhs, in T[] rhs)
 {
     return lhs.ptr + lhs.length == rhs.ptr + rhs.length;
 }
@@ -3492,13 +3505,14 @@  if (isDynamicArray!A)
         }
         else
         {
-            import core.internal.lifetime : emplaceRef;
+            import core.lifetime : emplace;
 
             ensureAddable(1);
             immutable len = _data.arr.length;
 
             auto bigData = (() @trusted => _data.arr.ptr[0 .. len + 1])();
-            emplaceRef!(Unqual!T)(bigData[len], cast() item);
+            auto itemUnqual = (() @trusted => & cast() item)();
+            emplace(&bigData[len], *itemUnqual);
             //We do this at the end, in case of exceptions
             _data.arr = bigData;
         }
diff --git a/libphobos/src/std/bitmanip.d b/libphobos/src/std/bitmanip.d
index 2dd6211aa7c..9af9d721230 100644
--- a/libphobos/src/std/bitmanip.d
+++ b/libphobos/src/std/bitmanip.d
@@ -2948,12 +2948,12 @@  if (isIntegral!T || isSomeChar!T || isBoolean!T)
 private union EndianSwapper(T)
 if (canSwapEndianness!T)
 {
-    Unqual!T value;
+    T value;
     ubyte[T.sizeof] array;
 
-    static if (is(FloatingPointTypeOf!(Unqual!T) == float))
+    static if (is(immutable FloatingPointTypeOf!(T) == immutable float))
         uint  intValue;
-    else static if (is(FloatingPointTypeOf!(Unqual!T) == double))
+    else static if (is(immutable FloatingPointTypeOf!(T) == immutable double))
         ulong intValue;
 
 }
diff --git a/libphobos/src/std/concurrency.d b/libphobos/src/std/concurrency.d
index d101ce4abf4..a9830af61a2 100644
--- a/libphobos/src/std/concurrency.d
+++ b/libphobos/src/std/concurrency.d
@@ -484,7 +484,7 @@  private template isSpawnable(F, T...)
             enum isParamsImplicitlyConvertible = false;
     }
 
-    enum isSpawnable = isCallable!F && is(ReturnType!F == void)
+    enum isSpawnable = isCallable!F && is(ReturnType!F : void)
             && isParamsImplicitlyConvertible!(F, void function(T))
             && (isFunctionPointer!F || !hasUnsharedAliasing!F);
 }
@@ -1573,10 +1573,9 @@  private:
             this.outer.yield();
         }
 
-        private bool notified;
+        bool notified;
     }
 
-private:
     void dispatch()
     {
         import std.algorithm.mutation : remove;
@@ -1600,7 +1599,6 @@  private:
         }
     }
 
-private:
     Fiber[] m_fibers;
     size_t m_pos;
 }
@@ -1919,48 +1917,53 @@  void yield(T)(T value)
     import core.exception;
     import std.exception;
 
-    static void testScheduler(Scheduler s)
-    {
-        scheduler = s;
-        scheduler.start({
-            auto tid = spawn({
-                int i;
-
-                try
+    auto mainTid = thisTid;
+    alias testdg = () {
+        auto tid = spawn(
+        (Tid mainTid) {
+            int i;
+            scope (failure) mainTid.send(false);
+            try
+            {
+                for (i = 1; i < 10; i++)
                 {
-                    for (i = 1; i < 10; i++)
+                    if (receiveOnly!int() != i)
                     {
-                        assertNotThrown!AssertError(assert(receiveOnly!int() == i));
+                        mainTid.send(false);
+                        break;
                     }
                 }
-                catch (OwnerTerminated e)
-                {
-
-                }
-
-                // i will advance 1 past the last value expected
-                assert(i == 4);
-            });
-
-            auto r = new Generator!int({
-                assertThrown!Exception(yield(2.0));
-                yield(); // ensure this is a no-op
-                yield(1);
-                yield(); // also once something has been yielded
-                yield(2);
-                yield(3);
-            });
-
-            foreach (e; r)
+            }
+            catch (OwnerTerminated e)
             {
-                tid.send(e);
+                // i will advance 1 past the last value expected
+                mainTid.send(i == 4);
             }
+        }, mainTid);
+        auto r = new Generator!int(
+        {
+            assertThrown!Exception(yield(2.0));
+            yield(); // ensure this is a no-op
+            yield(1);
+            yield(); // also once something has been yielded
+            yield(2);
+            yield(3);
         });
-        scheduler = null;
-    }
 
-    testScheduler(new ThreadScheduler);
-    testScheduler(new FiberScheduler);
+        foreach (e; r)
+        {
+            tid.send(e);
+        }
+    };
+
+    scheduler = new ThreadScheduler;
+    scheduler.spawn(testdg);
+    assert(receiveOnly!bool());
+
+    scheduler = new FiberScheduler;
+    scheduler.start(testdg);
+    assert(receiveOnly!bool());
+    scheduler = null;
 }
 ///
 @system unittest
diff --git a/libphobos/src/std/container/array.d b/libphobos/src/std/container/array.d
index 58de5b7e8b4..63dc86403ec 100644
--- a/libphobos/src/std/container/array.d
+++ b/libphobos/src/std/container/array.d
@@ -24,6 +24,61 @@  import std.traits;
 
 public import std.container.util;
 
+pure @system unittest
+{
+    // We test multiple array lengths in order to ensure that the "a1.capacity == a0.length" test is meaningful
+    // for the version in which the constructor uses insertBack
+    // (because for some lengths, the test passes even without reserve).
+    for (size_t n = 0; n < 100; ++n)
+    {
+        float[] a0;
+        {
+            import std.range : iota;
+            import std.array;
+            import std.algorithm.iteration : map;
+            a0 = iota (0, n).map!(i => i * 1.1f).array;
+        }
+
+        auto a1 = Array!float(a0);
+
+        // We check that a1 has the same length and contents as a0:
+        {
+            assert(a1.length == a0.length);
+
+            // I wish that I could write "assert(a1[] == a0[]);",
+            // but the compiler complains: "Error: incompatible types for `(a1.opSlice()) == (a0[])`: `RangeT!(Array!float)` and `float[]`".
+            import std.algorithm.comparison : equal;
+            assert(equal(a1[], a0[]));
+        }
+
+        // We check that a1's constructor has called reserve (to maintain good performance):
+        assert(a1.capacity == a0.length);
+    }
+}
+
+pure @system unittest
+{
+    // To avoid bad performance, we check that an Array constructed from an empty range
+    // does not initialize its RefCountedStore object, even after a call to "reserve(0)".
+
+    {
+        Array!float a1;
+        assert(! a1._data.refCountedStore.isInitialized);
+        a1.reserve(0);
+        assert(! a1._data.refCountedStore.isInitialized);
+    }
+
+    {
+        float[] a0 = [];
+        Array!float a1 = a0;
+        // [2021-09-26] TODO: Investigate RefCounted.
+        //assert(! a1._data.refCountedStore.isInitialized);
+        a1.reserve(0);
+        // [2021-09-26] TODO: Investigate RefCounted.
+        //assert(! a1._data.refCountedStore.isInitialized);
+    }
+}
+
 ///
 pure @system unittest
 {
@@ -246,6 +301,70 @@  private struct RangeT(A)
     }
 }
 
+@system unittest
+{
+    enum : bool { display = false }
+    static if (display)
+    {
+        import std.stdio;
+        enum { nDigitsForPointer = 2 * size_t.sizeof, nDigitsForNObjects = 4 }
+    }
+
+    static struct S
+    {
+        static size_t s_nConstructed;
+        static size_t s_nDestroyed;
+        static void throwIfTooMany()
+        {
+            if (s_nConstructed >= 7) throw new Exception ("Ka-boom !");
+        }
+
+        uint _i;
+
+        ~this()
+        {
+            static if (display) writefln("@%*Xh: Destroying.", nDigitsForPointer, &this);
+            ++s_nDestroyed;
+        }
+
+        this(uint i)
+        {
+            static if (display) writefln("@%*Xh: Constructing.", nDigitsForPointer, &this);
+            _i = i;
+            ++s_nConstructed;
+            throwIfTooMany();
+        }
+
+        this(this)
+        {
+            static if (display) writefln("@%*Xh: Copying.", nDigitsForPointer, &this);
+            ++s_nConstructed;
+            throwIfTooMany();
+        }
+    }
+
+    try
+    {
+        auto a = Array!S (S(0), S(1), S(2), S(3));
+        static if (display) writefln("@%*Xh: This is where the array elements are.", nDigitsForPointer, &a [0]);
+    }
+    catch (Exception e)
+    {
+        static if (display) writefln("Exception caught !");
+    }
+
+    static if (display)
+    {
+        writefln("s_nConstructed %*Xh.", nDigitsForNObjects, S.s_nConstructed);
+        writefln("s_nDestroyed   %*Xh.", nDigitsForNObjects, S.s_nDestroyed);
+        writefln("s_nConstructed should be equal to s_nDestroyed.");
+        writefln("");
+    }
+
+    assert(S.s_nDestroyed == S.s_nConstructed);
+}
+
+
 /**
  * _Array type with deterministic control of memory. The memory allocated
  * for the array is reclaimed as soon as possible; there is no reliance
@@ -441,32 +560,28 @@  if (!is(immutable T == immutable bool))
     this(U)(U[] values...)
     if (isImplicitlyConvertible!(U, T))
     {
-        import core.lifetime : emplace;
-
-        static if (T.sizeof == 1)
+        // [2021-07-17] Checking to see whether *always* calling ensureInitialized works-around-and/or-is-related-to https://issues.dlang.org/show_bug.cgihttps://issues.dlang.org/show_bug.cgi...
+        //if (values.length)
         {
-            const nbytes = values.length;
-        }
-        else
-        {
-            import core.checkedint : mulu;
-            bool overflow;
-            const nbytes = mulu(values.length, T.sizeof, overflow);
-            if (overflow)
-                assert(false, "Overflow");
-        }
-        auto p = cast(T*) enforceMalloc(nbytes);
-        // Before it is added to the gc, initialize the newly allocated memory
-        foreach (i, e; values)
-        {
-            emplace(p + i, e);
-        }
-        static if (hasIndirections!T)
-        {
-            if (p)
-                GC.addRange(p, T.sizeof * values.length);
+            _data.refCountedStore.ensureInitialized();
+            _data.reserve(values.length);
+            foreach (ref value; values)
+            {
+                // We do not simply write "_data.insertBack(value);"
+                // because that might perform, on each iteration, a now-redundant check of length vs capacity.
+                // Thanks to @dkorpel (https://github.com/dlang/phobos/pull/8162#discussion_r667479090).
+
+                import core.lifetime : emplace;
+                emplace(_data._payload.ptr + _data._payload.length, value);
+
+                // We increment the length after each iteration (as opposed to adjusting it just once, after the loop)
+                // in order to improve error-safety (in case one of the calls to emplace throws).
+                _data._payload = _data._payload.ptr[0 .. _data._payload.length + 1];
+            }
         }
-        _data = Data(p[0 .. values.length]);
+
+        assert(length == values.length);   // We check that all values have been inserted.
+        assert(capacity == values.length); // We check that reserve has been called before the loop.
     }
 
     /**
@@ -563,9 +678,9 @@  if (!is(immutable T == immutable bool))
      * Complexity: $(BIGOH 1).
      */
 
-    T[] data() @system
+    inout(T)[] data() inout @system
     {
-        return _data._payload;
+        return _data.refCountedStore.isInitialized ? _data._payload : [];
     }
 
     /**
@@ -581,34 +696,11 @@  if (!is(immutable T == immutable bool))
      */
     void reserve(size_t elements)
     {
-        if (!_data.refCountedStore.isInitialized)
-        {
-            if (!elements) return;
-            static if (T.sizeof == 1)
-            {
-                const sz = elements;
-            }
-            else
-            {
-                import core.checkedint : mulu;
-                bool overflow;
-                const sz = mulu(elements, T.sizeof, overflow);
-                if (overflow)
-                    assert(false, "Overflow");
-            }
-            auto p = enforceMalloc(sz);
-            static if (hasIndirections!T)
-            {
-                // Zero out unused capacity to prevent gc from seeing false pointers
-                memset(p, 0, sz);
-                GC.addRange(p, sz);
-            }
-            _data = Data(cast(T[]) p[0 .. 0]);
-            _data._capacity = elements;
-        }
-        else
+        if (elements > capacity)
         {
+            _data.refCountedStore.ensureInitialized();
             _data.reserve(elements);
+            assert(capacity == elements); // Might need changing to ">=" if implementation of Payload.reserve is changed.
         }
     }
 
@@ -2628,9 +2720,19 @@  if (is(immutable T == immutable bool))
 
 @system unittest
 {
+
     Array!int arr = [1, 2, 4, 5];
     int[] data = arr.data();
 
+    const Array!int arr2 = [8, 9];
+    assert(arr2.data() == [8, 9]);
+
     data[0] = 0;
     assert(arr[0] == 0);
+
+    arr.length = 0;
+    assert(arr.data == []);
+
+    Array!int empty;
+    assert(empty.data == []);
 }
diff --git a/libphobos/src/std/datetime/systime.d b/libphobos/src/std/datetime/systime.d
index 18b8524d7ad..4da1281f98a 100644
--- a/libphobos/src/std/datetime/systime.d
+++ b/libphobos/src/std/datetime/systime.d
@@ -8308,12 +8308,17 @@  public:
         YYYY-MM-DDTHH:MM:SS.FFFFFFFTZ (where F is fractional seconds and TZ
         is the time zone).
 
+        Default behaviour:
         Note that the number of digits in the fractional seconds varies with the
         number of fractional seconds. It's a maximum of 7 (which would be
         hnsecs), but only has as many as are necessary to hold the correct value
         (so no trailing zeroes), and if there are no fractional seconds, then
         there is no decimal point.
 
+        The optional parameter "prec" allows to change the default behavior by
+        specifying the precision of the fractional seconds. The accepted values
+        are in the range [-1, 7], where -1 represents the default behavior.
+
         If this $(LREF SysTime)'s time zone is
         $(REF LocalTime,std,datetime,timezone), then TZ is empty. If its time
         zone is `UTC`, then it is "Z". Otherwise, it is the offset from UTC
@@ -8325,25 +8330,30 @@  public:
         Params:
             writer = A `char` accepting
             $(REF_ALTTEXT output range, isOutputRange, std, range, primitives)
+            prec = An `int` representing the desired precision. Acceptable values range from -1 to 7, where -1 represents the default behavior.
         Returns:
             A `string` when not using an output range; `void` otherwise.
       +/
-    string toISOExtString() @safe const nothrow scope
+    string toISOExtString(int prec = -1) @safe const nothrow scope
     {
+        assert(prec >= -1 && prec <= 7, "Precision must be in the range [-1, 7]");
+
         import std.array : appender;
         auto app = appender!string();
         app.reserve(35);
         try
-            toISOExtString(app);
+            toISOExtString(app, prec);
         catch (Exception e)
             assert(0, "toISOExtString() threw.");
         return app.data;
     }
 
     /// ditto
-    void toISOExtString(W)(ref W writer) const scope
+    void toISOExtString(W)(ref W writer, int prec = -1) const scope
     if (isOutputRange!(W, char))
     {
+        assert(prec >= -1 && prec <= 7, "Precision must be in the range [-1, 7]");
+
         immutable adjustedTime = adjTime;
         long hnsecs = adjustedTime;
 
@@ -8365,14 +8375,14 @@  public:
         if (_timezone is LocalTime())
         {
             dateTime.toISOExtString(writer);
-            fracSecsToISOString(writer, cast(int) hnsecs);
+            fracSecsToISOString(writer, cast(int) hnsecs, prec);
             return;
         }
 
         if (_timezone is UTC())
         {
             dateTime.toISOExtString(writer);
-            fracSecsToISOString(writer, cast(int) hnsecs);
+            fracSecsToISOString(writer, cast(int) hnsecs, prec);
             put(writer, 'Z');
             return;
         }
@@ -8380,7 +8390,7 @@  public:
         immutable utcOffset = dur!"hnsecs"(adjustedTime - stdTime);
 
         dateTime.toISOExtString(writer);
-        fracSecsToISOString(writer, cast(int) hnsecs);
+        fracSecsToISOString(writer, cast(int) hnsecs, prec);
         SimpleTimeZone.toISOExtString(writer, utcOffset);
     }
 
@@ -8401,6 +8411,15 @@  public:
 
         assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toISOExtString() ==
                "-0004-01-05T00:00:02.052092");
+
+        assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toISOExtString(4) ==
+               "-0004-01-05T00:00:02.0520");
+
+        assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toISOExtString(2) ==
+               "-0004-01-05T00:00:02.05");
+
+        assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toISOExtString(7) ==
+               "-0004-01-05T00:00:02.0520920");
     }
 
     @safe unittest
@@ -11025,32 +11044,41 @@  private:
 /+
     Returns the given hnsecs as an ISO string of fractional seconds.
   +/
-string fracSecsToISOString(int hnsecs) @safe pure nothrow
+string fracSecsToISOString(int hnsecs, int prec = -1) @safe pure nothrow
 {
     import std.array : appender;
     auto w = appender!string();
     try
-        fracSecsToISOString(w, hnsecs);
+        fracSecsToISOString(w, hnsecs, prec);
     catch (Exception e)
         assert(0, "fracSecsToISOString() threw.");
     return w.data;
 }
 
-void fracSecsToISOString(W)(ref W writer, int hnsecs)
+void fracSecsToISOString(W)(ref W writer, int hnsecs, int prec = -1)
 {
     import std.conv : toChars;
     import std.range : padLeft;
 
     assert(hnsecs >= 0);
 
+    if (prec == 0)
+        return;
+
     if (hnsecs == 0)
         return;
 
     put(writer, '.');
     auto chars = hnsecs.toChars.padLeft('0', 7);
-    while (chars.back == '0')
-        chars.popBack();
-    put(writer, chars);
+
+    if (prec == -1)
+    {
+        while (chars.back == '0')
+            chars.popBack();
+        put(writer, chars);
+    }
+    else
+        put(writer, chars[0 .. prec]);
 }
 
 @safe unittest
diff --git a/libphobos/src/std/datetime/timezone.d b/libphobos/src/std/datetime/timezone.d
index 5df42e728c3..052758097a9 100644
--- a/libphobos/src/std/datetime/timezone.d
+++ b/libphobos/src/std/datetime/timezone.d
@@ -332,6 +332,7 @@  public:
         version (Posix)
         {
             version (FreeBSD)            enum utcZone = "Etc/UTC";
+            else version (OpenBSD)       enum utcZone = "UTC";
             else version (NetBSD)        enum utcZone = "UTC";
             else version (DragonFlyBSD)  enum utcZone = "UTC";
             else version (linux)         enum utcZone = "UTC";
diff --git a/libphobos/src/std/digest/ripemd.d b/libphobos/src/std/digest/ripemd.d
index 4a5deca6884..0fdc2519b18 100644
--- a/libphobos/src/std/digest/ripemd.d
+++ b/libphobos/src/std/digest/ripemd.d
@@ -210,7 +210,7 @@  struct RIPEMD160
          * RIPEMD160 basic transformation. Transforms state based on block.
          */
 
-        private void transform(const(ubyte[64])* block)
+        void transform(const(ubyte[64])* block)
             pure nothrow @nogc
         {
             uint aa = _state[0],
diff --git a/libphobos/src/std/exception.d b/libphobos/src/std/exception.d
index 5fcee2ab598..4f7f3c39153 100644
--- a/libphobos/src/std/exception.d
+++ b/libphobos/src/std/exception.d
@@ -191,7 +191,7 @@  auto assertNotThrown(T : Throwable = Exception, E)
 {
     import core.exception : AssertError;
 
-    void throwEx(Throwable t) { throw t; }
+    static noreturn throwEx(Throwable t) { throw t; }
     bool nothrowEx() { return true; }
 
     try
@@ -294,7 +294,9 @@  void assertThrown(T : Throwable = Exception, E)
         expression();
     catch (T)
         return;
-    throw new AssertError("assertThrown failed: No " ~ T.stringof ~ " was thrown"
+
+    static if (!is(immutable E == immutable noreturn))
+        throw new AssertError("assertThrown failed: No " ~ T.stringof ~ " was thrown"
                                  ~ (msg.length == 0 ? "." : ": ") ~ msg,
                           file, line);
 }
@@ -318,7 +320,7 @@  void assertThrown(T : Throwable = Exception, E)
 {
     import core.exception : AssertError;
 
-    void throwEx(Throwable t) { throw t; }
+    static noreturn throwEx(Throwable t) { throw t; }
     void nothrowEx() { }
 
     try
@@ -666,7 +668,9 @@  T collectException(T = Exception, E)(lazy E expression, ref E result)
     {
         return e;
     }
-    return null;
+    // Avoid "statement not reachable" warning
+    static if (!is(immutable E == immutable noreturn))
+        return null;
 }
 ///
 @system unittest
@@ -675,9 +679,14 @@  T collectException(T = Exception, E)(lazy E expression, ref E result)
     int foo() { throw new Exception("blah"); }
     assert(collectException(foo(), b));
 
-    int[] a = new int[3];
-    import core.exception : RangeError;
-    assert(collectException!RangeError(a[4], b));
+    version (D_NoBoundsChecks) {}
+    else
+    {
+        // check for out of bounds error
+        int[] a = new int[3];
+        import core.exception : RangeError;
+        assert(collectException!RangeError(a[4], b));
+    }
 }
 
 /++
@@ -706,7 +715,9 @@  T collectException(T : Throwable = Exception, E)(lazy E expression)
     {
         return t;
     }
-    return null;
+    // Avoid "statement not reachable" warning
+    static if (!is(immutable E == immutable noreturn))
+        return null;
 }
 
 ///
@@ -742,7 +753,9 @@  string collectExceptionMsg(T = Exception, E)(lazy E expression)
     {
         expression();
 
-        return cast(string) null;
+        // Avoid "statement not reachable" warning
+        static if (!is(immutable E == immutable noreturn))
+            return cast(string) null;
     }
     catch (T e)
         return e.msg.empty ? emptyExceptionMsg : e.msg;
@@ -766,6 +779,25 @@  string collectExceptionMsg(T = Exception, E)(lazy E expression)
  +/
 enum emptyExceptionMsg = "<Empty Exception Message>";
 
+// https://issues.dlang.org/show_bug.cgi?id=22364
+@system unittest
+{
+    static noreturn foo() { throw new Exception(""); }
+
+    const ex = collectException!(Exception, noreturn)(foo());
+    assert(ex);
+
+    const msg = collectExceptionMsg!(Exception, noreturn)(foo());
+    assert(msg);
+
+    noreturn n;
+
+    // Triggers a backend assertion failure
+    // collectException!(Exception, noreturn)(foo(), n);
+
+    static assert(__traits(compiles, collectException!(Exception, noreturn)(foo(), n)));
+}
+
 /**
  * Casts a mutable array to an immutable array in an idiomatic
  * manner. Technically, `assumeUnique` just inserts a cast,
diff --git a/libphobos/src/std/experimental/checkedint.d b/libphobos/src/std/experimental/checkedint.d
index b33c2ed354d..354851bfc84 100644
--- a/libphobos/src/std/experimental/checkedint.d
+++ b/libphobos/src/std/experimental/checkedint.d
@@ -1614,9 +1614,9 @@  static:
     been evaluated
     bound = The bound being violated
 
-    Returns: `cast(Lhs) rhs`
+    Returns: `cast(T) rhs`
     */
-    Lhs onLowerBound(Rhs, T)(Rhs rhs, T bound)
+    T onLowerBound(Rhs, T)(Rhs rhs, T bound)
     {
         trustedStderr.writefln("Lower bound error: %s(%s) < %s(%s)",
             Rhs.stringof, rhs, T.stringof, bound);
@@ -1793,6 +1793,12 @@  static:
     assert(witness == expected, "'" ~ witness ~ "'");
 }
 
+// https://issues.dlang.org/show_bug.cgi?id=22249
+@safe unittest
+{
+    alias _ = Warn.onLowerBound!(int, int);
+}
+
 // ProperCompare
 /**
 
diff --git a/libphobos/src/std/file.d b/libphobos/src/std/file.d
index 741656d74a7..1bfed64eae5 100644
--- a/libphobos/src/std/file.d
+++ b/libphobos/src/std/file.d
@@ -400,25 +400,23 @@  version (Posix) private void[] readImpl(scope const(char)[] name, scope const(FS
         : result[0 .. size.get];
 }
 
+version (Windows)
+private extern (Windows) @nogc nothrow
+{
+    pragma(mangle, CreateFileW.mangleof)
+    HANDLE trustedCreateFileW(scope const(wchar)* namez, DWORD dwDesiredAccess,
+        DWORD dwShareMode, SECURITY_ATTRIBUTES* lpSecurityAttributes,
+        DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes,
+        HANDLE hTemplateFile)  @trusted;
+
+    pragma(mangle, CloseHandle.mangleof) BOOL trustedCloseHandle(HANDLE) @trusted;
+}
 
 version (Windows) private void[] readImpl(scope const(char)[] name, scope const(FSChar)* namez,
                                           size_t upTo = size_t.max) @trusted
 {
     import core.memory : GC;
     import std.algorithm.comparison : min;
-    static trustedCreateFileW(scope const(wchar)* namez, DWORD dwDesiredAccess, DWORD dwShareMode,
-                              SECURITY_ATTRIBUTES *lpSecurityAttributes, DWORD dwCreationDisposition,
-                              DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
-    {
-        return CreateFileW(namez, dwDesiredAccess, dwShareMode,
-                           lpSecurityAttributes, dwCreationDisposition,
-                           dwFlagsAndAttributes, hTemplateFile);
-
-    }
-    static trustedCloseHandle(HANDLE hObject)
-    {
-        return CloseHandle(hObject);
-    }
     static trustedGetFileSize(HANDLE hFile, out ulong fileSize)
     {
         DWORD sizeHigh;
@@ -1125,6 +1123,9 @@  version (Windows) private ulong makeUlong(DWORD dwLow, DWORD dwHigh) @safe pure
     return li.QuadPart;
 }
 
+version (Posix) private extern (C) pragma(mangle, stat.mangleof)
+int trustedStat(const(FSChar)* namez, ref stat_t buf) @nogc nothrow @trusted;
+
 /**
 Get size of file `name` in bytes.
 
@@ -1148,10 +1149,6 @@  if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
     {
         auto namez = name.tempCString();
 
-        static trustedStat(const(FSChar)* namez, out stat_t buf) @trusted
-        {
-            return stat(namez, &buf);
-        }
         static if (isNarrowString!R && is(immutable ElementEncodingType!R == immutable char))
             alias names = name;
         else
@@ -1253,10 +1250,6 @@  if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
     {
         auto namez = name.tempCString();
 
-        static auto trustedStat(const(FSChar)* namez, ref stat_t buf) @trusted
-        {
-            return stat(namez, &buf);
-        }
         stat_t statbuf = void;
 
         static if (isNarrowString!R && is(immutable ElementEncodingType!R == immutable char))
@@ -1679,10 +1672,6 @@  if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
     else version (Posix)
     {
         auto namez = name.tempCString!FSChar();
-        static auto trustedStat(const(FSChar)* namez, ref stat_t buf) @trusted
-        {
-            return stat(namez, &buf);
-        }
         stat_t statbuf = void;
 
         static if (isNarrowString!R && is(immutable ElementEncodingType!R == immutable char))
@@ -1770,10 +1759,6 @@  if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R))
     else version (Posix)
     {
         auto namez = name.tempCString!FSChar();
-        static auto trustedStat(const(FSChar)* namez, ref stat_t buf) @trusted
-        {
-            return stat(namez, &buf);
-        }
         stat_t statbuf = void;
 
         return trustedStat(namez, statbuf) != 0 ?
@@ -2042,10 +2027,6 @@  if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
     else version (Posix)
     {
         auto namez = name.tempCString!FSChar();
-        static auto trustedStat(const(FSChar)* namez, ref stat_t buf) @trusted
-        {
-            return stat(namez, &buf);
-        }
         stat_t statbuf = void;
 
         static if (isNarrowString!R && is(immutable ElementEncodingType!R == immutable char))
@@ -5275,9 +5256,20 @@  slurp(Types...)(string filename, scope const(char)[] format)
     assert(slurp!(int)(deleteme, "%d") == [10, 20]);
 }
 
-
 /**
 Returns the path to a directory for temporary files.
+On POSIX platforms, it searches through the following list of directories
+and returns the first one which is found to exist:
+$(OL
+    $(LI The directory given by the `TMPDIR` environment variable.)
+    $(LI The directory given by the `TEMP` environment variable.)
+    $(LI The directory given by the `TMP` environment variable.)
+    $(LI `/tmp/`)
+    $(LI `/var/tmp/`)
+    $(LI `/usr/tmp/`)
+)
+
+On all platforms, `tempDir` returns the current working directory on failure.
 
 The return value of the function is cached, so the procedures described
 below will only be performed the first time the function is called.  All
@@ -5308,6 +5300,7 @@  Returns:
 */
 string tempDir() @trusted
 {
+    import std.path : dirSeparator;
     static string cache;
     if (cache is null)
     {
@@ -5327,7 +5320,7 @@  string tempDir() @trusted
             static string findExistingDir(T...)(lazy T alternatives)
             {
                 foreach (dir; alternatives)
-                    if (!dir.empty && exists(dir)) return dir;
+                    if (!dir.empty && exists(dir)) return dir ~ dirSeparator;
                 return null;
             }
 
@@ -5340,7 +5333,10 @@  string tempDir() @trusted
         }
         else static assert(false, "Unsupported platform");
 
-        if (cache is null) cache = getcwd();
+        if (cache is null)
+        {
+            cache = getcwd() ~ dirSeparator;
+        }
     }
     return cache;
 }
@@ -5363,6 +5359,13 @@  string tempDir() @trusted
     assert(myFile.readText == "hello");
 }
 
+@safe unittest
+{
+    import std.algorithm.searching : endsWith;
+    import std.path : dirSeparator;
+    assert(tempDir.endsWith(dirSeparator));
+}
+
 /**
 Returns the available disk space based on a given path.
 On Windows, `path` must be a directory; on POSIX systems, it can be a file or directory.
diff --git a/libphobos/src/std/format/internal/floats.d b/libphobos/src/std/format/internal/floats.d
index 81b21dc4995..632bf7674a6 100644
--- a/libphobos/src/std/format/internal/floats.d
+++ b/libphobos/src/std/format/internal/floats.d
@@ -17,7 +17,7 @@  module std.format.internal.floats;
 import std.format.spec : FormatSpec;
 
 // wrapper for unittests
-private auto printFloat(T, Char)(T val, FormatSpec!Char f)
+private auto printFloat(T, Char)(const(T) val, FormatSpec!Char f)
 if (is(T == float) || is(T == double)
     || (is(T == real) && (T.mant_dig == double.mant_dig || T.mant_dig == 64)))
 {
@@ -28,7 +28,7 @@  if (is(T == float) || is(T == double)
     return w.data;
 }
 
-package(std.format) void printFloat(Writer, T, Char)(auto ref Writer w, T val, FormatSpec!Char f)
+package(std.format) void printFloat(Writer, T, Char)(auto ref Writer w, const(T) val, FormatSpec!Char f)
 if (is(T == float) || is(T == double)
     || (is(T == real) && (T.mant_dig == double.mant_dig || T.mant_dig == 64)))
 {
@@ -76,7 +76,7 @@  if (is(T == float) || is(T == double)
     }
 }
 
-private void printFloatA(Writer, T, Char)(auto ref Writer w, T val,
+private void printFloatA(Writer, T, Char)(auto ref Writer w, const(T) val,
     FormatSpec!Char f, string sgn, int exp, ulong mnt, bool is_upper)
 if (is(T == float) || is(T == double)
     || (is(T == real) && (T.mant_dig == double.mant_dig || T.mant_dig == 64)))
@@ -586,7 +586,7 @@  if (is(T == float) || is(T == double)
     assert(printFloat(0x1.19f01p0, f) == "0X1.19FP+0");
 }
 
-private void printFloatE(bool g, Writer, T, Char)(auto ref Writer w, T val,
+private void printFloatE(bool g, Writer, T, Char)(auto ref Writer w, const(T) val,
     FormatSpec!Char f, string sgn, int exp, ulong mnt, bool is_upper)
 if (is(T == float) || is(T == double)
     || (is(T == real) && (T.mant_dig == double.mant_dig || T.mant_dig == 64)))
@@ -1505,7 +1505,7 @@  if (is(T == float) || is(T == double)
     });
 }
 
-private void printFloatF(bool g, Writer, T, Char)(auto ref Writer w, T val,
+private void printFloatF(bool g, Writer, T, Char)(auto ref Writer w, const(T) val,
     FormatSpec!Char f, string sgn, int exp, ulong mnt, bool is_upper)
 if (is(T == float) || is(T == double)
     || (is(T == real) && (T.mant_dig == double.mant_dig || T.mant_dig == 64)))
@@ -2268,7 +2268,7 @@  if (is(T == float) || is(T == double)
            ~"7175706828388979108268586060148663818836212158203125");
 }
 
-private void printFloatG(Writer, T, Char)(auto ref Writer w, T val,
+private void printFloatG(Writer, T, Char)(auto ref Writer w, const(T) val,
     FormatSpec!Char f, string sgn, int exp, ulong mnt, bool is_upper)
 if (is(T == float) || is(T == double)
     || (is(T == real) && (T.mant_dig == double.mant_dig || T.mant_dig == 64)))
diff --git a/libphobos/src/std/format/internal/write.d b/libphobos/src/std/format/internal/write.d
index 5883d8d3259..68b9e4daccc 100644
--- a/libphobos/src/std/format/internal/write.d
+++ b/libphobos/src/std/format/internal/write.d
@@ -28,7 +28,7 @@  package(std.format):
     `bool`s are formatted as `"true"` or `"false"` with `%s` and as `1` or
     `0` with integral-specific format specs.
  */
-void formatValueImpl(Writer, T, Char)(auto ref Writer w, T obj, scope const ref FormatSpec!Char f)
+void formatValueImpl(Writer, T, Char)(auto ref Writer w, const(T) obj, scope const ref FormatSpec!Char f)
 if (is(BooleanTypeOf!T) && !is(T == enum) && !hasToString!(T, Char))
 {
     BooleanTypeOf!T val = obj;
@@ -123,7 +123,7 @@  if (is(BooleanTypeOf!T) && !is(T == enum) && !hasToString!(T, Char))
 /*
     `null` literal is formatted as `"null"`
  */
-void formatValueImpl(Writer, T, Char)(auto ref Writer w, T obj, scope const ref FormatSpec!Char f)
+void formatValueImpl(Writer, T, Char)(auto ref Writer w, const(T) obj, scope const ref FormatSpec!Char f)
 if (is(immutable T == immutable typeof(null)) && !is(T == enum) && !hasToString!(T, Char))
 {
     import std.format : enforceFmt;
@@ -157,11 +157,9 @@  if (is(immutable T == immutable typeof(null)) && !is(T == enum) && !hasToString!
 /*
     Integrals are formatted like $(REF printf, core, stdc, stdio).
  */
-void formatValueImpl(Writer, T, Char)(auto ref Writer w, T obj, scope const ref FormatSpec!Char f)
+void formatValueImpl(Writer, T, Char)(auto ref Writer w, const(T) obj, scope const ref FormatSpec!Char f)
 if (is(IntegralTypeOf!T) && !is(T == enum) && !hasToString!(T, Char))
 {
-    import std.range.primitives : put;
-
     alias U = IntegralTypeOf!T;
     U val = obj;    // Extracting alias this may be impure/system/may-throw
 
@@ -171,56 +169,46 @@  if (is(IntegralTypeOf!T) && !is(T == enum) && !hasToString!(T, Char))
         auto raw = (ref val) @trusted {
             return (cast(const char*) &val)[0 .. val.sizeof];
         }(val);
-
+        import std.range.primitives : put;
         if (needToSwapEndianess(f))
-        {
             foreach_reverse (c; raw)
                 put(w, c);
-        }
         else
-        {
             foreach (c; raw)
                 put(w, c);
-        }
         return;
     }
 
-    immutable uint base =
-        f.spec == 'x' || f.spec == 'X' || f.spec == 'a' || f.spec == 'A' ? 16 :
-        f.spec == 'o' ? 8 :
-        f.spec == 'b' ? 2 :
-        f.spec == 's' || f.spec == 'd' || f.spec == 'u'
-        || f.spec == 'e' || f.spec == 'E' || f.spec == 'f' || f.spec == 'F'
-        || f.spec == 'g' || f.spec == 'G' ? 10 :
-        0;
-
-    import std.format : enforceFmt;
-    enforceFmt(base > 0,
-        "incompatible format character for integral argument: %" ~ f.spec);
-
-    import std.math.algebraic : abs;
-
-    bool negative = false;
-    ulong arg = val;
     static if (isSigned!U)
     {
-        if (f.spec != 'x' && f.spec != 'X' && f.spec != 'b' && f.spec != 'o' && f.spec != 'u')
-        {
-            if (val < 0)
-            {
-                negative = true;
-                arg = cast(ulong) abs(val);
-            }
-        }
+        const negative = val < 0 && f.spec != 'x' && f.spec != 'X' && f.spec != 'b' && f.spec != 'o' && f.spec != 'u';
+        ulong arg = negative ? -cast(ulong) val : val;
+    }
+    else
+    {
+        const negative = false;
+        ulong arg = val;
     }
-
     arg &= Unsigned!U.max;
 
+    formatValueImplUlong!(Writer, Char)(w, arg, negative, f);
+}
+
+// Helper function for `formatValueImpl` that avoids template bloat
+private void formatValueImplUlong(Writer, Char)(auto ref Writer w, ulong arg, in bool negative,
+                                                scope const ref FormatSpec!Char f)
+{
+    immutable uint base = baseOfSpec(f.spec);
+
+    const bool zero = arg == 0;
     char[64] digits = void;
     size_t pos = digits.length - 1;
     do
     {
-        digits[pos--] = '0' + arg % base;
+        /* `cast(char)` is needed because value range propagation (VRP) cannot
+         * analyze `base` because it’s computed in a separate function
+         * (`baseOfSpec`). */
+        digits[pos--] = cast(char) ('0' + arg % base);
         if (base > 10 && digits[pos + 1] > '9')
             digits[pos + 1] += ((f.spec == 'x' || f.spec == 'a') ? 'a' : 'A') - '0' - 10;
         arg /= base;
@@ -245,12 +233,12 @@  if (is(IntegralTypeOf!T) && !is(T == enum) && !hasToString!(T, Char))
     if (f.spec == 'x' || f.spec == 'X' || f.spec == 'b' || f.spec == 'o' || f.spec == 'u'
         || f.spec == 'd' || f.spec == 's')
     {
-        if (f.flHash && (base == 16) && obj != 0)
+        if (f.flHash && (base == 16) && !zero)
         {
             prefix[--left] = f.spec;
             prefix[--left] = '0';
         }
-        if (f.flHash && (base == 8) && obj != 0
+        if (f.flHash && (base == 8) && !zero
             && (digits.length - (pos + 1) >= f.precision || f.precision == f.UNSPECIFIED))
             prefix[--left] = '0';
 
@@ -358,6 +346,48 @@  if (is(IntegralTypeOf!T) && !is(T == enum) && !hasToString!(T, Char))
                  (f.spec == 'g' || f.spec == 'G') ? PrecisionType.allDigits : PrecisionType.fractionalDigits);
 }
 
+private uint baseOfSpec(in char spec) @safe pure
+{
+    typeof(return) base =
+        spec == 'x' || spec == 'X' || spec == 'a' || spec == 'A' ? 16 :
+        spec == 'o' ? 8 :
+        spec == 'b' ? 2 :
+        spec == 's' || spec == 'd' || spec == 'u'
+        || spec == 'e' || spec == 'E' || spec == 'f' || spec == 'F'
+        || spec == 'g' || spec == 'G' ? 10 :
+        0;
+
+    import std.format : enforceFmt;
+    enforceFmt(base > 0,
+        "incompatible format character for integral argument: %" ~ spec);
+
+    return base;
+}
+
+@safe pure unittest
+{
+    assertCTFEable!(
+    {
+        formatTest(byte.min, "-128");
+        formatTest(byte.max, "127");
+        formatTest(short.min, "-32768");
+        formatTest(short.max, "32767");
+        formatTest(int.min, "-2147483648");
+        formatTest(int.max, "2147483647");
+        formatTest(long.min, "-9223372036854775808");
+        formatTest(long.max, "9223372036854775807");
+
+        formatTest(ubyte.min, "0");
+        formatTest(ubyte.max, "255");
+        formatTest(ushort.min, "0");
+        formatTest(ushort.max, "65535");
+        formatTest(uint.min, "0");
+        formatTest(uint.max, "4294967295");
+        formatTest(ulong.min, "0");
+        formatTest(ulong.max, "18446744073709551615");
+    });
+}
+
 // https://issues.dlang.org/show_bug.cgi?id=18838
 @safe pure unittest
 {
@@ -577,7 +607,8 @@  if (is(IntegralTypeOf!T) && !is(T == enum) && !hasToString!(T, Char))
 /*
     Floating-point values are formatted like $(REF printf, core, stdc, stdio)
  */
-void formatValueImpl(Writer, T, Char)(auto ref Writer w, T obj, scope const ref FormatSpec!Char f)
+void formatValueImpl(Writer, T, Char)(auto ref Writer w, const(T) obj,
+                                      scope const ref FormatSpec!Char f)
 if (is(FloatingPointTypeOf!T) && !is(T == enum) && !hasToString!(T, Char))
 {
     import std.algorithm.searching : find;
@@ -986,7 +1017,7 @@  if (is(FloatingPointTypeOf!T) && !is(T == enum) && !hasToString!(T, Char))
     Formatting a `creal` is deprecated but still kept around for a while.
  */
 deprecated("Use of complex types is deprecated. Use std.complex")
-void formatValueImpl(Writer, T, Char)(auto ref Writer w, T obj, scope const ref FormatSpec!Char f)
+void formatValueImpl(Writer, T, Char)(auto ref Writer w, const(T) obj, scope const ref FormatSpec!Char f)
 if (is(immutable T : immutable creal) && !is(T == enum) && !hasToString!(T, Char))
 {
     import std.range.primitives : put;
@@ -1006,7 +1037,7 @@  if (is(immutable T : immutable creal) && !is(T == enum) && !hasToString!(T, Char
     Formatting an `ireal` is deprecated but still kept around for a while.
  */
 deprecated("Use of imaginary types is deprecated. Use std.complex")
-void formatValueImpl(Writer, T, Char)(auto ref Writer w, T obj, scope const ref FormatSpec!Char f)
+void formatValueImpl(Writer, T, Char)(auto ref Writer w, const(T) obj, scope const ref FormatSpec!Char f)
 if (is(immutable T : immutable ireal) && !is(T == enum) && !hasToString!(T, Char))
 {
     import std.range.primitives : put;
@@ -1021,7 +1052,7 @@  if (is(immutable T : immutable ireal) && !is(T == enum) && !hasToString!(T, Char
     Individual characters are formatted as Unicode characters with `%s`
     and as integers with integral-specific format specs
  */
-void formatValueImpl(Writer, T, Char)(auto ref Writer w, T obj, scope const ref FormatSpec!Char f)
+void formatValueImpl(Writer, T, Char)(auto ref Writer w, const(T) obj, scope const ref FormatSpec!Char f)
 if (is(CharTypeOf!T) && !is(T == enum) && !hasToString!(T, Char))
 {
     import std.meta : AliasSeq;
@@ -1111,11 +1142,11 @@  if (is(CharTypeOf!T) && !is(T == enum) && !hasToString!(T, Char))
 /*
     Strings are formatted like $(REF printf, core, stdc, stdio)
  */
-void formatValueImpl(Writer, T, Char)(auto ref Writer w, scope T obj,
+void formatValueImpl(Writer, T, Char)(auto ref Writer w, scope const(T) obj,
     scope const ref FormatSpec!Char f)
 if (is(StringTypeOf!T) && !is(StaticArrayTypeOf!T) && !is(T == enum) && !hasToString!(T, Char))
 {
-    Unqual!(StringTypeOf!T) val = obj;  // for `alias this`, see bug5371
+    Unqual!(const(StringTypeOf!T)) val = obj;  // for `alias this`, see bug5371
     formatRange(w, val, f);
 }
 
@@ -1306,7 +1337,7 @@  if (is(StringTypeOf!T) && !is(StaticArrayTypeOf!T) && !is(T == enum) && !hasToSt
 /*
     Static-size arrays are formatted as dynamic arrays.
  */
-void formatValueImpl(Writer, T, Char)(auto ref Writer w, auto ref T obj,
+void formatValueImpl(Writer, T, Char)(auto ref Writer w, auto ref const(T) obj,
     scope const ref FormatSpec!Char f)
 if (is(StaticArrayTypeOf!T) && !is(T == enum) && !hasToString!(T, Char))
 {
@@ -1751,13 +1782,13 @@  void formatChar(Writer)(ref Writer w, in dchar c, in char quote)
     Associative arrays are formatted by using `':'` and $(D ", ") as
     separators, and enclosed by `'['` and `']'`.
  */
-void formatValueImpl(Writer, T, Char)(auto ref Writer w, T obj, scope const ref FormatSpec!Char f)
+void formatValueImpl(Writer, T, Char)(auto ref Writer w, const(T) obj, scope const ref FormatSpec!Char f)
 if (is(AssocArrayTypeOf!T) && !is(T == enum) && !hasToString!(T, Char))
 {
     import std.format : enforceFmt, formatValue;
     import std.range.primitives : put;
 
-    AssocArrayTypeOf!T val = obj;
+    AssocArrayTypeOf!(const(T)) val = obj;
     const spec = f.spec;
 
     enforceFmt(spec == 's' || spec == '(',
@@ -2540,12 +2571,21 @@  if ((is(T == struct) || is(T == union)) && (hasToString!(T, Char) || !is(Builtin
             else static if (0 < i && val.tupleof[i-1].offsetof == val.tupleof[i].offsetof)
             {
                 static if (i == val.tupleof.length - 1 || val.tupleof[i].offsetof != val.tupleof[i+1].offsetof)
-                    put(w, separator~val.tupleof[i].stringof[4 .. $]~"}");
+                {
+                    enum el = separator ~ val.tupleof[i].stringof[4 .. $] ~ "}";
+                    put(w, el);
+                }
                 else
-                    put(w, separator~val.tupleof[i].stringof[4 .. $]);
+                {
+                    enum el = separator ~ val.tupleof[i].stringof[4 .. $];
+                    put(w, el);
+                }
             }
             else static if (i+1 < val.tupleof.length && val.tupleof[i].offsetof == val.tupleof[i+1].offsetof)
-                put(w, (i > 0 ? separator : "")~"#{overlap "~val.tupleof[i].stringof[4 .. $]);
+            {
+                enum el = (i > 0 ? separator : "") ~ "#{overlap " ~ val.tupleof[i].stringof[4 .. $];
+                put(w, el);
+            }
             else
             {
                 static if (i > 0)
@@ -2846,7 +2886,7 @@  void enforceValidFormatSpec(T, Char)(scope const ref FormatSpec!Char f)
 /*
     `enum`s are formatted like their base value
  */
-void formatValueImpl(Writer, T, Char)(auto ref Writer w, T val, scope const ref FormatSpec!Char f)
+void formatValueImpl(Writer, T, Char)(auto ref Writer w, const(T) val, scope const ref FormatSpec!Char f)
 if (is(T == enum))
 {
     import std.array : appender;
@@ -2866,7 +2906,9 @@  if (is(T == enum))
         auto w2 = appender!string();
 
         // val is not a member of T, output cast(T) rawValue instead.
-        put(w2, "cast(" ~ T.stringof ~ ")");
+        put(w2, "cast(");
+        put(w2, T.stringof);
+        put(w2, ")");
         static assert(!is(OriginalType!T == T), "OriginalType!" ~ T.stringof ~
             "must not be equal to " ~ T.stringof);
 
@@ -2934,7 +2976,7 @@  if (is(T == enum))
 /*
     Pointers are formatted as hex integers.
  */
-void formatValueImpl(Writer, T, Char)(auto ref Writer w, scope T val, scope const ref FormatSpec!Char f)
+void formatValueImpl(Writer, T, Char)(auto ref Writer w, scope const(T) val, scope const ref FormatSpec!Char f)
 if (isPointer!T && !is(T == enum) && !hasToString!(T, Char))
 {
     static if (is(typeof({ shared const void* p = val; })))
@@ -3048,7 +3090,7 @@  if (isPointer!T && !is(T == enum) && !hasToString!(T, Char))
 /*
     SIMD vectors are formatted as arrays.
  */
-void formatValueImpl(Writer, V, Char)(auto ref Writer w, V val, scope const ref FormatSpec!Char f)
+void formatValueImpl(Writer, V, Char)(auto ref Writer w, const(V) val, scope const ref FormatSpec!Char f)
 if (isSIMDVector!V)
 {
     formatValueImpl(w, val.array, f);
@@ -3082,7 +3124,7 @@  if (isSIMDVector!V)
     Known bug: Because of issue https://issues.dlang.org/show_bug.cgi?id=18269
                the FunctionAttributes might be wrong.
  */
-void formatValueImpl(Writer, T, Char)(auto ref Writer w, scope T, scope const ref FormatSpec!Char f)
+void formatValueImpl(Writer, T, Char)(auto ref Writer w, scope const(T), scope const ref FormatSpec!Char f)
 if (isDelegate!T)
 {
     formatValueImpl(w, T.stringof, f);
diff --git a/libphobos/src/std/functional.d b/libphobos/src/std/functional.d
index cec61fef575..b251e4006ec 100644
--- a/libphobos/src/std/functional.d
+++ b/libphobos/src/std/functional.d
@@ -1056,26 +1056,23 @@  Note: In the special case where only a single function is provided
 (`F[0]`).
 */
 template adjoin(F...)
-if (F.length == 1)
+if (F.length >= 1)
 {
-    alias adjoin = F[0];
-}
-/// ditto
-template adjoin(F...)
-if (F.length > 1)
-{
-    auto adjoin(V...)(auto ref V a)
-    {
-        import std.typecons : tuple;
-        import std.meta : staticMap;
-
-        auto resultElement(size_t i)()
+    static if (F.length == 1)
+        alias adjoin = F[0];
+    else
+        auto adjoin(V...)(auto ref V a)
         {
-            return F[i](a);
-        }
+            import std.typecons : tuple;
+            import std.meta : staticMap;
 
-        return tuple(staticMap!(resultElement, Iota!(F.length)));
-    }
+            auto resultElement(size_t i)()
+            {
+                return F[i](a);
+            }
+
+            return tuple(staticMap!(resultElement, Iota!(F.length)));
+        }
 }
 
 ///
diff --git a/libphobos/src/std/getopt.d b/libphobos/src/std/getopt.d
index d516012ac4a..482aae6306a 100644
--- a/libphobos/src/std/getopt.d
+++ b/libphobos/src/std/getopt.d
@@ -771,7 +771,7 @@  private void getoptImpl(T...)(ref string[] args, ref configuration cfg,
                     args = args.remove(i);
                 break;
             }
-            if (!a.length || a[0] != optionChar)
+            if (a.length < 2 || a[0] != optionChar)
             {
                 // not an option
                 if (cfg.stopOnFirstNonOption) break;
@@ -1890,6 +1890,17 @@  void defaultGetoptFormatter(Output)(Output output, string text, Option[] opt, st
     assert(f == "-");
 }
 
+// Hyphen at the option value;
+// https://issues.dlang.org/show_bug.cgi?id=22394
+@safe unittest
+{
+    auto args = ["program", "-"];
+
+    getopt(args);
+
+    assert(args == ["program", "-"]);
+}
+
 @safe unittest
 {
     import std.conv;
diff --git a/libphobos/src/std/internal/math/biguintcore.d b/libphobos/src/std/internal/math/biguintcore.d
index 59d784265c1..79446756fa6 100644
--- a/libphobos/src/std/internal/math/biguintcore.d
+++ b/libphobos/src/std/internal/math/biguintcore.d
@@ -1910,7 +1910,6 @@  pure @safe unittest
 }
 
 
-private:
 // Converts a big uint to a hexadecimal string.
 //
 // Optionally, a separator character (eg, an underscore) may be added between
@@ -2185,7 +2184,6 @@  do
 }
 
 
-private:
 // ------------------------
 // These in-place functions are only for internal use; they are incompatible
 // with COW.
@@ -2628,8 +2626,6 @@  again:
     }
 }
 
-private:
-
 // TODO: Replace with a library call
 void itoaZeroPadded(char[] output, uint value)
     pure nothrow @safe @nogc
@@ -2669,8 +2665,6 @@  void toHexZeroPadded(char[] output, uint value,
     }
 }
 
-private:
-
 // Returns the highest value of i for which left[i]!=right[i],
 // or 0 if left[] == right[]
 size_t highestDifferentDigit(const BigDigit [] left, const BigDigit [] right)
diff --git a/libphobos/src/std/internal/windows/advapi32.d b/libphobos/src/std/internal/windows/advapi32.d
index 2220eec63ec..6f999ba8019 100644
--- a/libphobos/src/std/internal/windows/advapi32.d
+++ b/libphobos/src/std/internal/windows/advapi32.d
@@ -16,17 +16,21 @@  import core.sys.windows.winbase, core.sys.windows.winnt, core.sys.windows.winreg
 
 pragma(lib, "advapi32.lib");
 
-immutable bool isWow64;
-
-shared static this()
+@property bool isWow64()
 {
     // WOW64 is the x86 emulator that allows 32-bit Windows-based applications to run seamlessly on 64-bit Windows
     // IsWow64Process Function - Minimum supported client - Windows Vista, Windows XP with SP2
+    static int result = -1; // <0 if uninitialized, >0 if yes, ==0 if no
+    if (result >= 0)
+        return result > 0;  // short path
+    // Will do this work once per thread to avoid importing std.concurrency
+    // or doing gnarly initonce work.
     alias fptr_t = extern(Windows) BOOL function(HANDLE, PBOOL);
     auto hKernel = GetModuleHandleA("kernel32");
     auto IsWow64Process = cast(fptr_t) GetProcAddress(hKernel, "IsWow64Process");
     BOOL bIsWow64;
-    isWow64 = IsWow64Process && IsWow64Process(GetCurrentProcess(), &bIsWow64) && bIsWow64;
+    result = IsWow64Process && IsWow64Process(GetCurrentProcess(), &bIsWow64) && bIsWow64;
+    return result > 0;
 }
 
 HMODULE hAdvapi32 = null;
diff --git a/libphobos/src/std/json.d b/libphobos/src/std/json.d
index 39f89a60c04..af7aa383d8e 100644
--- a/libphobos/src/std/json.d
+++ b/libphobos/src/std/json.d
@@ -735,13 +735,13 @@  struct JSONValue
      * Tests wether a key can be found in an object.
      *
      * Returns:
-     *      when found, the `const(JSONValue)*` that matches to the key,
+     *      when found, the `inout(JSONValue)*` that matches to the key,
      *      otherwise `null`.
      *
      * Throws: `JSONException` if the right hand side argument `JSONType`
      * is not `object`.
      */
-    auto opBinaryRight(string op : "in")(string k) const @safe
+    inout(JSONValue)* opBinaryRight(string op : "in")(string k) inout @safe
     {
         return k in this.objectNoRef;
     }
@@ -750,6 +750,8 @@  struct JSONValue
     {
         JSONValue j = [ "language": "D", "author": "walter" ];
         string a = ("author" in j).str;
+        *("author" in j) = "Walter";
+        assert(j["author"].str == "Walter");
     }
 
     bool opEquals(const JSONValue rhs) const @nogc nothrow pure @safe
diff --git a/libphobos/src/std/math/algebraic.d b/libphobos/src/std/math/algebraic.d
index ae7cbf941b4..db70b7a5552 100644
--- a/libphobos/src/std/math/algebraic.d
+++ b/libphobos/src/std/math/algebraic.d
@@ -595,6 +595,12 @@  if (isFloatingPoint!T1 && isFloatingPoint!T2)
     return r;
 }
 
+version (linux)             version = GenericPosixVersion;
+else version (FreeBSD)      version = GenericPosixVersion;
+else version (OpenBSD)      version = GenericPosixVersion;
+else version (Solaris)      version = GenericPosixVersion;
+else version (DragonFlyBSD) version = GenericPosixVersion;
+
 private real polyImpl(real x, in real[] A) @trusted pure nothrow @nogc
 {
     version (D_InlineAsm_X86)
@@ -631,7 +637,7 @@  private real polyImpl(real x, in real[] A) @trusted pure nothrow @nogc
         return_ST:                              ;
             }
         }
-        else version (linux)
+        else version (GenericPosixVersion)
         {
             asm pure nothrow @nogc // assembler by W. Bright
             {
@@ -685,87 +691,6 @@  private real polyImpl(real x, in real[] A) @trusted pure nothrow @nogc
         return_ST:                              ;
             }
         }
-        else version (FreeBSD)
-        {
-            asm pure nothrow @nogc // assembler by W. Bright
-            {
-                // EDX = (A.length - 1) * real.sizeof
-                mov     ECX,A[EBP]              ; // ECX = A.length
-                dec     ECX                     ;
-                lea     EDX,[ECX*8]             ;
-                lea     EDX,[EDX][ECX*4]        ;
-                add     EDX,A+4[EBP]            ;
-                fld     real ptr [EDX]          ; // ST0 = coeff[ECX]
-                jecxz   return_ST               ;
-                fld     x[EBP]                  ; // ST0 = x
-                fxch    ST(1)                   ; // ST1 = x, ST0 = r
-                align   4                       ;
-        L2:     fmul    ST,ST(1)                ; // r *= x
-                fld     real ptr -12[EDX]       ;
-                sub     EDX,12                  ; // deg--
-                faddp   ST(1),ST                ;
-                dec     ECX                     ;
-                jne     L2                      ;
-                fxch    ST(1)                   ; // ST1 = r, ST0 = x
-                fstp    ST(0)                   ; // dump x
-                align   4                       ;
-        return_ST:                              ;
-            }
-        }
-        else version (Solaris)
-        {
-            asm pure nothrow @nogc // assembler by W. Bright
-            {
-                // EDX = (A.length - 1) * real.sizeof
-                mov     ECX,A[EBP]              ; // ECX = A.length
-                dec     ECX                     ;
-                lea     EDX,[ECX*8]             ;
-                lea     EDX,[EDX][ECX*4]        ;
-                add     EDX,A+4[EBP]            ;
-                fld     real ptr [EDX]          ; // ST0 = coeff[ECX]
-                jecxz   return_ST               ;
-                fld     x[EBP]                  ; // ST0 = x
-                fxch    ST(1)                   ; // ST1 = x, ST0 = r
-                align   4                       ;
-        L2:     fmul    ST,ST(1)                ; // r *= x
-                fld     real ptr -12[EDX]       ;
-                sub     EDX,12                  ; // deg--
-                faddp   ST(1),ST                ;
-                dec     ECX                     ;
-                jne     L2                      ;
-                fxch    ST(1)                   ; // ST1 = r, ST0 = x
-                fstp    ST(0)                   ; // dump x
-                align   4                       ;
-        return_ST:                              ;
-            }
-        }
-        else version (DragonFlyBSD)
-        {
-            asm pure nothrow @nogc // assembler by W. Bright
-            {
-                // EDX = (A.length - 1) * real.sizeof
-                mov     ECX,A[EBP]              ; // ECX = A.length
-                dec     ECX                     ;
-                lea     EDX,[ECX*8]             ;
-                lea     EDX,[EDX][ECX*4]        ;
-                add     EDX,A+4[EBP]            ;
-                fld     real ptr [EDX]          ; // ST0 = coeff[ECX]
-                jecxz   return_ST               ;
-                fld     x[EBP]                  ; // ST0 = x
-                fxch    ST(1)                   ; // ST1 = x, ST0 = r
-                align   4                       ;
-        L2:     fmul    ST,ST(1)                ; // r *= x
-                fld     real ptr -12[EDX]       ;
-                sub     EDX,12                  ; // deg--
-                faddp   ST(1),ST                ;
-                dec     ECX                     ;
-                jne     L2                      ;
-                fxch    ST(1)                   ; // ST1 = r, ST0 = x
-                fstp    ST(0)                   ; // dump x
-                align   4                       ;
-        return_ST:                              ;
-            }
-        }
         else
         {
             static assert(0);
diff --git a/libphobos/src/std/math/operations.d b/libphobos/src/std/math/operations.d
index dfb1aeea587..cb3c805f76f 100644
--- a/libphobos/src/std/math/operations.d
+++ b/libphobos/src/std/math/operations.d
@@ -1717,11 +1717,12 @@  if (isFloatingPoint!T)
     bool negative;
 }
 
-FloatingPointBitpattern!T extractBitpattern(T)(T val) @trusted
+FloatingPointBitpattern!T extractBitpattern(T)(const(T) value) @trusted
 if (isFloatingPoint!T)
 {
     import std.math : floatTraits, RealFormat;
 
+    T val = value;
     FloatingPointBitpattern!T ret;
 
     alias F = floatTraits!T;
diff --git a/libphobos/src/std/meta.d b/libphobos/src/std/meta.d
index 1209987eabd..0075ed7edf7 100644
--- a/libphobos/src/std/meta.d
+++ b/libphobos/src/std/meta.d
@@ -511,30 +511,19 @@  if (args.length >= 2)
 }
 
 /**
- * Returns an `AliasSeq` created from TList with all occurrences
- * of T, if found, replaced with U.
+ * Returns an `AliasSeq` created from `args[2 .. $]` with all occurrences
+ * of `args[0]`, if any, replaced with `args[1]`.
  */
-template ReplaceAll(T, U, TList...)
-{
-    alias ReplaceAll = GenericReplaceAll!(T, U, TList).result;
-}
-
-/// Ditto
-template ReplaceAll(alias T, U, TList...)
+template ReplaceAll(args...)
 {
-    alias ReplaceAll = GenericReplaceAll!(T, U, TList).result;
-}
-
-/// Ditto
-template ReplaceAll(T, alias U, TList...)
-{
-    alias ReplaceAll = GenericReplaceAll!(T, U, TList).result;
-}
-
-/// Ditto
-template ReplaceAll(alias T, alias U, TList...)
-{
-    alias ReplaceAll = GenericReplaceAll!(T, U, TList).result;
+    alias ReplaceAll = AliasSeq!();
+    static foreach (arg; args[2 .. $])
+    {
+        static if (isSame!(args[0], arg))
+            ReplaceAll = AliasSeq!(ReplaceAll, args[1]);
+        else
+            ReplaceAll = AliasSeq!(ReplaceAll, arg);
+    }
 }
 
 ///
@@ -546,31 +535,6 @@  template ReplaceAll(alias T, alias U, TList...)
     static assert(is(TL == AliasSeq!(int, char, char, int, float)));
 }
 
-// [internal]
-private template GenericReplaceAll(args...)
-if (args.length >= 2)
-{
-    alias from  = OldAlias!(args[0]);
-    alias to    = OldAlias!(args[1]);
-    alias tuple = args[2 .. $];
-
-    static if (tuple.length)
-    {
-        alias head = OldAlias!(tuple[0]);
-        alias tail = tuple[1 .. $];
-        alias next = GenericReplaceAll!(from, to, tail).result;
-
-        static if (isSame!(from, head))
-            alias result = AliasSeq!(to, next);
-        else
-            alias result = AliasSeq!(head, next);
-    }
-    else
-    {
-        alias result = AliasSeq!();
-    }
-}
-
 @safe unittest
 {
     static assert(Pack!(ReplaceAll!(byte, ubyte,
@@ -658,29 +622,40 @@  template DerivedToFront(TList...)
     static assert(is(TL2 == AliasSeq!(C, C, C, B, B, B, A, A, A)));
 }
 
-private enum staticMapExpandFactor = 150;
-private string generateCases()
-{
-    string[staticMapExpandFactor] chunks;
-    chunks[0] = q{};
-    static foreach (enum i; 0 .. staticMapExpandFactor - 1)
-        chunks[i + 1] = chunks[i] ~ `F!(Args[` ~ i.stringof ~ `]),`;
-    string ret = `AliasSeq!(`;
-    foreach (chunk; chunks)
-        ret ~= `q{alias staticMap = AliasSeq!(` ~ chunk ~ `);},`;
-    return ret ~ `)`;
-}
-private alias staticMapBasicCases = AliasSeq!(mixin(generateCases()));
-
 /**
-Evaluates to $(D AliasSeq!(F!(T[0]), F!(T[1]), ..., F!(T[$ - 1]))).
+Evaluates to `AliasSeq!(fun!(args[0]), fun!(args[1]), ..., fun!(args[$ - 1]))`.
  */
-template staticMap(alias F, Args ...)
+template staticMap(alias fun, args...)
 {
-    static if (Args.length < staticMapExpandFactor)
-        mixin(staticMapBasicCases[Args.length]);
-    else
-        alias staticMap = AliasSeq!(staticMap!(F, Args[0 .. $/2]), staticMap!(F, Args[$/2 .. $]));
+    version (__staticMap_simplest_but_buggy)
+    {
+        // @@@ BUG @@@
+        // The following straightforward implementation exposes a bug.
+        // See issue https://issues.dlang.org/show_bug.cgi?id=22421 and unittest below.
+        alias staticMap = AliasSeq!();
+        static foreach (arg; args)
+             staticMap = AliasSeq!(staticMap, fun!arg);
+    }
+    else version (__staticMap_simple_but_slow)
+    {
+        // This has a performance bug. Appending to the staticMap seems to be quadratic.
+        alias staticMap = AliasSeq!();
+        static foreach (i; 0 .. args.length)
+            staticMap = AliasSeq!(staticMap, fun!(args[i]));
+    }
+    else // Current best-of-breed implementation imitates quicksort
+    {
+        static if (args.length <= 8)
+        {
+            alias staticMap = AliasSeq!();
+            static foreach (i; 0 .. args.length)
+                staticMap = AliasSeq!(staticMap, fun!(args[i]));
+        }
+        else
+        {
+            alias staticMap = AliasSeq!(staticMap!(fun, args[0 .. $ / 2]), staticMap!(fun, args[$ / 2 .. $]));
+        }
+    }
 }
 
 ///
@@ -705,6 +680,14 @@  template staticMap(alias F, Args ...)
 
     alias T = staticMap!(Unqual, int, const int, immutable int, uint, ubyte, byte, short, ushort, long);
     static assert(is(T == AliasSeq!(int, int, int, uint, ubyte, byte, short, ushort, long)));
+
+    // @@@ BUG @@@ The test below exposes failure of the straightforward use.
+    // See @adamdruppe's comment to https://github.com/dlang/phobos/pull/8039
+    template id(alias what) {
+            enum id = __traits(identifier, what);
+    }
+    enum A { a }
+    static assert(staticMap!(id, A.a) == AliasSeq!("a"));
 }
 
 // regression test for https://issues.dlang.org/show_bug.cgi?id=21088
@@ -716,17 +699,25 @@  template staticMap(alias F, Args ...)
     assert(A == typeid(int));
 }
 
-/**
-Tests whether all given items satisfy a template predicate, i.e. evaluates to
-$(D F!(T[0]) && F!(T[1]) && ... && F!(T[$ - 1])).
+version (StdDdoc)
+{
+    /**
+       Tests whether all given items satisfy a template predicate, i.e. evaluates to
+       $(D F!(T[0]) && F!(T[1]) && ... && F!(T[$ - 1])).
 
-Evaluation is $(I not) short-circuited if a false result is encountered; the
-template predicate must be instantiable with all the given items.
- */
-template allSatisfy(alias F, T...)
+       Evaluation is $(I not) short-circuited if a false result is encountered; the
+       template predicate must be instantiable with all the given items.
+    */
+    template allSatisfy(alias F, T...)
+    {
+        import core.internal.traits : allSat = allSatisfy;
+        alias allSatisfy = allSat!(F, T);
+    }
+}
+else
 {
     import core.internal.traits : allSat = allSatisfy;
-    alias allSatisfy = allSat!(F, T);
+    alias allSatisfy = allSat;
 }
 
 ///
@@ -738,17 +729,25 @@  template allSatisfy(alias F, T...)
     static assert( allSatisfy!(isIntegral, int, long));
 }
 
-/**
-Tests whether any given items satisfy a template predicate, i.e. evaluates to
-$(D F!(T[0]) || F!(T[1]) || ... || F!(T[$ - 1])).
+version (StdDdoc)
+{
+    /**
+       Tests whether any given items satisfy a template predicate, i.e. evaluates to
+       $(D F!(T[0]) || F!(T[1]) || ... || F!(T[$ - 1])).
 
-Evaluation is short-circuited if a true result is encountered; the
-template predicate must be instantiable with one of the given items.
- */
-template anySatisfy(alias F, T...)
+       Evaluation is short-circuited if a true result is encountered; the
+       template predicate must be instantiable with one of the given items.
+    */
+    template anySatisfy(alias F, T...)
+    {
+        import core.internal.traits : anySat = anySatisfy;
+        alias anySatisfy = anySat!(F, T);
+    }
+}
+else
 {
     import core.internal.traits : anySat = anySatisfy;
-    alias anySatisfy = anySat!(F, T);
+    alias anySatisfy = anySat;
 }
 
 ///
@@ -760,170 +759,16 @@  template anySatisfy(alias F, T...)
     static assert( anySatisfy!(isIntegral, int, double));
 }
 
-private alias FilterShortCode = AliasSeq!(
-    q{
-        alias Filter = Nothing;
-    },
-    q{
-        static if (pred!(TList[0]))
-            alias Filter = AliasSeq!(TList[0]);
-        else
-            alias Filter = Nothing;
-    },
-    q{
-        static if (pred!(TList[0]))
-        {
-            static if (pred!(TList[1]))
-                alias Filter = AliasSeq!(TList[0], TList[1]);
-            else
-                alias Filter = AliasSeq!(TList[0]);
-        }
-        else
-        {
-            static if (pred!(TList[1]))
-                alias Filter = AliasSeq!(TList[1]);
-            else
-                alias Filter = Nothing;
-        }
-    },
-    q{
-        static if (pred!(TList[0]))
-        {
-            static if (pred!(TList[1]))
-            {
-                static if (pred!(TList[2]))
-                    alias Filter = AliasSeq!(TList[0], TList[1], TList[2]);
-                else
-                    alias Filter = AliasSeq!(TList[0], TList[1]);
-            }
-            else
-            {
-                static if (pred!(TList[2]))
-                    alias Filter = AliasSeq!(TList[0], TList[2]);
-                else
-                    alias Filter = AliasSeq!(TList[0]);
-            }
-        }
-        else
-        {
-            static if (pred!(TList[1]))
-            {
-                static if (pred!(TList[2]))
-                    alias Filter = AliasSeq!(TList[1], TList[2]);
-                else
-                    alias Filter = AliasSeq!(TList[1]);
-            }
-            else
-            {
-                static if (pred!(TList[2]))
-                    alias Filter = AliasSeq!(TList[2]);
-                else
-                    alias Filter = Nothing;
-            }
-        }
-    },
-    q{
-        static if (pred!(TList[0]))
-        {
-            static if (pred!(TList[1]))
-            {
-                static if (pred!(TList[2]))
-                {
-                    static if (pred!(TList[3]))
-                        alias Filter = AliasSeq!(TList[0], TList[1], TList[2], TList[3]);
-                    else
-                        alias Filter = AliasSeq!(TList[0], TList[1], TList[2]);
-                }
-                else
-                {
-                    static if (pred!(TList[3]))
-                        alias Filter = AliasSeq!(TList[0], TList[1], TList[3]);
-                    else
-                        alias Filter = AliasSeq!(TList[0], TList[1]);
-                }
-            }
-            else
-            {
-                static if (pred!(TList[2]))
-                {
-                    static if (pred!(TList[3]))
-                        alias Filter = AliasSeq!(TList[0], TList[2], TList[3]);
-                    else
-                        alias Filter = AliasSeq!(TList[0], TList[2]);
-                }
-                else
-                {
-                    static if (pred!(TList[3]))
-                        alias Filter = AliasSeq!(TList[0], TList[3]);
-                    else
-                        alias Filter = AliasSeq!(TList[0]);
-                }
-            }
-        }
-        else
-        {
-            static if (pred!(TList[1]))
-            {
-                static if (pred!(TList[2]))
-                {
-                    static if (pred!(TList[3]))
-                        alias Filter = AliasSeq!(TList[1], TList[2], TList[3]);
-                    else
-                        alias Filter = AliasSeq!(TList[1], TList[2]);
-                }
-                else
-                {
-                    static if (pred!(TList[3]))
-                        alias Filter = AliasSeq!(TList[1], TList[3]);
-                    else
-                        alias Filter = AliasSeq!(TList[1]);
-                }
-            }
-            else
-            {
-                static if (pred!(TList[2]))
-                {
-                    static if (pred!(TList[3]))
-                        alias Filter = AliasSeq!(TList[2], TList[3]);
-                    else
-                        alias Filter = AliasSeq!(TList[2]);
-                }
-                else
-                {
-                    static if (pred!(TList[3]))
-                        alias Filter = AliasSeq!(TList[3]);
-                    else
-                        alias Filter = Nothing;
-                }
-            }
-        }
-    }
-);
-
-private enum filterExpandFactor = FilterShortCode.length;
-
-package alias Nothing = AliasSeq!(); // yes, this really does speed up compilation!
 /**
  * Filters an `AliasSeq` using a template predicate. Returns an
  * `AliasSeq` of the elements which satisfy the predicate.
  */
-template Filter(alias pred, TList ...)
+template Filter(alias pred, args...)
 {
-    static if (TList.length < filterExpandFactor)
-    {
-        mixin(FilterShortCode[TList.length]);
-    }
-    else
-    {
-        template MaybeNothing(Q ...)
-        {
-            static if (pred!(Q[0]))
-                alias MaybeNothing = AliasSeq!(Q[0]);
-            else
-                alias MaybeNothing = Nothing;
-        }
-        alias Filter = staticMap!(MaybeNothing, TList);
-    }
+    alias Filter = AliasSeq!();
+    static foreach (arg; args)
+        static if (pred!arg)
+            Filter = AliasSeq!(Filter, arg);
 }
 
 ///
@@ -993,6 +838,7 @@  template templateNot(alias pred)
     static assert(allSatisfy!(isNoPointer, string, char, float));
 }
 
+version (StdUnittest)
 @safe unittest
 {
     static foreach (T; AliasSeq!(int, staticMap, 42))
@@ -1044,6 +890,7 @@  template templateAnd(Preds...)
     static assert(alwaysTrue!int);
 }
 
+version (StdUnittest)
 @safe unittest
 {
     static foreach (T; AliasSeq!(int, staticMap, 42))
@@ -1102,6 +949,7 @@  template templateOr(Preds...)
     static assert(!alwaysFalse!int);
 }
 
+version (StdUnittest)
 @safe unittest
 {
     static foreach (T; AliasSeq!(int, staticMap, 42))
@@ -1427,28 +1275,18 @@  template Repeat(size_t n, items...)
  *     cmp = A template that returns a `bool` (if its first argument is less than the second one)
  *         or an `int` (-1 means less than, 0 means equal, 1 means greater than)
  *
- *     Seq = The  $(LREF AliasSeq) to sort
+ *     items = The  $(LREF AliasSeq) to sort
  *
  * Returns: The sorted alias sequence
  */
-template staticSort(alias cmp, Seq...)
+template staticSort(alias cmp, items...)
 {
-    static if (Seq.length < 2)
-    {
-        alias staticSort = Seq;
-    }
+    static if (items.length < 2)
+        alias staticSort = items;
     else
-    {
-        private alias btm = staticSort!(cmp, Seq[0 .. $ / 2]);
-        private alias top = staticSort!(cmp, Seq[$ / 2 .. $]);
-
-        static if (isLessEq!(cmp, btm[$ - 1], top[0]))
-            alias staticSort = AliasSeq!(btm, top); // already ascending
-        else static if (isLessEq!(cmp, top[$ - 1], btm[0]))
-            alias staticSort = AliasSeq!(top, btm); // already descending
-        else
-            alias staticSort = staticMerge!(cmp, Seq.length / 2, btm, top);
-    }
+        alias staticSort = staticMerge!(cmp, items.length / 2,
+            staticSort!(cmp, items[0 .. $ / 2]),
+            staticSort!(cmp, items[$ / 2 .. $]));
 }
 
 ///
@@ -1468,25 +1306,21 @@  template staticSort(alias cmp, Seq...)
         Types)));
 }
 
-private template staticMerge(alias cmp, int half, Seq...)
+private template staticMerge(alias cmp, uint mid, items...)
 {
-    static if (half == 0 || half == Seq.length)
+    enum run =
     {
-        alias staticMerge = Seq;
-    }
+        static if (mid < items.length)
+            static foreach (i, item; items[0 .. mid])
+                static if (!isLessEq!(cmp, item, items[mid]))
+                    if (__ctfe) return i;
+        return mid;
+    }();
+    static if (run == mid)
+        alias staticMerge = items;
     else
-    {
-        static if (isLessEq!(cmp, Seq[0], Seq[half]))
-        {
-            alias staticMerge = AliasSeq!(Seq[0],
-                staticMerge!(cmp, half - 1, Seq[1 .. $]));
-        }
-        else
-        {
-            alias staticMerge = AliasSeq!(Seq[half],
-                staticMerge!(cmp, half, Seq[0 .. half], Seq[half + 1 .. $]));
-        }
-    }
+        alias staticMerge = AliasSeq!(items[0 .. run], items[mid],
+            staticMerge!(cmp, mid - run, items[run .. mid], items[mid + 1 .. $]));
 }
 
 private template isLessEq(alias cmp, Seq...)
diff --git a/libphobos/src/std/parallelism.d b/libphobos/src/std/parallelism.d
index 664330a3c2b..bd467d21c3f 100644
--- a/libphobos/src/std/parallelism.d
+++ b/libphobos/src/std/parallelism.d
@@ -955,16 +955,46 @@  uint totalCPUsImpl() @nogc nothrow @trusted
     }
     else version (linux)
     {
-        import core.sys.linux.sched : CPU_COUNT, cpu_set_t, sched_getaffinity;
+        import core.stdc.stdlib : calloc;
+        import core.stdc.string : memset;
+        import core.sys.linux.sched : CPU_ALLOC_SIZE, CPU_FREE, CPU_COUNT, CPU_COUNT_S, cpu_set_t, sched_getaffinity;
         import core.sys.posix.unistd : _SC_NPROCESSORS_ONLN, sysconf;
 
-        cpu_set_t set = void;
-        if (sched_getaffinity(0, cpu_set_t.sizeof, &set) == 0)
+        int count = 0;
+
+        /**
+         * According to ruby's source code, CPU_ALLOC() doesn't work as expected.
+         *  see: https://github.com/ruby/ruby/commit/7d9e04de496915dd9e4544ee18b1a0026dc79242
+         *
+         *  The hardcode number also comes from ruby's source code.
+         *  see: https://github.com/ruby/ruby/commit/0fa75e813ecf0f5f3dd01f89aa76d0e25ab4fcd4
+         */
+        for (int n = 64; n <= 16384; n *= 2)
         {
-            int count = CPU_COUNT(&set);
+            size_t size = CPU_ALLOC_SIZE(count);
+            if (size >= 0x400)
+            {
+                auto cpuset = cast(cpu_set_t*) calloc(1, size);
+                if (cpuset is null) break;
+                if (sched_getaffinity(0, size, cpuset) == 0)
+                {
+                    count = CPU_COUNT_S(size, cpuset);
+                }
+                CPU_FREE(cpuset);
+            }
+            else
+            {
+                cpu_set_t cpuset;
+                if (sched_getaffinity(0, cpu_set_t.sizeof, &cpuset) == 0)
+                {
+                    count = CPU_COUNT(&cpuset);
+                }
+            }
+
             if (count > 0)
                 return cast(uint) count;
         }
+
         return cast(uint) sysconf(_SC_NPROCESSORS_ONLN);
     }
     else version (Darwin)
@@ -2733,9 +2763,6 @@  public:
                 }
             }
 
-            foreach (ref t; tasks[])
-                emplaceRef(t, RTask());
-
             // Hack to take the address of a nested function w/o
             // making a closure.
             static auto scopedAddress(D)(scope D del) @system
@@ -2748,12 +2775,19 @@  public:
             void useTask(ref RTask task)
             {
                 import std.algorithm.comparison : min;
+                import core.lifetime : emplace;
+
+                // Private constructor, so can't feed it's arguments directly
+                // to emplace
+                emplace(&task, RTask
+                (
+                    scopedAddress(&reduceOnRange),
+                    range,
+                    curPos, // lower bound.
+                    cast() min(len, curPos + workUnitSize)  // upper bound.
+                ));
 
                 task.pool = this;
-                task._args[0] = scopedAddress(&reduceOnRange);
-                task._args[3] = min(len, curPos + workUnitSize);  // upper bound.
-                task._args[1] = range;  // range
-                task._args[2] = curPos; // lower bound.
 
                 curPos += workUnitSize;
             }
@@ -3505,6 +3539,21 @@  public:
     assert(taskPool.fold!("a + b", "a + b")(r, 0, 0, 42) == tuple(expected, expected));
 }
 
+// Issue 16705
+@system unittest
+{
+    struct MyIota
+    {
+        size_t front;
+        void popFront()(){front++;}
+        auto empty(){return front >= 25;}
+        auto opIndex(size_t i){return front+i;}
+        auto length(){return 25-front;}
+    }
+
+    auto mySum = taskPool.reduce!"a + b"(MyIota());
+}
+
 /**
 Returns a lazily initialized global instantiation of `TaskPool`.
 This function can safely be called concurrently from multiple non-worker
diff --git a/libphobos/src/std/process.d b/libphobos/src/std/process.d
index 7ec8fa1dc59..98c5b946748 100644
--- a/libphobos/src/std/process.d
+++ b/libphobos/src/std/process.d
@@ -1498,10 +1498,10 @@  package(std) string searchPathFor(scope const(char)[] executable)
     @safe
 {
     import std.algorithm.iteration : splitter;
-    import std.conv : text;
+    import std.conv : to;
     import std.path : chainPath;
 
-    string result;
+    typeof(return) result;
 
     environment.getImpl("PATH",
         (scope const(char)[] path)
@@ -1514,7 +1514,7 @@  package(std) string searchPathFor(scope const(char)[] executable)
                 auto execPath = chainPath(dir, executable);
                 if (isExecutable(execPath))
                 {
-                    result = text(execPath);
+                    result = execPath.to!(typeof(result));
                     return;
                 }
             }
@@ -1580,6 +1580,7 @@  private void setCLOEXEC(int fd, bool on) nothrow @nogc
 // calls, but we make do...
 version (Posix) @system unittest
 {
+    import core.stdc.errno : errno;
     import core.sys.posix.fcntl : open, O_RDONLY;
     import core.sys.posix.unistd : close;
     import std.algorithm.searching : canFind, findSplitBefore;
@@ -1594,7 +1595,20 @@  version (Posix) @system unittest
     scope(exit) std.file.rmdirRecurse(directory);
     auto path = buildPath(directory, "tmp");
     std.file.write(path, null);
+    errno = 0;
     auto fd = open(path.tempCString, O_RDONLY);
+    if (fd == -1)
+    {
+        import core.stdc.string : strerror;
+        import std.stdio : stderr;
+        import std.string : fromStringz;
+
+        // For the CI logs
+        stderr.writefln("%s: could not open '%s': %s",
+            __FUNCTION__, path, strerror(errno).fromStringz);
+        // TODO: should we retry here instead?
+        return;
+    }
     scope(exit) close(fd);
 
     // command >&2 (or any other number) checks whethether that number
@@ -1642,7 +1656,12 @@  version (Posix) @system unittest
         if (lsofRes.status == 0)
         {
             assert(!lsofRes.output.canFind(path));
-            assert(execute(lsof.path, null, Config.inheritFDs).output.canFind(path));
+            auto lsofOut = execute(lsof.path, null, Config.inheritFDs).output;
+            if (!lsofOut.canFind(path))
+            {
+                std.stdio.stderr.writeln(__FILE__, ':', __LINE__,
+                    ": Warning: unexpected lsof output:", lsofOut);
+            }
             return;
         }
 
diff --git a/libphobos/src/std/random.d b/libphobos/src/std/random.d
index 441bc5d5533..a3483561134 100644
--- a/libphobos/src/std/random.d
+++ b/libphobos/src/std/random.d
@@ -1799,13 +1799,19 @@  how excellent the source of entropy is.
                 {
                     db 0x0f, 0xc7, 0xf0; // rdrand EAX
                     jnc LnotUsingRdrand;
+                    mov result, EAX;
                     // Some AMD CPUs shipped with bugs where RDRAND could fail
                     // but still set the carry flag to 1. In those cases the
                     // output will be -1.
                     cmp EAX, 0xffff_ffff;
+                    jne LusingRdrand;
+                    // If result was -1 verify RDAND isn't constantly returning -1.
+                    db 0x0f, 0xc7, 0xf0;
+                    jnc LusingRdrand;
+                    cmp EAX, 0xffff_ffff;
                     je LnotUsingRdrand;
-                    mov result, EAX;
                 }
+            LusingRdrand:
                 return result;
             }
         LnotUsingRdrand:
@@ -1853,13 +1859,19 @@  if (isUnsigned!UIntType)
                             {
                                 db 0x0f, 0xc7, 0xf0; // rdrand EAX
                                 jnc LnotUsingRdrand;
+                                mov result, EAX;
                                 // Some AMD CPUs shipped with bugs where RDRAND could fail
                                 // but still set the carry flag to 1. In those cases the
                                 // output will be -1.
                                 cmp EAX, 0xffff_ffff;
+                                jne LusingRdrand;
+                                // If result was -1 verify RDAND isn't constantly returning -1.
+                                db 0x0f, 0xc7, 0xf0;
+                                jnc LusingRdrand;
+                                cmp EAX, 0xffff_ffff;
                                 je LnotUsingRdrand;
-                                mov result, EAX;
                             }
+                        LusingRdrand:
                             return cast(UIntType) result;
                         }
                         else version (D_InlineAsm_X86_64)
@@ -1869,13 +1881,19 @@  if (isUnsigned!UIntType)
                             {
                                 db 0x48, 0x0f, 0xc7, 0xf0; // rdrand RAX
                                 jnc LnotUsingRdrand;
+                                mov result, RAX;
                                 // Some AMD CPUs shipped with bugs where RDRAND could fail
                                 // but still set the carry flag to 1. In those cases the
                                 // output will be -1.
                                 cmp RAX, 0xffff_ffff_ffff_ffff;
+                                jne LusingRdrand;
+                                // If result was -1 verify RDAND isn't constantly returning -1.
+                                db 0x48, 0x0f, 0xc7, 0xf0;
+                                jnc LusingRdrand;
+                                cmp RAX, 0xffff_ffff_ffff_ffff;
                                 je LnotUsingRdrand;
-                                mov result, RAX;
                             }
+                        LusingRdrand:
                             return result;
                         }
                         else
diff --git a/libphobos/src/std/range/interfaces.d b/libphobos/src/std/range/interfaces.d
index 4f8eba73278..475f35b51da 100644
--- a/libphobos/src/std/range/interfaces.d
+++ b/libphobos/src/std/range/interfaces.d
@@ -100,7 +100,9 @@  interface InputRange(E) {
     ///
     @property E front();
 
-    ///
+    /**Calls $(REF moveFront, std, range, primitives) on the wrapped range, if
+     * possible. Otherwise, throws an $(LREF UnsupportedRangeMethod) exception.
+     */
     E moveFront();
 
     ///
@@ -162,7 +164,9 @@  interface BidirectionalRange(E) : ForwardRange!(E) {
     ///
     @property E back();
 
-    ///
+    /**Calls $(REF moveBack, std, range, primitives) on the wrapped range, if
+     * possible. Otherwise, throws an $(LREF UnsupportedRangeMethod) exception
+     */
     E moveBack();
 
     ///
@@ -197,7 +201,9 @@  interface RandomAccessFinite(E) : BidirectionalRange!(E) {
 
 /**Interface for an infinite random access range of type `E`.*/
 interface RandomAccessInfinite(E) : ForwardRange!E {
-    ///
+    /**Calls $(REF moveAt, std, range, primitives) on the wrapped range, if
+     * possible. Otherwise, throws an $(LREF UnsupportedRangeMethod) exception.
+     */
     E moveAt(size_t);
 
     ///
@@ -377,7 +383,11 @@  if (isInputRange!(Unqual!R))
             @property E front() { return _range.front; }
 
             E moveFront() {
-                return _range.moveFront();
+                static if (__traits(compiles, _range.moveFront()))
+                    return _range.moveFront();
+                else
+                    throw new UnsupportedRangeMethod(
+                        "Cannot move the front of a(n) `" ~ R.stringof ~ "`");
             }
 
             void popFront() { _range.popFront(); }
@@ -402,7 +412,11 @@  if (isInputRange!(Unqual!R))
                 @property E back() { return _range.back; }
 
                 E moveBack() {
-                    return _range.moveBack();
+                    static if (__traits(compiles, _range.moveFront()))
+                        return _range.moveBack();
+                    else
+                        throw new UnsupportedRangeMethod(
+                            "Cannot move the back of a(n) `" ~ R.stringof ~ "`");
                 }
 
                 void popBack() { return _range.popBack(); }
@@ -422,7 +436,11 @@  if (isInputRange!(Unqual!R))
                 }
 
                 E moveAt(size_t index) {
-                    return _range.moveAt(index);
+                    static if (__traits(compiles, _range.moveAt(index)))
+                        return _range.moveAt(index);
+                    else
+                        throw new UnsupportedRangeMethod(
+                            "Cannot move an element of a(n) `" ~ R.stringof ~ "`");
                 }
 
                 static if (hasAssignableElements!R)
@@ -520,6 +538,14 @@  template outputRangeObject(E...) {
      static assert(is(typeof(appWrapped) : OutputRange!(uint)));
 }
 
+/// Thrown when an interface method is not supported by the wrapped range
+class UnsupportedRangeMethod : Exception
+{
+    import std.exception : basicExceptionCtors;
+
+    mixin basicExceptionCtors;
+}
+
 @system unittest
 {
     import std.algorithm.comparison : equal;
@@ -568,3 +594,16 @@  template outputRangeObject(E...) {
     assert(app.data.length == 3);
     assert(equal(app.data, [1,2,3]));
 }
+
+// https://issues.dlang.org/show_bug.cgi?id=19544
+@safe unittest
+{
+    import std.range : repeat;
+
+    static struct HasCC
+    {
+        inout this(ref inout typeof(this)) {}
+    }
+
+    auto r = repeat(HasCC.init).inputRangeObject;
+}
diff --git a/libphobos/src/std/range/package.d b/libphobos/src/std/range/package.d
index 86bd4a1dd19..a21f4d01745 100644
--- a/libphobos/src/std/range/package.d
+++ b/libphobos/src/std/range/package.d
@@ -902,7 +902,7 @@  if (Ranges.length > 0 &&
         private:
             alias R = staticMap!(Unqual, Ranges);
             alias RvalueElementType = CommonType!(staticMap!(.ElementType, R));
-            private template sameET(A)
+            template sameET(A)
             {
                 enum sameET = is(.ElementType!A == RvalueElementType);
             }
@@ -8427,7 +8427,7 @@  if (isForwardRange!Source && hasLength!Source)
     /// Ditto
     @property bool empty()
     {
-        return _source.empty;
+        return _chunkCount == 0;
     }
 
     /// Ditto
@@ -9713,9 +9713,18 @@  if (Values.length > 1)
 {
     private enum arity = Values.length;
 
+    private alias UnqualValues = staticMap!(Unqual, Values);
+
     private this(return scope ref Values values)
     {
-        this.values = values;
+        ref @trusted unqual(T)(ref T x){return cast() x;}
+
+        // TODO: this calls any possible copy constructors without qualifiers.
+        // Find a way to initialize values using qualified copy constructors.
+        static foreach (i; 0 .. Values.length)
+        {
+            this.values[i] = unqual(values[i]);
+        }
         this.backIndex = arity;
     }
 
@@ -9760,7 +9769,7 @@  if (Values.length > 1)
 
     alias opDollar = length;
 
-    CommonType!Values opIndex(size_t idx)
+    @trusted CommonType!Values opIndex(size_t idx)
     {
         // when i + idx points to elements popped
         // with popBack
@@ -9768,7 +9777,7 @@  if (Values.length > 1)
         final switch (frontIndex + idx)
             static foreach (i, T; Values)
             case i:
-                return values[i];
+                return cast(T) values[i];
     }
 
     OnlyResult opSlice()
@@ -9800,12 +9809,15 @@  if (Values.length > 1)
     {
         import std.traits : hasElaborateAssign;
         static if (hasElaborateAssign!T)
-            private Values values;
+            private UnqualValues values;
         else
-            private Values values = void;
+            private UnqualValues values = void;
     }
     else
-        private Values values;
+        // These may alias to shared or immutable data. Do not let the user
+        // to access these directly, and do not allow mutation without checking
+        // the qualifier.
+        private UnqualValues values;
 }
 
 // Specialize for single-element results
@@ -9814,12 +9826,12 @@  private struct OnlyResult(T)
     @property T front()
     {
         assert(!empty, "Attempting to fetch the front of an empty Only range");
-        return _value;
+        return fetchFront();
     }
     @property T back()
     {
         assert(!empty, "Attempting to fetch the back of an empty Only range");
-        return _value;
+        return fetchFront();
     }
     @property bool empty() const { return _empty; }
     @property size_t length() const { return !_empty; }
@@ -9838,14 +9850,17 @@  private struct OnlyResult(T)
 
     private this()(return scope auto ref T value)
     {
-        this._value = value;
+        ref @trusted unqual(ref T x){return cast() x;}
+        // TODO: this calls the possible copy constructor without qualifiers.
+        // Find a way to initialize value using a qualified copy constructor.
+        this._value = unqual(value);
         this._empty = false;
     }
 
     T opIndex(size_t i)
     {
         assert(!_empty && i == 0, "Attempting to fetch an out of bounds index from an Only range");
-        return _value;
+        return fetchFront();
     }
 
     OnlyResult opSlice()
@@ -9868,35 +9883,14 @@  private struct OnlyResult(T)
         return copy;
     }
 
+    // This may alias to shared or immutable data. Do not let the user
+    // to access this directly, and do not allow mutation without checking
+    // the qualifier.
     private Unqual!T _value;
     private bool _empty = true;
-}
-
-// Specialize for the empty range
-private struct OnlyResult()
-{
-    private static struct EmptyElementType {}
-
-    bool empty() @property { return true; }
-    size_t length() const @property { return 0; }
-    alias opDollar = length;
-    EmptyElementType front() @property { assert(false); }
-    void popFront() { assert(false); }
-    EmptyElementType back() @property { assert(false); }
-    void popBack() { assert(false); }
-    OnlyResult save() @property { return this; }
-
-    EmptyElementType opIndex(size_t i)
-    {
-        assert(false);
-    }
-
-    OnlyResult opSlice() { return this; }
-
-    OnlyResult opSlice(size_t from, size_t to)
+    private @trusted T fetchFront()
     {
-        assert(from == 0 && to == 0);
-        return this;
+        return *cast(T*)&_value;
     }
 }
 
@@ -9921,11 +9915,20 @@  Returns:
 See_Also: $(LREF chain) to chain ranges
  */
 auto only(Values...)(return scope Values values)
-if (!is(CommonType!Values == void) || Values.length == 0)
+if (!is(CommonType!Values == void))
 {
     return OnlyResult!Values(values);
 }
 
+/// ditto
+auto only()()
+{
+    // cannot use noreturn due to issue 22383
+    struct EmptyElementType {}
+    EmptyElementType[] result;
+    return result;
+}
+
 ///
 @safe unittest
 {
@@ -10157,6 +10160,19 @@  if (!is(CommonType!Values == void) || Values.length == 0)
     assert(range.join == "Hello World");
 }
 
+// https://issues.dlang.org/show_bug.cgi?id=21022
+@safe pure nothrow unittest
+{
+    struct S
+    {
+        int* mem;
+    }
+
+    immutable S x;
+    immutable(S)[] arr;
+    auto r1 = arr.chain(x.only, only(x, x));
+}
+
 /**
 Iterate over `range` with an attached index variable.
 
@@ -12740,8 +12756,12 @@  if (isInputRange!R && isIntegral!(ElementType!R))
 
         import std.exception : assertThrown;
 
-        // Check out of bounds error
-        assertThrown!Error(bw[2 * bitsNum - 1]);
+        version (D_NoBoundsChecks) {}
+        else
+        {
+            // Check out of bounds error
+            assertThrown!Error(bw[2 * bitsNum - 1]);
+        }
 
         bw[2] = true;
         assert(bw[2] == true);
diff --git a/libphobos/src/std/range/primitives.d b/libphobos/src/std/range/primitives.d
index 9c61ff5253a..c092a9d0946 100644
--- a/libphobos/src/std/range/primitives.d
+++ b/libphobos/src/std/range/primitives.d
@@ -2562,3 +2562,20 @@  package(std) mixin template ImplementLength(alias member)
         alias opDollar = length;
     }
 }
+
+@safe unittest
+{
+    import std.meta : AliasSeq;
+
+    foreach (alias E; AliasSeq!(noreturn, const(noreturn), immutable(noreturn) ))
+    {
+        alias R = E[];
+
+        static assert(isInputRange!R);
+        static assert(isForwardRange!R);
+        static assert(isBidirectionalRange!R);
+        static assert(isRandomAccessRange!R);
+    }
+
+    static assert(isOutputRange!(noreturn[], noreturn));
+}
diff --git a/libphobos/src/std/socket.d b/libphobos/src/std/socket.d
index be0aeba5ca8..f8908cf76ef 100644
--- a/libphobos/src/std/socket.d
+++ b/libphobos/src/std/socket.d
@@ -2121,23 +2121,6 @@  enum SocketFlags: int
 }
 
 
-private mixin template FieldProxy(string target, string field)
-{
-    mixin(`
-        @property typeof(`~target~`) `~field~`() const pure nothrow @nogc
-        {
-            return `~target~`;
-        }
-
-        /// ditto
-        @property typeof(`~target~`) `~field~`(typeof(`~target~`) value) pure nothrow @nogc
-        {
-            return `~target~` = value;
-        }
-    `);
-}
-
-
 /// Duration timeout value.
 struct TimeVal
 {
@@ -2145,16 +2128,18 @@  struct TimeVal
     alias tv_sec_t = typeof(ctimeval.tv_sec);
     alias tv_usec_t = typeof(ctimeval.tv_usec);
 
-    version (StdDdoc) // no DDoc for string mixins, can't forward individual fields
+    /// Number of _seconds.
+    pure nothrow @nogc @property
+    ref inout(tv_sec_t) seconds() inout return
     {
-        tv_sec_t seconds;           /// Number of _seconds.
-        tv_usec_t microseconds;     /// Number of additional _microseconds.
+        return ctimeval.tv_sec;
     }
-    else
+
+    /// Number of additional _microseconds.
+    pure nothrow @nogc @property
+    ref inout(tv_usec_t) microseconds() inout return
     {
-        // D interface
-        mixin FieldProxy!(`ctimeval.tv_sec`, `seconds`);
-        mixin FieldProxy!(`ctimeval.tv_usec`, `microseconds`);
+        return ctimeval.tv_usec;
     }
 }
 
@@ -2567,18 +2552,21 @@  struct Linger
 {
     _clinger clinger;
 
-    version (StdDdoc) // no DDoc for string mixins, can't forward individual fields
+    private alias l_onoff_t = typeof(_clinger.init.l_onoff );
+    private alias l_linger_t = typeof(_clinger.init.l_linger);
+
+    /// Nonzero for _on.
+    pure nothrow @nogc @property
+    ref inout(l_onoff_t) on() inout return
     {
-        private alias l_onoff_t = typeof(_clinger.init.l_onoff );
-        private alias l_linger_t = typeof(_clinger.init.l_linger);
-        l_onoff_t  on;   /// Nonzero for _on.
-        l_linger_t time; /// Linger _time.
+        return clinger.l_onoff;
     }
-    else
+
+    /// Linger _time.
+    pure nothrow @nogc @property
+    ref inout(l_linger_t) time() inout return
     {
-        // D interface
-        mixin FieldProxy!(`clinger.l_onoff`, `on`);
-        mixin FieldProxy!(`clinger.l_linger`, `time`);
+        return clinger.l_linger;
     }
 }
 
@@ -3119,21 +3107,17 @@  public:
             from = createAddress();
         socklen_t nameLen = from.nameLen;
         version (Windows)
-        {
             auto read = .recvfrom(sock, buf.ptr, capToInt(buf.length), cast(int) flags, from.name, &nameLen);
-            from.setNameLen(nameLen);
-            assert(from.addressFamily == _family);
-            // if (!read) //connection closed
-            return read;
-        }
+
         else
-        {
             auto read = .recvfrom(sock, buf.ptr, buf.length, cast(int) flags, from.name, &nameLen);
+
+        if (read >= 0)
+        {
             from.setNameLen(nameLen);
             assert(from.addressFamily == _family);
-            // if (!read) //connection closed
-            return read;
         }
+        return read;
     }
 
 
@@ -3576,6 +3560,17 @@  class UdpSocket: Socket
     }
 }
 
+@safe unittest
+{
+    byte[] buf;
+    buf.length = 1;
+    Address addr;
+    auto s = new UdpSocket;
+    s.blocking = false;
+    s.bind(new InternetAddress(InternetAddress.PORT_ANY));
+    s.receiveFrom(buf, addr);
+}
+
 // https://issues.dlang.org/show_bug.cgi?id=16514
 @safe unittest
 {
diff --git a/libphobos/src/std/stdio.d b/libphobos/src/std/stdio.d
index a88beb8ff32..d3097d548ce 100644
--- a/libphobos/src/std/stdio.d
+++ b/libphobos/src/std/stdio.d
@@ -281,17 +281,14 @@  else version (GENERIC_IO)
     nothrow:
     @nogc:
 
-    private int _FPUTC(int c, _iobuf* fp) { return fputc(c, cast(shared) fp); }
-    private int _FPUTWC(wchar_t c, _iobuf* fp)
+    extern (C) private
     {
-        import core.stdc.wchar_ : fputwc;
-        return fputwc(c, cast(shared) fp);
-    }
-    private int _FGETC(_iobuf* fp) { return fgetc(cast(shared) fp); }
-    private int _FGETWC(_iobuf* fp)
-    {
-        import core.stdc.wchar_ : fgetwc;
-        return fgetwc(cast(shared) fp);
+        static import core.stdc.wchar_;
+
+        pragma(mangle, fputc.mangleof) int _FPUTC(int c, _iobuf* fp);
+        pragma(mangle, core.stdc.wchar_.fputwc.mangleof) int _FPUTWC(wchar_t c, _iobuf* fp);
+        pragma(mangle, fgetc.mangleof) int _FGETC(_iobuf* fp);
+        pragma(mangle, core.stdc.wchar_.fgetwc.mangleof) int _FGETWC(_iobuf* fp);
     }
 
     version (Posix)
@@ -307,27 +304,19 @@  else version (GENERIC_IO)
     // @@@DEPRECATED_2.107@@@
     deprecated("internal function fputc_unlocked was unintentionally available "
                ~ "from std.stdio and will be removed afer 2.107")
-    int fputc_unlocked(int c, _iobuf* fp) { return fputc(c, cast(shared) fp); }
+    extern (C) pragma(mangle, fputc.mangleof) int fputc_unlocked(int c, _iobuf* fp);
     // @@@DEPRECATED_2.107@@@
     deprecated("internal function fputwc_unlocked was unintentionally available "
                ~ "from std.stdio and will be removed afer 2.107")
-    int fputwc_unlocked(wchar_t c, _iobuf* fp)
-    {
-        import core.stdc.wchar_ : fputwc;
-        return fputwc(c, cast(shared) fp);
-    }
+    extern (C) pragma(mangle, core.stdc.wchar_.fputwc.mangleof) int fputwc_unlocked(wchar_t c, _iobuf* fp);
     // @@@DEPRECATED_2.107@@@
     deprecated("internal function fgetc_unlocked was unintentionally available "
                ~ "from std.stdio and will be removed afer 2.107")
-    int fgetc_unlocked(_iobuf* fp) { return fgetc(cast(shared) fp); }
+    extern (C) pragma(mangle, fgetc.mangleof) int fgetc_unlocked(_iobuf* fp);
     // @@@DEPRECATED_2.107@@@
     deprecated("internal function fgetwc_unlocked was unintentionally available "
                ~ "from std.stdio and will be removed afer 2.107")
-    int fgetwc_unlocked(_iobuf* fp)
-    {
-        import core.stdc.wchar_ : fgetwc;
-        return fgetwc(cast(shared) fp);
-    }
+    extern (C) pragma(mangle, core.stdc.wchar_.fgetwc.mangleof) int fgetwc_unlocked(_iobuf* fp);
 
     // @@@DEPRECATED_2.107@@@
     deprecated("internal alias FPUTC was unintentionally available from "
@@ -363,6 +352,16 @@  else
     static assert(0, "unsupported C I/O system");
 }
 
+private extern (C) @nogc nothrow
+{
+    pragma(mangle, _FPUTC.mangleof) int trustedFPUTC(int ch, _iobuf* h) @trusted;
+
+    version (DIGITAL_MARS_STDIO)
+        pragma(mangle, _FPUTWC.mangleof) int trustedFPUTWC(int ch, _iobuf* h) @trusted;
+    else
+        pragma(mangle, _FPUTWC.mangleof) int trustedFPUTWC(wchar_t ch, _iobuf* h) @trusted;
+}
+
 static if (__traits(compiles, core.sys.posix.stdio.getdelim))
 {
     extern(C) nothrow @nogc
@@ -3183,16 +3182,7 @@  is empty, throws an `Exception`. In case of an I/O error throws
         /// ditto
         void put(C)(scope C c) @safe if (isSomeChar!C || is(C : const(ubyte)))
         {
-            import std.traits : Parameters;
             import std.utf : decodeFront, encode, stride;
-            static auto trustedFPUTC(int ch, _iobuf* h) @trusted
-            {
-                return _FPUTC(ch, h);
-            }
-            static auto trustedFPUTWC(Parameters!_FPUTWC[0] ch, _iobuf* h) @trusted
-            {
-                return _FPUTWC(ch, h);
-            }
 
             static if (c.sizeof == 1)
             {
diff --git a/libphobos/src/std/string.d b/libphobos/src/std/string.d
index 420b68abe6a..5c9a2c946ba 100644
--- a/libphobos/src/std/string.d
+++ b/libphobos/src/std/string.d
@@ -1759,8 +1759,8 @@  if (isSomeChar!Char && isSomeChar!Char2)
         haystack = String to search for needles in.
         needles = Strings to search for in haystack.
         startIdx = slices haystack like this $(D haystack[startIdx .. $]). If
-            the startIdx is greater equal the length of haystack the functions
-            returns `-1`.
+            the startIdx is greater than or equal to the length of haystack the
+            functions returns `-1`.
         cs = Indicates whether the comparisons are case sensitive.
 */
 ptrdiff_t indexOfAny(Char,Char2)(const(Char)[] haystack, const(Char2)[] needles,
@@ -1926,8 +1926,8 @@  if (isSomeChar!Char && isSomeChar!Char2)
         haystack = String to search for needles in.
         needles = Strings to search for in haystack.
         stopIdx = slices haystack like this $(D haystack[0 .. stopIdx]). If
-            the stopIdx is greater equal the length of haystack the functions
-            returns `-1`.
+            the stopIdx is greater than or equal to the length of haystack the
+            functions returns `-1`.
         cs = Indicates whether the comparisons are case sensitive.
 */
 ptrdiff_t lastIndexOfAny(Char,Char2)(const(Char)[] haystack,
@@ -2105,8 +2105,8 @@  if (isSomeChar!Char && isSomeChar!Char2)
         haystack = String to search for needles in.
         needles = Strings to search for in haystack.
         startIdx = slices haystack like this $(D haystack[startIdx .. $]). If
-            the startIdx is greater equal the length of haystack the functions
-            returns `-1`.
+            the startIdx is greater than or equal to the length of haystack the
+            functions returns `-1`.
         cs = Indicates whether the comparisons are case sensitive.
 */
 ptrdiff_t indexOfNeither(Char,Char2)(const(Char)[] haystack,
@@ -2265,8 +2265,8 @@  if (isSomeChar!Char && isSomeChar!Char2)
         haystack = String to search for needles in.
         needles = Strings to search for in haystack.
         stopIdx = slices haystack like this $(D haystack[0 .. stopIdx]) If
-        the stopIdx is greater equal the length of haystack the functions
-        returns `-1`.
+            the stopIdx is greater than or equal to the length of haystack the
+            functions returns `-1`.
         cs = Indicates whether the comparisons are case sensitive.
 */
 ptrdiff_t lastIndexOfNeither(Char,Char2)(const(Char)[] haystack,
diff --git a/libphobos/src/std/system.d b/libphobos/src/std/system.d
index 7a115da5409..55fcfd773b7 100644
--- a/libphobos/src/std/system.d
+++ b/libphobos/src/std/system.d
@@ -36,6 +36,7 @@  immutable
         watchOS,   /// watchOS
         freeBSD,   /// FreeBSD
         netBSD,    /// NetBSD
+        openBSD,   /// OpenBSD
         dragonFlyBSD, /// DragonFlyBSD
         solaris,   /// Solaris
         android,   /// Android
@@ -54,6 +55,7 @@  immutable
     else version (watchOS) OS os = OS.watchOS;
     else version (FreeBSD) OS os = OS.freeBSD;
     else version (NetBSD)  OS os = OS.netBSD;
+    else version (OpenBSD) OS os = OS.openBSD;
     else version (DragonFlyBSD) OS os = OS.dragonFlyBSD;
     else version (Posix)   OS os = OS.otherPosix;
     else OS os = OS.unknown;
diff --git a/libphobos/src/std/traits.d b/libphobos/src/std/traits.d
index 230a7c677cf..154141588ba 100644
--- a/libphobos/src/std/traits.d
+++ b/libphobos/src/std/traits.d
@@ -562,15 +562,10 @@  struct MyStruct {}
 static assert(fullyQualifiedName!(const MyStruct[]) == "const(myModule.MyStruct[])");
 -----------------
 */
-template fullyQualifiedName(T...)
-if (T.length == 1)
-{
+enum fullyQualifiedName(T) = fqnType!(T, false, false, false, false);
 
-    static if (is(T))
-        enum fullyQualifiedName = fqnType!(T[0], false, false, false, false);
-    else
-        enum fullyQualifiedName = fqnSym!(T[0]);
-}
+/// ditto
+enum fullyQualifiedName(alias T) = fqnSym!(T);
 
 ///
 @safe unittest
@@ -986,8 +981,8 @@  private template fqnType(T,
  * is not part of a type, but the attribute of the function
  * (see template $(LREF functionAttributes)).
  */
-template ReturnType(func...)
-if (func.length == 1 && isCallable!func)
+template ReturnType(alias func)
+if (isCallable!func)
 {
     static if (is(FunctionTypeOf!func R == return))
         alias ReturnType = R;
@@ -1045,8 +1040,8 @@  Get, as a tuple, the types of the parameters to a function, a pointer
 to function, a delegate, a struct with an `opCall`, a pointer to a
 struct with an `opCall`, or a class with an `opCall`.
 */
-template Parameters(func...)
-if (func.length == 1 && isCallable!func)
+template Parameters(alias func)
+if (isCallable!func)
 {
     static if (is(FunctionTypeOf!func P == function))
         alias Parameters = P;
@@ -1095,9 +1090,8 @@  alias ParameterTypeTuple = Parameters;
 Returns the number of arguments of function `func`.
 arity is undefined for variadic functions.
 */
-template arity(func...)
-if (func.length == 1 && isCallable!func &&
-    variadicFunctionStyle!func == Variadic.no)
+template arity(alias func)
+if (isCallable!func && variadicFunctionStyle!func == Variadic.no)
 {
     enum size_t arity = Parameters!func.length;
 }
@@ -1143,8 +1137,8 @@  enum ParameterStorageClass : uint
 }
 
 /// ditto
-template ParameterStorageClassTuple(func...)
-if (func.length == 1 && isCallable!func)
+template ParameterStorageClassTuple(alias func)
+if (isCallable!func)
 {
     alias Func = FunctionTypeOf!func;
 
@@ -1308,8 +1302,8 @@  template extractParameterStorageClassFlags(Attribs...)
 /**
 Get, as a tuple, the identifiers of the parameters to a function symbol.
  */
-template ParameterIdentifierTuple(func...)
-if (func.length == 1 && isCallable!func)
+template ParameterIdentifierTuple(alias func)
+if (isCallable!func)
 {
     static if (is(FunctionTypeOf!func PT == __parameters))
     {
@@ -1331,7 +1325,7 @@  if (func.length == 1 && isCallable!func)
     }
     else
     {
-        static assert(0, func[0].stringof ~ " is not a function");
+        static assert(0, func.stringof ~ " is not a function");
 
         // Define dummy entities to avoid pointless errors
         template Get(size_t i) { enum Get = ""; }
@@ -1407,11 +1401,11 @@  if (func.length == 1 && isCallable!func)
 Get, as a tuple, the default value of the parameters to a function symbol.
 If a parameter doesn't have the default value, `void` is returned instead.
  */
-template ParameterDefaults(func...)
-if (func.length == 1 && isCallable!func)
+template ParameterDefaults(alias func)
+if (isCallable!func)
 {
     alias param_names = ParameterIdentifierTuple!func;
-    static if (is(FunctionTypeOf!(func[0]) PT == __parameters))
+    static if (is(FunctionTypeOf!(func) PT == __parameters))
     {
         template Get(size_t i)
         {
@@ -1444,7 +1438,7 @@  if (func.length == 1 && isCallable!func)
     }
     else
     {
-        static assert(0, func[0].stringof ~ " is not a function");
+        static assert(0, func.stringof ~ " is not a function");
 
         // Define dummy entities to avoid pointless errors
         template Get(size_t i) { enum Get = ""; }
@@ -1559,8 +1553,8 @@  enum FunctionAttribute : uint
 }
 
 /// ditto
-template functionAttributes(func...)
-if (func.length == 1 && isCallable!func)
+template functionAttributes(alias func)
+if (isCallable!func)
 {
     // @bug: workaround for opCall
     alias FuncSym = Select!(is(typeof(__traits(getFunctionAttributes, func))),
@@ -2090,8 +2084,8 @@  Params:
 Returns:
     one of the strings "D", "C", "C++", "Windows", "Objective-C", or "System".
 */
-template functionLinkage(func...)
-if (func.length == 1 && isCallable!func)
+template functionLinkage(alias func)
+if (isCallable!func)
 {
     enum string functionLinkage = __traits(getLinkage, FunctionTypeOf!func);
 }
@@ -2148,8 +2142,8 @@  enum Variadic
 }
 
 /// ditto
-template variadicFunctionStyle(func...)
-if (func.length == 1 && isCallable!func)
+template variadicFunctionStyle(alias func)
+if (isCallable!func)
 {
     enum string varargs = __traits(getFunctionVariadicStyle, FunctionTypeOf!func);
     enum Variadic variadicFunctionStyle =
@@ -2198,25 +2192,25 @@  Note:
 Do not confuse function types with function pointer types; function types are
 usually used for compile-time reflection purposes.
  */
-template FunctionTypeOf(func...)
-if (func.length == 1 && isCallable!func)
+template FunctionTypeOf(alias func)
+if (isCallable!func)
 {
-    static if ((is(typeof(& func[0]) Fsym : Fsym*) && is(Fsym == function)) || is(typeof(& func[0]) Fsym == delegate))
+    static if ((is(typeof(& func) Fsym : Fsym*) && is(Fsym == function)) || is(typeof(& func) Fsym == delegate))
     {
         alias FunctionTypeOf = Fsym; // HIT: (nested) function symbol
     }
-    else static if (is(typeof(& func[0].opCall) Fobj == delegate) || is(typeof(& func[0].opCall!()) Fobj == delegate))
+    else static if (is(typeof(& func.opCall) Fobj == delegate) || is(typeof(& func.opCall!()) Fobj == delegate))
     {
         alias FunctionTypeOf = Fobj; // HIT: callable object
     }
     else static if (
-            (is(typeof(& func[0].opCall) Ftyp : Ftyp*) && is(Ftyp == function)) ||
-            (is(typeof(& func[0].opCall!()) Ftyp : Ftyp*) && is(Ftyp == function))
+            (is(typeof(& func.opCall) Ftyp : Ftyp*) && is(Ftyp == function)) ||
+            (is(typeof(& func.opCall!()) Ftyp : Ftyp*) && is(Ftyp == function))
         )
     {
         alias FunctionTypeOf = Ftyp; // HIT: callable type
     }
-    else static if (is(func[0] T) || is(typeof(func[0]) T))
+    else static if (is(func T) || is(typeof(func) T))
     {
         static if (is(T == function))
             alias FunctionTypeOf = T;    // HIT: function
@@ -2675,12 +2669,8 @@  template hasNested(T)
  */
 template Fields(T)
 {
-    static if (is(T == struct) || is(T == union))
-        alias Fields = typeof(T.tupleof[0 .. $ - isNested!T]);
-    else static if (is(T == class) || is(T == interface))
-        alias Fields = typeof(T.tupleof);
-    else
-        alias Fields = AliasSeq!T;
+    import core.internal.traits : _Fields = Fields;
+    alias Fields = _Fields!T;
 }
 
 ///
@@ -2847,6 +2837,8 @@  template RepresentationTypeTuple(T)
     struct S5 { int a; Rebindable!(immutable Object) b; }
     alias R2 = RepresentationTypeTuple!S5;
     static assert(R2.length == 2 && is(R2[0] == int) && is(R2[1] == immutable(Object)));
+
+    static assert(is(RepresentationTypeTuple!noreturn == AliasSeq!noreturn));
 }
 
 @safe unittest
@@ -2869,7 +2861,7 @@  private template RepresentationTypeTupleImpl(T)
 {
     import std.typecons : Rebindable;
 
-    static if (is(T R: Rebindable!R))
+    static if (is(immutable T == immutable Rebindable!R, R))
     {
         alias RepresentationTypeTupleImpl
             = staticMapMeta!(.RepresentationTypeTupleImpl, RepresentationTypeTupleImpl!R);
@@ -3292,13 +3284,15 @@  template hasAliasing(T...)
     class S15 { S15[1] a; }
     static assert( hasAliasing!S15);
     static assert(!hasAliasing!(immutable(S15)));
+
+    static assert(!hasAliasing!noreturn);
 }
 
 private template hasAliasingImpl(T)
 {
     import std.typecons : Rebindable;
 
-    static if (is(T : Rebindable!R, R))
+    static if (is(immutable T == immutable Rebindable!R, R))
     {
         enum hasAliasingImpl = hasAliasingImpl!R;
     }
@@ -3324,15 +3318,8 @@  $(LI a [context pointer][isNested].))
  */
 template hasIndirections(T)
 {
-    static if (is(T == struct) || is(T == union))
-        enum hasIndirections = anySatisfy!(.hasIndirections, typeof(T.tupleof));
-    else static if (isStaticArray!T && is(T : E[N], E, size_t N))
-        enum hasIndirections = is(E == void) ? true : hasIndirections!E;
-    else static if (isFunctionPointer!T)
-        enum hasIndirections = false;
-    else
-        enum hasIndirections = isPointer!T || isDelegate!T || isDynamicArray!T ||
-            isAssociativeArray!T || is (T == class) || is(T == interface);
+    import core.internal.traits : _hasIndirections = hasIndirections;
+    alias hasIndirections = _hasIndirections!T;
 }
 
 ///
@@ -3409,6 +3396,8 @@  template hasIndirections(T)
     int local;
     struct HasContextPointer { int opCall() { return ++local; } }
     static assert(hasIndirections!HasContextPointer);
+
+    static assert(!hasIndirections!noreturn);
 }
 
 // https://issues.dlang.org/show_bug.cgi?id=12000
@@ -3575,13 +3564,15 @@  template hasUnsharedAliasing(T...)
     static assert( hasUnsharedAliasing!S18);
     static assert( hasUnsharedAliasing!S19);
     static assert(!hasUnsharedAliasing!S20);
+
+    static assert(!hasUnsharedAliasing!noreturn);
 }
 
 private template hasUnsharedAliasingImpl(T)
 {
     import std.typecons : Rebindable;
 
-    static if (is(T R: Rebindable!R))
+    static if (is(immutable T == immutable Rebindable!R, R))
     {
         enum hasUnsharedAliasingImpl = hasUnsharedAliasingImpl!R;
     }
@@ -3603,17 +3594,25 @@  private template hasUnsharedAliasingImpl(T)
     }
 }
 
-/**
- True if `S` or any type embedded directly in the representation of `S`
- defines an elaborate copy constructor. Elaborate copy constructors are
- introduced by defining `this(this)` for a `struct`.
+version (StdDdoc)
+{
+    /**
+       True if `S` or any type embedded directly in the representation of `S`
+       defines an elaborate copy constructor. Elaborate copy constructors are
+       introduced by defining `this(this)` for a `struct`.
 
- Classes and unions never have elaborate copy constructors.
- */
-template hasElaborateCopyConstructor(S)
+       Classes and unions never have elaborate copy constructors.
+    */
+    template hasElaborateCopyConstructor(S)
+    {
+        import core.internal.traits : hasElabCCtor = hasElaborateCopyConstructor;
+        alias hasElaborateCopyConstructor = hasElabCCtor!(S);
+    }
+}
+else
 {
     import core.internal.traits : hasElabCCtor = hasElaborateCopyConstructor;
-    alias hasElaborateCopyConstructor = hasElabCCtor!(S);
+    alias hasElaborateCopyConstructor = hasElabCCtor;
 }
 
 ///
@@ -3732,19 +3731,27 @@  template hasElaborateAssign(S)
     static assert( hasElaborateAssign!SS9);
 }
 
-/**
-   True if `S` or any type directly embedded in the representation
-   of `S` defines an elaborate destructor. Elaborate destructors
-   are introduced by defining `~this()` for a $(D
-   struct).
+version (StdDdoc)
+{
+    /**
+       True if `S` or any type directly embedded in the representation
+       of `S` defines an elaborate destructor. Elaborate destructors
+       are introduced by defining `~this()` for a $(D
+       struct).
 
-   Classes and unions never have elaborate destructors, even
-   though classes may define `~this()`.
- */
-template hasElaborateDestructor(S)
+       Classes and unions never have elaborate destructors, even
+       though classes may define `~this()`.
+    */
+    template hasElaborateDestructor(S)
+    {
+        import core.internal.traits : hasElabDest = hasElaborateDestructor;
+        alias hasElaborateDestructor = hasElabDest!(S);
+    }
+}
+else
 {
     import core.internal.traits : hasElabDest = hasElaborateDestructor;
-    alias hasElaborateDestructor = hasElabDest!(S);
+    alias hasElaborateDestructor = hasElabDest;
 }
 
 ///
@@ -3771,17 +3778,25 @@  template hasElaborateDestructor(S)
     static assert( hasElaborateDestructor!S7);
 }
 
-/**
- True if `S` or any type embedded directly in the representation of `S`
- defines elaborate move semantics. Elaborate move semantics are
- introduced by defining `opPostMove(ref typeof(this))` for a `struct`.
+version (StdDdoc)
+{
+    /**
+       True if `S` or any type embedded directly in the representation of `S`
+       defines elaborate move semantics. Elaborate move semantics are
+       introduced by defining `opPostMove(ref typeof(this))` for a `struct`.
 
- Classes and unions never have elaborate move semantics.
- */
-template hasElaborateMove(S)
+       Classes and unions never have elaborate move semantics.
+    */
+    template hasElaborateMove(S)
+    {
+        import core.internal.traits : hasElabMove = hasElaborateMove;
+        alias hasElaborateMove = hasElabMove!(S);
+    }
+}
+else
 {
     import core.internal.traits : hasElabMove = hasElaborateMove;
-    alias hasElaborateMove = hasElabMove!(S);
+    alias hasElaborateMove = hasElabMove;
 }
 
 ///
@@ -4116,50 +4131,9 @@  int[] abc = cast(int[]) [ EnumMembers!E ];
 template EnumMembers(E)
 if (is(E == enum))
 {
-    import std.meta : AliasSeq;
-    // Supply the specified identifier to an constant value.
-    template WithIdentifier(string ident)
-    {
-        static if (ident == "Symbolize")
-        {
-            template Symbolize(alias value)
-            {
-                enum Symbolize = value;
-            }
-        }
-        else
-        {
-            mixin("template Symbolize(alias "~ ident ~")"
-                 ~"{"
-                     ~"alias Symbolize = "~ ident ~";"
-                 ~"}");
-        }
-    }
-
-    template EnumSpecificMembers(names...)
-    {
-        static if (names.length == 1)
-        {
-            alias EnumSpecificMembers = AliasSeq!(WithIdentifier!(names[0])
-                        .Symbolize!(__traits(getMember, E, names[0])));
-        }
-        else static if (names.length > 0)
-        {
-            alias EnumSpecificMembers =
-                AliasSeq!(
-                    WithIdentifier!(names[0])
-                        .Symbolize!(__traits(getMember, E, names[0])),
-                    EnumSpecificMembers!(names[1 .. $/2]),
-                    EnumSpecificMembers!(names[$/2..$])
-                );
-        }
-        else
-        {
-            alias EnumSpecificMembers = AliasSeq!();
-        }
-    }
-
-    alias EnumMembers = EnumSpecificMembers!(__traits(allMembers, E));
+    alias EnumMembers = AliasSeq!();
+    static foreach (M; __traits(allMembers, E))
+        EnumMembers = AliasSeq!(EnumMembers, __traits(getMember, E, M));
 }
 
 /// Create an array of enumerated values
@@ -4494,14 +4468,7 @@  template InterfacesTuple(T)
  * interfaces. $(D_PARAM TransitiveBaseTypeTuple!Object) yields the
  * empty type tuple.
  */
-template TransitiveBaseTypeTuple(T)
-{
-    static if (is(T == Object))
-        alias TransitiveBaseTypeTuple = AliasSeq!();
-    else
-        alias TransitiveBaseTypeTuple =
-            AliasSeq!(BaseClassesTuple!T, InterfacesTuple!T);
-}
+alias TransitiveBaseTypeTuple(T) = AliasSeq!(BaseClassesTuple!T, InterfacesTuple!T);
 
 ///
 @safe unittest
@@ -4748,22 +4715,13 @@  if (is(C == class) || is(C == interface))
 Returns an alias to the template that `T` is an instance of.
 It will return `void` if a symbol without a template is given.
  */
-template TemplateOf(alias T : Base!Args, alias Base, Args...)
-{
-    alias TemplateOf = Base;
-}
+alias TemplateOf(alias T : Base!Args, alias Base, Args...) = Base;
 
 /// ditto
-template TemplateOf(T : Base!Args, alias Base, Args...)
-{
-    alias TemplateOf = Base;
-}
+alias TemplateOf(T : Base!Args, alias Base, Args...) = Base;
 
 /// ditto
-template TemplateOf(T)
-{
-    alias TemplateOf = void;
-}
+alias TemplateOf(T) = void;
 
 ///
 @safe unittest
@@ -4805,16 +4763,10 @@  template TemplateOf(T)
 /**
 Returns a `AliasSeq` of the template arguments used to instantiate `T`.
  */
-template TemplateArgsOf(alias T : Base!Args, alias Base, Args...)
-{
-    alias TemplateArgsOf = Args;
-}
+alias TemplateArgsOf(alias T : Base!Args, alias Base, Args...) = Args;
 
 /// ditto
-template TemplateArgsOf(T : Base!Args, alias Base, Args...)
-{
-    alias TemplateArgsOf = Args;
-}
+alias TemplateArgsOf(T : Base!Args, alias Base, Args...) = Args;
 
 ///
 @safe unittest
@@ -4850,24 +4802,15 @@  template TemplateArgsOf(T : Base!Args, alias Base, Args...)
     static assert(is(TemplateArgsOf!(Foo10!()) == AliasSeq!()));
 }
 
-
-package template maxAlignment(U...)
-if (isTypeTuple!U)
+// Returns the largest alignment in a type tuple.
+package enum maxAlignment(U...) =
 {
-    static if (U.length == 0)
-        static assert(0);
-    else static if (U.length == 1)
-        enum maxAlignment = U[0].alignof;
-    else static if (U.length == 2)
-        enum maxAlignment = U[0].alignof > U[1].alignof ? U[0].alignof : U[1].alignof;
-    else
-    {
-        enum a = maxAlignment!(U[0 .. ($+1)/2]);
-        enum b = maxAlignment!(U[($+1)/2 .. $]);
-        enum maxAlignment = a > b ? a : b;
-    }
-}
-
+    size_t result = U[0].alignof;
+    static foreach (T; U[1 .. $])
+        if (result < T.alignof)
+            result = T.alignof;
+    return result;
+}();
 
 /**
 Returns class instance alignment.
@@ -4902,25 +4845,10 @@  types have no common type.
  */
 template CommonType(T...)
 {
-    static if (!T.length)
-    {
-        alias CommonType = void;
-    }
-    else static if (T.length == 1)
-    {
-        static if (is(typeof(T[0])))
-        {
-            alias CommonType = typeof(T[0]);
-        }
-        else
-        {
-            alias CommonType = T[0];
-        }
-    }
+    static if (T.length == 1)
+        alias CommonType = typeof(T[0].init);
     else static if (is(typeof(true ? T[0].init : T[1].init) U))
-    {
         alias CommonType = CommonType!(U, T[2 .. $]);
-    }
     else
         alias CommonType = void;
 }
@@ -4966,36 +4894,29 @@  template AllImplicitConversionTargets(T)
 {
     static if (is(T == bool))
         alias AllImplicitConversionTargets =
-            AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong, CentTypeList,
-                       float, double, real, char, wchar, dchar);
+            AliasSeq!(byte, AllImplicitConversionTargets!byte);
     else static if (is(T == byte))
         alias AllImplicitConversionTargets =
-            AliasSeq!(ubyte, short, ushort, int, uint, long, ulong, CentTypeList,
-                       float, double, real, char, wchar, dchar);
+            AliasSeq!(char, ubyte, short, AllImplicitConversionTargets!short);
     else static if (is(T == ubyte))
         alias AllImplicitConversionTargets =
-            AliasSeq!(byte, short, ushort, int, uint, long, ulong, CentTypeList,
-                       float, double, real, char, wchar, dchar);
+            AliasSeq!(byte, char, short, AllImplicitConversionTargets!short);
     else static if (is(T == short))
         alias AllImplicitConversionTargets =
-            AliasSeq!(ushort, int, uint, long, ulong, CentTypeList, float, double, real);
+            AliasSeq!(ushort, wchar, int, AllImplicitConversionTargets!int);
     else static if (is(T == ushort))
         alias AllImplicitConversionTargets =
-            AliasSeq!(short, int, uint, long, ulong, CentTypeList, float, double, real);
+            AliasSeq!(short, wchar, dchar, AllImplicitConversionTargets!dchar);
     else static if (is(T == int))
         alias AllImplicitConversionTargets =
-            AliasSeq!(uint, long, ulong, CentTypeList, float, double, real);
+            AliasSeq!(dchar, uint, long, AllImplicitConversionTargets!long);
     else static if (is(T == uint))
         alias AllImplicitConversionTargets =
-            AliasSeq!(int, long, ulong, CentTypeList, float, double, real);
+            AliasSeq!(dchar, int, long, AllImplicitConversionTargets!long);
     else static if (is(T == long))
-        alias AllImplicitConversionTargets = AliasSeq!(ulong, float, double, real);
+        alias AllImplicitConversionTargets = AliasSeq!(ulong, CentTypeList, float, double, real);
     else static if (is(T == ulong))
-        alias AllImplicitConversionTargets = AliasSeq!(long, float, double, real);
-    else static if (is(cent) && is(T == cent))
-        alias AllImplicitConversionTargets = AliasSeq!(UnsignedCentTypeList, float, double, real);
-    else static if (is(ucent) && is(T == ucent))
-        alias AllImplicitConversionTargets = AliasSeq!(SignedCentTypeList, float, double, real);
+        alias AllImplicitConversionTargets = AliasSeq!(long, CentTypeList, float, double, real);
     else static if (is(T == float))
         alias AllImplicitConversionTargets = AliasSeq!(double, real);
     else static if (is(T == double))
@@ -5004,21 +4925,17 @@  template AllImplicitConversionTargets(T)
         alias AllImplicitConversionTargets = AliasSeq!(float, double);
     else static if (is(T == char))
         alias AllImplicitConversionTargets =
-            AliasSeq!(wchar, dchar, byte, ubyte, short, ushort,
-                       int, uint, long, ulong, CentTypeList, float, double, real);
+            AliasSeq!(byte, ubyte, short, AllImplicitConversionTargets!short);
     else static if (is(T == wchar))
         alias AllImplicitConversionTargets =
-            AliasSeq!(dchar, short, ushort, int, uint, long, ulong, CentTypeList,
-                       float, double, real);
+            AliasSeq!(short, ushort, dchar, AllImplicitConversionTargets!dchar);
     else static if (is(T == dchar))
         alias AllImplicitConversionTargets =
-            AliasSeq!(int, uint, long, ulong, CentTypeList, float, double, real);
-    else static if (is(T : typeof(null)))
-        alias AllImplicitConversionTargets = AliasSeq!(typeof(null));
+            AliasSeq!(int, uint, long, AllImplicitConversionTargets!long);
     else static if (is(T == class))
-        alias AllImplicitConversionTargets = staticMap!(ApplyLeft!(CopyConstness, T), TransitiveBaseTypeTuple!(T));
+        alias AllImplicitConversionTargets = staticMap!(ApplyLeft!(CopyConstness, T), TransitiveBaseTypeTuple!T);
     else static if (is(T == interface))
-        alias AllImplicitConversionTargets = staticMap!(ApplyLeft!(CopyConstness, T), InterfacesTuple!(T));
+        alias AllImplicitConversionTargets = staticMap!(ApplyLeft!(CopyConstness, T), InterfacesTuple!T);
     else static if (isDynamicArray!T && !is(typeof(T.init[0]) == const))
     {
        static if (is(typeof(T.init[0]) == shared))
@@ -5028,8 +4945,12 @@  template AllImplicitConversionTargets(T)
            alias AllImplicitConversionTargets =
            AliasSeq!(const(Unqual!(typeof(T.init[0])))[]);
     }
-    else static if (is(T : void*))
+    else static if (is(T : void*) && !is(T == void*))
         alias AllImplicitConversionTargets = AliasSeq!(void*);
+    else static if (is(cent) && is(T == cent))
+        alias AllImplicitConversionTargets = AliasSeq!(UnsignedCentTypeList, float, double, real);
+    else static if (is(ucent) && is(T == ucent))
+        alias AllImplicitConversionTargets = AliasSeq!(SignedCentTypeList, float, double, real);
     else
         alias AllImplicitConversionTargets = AliasSeq!();
 }
@@ -5040,22 +4961,23 @@  template AllImplicitConversionTargets(T)
     import std.meta : AliasSeq;
 
     static assert(is(AllImplicitConversionTargets!(ulong) == AliasSeq!(long, float, double, real)));
-    static assert(is(AllImplicitConversionTargets!(int) == AliasSeq!(uint, long, ulong, float, double, real)));
+    static assert(is(AllImplicitConversionTargets!(int) == AliasSeq!(dchar, uint, long, ulong, float, double, real)));
     static assert(is(AllImplicitConversionTargets!(float) == AliasSeq!(double, real)));
     static assert(is(AllImplicitConversionTargets!(double) == AliasSeq!(float, real)));
 
-    static assert(is(AllImplicitConversionTargets!(char) == AliasSeq!(
-        wchar, dchar, byte, ubyte, short, ushort, int, uint, long, ulong, float, double, real
-    )));
+    static assert(is(AllImplicitConversionTargets!(char) ==
+        AliasSeq!(byte, ubyte, short, ushort, wchar, int, dchar, uint, long,
+            ulong, float, double, real)
+    ));
     static assert(is(AllImplicitConversionTargets!(wchar) == AliasSeq!(
-        dchar, short, ushort, int, uint, long, ulong, float, double, real
+        short, ushort, dchar, int, uint, long, ulong, float, double, real
     )));
     static assert(is(AllImplicitConversionTargets!(dchar) == AliasSeq!(
         int, uint, long, ulong, float, double, real
     )));
 
     static assert(is(AllImplicitConversionTargets!(string) == AliasSeq!(const(char)[])));
-    static assert(is(AllImplicitConversionTargets!(void*) == AliasSeq!(void*)));
+    static assert(is(AllImplicitConversionTargets!(int*) == AliasSeq!(void*)));
 
     interface A {}
     interface B {}
@@ -5747,13 +5669,11 @@  Note: Trying to use returned value will result in a
 // SomethingTypeOf
 //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
 
-private alias AliasThisTypeOf(T) = typeof(__traits(getMember, T.init, __traits(getAliasThis, T)[0]));
-
 /*
  */
 template BooleanTypeOf(T)
 {
-    static if (is(AliasThisTypeOf!T AT) && !is(AT[] == AT))
+    static if (is(typeof(__traits(getMember, T.init, __traits(getAliasThis, T)[0])) AT) && !is(AT[] == AT))
         alias X = BooleanTypeOf!AT;
     else
         alias X = OriginalType!T;
@@ -5804,7 +5724,7 @@  template BooleanTypeOf(T)
  */
 template IntegralTypeOf(T)
 {
-    static if (is(AliasThisTypeOf!T AT) && !is(AT[] == AT))
+    static if (is(typeof(__traits(getMember, T.init, __traits(getAliasThis, T)[0])) AT) && !is(AT[] == AT))
         alias X = IntegralTypeOf!AT;
     else
         alias X = OriginalType!T;
@@ -5840,7 +5760,7 @@  template IntegralTypeOf(T)
  */
 template FloatingPointTypeOf(T)
 {
-    static if (is(AliasThisTypeOf!T AT) && !is(AT[] == AT))
+    static if (is(typeof(__traits(getMember, T.init, __traits(getAliasThis, T)[0])) AT) && !is(AT[] == AT))
         alias X = FloatingPointTypeOf!AT;
     else
         alias X = OriginalType!T;
@@ -5925,7 +5845,7 @@  template SignedTypeOf(T)
  */
 template CharTypeOf(T)
 {
-    static if (is(AliasThisTypeOf!T AT) && !is(AT[] == AT))
+    static if (is(typeof(__traits(getMember, T.init, __traits(getAliasThis, T)[0])) AT) && !is(AT[] == AT))
         alias X = CharTypeOf!AT;
     else
         alias X = OriginalType!T;
@@ -5966,7 +5886,7 @@  template CharTypeOf(T)
  */
 template StaticArrayTypeOf(T)
 {
-    static if (is(AliasThisTypeOf!T AT) && !is(AT[] == AT))
+    static if (is(typeof(__traits(getMember, T.init, __traits(getAliasThis, T)[0])) AT) && !is(AT[] == AT))
         alias X = StaticArrayTypeOf!AT;
     else
         alias X = OriginalType!T;
@@ -6001,17 +5921,8 @@  template StaticArrayTypeOf(T)
  */
 template DynamicArrayTypeOf(T)
 {
-    static if (is(AliasThisTypeOf!T AT) && !is(AT[] == AT))
-        alias X = DynamicArrayTypeOf!AT;
-    else
-        alias X = OriginalType!T;
-
-    static if (is(X == E[], E))
-    {
-        alias DynamicArrayTypeOf = X;
-    }
-    else
-        static assert(0, T.stringof~" is not a dynamic array");
+    import core.internal.traits : _DynamicArrayTypeOf = DynamicArrayTypeOf;
+    alias DynamicArrayTypeOf = _DynamicArrayTypeOf!T;
 }
 
 @safe unittest
@@ -6132,7 +6043,7 @@  template StringTypeOf(T)
  */
 template AssocArrayTypeOf(T)
 {
-    static if (is(AliasThisTypeOf!T AT) && !is(AT[] == AT))
+    static if (is(typeof(__traits(getMember, T.init, __traits(getAliasThis, T)[0])) AT) && !is(AT[] == AT))
         alias X = AssocArrayTypeOf!AT;
     else
         alias X = OriginalType!T;
@@ -6173,7 +6084,7 @@  template BuiltinTypeOf(T)
         alias BuiltinTypeOf = void;
     else
     {
-        static if (is(AliasThisTypeOf!T AT) && !is(AT[] == AT))
+        static if (is(typeof(__traits(getMember, T.init, __traits(getAliasThis, T)[0])) AT) && !is(AT[] == AT))
             alias X = BuiltinTypeOf!AT;
         else
             alias X = OriginalType!T;
@@ -6902,7 +6813,9 @@  template isAutodecodableString(T)
     import std.range.primitives : autodecodeStrings;
 
     enum isAutodecodableString = autodecodeStrings &&
-        (is(T : const char[]) || is(T : const wchar[])) && !is(T : U[n], U, size_t n);
+        (is(T : const char[]) || is(T : const wchar[]))
+        && !is(T : U[n], U, size_t n)
+        && !is(immutable T : immutable noreturn[]);
 }
 
 ///
@@ -6937,6 +6850,9 @@  template isAutodecodableString(T)
 
     static assert(isAutodecodableString!(H));
     static assert(isAutodecodableString!(I));
+
+    static assert(!isAutodecodableString!(noreturn[]));
+    static assert(!isAutodecodableString!(immutable(noreturn)[]));
 }
 
 /**
@@ -7381,15 +7297,14 @@  alias isExpressionTuple = isExpressions;
  *
  * See_Also: $(LREF isExpressions).
  */
-template isTypeTuple(T...)
+enum isTypeTuple(T...) =
 {
-    static if (T.length >= 2)
-        enum bool isTypeTuple = isTypeTuple!(T[0 .. $/2]) && isTypeTuple!(T[$/2 .. $]);
-    else static if (T.length == 1)
-        enum bool isTypeTuple = is(T[0]);
-    else
-        enum bool isTypeTuple = true; // default
-}
+    static foreach (U; T)
+        static if (!is(U))
+            if (__ctfe)
+                return false;
+    return true;
+}();
 
 ///
 @safe unittest
@@ -7473,15 +7388,14 @@  Params:
 Returns:
     A `bool`
  */
-template isSomeFunction(T...)
-if (T.length == 1)
+template isSomeFunction(alias T)
 {
-    static if (is(typeof(& T[0]) U : U*) && is(U == function) || is(typeof(& T[0]) U == delegate))
+    static if (is(typeof(& T) U : U*) && is(U == function) || is(typeof(& T) U == delegate))
     {
         // T is a (nested) function symbol.
         enum bool isSomeFunction = true;
     }
-    else static if (is(T[0] W) || is(typeof(T[0]) W))
+    else static if (is(T W) || is(typeof(T) W))
     {
         // T is an expression or a type.  Take the type of it and examine.
         static if (is(W F : F*) && is(F == function))
@@ -7623,11 +7537,7 @@  Params:
 Returns:
     A `bool`
  */
-template isAbstractFunction(T...)
-if (T.length == 1)
-{
-    enum bool isAbstractFunction = __traits(isAbstractFunction, T[0]);
-}
+enum isAbstractFunction(alias T) = __traits(isAbstractFunction, T);
 
 ///
 @safe unittest
@@ -7644,11 +7554,7 @@  if (T.length == 1)
 /**
  * Detect whether `T` is a final function.
  */
-template isFinalFunction(T...)
-if (T.length == 1)
-{
-    enum bool isFinalFunction = __traits(isFinalFunction, T[0]);
-}
+enum isFinalFunction(alias T) = __traits(isFinalFunction, T);
 
 ///
 @safe unittest
@@ -7716,11 +7622,7 @@  template isNestedFunction(alias f)
 /**
  * Detect whether `T` is an abstract class.
  */
-template isAbstractClass(T...)
-if (T.length == 1)
-{
-    enum bool isAbstractClass = __traits(isAbstractClass, T[0]);
-}
+enum isAbstractClass(alias T) = __traits(isAbstractClass, T);
 
 ///
 @safe unittest
@@ -7740,11 +7642,7 @@  if (T.length == 1)
 /**
  * Detect whether `T` is a final class.
  */
-template isFinalClass(T...)
-if (T.length == 1)
-{
-    enum bool isFinalClass = __traits(isFinalClass, T[0]);
-}
+enum isFinalClass(alias T) = __traits(isFinalClass, T);
 
 ///
 @safe unittest
@@ -7767,13 +7665,21 @@  if (T.length == 1)
 // General Types
 //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
 
-/**
-Removes `const`, `inout` and `immutable` qualifiers, if any, from type `T`.
- */
-template Unconst(T)
+version (StdDdoc)
+{
+    /**
+       Removes `const`, `inout` and `immutable` qualifiers, if any, from type `T`.
+    */
+    template Unconst(T)
+    {
+        import core.internal.traits : CoreUnconst = Unconst;
+        alias Unconst = CoreUnconst!(T);
+    }
+}
+else
 {
     import core.internal.traits : CoreUnconst = Unconst;
-    alias Unconst = CoreUnconst!(T);
+    alias Unconst = CoreUnconst;
 }
 
 ///
@@ -7802,13 +7708,21 @@  template Unconst(T)
     static assert(is(Unconst!ImmIntArr == immutable(int)[]));
 }
 
-/**
-Removes all qualifiers, if any, from type `T`.
- */
-template Unqual(T)
+version (StdDdoc)
+{
+    /**
+       Removes all qualifiers, if any, from type `T`.
+    */
+    template Unqual(T)
+    {
+        import core.internal.traits : CoreUnqual = Unqual;
+        alias Unqual = CoreUnqual!(T);
+    }
+}
+else
 {
     import core.internal.traits : CoreUnqual = Unqual;
-    alias Unqual = CoreUnqual!(T);
+    alias Unqual = CoreUnqual;
 }
 
 ///
@@ -7840,29 +7754,8 @@  template Unqual(T)
 // [For internal use]
 package template ModifyTypePreservingTQ(alias Modifier, T)
 {
-         static if (is(T U ==          immutable U)) alias ModifyTypePreservingTQ =          immutable Modifier!U;
-    else static if (is(T U == shared inout const U)) alias ModifyTypePreservingTQ = shared inout const Modifier!U;
-    else static if (is(T U == shared inout       U)) alias ModifyTypePreservingTQ = shared inout       Modifier!U;
-    else static if (is(T U == shared       const U)) alias ModifyTypePreservingTQ = shared       const Modifier!U;
-    else static if (is(T U == shared             U)) alias ModifyTypePreservingTQ = shared             Modifier!U;
-    else static if (is(T U ==        inout const U)) alias ModifyTypePreservingTQ =        inout const Modifier!U;
-    else static if (is(T U ==        inout       U)) alias ModifyTypePreservingTQ =              inout Modifier!U;
-    else static if (is(T U ==              const U)) alias ModifyTypePreservingTQ =              const Modifier!U;
-    else                                             alias ModifyTypePreservingTQ =                    Modifier!T;
-}
-
-@safe unittest
-{
-    alias Intify(T) = int;
-    static assert(is(ModifyTypePreservingTQ!(Intify,                    real) ==                    int));
-    static assert(is(ModifyTypePreservingTQ!(Intify,              const real) ==              const int));
-    static assert(is(ModifyTypePreservingTQ!(Intify,        inout       real) ==        inout       int));
-    static assert(is(ModifyTypePreservingTQ!(Intify,        inout const real) ==        inout const int));
-    static assert(is(ModifyTypePreservingTQ!(Intify, shared             real) == shared             int));
-    static assert(is(ModifyTypePreservingTQ!(Intify, shared       const real) == shared       const int));
-    static assert(is(ModifyTypePreservingTQ!(Intify, shared inout       real) == shared inout       int));
-    static assert(is(ModifyTypePreservingTQ!(Intify, shared inout const real) == shared inout const int));
-    static assert(is(ModifyTypePreservingTQ!(Intify,          immutable real) ==          immutable int));
+    import core.internal.traits : _ModifyTypePreservingTQ = ModifyTypePreservingTQ;
+    alias ModifyTypePreservingTQ = _ModifyTypePreservingTQ!(Modifier, T);
 }
 
 /**
@@ -8009,20 +7902,8 @@  template ForeachType(T)
  */
 template OriginalType(T)
 {
-    static if (is(T == enum))
-    {
-        template Impl(T)
-        {
-            static if (is(T U == enum)) alias Impl = OriginalType!U;
-            else                        alias Impl =              T;
-        }
-
-        alias OriginalType = ModifyTypePreservingTQ!(Impl, T);
-    }
-    else
-    {
-        alias OriginalType = T;
-    }
+    import core.internal.traits : _OriginalType = OriginalType;
+    alias OriginalType = _OriginalType!T;
 }
 
 ///
@@ -8158,25 +8039,9 @@  returned.
 template Largest(T...)
 if (T.length >= 1)
 {
-    static if (T.length == 1)
-    {
-        alias Largest = T[0];
-    }
-    else static if (T.length == 2)
-    {
-        static if (T[0].sizeof >= T[1].sizeof)
-        {
-            alias Largest = T[0];
-        }
-        else
-        {
-            alias Largest = T[1];
-        }
-    }
-    else
-    {
-        alias Largest = Largest!(Largest!(T[0 .. $/2]), Largest!(T[$/2 .. $]));
-    }
+    alias Largest = T[0];
+    static foreach (U; T[1 .. $])
+        Largest = Select!(U.sizeof > Largest.sizeof, U, Largest);
 }
 
 ///
@@ -8332,11 +8197,7 @@  Returns the mangled name of symbol or type `sth`.
 might be more convenient in generic code, e.g. as a template argument
 when invoking staticMap.
  */
-template mangledName(sth...)
-if (sth.length == 1)
-{
-    enum string mangledName = sth[0].mangleof;
-}
+enum mangledName(alias sth) = sth.mangleof;
 
 ///
 @safe unittest
@@ -8451,10 +8312,7 @@  B select(bool cond : false, A, B)(lazy A a, B b) { return b; }
     See_Also:
         $(LREF getUDAs)
   +/
-template hasUDA(alias symbol, alias attribute)
-{
-    enum hasUDA = getUDAs!(symbol, attribute).length != 0;
-}
+enum hasUDA(alias symbol, alias attribute) = getUDAs!(symbol, attribute).length != 0;
 
 ///
 @safe unittest
@@ -8941,28 +8799,22 @@  private template getSymbolsByUDAImpl(alias symbol, alias attribute, names...)
 }
 
 /**
-   Returns: `true` iff all types `T` are the same.
+   Returns: `true` iff all types `Ts` are the same.
 */
-template allSameType(T...)
+enum bool allSameType(Ts...) =
 {
-    static foreach (idx, Ti; T)
-    {
-        static if (idx + 1 < T.length &&
-                   !is(typeof(allSameType) == bool) &&
-                   !is(T[idx] == T[idx + 1]))
-        {
-            enum bool allSameType = false;
-        }
-    }
-    static if (!is(typeof(allSameType) == bool))
-    {
-        enum bool allSameType = true;
-    }
-}
+    static foreach (T; Ts[Ts.length > 1 .. $])
+        static if (!is(Ts[0] == T))
+            if (__ctfe)  // Dodge the "statement is unreachable" warning
+                return false;
+    return true;
+}();
 
 ///
 @safe unittest
 {
+    static assert(allSameType!());
+    static assert(allSameType!(int));
     static assert(allSameType!(int, int));
     static assert(allSameType!(int, int, int));
     static assert(allSameType!(float, float, float));
@@ -8993,11 +8845,7 @@  enum ifTestable(T, alias pred = a => a) = __traits(compiles, { if (pred(T.init))
  * Returns:
  *      `true` if `X` is a type, `false` otherwise
  */
-template isType(X...)
-if (X.length == 1)
-{
-    enum isType = is(X[0]);
-}
+enum isType(alias X) = is(X);
 
 ///
 @safe unittest
@@ -9037,16 +8885,15 @@  if (X.length == 1)
  *     Use $(LREF isFunctionPointer) or $(LREF isDelegate) for detecting those types
  *     respectively.
  */
-template isFunction(X...)
-if (X.length == 1)
+template isFunction(alias X)
 {
-    static if (is(typeof(&X[0]) U : U*) && is(U == function) ||
-               is(typeof(&X[0]) U == delegate))
+    static if (is(typeof(&X) U : U*) && is(U == function) ||
+               is(typeof(&X) U == delegate))
     {
         // x is a (nested) function symbol.
         enum isFunction = true;
     }
-    else static if (is(X[0] T))
+    else static if (is(X T))
     {
         // x is a type.  Take the type of it and examine.
         enum isFunction = is(T == function);
@@ -9074,13 +8921,12 @@  if (X.length == 1)
  * Returns:
  *     `true` if `X` is final, `false` otherwise
  */
-template isFinal(X...)
-if (X.length == 1)
+template isFinal(alias X)
 {
-    static if (is(X[0] == class))
-        enum isFinal = __traits(isFinalClass, X[0]);
+    static if (is(X == class))
+        enum isFinal = __traits(isFinalClass, X);
     else static if (isFunction!X)
-        enum isFinal = __traits(isFinalFunction, X[0]);
+        enum isFinal = __traits(isFinalFunction, X);
     else
         enum isFinal = false;
 }
diff --git a/libphobos/src/std/typecons.d b/libphobos/src/std/typecons.d
index feedf90e951..db0e3da304c 100644
--- a/libphobos/src/std/typecons.d
+++ b/libphobos/src/std/typecons.d
@@ -448,6 +448,90 @@  private enum bool distinctFieldNames(names...) = __traits(compiles,
     static assert(!distinctFieldNames!(int, "int"));
 }
 
+
+// Parse (type,name) pairs (FieldSpecs) out of the specified
+// arguments. Some fields would have name, others not.
+private template parseSpecs(Specs...)
+{
+    static if (Specs.length == 0)
+    {
+        alias parseSpecs = AliasSeq!();
+    }
+    else static if (is(Specs[0]))
+    {
+        static if (is(typeof(Specs[1]) : string))
+        {
+            alias parseSpecs =
+                AliasSeq!(FieldSpec!(Specs[0 .. 2]),
+                          parseSpecs!(Specs[2 .. $]));
+        }
+        else
+        {
+            alias parseSpecs =
+                AliasSeq!(FieldSpec!(Specs[0]),
+                          parseSpecs!(Specs[1 .. $]));
+        }
+    }
+    else
+    {
+        static assert(0, "Attempted to instantiate Tuple with an "
+                        ~"invalid argument: "~ Specs[0].stringof);
+    }
+}
+
+private template FieldSpec(T, string s = "")
+{
+    alias Type = T;
+    alias name = s;
+}
+
+// Used with staticMap.
+private alias extractType(alias spec) = spec.Type;
+private alias extractName(alias spec) = spec.name;
+private template expandSpec(alias spec)
+{
+    static if (spec.name.length == 0)
+        alias expandSpec = AliasSeq!(spec.Type);
+    else
+        alias expandSpec = AliasSeq!(spec.Type, spec.name);
+}
+
+
+private enum areCompatibleTuples(Tup1, Tup2, string op) =
+    isTuple!(OriginalType!Tup2) && Tup1.Types.length == Tup2.Types.length && is(typeof(
+    (ref Tup1 tup1, ref Tup2 tup2)
+    {
+        static foreach (i; 0 .. Tup1.Types.length)
+        {{
+            auto lhs = typeof(tup1.field[i]).init;
+            auto rhs = typeof(tup2.field[i]).init;
+            static if (op == "=")
+                lhs = rhs;
+            else
+                auto result = mixin("lhs "~op~" rhs");
+        }}
+    }));
+
+private enum areBuildCompatibleTuples(Tup1, Tup2) =
+    isTuple!Tup2 && Tup1.Types.length == Tup2.Types.length && is(typeof(
+    {
+        static foreach (i; 0 .. Tup1.Types.length)
+            static assert(isBuildable!(Tup1.Types[i], Tup2.Types[i]));
+    }));
+
+// Returns `true` iff a `T` can be initialized from a `U`.
+private enum isBuildable(T, U) = is(typeof(
+    {
+        U u = U.init;
+        T t = u;
+    }));
+// Helper for partial instantiation
+private template isBuildableFrom(U)
+{
+    enum isBuildableFrom(T) = isBuildable!(T, U);
+}
+
+
 /**
 _Tuple of values, for example $(D Tuple!(int, string)) is a record that
 stores an `int` and a `string`. `Tuple` can be used to bundle
@@ -466,48 +550,8 @@  if (distinctFieldNames!(Specs))
 {
     import std.meta : staticMap;
 
-    // Parse (type,name) pairs (FieldSpecs) out of the specified
-    // arguments. Some fields would have name, others not.
-    template parseSpecs(Specs...)
-    {
-        static if (Specs.length == 0)
-        {
-            alias parseSpecs = AliasSeq!();
-        }
-        else static if (is(Specs[0]))
-        {
-            static if (is(typeof(Specs[1]) : string))
-            {
-                alias parseSpecs =
-                    AliasSeq!(FieldSpec!(Specs[0 .. 2]),
-                              parseSpecs!(Specs[2 .. $]));
-            }
-            else
-            {
-                alias parseSpecs =
-                    AliasSeq!(FieldSpec!(Specs[0]),
-                              parseSpecs!(Specs[1 .. $]));
-            }
-        }
-        else
-        {
-            static assert(0, "Attempted to instantiate Tuple with an "
-                            ~"invalid argument: "~ Specs[0].stringof);
-        }
-    }
-
-    template FieldSpec(T, string s = "")
-    {
-        alias Type = T;
-        alias name = s;
-    }
-
     alias fieldSpecs = parseSpecs!Specs;
 
-    // Used with staticMap.
-    alias extractType(alias spec) = spec.Type;
-    alias extractName(alias spec) = spec.name;
-
     // Generates named fields as follows:
     //    alias name_0 = Identity!(field[0]);
     //    alias name_1 = Identity!(field[1]);
@@ -534,52 +578,6 @@  if (distinctFieldNames!(Specs))
     alias sliceSpecs(size_t from, size_t to) =
         staticMap!(expandSpec, fieldSpecs[from .. to]);
 
-    template expandSpec(alias spec)
-    {
-        static if (spec.name.length == 0)
-        {
-            alias expandSpec = AliasSeq!(spec.Type);
-        }
-        else
-        {
-            alias expandSpec = AliasSeq!(spec.Type, spec.name);
-        }
-    }
-
-    enum areCompatibleTuples(Tup1, Tup2, string op) = isTuple!(OriginalType!Tup2) && is(typeof(
-    (ref Tup1 tup1, ref Tup2 tup2)
-    {
-        static assert(tup1.field.length == tup2.field.length);
-        static foreach (i; 0 .. Tup1.Types.length)
-        {{
-            auto lhs = typeof(tup1.field[i]).init;
-            auto rhs = typeof(tup2.field[i]).init;
-            static if (op == "=")
-                lhs = rhs;
-            else
-                auto result = mixin("lhs "~op~" rhs");
-        }}
-    }));
-
-    enum areBuildCompatibleTuples(Tup1, Tup2) = isTuple!Tup2 && is(typeof(
-    {
-        static assert(Tup1.Types.length == Tup2.Types.length);
-        static foreach (i; 0 .. Tup1.Types.length)
-            static assert(isBuildable!(Tup1.Types[i], Tup2.Types[i]));
-    }));
-
-    /+ Returns `true` iff a `T` can be initialized from a `U`. +/
-    enum isBuildable(T, U) =  is(typeof(
-    {
-        U u = U.init;
-        T t = u;
-    }));
-    /+ Helper for partial instantiation +/
-    template isBuildableFrom(U)
-    {
-        enum isBuildableFrom(T) = isBuildable!(T, U);
-    }
-
     struct Tuple
     {
         /**
@@ -1359,8 +1357,7 @@  if (distinctFieldNames!(Specs))
         }
 
         ///
-        static if (Types.length == 0)
-        @safe unittest
+        static if (Specs.length == 0) @safe unittest
         {
             import std.format : format;
 
@@ -1381,8 +1378,7 @@  if (distinctFieldNames!(Specs))
         }
 
         ///
-        static if (Types.length == 0)
-        @safe unittest
+        static if (Specs.length == 0) @safe unittest
         {
             import std.exception : assertThrown;
             import std.format : format, FormatException;
@@ -2762,7 +2758,11 @@  struct Nullable(T)
 {
     private union DontCallDestructorT
     {
-        T payload;
+        import std.traits : hasIndirections;
+        static if (hasIndirections!T)
+            T payload;
+        else
+            T payload = void;
     }
 
     private DontCallDestructorT _value = DontCallDestructorT.init;
@@ -3020,7 +3020,7 @@  struct Nullable(T)
 
         if (_isNull)
         {
-            // trusted since payload is known to be T.init here.
+            // trusted since payload is known to be uninitialized.
             () @trusted { moveEmplace(copy.payload, _value.payload); }();
         }
         else
@@ -6850,9 +6850,10 @@  RefCounted!(T, RefCountedAutoInitialize.no) refCounted(T)(T val)
 {
     static struct File
     {
+        static size_t nDestroyed;
         string name;
         @disable this(this); // not copyable
-        ~this() { name = null; }
+        ~this() { name = null; ++nDestroyed; }
     }
 
     auto file = File("name");
@@ -6860,14 +6861,37 @@  RefCounted!(T, RefCountedAutoInitialize.no) refCounted(T)(T val)
     // file cannot be copied and has unique ownership
     static assert(!__traits(compiles, {auto file2 = file;}));
 
+    assert(File.nDestroyed == 0);
+
     // make the file refcounted to share ownership
-    import std.algorithm.mutation : move;
-    auto rcFile = refCounted(move(file));
-    assert(rcFile.name == "name");
-    assert(file.name == null);
-    auto rcFile2 = rcFile;
-    assert(rcFile.refCountedStore.refCount == 2);
-    // file gets properly closed when last reference is dropped
+    // Note:
+    //   We write a compound statement (brace-delimited scope) in which all `RefCounted!File` handles are created and deleted.
+    //   This allows us to see (after the scope) what happens after all handles have been destroyed.
+    {
+        // We move the content of `file` to a separate (and heap-allocated) `File` object,
+        // managed-and-accessed via one-or-multiple (initially: one) `RefCounted!File` objects ("handles").
+        // This "moving":
+        //   (1) invokes `file`'s destructor (=> `File.nDestroyed` is incremented from 0 to 1 and `file.name` becomes `null`);
+        //   (2) overwrites `file` with `File.init` (=> `file.name` becomes `null`).
+        // It appears that writing `name = null;` in the destructor is redundant,
+        // but please note that (2) is only performed if `File` defines a destructor (or post-blit operator),
+        // and in the absence of the `nDestroyed` instrumentation there would have been no reason to define a destructor.
+        import std.algorithm.mutation : move;
+        auto rcFile = refCounted(move(file));
+        assert(rcFile.name == "name");
+        assert(File.nDestroyed == 1);
+        assert(file.name == null);
+
+        // We create another `RefCounted!File` handle to the same separate `File` object.
+        // While any of the handles is still alive, the `File` object is kept alive (=> `File.nDestroyed` is not modified).
+        auto rcFile2 = rcFile;
+        assert(rcFile.refCountedStore.refCount == 2);
+        assert(File.nDestroyed == 1);
+    }
+    // The separate `File` object is deleted when the last `RefCounted!File` handle is destroyed
+    // (i.e. at the closing brace of the compound statement above, which destroys both handles: `rcFile` and `rcFile2`)
+    // (=> `File.nDestroyed` is incremented again, from 1 to 2):
+    assert(File.nDestroyed == 2);
 }
 
 /**
@@ -9086,9 +9110,14 @@  template ReplaceTypeUnless(alias pred, From, To, T...)
         {
             template replaceTemplateArgs(T...)
             {
-                static if (is(typeof(T[0])))    // template argument is value or symbol
-                    enum replaceTemplateArgs = T[0];
-                else
+                static if (is(typeof(T[0]))) {   // template argument is value or symbol
+                    static if (__traits(compiles, { alias _ = T[0]; }))
+                        // it's a symbol
+                        alias replaceTemplateArgs = T[0];
+                    else
+                        // it's a value
+                        enum replaceTemplateArgs = T[0];
+                } else
                     alias replaceTemplateArgs = ReplaceTypeUnless!(pred, From, To, T[0]);
             }
             alias ReplaceTypeUnless = U!(staticMap!(replaceTemplateArgs, V));
@@ -9341,6 +9370,14 @@  private template replaceTypeInFunctionTypeUnless(alias pred, From, To, fun)
     static assert(is(ReplaceType!(int, string, C) == C));
 }
 
+// https://issues.dlang.org/show_bug.cgi?id=22325
+@safe unittest
+{
+    static struct Foo(alias f) {}
+    static void bar() {}
+    alias _ = ReplaceType!(int, int, Foo!bar);
+}
+
 /**
 Ternary type with three truth values:
 
diff --git a/libphobos/src/std/uni/package.d b/libphobos/src/std/uni/package.d
index 318bcb32a6f..45b7207c1f1 100644
--- a/libphobos/src/std/uni/package.d
+++ b/libphobos/src/std/uni/package.d
@@ -1528,7 +1528,7 @@  if (is(Unqual!T == T))
     return SliceOverIndexed!T(a, b, x);
 }
 
-@system unittest
+@safe unittest
 {
     int[] idxArray = [2, 3, 5, 8, 13];
     auto sliced = sliceOverIndexed(0, idxArray.length, &idxArray);
@@ -3116,7 +3116,7 @@  private:
     CowArray!SP data;
 }
 
-pure @system unittest
+pure @safe unittest
 {
     import std.conv : to;
     assert(unicode.ASCII.to!string() == "[0..128)");
@@ -5410,7 +5410,7 @@  pure @safe unittest
 }
 
 // cover decode fail cases of Matcher
-pure @system unittest
+pure @safe unittest
 {
     import std.algorithm.iteration : map;
     import std.exception : collectException;
@@ -5427,7 +5427,7 @@  pure @system unittest
             auto s = msg;
             size_t idx = 0;
             utf8.test(s);
-        }()), format("%( %2x %)", cast(ubyte[]) msg));
+        }()), format("%( %2x %)", cast(immutable(ubyte)[]) msg));
     }
     //decode failure cases UTF-16
     alias fails16 = AliasSeq!([0xD811], [0xDC02]);
@@ -7150,7 +7150,7 @@  if (isInputRange!Input && is(immutable ElementType!Input == immutable dchar))
     return genericDecodeGrapheme!true(inp);
 }
 
-@system unittest
+@safe unittest
 {
     import std.algorithm.comparison : equal;
 
@@ -7233,7 +7233,7 @@  if (isInputRange!Range && is(immutable ElementType!Range == immutable dchar))
 
 // For testing non-forward-range input ranges
 version (StdUnittest)
-private static struct InputRangeString
+private static @safe struct InputRangeString
 {
     private string s;
 
@@ -7242,7 +7242,7 @@  private static struct InputRangeString
     void popFront() { s.popFront(); }
 }
 
-@system unittest
+@safe unittest
 {
     import std.algorithm.comparison : equal;
     import std.array : array;
@@ -7366,7 +7366,7 @@  if (isInputRange!Range && is(immutable ElementType!Range == immutable dchar))
     assert(reverse == "le\u0308on"); // lëon
 }
 
-@system unittest
+@safe unittest
 {
     import std.algorithm.comparison : equal;
     import std.range.primitives : walkLength;
@@ -7523,7 +7523,7 @@  public:
     }
 
     ///
-    @system unittest
+    @safe unittest
     {
         import std.algorithm.comparison : equal;
         auto g = Grapheme("A");
@@ -7650,7 +7650,7 @@  private:
 static assert(Grapheme.sizeof == size_t.sizeof*4);
 
 
-@system pure /*nothrow @nogc*/ unittest // TODO: string .front is GC and throw
+@safe pure /*nothrow @nogc*/ unittest // TODO: string .front is GC and throw
 {
     import std.algorithm.comparison : equal;
     Grapheme[3] data = [Grapheme("Ю"), Grapheme("У"), Grapheme("З")];
@@ -7658,7 +7658,7 @@  static assert(Grapheme.sizeof == size_t.sizeof*4);
 }
 
 ///
-@system unittest
+@safe unittest
 {
     import std.algorithm.comparison : equal;
     import std.algorithm.iteration : filter;
@@ -7704,7 +7704,7 @@  static assert(Grapheme.sizeof == size_t.sizeof*4);
     assert(!g.valid);
 }
 
-@system unittest
+@safe unittest
 {
     import std.algorithm.comparison : equal;
     import std.algorithm.iteration : map;
@@ -8205,7 +8205,7 @@  package(std) auto simpleCaseFoldings(dchar ch) @safe
     return Range(start, entry.size);
 }
 
-@system unittest
+@safe unittest
 {
     import std.algorithm.comparison : equal;
     import std.algorithm.searching : canFind;
@@ -8356,7 +8356,7 @@  public Grapheme decompose(UnicodeDecomposition decompType=Canonical)(dchar ch) @
 }
 
 ///
-@system unittest
+@safe unittest
 {
     import std.algorithm.comparison : equal;
 
@@ -8464,7 +8464,7 @@  Grapheme decomposeHangul(dchar ch) @safe
 }
 
 ///
-@system unittest
+@safe unittest
 {
     import std.algorithm.comparison : equal;
     assert(decomposeHangul('\uD4DB')[].equal("\u1111\u1171\u11B6"));
@@ -8504,7 +8504,7 @@  dchar composeJamo(dchar lead, dchar vowel, dchar trailing=dchar.init) pure nothr
     assert(composeJamo('A', '\u1171') == dchar.init);
 }
 
-@system unittest
+@safe unittest
 {
     import std.algorithm.comparison : equal;
     import std.conv : text;
@@ -10105,7 +10105,7 @@  if (isSomeString!S || (isRandomAccessRange!S && hasLength!S && hasSlicing!S && i
     assert(s2 !is s1);
 }
 
-@system unittest
+@safe unittest
 {
     static void doTest(C)(const(C)[] s, const(C)[] trueUp, const(C)[] trueLow)
     {
@@ -10118,9 +10118,9 @@  if (isSomeString!S || (isRandomAccessRange!S && hasLength!S && hasSlicing!S && i
         assert(low == trueLow, format(diff, low, trueLow));
         assert(up == trueUp,  format(diff, up, trueUp));
         assert(lowInp == trueLow,
-            format(diff, cast(ubyte[]) s, cast(ubyte[]) lowInp, cast(ubyte[]) trueLow));
+            format(diff, cast(const(ubyte)[]) s, cast(const(ubyte)[]) lowInp, cast(const(ubyte)[]) trueLow));
         assert(upInp == trueUp,
-            format(diff, cast(ubyte[]) s, cast(ubyte[]) upInp, cast(ubyte[]) trueUp));
+            format(diff, cast(const(ubyte)[]) s, cast(const(ubyte)[]) upInp, cast(const(ubyte)[]) trueUp));
     }
     static foreach (S; AliasSeq!(dstring, wstring, string))
     {{
diff --git a/libphobos/src/std/variant.d b/libphobos/src/std/variant.d
index 953d6eafaee..ce635fb9b34 100644
--- a/libphobos/src/std/variant.d
+++ b/libphobos/src/std/variant.d
@@ -78,7 +78,7 @@  import std.meta, std.traits, std.typecons;
 /++
     Gives the `sizeof` the largest type given.
 
-    See_Also: https://forum.dlang.org/thread/wbpnncxepehgcswhuazl@forum.dlang.org?page=1
+    See_Also: $(LINK https://forum.dlang.org/thread/wbpnncxepehgcswhuazl@forum.dlang.org?page=1)
   +/
 template maxSize(Ts...)
 {
diff --git a/libphobos/src/std/windows/registry.d b/libphobos/src/std/windows/registry.d
index cdf37c11cf6..d66adff58ca 100644
--- a/libphobos/src/std/windows/registry.d
+++ b/libphobos/src/std/windows/registry.d
@@ -881,7 +881,6 @@  public:
         return new ValueNameSequence(this);
     }
 
-public:
     /**
         Returns the named sub-key of this key.
 
@@ -1412,7 +1411,6 @@  public:
         return getKeyName(index);
     }
 
-public:
     ///
     int opApply(scope int delegate(ref string name) dg)
     {
@@ -1509,7 +1507,6 @@  public:
         return getKey(index);
     }
 
-public:
     ///
     int opApply(scope int delegate(ref Key key) dg)
     {
@@ -1618,7 +1615,6 @@  public:
         return getValueName(index);
     }
 
-public:
     ///
     int opApply(scope int delegate(ref string name) dg)
     {
@@ -1712,7 +1708,6 @@  public:
         return getValue(index);
     }
 
-public:
     ///
     int opApply(scope int delegate(ref Value value) dg)
     {