diff --git a/std/algorithm.d b/std/algorithm.d index ec4e40adc..750f1da13 100644 --- a/std/algorithm.d +++ b/std/algorithm.d @@ -1061,7 +1061,7 @@ $(D !pointsTo(lhs, lhs) && !pointsTo(lhs, rhs) && !pointsTo(rhs, lhs) && !pointsTo(rhs, rhs)) */ void swap(T)(ref T lhs, ref T rhs) @trusted pure nothrow -if (!is(typeof(T.init.proxySwap(T.init)))) +if (isMutable!T && !is(typeof(T.init.proxySwap(T.init)))) { static if (hasElaborateAssign!T) { @@ -1120,6 +1120,9 @@ unittest assert(s2.x == 0); assert(s2.c == 'z'); assert(s2.y == [ 1, 2 ]); + + immutable int imm1, imm2; + static assert(!__traits(compiles, swap(imm1, imm2))); } unittest @@ -1147,6 +1150,9 @@ unittest swap(h1, h2); assert(h1.noCopy.n == 65 && h1.noCopy.s == null); assert(h2.noCopy.n == 31 && h2.noCopy.s == "abc"); + + const NoCopy const1, const2; + static assert(!__traits(compiles, swap(const1, const2))); } void swapFront(R1, R2)(R1 r1, R2 r2) diff --git a/std/array.d b/std/array.d index 7799494a5..644ad39a0 100644 --- a/std/array.d +++ b/std/array.d @@ -256,10 +256,6 @@ void main() return a; } -private template notConst(T) { - enum notConst = !is(T == const) && !is(T == immutable); -} - /** Implements the range interface primitive $(D popFront) for built-in arrays. Due to the fact that nonmember functions can be called with @@ -279,7 +275,7 @@ void main() */ void popFront(A)(ref A a) -if(!isNarrowString!A && isDynamicArray!A && notConst!A && !is(A == void[])) +if(!isNarrowString!A && isDynamicArray!A && isMutable!A && !is(A == void[])) { alias typeof(A[0]) T; assert(a.length, "Attempting to popFront() past the end of an array of " @@ -299,7 +295,7 @@ unittest } void popFront(A)(ref A a) -if(isNarrowString!A && notConst!A) +if(isNarrowString!A && isMutable!A) { alias typeof(a[0]) T; assert(a.length, "Attempting to popFront() past the end of an array of " @@ -340,7 +336,7 @@ void main() */ void popBack(A)(ref A a) -if(isDynamicArray!A && !isNarrowString!A && notConst!A && !is(A == void[])) +if(isDynamicArray!A && !isNarrowString!A && isMutable!A && !is(A == void[])) { assert(a.length); a = a[0 .. $ - 1]; @@ -358,7 +354,7 @@ unittest } void popBack(A)(ref A a) -if(is(A : const(char)[]) && notConst!A) +if(is(A : const(char)[]) && isMutable!A) { immutable n = a.length; const p = a.ptr + n; @@ -400,7 +396,7 @@ unittest } void popBack(A)(ref A a) -if(is(A : const(wchar)[]) && notConst!A) +if(is(A : const(wchar)[]) && isMutable!A) { assert(a.length); if (a.length == 1) diff --git a/std/traits.d b/std/traits.d index 5702a59b2..083cedc93 100644 --- a/std/traits.d +++ b/std/traits.d @@ -2774,6 +2774,27 @@ unittest { static assert(isIterable!(Range)); } +/* + * Returns true if T is not const or immutable. Note that isMutable is true for + * string, or immutable(char)[], because the 'head' is mutable. + */ +template isMutable(T) +{ + enum isMutable = !is(T == const) && !is(T == immutable); +} + +unittest +{ + static assert(isMutable!int); + static assert(isMutable!string); + static assert(isMutable!(shared int)); + static assert(isMutable!(shared const(int)[])); + + static assert(!isMutable!(const int)); + static assert(!isMutable!(shared(const int))); + static assert(!isMutable!(immutable string)); +} + /** * Tells whether the tuple T is an expression tuple. */