master
1const std = @import("std");
2const builtin = @import("builtin");
3const assert = std.debug.assert;
4const expect = std.testing.expect;
5const expectEqual = std.testing.expectEqual;
6const math = std.math;
7const maxInt = std.math.maxInt;
8const minInt = std.math.minInt;
9const native_endian = builtin.target.cpu.arch.endian();
10
11test "@bitCast iX -> uX (32, 64)" {
12 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
13
14 const bit_values = [_]usize{ 32, 64 };
15
16 inline for (bit_values) |bits| {
17 try testBitCast(bits);
18 try comptime testBitCast(bits);
19 }
20}
21
22test "@bitCast iX -> uX (8, 16, 128)" {
23 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
24 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
25 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
26 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
27
28 const bit_values = [_]usize{ 8, 16, 128 };
29
30 inline for (bit_values) |bits| {
31 try testBitCast(bits);
32 try comptime testBitCast(bits);
33 }
34}
35
36test "@bitCast iX -> uX exotic integers" {
37 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
38 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
39 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
40 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
41 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
42 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
43
44 const bit_values = [_]usize{ 1, 48, 27, 512, 493, 293, 125, 204, 112 };
45
46 inline for (bit_values) |bits| {
47 try testBitCast(bits);
48 try comptime testBitCast(bits);
49 }
50}
51
52fn testBitCast(comptime N: usize) !void {
53 const iN = std.meta.Int(.signed, N);
54 const uN = std.meta.Int(.unsigned, N);
55
56 try expect(conv_iN(N, -1) == maxInt(uN));
57 try expect(conv_uN(N, maxInt(uN)) == -1);
58
59 try expect(conv_iN(N, maxInt(iN)) == maxInt(iN));
60 try expect(conv_uN(N, maxInt(iN)) == maxInt(iN));
61
62 try expect(conv_uN(N, 1 << (N - 1)) == minInt(iN));
63 try expect(conv_iN(N, minInt(iN)) == (1 << (N - 1)));
64
65 try expect(conv_uN(N, 0) == 0);
66 try expect(conv_iN(N, 0) == 0);
67
68 if (N > 24) {
69 try expect(conv_uN(N, 0xf23456) == 0xf23456);
70 }
71}
72
73fn conv_iN(comptime N: usize, x: std.meta.Int(.signed, N)) std.meta.Int(.unsigned, N) {
74 return @as(std.meta.Int(.unsigned, N), @bitCast(x));
75}
76
77fn conv_uN(comptime N: usize, x: std.meta.Int(.unsigned, N)) std.meta.Int(.signed, N) {
78 return @as(std.meta.Int(.signed, N), @bitCast(x));
79}
80
81test "bitcast uX to bytes" {
82 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
83 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
84 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
85 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
86 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
87 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
88
89 const bit_values = [_]usize{ 1, 48, 27, 512, 493, 293, 125, 204, 112 };
90 inline for (bit_values) |bits| {
91 try testBitCast(bits);
92 try comptime testBitCast(bits);
93 }
94}
95
96fn testBitCastuXToBytes(comptime N: usize) !void {
97
98 // The location of padding bits in these layouts are technically not defined
99 // by LLVM, but we currently allow exotic integers to be cast (at comptime)
100 // to types that expose their padding bits anyway.
101 //
102 // This test at least makes sure those bits are matched by the runtime behavior
103 // on the platforms we target. If the above behavior is restricted after all,
104 // this test should be deleted.
105
106 const T = std.meta.Int(.unsigned, N);
107 for ([_]T{ 0, ~@as(T, 0) }) |init_value| {
108 var x: T = init_value;
109 const bytes = std.mem.asBytes(&x);
110
111 const byte_count = (N + 7) / 8;
112 switch (native_endian) {
113 .little => {
114 var byte_i = 0;
115 while (byte_i < (byte_count - 1)) : (byte_i += 1) {
116 try expect(bytes[byte_i] == 0xff);
117 }
118 try expect(((bytes[byte_i] ^ 0xff) << -%@as(u3, @truncate(N))) == 0);
119 },
120 .big => {
121 var byte_i = byte_count - 1;
122 while (byte_i > 0) : (byte_i -= 1) {
123 try expect(bytes[byte_i] == 0xff);
124 }
125 try expect(((bytes[byte_i] ^ 0xff) << -%@as(u3, @truncate(N))) == 0);
126 },
127 }
128 }
129}
130
131test "nested bitcast" {
132 const S = struct {
133 fn moo(x: isize) !void {
134 try expect(@as(isize, @intCast(42)) == x);
135 }
136
137 fn foo(x: isize) !void {
138 try @This().moo(
139 @as(isize, @bitCast(if (x != 0) @as(usize, @bitCast(x)) else @as(usize, @bitCast(x)))),
140 );
141 }
142 };
143
144 try S.foo(42);
145 try comptime S.foo(42);
146}
147
148// issue #3010: compiler segfault
149test "bitcast literal [4]u8 param to u32" {
150 const ip = @as(u32, @bitCast([_]u8{ 255, 255, 255, 255 }));
151 try expect(ip == maxInt(u32));
152}
153
154test "bitcast generates a temporary value" {
155 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
156
157 var y: u16 = 0x55AA;
158 _ = &y;
159 const x: u16 = @bitCast(@as([2]u8, @bitCast(y)));
160 try expect(y == x);
161}
162
163test "@bitCast packed structs at runtime and comptime" {
164 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
165 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
166 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
167
168 const Full = packed struct {
169 number: u16,
170 };
171 const Divided = packed struct {
172 half1: u8,
173 quarter3: u4,
174 quarter4: u4,
175 };
176 const S = struct {
177 fn doTheTest() !void {
178 var full = Full{ .number = 0x1234 };
179 _ = &full;
180 const two_halves: Divided = @bitCast(full);
181 try expect(two_halves.half1 == 0x34);
182 try expect(two_halves.quarter3 == 0x2);
183 try expect(two_halves.quarter4 == 0x1);
184 }
185 };
186 try S.doTheTest();
187 try comptime S.doTheTest();
188}
189
190test "@bitCast extern structs at runtime and comptime" {
191 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
192 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
193 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
194
195 const Full = extern struct {
196 number: u16,
197 };
198 const TwoHalves = extern struct {
199 half1: u8,
200 half2: u8,
201 };
202 const S = struct {
203 fn doTheTest() !void {
204 var full = Full{ .number = 0x1234 };
205 _ = &full;
206 const two_halves: TwoHalves = @bitCast(full);
207 switch (native_endian) {
208 .big => {
209 try expect(two_halves.half1 == 0x12);
210 try expect(two_halves.half2 == 0x34);
211 },
212 .little => {
213 try expect(two_halves.half1 == 0x34);
214 try expect(two_halves.half2 == 0x12);
215 },
216 }
217 }
218 };
219 try S.doTheTest();
220 try comptime S.doTheTest();
221}
222
223test "bitcast packed struct to integer and back" {
224 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
225 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
226 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
227
228 const LevelUpMove = packed struct {
229 move_id: u9,
230 level: u7,
231 };
232 const S = struct {
233 fn doTheTest() !void {
234 var move = LevelUpMove{ .move_id = 1, .level = 2 };
235 _ = &move;
236 const v: u16 = @bitCast(move);
237 const back_to_a_move: LevelUpMove = @bitCast(v);
238 try expect(back_to_a_move.move_id == 1);
239 try expect(back_to_a_move.level == 2);
240 }
241 };
242 try S.doTheTest();
243 try comptime S.doTheTest();
244}
245
246test "implicit cast to error union by returning" {
247 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
248 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
249
250 const S = struct {
251 fn entry() !void {
252 try expect((func(-1) catch unreachable) == maxInt(u64));
253 }
254 pub fn func(sz: i64) anyerror!u64 {
255 return @as(u64, @bitCast(sz));
256 }
257 };
258 try S.entry();
259 try comptime S.entry();
260}
261
262test "bitcast packed struct literal to byte" {
263 const Foo = packed struct {
264 value: u8,
265 };
266 const casted = @as(u8, @bitCast(Foo{ .value = 0xF }));
267 try expect(casted == 0xf);
268}
269
270test "comptime bitcast used in expression has the correct type" {
271 const Foo = packed struct {
272 value: u8,
273 };
274 try expect(@as(u8, @bitCast(Foo{ .value = 0xF })) == 0xf);
275}
276
277test "bitcast passed as tuple element" {
278 const S = struct {
279 fn foo(args: anytype) !void {
280 comptime assert(@TypeOf(args[0]) == f32);
281 try expect(args[0] == 12.34);
282 }
283 };
284 try S.foo(.{@as(f32, @bitCast(@as(u32, 0x414570A4)))});
285}
286
287test "triple level result location with bitcast sandwich passed as tuple element" {
288 const S = struct {
289 fn foo(args: anytype) !void {
290 comptime assert(@TypeOf(args[0]) == f64);
291 try expect(args[0] > 12.33 and args[0] < 12.35);
292 }
293 };
294 try S.foo(.{@as(f64, @as(f32, @bitCast(@as(u32, 0x414570A4))))});
295}
296
297test "@bitCast packed struct of floats" {
298 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
299 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
300 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
301 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
302 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
303 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
304 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
305
306 const Foo = packed struct {
307 a: f16 = 0,
308 b: f32 = 1,
309 c: f64 = 2,
310 d: f128 = 3,
311 };
312
313 const Foo2 = packed struct {
314 a: f16 = 0,
315 b: f32 = 1,
316 c: f64 = 2,
317 d: f128 = 3,
318 };
319
320 const S = struct {
321 fn doTheTest() !void {
322 var foo = Foo{};
323 _ = &foo;
324 const v: Foo2 = @bitCast(foo);
325 try expect(v.a == foo.a);
326 try expect(v.b == foo.b);
327 try expect(v.c == foo.c);
328 try expect(v.d == foo.d);
329 }
330 };
331 try S.doTheTest();
332 try comptime S.doTheTest();
333}
334
335test "comptime @bitCast packed struct to int and back" {
336 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
337 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
338 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
339 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
340 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
341 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
342 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
343
344 const S = packed struct {
345 void: void = {},
346 uint: u8 = 13,
347 uint_bit_aligned: u3 = 2,
348 iint_pos: i4 = 1,
349 iint_neg4: i3 = -4,
350 iint_neg2: i3 = -2,
351 float: f32 = 3.14,
352 @"enum": enum(u2) { A, B = 1, C, D } = .B,
353 vectorb: @Vector(3, bool) = .{ true, false, true },
354 vectori: @Vector(2, u8) = .{ 127, 42 },
355 vectorf: @Vector(2, f16) = .{ 3.14, 2.71 },
356 };
357 const Int = @typeInfo(S).@"struct".backing_integer.?;
358
359 // S -> Int
360 var s: S = .{};
361 _ = &s;
362 try expectEqual(@as(Int, @bitCast(s)), comptime @as(Int, @bitCast(S{})));
363
364 // Int -> S
365 var i: Int = 0;
366 _ = &i;
367 const rt_cast = @as(S, @bitCast(i));
368 const ct_cast = comptime @as(S, @bitCast(@as(Int, 0)));
369 inline for (@typeInfo(S).@"struct".fields) |field| {
370 try expectEqual(@field(rt_cast, field.name), @field(ct_cast, field.name));
371 }
372}
373
374test "comptime bitcast with fields following f80" {
375 if (true) {
376 // https://github.com/ziglang/zig/issues/19387
377 return error.SkipZigTest;
378 }
379
380 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
381 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
382 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
383
384 const FloatT = extern struct { f: f80, x: u128 align(16) };
385 const x: FloatT = .{ .f = 0.5, .x = 123 };
386 var x_as_uint: u256 = comptime @as(u256, @bitCast(x));
387 _ = &x_as_uint;
388
389 try expect(x.f == @as(FloatT, @bitCast(x_as_uint)).f);
390 try expect(x.x == @as(FloatT, @bitCast(x_as_uint)).x);
391}
392
393test "bitcast vector to integer and back" {
394 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
395 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
396 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
397 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
398 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
399 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
400 if (builtin.cpu.arch == .aarch64_be and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
401
402 const arr: [16]bool = [_]bool{ true, false } ++ [_]bool{true} ** 14;
403 var x: @Vector(16, bool) = @splat(true);
404 x[1] = false;
405 try expect(@as(u16, @bitCast(x)) == comptime @as(u16, @bitCast(@as(@Vector(16, bool), arr))));
406}
407
408fn bitCastWrapper16(x: f16) u16 {
409 return @as(u16, @bitCast(x));
410}
411fn bitCastWrapper32(x: f32) u32 {
412 return @as(u32, @bitCast(x));
413}
414fn bitCastWrapper64(x: f64) u64 {
415 return @as(u64, @bitCast(x));
416}
417fn bitCastWrapper128(x: f128) u128 {
418 return @as(u128, @bitCast(x));
419}
420test "bitcast nan float does not modify signaling bit" {
421 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
422 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
423 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
424 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
425
426 const snan_u16: u16 = 0x7D00;
427 const snan_u32: u32 = 0x7FA00000;
428 const snan_u64: u64 = 0x7FF4000000000000;
429 const snan_u128: u128 = 0x7FFF4000000000000000000000000000;
430
431 // 16 bit
432 const snan_f16_const = math.snan(f16);
433 try expectEqual(snan_u16, @as(u16, @bitCast(snan_f16_const)));
434 try expectEqual(snan_u16, bitCastWrapper16(snan_f16_const));
435
436 var snan_f16_var = math.snan(f16);
437 _ = &snan_f16_var;
438 try expectEqual(snan_u16, @as(u16, @bitCast(snan_f16_var)));
439 try expectEqual(snan_u16, bitCastWrapper16(snan_f16_var));
440
441 // 32 bit
442 const snan_f32_const = math.snan(f32);
443 try expectEqual(snan_u32, @as(u32, @bitCast(snan_f32_const)));
444 try expectEqual(snan_u32, bitCastWrapper32(snan_f32_const));
445
446 var snan_f32_var = math.snan(f32);
447 _ = &snan_f32_var;
448 try expectEqual(snan_u32, @as(u32, @bitCast(snan_f32_var)));
449 try expectEqual(snan_u32, bitCastWrapper32(snan_f32_var));
450
451 // 64 bit
452 const snan_f64_const = math.snan(f64);
453 try expectEqual(snan_u64, @as(u64, @bitCast(snan_f64_const)));
454 try expectEqual(snan_u64, bitCastWrapper64(snan_f64_const));
455
456 var snan_f64_var = math.snan(f64);
457 _ = &snan_f64_var;
458 try expectEqual(snan_u64, @as(u64, @bitCast(snan_f64_var)));
459 try expectEqual(snan_u64, bitCastWrapper64(snan_f64_var));
460
461 // 128 bit
462 const snan_f128_const = math.snan(f128);
463 try expectEqual(snan_u128, @as(u128, @bitCast(snan_f128_const)));
464 try expectEqual(snan_u128, bitCastWrapper128(snan_f128_const));
465
466 var snan_f128_var = math.snan(f128);
467 _ = &snan_f128_var;
468 try expectEqual(snan_u128, @as(u128, @bitCast(snan_f128_var)));
469 try expectEqual(snan_u128, bitCastWrapper128(snan_f128_var));
470}
471
472test "@bitCast of packed struct of bools all true" {
473 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
474 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
475 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
476 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
477 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
478
479 const P = packed struct {
480 b0: bool,
481 b1: bool,
482 b2: bool,
483 b3: bool,
484 };
485 var p = std.mem.zeroes(P);
486 p.b0 = true;
487 p.b1 = true;
488 p.b2 = true;
489 p.b3 = true;
490 try expect(@as(u8, @as(u4, @bitCast(p))) == 15);
491}
492
493test "@bitCast of packed struct of bools all false" {
494 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
495 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
496 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
497 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
498
499 const P = packed struct {
500 b0: bool,
501 b1: bool,
502 b2: bool,
503 b3: bool,
504 };
505 var p = std.mem.zeroes(P);
506 p.b0 = false;
507 p.b1 = false;
508 p.b2 = false;
509 p.b3 = false;
510 try expect(@as(u8, @as(u4, @bitCast(p))) == 0);
511}
512
513test "@bitCast of packed struct containing pointer" {
514 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
515 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
516 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
517 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
518 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // https://discourse.llvm.org/t/rfc-remove-most-constant-expressions/63179
519
520 const S = struct {
521 const A = packed struct {
522 ptr: *const u32,
523 };
524
525 const B = packed struct {
526 ptr: *const i32,
527 };
528
529 fn doTheTest() !void {
530 const x: u32 = 123;
531 var a: A = undefined;
532 a = .{ .ptr = &x };
533 const b: B = @bitCast(a);
534 try expect(b.ptr.* == 123);
535 }
536 };
537
538 try S.doTheTest();
539 try comptime S.doTheTest();
540}
541
542test "@bitCast of extern struct containing pointer" {
543 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
544 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
545 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
546 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
547 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
548
549 const S = struct {
550 const A = extern struct {
551 ptr: *const u32,
552 };
553
554 const B = extern struct {
555 ptr: *const i32,
556 };
557
558 fn doTheTest() !void {
559 const x: u32 = 123;
560 var a: A = undefined;
561 a = .{ .ptr = &x };
562 const b: B = @bitCast(a);
563 try expect(b.ptr.* == 123);
564 }
565 };
566
567 try S.doTheTest();
568 try comptime S.doTheTest();
569}