1const std = @import("std");
2const expect = std.testing.expect;
3const builtin = @import("builtin");
4const native_arch = builtin.target.cpu.arch;
5const assert = std.debug.assert;
6
7var foo: u8 align(4) = 100;
8
9test "global variable alignment" {
10 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
11
12 comptime assert(@typeInfo(@TypeOf(&foo)).pointer.attrs.@"align" == 4);
13 comptime assert(@TypeOf(&foo) == *align(4) u8);
14 {
15 const slice = @as(*align(4) [1]u8, &foo)[0..];
16 comptime assert(@TypeOf(slice) == *align(4) [1]u8);
17 }
18}
19
20test "large abi alignment of global" {
21 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
22
23 const S = struct {
24 var global: @This() = undefined;
25 x: u64 align(64),
26 };
27
28 try std.testing.expect(@ctz(@intFromPtr(&S.global)) >= 6);
29}
30
31test "large alignment of local constant" {
32 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
33 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // flaky
34 if (builtin.zig_backend == .stage2_c and builtin.target.abi == .msvc) return error.SkipZigTest;
35
36 if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .windows) {
37 // https://codeberg.org/ziglang/zig/issues/35537
38 return error.SkipZigTest;
39 }
40
41 const x: f32 align(128) = 12.34;
42 try std.testing.expect(@intFromPtr(&x) % 128 == 0);
43}
44
45test "slicing array of length 1 can not assume runtime index is always zero" {
46 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
47 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // flaky
48
49 var runtime_index: usize = 1;
50 _ = &runtime_index;
51 const slice = @as(*align(4) [1]u8, &foo)[runtime_index..];
52 try expect(@TypeOf(slice) == []align(1) u8);
53 try expect(slice.len == 0);
54 try expect(@as(u2, @truncate(@intFromPtr(slice.ptr) - 1)) == 0);
55}
56
57test "implicitly-aligned pointer is coercible to equivalent explicitly-aligned pointer" {
58 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
59
60 const A = *u32;
61 const B = *align(@alignOf(u32)) u32;
62
63 comptime assert(A != B);
64
65 const static = struct {
66 fn doTheTest() !void {
67 var buf: u32 = 123;
68
69 const ptr: A = &buf;
70 const coerced_ptr: B = ptr;
71
72 try expect(ptr == coerced_ptr);
73 try expect(ptr.* == 123);
74 try expect(coerced_ptr.* == 123);
75
76 const ptr_ptr: *const A = &ptr;
77 const coerced_ptr_ptr: *const B = ptr_ptr;
78
79 try expect(ptr_ptr == coerced_ptr_ptr);
80 try expect(ptr_ptr.* == &buf);
81 try expect(coerced_ptr_ptr.* == &buf);
82 try expect(ptr_ptr.*.* == 123);
83 try expect(coerced_ptr_ptr.*.* == 123);
84 }
85 };
86
87 try static.doTheTest();
88 try comptime static.doTheTest();
89}
90
91test "implicitly decreasing pointer alignment" {
92 const a: u32 align(4) = 3;
93 const b: u32 align(8) = 4;
94 try expect(addUnaligned(&a, &b) == 7);
95}
96
97fn addUnaligned(a: *align(1) const u32, b: *align(1) const u32) u32 {
98 return a.* + b.*;
99}
100
101test "@alignCast pointers" {
102 var x: u32 align(4) = 1;
103 expectsOnly1(&x);
104 try expect(x == 2);
105}
106fn expectsOnly1(x: *align(1) u32) void {
107 expects4(@alignCast(x));
108}
109fn expects4(x: *align(4) u32) void {
110 x.* += 1;
111}
112
113test "alignment of struct with pointer has same alignment as usize" {
114 try expect(@alignOf(struct {
115 a: i32,
116 b: *i32,
117 }) == @alignOf(usize));
118}
119
120test "alignment and size of structs with 128-bit fields" {
121 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
122 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
123
124 const A = struct {
125 x: u128,
126 };
127 const B = extern struct {
128 x: u128,
129 y: u8,
130 };
131 const expected = switch (builtin.cpu.arch) {
132 .s390x => .{
133 .a_align = 8,
134 .a_size = 16,
135
136 .b_align = 8,
137 .b_size = 24,
138
139 .u128_align = 8,
140 .u128_size = 16,
141 .u129_align = 8,
142 .u129_size = 24,
143 },
144 .x86 => switch (builtin.os.tag) {
145 else => .{
146 .a_align = 4,
147 .a_size = 16,
148
149 .b_align = 4,
150 .b_size = 20,
151
152 .u128_align = 4,
153 .u128_size = 16,
154 .u129_align = 4,
155 .u129_size = 20,
156 },
157 .uefi, .windows => .{
158 .a_align = 8,
159 .a_size = 16,
160
161 .b_align = 8,
162 .b_size = 24,
163
164 .u128_align = 8,
165 .u128_size = 16,
166 .u129_align = 8,
167 .u129_size = 24,
168 },
169 },
170 .amdgcn,
171 .arm,
172 .armeb,
173 .thumb,
174 .thumbeb,
175 .hexagon,
176 .lanai,
177 .mips,
178 .mipsel,
179 .powerpc,
180 .powerpcle,
181 .riscv32,
182 .sparc,
183 => .{
184 .a_align = 8,
185 .a_size = 16,
186
187 .b_align = 8,
188 .b_size = 24,
189
190 .u128_align = 8,
191 .u128_size = 16,
192 .u129_align = 8,
193 .u129_size = 24,
194 },
195
196 .aarch64,
197 .aarch64_be,
198 .bpfel,
199 .bpfeb,
200 .mips64,
201 .mips64el,
202 .nvptx,
203 .nvptx64,
204 .powerpc64,
205 .powerpc64le,
206 .sparc64,
207 .riscv64,
208 .wasm32,
209 .wasm64,
210 .x86_64,
211 => .{
212 .a_align = 16,
213 .a_size = 16,
214
215 .b_align = 16,
216 .b_size = 32,
217
218 .u128_align = 16,
219 .u128_size = 16,
220 .u129_align = 16,
221 .u129_size = 32,
222 },
223
224 else => return error.SkipZigTest,
225 };
226 comptime {
227 assert(@alignOf(A) == expected.a_align);
228 assert(@sizeOf(A) == expected.a_size);
229
230 assert(@alignOf(B) == expected.b_align);
231 assert(@sizeOf(B) == expected.b_size);
232
233 assert(@alignOf(u128) == expected.u128_align);
234 assert(@sizeOf(u128) == expected.u128_size);
235
236 assert(@alignOf(u129) == expected.u129_align);
237 assert(@sizeOf(u129) == expected.u129_size);
238 }
239}
240
241test "implicitly decreasing slice alignment" {
242 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
243 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
244 const a: u32 align(4) = 3;
245 const b: u32 align(8) = 4;
246 try expect(addUnalignedSlice(@as(*const [1]u32, &a)[0..], @as(*const [1]u32, &b)[0..]) == 7);
247}
248fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) u32 {
249 return a[0] + b[0];
250}
251
252test "specifying alignment allows pointer cast" {
253 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
254 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
255
256 try testBytesAlign(0x33);
257}
258fn testBytesAlign(b: u8) !void {
259 var bytes align(4) = [_]u8{ b, b, b, b };
260 const ptr = @as(*u32, @ptrCast(&bytes[0]));
261 try expect(ptr.* == 0x33333333);
262}
263
264test "@alignCast slices" {
265 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
266 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
267 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
268
269 var array align(4) = [_]u32{ 1, 1 };
270 const slice = array[0..];
271 sliceExpectsOnly1(slice);
272 try expect(slice[0] == 2);
273}
274fn sliceExpectsOnly1(slice: []align(1) u32) void {
275 sliceExpects4(@alignCast(slice));
276}
277fn sliceExpects4(slice: []align(4) u32) void {
278 slice[0] += 1;
279}
280
281test "return error union with 128-bit integer" {
282 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
283 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
284 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
285 try expect(3 == try give());
286}
287fn give() anyerror!u128 {
288 return 3;
289}
290
291test "page aligned array on stack" {
292 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
293 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
294 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
295 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
296 // Large alignment value to make it hard to accidentally pass.
297 var array align(0x1000) = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };
298 var number1: u8 align(16) = 42;
299 var number2: u8 align(16) = 43;
300
301 try expect(@intFromPtr(&array[0]) & 0xFFF == 0);
302 try expect(array[3] == 4);
303
304 try expect(@as(u4, @truncate(@intFromPtr(&number1))) == 0);
305 try expect(@as(u4, @truncate(@intFromPtr(&number2))) == 0);
306 try expect(number1 == 42);
307 try expect(number2 == 43);
308}
309
310test "function alignment" {
311 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
312 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
313 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
314
315 // function alignment is a compile error on wasm
316 if (native_arch.isWasm()) return error.SkipZigTest;
317
318 const S = struct {
319 fn alignExpr() align(@sizeOf(usize) * 2) i32 {
320 return 1234;
321 }
322 fn align1() align(1) void {}
323 fn align4() align(4) void {}
324 };
325
326 try expect(S.alignExpr() == 1234);
327 try expect(@TypeOf(S.alignExpr) == fn () i32);
328 try expect(@TypeOf(&S.alignExpr) == *align(@sizeOf(usize) * 2) const fn () i32);
329
330 S.align1();
331 try expect(@TypeOf(S.align1) == fn () void);
332 try expect(@TypeOf(&S.align1) == *align(1) const fn () void);
333
334 S.align4();
335 try expect(@TypeOf(S.align4) == fn () void);
336 try expect(@TypeOf(&S.align4) == *align(4) const fn () void);
337}
338
339test "implicitly decreasing fn alignment" {
340 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
341 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
342 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
343
344 // function alignment is a compile error on wasm
345 if (native_arch.isWasm()) return error.SkipZigTest;
346
347 try testImplicitlyDecreaseFnAlign(alignedSmall, 1234);
348 try testImplicitlyDecreaseFnAlign(alignedBig, 5678);
349}
350
351fn testImplicitlyDecreaseFnAlign(ptr: *align(1) const fn () i32, answer: i32) !void {
352 try expect(ptr() == answer);
353}
354
355fn alignedSmall() align(8) i32 {
356 return 1234;
357}
358fn alignedBig() align(16) i32 {
359 return 5678;
360}
361
362test "@alignCast functions" {
363 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
364 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
365 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
366
367 // function alignment is a compile error on wasm
368 if (native_arch.isWasm()) return error.SkipZigTest;
369
370 try expect(fnExpectsOnly1(simple4) == 0x19);
371}
372fn fnExpectsOnly1(ptr: *align(1) const fn () i32) i32 {
373 return fnExpects4(@alignCast(ptr));
374}
375fn fnExpects4(ptr: *align(4) const fn () i32) i32 {
376 return ptr();
377}
378fn simple4() align(4) i32 {
379 return 0x19;
380}
381
382test "runtime-known array index has best alignment possible" {
383 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
384 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
385
386 // take full advantage of over-alignment
387 var array align(4) = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };
388 comptime assert(@TypeOf(&array[0]) == *align(4) u8);
389 comptime assert(@TypeOf(&array[1]) == *align(1) u8);
390 comptime assert(@TypeOf(&array[2]) == *align(2) u8);
391 comptime assert(@TypeOf(&array[3]) == *align(1) u8);
392 comptime assert(@TypeOf(&array[4]) == *align(4) u8);
393 comptime assert(@TypeOf(&array[5]) == *align(1) u8);
394 comptime assert(@TypeOf(&array[6]) == *align(2) u8);
395 comptime assert(@TypeOf(&array[7]) == *align(1) u8);
396
397 // because align is too small but we still figure out to use 2
398 var bigger align(2) = [_]u64{ 1, 2, 3, 4 };
399 comptime assert(@TypeOf(&bigger[0]) == *align(2) u64);
400 comptime assert(@TypeOf(&bigger[1]) == *align(2) u64);
401 comptime assert(@TypeOf(&bigger[2]) == *align(2) u64);
402 comptime assert(@TypeOf(&bigger[3]) == *align(2) u64);
403
404 // because pointer is align 2 and u32 align % 2 == 0 we can assume align 2
405 var smaller align(2) = [_]u32{ 1, 2, 3, 4 };
406 var runtime_zero: usize = 0;
407 _ = &runtime_zero;
408 comptime assert(@TypeOf(smaller[runtime_zero..]) == []align(2) u32);
409 comptime assert(@TypeOf(smaller[runtime_zero..].ptr) == [*]align(2) u32);
410 try testIndex(smaller[runtime_zero..].ptr, 0, *align(2) u32);
411 try testIndex(smaller[runtime_zero..].ptr, 1, *align(2) u32);
412 try testIndex(smaller[runtime_zero..].ptr, 2, *align(2) u32);
413 try testIndex(smaller[runtime_zero..].ptr, 3, *align(2) u32);
414
415 // has to use ABI alignment because index known at runtime only
416 try testIndex2(&array, 0, *align(1) u8);
417 try testIndex2(&array, 1, *align(1) u8);
418 try testIndex2(&array, 2, *align(1) u8);
419 try testIndex2(&array, 3, *align(1) u8);
420 try testIndex2(&array, 4, *align(1) u8);
421 try testIndex2(&array, 5, *align(1) u8);
422 try testIndex2(&array, 6, *align(1) u8);
423 try testIndex2(&array, 7, *align(1) u8);
424}
425fn testIndex(smaller: [*]align(2) u32, index: usize, comptime T: type) !void {
426 comptime assert(@TypeOf(&smaller[index]) == T);
427}
428fn testIndex2(ptr: [*]align(4) u8, index: usize, comptime T: type) !void {
429 comptime assert(@TypeOf(&ptr[index]) == T);
430}
431
432test "alignment of function with c calling convention" {
433 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
434
435 const a = @alignOf(@TypeOf(nothing));
436
437 var runtime_nothing = &nothing;
438 _ = &runtime_nothing;
439 const casted1: *align(a) const u8 = @ptrCast(runtime_nothing);
440 const casted2: *const fn () callconv(.c) void = @ptrCast(casted1);
441 casted2();
442}
443
444fn nothing() callconv(.c) void {}
445
446const DefaultAligned = struct {
447 nevermind: u32,
448 badguy: i128,
449};
450
451test "read 128-bit field from default aligned struct in stack memory" {
452 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
453 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
454 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
455
456 var default_aligned = DefaultAligned{
457 .nevermind = 1,
458 .badguy = 12,
459 };
460 _ = &default_aligned;
461 try expect(12 == default_aligned.badguy);
462}
463
464var default_aligned_global = DefaultAligned{
465 .nevermind = 1,
466 .badguy = 12,
467};
468
469test "read 128-bit field from default aligned struct in global memory" {
470 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
471 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
472 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
473
474 try expect(12 == default_aligned_global.badguy);
475}
476
477test "struct field explicit alignment" {
478 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
479 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
480 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // flaky
481 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
482
483 const S = struct {
484 const Node = struct {
485 next: *Node,
486 massive_byte: u8 align(64),
487 };
488 };
489
490 var node: S.Node = undefined;
491 node.massive_byte = 100;
492 try expect(node.massive_byte == 100);
493 comptime assert(@TypeOf(&node.massive_byte) == *align(64) u8);
494 try expect(@intFromPtr(&node.massive_byte) % 64 == 0);
495}
496
497test "align(N) on functions" {
498 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
499 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
500 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
501
502 if (builtin.zig_backend == .stage2_c) {
503 // https://github.com/ziglang/zig/issues/16845
504 return error.SkipZigTest;
505 }
506
507 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) {
508 // This is not supported on MSVC.
509 return error.SkipZigTest;
510 }
511
512 // function alignment is a compile error on wasm
513 if (native_arch.isWasm()) return error.SkipZigTest;
514 if (native_arch.isThumb()) return error.SkipZigTest;
515
516 try expect((@intFromPtr(&overaligned_fn) & (0x1000 - 1)) == 0);
517}
518fn overaligned_fn() align(0x1000) i32 {
519 return 42;
520}
521
522test "comptime alloc alignment" {
523 // TODO: it's impossible to test this in Zig today, since comptime vars do not have runtime addresses.
524 if (true) return error.SkipZigTest;
525 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
526 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
527
528 comptime var bytes1 = [_]u8{0};
529 _ = &bytes1;
530
531 comptime var bytes2 align(256) = [_]u8{0};
532 const bytes2_addr = @intFromPtr(&bytes2);
533 try expect(bytes2_addr & 0xff == 0);
534}
535
536test "@alignCast null" {
537 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
538 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
539
540 var ptr: ?*anyopaque = null;
541 _ = &ptr;
542 const aligned: ?*anyopaque = @alignCast(ptr);
543 try expect(aligned == null);
544}
545
546test "alignment of slice element" {
547 const a: []align(1024) const u8 = undefined;
548 try expect(@TypeOf(&a[0]) == *align(1024) const u8);
549}
550
551test "sub-aligned pointer field access" {
552 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
553 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
554 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
555
556 // Originally reported at https://github.com/ziglang/zig/issues/14904
557
558 const Header = extern struct {
559 tag: u32,
560 bytes_len: u32,
561 };
562 var buf: [9]u8 align(4) = .{ 1, 2, 3, 4, 5, 6, 7, 8, 9 };
563 const ptr: *align(1) Header = @ptrCast(buf[1..][0..8]);
564 const x = ptr.bytes_len;
565 switch (builtin.cpu.arch.endian()) {
566 .big => try expect(x == 0x06070809),
567 .little => try expect(x == 0x09080706),
568 }
569}
570
571test "alignment of zero-bit types is respected" {
572 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
573 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
574
575 const S = struct { arr: [0]usize = .{} };
576
577 comptime assert(@alignOf(void) == 1);
578 comptime assert(@alignOf(u0) == 1);
579 comptime assert(@alignOf([0]usize) == @alignOf(usize));
580 comptime assert(@alignOf(S) == @alignOf(usize));
581
582 var s: S = .{};
583 var v32: void align(32) = {};
584 var x32: u0 align(32) = 0;
585 var s32: S align(32) = .{};
586
587 var zero: usize = 0;
588 _ = &zero;
589
590 try expect(@intFromPtr(&s) % @alignOf(usize) == 0);
591 try expect(@intFromPtr(&s.arr) % @alignOf(usize) == 0);
592 try expect(@intFromPtr(s.arr[zero..zero].ptr) % @alignOf(usize) == 0);
593 try expect(@intFromPtr(&v32) % 32 == 0);
594 try expect(@intFromPtr(&x32) % 32 == 0);
595 try expect(@intFromPtr(&s32) % 32 == 0);
596 try expect(@intFromPtr(&s32.arr) % 32 == 0);
597 try expect(@intFromPtr(s32.arr[zero..zero].ptr) % 32 == 0);
598}
599
600test "zero-bit fields in extern struct pad fields appropriately" {
601 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
602 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
603 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
604 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
605
606 const S = extern struct {
607 x: u8,
608 a: [0]u16 = .{},
609 y: u8,
610 };
611
612 // `a` should give `S` alignment 2, and pad the `arr` field.
613 comptime assert(@alignOf(S) == 2);
614 comptime assert(@sizeOf(S) == 4);
615 comptime assert(@offsetOf(S, "x") == 0);
616 comptime assert(@offsetOf(S, "a") == 2);
617 comptime assert(@offsetOf(S, "y") == 2);
618
619 var s: S = .{ .x = 100, .y = 200 };
620
621 try expect(@intFromPtr(&s) % 2 == 0);
622 try expect(@intFromPtr(&s.y) - @intFromPtr(&s.x) == 2);
623 try expect(@intFromPtr(&s.y) == @intFromPtr(&s.a));
624 try expect(@as(*S, @fieldParentPtr("a", &s.a)) == &s);
625}
626
627test "function pointer @intFromPtr/@ptrFromInt roundtrip" {
628 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
629
630 // This only succeeds on Thumb if we handle the Thumb bit correctly; if not, the `@ptrFromInt`
631 // will incorrectly trip an alignment safety check.
632
633 const nothing_ptr: *const fn () callconv(.c) void = &nothing;
634 const nothing_int: usize = @intFromPtr(nothing_ptr);
635 const nothing_ptr2: *const fn () callconv(.c) void = @ptrFromInt(nothing_int);
636
637 try std.testing.expectEqual(nothing_ptr, nothing_ptr2);
638}
639
640test "function pointer align mask" {
641 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
642
643 const int = if (builtin.cpu.arch.isArm() or builtin.cpu.arch.isMIPS()) 0x20202021 else 0x20202020;
644 const unaligned: *const fn () callconv(.c) void = @ptrFromInt(int);
645 const aligned: *align(16) const fn () callconv(.c) void = @alignCast(unaligned);
646 try expect(@intFromPtr(aligned) == int);
647}
648
649test "align expression is implicitly comptime" {
650 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
651
652 const S = struct {
653 fn alignment() usize {
654 return 4;
655 }
656
657 var global: [3]u8 align(alignment()) = @splat(0);
658 fn check() !void {
659 try std.testing.expect(@intFromPtr(&global) % alignment() == 0);
660 var local: [3]u8 align(alignment()) = @splat(0);
661 try std.testing.expect(@intFromPtr(&local) % alignment() == 0);
662 var de: [3]u8 align(alignment()), var structure: [3]u8 align(alignment()) = .{ @splat(0), @splat(0) };
663 try std.testing.expect(@intFromPtr(&de) % alignment() == 0);
664 try std.testing.expect(@intFromPtr(&structure) % alignment() == 0);
665 var @"struct": struct { field: [3]u8 align(alignment()) } = .{ .field = @splat(0) };
666 try std.testing.expect(@intFromPtr(&@"struct".field) % alignment() == 0);
667 var @"union": union { field: [3]u8 align(alignment()) } = .{ .field = @splat(0) };
668 try std.testing.expect(@intFromPtr(&@"union".field) % alignment() == 0);
669 const ptr: *align(alignment()) [3]u8 = &global;
670 try std.testing.expect(@intFromPtr(ptr) % alignment() == 0);
671 }
672 };
673 try S.check();
674}