mirror of
https://github.com/ziglang/zig.git
synced 2025-12-25 15:43:06 +00:00
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.
182 lines
4.7 KiB
Zig
182 lines
4.7 KiB
Zig
const builtin = @import("builtin");
|
|
const std = @import("std");
|
|
const expect = std.testing.expect;
|
|
const expectEqualSlices = std.testing.expectEqualSlices;
|
|
const expectEqual = std.testing.expectEqual;
|
|
const mem = std.mem;
|
|
|
|
// comptime array passed as slice argument
|
|
comptime {
|
|
const S = struct {
|
|
fn indexOfScalarPos(comptime T: type, slice: []const T, start_index: usize, value: T) ?usize {
|
|
var i: usize = start_index;
|
|
while (i < slice.len) : (i += 1) {
|
|
if (slice[i] == value) return i;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
fn indexOfScalar(comptime T: type, slice: []const T, value: T) ?usize {
|
|
return indexOfScalarPos(T, slice, 0, value);
|
|
}
|
|
};
|
|
const unsigned = [_]type{ c_uint, c_ulong, c_ulonglong };
|
|
const list: []const type = &unsigned;
|
|
var pos = S.indexOfScalar(type, list, c_ulong).?;
|
|
if (pos != 1) @compileError("bad pos");
|
|
}
|
|
|
|
test "slicing" {
|
|
var array: [20]i32 = undefined;
|
|
|
|
array[5] = 1234;
|
|
|
|
var slice = array[5..10];
|
|
|
|
if (slice.len != 5) unreachable;
|
|
|
|
const ptr = &slice[0];
|
|
if (ptr.* != 1234) unreachable;
|
|
|
|
var slice_rest = array[10..];
|
|
if (slice_rest.len != 10) unreachable;
|
|
}
|
|
|
|
test "const slice" {
|
|
comptime {
|
|
const a = "1234567890";
|
|
try expect(a.len == 10);
|
|
const b = a[1..2];
|
|
try expect(b.len == 1);
|
|
try expect(b[0] == '2');
|
|
}
|
|
}
|
|
|
|
test "comptime slice of undefined pointer of length 0" {
|
|
const slice1 = @as([*]i32, undefined)[0..0];
|
|
try expect(slice1.len == 0);
|
|
const slice2 = @as([*]i32, undefined)[100..100];
|
|
try expect(slice2.len == 0);
|
|
}
|
|
|
|
test "implicitly cast array of size 0 to slice" {
|
|
var msg = [_]u8{};
|
|
try assertLenIsZero(&msg);
|
|
}
|
|
|
|
fn assertLenIsZero(msg: []const u8) !void {
|
|
try expect(msg.len == 0);
|
|
}
|
|
|
|
test "access len index of sentinel-terminated slice" {
|
|
const S = struct {
|
|
fn doTheTest() !void {
|
|
var slice: [:0]const u8 = "hello";
|
|
|
|
try expect(slice.len == 5);
|
|
try expect(slice[5] == 0);
|
|
}
|
|
};
|
|
try S.doTheTest();
|
|
comptime try S.doTheTest();
|
|
}
|
|
|
|
test "comptime slice of slice preserves comptime var" {
|
|
comptime {
|
|
var buff: [10]u8 = undefined;
|
|
buff[0..][0..][0] = 1;
|
|
try expect(buff[0..][0..][0] == 1);
|
|
}
|
|
}
|
|
|
|
test "slice of type" {
|
|
comptime {
|
|
var types_array = [_]type{ i32, f64, type };
|
|
for (types_array) |T, i| {
|
|
switch (i) {
|
|
0 => try expect(T == i32),
|
|
1 => try expect(T == f64),
|
|
2 => try expect(T == type),
|
|
else => unreachable,
|
|
}
|
|
}
|
|
for (types_array[0..]) |T, i| {
|
|
switch (i) {
|
|
0 => try expect(T == i32),
|
|
1 => try expect(T == f64),
|
|
2 => try expect(T == type),
|
|
else => unreachable,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
test "generic malloc free" {
|
|
const a = memAlloc(u8, 10) catch unreachable;
|
|
memFree(u8, a);
|
|
}
|
|
var some_mem: [100]u8 = undefined;
|
|
fn memAlloc(comptime T: type, n: usize) anyerror![]T {
|
|
return @ptrCast([*]T, &some_mem[0])[0..n];
|
|
}
|
|
fn memFree(comptime T: type, memory: []T) void {
|
|
_ = memory;
|
|
}
|
|
|
|
test "slice of hardcoded address to pointer" {
|
|
const S = struct {
|
|
fn doTheTest() !void {
|
|
const pointer = @intToPtr([*]u8, 0x04)[0..2];
|
|
comptime try expect(@TypeOf(pointer) == *[2]u8);
|
|
const slice: []const u8 = pointer;
|
|
try expect(@ptrToInt(slice.ptr) == 4);
|
|
try expect(slice.len == 2);
|
|
}
|
|
};
|
|
|
|
try S.doTheTest();
|
|
}
|
|
|
|
test "comptime slice of pointer preserves comptime var" {
|
|
comptime {
|
|
var buff: [10]u8 = undefined;
|
|
var a = @ptrCast([*]u8, &buff);
|
|
a[0..1][0] = 1;
|
|
try expect(buff[0..][0..][0] == 1);
|
|
}
|
|
}
|
|
|
|
test "comptime pointer cast array and then slice" {
|
|
const array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };
|
|
|
|
const ptrA: [*]const u8 = @ptrCast([*]const u8, &array);
|
|
const sliceA: []const u8 = ptrA[0..2];
|
|
|
|
const ptrB: [*]const u8 = &array;
|
|
const sliceB: []const u8 = ptrB[0..2];
|
|
|
|
try expect(sliceA[1] == 2);
|
|
try expect(sliceB[1] == 2);
|
|
}
|
|
|
|
test "slicing zero length array" {
|
|
const s1 = ""[0..];
|
|
const s2 = ([_]u32{})[0..];
|
|
try expect(s1.len == 0);
|
|
try expect(s2.len == 0);
|
|
try expect(mem.eql(u8, s1, ""));
|
|
try expect(mem.eql(u32, s2, &[_]u32{}));
|
|
}
|
|
|
|
const x = @intToPtr([*]i32, 0x1000)[0..0x500];
|
|
const y = x[0x100..];
|
|
test "compile time slice of pointer to hard coded address" {
|
|
if (builtin.zig_backend == .stage1) return error.SkipZigTest;
|
|
|
|
try expect(@ptrToInt(x) == 0x1000);
|
|
try expect(x.len == 0x500);
|
|
|
|
try expect(@ptrToInt(y) == 0x1400);
|
|
try expect(y.len == 0x400);
|
|
}
|