2019-08-30 14:53:44 -04:00
|
|
|
const std = @import("std");
|
|
|
|
|
const expect = std.testing.expect;
|
2017-10-02 22:00:42 -04:00
|
|
|
const builtin = @import("builtin");
|
2021-04-29 15:18:40 -07:00
|
|
|
const native_arch = builtin.target.cpu.arch;
|
2017-08-29 08:35:51 -04:00
|
|
|
|
2022-01-17 20:30:44 +01:00
|
|
|
var foo: u8 align(4) = 100;
|
|
|
|
|
|
|
|
|
|
test "global variable alignment" {
|
2022-03-12 19:55:48 -07:00
|
|
|
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
|
|
|
|
|
|
2022-01-17 20:30:44 +01:00
|
|
|
comptime try expect(@typeInfo(@TypeOf(&foo)).Pointer.alignment == 4);
|
|
|
|
|
comptime try expect(@TypeOf(&foo) == *align(4) u8);
|
|
|
|
|
{
|
2022-03-09 17:33:01 -07:00
|
|
|
const slice = @as(*align(4) [1]u8, &foo)[0..];
|
2022-01-17 20:30:44 +01:00
|
|
|
comptime try expect(@TypeOf(slice) == *align(4) [1]u8);
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
var runtime_zero: usize = 0;
|
2022-03-09 17:33:01 -07:00
|
|
|
const slice = @as(*align(4) [1]u8, &foo)[runtime_zero..];
|
2022-01-17 20:30:44 +01:00
|
|
|
comptime try expect(@TypeOf(slice) == []align(4) u8);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
test "default alignment allows unspecified in type syntax" {
|
|
|
|
|
try expect(*u32 == *align(@alignOf(u32)) u32);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
test "implicitly decreasing pointer alignment" {
|
|
|
|
|
const a: u32 align(4) = 3;
|
|
|
|
|
const b: u32 align(8) = 4;
|
|
|
|
|
try expect(addUnaligned(&a, &b) == 7);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn addUnaligned(a: *align(1) const u32, b: *align(1) const u32) u32 {
|
|
|
|
|
return a.* + b.*;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
test "@alignCast pointers" {
|
|
|
|
|
var x: u32 align(4) = 1;
|
|
|
|
|
expectsOnly1(&x);
|
|
|
|
|
try expect(x == 2);
|
|
|
|
|
}
|
|
|
|
|
fn expectsOnly1(x: *align(1) u32) void {
|
|
|
|
|
expects4(@alignCast(4, x));
|
|
|
|
|
}
|
|
|
|
|
fn expects4(x: *align(4) u32) void {
|
|
|
|
|
x.* += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-03 23:44:32 -07:00
|
|
|
test "alignment of struct with pointer has same alignment as usize" {
|
2022-01-17 20:30:44 +01:00
|
|
|
try expect(@alignOf(struct {
|
|
|
|
|
a: i32,
|
|
|
|
|
b: *i32,
|
|
|
|
|
}) == @alignOf(usize));
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-03 23:44:32 -07:00
|
|
|
test "alignment and size of structs with 128-bit fields" {
|
|
|
|
|
const A = struct {
|
2022-01-17 20:30:44 +01:00
|
|
|
x: u128,
|
2022-05-03 23:44:32 -07:00
|
|
|
};
|
|
|
|
|
const B = extern struct {
|
2022-01-17 20:30:44 +01:00
|
|
|
x: u128,
|
|
|
|
|
y: u8,
|
2022-05-03 23:44:32 -07:00
|
|
|
};
|
|
|
|
|
const expected = switch (builtin.cpu.arch) {
|
|
|
|
|
.arm,
|
|
|
|
|
.armeb,
|
|
|
|
|
.thumb,
|
|
|
|
|
.thumbeb,
|
|
|
|
|
.x86_64,
|
|
|
|
|
.hexagon,
|
|
|
|
|
.mips,
|
|
|
|
|
.mipsel,
|
|
|
|
|
.mips64,
|
|
|
|
|
.mips64el,
|
|
|
|
|
.powerpc,
|
|
|
|
|
.powerpcle,
|
|
|
|
|
.powerpc64,
|
|
|
|
|
.powerpc64le,
|
|
|
|
|
.r600,
|
|
|
|
|
.amdgcn,
|
|
|
|
|
.riscv32,
|
|
|
|
|
.riscv64,
|
|
|
|
|
.sparc,
|
|
|
|
|
.sparcv9,
|
|
|
|
|
.sparcel,
|
|
|
|
|
.s390x,
|
|
|
|
|
.lanai,
|
|
|
|
|
.wasm32,
|
|
|
|
|
.wasm64,
|
|
|
|
|
=> .{
|
|
|
|
|
.a_align = 8,
|
|
|
|
|
.a_size = 16,
|
|
|
|
|
|
|
|
|
|
.b_align = 8,
|
|
|
|
|
.b_size = 24,
|
|
|
|
|
|
|
|
|
|
.u128_align = 8,
|
|
|
|
|
.u128_size = 16,
|
|
|
|
|
.u129_align = 8,
|
|
|
|
|
.u129_size = 24,
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
.i386 => switch (builtin.os.tag) {
|
|
|
|
|
.windows => .{
|
|
|
|
|
.a_align = 8,
|
|
|
|
|
.a_size = 16,
|
|
|
|
|
|
|
|
|
|
.b_align = 8,
|
|
|
|
|
.b_size = 24,
|
|
|
|
|
|
|
|
|
|
.u128_align = 8,
|
|
|
|
|
.u128_size = 16,
|
|
|
|
|
.u129_align = 8,
|
|
|
|
|
.u129_size = 24,
|
|
|
|
|
},
|
|
|
|
|
else => .{
|
|
|
|
|
.a_align = 4,
|
|
|
|
|
.a_size = 16,
|
|
|
|
|
|
|
|
|
|
.b_align = 4,
|
|
|
|
|
.b_size = 20,
|
|
|
|
|
|
|
|
|
|
.u128_align = 4,
|
|
|
|
|
.u128_size = 16,
|
|
|
|
|
.u129_align = 4,
|
|
|
|
|
.u129_size = 20,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
.aarch64,
|
|
|
|
|
.aarch64_be,
|
|
|
|
|
.aarch64_32,
|
|
|
|
|
.bpfel,
|
|
|
|
|
.bpfeb,
|
|
|
|
|
.nvptx,
|
|
|
|
|
.nvptx64,
|
|
|
|
|
=> .{
|
|
|
|
|
.a_align = 16,
|
|
|
|
|
.a_size = 16,
|
|
|
|
|
|
|
|
|
|
.b_align = 16,
|
|
|
|
|
.b_size = 32,
|
|
|
|
|
|
|
|
|
|
.u128_align = 16,
|
|
|
|
|
.u128_size = 16,
|
|
|
|
|
.u129_align = 16,
|
|
|
|
|
.u129_size = 32,
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
else => return error.SkipZigTest,
|
|
|
|
|
};
|
2022-01-17 20:30:44 +01:00
|
|
|
comptime {
|
2022-05-03 23:44:32 -07:00
|
|
|
std.debug.assert(@alignOf(A) == expected.a_align);
|
|
|
|
|
std.debug.assert(@sizeOf(A) == expected.a_size);
|
|
|
|
|
|
|
|
|
|
std.debug.assert(@alignOf(B) == expected.b_align);
|
|
|
|
|
std.debug.assert(@sizeOf(B) == expected.b_size);
|
|
|
|
|
|
|
|
|
|
std.debug.assert(@alignOf(u128) == expected.u128_align);
|
|
|
|
|
std.debug.assert(@sizeOf(u128) == expected.u128_size);
|
|
|
|
|
|
|
|
|
|
std.debug.assert(@alignOf(u129) == expected.u129_align);
|
|
|
|
|
std.debug.assert(@sizeOf(u129) == expected.u129_size);
|
2022-01-17 20:30:44 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
test "@ptrCast preserves alignment of bigger source" {
|
|
|
|
|
var x: u32 align(16) = 1234;
|
|
|
|
|
const ptr = @ptrCast(*u8, &x);
|
|
|
|
|
try expect(@TypeOf(ptr) == *align(16) u8);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
test "alignstack" {
|
|
|
|
|
try expect(fnWithAlignedStack() == 1234);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn fnWithAlignedStack() i32 {
|
|
|
|
|
@setAlignStack(256);
|
|
|
|
|
return 1234;
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-29 15:19:15 -04:00
|
|
|
test "implicitly decreasing slice alignment" {
|
Sema: fix pointer type hash and equality functions
Several issues with pointer types are fixed:
Prior to this commit, Zig would not canonicalize a pointer type with
an explicit alignment to alignment=0 if it matched the pointee ABI
alignment. In order to fix this, `Type.ptr` now takes a Target
parameter. I also moved the host_size canonicalization to `Type.ptr`
since target is now available. Similarly, is_allowzero in the case of
C pointers is now treated as a canonicalization done by the function
rather than a precondition.
in-memory coercion for pointers now properly checks ABI alignment
of pointee types instead of incorrectly treating the 0 value as an
alignment.
Type equality is completely reworked based on the tag() rather than the
zigTypeTag(). It's still semantically based on zigTypeTag() but that
knowledge is implied rather than dictating the control flow of the
logic. Importantly, this fixes cases for opaques, structs, tuples,
enums, and unions, where type equality was incorrectly returning based
on whether the tag() values were equal.
Additionally, pointer type equality now takes into account alignment.
Because we canonicalize non-zero alignment which equals pointee type ABI
alignment to alignment=0, this now can be a simple integer comparison.
Type hashing is implemented for pointers and floats. Array types now
additionally hash their sentinels.
This regressed some behavior tests that were passing but only because
of bugs regarding type equality.
The C backend has a noticeable problem with lowering differently-aligned
pointers (particularly slices) as the same type, causing C compilation
errors due to duplicate declarations.
2022-02-28 19:22:16 -07:00
|
|
|
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
|
2022-02-14 22:33:01 +01:00
|
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
2022-01-17 20:30:44 +01:00
|
|
|
|
2017-08-30 04:54:33 -04:00
|
|
|
const a: u32 align(4) = 3;
|
|
|
|
|
const b: u32 align(8) = 4;
|
2021-05-04 21:23:22 +03:00
|
|
|
try expect(addUnalignedSlice(@as(*const [1]u32, &a)[0..], @as(*const [1]u32, &b)[0..]) == 7);
|
2017-08-29 15:19:15 -04:00
|
|
|
}
|
2018-04-30 20:35:54 -04:00
|
|
|
fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) u32 {
|
|
|
|
|
return a[0] + b[0];
|
|
|
|
|
}
|
2021-10-22 17:50:36 -07:00
|
|
|
|
|
|
|
|
test "specifying alignment allows pointer cast" {
|
Sema: fix pointer type hash and equality functions
Several issues with pointer types are fixed:
Prior to this commit, Zig would not canonicalize a pointer type with
an explicit alignment to alignment=0 if it matched the pointee ABI
alignment. In order to fix this, `Type.ptr` now takes a Target
parameter. I also moved the host_size canonicalization to `Type.ptr`
since target is now available. Similarly, is_allowzero in the case of
C pointers is now treated as a canonicalization done by the function
rather than a precondition.
in-memory coercion for pointers now properly checks ABI alignment
of pointee types instead of incorrectly treating the 0 value as an
alignment.
Type equality is completely reworked based on the tag() rather than the
zigTypeTag(). It's still semantically based on zigTypeTag() but that
knowledge is implied rather than dictating the control flow of the
logic. Importantly, this fixes cases for opaques, structs, tuples,
enums, and unions, where type equality was incorrectly returning based
on whether the tag() values were equal.
Additionally, pointer type equality now takes into account alignment.
Because we canonicalize non-zero alignment which equals pointee type ABI
alignment to alignment=0, this now can be a simple integer comparison.
Type hashing is implemented for pointers and floats. Array types now
additionally hash their sentinels.
This regressed some behavior tests that were passing but only because
of bugs regarding type equality.
The C backend has a noticeable problem with lowering differently-aligned
pointers (particularly slices) as the same type, causing C compilation
errors due to duplicate declarations.
2022-02-28 19:22:16 -07:00
|
|
|
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
|
2022-02-14 22:33:01 +01:00
|
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
2022-01-17 20:30:44 +01:00
|
|
|
|
2021-10-22 17:50:36 -07:00
|
|
|
try testBytesAlign(0x33);
|
|
|
|
|
}
|
|
|
|
|
fn testBytesAlign(b: u8) !void {
|
|
|
|
|
var bytes align(4) = [_]u8{ b, b, b, b };
|
|
|
|
|
const ptr = @ptrCast(*u32, &bytes[0]);
|
|
|
|
|
try expect(ptr.* == 0x33333333);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
test "@alignCast slices" {
|
Sema: fix pointer type hash and equality functions
Several issues with pointer types are fixed:
Prior to this commit, Zig would not canonicalize a pointer type with
an explicit alignment to alignment=0 if it matched the pointee ABI
alignment. In order to fix this, `Type.ptr` now takes a Target
parameter. I also moved the host_size canonicalization to `Type.ptr`
since target is now available. Similarly, is_allowzero in the case of
C pointers is now treated as a canonicalization done by the function
rather than a precondition.
in-memory coercion for pointers now properly checks ABI alignment
of pointee types instead of incorrectly treating the 0 value as an
alignment.
Type equality is completely reworked based on the tag() rather than the
zigTypeTag(). It's still semantically based on zigTypeTag() but that
knowledge is implied rather than dictating the control flow of the
logic. Importantly, this fixes cases for opaques, structs, tuples,
enums, and unions, where type equality was incorrectly returning based
on whether the tag() values were equal.
Additionally, pointer type equality now takes into account alignment.
Because we canonicalize non-zero alignment which equals pointee type ABI
alignment to alignment=0, this now can be a simple integer comparison.
Type hashing is implemented for pointers and floats. Array types now
additionally hash their sentinels.
This regressed some behavior tests that were passing but only because
of bugs regarding type equality.
The C backend has a noticeable problem with lowering differently-aligned
pointers (particularly slices) as the same type, causing C compilation
errors due to duplicate declarations.
2022-02-28 19:22:16 -07:00
|
|
|
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
|
2022-02-14 22:33:01 +01:00
|
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
2022-02-28 19:54:13 +01:00
|
|
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
2022-01-17 20:30:44 +01:00
|
|
|
|
2021-10-22 17:50:36 -07:00
|
|
|
var array align(4) = [_]u32{ 1, 1 };
|
|
|
|
|
const slice = array[0..];
|
|
|
|
|
sliceExpectsOnly1(slice);
|
|
|
|
|
try expect(slice[0] == 2);
|
|
|
|
|
}
|
|
|
|
|
fn sliceExpectsOnly1(slice: []align(1) u32) void {
|
|
|
|
|
sliceExpects4(@alignCast(4, slice));
|
|
|
|
|
}
|
|
|
|
|
fn sliceExpects4(slice: []align(4) u32) void {
|
|
|
|
|
slice[0] += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
test "return error union with 128-bit integer" {
|
2022-02-14 22:33:01 +01:00
|
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
2022-02-28 19:54:13 +01:00
|
|
|
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
|
|
|
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
2022-03-06 16:52:10 +01:00
|
|
|
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
|
2022-01-17 20:30:44 +01:00
|
|
|
|
2021-10-22 17:50:36 -07:00
|
|
|
try expect(3 == try give());
|
|
|
|
|
}
|
|
|
|
|
fn give() anyerror!u128 {
|
|
|
|
|
return 3;
|
|
|
|
|
}
|
2022-01-20 22:46:15 +01:00
|
|
|
|
|
|
|
|
test "page aligned array on stack" {
|
2022-02-14 22:33:01 +01:00
|
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
2022-01-24 22:04:28 -07:00
|
|
|
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
|
|
|
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
2022-01-20 22:46:15 +01:00
|
|
|
|
|
|
|
|
// Large alignment value to make it hard to accidentally pass.
|
|
|
|
|
var array align(0x1000) = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };
|
|
|
|
|
var number1: u8 align(16) = 42;
|
|
|
|
|
var number2: u8 align(16) = 43;
|
|
|
|
|
|
|
|
|
|
try expect(@ptrToInt(&array[0]) & 0xFFF == 0);
|
|
|
|
|
try expect(array[3] == 4);
|
|
|
|
|
|
|
|
|
|
try expect(@truncate(u4, @ptrToInt(&number1)) == 0);
|
|
|
|
|
try expect(@truncate(u4, @ptrToInt(&number2)) == 0);
|
|
|
|
|
try expect(number1 == 42);
|
|
|
|
|
try expect(number2 == 43);
|
|
|
|
|
}
|
stage2: type system treats fn ptr and body separately
This commit updates stage2 to enforce the property that the syntax
`fn()void` is a function *body* not a *pointer*. To get a pointer, the
syntax `*const fn()void` is required.
ZIR puts function alignment into the func instruction rather than the
decl because this way it makes it into function types. LLVM backend
respects function alignments.
Struct and Union have methods `fieldSrcLoc` to help look up source
locations of their fields. These trigger full loading, tokenization, and
parsing of source files, so should only be called once it is confirmed
that an error message needs to be printed.
There are some nice new error hints for explaining why a type is
required to be comptime, particularly for structs that contain function
body types.
`Type.requiresComptime` is now moved into Sema because it can fail and
might need to trigger field type resolution. Comptime pointer loading
takes into account types that do not have a well-defined memory layout
and does not try to compute a byte offset for them.
`fn()void` syntax no longer secretly makes a pointer. You get a function
body type, which requires comptime. However a pointer to a function body
can be runtime known (obviously).
Compile errors that report "expected pointer, found ..." are factored
out into convenience functions `checkPtrOperand` and `checkPtrType` and
have a note about function pointers.
Implemented `Value.hash` for functions, enum literals, and undefined values.
stage1 is not updated to this (yet?), so some workarounds and disabled
tests are needed to keep everything working. Should we update stage1 to
these new type semantics? Yes probably because I don't want to add too
much conditional compilation logic in the std lib for the different
backends.
2022-01-21 00:49:58 -07:00
|
|
|
|
|
|
|
|
fn derp() align(@sizeOf(usize) * 2) i32 {
|
|
|
|
|
return 1234;
|
|
|
|
|
}
|
|
|
|
|
fn noop1() align(1) void {}
|
|
|
|
|
fn noop4() align(4) void {}
|
|
|
|
|
|
|
|
|
|
test "function alignment" {
|
2022-02-14 22:33:01 +01:00
|
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
2022-01-24 22:04:28 -07:00
|
|
|
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
|
stage2: type system treats fn ptr and body separately
This commit updates stage2 to enforce the property that the syntax
`fn()void` is a function *body* not a *pointer*. To get a pointer, the
syntax `*const fn()void` is required.
ZIR puts function alignment into the func instruction rather than the
decl because this way it makes it into function types. LLVM backend
respects function alignments.
Struct and Union have methods `fieldSrcLoc` to help look up source
locations of their fields. These trigger full loading, tokenization, and
parsing of source files, so should only be called once it is confirmed
that an error message needs to be printed.
There are some nice new error hints for explaining why a type is
required to be comptime, particularly for structs that contain function
body types.
`Type.requiresComptime` is now moved into Sema because it can fail and
might need to trigger field type resolution. Comptime pointer loading
takes into account types that do not have a well-defined memory layout
and does not try to compute a byte offset for them.
`fn()void` syntax no longer secretly makes a pointer. You get a function
body type, which requires comptime. However a pointer to a function body
can be runtime known (obviously).
Compile errors that report "expected pointer, found ..." are factored
out into convenience functions `checkPtrOperand` and `checkPtrType` and
have a note about function pointers.
Implemented `Value.hash` for functions, enum literals, and undefined values.
stage1 is not updated to this (yet?), so some workarounds and disabled
tests are needed to keep everything working. Should we update stage1 to
these new type semantics? Yes probably because I don't want to add too
much conditional compilation logic in the std lib for the different
backends.
2022-01-21 00:49:58 -07:00
|
|
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
|
|
|
|
|
2022-01-24 22:04:28 -07:00
|
|
|
// function alignment is a compile error on wasm32/wasm64
|
|
|
|
|
if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;
|
|
|
|
|
|
stage2: type system treats fn ptr and body separately
This commit updates stage2 to enforce the property that the syntax
`fn()void` is a function *body* not a *pointer*. To get a pointer, the
syntax `*const fn()void` is required.
ZIR puts function alignment into the func instruction rather than the
decl because this way it makes it into function types. LLVM backend
respects function alignments.
Struct and Union have methods `fieldSrcLoc` to help look up source
locations of their fields. These trigger full loading, tokenization, and
parsing of source files, so should only be called once it is confirmed
that an error message needs to be printed.
There are some nice new error hints for explaining why a type is
required to be comptime, particularly for structs that contain function
body types.
`Type.requiresComptime` is now moved into Sema because it can fail and
might need to trigger field type resolution. Comptime pointer loading
takes into account types that do not have a well-defined memory layout
and does not try to compute a byte offset for them.
`fn()void` syntax no longer secretly makes a pointer. You get a function
body type, which requires comptime. However a pointer to a function body
can be runtime known (obviously).
Compile errors that report "expected pointer, found ..." are factored
out into convenience functions `checkPtrOperand` and `checkPtrType` and
have a note about function pointers.
Implemented `Value.hash` for functions, enum literals, and undefined values.
stage1 is not updated to this (yet?), so some workarounds and disabled
tests are needed to keep everything working. Should we update stage1 to
these new type semantics? Yes probably because I don't want to add too
much conditional compilation logic in the std lib for the different
backends.
2022-01-21 00:49:58 -07:00
|
|
|
try expect(derp() == 1234);
|
|
|
|
|
try expect(@TypeOf(noop1) == fn () align(1) void);
|
|
|
|
|
try expect(@TypeOf(noop4) == fn () align(4) void);
|
|
|
|
|
noop1();
|
|
|
|
|
noop4();
|
|
|
|
|
}
|
2022-01-25 23:29:02 -07:00
|
|
|
|
|
|
|
|
test "implicitly decreasing fn alignment" {
|
|
|
|
|
if (builtin.zig_backend == .stage1) return error.SkipZigTest;
|
|
|
|
|
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
|
2022-03-09 18:47:42 -07:00
|
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
2022-01-25 23:29:02 -07:00
|
|
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
|
|
|
|
|
|
|
|
|
// function alignment is a compile error on wasm32/wasm64
|
|
|
|
|
if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;
|
|
|
|
|
|
|
|
|
|
try testImplicitlyDecreaseFnAlign(alignedSmall, 1234);
|
|
|
|
|
try testImplicitlyDecreaseFnAlign(alignedBig, 5678);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO make it a compile error to put align on the fn proto instead of on the ptr
|
|
|
|
|
fn testImplicitlyDecreaseFnAlign(ptr: *align(1) const fn () i32, answer: i32) !void {
|
|
|
|
|
try expect(ptr() == answer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn alignedSmall() align(8) i32 {
|
|
|
|
|
return 1234;
|
|
|
|
|
}
|
|
|
|
|
fn alignedBig() align(16) i32 {
|
|
|
|
|
return 5678;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
test "@alignCast functions" {
|
2022-02-14 22:33:01 +01:00
|
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
2022-01-25 23:29:02 -07:00
|
|
|
if (builtin.zig_backend == .stage1) return error.SkipZigTest;
|
|
|
|
|
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
|
|
|
|
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
|
|
|
|
|
|
|
|
|
// function alignment is a compile error on wasm32/wasm64
|
|
|
|
|
if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;
|
|
|
|
|
if (native_arch == .thumb) return error.SkipZigTest;
|
|
|
|
|
|
|
|
|
|
try expect(fnExpectsOnly1(simple4) == 0x19);
|
|
|
|
|
}
|
|
|
|
|
fn fnExpectsOnly1(ptr: *const fn () align(1) i32) i32 {
|
|
|
|
|
return fnExpects4(@alignCast(4, ptr));
|
|
|
|
|
}
|
|
|
|
|
fn fnExpects4(ptr: *align(4) const fn () i32) i32 {
|
|
|
|
|
return ptr();
|
|
|
|
|
}
|
|
|
|
|
fn simple4() align(4) i32 {
|
|
|
|
|
return 0x19;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
test "generic function with align param" {
|
2022-02-14 22:33:01 +01:00
|
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
2022-01-25 23:29:02 -07:00
|
|
|
if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
|
|
|
|
|
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
|
|
|
|
|
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
|
|
|
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
|
|
|
|
|
|
|
|
|
// function alignment is a compile error on wasm32/wasm64
|
|
|
|
|
if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;
|
|
|
|
|
if (native_arch == .thumb) return error.SkipZigTest;
|
|
|
|
|
|
|
|
|
|
try expect(whyWouldYouEverDoThis(1) == 0x1);
|
|
|
|
|
try expect(whyWouldYouEverDoThis(4) == 0x1);
|
|
|
|
|
try expect(whyWouldYouEverDoThis(8) == 0x1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) u8 {
|
|
|
|
|
_ = align_bytes;
|
|
|
|
|
return 0x1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
test "runtime known array index has best alignment possible" {
|
Sema: fix pointer type hash and equality functions
Several issues with pointer types are fixed:
Prior to this commit, Zig would not canonicalize a pointer type with
an explicit alignment to alignment=0 if it matched the pointee ABI
alignment. In order to fix this, `Type.ptr` now takes a Target
parameter. I also moved the host_size canonicalization to `Type.ptr`
since target is now available. Similarly, is_allowzero in the case of
C pointers is now treated as a canonicalization done by the function
rather than a precondition.
in-memory coercion for pointers now properly checks ABI alignment
of pointee types instead of incorrectly treating the 0 value as an
alignment.
Type equality is completely reworked based on the tag() rather than the
zigTypeTag(). It's still semantically based on zigTypeTag() but that
knowledge is implied rather than dictating the control flow of the
logic. Importantly, this fixes cases for opaques, structs, tuples,
enums, and unions, where type equality was incorrectly returning based
on whether the tag() values were equal.
Additionally, pointer type equality now takes into account alignment.
Because we canonicalize non-zero alignment which equals pointee type ABI
alignment to alignment=0, this now can be a simple integer comparison.
Type hashing is implemented for pointers and floats. Array types now
additionally hash their sentinels.
This regressed some behavior tests that were passing but only because
of bugs regarding type equality.
The C backend has a noticeable problem with lowering differently-aligned
pointers (particularly slices) as the same type, causing C compilation
errors due to duplicate declarations.
2022-02-28 19:22:16 -07:00
|
|
|
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
|
|
|
|
|
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
|
2022-01-25 23:29:02 -07:00
|
|
|
|
|
|
|
|
// take full advantage of over-alignment
|
|
|
|
|
var array align(4) = [_]u8{ 1, 2, 3, 4 };
|
|
|
|
|
try expect(@TypeOf(&array[0]) == *align(4) u8);
|
|
|
|
|
try expect(@TypeOf(&array[1]) == *u8);
|
|
|
|
|
try expect(@TypeOf(&array[2]) == *align(2) u8);
|
|
|
|
|
try expect(@TypeOf(&array[3]) == *u8);
|
|
|
|
|
|
|
|
|
|
// because align is too small but we still figure out to use 2
|
|
|
|
|
var bigger align(2) = [_]u64{ 1, 2, 3, 4 };
|
|
|
|
|
try expect(@TypeOf(&bigger[0]) == *align(2) u64);
|
|
|
|
|
try expect(@TypeOf(&bigger[1]) == *align(2) u64);
|
|
|
|
|
try expect(@TypeOf(&bigger[2]) == *align(2) u64);
|
|
|
|
|
try expect(@TypeOf(&bigger[3]) == *align(2) u64);
|
|
|
|
|
|
|
|
|
|
// because pointer is align 2 and u32 align % 2 == 0 we can assume align 2
|
|
|
|
|
var smaller align(2) = [_]u32{ 1, 2, 3, 4 };
|
|
|
|
|
var runtime_zero: usize = 0;
|
|
|
|
|
comptime try expect(@TypeOf(smaller[runtime_zero..]) == []align(2) u32);
|
|
|
|
|
comptime try expect(@TypeOf(smaller[runtime_zero..].ptr) == [*]align(2) u32);
|
|
|
|
|
try testIndex(smaller[runtime_zero..].ptr, 0, *align(2) u32);
|
|
|
|
|
try testIndex(smaller[runtime_zero..].ptr, 1, *align(2) u32);
|
|
|
|
|
try testIndex(smaller[runtime_zero..].ptr, 2, *align(2) u32);
|
|
|
|
|
try testIndex(smaller[runtime_zero..].ptr, 3, *align(2) u32);
|
|
|
|
|
|
|
|
|
|
// has to use ABI alignment because index known at runtime only
|
|
|
|
|
try testIndex2(array[runtime_zero..].ptr, 0, *u8);
|
|
|
|
|
try testIndex2(array[runtime_zero..].ptr, 1, *u8);
|
|
|
|
|
try testIndex2(array[runtime_zero..].ptr, 2, *u8);
|
|
|
|
|
try testIndex2(array[runtime_zero..].ptr, 3, *u8);
|
|
|
|
|
}
|
|
|
|
|
fn testIndex(smaller: [*]align(2) u32, index: usize, comptime T: type) !void {
|
|
|
|
|
comptime try expect(@TypeOf(&smaller[index]) == T);
|
|
|
|
|
}
|
|
|
|
|
fn testIndex2(ptr: [*]align(4) u8, index: usize, comptime T: type) !void {
|
|
|
|
|
comptime try expect(@TypeOf(&ptr[index]) == T);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
test "alignment of function with c calling convention" {
|
|
|
|
|
if (builtin.zig_backend == .stage1) return error.SkipZigTest;
|
|
|
|
|
|
|
|
|
|
var runtime_nothing = ¬hing;
|
|
|
|
|
const casted1 = @ptrCast(*const u8, runtime_nothing);
|
|
|
|
|
const casted2 = @ptrCast(*const fn () callconv(.C) void, casted1);
|
|
|
|
|
casted2();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn nothing() callconv(.C) void {}
|
|
|
|
|
|
|
|
|
|
const DefaultAligned = struct {
|
|
|
|
|
nevermind: u32,
|
|
|
|
|
badguy: i128,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
test "read 128-bit field from default aligned struct in stack memory" {
|
2022-02-14 22:33:01 +01:00
|
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
2022-01-25 23:29:02 -07:00
|
|
|
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
|
|
|
|
|
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
|
|
|
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
|
|
|
|
|
|
|
|
|
var default_aligned = DefaultAligned{
|
|
|
|
|
.nevermind = 1,
|
|
|
|
|
.badguy = 12,
|
|
|
|
|
};
|
|
|
|
|
try expect(12 == default_aligned.badguy);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var default_aligned_global = DefaultAligned{
|
|
|
|
|
.nevermind = 1,
|
|
|
|
|
.badguy = 12,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
test "read 128-bit field from default aligned struct in global memory" {
|
2022-02-14 22:33:01 +01:00
|
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
2022-01-25 23:29:02 -07:00
|
|
|
if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
|
|
|
|
|
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
|
|
|
|
|
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
|
|
|
|
|
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
|
|
|
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
|
|
|
|
|
|
|
|
|
try expect(12 == default_aligned_global.badguy);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
test "struct field explicit alignment" {
|
|
|
|
|
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
|
|
|
|
|
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
|
|
|
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
2022-03-09 18:47:42 -07:00
|
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
2022-01-25 23:29:02 -07:00
|
|
|
|
|
|
|
|
const S = struct {
|
|
|
|
|
const Node = struct {
|
|
|
|
|
next: *Node,
|
|
|
|
|
massive_byte: u8 align(64),
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var node: S.Node = undefined;
|
|
|
|
|
node.massive_byte = 100;
|
|
|
|
|
try expect(node.massive_byte == 100);
|
|
|
|
|
comptime try expect(@TypeOf(&node.massive_byte) == *align(64) u8);
|
|
|
|
|
try expect(@ptrToInt(&node.massive_byte) % 64 == 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
test "align(@alignOf(T)) T does not force resolution of T" {
|
2022-02-14 22:33:01 +01:00
|
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
2022-01-25 23:29:02 -07:00
|
|
|
if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
|
|
|
|
|
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
|
|
|
|
|
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
|
|
|
|
|
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
|
|
|
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
|
|
|
|
|
|
|
|
|
const S = struct {
|
|
|
|
|
const A = struct {
|
|
|
|
|
a: *align(@alignOf(A)) A,
|
|
|
|
|
};
|
|
|
|
|
fn doTheTest() void {
|
|
|
|
|
suspend {
|
|
|
|
|
resume @frame();
|
|
|
|
|
}
|
|
|
|
|
_ = bar(@Frame(doTheTest));
|
|
|
|
|
}
|
|
|
|
|
fn bar(comptime T: type) *align(@alignOf(T)) T {
|
|
|
|
|
ok = true;
|
|
|
|
|
return undefined;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var ok = false;
|
|
|
|
|
};
|
|
|
|
|
_ = async S.doTheTest();
|
|
|
|
|
try expect(S.ok);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
test "align(N) on functions" {
|
|
|
|
|
if (builtin.zig_backend == .stage1) return error.SkipZigTest;
|
2022-03-09 18:47:42 -07:00
|
|
|
|
|
|
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
2022-01-25 23:29:02 -07:00
|
|
|
if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
|
|
|
|
|
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
|
|
|
|
|
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
|
|
|
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
|
|
|
|
|
|
|
|
|
// function alignment is a compile error on wasm32/wasm64
|
|
|
|
|
if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;
|
|
|
|
|
if (native_arch == .thumb) return error.SkipZigTest;
|
|
|
|
|
|
|
|
|
|
try expect((@ptrToInt(&overaligned_fn) & (0x1000 - 1)) == 0);
|
|
|
|
|
}
|
|
|
|
|
fn overaligned_fn() align(0x1000) i32 {
|
|
|
|
|
return 42;
|
|
|
|
|
}
|
2022-03-19 11:59:41 -07:00
|
|
|
|
|
|
|
|
test "comptime alloc alignment" {
|
|
|
|
|
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
|
|
|
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
|
|
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
|
|
|
|
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
|
|
|
|
|
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
|
|
|
|
|
|
|
|
|
comptime var bytes1 = [_]u8{0};
|
|
|
|
|
_ = bytes1;
|
|
|
|
|
|
|
|
|
|
comptime var bytes2 align(256) = [_]u8{0};
|
|
|
|
|
var bytes2_addr = @ptrToInt(&bytes2);
|
|
|
|
|
try std.testing.expect(bytes2_addr & 0xff == 0);
|
|
|
|
|
}
|