xref: /netbsd-src/external/gpl3/gcc/dist/libphobos/libdruntime/core/internal/array/casting.d (revision 0a3071956a3a9fdebdbf7f338cf2d439b45fc728)
1 /**
2  This module contains compiler support for casting dynamic arrays
3 
4   Copyright: Copyright Digital Mars 2000 - 2019.
5   License: Distributed under the
6        $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
7      (See accompanying file LICENSE)
8   Source: $(DRUNTIMESRC core/internal/_array/_casting.d)
9 */
10 module core.internal.array.casting;
11 
12 /**
13 Used by `__ArrayCast` to emit a descriptive error message.
14 
15 It is a template so it can be used by `__ArrayCast` in -betterC
16 builds.  It is separate from `__ArrayCast` to minimize code
17 bloat.
18 
19 Params:
20     fromType   = name of the type being cast from
21     fromSize   = total size in bytes of the array being cast from
22     fromLength = length of array being cast from
23     toType     = name of the type being cast to
24     toElemSize = element size of array being cast to
25  */
onArrayCastError()26 private void onArrayCastError()(string fromType, size_t fromSize, size_t fromLength, string toType, size_t toElemSize) @trusted
27 {
28     import core.internal.string : unsignedToTempString;
29     import core.memory : pureMalloc;
30 
31     // convert discontiguous `msgComponents` to contiguous string on the C heap
32     enum msgLength = 2048;
33     // note: never freed!
34     char* msg = cast(char *)pureMalloc(msgLength);
35 
36     size_t index = 0;
37     void add(const(char)[] m)
38     {
39         import core.stdc.string : memcpy;
40 
41         auto N = msgLength - 1 - index;
42         if (N > m.length)
43             N = m.length;
44         // prevent superfluous and betterC-unfriendly checks via direct memcpy
45         memcpy(msg + index, m.ptr, N);
46         index += N;
47     }
48 
49     add("`");
50     add(fromType);
51     add("[]` of length ");
52     auto s = unsignedToTempString(fromLength);
53     add(s[]);
54     add(" cannot be cast to `");
55     add(toType);
56     add("[]` as its length in bytes (");
57     s = unsignedToTempString(fromSize);
58     add(s[]);
59     add(") is not a multiple of `");
60     add(toType);
61     add(".sizeof` (");
62     s = unsignedToTempString(toElemSize);
63     add(s[]);
64     add(").");
65     msg[index] = '\0'; // null-termination
66 
67     // first argument must evaluate to `false` at compile-time to maintain memory safety in release builds
68     assert(false, msg[0 .. index]);
69 }
70 
71 /**
72 The compiler lowers expressions of `cast(TTo[])TFrom[]` to
73 this implementation. Note that this does not detect alignment problems.
74 
75 Params:
76     from = the array to reinterpret-cast
77 
78 Returns:
79     `from` reinterpreted as `TTo[]`
80  */
__ArrayCast(TFrom,TTo)81 TTo[] __ArrayCast(TFrom, TTo)(return scope TFrom[] from) @nogc pure @trusted
82 {
83     const fromSize = from.length * TFrom.sizeof;
84     const toLength = fromSize / TTo.sizeof;
85 
86     if ((fromSize % TTo.sizeof) != 0)
87     {
88         onArrayCastError(TFrom.stringof, fromSize, from.length, TTo.stringof, TTo.sizeof);
89     }
90 
91     struct Array
92     {
93         size_t length;
94         void* ptr;
95     }
96     auto a = cast(Array*)&from;
97     a.length = toLength; // jam new length
98     return *cast(TTo[]*)a;
99 }
100 
101 @safe @nogc pure nothrow unittest
102 {
103     byte[int.sizeof * 3] b = cast(byte) 0xab;
104     int[] i;
105     short[] s;
106 
107     i = __ArrayCast!(byte, int)(b);
108     assert(i.length == 3);
109     foreach (v; i)
110         assert(v == cast(int) 0xabab_abab);
111 
112     s = __ArrayCast!(byte, short)(b);
113     assert(s.length == 6);
114     foreach (v; s)
115         assert(v == cast(short) 0xabab);
116 
117     s = __ArrayCast!(int, short)(i);
118     assert(s.length == 6);
119     foreach (v; s)
120         assert(v == cast(short) 0xabab);
121 }
122 
123 @system nothrow unittest
124 {
125     string msg;
126     try
127     {
128         auto str = "hello";
129         auto wstr = cast(wstring) str;
130     }
131     catch (Throwable t)
132         msg = t.msg;
133 
134     static immutable expected = "`immutable(char)[]` of length 5 cannot be cast to `immutable(wchar)[]` as " ~
135                             "its length in bytes (5) is not a multiple of `immutable(wchar).sizeof` (2).";
136 
137     if (msg != expected)
138     {
139         import core.stdc.stdio;
140         printf("Expected: |%.*s|\n", cast(int) expected.length, expected.ptr);
141         printf("Actual  : |%.*s|\n", cast(int) msg.length, msg.ptr);
142         assert(false);
143     }
144 }
145