@@ -4881,3 +4881,101 @@ void __ArrayDtor(T)(T[] a)
48814881 foreach_reverse (ref T e; a)
48824882 e.__xdtor();
48834883}
4884+
4885+ /**
4886+ Used by `__ArrayCast` to emit a descriptive error message.
4887+
4888+ It is a template so it can be used by `__ArrayCast` in -betterC
4889+ builds. It is separate from `__ArrayCast` to minimize code
4890+ bloat.
4891+
4892+ Params:
4893+ fromType = name of the type being cast from
4894+ fromSize = total size in bytes of the array being cast from
4895+ toType = name of the type being cast o
4896+ toSize = total size in bytes of the array being cast to
4897+ */
4898+ private void onArrayCastError ()(string fromType, size_t fromSize, string toType, size_t toSize) @trusted
4899+ {
4900+ import core.internal.string : unsignedToTempString;
4901+ import core.stdc.stdlib : alloca;
4902+
4903+ const (char )[][8 ] msgComponents =
4904+ [
4905+ " Cannot cast `"
4906+ , fromType
4907+ , " ` to `"
4908+ , toType
4909+ , " `; an array of size "
4910+ , unsignedToTempString(fromSize)
4911+ , " does not align on an array of size "
4912+ , unsignedToTempString(toSize)
4913+ ];
4914+
4915+ // convert discontiguous `msgComponents` to contiguous string on the stack
4916+ size_t length = 0 ;
4917+ foreach (m ; msgComponents)
4918+ length += m.length;
4919+
4920+ auto msg = (cast (char * )alloca(length))[0 .. length];
4921+
4922+ size_t index = 0 ;
4923+ foreach (m ; msgComponents)
4924+ foreach (c; m)
4925+ msg[index++ ] = c;
4926+
4927+ // first argument must evaluate to `false` at compile-time to maintain memory safety in release builds
4928+ assert (false , msg);
4929+ }
4930+
4931+ /**
4932+ The compiler lowers expressions of `cast(TTo[])TFrom[]` to
4933+ this implementation.
4934+
4935+ Params:
4936+ from = the array to reinterpret-cast
4937+
4938+ Returns:
4939+ `from` reinterpreted as `TTo[]`
4940+ */
4941+ TTo[] __ArrayCast (TFrom, TTo)(TFrom[] from) @nogc pure @trusted
4942+ {
4943+ const fromSize = from.length * TFrom.sizeof;
4944+ const toLength = fromSize / TTo.sizeof;
4945+
4946+ if ((fromSize % TTo.sizeof) != 0 )
4947+ {
4948+ onArrayCastError(TFrom.stringof, fromSize, TTo.stringof, toLength * TTo.sizeof);
4949+ }
4950+
4951+ struct Array
4952+ {
4953+ size_t length;
4954+ void * ptr;
4955+ }
4956+ auto a = cast (Array* )&from;
4957+ a.length = toLength; // jam new length
4958+ return * cast (TTo[]* )a;
4959+ }
4960+
4961+ @safe @nogc pure nothrow unittest
4962+ {
4963+ byte [int .sizeof * 3 ] b = cast (byte ) 0xab ;
4964+ int [] i;
4965+ short [] s;
4966+
4967+ i = __ArrayCast! (byte , int )(b);
4968+ assert (i.length == 3 );
4969+ foreach (v; i)
4970+ assert (v == cast (int ) 0xabab_abab);
4971+
4972+ s = __ArrayCast! (byte , short )(b);
4973+ assert (s.length == 6 );
4974+ foreach (v; s)
4975+ assert (v == cast (short ) 0xabab );
4976+
4977+ s = __ArrayCast! (int , short )(i);
4978+ assert (s.length == 6 );
4979+ foreach (v; s)
4980+ assert (v == cast (short ) 0xabab );
4981+ }
0 commit comments