Merge pull request #4752 from ziglang/slice-array
slicing with comptime start and end indexes results in pointer-to-arraymaster
commit
dc04e97098
|
@ -2093,8 +2093,9 @@ var foo: u8 align(4) = 100;
|
|||
test "global variable alignment" {
|
||||
assert(@TypeOf(&foo).alignment == 4);
|
||||
assert(@TypeOf(&foo) == *align(4) u8);
|
||||
const slice = @as(*[1]u8, &foo)[0..];
|
||||
assert(@TypeOf(slice) == []align(4) u8);
|
||||
const as_pointer_to_array: *[1]u8 = &foo;
|
||||
const as_slice: []u8 = as_pointer_to_array;
|
||||
assert(@TypeOf(as_slice) == []align(4) u8);
|
||||
}
|
||||
|
||||
fn derp() align(@sizeOf(usize) * 2) i32 { return 1234; }
|
||||
|
@ -2187,7 +2188,8 @@ test "basic slices" {
|
|||
// a slice is that the array's length is part of the type and known at
|
||||
// compile-time, whereas the slice's length is known at runtime.
|
||||
// Both can be accessed with the `len` field.
|
||||
const slice = array[0..array.len];
|
||||
var known_at_runtime_zero: usize = 0;
|
||||
const slice = array[known_at_runtime_zero..array.len];
|
||||
assert(&slice[0] == &array[0]);
|
||||
assert(slice.len == array.len);
|
||||
|
||||
|
@ -2207,13 +2209,15 @@ test "basic slices" {
|
|||
{#code_end#}
|
||||
<p>This is one reason we prefer slices to pointers.</p>
|
||||
{#code_begin|test|slices#}
|
||||
const assert = @import("std").debug.assert;
|
||||
const mem = @import("std").mem;
|
||||
const fmt = @import("std").fmt;
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const mem = std.mem;
|
||||
const fmt = std.fmt;
|
||||
|
||||
test "using slices for strings" {
|
||||
// Zig has no concept of strings. String literals are arrays of u8, and
|
||||
// in general the string type is []u8 (slice of u8).
|
||||
// Zig has no concept of strings. String literals are const pointers to
|
||||
// arrays of u8, and by convention parameters that are "strings" are
|
||||
// expected to be UTF-8 encoded slices of u8.
|
||||
// Here we coerce [5]u8 to []const u8
|
||||
const hello: []const u8 = "hello";
|
||||
const world: []const u8 = "世界";
|
||||
|
@ -2222,7 +2226,7 @@ test "using slices for strings" {
|
|||
// You can use slice syntax on an array to convert an array into a slice.
|
||||
const all_together_slice = all_together[0..];
|
||||
// String concatenation example.
|
||||
const hello_world = try fmt.bufPrint(all_together_slice, "{} {}", .{hello, world});
|
||||
const hello_world = try fmt.bufPrint(all_together_slice, "{} {}", .{ hello, world });
|
||||
|
||||
// Generally, you can use UTF-8 and not worry about whether something is a
|
||||
// string. If you don't need to deal with individual characters, no need
|
||||
|
@ -2239,23 +2243,15 @@ test "slice pointer" {
|
|||
slice[2] = 3;
|
||||
assert(slice[2] == 3);
|
||||
// The slice is mutable because we sliced a mutable pointer.
|
||||
assert(@TypeOf(slice) == []u8);
|
||||
// Furthermore, it is actually a pointer to an array, since the start
|
||||
// and end indexes were both comptime-known.
|
||||
assert(@TypeOf(slice) == *[5]u8);
|
||||
|
||||
// You can also slice a slice:
|
||||
const slice2 = slice[2..3];
|
||||
assert(slice2.len == 1);
|
||||
assert(slice2[0] == 3);
|
||||
}
|
||||
|
||||
test "slice widening" {
|
||||
// Zig supports slice widening and slice narrowing. Cast a slice of u8
|
||||
// to a slice of anything else, and Zig will perform the length conversion.
|
||||
const array align(@alignOf(u32)) = [_]u8{ 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13 };
|
||||
const slice = mem.bytesAsSlice(u32, array[0..]);
|
||||
assert(slice.len == 2);
|
||||
assert(slice[0] == 0x12121212);
|
||||
assert(slice[1] == 0x13131313);
|
||||
}
|
||||
{#code_end#}
|
||||
{#see_also|Pointers|for|Arrays#}
|
||||
|
||||
|
|
|
@ -15,10 +15,10 @@ fn rotw(w: u32) u32 {
|
|||
|
||||
// Encrypt one block from src into dst, using the expanded key xk.
|
||||
fn encryptBlock(xk: []const u32, dst: []u8, src: []const u8) void {
|
||||
var s0 = mem.readIntSliceBig(u32, src[0..4]);
|
||||
var s1 = mem.readIntSliceBig(u32, src[4..8]);
|
||||
var s2 = mem.readIntSliceBig(u32, src[8..12]);
|
||||
var s3 = mem.readIntSliceBig(u32, src[12..16]);
|
||||
var s0 = mem.readIntBig(u32, src[0..4]);
|
||||
var s1 = mem.readIntBig(u32, src[4..8]);
|
||||
var s2 = mem.readIntBig(u32, src[8..12]);
|
||||
var s3 = mem.readIntBig(u32, src[12..16]);
|
||||
|
||||
// First round just XORs input with key.
|
||||
s0 ^= xk[0];
|
||||
|
@ -58,18 +58,18 @@ fn encryptBlock(xk: []const u32, dst: []u8, src: []const u8) void {
|
|||
s2 ^= xk[k + 2];
|
||||
s3 ^= xk[k + 3];
|
||||
|
||||
mem.writeIntSliceBig(u32, dst[0..4], s0);
|
||||
mem.writeIntSliceBig(u32, dst[4..8], s1);
|
||||
mem.writeIntSliceBig(u32, dst[8..12], s2);
|
||||
mem.writeIntSliceBig(u32, dst[12..16], s3);
|
||||
mem.writeIntBig(u32, dst[0..4], s0);
|
||||
mem.writeIntBig(u32, dst[4..8], s1);
|
||||
mem.writeIntBig(u32, dst[8..12], s2);
|
||||
mem.writeIntBig(u32, dst[12..16], s3);
|
||||
}
|
||||
|
||||
// Decrypt one block from src into dst, using the expanded key xk.
|
||||
pub fn decryptBlock(xk: []const u32, dst: []u8, src: []const u8) void {
|
||||
var s0 = mem.readIntSliceBig(u32, src[0..4]);
|
||||
var s1 = mem.readIntSliceBig(u32, src[4..8]);
|
||||
var s2 = mem.readIntSliceBig(u32, src[8..12]);
|
||||
var s3 = mem.readIntSliceBig(u32, src[12..16]);
|
||||
var s0 = mem.readIntBig(u32, src[0..4]);
|
||||
var s1 = mem.readIntBig(u32, src[4..8]);
|
||||
var s2 = mem.readIntBig(u32, src[8..12]);
|
||||
var s3 = mem.readIntBig(u32, src[12..16]);
|
||||
|
||||
// First round just XORs input with key.
|
||||
s0 ^= xk[0];
|
||||
|
@ -109,10 +109,10 @@ pub fn decryptBlock(xk: []const u32, dst: []u8, src: []const u8) void {
|
|||
s2 ^= xk[k + 2];
|
||||
s3 ^= xk[k + 3];
|
||||
|
||||
mem.writeIntSliceBig(u32, dst[0..4], s0);
|
||||
mem.writeIntSliceBig(u32, dst[4..8], s1);
|
||||
mem.writeIntSliceBig(u32, dst[8..12], s2);
|
||||
mem.writeIntSliceBig(u32, dst[12..16], s3);
|
||||
mem.writeIntBig(u32, dst[0..4], s0);
|
||||
mem.writeIntBig(u32, dst[4..8], s1);
|
||||
mem.writeIntBig(u32, dst[8..12], s2);
|
||||
mem.writeIntBig(u32, dst[12..16], s3);
|
||||
}
|
||||
|
||||
fn xorBytes(dst: []u8, a: []const u8, b: []const u8) usize {
|
||||
|
@ -154,8 +154,8 @@ fn AES(comptime keysize: usize) type {
|
|||
var n: usize = 0;
|
||||
while (n < src.len) {
|
||||
ctx.encrypt(keystream[0..], ctrbuf[0..]);
|
||||
var ctr_i = std.mem.readIntSliceBig(u128, ctrbuf[0..]);
|
||||
std.mem.writeIntSliceBig(u128, ctrbuf[0..], ctr_i +% 1);
|
||||
var ctr_i = std.mem.readIntBig(u128, ctrbuf[0..]);
|
||||
std.mem.writeIntBig(u128, ctrbuf[0..], ctr_i +% 1);
|
||||
|
||||
n += xorBytes(dst[n..], src[n..], &keystream);
|
||||
}
|
||||
|
@ -251,7 +251,7 @@ fn expandKey(key: []const u8, enc: []u32, dec: []u32) void {
|
|||
var i: usize = 0;
|
||||
var nk = key.len / 4;
|
||||
while (i < nk) : (i += 1) {
|
||||
enc[i] = mem.readIntSliceBig(u32, key[4 * i .. 4 * i + 4]);
|
||||
enc[i] = mem.readIntBig(u32, key[4 * i ..][0..4]);
|
||||
}
|
||||
while (i < enc.len) : (i += 1) {
|
||||
var t = enc[i - 1];
|
||||
|
|
|
@ -123,8 +123,7 @@ fn Blake2s(comptime out_len: usize) type {
|
|||
const rr = d.h[0 .. out_len / 32];
|
||||
|
||||
for (rr) |s, j| {
|
||||
// TODO https://github.com/ziglang/zig/issues/863
|
||||
mem.writeIntSliceLittle(u32, out[4 * j .. 4 * j + 4], s);
|
||||
mem.writeIntLittle(u32, out[4 * j ..][0..4], s);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -135,8 +134,7 @@ fn Blake2s(comptime out_len: usize) type {
|
|||
var v: [16]u32 = undefined;
|
||||
|
||||
for (m) |*r, i| {
|
||||
// TODO https://github.com/ziglang/zig/issues/863
|
||||
r.* = mem.readIntSliceLittle(u32, b[4 * i .. 4 * i + 4]);
|
||||
r.* = mem.readIntLittle(u32, b[4 * i ..][0..4]);
|
||||
}
|
||||
|
||||
var k: usize = 0;
|
||||
|
@ -358,8 +356,7 @@ fn Blake2b(comptime out_len: usize) type {
|
|||
const rr = d.h[0 .. out_len / 64];
|
||||
|
||||
for (rr) |s, j| {
|
||||
// TODO https://github.com/ziglang/zig/issues/863
|
||||
mem.writeIntSliceLittle(u64, out[8 * j .. 8 * j + 8], s);
|
||||
mem.writeIntLittle(u64, out[8 * j ..][0..8], s);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -370,7 +367,7 @@ fn Blake2b(comptime out_len: usize) type {
|
|||
var v: [16]u64 = undefined;
|
||||
|
||||
for (m) |*r, i| {
|
||||
r.* = mem.readIntSliceLittle(u64, b[8 * i .. 8 * i + 8]);
|
||||
r.* = mem.readIntLittle(u64, b[8 * i ..][0..8]);
|
||||
}
|
||||
|
||||
var k: usize = 0;
|
||||
|
|
|
@ -61,8 +61,7 @@ fn salsa20_wordtobyte(out: []u8, input: [16]u32) void {
|
|||
}
|
||||
|
||||
for (x) |_, i| {
|
||||
// TODO https://github.com/ziglang/zig/issues/863
|
||||
mem.writeIntSliceLittle(u32, out[4 * i .. 4 * i + 4], x[i] +% input[i]);
|
||||
mem.writeIntLittle(u32, out[4 * i ..][0..4], x[i] +% input[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,10 +72,10 @@ fn chaCha20_internal(out: []u8, in: []const u8, key: [8]u32, counter: [4]u32) vo
|
|||
|
||||
const c = "expand 32-byte k";
|
||||
const constant_le = [_]u32{
|
||||
mem.readIntSliceLittle(u32, c[0..4]),
|
||||
mem.readIntSliceLittle(u32, c[4..8]),
|
||||
mem.readIntSliceLittle(u32, c[8..12]),
|
||||
mem.readIntSliceLittle(u32, c[12..16]),
|
||||
mem.readIntLittle(u32, c[0..4]),
|
||||
mem.readIntLittle(u32, c[4..8]),
|
||||
mem.readIntLittle(u32, c[8..12]),
|
||||
mem.readIntLittle(u32, c[12..16]),
|
||||
};
|
||||
|
||||
mem.copy(u32, ctx[0..], constant_le[0..4]);
|
||||
|
@ -120,19 +119,19 @@ pub fn chaCha20IETF(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce:
|
|||
var k: [8]u32 = undefined;
|
||||
var c: [4]u32 = undefined;
|
||||
|
||||
k[0] = mem.readIntSliceLittle(u32, key[0..4]);
|
||||
k[1] = mem.readIntSliceLittle(u32, key[4..8]);
|
||||
k[2] = mem.readIntSliceLittle(u32, key[8..12]);
|
||||
k[3] = mem.readIntSliceLittle(u32, key[12..16]);
|
||||
k[4] = mem.readIntSliceLittle(u32, key[16..20]);
|
||||
k[5] = mem.readIntSliceLittle(u32, key[20..24]);
|
||||
k[6] = mem.readIntSliceLittle(u32, key[24..28]);
|
||||
k[7] = mem.readIntSliceLittle(u32, key[28..32]);
|
||||
k[0] = mem.readIntLittle(u32, key[0..4]);
|
||||
k[1] = mem.readIntLittle(u32, key[4..8]);
|
||||
k[2] = mem.readIntLittle(u32, key[8..12]);
|
||||
k[3] = mem.readIntLittle(u32, key[12..16]);
|
||||
k[4] = mem.readIntLittle(u32, key[16..20]);
|
||||
k[5] = mem.readIntLittle(u32, key[20..24]);
|
||||
k[6] = mem.readIntLittle(u32, key[24..28]);
|
||||
k[7] = mem.readIntLittle(u32, key[28..32]);
|
||||
|
||||
c[0] = counter;
|
||||
c[1] = mem.readIntSliceLittle(u32, nonce[0..4]);
|
||||
c[2] = mem.readIntSliceLittle(u32, nonce[4..8]);
|
||||
c[3] = mem.readIntSliceLittle(u32, nonce[8..12]);
|
||||
c[1] = mem.readIntLittle(u32, nonce[0..4]);
|
||||
c[2] = mem.readIntLittle(u32, nonce[4..8]);
|
||||
c[3] = mem.readIntLittle(u32, nonce[8..12]);
|
||||
chaCha20_internal(out, in, k, c);
|
||||
}
|
||||
|
||||
|
@ -147,19 +146,19 @@ pub fn chaCha20With64BitNonce(out: []u8, in: []const u8, counter: u64, key: [32]
|
|||
var k: [8]u32 = undefined;
|
||||
var c: [4]u32 = undefined;
|
||||
|
||||
k[0] = mem.readIntSliceLittle(u32, key[0..4]);
|
||||
k[1] = mem.readIntSliceLittle(u32, key[4..8]);
|
||||
k[2] = mem.readIntSliceLittle(u32, key[8..12]);
|
||||
k[3] = mem.readIntSliceLittle(u32, key[12..16]);
|
||||
k[4] = mem.readIntSliceLittle(u32, key[16..20]);
|
||||
k[5] = mem.readIntSliceLittle(u32, key[20..24]);
|
||||
k[6] = mem.readIntSliceLittle(u32, key[24..28]);
|
||||
k[7] = mem.readIntSliceLittle(u32, key[28..32]);
|
||||
k[0] = mem.readIntLittle(u32, key[0..4]);
|
||||
k[1] = mem.readIntLittle(u32, key[4..8]);
|
||||
k[2] = mem.readIntLittle(u32, key[8..12]);
|
||||
k[3] = mem.readIntLittle(u32, key[12..16]);
|
||||
k[4] = mem.readIntLittle(u32, key[16..20]);
|
||||
k[5] = mem.readIntLittle(u32, key[20..24]);
|
||||
k[6] = mem.readIntLittle(u32, key[24..28]);
|
||||
k[7] = mem.readIntLittle(u32, key[28..32]);
|
||||
|
||||
c[0] = @truncate(u32, counter);
|
||||
c[1] = @truncate(u32, counter >> 32);
|
||||
c[2] = mem.readIntSliceLittle(u32, nonce[0..4]);
|
||||
c[3] = mem.readIntSliceLittle(u32, nonce[4..8]);
|
||||
c[2] = mem.readIntLittle(u32, nonce[0..4]);
|
||||
c[3] = mem.readIntLittle(u32, nonce[4..8]);
|
||||
|
||||
const block_size = (1 << 6);
|
||||
// The full block size is greater than the address space on a 32bit machine
|
||||
|
@ -463,8 +462,8 @@ pub fn chacha20poly1305Seal(dst: []u8, plaintext: []const u8, data: []const u8,
|
|||
mac.update(zeros[0..padding]);
|
||||
}
|
||||
var lens: [16]u8 = undefined;
|
||||
mem.writeIntSliceLittle(u64, lens[0..8], data.len);
|
||||
mem.writeIntSliceLittle(u64, lens[8..16], plaintext.len);
|
||||
mem.writeIntLittle(u64, lens[0..8], data.len);
|
||||
mem.writeIntLittle(u64, lens[8..16], plaintext.len);
|
||||
mac.update(lens[0..]);
|
||||
mac.final(dst[plaintext.len..]);
|
||||
}
|
||||
|
@ -500,8 +499,8 @@ pub fn chacha20poly1305Open(dst: []u8, msgAndTag: []const u8, data: []const u8,
|
|||
mac.update(zeros[0..padding]);
|
||||
}
|
||||
var lens: [16]u8 = undefined;
|
||||
mem.writeIntSliceLittle(u64, lens[0..8], data.len);
|
||||
mem.writeIntSliceLittle(u64, lens[8..16], ciphertext.len);
|
||||
mem.writeIntLittle(u64, lens[0..8], data.len);
|
||||
mem.writeIntLittle(u64, lens[8..16], ciphertext.len);
|
||||
mac.update(lens[0..]);
|
||||
var computedTag: [16]u8 = undefined;
|
||||
mac.final(computedTag[0..]);
|
||||
|
|
|
@ -112,8 +112,7 @@ pub const Md5 = struct {
|
|||
d.round(d.buf[0..]);
|
||||
|
||||
for (d.s) |s, j| {
|
||||
// TODO https://github.com/ziglang/zig/issues/863
|
||||
mem.writeIntSliceLittle(u32, out[4 * j .. 4 * j + 4], s);
|
||||
mem.writeIntLittle(u32, out[4 * j ..][0..4], s);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
// https://monocypher.org/
|
||||
|
||||
const std = @import("../std.zig");
|
||||
const builtin = @import("builtin");
|
||||
const builtin = std.builtin;
|
||||
|
||||
const Endian = builtin.Endian;
|
||||
const readIntSliceLittle = std.mem.readIntSliceLittle;
|
||||
const writeIntSliceLittle = std.mem.writeIntSliceLittle;
|
||||
const readIntLittle = std.mem.readIntLittle;
|
||||
const writeIntLittle = std.mem.writeIntLittle;
|
||||
|
||||
pub const Poly1305 = struct {
|
||||
const Self = @This();
|
||||
|
@ -59,19 +59,19 @@ pub const Poly1305 = struct {
|
|||
{
|
||||
var i: usize = 0;
|
||||
while (i < 1) : (i += 1) {
|
||||
ctx.r[0] = readIntSliceLittle(u32, key[0..4]) & 0x0fffffff;
|
||||
ctx.r[0] = readIntLittle(u32, key[0..4]) & 0x0fffffff;
|
||||
}
|
||||
}
|
||||
{
|
||||
var i: usize = 1;
|
||||
while (i < 4) : (i += 1) {
|
||||
ctx.r[i] = readIntSliceLittle(u32, key[i * 4 .. i * 4 + 4]) & 0x0ffffffc;
|
||||
ctx.r[i] = readIntLittle(u32, key[i * 4 ..][0..4]) & 0x0ffffffc;
|
||||
}
|
||||
}
|
||||
{
|
||||
var i: usize = 0;
|
||||
while (i < 4) : (i += 1) {
|
||||
ctx.pad[i] = readIntSliceLittle(u32, key[i * 4 + 16 .. i * 4 + 16 + 4]);
|
||||
ctx.pad[i] = readIntLittle(u32, key[i * 4 + 16 ..][0..4]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -168,10 +168,10 @@ pub const Poly1305 = struct {
|
|||
const nb_blocks = nmsg.len >> 4;
|
||||
var i: usize = 0;
|
||||
while (i < nb_blocks) : (i += 1) {
|
||||
ctx.c[0] = readIntSliceLittle(u32, nmsg[0..4]);
|
||||
ctx.c[1] = readIntSliceLittle(u32, nmsg[4..8]);
|
||||
ctx.c[2] = readIntSliceLittle(u32, nmsg[8..12]);
|
||||
ctx.c[3] = readIntSliceLittle(u32, nmsg[12..16]);
|
||||
ctx.c[0] = readIntLittle(u32, nmsg[0..4]);
|
||||
ctx.c[1] = readIntLittle(u32, nmsg[4..8]);
|
||||
ctx.c[2] = readIntLittle(u32, nmsg[8..12]);
|
||||
ctx.c[3] = readIntLittle(u32, nmsg[12..16]);
|
||||
polyBlock(ctx);
|
||||
nmsg = nmsg[16..];
|
||||
}
|
||||
|
@ -210,11 +210,10 @@ pub const Poly1305 = struct {
|
|||
const uu2 = (uu1 >> 32) + ctx.h[2] + ctx.pad[2]; // <= 2_00000000
|
||||
const uu3 = (uu2 >> 32) + ctx.h[3] + ctx.pad[3]; // <= 2_00000000
|
||||
|
||||
// TODO https://github.com/ziglang/zig/issues/863
|
||||
writeIntSliceLittle(u32, out[0..], @truncate(u32, uu0));
|
||||
writeIntSliceLittle(u32, out[4..], @truncate(u32, uu1));
|
||||
writeIntSliceLittle(u32, out[8..], @truncate(u32, uu2));
|
||||
writeIntSliceLittle(u32, out[12..], @truncate(u32, uu3));
|
||||
writeIntLittle(u32, out[0..4], @truncate(u32, uu0));
|
||||
writeIntLittle(u32, out[4..8], @truncate(u32, uu1));
|
||||
writeIntLittle(u32, out[8..12], @truncate(u32, uu2));
|
||||
writeIntLittle(u32, out[12..16], @truncate(u32, uu3));
|
||||
|
||||
ctx.secureZero();
|
||||
}
|
||||
|
|
|
@ -109,8 +109,7 @@ pub const Sha1 = struct {
|
|||
d.round(d.buf[0..]);
|
||||
|
||||
for (d.s) |s, j| {
|
||||
// TODO https://github.com/ziglang/zig/issues/863
|
||||
mem.writeIntSliceBig(u32, out[4 * j .. 4 * j + 4], s);
|
||||
mem.writeIntBig(u32, out[4 * j ..][0..4], s);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -167,8 +167,7 @@ fn Sha2_32(comptime params: Sha2Params32) type {
|
|||
const rr = d.s[0 .. params.out_len / 32];
|
||||
|
||||
for (rr) |s, j| {
|
||||
// TODO https://github.com/ziglang/zig/issues/863
|
||||
mem.writeIntSliceBig(u32, out[4 * j .. 4 * j + 4], s);
|
||||
mem.writeIntBig(u32, out[4 * j ..][0..4], s);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -509,8 +508,7 @@ fn Sha2_64(comptime params: Sha2Params64) type {
|
|||
const rr = d.s[0 .. params.out_len / 64];
|
||||
|
||||
for (rr) |s, j| {
|
||||
// TODO https://github.com/ziglang/zig/issues/863
|
||||
mem.writeIntSliceBig(u64, out[8 * j .. 8 * j + 8], s);
|
||||
mem.writeIntBig(u64, out[8 * j ..][0..8], s);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -120,7 +120,7 @@ fn keccak_f(comptime F: usize, d: []u8) void {
|
|||
var c = [_]u64{0} ** 5;
|
||||
|
||||
for (s) |*r, i| {
|
||||
r.* = mem.readIntSliceLittle(u64, d[8 * i .. 8 * i + 8]);
|
||||
r.* = mem.readIntLittle(u64, d[8 * i ..][0..8]);
|
||||
}
|
||||
|
||||
comptime var x: usize = 0;
|
||||
|
@ -167,8 +167,7 @@ fn keccak_f(comptime F: usize, d: []u8) void {
|
|||
}
|
||||
|
||||
for (s) |r, i| {
|
||||
// TODO https://github.com/ziglang/zig/issues/863
|
||||
mem.writeIntSliceLittle(u64, d[8 * i .. 8 * i + 8], r);
|
||||
mem.writeIntLittle(u64, d[8 * i ..][0..8], r);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,8 +7,8 @@ const builtin = @import("builtin");
|
|||
const fmt = std.fmt;
|
||||
|
||||
const Endian = builtin.Endian;
|
||||
const readIntSliceLittle = std.mem.readIntSliceLittle;
|
||||
const writeIntSliceLittle = std.mem.writeIntSliceLittle;
|
||||
const readIntLittle = std.mem.readIntLittle;
|
||||
const writeIntLittle = std.mem.writeIntLittle;
|
||||
|
||||
// Based on Supercop's ref10 implementation.
|
||||
pub const X25519 = struct {
|
||||
|
@ -255,16 +255,16 @@ const Fe = struct {
|
|||
|
||||
var t: [10]i64 = undefined;
|
||||
|
||||
t[0] = readIntSliceLittle(u32, s[0..4]);
|
||||
t[1] = @as(u32, readIntSliceLittle(u24, s[4..7])) << 6;
|
||||
t[2] = @as(u32, readIntSliceLittle(u24, s[7..10])) << 5;
|
||||
t[3] = @as(u32, readIntSliceLittle(u24, s[10..13])) << 3;
|
||||
t[4] = @as(u32, readIntSliceLittle(u24, s[13..16])) << 2;
|
||||
t[5] = readIntSliceLittle(u32, s[16..20]);
|
||||
t[6] = @as(u32, readIntSliceLittle(u24, s[20..23])) << 7;
|
||||
t[7] = @as(u32, readIntSliceLittle(u24, s[23..26])) << 5;
|
||||
t[8] = @as(u32, readIntSliceLittle(u24, s[26..29])) << 4;
|
||||
t[9] = (@as(u32, readIntSliceLittle(u24, s[29..32])) & 0x7fffff) << 2;
|
||||
t[0] = readIntLittle(u32, s[0..4]);
|
||||
t[1] = @as(u32, readIntLittle(u24, s[4..7])) << 6;
|
||||
t[2] = @as(u32, readIntLittle(u24, s[7..10])) << 5;
|
||||
t[3] = @as(u32, readIntLittle(u24, s[10..13])) << 3;
|
||||
t[4] = @as(u32, readIntLittle(u24, s[13..16])) << 2;
|
||||
t[5] = readIntLittle(u32, s[16..20]);
|
||||
t[6] = @as(u32, readIntLittle(u24, s[20..23])) << 7;
|
||||
t[7] = @as(u32, readIntLittle(u24, s[23..26])) << 5;
|
||||
t[8] = @as(u32, readIntLittle(u24, s[26..29])) << 4;
|
||||
t[9] = (@as(u32, readIntLittle(u24, s[29..32])) & 0x7fffff) << 2;
|
||||
|
||||
carry1(h, t[0..]);
|
||||
}
|
||||
|
@ -544,15 +544,14 @@ const Fe = struct {
|
|||
ut[i] = @bitCast(u32, @intCast(i32, t[i]));
|
||||
}
|
||||
|
||||
// TODO https://github.com/ziglang/zig/issues/863
|
||||
writeIntSliceLittle(u32, s[0..4], (ut[0] >> 0) | (ut[1] << 26));
|
||||
writeIntSliceLittle(u32, s[4..8], (ut[1] >> 6) | (ut[2] << 19));
|
||||
writeIntSliceLittle(u32, s[8..12], (ut[2] >> 13) | (ut[3] << 13));
|
||||
writeIntSliceLittle(u32, s[12..16], (ut[3] >> 19) | (ut[4] << 6));
|
||||
writeIntSliceLittle(u32, s[16..20], (ut[5] >> 0) | (ut[6] << 25));
|
||||
writeIntSliceLittle(u32, s[20..24], (ut[6] >> 7) | (ut[7] << 19));
|
||||
writeIntSliceLittle(u32, s[24..28], (ut[7] >> 13) | (ut[8] << 12));
|
||||
writeIntSliceLittle(u32, s[28..], (ut[8] >> 20) | (ut[9] << 6));
|
||||
writeIntLittle(u32, s[0..4], (ut[0] >> 0) | (ut[1] << 26));
|
||||
writeIntLittle(u32, s[4..8], (ut[1] >> 6) | (ut[2] << 19));
|
||||
writeIntLittle(u32, s[8..12], (ut[2] >> 13) | (ut[3] << 13));
|
||||
writeIntLittle(u32, s[12..16], (ut[3] >> 19) | (ut[4] << 6));
|
||||
writeIntLittle(u32, s[16..20], (ut[5] >> 0) | (ut[6] << 25));
|
||||
writeIntLittle(u32, s[20..24], (ut[6] >> 7) | (ut[7] << 19));
|
||||
writeIntLittle(u32, s[24..28], (ut[7] >> 13) | (ut[8] << 12));
|
||||
writeIntLittle(u32, s[28..32], (ut[8] >> 20) | (ut[9] << 6));
|
||||
|
||||
std.mem.secureZero(i64, t[0..]);
|
||||
}
|
||||
|
|
|
@ -1223,7 +1223,8 @@ test "slice" {
|
|||
try testFmt("slice: abc\n", "slice: {}\n", .{value});
|
||||
}
|
||||
{
|
||||
const value = @intToPtr([*]align(1) const []const u8, 0xdeadbeef)[0..0];
|
||||
var runtime_zero: usize = 0;
|
||||
const value = @intToPtr([*]align(1) const []const u8, 0xdeadbeef)[runtime_zero..runtime_zero];
|
||||
try testFmt("slice: []const u8@deadbeef\n", "slice: {}\n", .{value});
|
||||
}
|
||||
|
||||
|
|
|
@ -341,7 +341,7 @@ pub const Dir = struct {
|
|||
if (self.index >= self.end_index) {
|
||||
const rc = os.system.getdirentries(
|
||||
self.dir.fd,
|
||||
self.buf[0..].ptr,
|
||||
&self.buf,
|
||||
self.buf.len,
|
||||
&self.seek,
|
||||
);
|
||||
|
|
|
@ -40,7 +40,9 @@ pub fn hashPointer(hasher: var, key: var, comptime strat: HashStrategy) void {
|
|||
.DeepRecursive => hashArray(hasher, key, .DeepRecursive),
|
||||
},
|
||||
|
||||
.Many, .C, => switch (strat) {
|
||||
.Many,
|
||||
.C,
|
||||
=> switch (strat) {
|
||||
.Shallow => hash(hasher, @ptrToInt(key), .Shallow),
|
||||
else => @compileError(
|
||||
\\ unknown-length pointers and C pointers cannot be hashed deeply.
|
||||
|
@ -236,9 +238,11 @@ test "hash slice shallow" {
|
|||
defer std.testing.allocator.destroy(array1);
|
||||
array1.* = [_]u32{ 1, 2, 3, 4, 5, 6 };
|
||||
const array2 = [_]u32{ 1, 2, 3, 4, 5, 6 };
|
||||
const a = array1[0..];
|
||||
const b = array2[0..];
|
||||
const c = array1[0..3];
|
||||
// TODO audit deep/shallow - maybe it has the wrong behavior with respect to array pointers and slices
|
||||
var runtime_zero: usize = 0;
|
||||
const a = array1[runtime_zero..];
|
||||
const b = array2[runtime_zero..];
|
||||
const c = array1[runtime_zero..3];
|
||||
testing.expect(testHashShallow(a) == testHashShallow(a));
|
||||
testing.expect(testHashShallow(a) != testHashShallow(array1));
|
||||
testing.expect(testHashShallow(a) != testHashShallow(b));
|
||||
|
|
|
@ -39,8 +39,8 @@ fn SipHashStateless(comptime T: type, comptime c_rounds: usize, comptime d_round
|
|||
pub fn init(key: []const u8) Self {
|
||||
assert(key.len >= 16);
|
||||
|
||||
const k0 = mem.readIntSliceLittle(u64, key[0..8]);
|
||||
const k1 = mem.readIntSliceLittle(u64, key[8..16]);
|
||||
const k0 = mem.readIntLittle(u64, key[0..8]);
|
||||
const k1 = mem.readIntLittle(u64, key[8..16]);
|
||||
|
||||
var d = Self{
|
||||
.v0 = k0 ^ 0x736f6d6570736575,
|
||||
|
@ -111,7 +111,7 @@ fn SipHashStateless(comptime T: type, comptime c_rounds: usize, comptime d_round
|
|||
fn round(self: *Self, b: []const u8) void {
|
||||
assert(b.len == 8);
|
||||
|
||||
const m = mem.readIntSliceLittle(u64, b[0..]);
|
||||
const m = mem.readIntLittle(u64, b[0..8]);
|
||||
self.v3 ^= m;
|
||||
|
||||
// TODO this is a workaround, should be able to supply the value without a separate variable
|
||||
|
|
|
@ -11,7 +11,7 @@ const primes = [_]u64{
|
|||
|
||||
fn read_bytes(comptime bytes: u8, data: []const u8) u64 {
|
||||
const T = std.meta.IntType(false, 8 * bytes);
|
||||
return mem.readIntSliceLittle(T, data[0..bytes]);
|
||||
return mem.readIntLittle(T, data[0..bytes]);
|
||||
}
|
||||
|
||||
fn read_8bytes_swapped(data: []const u8) u64 {
|
||||
|
|
|
@ -2249,11 +2249,16 @@ pub const StringifyOptions = struct {
|
|||
// TODO: allow picking if []u8 is string or array?
|
||||
};
|
||||
|
||||
pub const StringifyError = error{
|
||||
TooMuchData,
|
||||
DifferentData,
|
||||
};
|
||||
|
||||
pub fn stringify(
|
||||
value: var,
|
||||
options: StringifyOptions,
|
||||
out_stream: var,
|
||||
) !void {
|
||||
) StringifyError!void {
|
||||
const T = @TypeOf(value);
|
||||
switch (@typeInfo(T)) {
|
||||
.Float, .ComptimeFloat => {
|
||||
|
@ -2320,9 +2325,15 @@ pub fn stringify(
|
|||
return;
|
||||
},
|
||||
.Pointer => |ptr_info| switch (ptr_info.size) {
|
||||
.One => {
|
||||
// TODO: avoid loops?
|
||||
return try stringify(value.*, options, out_stream);
|
||||
.One => switch (@typeInfo(ptr_info.child)) {
|
||||
.Array => {
|
||||
const Slice = []const std.meta.Elem(ptr_info.child);
|
||||
return stringify(@as(Slice, value), options, out_stream);
|
||||
},
|
||||
else => {
|
||||
// TODO: avoid loops?
|
||||
return stringify(value.*, options, out_stream);
|
||||
},
|
||||
},
|
||||
// TODO: .Many when there is a sentinel (waiting for https://github.com/ziglang/zig/pull/3972)
|
||||
.Slice => {
|
||||
|
@ -2381,9 +2392,7 @@ pub fn stringify(
|
|||
},
|
||||
else => @compileError("Unable to stringify type '" ++ @typeName(T) ++ "'"),
|
||||
},
|
||||
.Array => |info| {
|
||||
return try stringify(value[0..], options, out_stream);
|
||||
},
|
||||
.Array => return stringify(&value, options, out_stream),
|
||||
else => @compileError("Unable to stringify type '" ++ @typeName(T) ++ "'"),
|
||||
}
|
||||
unreachable;
|
||||
|
|
113
lib/std/mem.zig
113
lib/std/mem.zig
|
@ -560,7 +560,7 @@ pub fn span(ptr: var) Span(@TypeOf(ptr)) {
|
|||
|
||||
test "span" {
|
||||
var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 };
|
||||
const ptr = array[0..2 :3].ptr;
|
||||
const ptr = @as([*:3]u16, array[0..2 :3]);
|
||||
testing.expect(eql(u16, span(ptr), &[_]u16{ 1, 2 }));
|
||||
testing.expect(eql(u16, span(&array), &[_]u16{ 1, 2, 3, 4, 5 }));
|
||||
}
|
||||
|
@ -602,7 +602,7 @@ test "len" {
|
|||
testing.expect(len(&array) == 5);
|
||||
testing.expect(len(array[0..3]) == 3);
|
||||
array[2] = 0;
|
||||
const ptr = array[0..2 :0].ptr;
|
||||
const ptr = @as([*:0]u16, array[0..2 :0]);
|
||||
testing.expect(len(ptr) == 2);
|
||||
}
|
||||
{
|
||||
|
@ -824,8 +824,7 @@ pub const readIntBig = switch (builtin.endian) {
|
|||
pub fn readIntSliceNative(comptime T: type, bytes: []const u8) T {
|
||||
const n = @divExact(T.bit_count, 8);
|
||||
assert(bytes.len >= n);
|
||||
// TODO https://github.com/ziglang/zig/issues/863
|
||||
return readIntNative(T, @ptrCast(*const [n]u8, bytes.ptr));
|
||||
return readIntNative(T, bytes[0..n]);
|
||||
}
|
||||
|
||||
/// Asserts that bytes.len >= T.bit_count / 8. Reads the integer starting from index 0
|
||||
|
@ -863,8 +862,7 @@ pub fn readInt(comptime T: type, bytes: *const [@divExact(T.bit_count, 8)]u8, en
|
|||
pub fn readIntSlice(comptime T: type, bytes: []const u8, endian: builtin.Endian) T {
|
||||
const n = @divExact(T.bit_count, 8);
|
||||
assert(bytes.len >= n);
|
||||
// TODO https://github.com/ziglang/zig/issues/863
|
||||
return readInt(T, @ptrCast(*const [n]u8, bytes.ptr), endian);
|
||||
return readInt(T, bytes[0..n], endian);
|
||||
}
|
||||
|
||||
test "comptime read/write int" {
|
||||
|
@ -1586,24 +1584,24 @@ pub fn nativeToBig(comptime T: type, x: T) T {
|
|||
}
|
||||
|
||||
fn AsBytesReturnType(comptime P: type) type {
|
||||
if (comptime !trait.isSingleItemPtr(P))
|
||||
if (!trait.isSingleItemPtr(P))
|
||||
@compileError("expected single item pointer, passed " ++ @typeName(P));
|
||||
|
||||
const size = @as(usize, @sizeOf(meta.Child(P)));
|
||||
const alignment = comptime meta.alignment(P);
|
||||
const size = @sizeOf(meta.Child(P));
|
||||
const alignment = meta.alignment(P);
|
||||
|
||||
if (alignment == 0) {
|
||||
if (comptime trait.isConstPtr(P))
|
||||
if (trait.isConstPtr(P))
|
||||
return *const [size]u8;
|
||||
return *[size]u8;
|
||||
}
|
||||
|
||||
if (comptime trait.isConstPtr(P))
|
||||
if (trait.isConstPtr(P))
|
||||
return *align(alignment) const [size]u8;
|
||||
return *align(alignment) [size]u8;
|
||||
}
|
||||
|
||||
///Given a pointer to a single item, returns a slice of the underlying bytes, preserving constness.
|
||||
/// Given a pointer to a single item, returns a slice of the underlying bytes, preserving constness.
|
||||
pub fn asBytes(ptr: var) AsBytesReturnType(@TypeOf(ptr)) {
|
||||
const P = @TypeOf(ptr);
|
||||
return @ptrCast(AsBytesReturnType(P), ptr);
|
||||
|
@ -1750,34 +1748,50 @@ fn BytesAsSliceReturnType(comptime T: type, comptime bytesType: type) type {
|
|||
}
|
||||
|
||||
pub fn bytesAsSlice(comptime T: type, bytes: var) BytesAsSliceReturnType(T, @TypeOf(bytes)) {
|
||||
const bytesSlice = if (comptime trait.isPtrTo(.Array)(@TypeOf(bytes))) bytes[0..] else bytes;
|
||||
|
||||
// let's not give an undefined pointer to @ptrCast
|
||||
// it may be equal to zero and fail a null check
|
||||
if (bytesSlice.len == 0) {
|
||||
if (bytes.len == 0) {
|
||||
return &[0]T{};
|
||||
}
|
||||
|
||||
const bytesType = @TypeOf(bytesSlice);
|
||||
const alignment = comptime meta.alignment(bytesType);
|
||||
const Bytes = @TypeOf(bytes);
|
||||
const alignment = comptime meta.alignment(Bytes);
|
||||
|
||||
const castTarget = if (comptime trait.isConstPtr(bytesType)) [*]align(alignment) const T else [*]align(alignment) T;
|
||||
const cast_target = if (comptime trait.isConstPtr(Bytes)) [*]align(alignment) const T else [*]align(alignment) T;
|
||||
|
||||
return @ptrCast(castTarget, bytesSlice.ptr)[0..@divExact(bytes.len, @sizeOf(T))];
|
||||
return @ptrCast(cast_target, bytes)[0..@divExact(bytes.len, @sizeOf(T))];
|
||||
}
|
||||
|
||||
test "bytesAsSlice" {
|
||||
const bytes = [_]u8{ 0xDE, 0xAD, 0xBE, 0xEF };
|
||||
const slice = bytesAsSlice(u16, bytes[0..]);
|
||||
testing.expect(slice.len == 2);
|
||||
testing.expect(bigToNative(u16, slice[0]) == 0xDEAD);
|
||||
testing.expect(bigToNative(u16, slice[1]) == 0xBEEF);
|
||||
{
|
||||
const bytes = [_]u8{ 0xDE, 0xAD, 0xBE, 0xEF };
|
||||
const slice = bytesAsSlice(u16, bytes[0..]);
|
||||
testing.expect(slice.len == 2);
|
||||
testing.expect(bigToNative(u16, slice[0]) == 0xDEAD);
|
||||
testing.expect(bigToNative(u16, slice[1]) == 0xBEEF);
|
||||
}
|
||||
{
|
||||
const bytes = [_]u8{ 0xDE, 0xAD, 0xBE, 0xEF };
|
||||
var runtime_zero: usize = 0;
|
||||
const slice = bytesAsSlice(u16, bytes[runtime_zero..]);
|
||||
testing.expect(slice.len == 2);
|
||||
testing.expect(bigToNative(u16, slice[0]) == 0xDEAD);
|
||||
testing.expect(bigToNative(u16, slice[1]) == 0xBEEF);
|
||||
}
|
||||
}
|
||||
|
||||
test "bytesAsSlice keeps pointer alignment" {
|
||||
var bytes = [_]u8{ 0x01, 0x02, 0x03, 0x04 };
|
||||
const numbers = bytesAsSlice(u32, bytes[0..]);
|
||||
comptime testing.expect(@TypeOf(numbers) == []align(@alignOf(@TypeOf(bytes))) u32);
|
||||
{
|
||||
var bytes = [_]u8{ 0x01, 0x02, 0x03, 0x04 };
|
||||
const numbers = bytesAsSlice(u32, bytes[0..]);
|
||||
comptime testing.expect(@TypeOf(numbers) == []align(@alignOf(@TypeOf(bytes))) u32);
|
||||
}
|
||||
{
|
||||
var bytes = [_]u8{ 0x01, 0x02, 0x03, 0x04 };
|
||||
var runtime_zero: usize = 0;
|
||||
const numbers = bytesAsSlice(u32, bytes[runtime_zero..]);
|
||||
comptime testing.expect(@TypeOf(numbers) == []align(@alignOf(@TypeOf(bytes))) u32);
|
||||
}
|
||||
}
|
||||
|
||||
test "bytesAsSlice on a packed struct" {
|
||||
|
@ -1813,21 +1827,19 @@ fn SliceAsBytesReturnType(comptime sliceType: type) type {
|
|||
}
|
||||
|
||||
pub fn sliceAsBytes(slice: var) SliceAsBytesReturnType(@TypeOf(slice)) {
|
||||
const actualSlice = if (comptime trait.isPtrTo(.Array)(@TypeOf(slice))) slice[0..] else slice;
|
||||
const actualSliceTypeInfo = @typeInfo(@TypeOf(actualSlice)).Pointer;
|
||||
const Slice = @TypeOf(slice);
|
||||
|
||||
// let's not give an undefined pointer to @ptrCast
|
||||
// it may be equal to zero and fail a null check
|
||||
if (actualSlice.len == 0 and actualSliceTypeInfo.sentinel == null) {
|
||||
if (slice.len == 0 and comptime meta.sentinel(Slice) == null) {
|
||||
return &[0]u8{};
|
||||
}
|
||||
|
||||
const sliceType = @TypeOf(actualSlice);
|
||||
const alignment = comptime meta.alignment(sliceType);
|
||||
const alignment = comptime meta.alignment(Slice);
|
||||
|
||||
const castTarget = if (comptime trait.isConstPtr(sliceType)) [*]align(alignment) const u8 else [*]align(alignment) u8;
|
||||
const cast_target = if (comptime trait.isConstPtr(Slice)) [*]align(alignment) const u8 else [*]align(alignment) u8;
|
||||
|
||||
return @ptrCast(castTarget, actualSlice.ptr)[0 .. actualSlice.len * @sizeOf(comptime meta.Child(sliceType))];
|
||||
return @ptrCast(cast_target, slice)[0 .. slice.len * @sizeOf(meta.Elem(Slice))];
|
||||
}
|
||||
|
||||
test "sliceAsBytes" {
|
||||
|
@ -1897,39 +1909,6 @@ test "sliceAsBytes and bytesAsSlice back" {
|
|||
testing.expect(bytes[11] == math.maxInt(u8));
|
||||
}
|
||||
|
||||
fn SubArrayPtrReturnType(comptime T: type, comptime length: usize) type {
|
||||
if (trait.isConstPtr(T))
|
||||
return *const [length]meta.Child(meta.Child(T));
|
||||
return *[length]meta.Child(meta.Child(T));
|
||||
}
|
||||
|
||||
/// Given a pointer to an array, returns a pointer to a portion of that array, preserving constness.
|
||||
/// TODO this will be obsoleted by https://github.com/ziglang/zig/issues/863
|
||||
pub fn subArrayPtr(
|
||||
ptr: var,
|
||||
comptime start: usize,
|
||||
comptime length: usize,
|
||||
) SubArrayPtrReturnType(@TypeOf(ptr), length) {
|
||||
assert(start + length <= ptr.*.len);
|
||||
|
||||
const ReturnType = SubArrayPtrReturnType(@TypeOf(ptr), length);
|
||||
const T = meta.Child(meta.Child(@TypeOf(ptr)));
|
||||
return @ptrCast(ReturnType, &ptr[start]);
|
||||
}
|
||||
|
||||
test "subArrayPtr" {
|
||||
const a1: [6]u8 = "abcdef".*;
|
||||
const sub1 = subArrayPtr(&a1, 2, 3);
|
||||
testing.expect(eql(u8, sub1, "cde"));
|
||||
|
||||
var a2: [6]u8 = "abcdef".*;
|
||||
var sub2 = subArrayPtr(&a2, 2, 3);
|
||||
|
||||
testing.expect(eql(u8, sub2, "cde"));
|
||||
sub2[1] = 'X';
|
||||
testing.expect(eql(u8, &a2, "abcXef"));
|
||||
}
|
||||
|
||||
/// Round an address up to the nearest aligned address
|
||||
/// The alignment must be a power of 2 and greater than 0.
|
||||
pub fn alignForward(addr: usize, alignment: usize) usize {
|
||||
|
|
|
@ -104,7 +104,7 @@ pub fn Child(comptime T: type) type {
|
|||
.Array => |info| info.child,
|
||||
.Pointer => |info| info.child,
|
||||
.Optional => |info| info.child,
|
||||
else => @compileError("Expected pointer, optional, or array type, " ++ "found '" ++ @typeName(T) ++ "'"),
|
||||
else => @compileError("Expected pointer, optional, or array type, found '" ++ @typeName(T) ++ "'"),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -115,30 +115,65 @@ test "std.meta.Child" {
|
|||
testing.expect(Child(?u8) == u8);
|
||||
}
|
||||
|
||||
/// Given a type with a sentinel e.g. `[:0]u8`, returns the sentinel
|
||||
pub fn Sentinel(comptime T: type) Child(T) {
|
||||
// comptime asserts that ptr has a sentinel
|
||||
/// Given a "memory span" type, returns the "element type".
|
||||
pub fn Elem(comptime T: type) type {
|
||||
switch (@typeInfo(T)) {
|
||||
.Array => |arrayInfo| {
|
||||
return comptime arrayInfo.sentinel.?;
|
||||
.Array => |info| return info.child,
|
||||
.Pointer => |info| switch (info.size) {
|
||||
.One => switch (@typeInfo(info.child)) {
|
||||
.Array => |array_info| return array_info.child,
|
||||
else => {},
|
||||
},
|
||||
.Many, .C, .Slice => return info.child,
|
||||
},
|
||||
.Pointer => |ptrInfo| {
|
||||
switch (ptrInfo.size) {
|
||||
.Many, .Slice => {
|
||||
return comptime ptrInfo.sentinel.?;
|
||||
else => {},
|
||||
}
|
||||
@compileError("Expected pointer, slice, or array, found '" ++ @typeName(T) ++ "'");
|
||||
}
|
||||
|
||||
test "std.meta.Elem" {
|
||||
testing.expect(Elem([1]u8) == u8);
|
||||
testing.expect(Elem([*]u8) == u8);
|
||||
testing.expect(Elem([]u8) == u8);
|
||||
testing.expect(Elem(*[10]u8) == u8);
|
||||
}
|
||||
|
||||
/// Given a type which can have a sentinel e.g. `[:0]u8`, returns the sentinel value,
|
||||
/// or `null` if there is not one.
|
||||
/// Types which cannot possibly have a sentinel will be a compile error.
|
||||
pub fn sentinel(comptime T: type) ?Elem(T) {
|
||||
switch (@typeInfo(T)) {
|
||||
.Array => |info| return info.sentinel,
|
||||
.Pointer => |info| {
|
||||
switch (info.size) {
|
||||
.Many, .Slice => return info.sentinel,
|
||||
.One => switch (@typeInfo(info.child)) {
|
||||
.Array => |array_info| return array_info.sentinel,
|
||||
else => {},
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
@compileError("not a sentinel type, found '" ++ @typeName(T) ++ "'");
|
||||
@compileError("type '" ++ @typeName(T) ++ "' cannot possibly have a sentinel");
|
||||
}
|
||||
|
||||
test "std.meta.Sentinel" {
|
||||
testing.expectEqual(@as(u8, 0), Sentinel([:0]u8));
|
||||
testing.expectEqual(@as(u8, 0), Sentinel([*:0]u8));
|
||||
testing.expectEqual(@as(u8, 0), Sentinel([5:0]u8));
|
||||
test "std.meta.sentinel" {
|
||||
testSentinel();
|
||||
comptime testSentinel();
|
||||
}
|
||||
|
||||
fn testSentinel() void {
|
||||
testing.expectEqual(@as(u8, 0), sentinel([:0]u8).?);
|
||||
testing.expectEqual(@as(u8, 0), sentinel([*:0]u8).?);
|
||||
testing.expectEqual(@as(u8, 0), sentinel([5:0]u8).?);
|
||||
testing.expectEqual(@as(u8, 0), sentinel(*const [5:0]u8).?);
|
||||
|
||||
testing.expect(sentinel([]u8) == null);
|
||||
testing.expect(sentinel([*]u8) == null);
|
||||
testing.expect(sentinel([5]u8) == null);
|
||||
testing.expect(sentinel(*const [5]u8) == null);
|
||||
}
|
||||
|
||||
pub fn containerLayout(comptime T: type) TypeInfo.ContainerLayout {
|
||||
|
|
|
@ -230,9 +230,10 @@ pub fn isSingleItemPtr(comptime T: type) bool {
|
|||
|
||||
test "std.meta.trait.isSingleItemPtr" {
|
||||
const array = [_]u8{0} ** 10;
|
||||
testing.expect(isSingleItemPtr(@TypeOf(&array[0])));
|
||||
testing.expect(!isSingleItemPtr(@TypeOf(array)));
|
||||
testing.expect(!isSingleItemPtr(@TypeOf(array[0..1])));
|
||||
comptime testing.expect(isSingleItemPtr(@TypeOf(&array[0])));
|
||||
comptime testing.expect(!isSingleItemPtr(@TypeOf(array)));
|
||||
var runtime_zero: usize = 0;
|
||||
testing.expect(!isSingleItemPtr(@TypeOf(array[runtime_zero..1])));
|
||||
}
|
||||
|
||||
pub fn isManyItemPtr(comptime T: type) bool {
|
||||
|
@ -259,7 +260,8 @@ pub fn isSlice(comptime T: type) bool {
|
|||
|
||||
test "std.meta.trait.isSlice" {
|
||||
const array = [_]u8{0} ** 10;
|
||||
testing.expect(isSlice(@TypeOf(array[0..])));
|
||||
var runtime_zero: usize = 0;
|
||||
testing.expect(isSlice(@TypeOf(array[runtime_zero..])));
|
||||
testing.expect(!isSlice(@TypeOf(array)));
|
||||
testing.expect(!isSlice(@TypeOf(&array[0])));
|
||||
}
|
||||
|
@ -276,7 +278,7 @@ pub fn isIndexable(comptime T: type) bool {
|
|||
|
||||
test "std.meta.trait.isIndexable" {
|
||||
const array = [_]u8{0} ** 10;
|
||||
const slice = array[0..];
|
||||
const slice = @as([]const u8, &array);
|
||||
|
||||
testing.expect(isIndexable(@TypeOf(array)));
|
||||
testing.expect(isIndexable(@TypeOf(&array)));
|
||||
|
|
|
@ -612,8 +612,7 @@ fn linuxLookupName(
|
|||
} else {
|
||||
mem.copy(u8, &sa6.addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff");
|
||||
mem.copy(u8, &da6.addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff");
|
||||
// TODO https://github.com/ziglang/zig/issues/863
|
||||
mem.writeIntNative(u32, @ptrCast(*[4]u8, da6.addr[12..].ptr), addr.addr.in.addr);
|
||||
mem.writeIntNative(u32, da6.addr[12..], addr.addr.in.addr);
|
||||
da4.addr = addr.addr.in.addr;
|
||||
da = @ptrCast(*os.sockaddr, &da4);
|
||||
dalen = @sizeOf(os.sockaddr_in);
|
||||
|
@ -821,7 +820,7 @@ fn linuxLookupNameFromHosts(
|
|||
// Skip to the delimiter in the stream, to fix parsing
|
||||
try stream.skipUntilDelimiterOrEof('\n');
|
||||
// Use the truncated line. A truncated comment or hostname will be handled correctly.
|
||||
break :blk line_buf[0..];
|
||||
break :blk @as([]u8, &line_buf); // TODO the cast should not be necessary
|
||||
},
|
||||
else => |e| return e,
|
||||
}) |line| {
|
||||
|
@ -958,7 +957,10 @@ fn linuxLookupNameFromDns(
|
|||
}
|
||||
}
|
||||
|
||||
var ap = [2][]u8{ apbuf[0][0..0], apbuf[1][0..0] };
|
||||
var ap = [2][]u8{ apbuf[0], apbuf[1] };
|
||||
ap[0].len = 0;
|
||||
ap[1].len = 0;
|
||||
|
||||
try resMSendRc(qp[0..nq], ap[0..nq], apbuf[0..nq], rc);
|
||||
|
||||
var i: usize = 0;
|
||||
|
@ -1015,7 +1017,7 @@ fn getResolvConf(allocator: *mem.Allocator, rc: *ResolvConf) !void {
|
|||
// Skip to the delimiter in the stream, to fix parsing
|
||||
try stream.skipUntilDelimiterOrEof('\n');
|
||||
// Give an empty line to the while loop, which will be skipped.
|
||||
break :blk line_buf[0..0];
|
||||
break :blk @as([]u8, line_buf[0..0]); // TODO the cast should not be necessary
|
||||
},
|
||||
else => |e| return e,
|
||||
}) |line| {
|
||||
|
|
|
@ -1276,7 +1276,15 @@ pub fn unexpectedError(err: Win32Error) std.os.UnexpectedError {
|
|||
// 614 is the length of the longest windows error desciption
|
||||
var buf_u16: [614]u16 = undefined;
|
||||
var buf_u8: [614]u8 = undefined;
|
||||
var len = kernel32.FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, null, err, MAKELANGID(LANG.NEUTRAL, SUBLANG.DEFAULT), buf_u16[0..].ptr, buf_u16.len / @sizeOf(TCHAR), null);
|
||||
const len = kernel32.FormatMessageW(
|
||||
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
null,
|
||||
err,
|
||||
MAKELANGID(LANG.NEUTRAL, SUBLANG.DEFAULT),
|
||||
&buf_u16,
|
||||
buf_u16.len / @sizeOf(TCHAR),
|
||||
null,
|
||||
);
|
||||
_ = std.unicode.utf16leToUtf8(&buf_u8, buf_u16[0..len]) catch unreachable;
|
||||
std.debug.warn("error.Unexpected: GetLastError({}): {}\n", .{ @enumToInt(err), buf_u8[0..len] });
|
||||
std.debug.dumpCurrentStackTrace(null);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
// ```
|
||||
// var buf: [8]u8 = undefined;
|
||||
// try std.crypto.randomBytes(buf[0..]);
|
||||
// const seed = mem.readIntSliceLittle(u64, buf[0..8]);
|
||||
// const seed = mem.readIntLittle(u64, buf[0..8]);
|
||||
//
|
||||
// var r = DefaultPrng.init(seed);
|
||||
//
|
||||
|
|
|
@ -251,12 +251,12 @@ pub const Utf16LeIterator = struct {
|
|||
pub fn nextCodepoint(it: *Utf16LeIterator) !?u21 {
|
||||
assert(it.i <= it.bytes.len);
|
||||
if (it.i == it.bytes.len) return null;
|
||||
const c0: u21 = mem.readIntSliceLittle(u16, it.bytes[it.i .. it.i + 2]);
|
||||
const c0: u21 = mem.readIntLittle(u16, it.bytes[it.i..][0..2]);
|
||||
if (c0 & ~@as(u21, 0x03ff) == 0xd800) {
|
||||
// surrogate pair
|
||||
it.i += 2;
|
||||
if (it.i >= it.bytes.len) return error.DanglingSurrogateHalf;
|
||||
const c1: u21 = mem.readIntSliceLittle(u16, it.bytes[it.i .. it.i + 2]);
|
||||
const c1: u21 = mem.readIntLittle(u16, it.bytes[it.i..][0..2]);
|
||||
if (c1 & ~@as(u21, 0x03ff) != 0xdc00) return error.ExpectedSecondSurrogateHalf;
|
||||
it.i += 2;
|
||||
return 0x10000 + (((c0 & 0x03ff) << 10) | (c1 & 0x03ff));
|
||||
|
@ -630,11 +630,11 @@ test "utf8ToUtf16LeWithNull" {
|
|||
}
|
||||
}
|
||||
|
||||
/// Converts a UTF-8 string literal into a UTF-16LE string literal.
|
||||
pub fn utf8ToUtf16LeStringLiteral(comptime utf8: []const u8) *const [calcUtf16LeLen(utf8) :0] u16 {
|
||||
/// Converts a UTF-8 string literal into a UTF-16LE string literal.
|
||||
pub fn utf8ToUtf16LeStringLiteral(comptime utf8: []const u8) *const [calcUtf16LeLen(utf8):0]u16 {
|
||||
comptime {
|
||||
const len: usize = calcUtf16LeLen(utf8);
|
||||
var utf16le: [len :0]u16 = [_ :0]u16{0} ** len;
|
||||
var utf16le: [len:0]u16 = [_:0]u16{0} ** len;
|
||||
const utf16le_len = utf8ToUtf16Le(&utf16le, utf8[0..]) catch |err| @compileError(err);
|
||||
assert(len == utf16le_len);
|
||||
return &utf16le;
|
||||
|
@ -660,8 +660,8 @@ fn calcUtf16LeLen(utf8: []const u8) usize {
|
|||
}
|
||||
|
||||
test "utf8ToUtf16LeStringLiteral" {
|
||||
{
|
||||
const bytes = [_:0]u16{ 0x41 };
|
||||
{
|
||||
const bytes = [_:0]u16{0x41};
|
||||
const utf16 = utf8ToUtf16LeStringLiteral("A");
|
||||
testing.expectEqualSlices(u16, &bytes, utf16);
|
||||
testing.expect(utf16[1] == 0);
|
||||
|
@ -673,19 +673,19 @@ test "utf8ToUtf16LeStringLiteral" {
|
|||
testing.expect(utf16[2] == 0);
|
||||
}
|
||||
{
|
||||
const bytes = [_:0]u16{ 0x02FF };
|
||||
const bytes = [_:0]u16{0x02FF};
|
||||
const utf16 = utf8ToUtf16LeStringLiteral("\u{02FF}");
|
||||
testing.expectEqualSlices(u16, &bytes, utf16);
|
||||
testing.expect(utf16[1] == 0);
|
||||
}
|
||||
{
|
||||
const bytes = [_:0]u16{ 0x7FF };
|
||||
const bytes = [_:0]u16{0x7FF};
|
||||
const utf16 = utf8ToUtf16LeStringLiteral("\u{7FF}");
|
||||
testing.expectEqualSlices(u16, &bytes, utf16);
|
||||
testing.expect(utf16[1] == 0);
|
||||
}
|
||||
{
|
||||
const bytes = [_:0]u16{ 0x801 };
|
||||
const bytes = [_:0]u16{0x801};
|
||||
const utf16 = utf8ToUtf16LeStringLiteral("\u{801}");
|
||||
testing.expectEqualSlices(u16, &bytes, utf16);
|
||||
testing.expect(utf16[1] == 0);
|
||||
|
|
|
@ -128,7 +128,7 @@ export fn stage2_translate_c(
|
|||
args_end: [*]?[*]const u8,
|
||||
resources_path: [*:0]const u8,
|
||||
) Error {
|
||||
var errors = @as([*]translate_c.ClangErrMsg, undefined)[0..0];
|
||||
var errors: []translate_c.ClangErrMsg = &[0]translate_c.ClangErrMsg{};
|
||||
out_ast.* = translate_c.translate(std.heap.c_allocator, args_begin, args_end, &errors, resources_path) catch |err| switch (err) {
|
||||
error.SemanticAnalyzeFail => {
|
||||
out_errors_ptr.* = errors.ptr;
|
||||
|
|
|
@ -1744,20 +1744,18 @@ fn writeEscapedString(buf: []u8, s: []const u8) void {
|
|||
// Returns either a string literal or a slice of `buf`.
|
||||
fn escapeChar(c: u8, char_buf: *[4]u8) []const u8 {
|
||||
return switch (c) {
|
||||
'\"' => "\\\""[0..],
|
||||
'\'' => "\\'"[0..],
|
||||
'\\' => "\\\\"[0..],
|
||||
'\n' => "\\n"[0..],
|
||||
'\r' => "\\r"[0..],
|
||||
'\t' => "\\t"[0..],
|
||||
else => {
|
||||
// Handle the remaining escapes Zig doesn't support by turning them
|
||||
// into their respective hex representation
|
||||
if (std.ascii.isCntrl(c))
|
||||
return std.fmt.bufPrint(char_buf[0..], "\\x{x:0<2}", .{c}) catch unreachable
|
||||
else
|
||||
return std.fmt.bufPrint(char_buf[0..], "{c}", .{c}) catch unreachable;
|
||||
},
|
||||
'\"' => "\\\"",
|
||||
'\'' => "\\'",
|
||||
'\\' => "\\\\",
|
||||
'\n' => "\\n",
|
||||
'\r' => "\\r",
|
||||
'\t' => "\\t",
|
||||
// Handle the remaining escapes Zig doesn't support by turning them
|
||||
// into their respective hex representation
|
||||
else => if (std.ascii.isCntrl(c))
|
||||
std.fmt.bufPrint(char_buf, "\\x{x:0<2}", .{c}) catch unreachable
|
||||
else
|
||||
std.fmt.bufPrint(char_buf, "{c}", .{c}) catch unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -231,6 +231,7 @@ enum ConstPtrSpecial {
|
|||
// The pointer is a reference to a single object.
|
||||
ConstPtrSpecialRef,
|
||||
// The pointer points to an element in an underlying array.
|
||||
// Not to be confused with ConstPtrSpecialSubArray.
|
||||
ConstPtrSpecialBaseArray,
|
||||
// The pointer points to a field in an underlying struct.
|
||||
ConstPtrSpecialBaseStruct,
|
||||
|
@ -257,6 +258,10 @@ enum ConstPtrSpecial {
|
|||
// types to be the same, so all optionals of pointer types use x_ptr
|
||||
// instead of x_optional.
|
||||
ConstPtrSpecialNull,
|
||||
// The pointer points to a sub-array (not an individual element).
|
||||
// Not to be confused with ConstPtrSpecialBaseArray. However, it uses the same
|
||||
// union payload struct (base_array).
|
||||
ConstPtrSpecialSubArray,
|
||||
};
|
||||
|
||||
enum ConstPtrMut {
|
||||
|
@ -3706,6 +3711,7 @@ struct IrInstGenSlice {
|
|||
IrInstGen *start;
|
||||
IrInstGen *end;
|
||||
IrInstGen *result_loc;
|
||||
ZigValue *sentinel;
|
||||
bool safety_check_on;
|
||||
};
|
||||
|
||||
|
|
|
@ -780,6 +780,8 @@ ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payloa
|
|||
}
|
||||
|
||||
ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, ZigValue *sentinel) {
|
||||
Error err;
|
||||
|
||||
TypeId type_id = {};
|
||||
type_id.id = ZigTypeIdArray;
|
||||
type_id.data.array.codegen = g;
|
||||
|
@ -791,7 +793,11 @@ ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, Zi
|
|||
return existing_entry->value;
|
||||
}
|
||||
|
||||
assert(type_is_resolved(child_type, ResolveStatusSizeKnown));
|
||||
size_t full_array_size = array_size + ((sentinel != nullptr) ? 1 : 0);
|
||||
|
||||
if (full_array_size != 0 && (err = type_resolve(g, child_type, ResolveStatusSizeKnown))) {
|
||||
codegen_report_errors_and_exit(g);
|
||||
}
|
||||
|
||||
ZigType *entry = new_type_table_entry(ZigTypeIdArray);
|
||||
|
||||
|
@ -803,9 +809,8 @@ ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, Zi
|
|||
}
|
||||
buf_appendf(&entry->name, "]%s", buf_ptr(&child_type->name));
|
||||
|
||||
size_t full_array_size = array_size + ((sentinel != nullptr) ? 1 : 0);
|
||||
entry->size_in_bits = child_type->size_in_bits * full_array_size;
|
||||
entry->abi_align = child_type->abi_align;
|
||||
entry->abi_align = (full_array_size == 0) ? 0 : child_type->abi_align;
|
||||
entry->abi_size = child_type->abi_size * full_array_size;
|
||||
|
||||
entry->data.array.child_type = child_type;
|
||||
|
@ -4483,7 +4488,14 @@ static uint32_t get_async_frame_align_bytes(CodeGen *g) {
|
|||
}
|
||||
|
||||
uint32_t get_ptr_align(CodeGen *g, ZigType *type) {
|
||||
ZigType *ptr_type = get_src_ptr_type(type);
|
||||
ZigType *ptr_type;
|
||||
if (type->id == ZigTypeIdStruct) {
|
||||
assert(type->data.structure.special == StructSpecialSlice);
|
||||
TypeStructField *ptr_field = type->data.structure.fields[slice_ptr_index];
|
||||
ptr_type = resolve_struct_field_type(g, ptr_field);
|
||||
} else {
|
||||
ptr_type = get_src_ptr_type(type);
|
||||
}
|
||||
if (ptr_type->id == ZigTypeIdPointer) {
|
||||
return (ptr_type->data.pointer.explicit_alignment == 0) ?
|
||||
get_abi_alignment(g, ptr_type->data.pointer.child_type) : ptr_type->data.pointer.explicit_alignment;
|
||||
|
@ -4500,8 +4512,15 @@ uint32_t get_ptr_align(CodeGen *g, ZigType *type) {
|
|||
}
|
||||
}
|
||||
|
||||
bool get_ptr_const(ZigType *type) {
|
||||
ZigType *ptr_type = get_src_ptr_type(type);
|
||||
bool get_ptr_const(CodeGen *g, ZigType *type) {
|
||||
ZigType *ptr_type;
|
||||
if (type->id == ZigTypeIdStruct) {
|
||||
assert(type->data.structure.special == StructSpecialSlice);
|
||||
TypeStructField *ptr_field = type->data.structure.fields[slice_ptr_index];
|
||||
ptr_type = resolve_struct_field_type(g, ptr_field);
|
||||
} else {
|
||||
ptr_type = get_src_ptr_type(type);
|
||||
}
|
||||
if (ptr_type->id == ZigTypeIdPointer) {
|
||||
return ptr_type->data.pointer.is_const;
|
||||
} else if (ptr_type->id == ZigTypeIdFn) {
|
||||
|
@ -5277,6 +5296,11 @@ static uint32_t hash_const_val_ptr(ZigValue *const_val) {
|
|||
hash_val += hash_ptr(const_val->data.x_ptr.data.base_array.array_val);
|
||||
hash_val += hash_size(const_val->data.x_ptr.data.base_array.elem_index);
|
||||
return hash_val;
|
||||
case ConstPtrSpecialSubArray:
|
||||
hash_val += (uint32_t)2643358777;
|
||||
hash_val += hash_ptr(const_val->data.x_ptr.data.base_array.array_val);
|
||||
hash_val += hash_size(const_val->data.x_ptr.data.base_array.elem_index);
|
||||
return hash_val;
|
||||
case ConstPtrSpecialBaseStruct:
|
||||
hash_val += (uint32_t)3518317043;
|
||||
hash_val += hash_ptr(const_val->data.x_ptr.data.base_struct.struct_val);
|
||||
|
@ -6743,6 +6767,7 @@ bool const_values_equal_ptr(ZigValue *a, ZigValue *b) {
|
|||
return false;
|
||||
return true;
|
||||
case ConstPtrSpecialBaseArray:
|
||||
case ConstPtrSpecialSubArray:
|
||||
if (a->data.x_ptr.data.base_array.array_val != b->data.x_ptr.data.base_array.array_val) {
|
||||
return false;
|
||||
}
|
||||
|
@ -7000,6 +7025,7 @@ static void render_const_val_ptr(CodeGen *g, Buf *buf, ZigValue *const_val, ZigT
|
|||
render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr));
|
||||
return;
|
||||
case ConstPtrSpecialBaseArray:
|
||||
case ConstPtrSpecialSubArray:
|
||||
buf_appendf(buf, "*");
|
||||
// TODO we need a source node for const_ptr_pointee because it can generate compile errors
|
||||
render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr));
|
||||
|
|
|
@ -76,7 +76,7 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node, bool all
|
|||
|
||||
ZigType *get_src_ptr_type(ZigType *type);
|
||||
uint32_t get_ptr_align(CodeGen *g, ZigType *type);
|
||||
bool get_ptr_const(ZigType *type);
|
||||
bool get_ptr_const(CodeGen *g, ZigType *type);
|
||||
ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry);
|
||||
ZigType *container_ref_type(ZigType *type_entry);
|
||||
bool type_is_complete(ZigType *type_entry);
|
||||
|
|
|
@ -5418,12 +5418,16 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI
|
|||
ZigType *array_type = array_ptr_type->data.pointer.child_type;
|
||||
LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type, array_ptr_type);
|
||||
|
||||
LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc);
|
||||
|
||||
bool want_runtime_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base);
|
||||
|
||||
ZigType *res_slice_ptr_type = instruction->base.value->type->data.structure.fields[slice_ptr_index]->type_entry;
|
||||
ZigValue *sentinel = res_slice_ptr_type->data.pointer.sentinel;
|
||||
ZigType *result_type = instruction->base.value->type;
|
||||
if (!type_has_bits(g, result_type)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// This is not whether the result type has a sentinel, but whether there should be a sentinel check,
|
||||
// e.g. if they used [a..b :s] syntax.
|
||||
ZigValue *sentinel = instruction->sentinel;
|
||||
|
||||
if (array_type->id == ZigTypeIdArray ||
|
||||
(array_type->id == ZigTypeIdPointer && array_type->data.pointer.ptr_len == PtrLenSingle))
|
||||
|
@ -5458,6 +5462,8 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI
|
|||
}
|
||||
}
|
||||
if (!type_has_bits(g, array_type)) {
|
||||
LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc);
|
||||
|
||||
LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, "");
|
||||
|
||||
// TODO if runtime safety is on, store 0xaaaaaaa in ptr field
|
||||
|
@ -5466,20 +5472,26 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI
|
|||
return tmp_struct_ptr;
|
||||
}
|
||||
|
||||
|
||||
LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_ptr_index, "");
|
||||
LLVMValueRef indices[] = {
|
||||
LLVMConstNull(g->builtin_types.entry_usize->llvm_type),
|
||||
start_val,
|
||||
};
|
||||
LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, "");
|
||||
gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false);
|
||||
if (result_type->id == ZigTypeIdPointer) {
|
||||
ir_assert(instruction->result_loc == nullptr, &instruction->base);
|
||||
LLVMTypeRef result_ptr_type = get_llvm_type(g, result_type);
|
||||
return LLVMBuildBitCast(g->builder, slice_start_ptr, result_ptr_type, "");
|
||||
} else {
|
||||
LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc);
|
||||
LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_ptr_index, "");
|
||||
gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false);
|
||||
|
||||
LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, "");
|
||||
LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, "");
|
||||
gen_store_untyped(g, len_value, len_field_ptr, 0, false);
|
||||
LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, "");
|
||||
LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, "");
|
||||
gen_store_untyped(g, len_value, len_field_ptr, 0, false);
|
||||
|
||||
return tmp_struct_ptr;
|
||||
return tmp_struct_ptr;
|
||||
}
|
||||
} else if (array_type->id == ZigTypeIdPointer) {
|
||||
assert(array_type->data.pointer.ptr_len != PtrLenSingle);
|
||||
LLVMValueRef start_val = ir_llvm_value(g, instruction->start);
|
||||
|
@ -5493,24 +5505,39 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI
|
|||
}
|
||||
}
|
||||
|
||||
if (type_has_bits(g, array_type)) {
|
||||
size_t gen_ptr_index = instruction->base.value->type->data.structure.fields[slice_ptr_index]->gen_index;
|
||||
LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_ptr_index, "");
|
||||
LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, &start_val, 1, "");
|
||||
gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false);
|
||||
if (!type_has_bits(g, array_type)) {
|
||||
LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc);
|
||||
size_t gen_len_index = result_type->data.structure.fields[slice_len_index]->gen_index;
|
||||
LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_len_index, "");
|
||||
LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, "");
|
||||
gen_store_untyped(g, len_value, len_field_ptr, 0, false);
|
||||
return tmp_struct_ptr;
|
||||
}
|
||||
|
||||
size_t gen_len_index = instruction->base.value->type->data.structure.fields[slice_len_index]->gen_index;
|
||||
LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, &start_val, 1, "");
|
||||
if (result_type->id == ZigTypeIdPointer) {
|
||||
ir_assert(instruction->result_loc == nullptr, &instruction->base);
|
||||
LLVMTypeRef result_ptr_type = get_llvm_type(g, result_type);
|
||||
return LLVMBuildBitCast(g->builder, slice_start_ptr, result_ptr_type, "");
|
||||
}
|
||||
|
||||
LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc);
|
||||
|
||||
size_t gen_ptr_index = result_type->data.structure.fields[slice_ptr_index]->gen_index;
|
||||
LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_ptr_index, "");
|
||||
gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false);
|
||||
|
||||
size_t gen_len_index = result_type->data.structure.fields[slice_len_index]->gen_index;
|
||||
LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_len_index, "");
|
||||
LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, "");
|
||||
gen_store_untyped(g, len_value, len_field_ptr, 0, false);
|
||||
|
||||
return tmp_struct_ptr;
|
||||
|
||||
} else if (array_type->id == ZigTypeIdStruct) {
|
||||
assert(array_type->data.structure.special == StructSpecialSlice);
|
||||
assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind);
|
||||
assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind);
|
||||
assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(tmp_struct_ptr))) == LLVMStructTypeKind);
|
||||
|
||||
size_t ptr_index = array_type->data.structure.fields[slice_ptr_index]->gen_index;
|
||||
assert(ptr_index != SIZE_MAX);
|
||||
|
@ -5547,15 +5574,22 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI
|
|||
}
|
||||
}
|
||||
|
||||
LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, (unsigned)ptr_index, "");
|
||||
LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr, &start_val, 1, "");
|
||||
gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false);
|
||||
if (result_type->id == ZigTypeIdPointer) {
|
||||
ir_assert(instruction->result_loc == nullptr, &instruction->base);
|
||||
LLVMTypeRef result_ptr_type = get_llvm_type(g, result_type);
|
||||
return LLVMBuildBitCast(g->builder, slice_start_ptr, result_ptr_type, "");
|
||||
} else {
|
||||
LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc);
|
||||
LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, (unsigned)ptr_index, "");
|
||||
gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false);
|
||||
|
||||
LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, (unsigned)len_index, "");
|
||||
LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, "");
|
||||
gen_store_untyped(g, len_value, len_field_ptr, 0, false);
|
||||
LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, (unsigned)len_index, "");
|
||||
LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, "");
|
||||
gen_store_untyped(g, len_value, len_field_ptr, 0, false);
|
||||
|
||||
return tmp_struct_ptr;
|
||||
return tmp_struct_ptr;
|
||||
}
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
|
@ -6640,7 +6674,6 @@ static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ZigValue *array_co
|
|||
};
|
||||
return LLVMConstInBoundsGEP(base_ptr, indices, 2);
|
||||
} else {
|
||||
assert(parent->id == ConstParentIdScalar);
|
||||
return base_ptr;
|
||||
}
|
||||
}
|
||||
|
@ -6868,6 +6901,7 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ZigValue *const_val, const cha
|
|||
return const_val->llvm_value;
|
||||
}
|
||||
case ConstPtrSpecialBaseArray:
|
||||
case ConstPtrSpecialSubArray:
|
||||
{
|
||||
ZigValue *array_const_val = const_val->data.x_ptr.data.base_array.array_val;
|
||||
assert(array_const_val->type->id == ZigTypeIdArray);
|
||||
|
|
415
src/ir.cpp
415
src/ir.cpp
|
@ -784,14 +784,32 @@ static ZigValue *const_ptr_pointee_unchecked_no_isf(CodeGen *g, ZigValue *const_
|
|||
break;
|
||||
case ConstPtrSpecialBaseArray: {
|
||||
ZigValue *array_val = const_val->data.x_ptr.data.base_array.array_val;
|
||||
if (const_val->data.x_ptr.data.base_array.elem_index == array_val->type->data.array.len) {
|
||||
size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index;
|
||||
if (elem_index == array_val->type->data.array.len) {
|
||||
result = array_val->type->data.array.sentinel;
|
||||
} else {
|
||||
expand_undef_array(g, array_val);
|
||||
result = &array_val->data.x_array.data.s_none.elements[const_val->data.x_ptr.data.base_array.elem_index];
|
||||
result = &array_val->data.x_array.data.s_none.elements[elem_index];
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ConstPtrSpecialSubArray: {
|
||||
ZigValue *array_val = const_val->data.x_ptr.data.base_array.array_val;
|
||||
size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index;
|
||||
|
||||
// TODO handle sentinel terminated arrays
|
||||
expand_undef_array(g, array_val);
|
||||
result = g->pass1_arena->create<ZigValue>();
|
||||
result->special = array_val->special;
|
||||
result->type = get_array_type(g, array_val->type->data.array.child_type,
|
||||
array_val->type->data.array.len - elem_index, nullptr);
|
||||
result->data.x_array.special = ConstArraySpecialNone;
|
||||
result->data.x_array.data.s_none.elements = &array_val->data.x_array.data.s_none.elements[elem_index];
|
||||
result->parent.id = ConstParentIdArray;
|
||||
result->parent.data.p_array.array_val = array_val;
|
||||
result->parent.data.p_array.elem_index = elem_index;
|
||||
break;
|
||||
}
|
||||
case ConstPtrSpecialBaseStruct: {
|
||||
ZigValue *struct_val = const_val->data.x_ptr.data.base_struct.struct_val;
|
||||
expand_undef_struct(g, struct_val);
|
||||
|
@ -849,11 +867,6 @@ static bool is_slice(ZigType *type) {
|
|||
return type->id == ZigTypeIdStruct && type->data.structure.special == StructSpecialSlice;
|
||||
}
|
||||
|
||||
static bool slice_is_const(ZigType *type) {
|
||||
assert(is_slice(type));
|
||||
return type->data.structure.fields[slice_ptr_index]->type_entry->data.pointer.is_const;
|
||||
}
|
||||
|
||||
// This function returns true when you can change the type of a ZigValue and the
|
||||
// value remains meaningful.
|
||||
static bool types_have_same_zig_comptime_repr(CodeGen *codegen, ZigType *expected, ZigType *actual) {
|
||||
|
@ -3719,7 +3732,8 @@ static IrInstSrc *ir_build_slice_src(IrBuilderSrc *irb, Scope *scope, AstNode *s
|
|||
}
|
||||
|
||||
static IrInstGen *ir_build_slice_gen(IrAnalyze *ira, IrInst *source_instruction, ZigType *slice_type,
|
||||
IrInstGen *ptr, IrInstGen *start, IrInstGen *end, bool safety_check_on, IrInstGen *result_loc)
|
||||
IrInstGen *ptr, IrInstGen *start, IrInstGen *end, bool safety_check_on, IrInstGen *result_loc,
|
||||
ZigValue *sentinel)
|
||||
{
|
||||
IrInstGenSlice *instruction = ir_build_inst_gen<IrInstGenSlice>(
|
||||
&ira->new_irb, source_instruction->scope, source_instruction->source_node);
|
||||
|
@ -3729,11 +3743,12 @@ static IrInstGen *ir_build_slice_gen(IrAnalyze *ira, IrInst *source_instruction,
|
|||
instruction->end = end;
|
||||
instruction->safety_check_on = safety_check_on;
|
||||
instruction->result_loc = result_loc;
|
||||
instruction->sentinel = sentinel;
|
||||
|
||||
ir_ref_inst_gen(ptr, ira->new_irb.current_basic_block);
|
||||
ir_ref_inst_gen(start, ira->new_irb.current_basic_block);
|
||||
if (end) ir_ref_inst_gen(end, ira->new_irb.current_basic_block);
|
||||
ir_ref_inst_gen(result_loc, ira->new_irb.current_basic_block);
|
||||
if (end != nullptr) ir_ref_inst_gen(end, ira->new_irb.current_basic_block);
|
||||
if (result_loc != nullptr) ir_ref_inst_gen(result_loc, ira->new_irb.current_basic_block);
|
||||
|
||||
return &instruction->base;
|
||||
}
|
||||
|
@ -12677,41 +12692,80 @@ static IrInstGen *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInst* sourc
|
|||
Error err;
|
||||
|
||||
assert(array_ptr->value->type->id == ZigTypeIdPointer);
|
||||
assert(array_ptr->value->type->data.pointer.child_type->id == ZigTypeIdArray);
|
||||
|
||||
ZigType *array_type = array_ptr->value->type->data.pointer.child_type;
|
||||
size_t array_len = array_type->data.array.len;
|
||||
|
||||
// A zero-sized array can be casted regardless of the destination alignment, or
|
||||
// whether the pointer is undefined, and the result is always comptime known.
|
||||
// TODO However, this is exposing a result location bug that I failed to solve on the first try.
|
||||
// If you want to try to fix the bug, uncomment this block and get the tests passing.
|
||||
//if (array_len == 0 && array_type->data.array.sentinel == nullptr) {
|
||||
// ZigValue *undef_array = ira->codegen->pass1_arena->create<ZigValue>();
|
||||
// undef_array->special = ConstValSpecialUndef;
|
||||
// undef_array->type = array_type;
|
||||
|
||||
// IrInstGen *result = ir_const(ira, source_instr, wanted_type);
|
||||
// init_const_slice(ira->codegen, result->value, undef_array, 0, 0, false);
|
||||
// result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = ConstPtrMutComptimeConst;
|
||||
// result->value->type = wanted_type;
|
||||
// return result;
|
||||
//}
|
||||
|
||||
if ((err = type_resolve(ira->codegen, array_ptr->value->type, ResolveStatusAlignmentKnown))) {
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
}
|
||||
|
||||
assert(array_ptr->value->type->data.pointer.child_type->id == ZigTypeIdArray);
|
||||
|
||||
const size_t array_len = array_ptr->value->type->data.pointer.child_type->data.array.len;
|
||||
|
||||
// A zero-sized array can always be casted irregardless of the destination
|
||||
// alignment
|
||||
if (array_len != 0) {
|
||||
wanted_type = adjust_slice_align(ira->codegen, wanted_type,
|
||||
get_ptr_align(ira->codegen, array_ptr->value->type));
|
||||
}
|
||||
|
||||
if (instr_is_comptime(array_ptr)) {
|
||||
ZigValue *array_ptr_val = ir_resolve_const(ira, array_ptr, UndefBad);
|
||||
UndefAllowed undef_allowed = (array_len == 0) ? UndefOk : UndefBad;
|
||||
ZigValue *array_ptr_val = ir_resolve_const(ira, array_ptr, undef_allowed);
|
||||
if (array_ptr_val == nullptr)
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
ZigValue *pointee = const_ptr_pointee(ira, ira->codegen, array_ptr_val, source_instr->source_node);
|
||||
if (pointee == nullptr)
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
if (pointee->special != ConstValSpecialRuntime) {
|
||||
assert(array_ptr_val->type->id == ZigTypeIdPointer);
|
||||
ZigType *array_type = array_ptr_val->type->data.pointer.child_type;
|
||||
assert(is_slice(wanted_type));
|
||||
bool is_const = wanted_type->data.structure.fields[slice_ptr_index]->type_entry->data.pointer.is_const;
|
||||
ir_assert(is_slice(wanted_type), source_instr);
|
||||
if (array_ptr_val->special == ConstValSpecialUndef) {
|
||||
ZigValue *undef_array = ira->codegen->pass1_arena->create<ZigValue>();
|
||||
undef_array->special = ConstValSpecialUndef;
|
||||
undef_array->type = array_type;
|
||||
|
||||
IrInstGen *result = ir_const(ira, source_instr, wanted_type);
|
||||
init_const_slice(ira->codegen, result->value, pointee, 0, array_type->data.array.len, is_const);
|
||||
result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = array_ptr_val->data.x_ptr.mut;
|
||||
init_const_slice(ira->codegen, result->value, undef_array, 0, 0, false);
|
||||
result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = ConstPtrMutComptimeConst;
|
||||
result->value->type = wanted_type;
|
||||
return result;
|
||||
}
|
||||
bool wanted_const = wanted_type->data.structure.fields[slice_ptr_index]->type_entry->data.pointer.is_const;
|
||||
// Optimization to avoid creating unnecessary ZigValue in const_ptr_pointee
|
||||
if (array_ptr_val->data.x_ptr.special == ConstPtrSpecialSubArray) {
|
||||
ZigValue *array_val = array_ptr_val->data.x_ptr.data.base_array.array_val;
|
||||
if (array_val->special != ConstValSpecialRuntime) {
|
||||
IrInstGen *result = ir_const(ira, source_instr, wanted_type);
|
||||
init_const_slice(ira->codegen, result->value, array_val,
|
||||
array_ptr_val->data.x_ptr.data.base_array.elem_index,
|
||||
array_type->data.array.len, wanted_const);
|
||||
result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = array_ptr_val->data.x_ptr.mut;
|
||||
result->value->type = wanted_type;
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
ZigValue *pointee = const_ptr_pointee(ira, ira->codegen, array_ptr_val, source_instr->source_node);
|
||||
if (pointee == nullptr)
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
if (pointee->special != ConstValSpecialRuntime) {
|
||||
assert(array_ptr_val->type->id == ZigTypeIdPointer);
|
||||
|
||||
IrInstGen *result = ir_const(ira, source_instr, wanted_type);
|
||||
init_const_slice(ira->codegen, result->value, pointee, 0, array_type->data.array.len, wanted_const);
|
||||
result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = array_ptr_val->data.x_ptr.mut;
|
||||
result->value->type = wanted_type;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result_loc == nullptr) result_loc = no_result_loc();
|
||||
|
@ -14581,7 +14635,7 @@ static IrInstGen *ir_analyze_cast(IrAnalyze *ira, IrInst *source_instr,
|
|||
return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type);
|
||||
}
|
||||
|
||||
// *[N]T to ?[]const T
|
||||
// *[N]T to ?[]T
|
||||
if (wanted_type->id == ZigTypeIdOptional &&
|
||||
is_slice(wanted_type->data.maybe.child_type) &&
|
||||
actual_type->id == ZigTypeIdPointer &&
|
||||
|
@ -19917,6 +19971,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source
|
|||
buf_write_value_bytes(codegen, (uint8_t*)buf_ptr(&buf), pointee);
|
||||
if ((err = buf_read_value_bytes(ira, codegen, source_node, (uint8_t*)buf_ptr(&buf), out_val)))
|
||||
return err;
|
||||
buf_deinit(&buf);
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
|
@ -19936,6 +19991,31 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source
|
|||
dst_size, buf_ptr(&pointee->type->name), src_size));
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
}
|
||||
case ConstPtrSpecialSubArray: {
|
||||
ZigValue *array_val = ptr_val->data.x_ptr.data.base_array.array_val;
|
||||
assert(array_val->type->id == ZigTypeIdArray);
|
||||
if (array_val->data.x_array.special != ConstArraySpecialNone)
|
||||
zig_panic("TODO");
|
||||
if (dst_size > src_size) {
|
||||
size_t elem_index = ptr_val->data.x_ptr.data.base_array.elem_index;
|
||||
opt_ir_add_error_node(ira, codegen, source_node,
|
||||
buf_sprintf("attempt to read %" ZIG_PRI_usize " bytes from %s at index %" ZIG_PRI_usize " which is %" ZIG_PRI_usize " bytes",
|
||||
dst_size, buf_ptr(&array_val->type->name), elem_index, src_size));
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
}
|
||||
size_t elem_size = src_size;
|
||||
size_t elem_count = (dst_size % elem_size == 0) ? (dst_size / elem_size) : (dst_size / elem_size + 1);
|
||||
Buf buf = BUF_INIT;
|
||||
buf_resize(&buf, elem_count * elem_size);
|
||||
for (size_t i = 0; i < elem_count; i += 1) {
|
||||
ZigValue *elem_val = &array_val->data.x_array.data.s_none.elements[i];
|
||||
buf_write_value_bytes(codegen, (uint8_t*)buf_ptr(&buf) + (i * elem_size), elem_val);
|
||||
}
|
||||
if ((err = buf_read_value_bytes(ira, codegen, source_node, (uint8_t*)buf_ptr(&buf), out_val)))
|
||||
return err;
|
||||
buf_deinit(&buf);
|
||||
return ErrorNone;
|
||||
}
|
||||
case ConstPtrSpecialBaseArray: {
|
||||
ZigValue *array_val = ptr_val->data.x_ptr.data.base_array.array_val;
|
||||
assert(array_val->type->id == ZigTypeIdArray);
|
||||
|
@ -19959,6 +20039,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source
|
|||
}
|
||||
if ((err = buf_read_value_bytes(ira, codegen, source_node, (uint8_t*)buf_ptr(&buf), out_val)))
|
||||
return err;
|
||||
buf_deinit(&buf);
|
||||
return ErrorNone;
|
||||
}
|
||||
case ConstPtrSpecialBaseStruct:
|
||||
|
@ -20538,6 +20619,44 @@ static ZigType *adjust_ptr_allow_zero(CodeGen *g, ZigType *ptr_type, bool allow_
|
|||
allow_zero);
|
||||
}
|
||||
|
||||
static Error compute_elem_align(IrAnalyze *ira, ZigType *elem_type, uint32_t base_ptr_align,
|
||||
uint64_t elem_index, uint32_t *result)
|
||||
{
|
||||
Error err;
|
||||
|
||||
if (base_ptr_align == 0) {
|
||||
*result = 0;
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
// figure out the largest alignment possible
|
||||
if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusSizeKnown)))
|
||||
return err;
|
||||
|
||||
uint64_t elem_size = type_size(ira->codegen, elem_type);
|
||||
uint64_t abi_align = get_abi_alignment(ira->codegen, elem_type);
|
||||
uint64_t ptr_align = base_ptr_align;
|
||||
|
||||
uint64_t chosen_align = abi_align;
|
||||
if (ptr_align >= abi_align) {
|
||||
while (ptr_align > abi_align) {
|
||||
if ((elem_index * elem_size) % ptr_align == 0) {
|
||||
chosen_align = ptr_align;
|
||||
break;
|
||||
}
|
||||
ptr_align >>= 1;
|
||||
}
|
||||
} else if (elem_size >= ptr_align && elem_size % ptr_align == 0) {
|
||||
chosen_align = ptr_align;
|
||||
} else {
|
||||
// can't get here because guaranteed elem_size >= abi_align
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
*result = chosen_align;
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemPtr *elem_ptr_instruction) {
|
||||
Error err;
|
||||
IrInstGen *array_ptr = elem_ptr_instruction->array_ptr->child;
|
||||
|
@ -20676,29 +20795,11 @@ static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemP
|
|||
get_ptr_align(ira->codegen, ptr_type), 0, host_vec_len, false, (uint32_t)index,
|
||||
nullptr, nullptr);
|
||||
} else if (return_type->data.pointer.explicit_alignment != 0) {
|
||||
// figure out the largest alignment possible
|
||||
|
||||
if ((err = type_resolve(ira->codegen, return_type->data.pointer.child_type, ResolveStatusSizeKnown)))
|
||||
uint32_t chosen_align;
|
||||
if ((err = compute_elem_align(ira, return_type->data.pointer.child_type,
|
||||
return_type->data.pointer.explicit_alignment, index, &chosen_align)))
|
||||
{
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
|
||||
uint64_t elem_size = type_size(ira->codegen, return_type->data.pointer.child_type);
|
||||
uint64_t abi_align = get_abi_alignment(ira->codegen, return_type->data.pointer.child_type);
|
||||
uint64_t ptr_align = get_ptr_align(ira->codegen, return_type);
|
||||
|
||||
uint64_t chosen_align = abi_align;
|
||||
if (ptr_align >= abi_align) {
|
||||
while (ptr_align > abi_align) {
|
||||
if ((index * elem_size) % ptr_align == 0) {
|
||||
chosen_align = ptr_align;
|
||||
break;
|
||||
}
|
||||
ptr_align >>= 1;
|
||||
}
|
||||
} else if (elem_size >= ptr_align && elem_size % ptr_align == 0) {
|
||||
chosen_align = ptr_align;
|
||||
} else {
|
||||
// can't get here because guaranteed elem_size >= abi_align
|
||||
zig_unreachable();
|
||||
}
|
||||
return_type = adjust_ptr_align(ira->codegen, return_type, chosen_align);
|
||||
}
|
||||
|
@ -20819,6 +20920,7 @@ static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemP
|
|||
}
|
||||
break;
|
||||
case ConstPtrSpecialBaseArray:
|
||||
case ConstPtrSpecialSubArray:
|
||||
{
|
||||
size_t offset = array_ptr_val->data.x_ptr.data.base_array.elem_index;
|
||||
new_index = offset + index;
|
||||
|
@ -20889,6 +20991,7 @@ static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemP
|
|||
out_val->data.x_ptr.special = ConstPtrSpecialRef;
|
||||
out_val->data.x_ptr.data.ref.pointee = ptr_field->data.x_ptr.data.ref.pointee;
|
||||
break;
|
||||
case ConstPtrSpecialSubArray:
|
||||
case ConstPtrSpecialBaseArray:
|
||||
{
|
||||
size_t offset = ptr_field->data.x_ptr.data.base_array.elem_index;
|
||||
|
@ -25440,11 +25543,22 @@ static IrInstGen *ir_analyze_instruction_err_set_cast(IrAnalyze *ira, IrInstSrcE
|
|||
static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align) {
|
||||
Error err;
|
||||
|
||||
ZigType *ptr_type = get_src_ptr_type(ty);
|
||||
ZigType *ptr_type;
|
||||
if (is_slice(ty)) {
|
||||
TypeStructField *ptr_field = ty->data.structure.fields[slice_ptr_index];
|
||||
ptr_type = resolve_struct_field_type(ira->codegen, ptr_field);
|
||||
} else {
|
||||
ptr_type = get_src_ptr_type(ty);
|
||||
}
|
||||
assert(ptr_type != nullptr);
|
||||
if (ptr_type->id == ZigTypeIdPointer) {
|
||||
if ((err = type_resolve(ira->codegen, ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown)))
|
||||
return err;
|
||||
} else if (is_slice(ptr_type)) {
|
||||
TypeStructField *ptr_field = ptr_type->data.structure.fields[slice_ptr_index];
|
||||
ZigType *slice_ptr_type = resolve_struct_field_type(ira->codegen, ptr_field);
|
||||
if ((err = type_resolve(ira->codegen, slice_ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown)))
|
||||
return err;
|
||||
}
|
||||
|
||||
*result_align = get_ptr_align(ira->codegen, ty);
|
||||
|
@ -25899,6 +26013,7 @@ static IrInstGen *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstSrcMemset
|
|||
start = 0;
|
||||
bound_end = 1;
|
||||
break;
|
||||
case ConstPtrSpecialSubArray:
|
||||
case ConstPtrSpecialBaseArray:
|
||||
{
|
||||
ZigValue *array_val = dest_ptr_val->data.x_ptr.data.base_array.array_val;
|
||||
|
@ -26032,6 +26147,7 @@ static IrInstGen *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstSrcMemcpy
|
|||
dest_start = 0;
|
||||
dest_end = 1;
|
||||
break;
|
||||
case ConstPtrSpecialSubArray:
|
||||
case ConstPtrSpecialBaseArray:
|
||||
{
|
||||
ZigValue *array_val = dest_ptr_val->data.x_ptr.data.base_array.array_val;
|
||||
|
@ -26075,6 +26191,7 @@ static IrInstGen *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstSrcMemcpy
|
|||
src_start = 0;
|
||||
src_end = 1;
|
||||
break;
|
||||
case ConstPtrSpecialSubArray:
|
||||
case ConstPtrSpecialBaseArray:
|
||||
{
|
||||
ZigValue *array_val = src_ptr_val->data.x_ptr.data.base_array.array_val;
|
||||
|
@ -26118,7 +26235,19 @@ static IrInstGen *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstSrcMemcpy
|
|||
return ir_build_memcpy_gen(ira, &instruction->base.base, casted_dest_ptr, casted_src_ptr, casted_count);
|
||||
}
|
||||
|
||||
static ZigType *get_result_loc_type(IrAnalyze *ira, ResultLoc *result_loc) {
|
||||
if (result_loc == nullptr) return nullptr;
|
||||
|
||||
if (result_loc->id == ResultLocIdCast) {
|
||||
return ir_resolve_type(ira, result_loc->source_instruction->child);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *instruction) {
|
||||
Error err;
|
||||
|
||||
IrInstGen *ptr_ptr = instruction->ptr->child;
|
||||
if (type_is_invalid(ptr_ptr->value->type))
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
|
@ -26148,6 +26277,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
|
|||
end = nullptr;
|
||||
}
|
||||
|
||||
ZigValue *slice_sentinel_val = nullptr;
|
||||
ZigType *non_sentinel_slice_ptr_type;
|
||||
ZigType *elem_type;
|
||||
|
||||
|
@ -26198,6 +26328,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
|
|||
}
|
||||
} else if (is_slice(array_type)) {
|
||||
ZigType *maybe_sentineled_slice_ptr_type = array_type->data.structure.fields[slice_ptr_index]->type_entry;
|
||||
slice_sentinel_val = maybe_sentineled_slice_ptr_type->data.pointer.sentinel;
|
||||
non_sentinel_slice_ptr_type = adjust_ptr_sentinel(ira->codegen, maybe_sentineled_slice_ptr_type, nullptr);
|
||||
elem_type = non_sentinel_slice_ptr_type->data.pointer.child_type;
|
||||
} else {
|
||||
|
@ -26206,7 +26337,6 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
|
|||
return ira->codegen->invalid_inst_gen;
|
||||
}
|
||||
|
||||
ZigType *return_type;
|
||||
ZigValue *sentinel_val = nullptr;
|
||||
if (instruction->sentinel) {
|
||||
IrInstGen *uncasted_sentinel = instruction->sentinel->child;
|
||||
|
@ -26218,11 +26348,76 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
|
|||
sentinel_val = ir_resolve_const(ira, sentinel, UndefBad);
|
||||
if (sentinel_val == nullptr)
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
ZigType *slice_ptr_type = adjust_ptr_sentinel(ira->codegen, non_sentinel_slice_ptr_type, sentinel_val);
|
||||
}
|
||||
|
||||
ZigType *child_array_type = (array_type->id == ZigTypeIdPointer &&
|
||||
array_type->data.pointer.ptr_len == PtrLenSingle) ? array_type->data.pointer.child_type : array_type;
|
||||
|
||||
ZigType *return_type;
|
||||
|
||||
// If start index and end index are both comptime known, then the result type is a pointer to array
|
||||
// not a slice. However, if the start or end index is a lazy value, and the result location is a slice,
|
||||
// then the pointer-to-array would be casted to a slice anyway. So, we preserve the laziness of these
|
||||
// values by making the return type a slice.
|
||||
ZigType *res_loc_type = get_result_loc_type(ira, instruction->result_loc);
|
||||
bool result_loc_is_slice = (res_loc_type != nullptr && is_slice(res_loc_type));
|
||||
bool end_is_known = !result_loc_is_slice &&
|
||||
((end != nullptr && value_is_comptime(end->value)) ||
|
||||
(end == nullptr && child_array_type->id == ZigTypeIdArray));
|
||||
|
||||
ZigValue *array_sentinel = sentinel_val;
|
||||
if (end_is_known) {
|
||||
uint64_t end_scalar;
|
||||
if (end != nullptr) {
|
||||
ZigValue *end_val = ir_resolve_const(ira, end, UndefBad);
|
||||
if (!end_val)
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
end_scalar = bigint_as_u64(&end_val->data.x_bigint);
|
||||
} else {
|
||||
end_scalar = child_array_type->data.array.len;
|
||||
}
|
||||
array_sentinel = (child_array_type->id == ZigTypeIdArray && end_scalar == child_array_type->data.array.len)
|
||||
? child_array_type->data.array.sentinel : sentinel_val;
|
||||
|
||||
if (value_is_comptime(casted_start->value)) {
|
||||
ZigValue *start_val = ir_resolve_const(ira, casted_start, UndefBad);
|
||||
if (!start_val)
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
|
||||
uint64_t start_scalar = bigint_as_u64(&start_val->data.x_bigint);
|
||||
|
||||
if (start_scalar > end_scalar) {
|
||||
ir_add_error(ira, &instruction->base.base, buf_sprintf("out of bounds slice"));
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
}
|
||||
|
||||
uint32_t base_ptr_align = non_sentinel_slice_ptr_type->data.pointer.explicit_alignment;
|
||||
uint32_t ptr_byte_alignment = 0;
|
||||
if (end_scalar > start_scalar) {
|
||||
if ((err = compute_elem_align(ira, elem_type, base_ptr_align, start_scalar, &ptr_byte_alignment)))
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
}
|
||||
|
||||
ZigType *return_array_type = get_array_type(ira->codegen, elem_type, end_scalar - start_scalar,
|
||||
array_sentinel);
|
||||
return_type = get_pointer_to_type_extra(ira->codegen, return_array_type,
|
||||
non_sentinel_slice_ptr_type->data.pointer.is_const,
|
||||
non_sentinel_slice_ptr_type->data.pointer.is_volatile,
|
||||
PtrLenSingle, ptr_byte_alignment, 0, 0, false);
|
||||
goto done_with_return_type;
|
||||
}
|
||||
} else if (array_sentinel == nullptr && end == nullptr) {
|
||||
array_sentinel = slice_sentinel_val;
|
||||
}
|
||||
if (array_sentinel != nullptr) {
|
||||
// TODO deal with non-abi-alignment here
|
||||
ZigType *slice_ptr_type = adjust_ptr_sentinel(ira->codegen, non_sentinel_slice_ptr_type, array_sentinel);
|
||||
return_type = get_slice_type(ira->codegen, slice_ptr_type);
|
||||
} else {
|
||||
// TODO deal with non-abi-alignment here
|
||||
return_type = get_slice_type(ira->codegen, non_sentinel_slice_ptr_type);
|
||||
}
|
||||
done_with_return_type:
|
||||
|
||||
if (instr_is_comptime(ptr_ptr) &&
|
||||
value_is_comptime(casted_start->value) &&
|
||||
|
@ -26233,12 +26428,8 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
|
|||
size_t abs_offset;
|
||||
size_t rel_end;
|
||||
bool ptr_is_undef = false;
|
||||
if (array_type->id == ZigTypeIdArray ||
|
||||
(array_type->id == ZigTypeIdPointer && array_type->data.pointer.ptr_len == PtrLenSingle))
|
||||
{
|
||||
if (child_array_type->id == ZigTypeIdArray) {
|
||||
if (array_type->id == ZigTypeIdPointer) {
|
||||
ZigType *child_array_type = array_type->data.pointer.child_type;
|
||||
assert(child_array_type->id == ZigTypeIdArray);
|
||||
parent_ptr = const_ptr_pointee(ira, ira->codegen, ptr_ptr->value, instruction->base.base.source_node);
|
||||
if (parent_ptr == nullptr)
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
|
@ -26249,6 +26440,10 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
|
|||
abs_offset = 0;
|
||||
rel_end = SIZE_MAX;
|
||||
ptr_is_undef = true;
|
||||
} else if (parent_ptr->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) {
|
||||
array_val = nullptr;
|
||||
abs_offset = 0;
|
||||
rel_end = SIZE_MAX;
|
||||
} else {
|
||||
array_val = const_ptr_pointee(ira, ira->codegen, parent_ptr, instruction->base.base.source_node);
|
||||
if (array_val == nullptr)
|
||||
|
@ -26291,6 +26486,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
|
|||
rel_end = 1;
|
||||
}
|
||||
break;
|
||||
case ConstPtrSpecialSubArray:
|
||||
case ConstPtrSpecialBaseArray:
|
||||
array_val = parent_ptr->data.x_ptr.data.base_array.array_val;
|
||||
abs_offset = parent_ptr->data.x_ptr.data.base_array.elem_index;
|
||||
|
@ -26341,6 +26537,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
|
|||
abs_offset = SIZE_MAX;
|
||||
rel_end = 1;
|
||||
break;
|
||||
case ConstPtrSpecialSubArray:
|
||||
case ConstPtrSpecialBaseArray:
|
||||
array_val = parent_ptr->data.x_ptr.data.base_array.array_val;
|
||||
abs_offset = parent_ptr->data.x_ptr.data.base_array.elem_index;
|
||||
|
@ -26401,15 +26598,28 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
|
|||
}
|
||||
|
||||
IrInstGen *result = ir_const(ira, &instruction->base.base, return_type);
|
||||
ZigValue *out_val = result->value;
|
||||
out_val->data.x_struct.fields = alloc_const_vals_ptrs(ira->codegen, 2);
|
||||
|
||||
ZigValue *ptr_val = out_val->data.x_struct.fields[slice_ptr_index];
|
||||
ZigValue *ptr_val;
|
||||
if (return_type->id == ZigTypeIdPointer) {
|
||||
// pointer to array
|
||||
ptr_val = result->value;
|
||||
} else {
|
||||
// slice
|
||||
result->value->data.x_struct.fields = alloc_const_vals_ptrs(ira->codegen, 2);
|
||||
|
||||
ptr_val = result->value->data.x_struct.fields[slice_ptr_index];
|
||||
|
||||
ZigValue *len_val = result->value->data.x_struct.fields[slice_len_index];
|
||||
init_const_usize(ira->codegen, len_val, end_scalar - start_scalar);
|
||||
}
|
||||
|
||||
bool return_type_is_const = non_sentinel_slice_ptr_type->data.pointer.is_const;
|
||||
if (array_val) {
|
||||
size_t index = abs_offset + start_scalar;
|
||||
bool is_const = slice_is_const(return_type);
|
||||
init_const_ptr_array(ira->codegen, ptr_val, array_val, index, is_const, PtrLenUnknown);
|
||||
init_const_ptr_array(ira->codegen, ptr_val, array_val, index, return_type_is_const, PtrLenUnknown);
|
||||
if (return_type->id == ZigTypeIdPointer) {
|
||||
ptr_val->data.x_ptr.special = ConstPtrSpecialSubArray;
|
||||
}
|
||||
if (array_type->id == ZigTypeIdArray) {
|
||||
ptr_val->data.x_ptr.mut = ptr_ptr->value->data.x_ptr.mut;
|
||||
} else if (is_slice(array_type)) {
|
||||
|
@ -26419,16 +26629,17 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
|
|||
}
|
||||
} else if (ptr_is_undef) {
|
||||
ptr_val->type = get_pointer_to_type(ira->codegen, parent_ptr->type->data.pointer.child_type,
|
||||
slice_is_const(return_type));
|
||||
return_type_is_const);
|
||||
ptr_val->special = ConstValSpecialUndef;
|
||||
} else switch (parent_ptr->data.x_ptr.special) {
|
||||
case ConstPtrSpecialInvalid:
|
||||
case ConstPtrSpecialDiscard:
|
||||
zig_unreachable();
|
||||
case ConstPtrSpecialRef:
|
||||
init_const_ptr_ref(ira->codegen, ptr_val,
|
||||
parent_ptr->data.x_ptr.data.ref.pointee, slice_is_const(return_type));
|
||||
init_const_ptr_ref(ira->codegen, ptr_val, parent_ptr->data.x_ptr.data.ref.pointee,
|
||||
return_type_is_const);
|
||||
break;
|
||||
case ConstPtrSpecialSubArray:
|
||||
case ConstPtrSpecialBaseArray:
|
||||
zig_unreachable();
|
||||
case ConstPtrSpecialBaseStruct:
|
||||
|
@ -26443,7 +26654,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
|
|||
init_const_ptr_hard_coded_addr(ira->codegen, ptr_val,
|
||||
parent_ptr->type->data.pointer.child_type,
|
||||
parent_ptr->data.x_ptr.data.hard_coded_addr.addr + start_scalar,
|
||||
slice_is_const(return_type));
|
||||
return_type_is_const);
|
||||
break;
|
||||
case ConstPtrSpecialFunction:
|
||||
zig_panic("TODO");
|
||||
|
@ -26451,26 +26662,11 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
|
|||
zig_panic("TODO");
|
||||
}
|
||||
|
||||
ZigValue *len_val = out_val->data.x_struct.fields[slice_len_index];
|
||||
init_const_usize(ira->codegen, len_val, end_scalar - start_scalar);
|
||||
|
||||
// In the case of pointer-to-array, we must restore this because above it overwrites ptr_val->type
|
||||
result->value->type = return_type;
|
||||
return result;
|
||||
}
|
||||
|
||||
IrInstGen *result_loc = ir_resolve_result(ira, &instruction->base.base, instruction->result_loc,
|
||||
return_type, nullptr, true, true);
|
||||
if (result_loc != nullptr) {
|
||||
if (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable) {
|
||||
return result_loc;
|
||||
}
|
||||
IrInstGen *dummy_value = ir_const(ira, &instruction->base.base, return_type);
|
||||
dummy_value->value->special = ConstValSpecialRuntime;
|
||||
IrInstGen *dummy_result = ir_implicit_cast2(ira, &instruction->base.base,
|
||||
dummy_value, result_loc->value->type->data.pointer.child_type);
|
||||
if (type_is_invalid(dummy_result->value->type))
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
}
|
||||
|
||||
if (generate_non_null_assert) {
|
||||
IrInstGen *ptr_val = ir_get_deref(ira, &instruction->base.base, ptr_ptr, nullptr);
|
||||
|
||||
|
@ -26480,8 +26676,26 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
|
|||
ir_build_assert_non_null(ira, &instruction->base.base, ptr_val);
|
||||
}
|
||||
|
||||
IrInstGen *result_loc = nullptr;
|
||||
|
||||
if (return_type->id != ZigTypeIdPointer) {
|
||||
result_loc = ir_resolve_result(ira, &instruction->base.base, instruction->result_loc,
|
||||
return_type, nullptr, true, true);
|
||||
if (result_loc != nullptr) {
|
||||
if (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable) {
|
||||
return result_loc;
|
||||
}
|
||||
IrInstGen *dummy_value = ir_const(ira, &instruction->base.base, return_type);
|
||||
dummy_value->value->special = ConstValSpecialRuntime;
|
||||
IrInstGen *dummy_result = ir_implicit_cast2(ira, &instruction->base.base,
|
||||
dummy_value, result_loc->value->type->data.pointer.child_type);
|
||||
if (type_is_invalid(dummy_result->value->type))
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
}
|
||||
}
|
||||
|
||||
return ir_build_slice_gen(ira, &instruction->base.base, return_type, ptr_ptr,
|
||||
casted_start, end, instruction->safety_check_on, result_loc);
|
||||
casted_start, end, instruction->safety_check_on, result_loc, sentinel_val);
|
||||
}
|
||||
|
||||
static IrInstGen *ir_analyze_instruction_has_field(IrAnalyze *ira, IrInstSrcHasField *instruction) {
|
||||
|
@ -27507,10 +27721,18 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn
|
|||
// We have a check for zero bits later so we use get_src_ptr_type to
|
||||
// validate src_type and dest_type.
|
||||
|
||||
ZigType *src_ptr_type = get_src_ptr_type(src_type);
|
||||
if (src_ptr_type == nullptr) {
|
||||
ir_add_error(ira, ptr_src, buf_sprintf("expected pointer, found '%s'", buf_ptr(&src_type->name)));
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
ZigType *if_slice_ptr_type;
|
||||
if (is_slice(src_type)) {
|
||||
TypeStructField *ptr_field = src_type->data.structure.fields[slice_ptr_index];
|
||||
if_slice_ptr_type = resolve_struct_field_type(ira->codegen, ptr_field);
|
||||
} else {
|
||||
if_slice_ptr_type = src_type;
|
||||
|
||||
ZigType *src_ptr_type = get_src_ptr_type(src_type);
|
||||
if (src_ptr_type == nullptr) {
|
||||
ir_add_error(ira, ptr_src, buf_sprintf("expected pointer, found '%s'", buf_ptr(&src_type->name)));
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
}
|
||||
}
|
||||
|
||||
ZigType *dest_ptr_type = get_src_ptr_type(dest_type);
|
||||
|
@ -27520,7 +27742,7 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn
|
|||
return ira->codegen->invalid_inst_gen;
|
||||
}
|
||||
|
||||
if (get_ptr_const(src_type) && !get_ptr_const(dest_type)) {
|
||||
if (get_ptr_const(ira->codegen, src_type) && !get_ptr_const(ira->codegen, dest_type)) {
|
||||
ir_add_error(ira, source_instr, buf_sprintf("cast discards const qualifier"));
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
}
|
||||
|
@ -27538,7 +27760,10 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn
|
|||
if ((err = type_resolve(ira->codegen, src_type, ResolveStatusZeroBitsKnown)))
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
|
||||
if (type_has_bits(ira->codegen, dest_type) && !type_has_bits(ira->codegen, src_type) && safety_check_on) {
|
||||
if (safety_check_on &&
|
||||
type_has_bits(ira->codegen, dest_type) &&
|
||||
!type_has_bits(ira->codegen, if_slice_ptr_type))
|
||||
{
|
||||
ErrorMsg *msg = ir_add_error(ira, source_instr,
|
||||
buf_sprintf("'%s' and '%s' do not have the same in-memory representation",
|
||||
buf_ptr(&src_type->name), buf_ptr(&dest_type->name)));
|
||||
|
@ -27549,6 +27774,14 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn
|
|||
return ira->codegen->invalid_inst_gen;
|
||||
}
|
||||
|
||||
// For slices, follow the `ptr` field.
|
||||
if (is_slice(src_type)) {
|
||||
TypeStructField *ptr_field = src_type->data.structure.fields[slice_ptr_index];
|
||||
IrInstGen *ptr_ref = ir_get_ref(ira, source_instr, ptr, true, false);
|
||||
IrInstGen *ptr_ptr = ir_analyze_struct_field_ptr(ira, source_instr, ptr_field, ptr_ref, src_type, false);
|
||||
ptr = ir_get_deref(ira, source_instr, ptr_ptr, nullptr);
|
||||
}
|
||||
|
||||
if (instr_is_comptime(ptr)) {
|
||||
bool dest_allows_addr_zero = ptr_allows_addr_zero(dest_type);
|
||||
UndefAllowed is_undef_allowed = dest_allows_addr_zero ? UndefOk : UndefBad;
|
||||
|
|
|
@ -292,7 +292,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
|
|||
\\pub export fn main() c_int {
|
||||
\\ var array = [_]u32{ 1, 7, 3, 2, 0, 9, 4, 8, 6, 5 };
|
||||
\\
|
||||
\\ c.qsort(@ptrCast(?*c_void, array[0..].ptr), @intCast(c_ulong, array.len), @sizeOf(i32), compare_fn);
|
||||
\\ c.qsort(@ptrCast(?*c_void, &array), @intCast(c_ulong, array.len), @sizeOf(i32), compare_fn);
|
||||
\\
|
||||
\\ for (array) |item, i| {
|
||||
\\ if (item != i) {
|
||||
|
|
|
@ -103,18 +103,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
|||
"tmp.zig:3:23: error: pointer to size 0 type has no address",
|
||||
});
|
||||
|
||||
cases.addTest("slice to pointer conversion mismatch",
|
||||
\\pub fn bytesAsSlice(bytes: var) [*]align(1) const u16 {
|
||||
\\ return @ptrCast([*]align(1) const u16, bytes.ptr)[0..1];
|
||||
\\}
|
||||
\\test "bytesAsSlice" {
|
||||
\\ const bytes = [_]u8{ 0xDE, 0xAD, 0xBE, 0xEF };
|
||||
\\ const slice = bytesAsSlice(bytes[0..]);
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
"tmp.zig:2:54: error: expected type '[*]align(1) const u16', found '[]align(1) const u16'",
|
||||
});
|
||||
|
||||
cases.addTest("access invalid @typeInfo decl",
|
||||
\\const A = B;
|
||||
\\test "Crash" {
|
||||
|
@ -1918,8 +1906,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
|||
cases.add("reading past end of pointer casted array",
|
||||
\\comptime {
|
||||
\\ const array: [4]u8 = "aoeu".*;
|
||||
\\ const slice = array[1..];
|
||||
\\ const int_ptr = @ptrCast(*const u24, slice.ptr);
|
||||
\\ const sub_array = array[1..];
|
||||
\\ const int_ptr = @ptrCast(*const u24, sub_array);
|
||||
\\ const deref = int_ptr.*;
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
|
|
|
@ -69,7 +69,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
|
|||
\\}
|
||||
\\pub fn main() void {
|
||||
\\ var buf: [4]u8 = undefined;
|
||||
\\ const ptr = buf[0..].ptr;
|
||||
\\ const ptr: [*]u8 = &buf;
|
||||
\\ const slice = ptr[0..3 :0];
|
||||
\\}
|
||||
);
|
||||
|
|
|
@ -5,10 +5,17 @@ const builtin = @import("builtin");
|
|||
var foo: u8 align(4) = 100;
|
||||
|
||||
test "global variable alignment" {
|
||||
expect(@TypeOf(&foo).alignment == 4);
|
||||
expect(@TypeOf(&foo) == *align(4) u8);
|
||||
const slice = @as(*[1]u8, &foo)[0..];
|
||||
expect(@TypeOf(slice) == []align(4) u8);
|
||||
comptime expect(@TypeOf(&foo).alignment == 4);
|
||||
comptime expect(@TypeOf(&foo) == *align(4) u8);
|
||||
{
|
||||
const slice = @as(*[1]u8, &foo)[0..];
|
||||
comptime expect(@TypeOf(slice) == *align(4) [1]u8);
|
||||
}
|
||||
{
|
||||
var runtime_zero: usize = 0;
|
||||
const slice = @as(*[1]u8, &foo)[runtime_zero..];
|
||||
comptime expect(@TypeOf(slice) == []align(4) u8);
|
||||
}
|
||||
}
|
||||
|
||||
fn derp() align(@sizeOf(usize) * 2) i32 {
|
||||
|
@ -171,18 +178,19 @@ test "runtime known array index has best alignment possible" {
|
|||
|
||||
// because pointer is align 2 and u32 align % 2 == 0 we can assume align 2
|
||||
var smaller align(2) = [_]u32{ 1, 2, 3, 4 };
|
||||
comptime expect(@TypeOf(smaller[0..]) == []align(2) u32);
|
||||
comptime expect(@TypeOf(smaller[0..].ptr) == [*]align(2) u32);
|
||||
testIndex(smaller[0..].ptr, 0, *align(2) u32);
|
||||
testIndex(smaller[0..].ptr, 1, *align(2) u32);
|
||||
testIndex(smaller[0..].ptr, 2, *align(2) u32);
|
||||
testIndex(smaller[0..].ptr, 3, *align(2) u32);
|
||||
var runtime_zero: usize = 0;
|
||||
comptime expect(@TypeOf(smaller[runtime_zero..]) == []align(2) u32);
|
||||
comptime expect(@TypeOf(smaller[runtime_zero..].ptr) == [*]align(2) u32);
|
||||
testIndex(smaller[runtime_zero..].ptr, 0, *align(2) u32);
|
||||
testIndex(smaller[runtime_zero..].ptr, 1, *align(2) u32);
|
||||
testIndex(smaller[runtime_zero..].ptr, 2, *align(2) u32);
|
||||
testIndex(smaller[runtime_zero..].ptr, 3, *align(2) u32);
|
||||
|
||||
// has to use ABI alignment because index known at runtime only
|
||||
testIndex2(array[0..].ptr, 0, *u8);
|
||||
testIndex2(array[0..].ptr, 1, *u8);
|
||||
testIndex2(array[0..].ptr, 2, *u8);
|
||||
testIndex2(array[0..].ptr, 3, *u8);
|
||||
testIndex2(array[runtime_zero..].ptr, 0, *u8);
|
||||
testIndex2(array[runtime_zero..].ptr, 1, *u8);
|
||||
testIndex2(array[runtime_zero..].ptr, 2, *u8);
|
||||
testIndex2(array[runtime_zero..].ptr, 3, *u8);
|
||||
}
|
||||
fn testIndex(smaller: [*]align(2) u32, index: usize, comptime T: type) void {
|
||||
comptime expect(@TypeOf(&smaller[index]) == T);
|
||||
|
|
|
@ -435,7 +435,8 @@ fn incrementVoidPtrValue(value: ?*c_void) void {
|
|||
|
||||
test "implicit cast from [*]T to ?*c_void" {
|
||||
var a = [_]u8{ 3, 2, 1 };
|
||||
incrementVoidPtrArray(a[0..].ptr, 3);
|
||||
var runtime_zero: usize = 0;
|
||||
incrementVoidPtrArray(a[runtime_zero..].ptr, 3);
|
||||
expect(std.mem.eql(u8, &a, &[_]u8{ 4, 3, 2 }));
|
||||
}
|
||||
|
||||
|
|
|
@ -524,7 +524,7 @@ test "comptime slice of slice preserves comptime var" {
|
|||
test "comptime slice of pointer preserves comptime var" {
|
||||
comptime {
|
||||
var buff: [10]u8 = undefined;
|
||||
var a = buff[0..].ptr;
|
||||
var a = @ptrCast([*]u8, &buff);
|
||||
a[0..1][0] = 1;
|
||||
expect(buff[0..][0..][0] == 1);
|
||||
}
|
||||
|
|
|
@ -102,8 +102,8 @@ test "memcpy and memset intrinsics" {
|
|||
var foo: [20]u8 = undefined;
|
||||
var bar: [20]u8 = undefined;
|
||||
|
||||
@memset(foo[0..].ptr, 'A', foo.len);
|
||||
@memcpy(bar[0..].ptr, foo[0..].ptr, bar.len);
|
||||
@memset(&foo, 'A', foo.len);
|
||||
@memcpy(&bar, &foo, bar.len);
|
||||
|
||||
if (bar[11] != 'A') unreachable;
|
||||
}
|
||||
|
@ -565,12 +565,16 @@ test "volatile load and store" {
|
|||
expect(ptr.* == 1235);
|
||||
}
|
||||
|
||||
test "slice string literal has type []const u8" {
|
||||
test "slice string literal has correct type" {
|
||||
comptime {
|
||||
expect(@TypeOf("aoeu"[0..]) == []const u8);
|
||||
expect(@TypeOf("aoeu"[0..]) == *const [4:0]u8);
|
||||
const array = [_]i32{ 1, 2, 3, 4 };
|
||||
expect(@TypeOf(array[0..]) == []const i32);
|
||||
expect(@TypeOf(array[0..]) == *const [4]i32);
|
||||
}
|
||||
var runtime_zero: usize = 0;
|
||||
comptime expect(@TypeOf("aoeu"[runtime_zero..]) == [:0]const u8);
|
||||
const array = [_]i32{ 1, 2, 3, 4 };
|
||||
comptime expect(@TypeOf(array[runtime_zero..]) == []const i32);
|
||||
}
|
||||
|
||||
test "pointer child field" {
|
||||
|
|
|
@ -159,12 +159,13 @@ test "allowzero pointer and slice" {
|
|||
var opt_ptr: ?[*]allowzero i32 = ptr;
|
||||
expect(opt_ptr != null);
|
||||
expect(@ptrToInt(ptr) == 0);
|
||||
var slice = ptr[0..10];
|
||||
expect(@TypeOf(slice) == []allowzero i32);
|
||||
var runtime_zero: usize = 0;
|
||||
var slice = ptr[runtime_zero..10];
|
||||
comptime expect(@TypeOf(slice) == []allowzero i32);
|
||||
expect(@ptrToInt(&slice[5]) == 20);
|
||||
|
||||
expect(@typeInfo(@TypeOf(ptr)).Pointer.is_allowzero);
|
||||
expect(@typeInfo(@TypeOf(slice)).Pointer.is_allowzero);
|
||||
comptime expect(@typeInfo(@TypeOf(ptr)).Pointer.is_allowzero);
|
||||
comptime expect(@typeInfo(@TypeOf(slice)).Pointer.is_allowzero);
|
||||
}
|
||||
|
||||
test "assign null directly to C pointer and test null equality" {
|
||||
|
|
|
@ -13,7 +13,7 @@ fn testReinterpretBytesAsInteger() void {
|
|||
builtin.Endian.Little => 0xab785634,
|
||||
builtin.Endian.Big => 0x345678ab,
|
||||
};
|
||||
expect(@ptrCast(*align(1) const u32, bytes[1..5].ptr).* == expected);
|
||||
expect(@ptrCast(*align(1) const u32, bytes[1..5]).* == expected);
|
||||
}
|
||||
|
||||
test "reinterpret bytes of an array into an extern struct" {
|
||||
|
|
|
@ -7,10 +7,10 @@ const mem = std.mem;
|
|||
const x = @intToPtr([*]i32, 0x1000)[0..0x500];
|
||||
const y = x[0x100..];
|
||||
test "compile time slice of pointer to hard coded address" {
|
||||
expect(@ptrToInt(x.ptr) == 0x1000);
|
||||
expect(@ptrToInt(x) == 0x1000);
|
||||
expect(x.len == 0x500);
|
||||
|
||||
expect(@ptrToInt(y.ptr) == 0x1100);
|
||||
expect(@ptrToInt(y) == 0x1100);
|
||||
expect(y.len == 0x400);
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,9 @@ test "C pointer slice access" {
|
|||
var buf: [10]u32 = [1]u32{42} ** 10;
|
||||
const c_ptr = @ptrCast([*c]const u32, &buf);
|
||||
|
||||
comptime expectEqual([]const u32, @TypeOf(c_ptr[0..1]));
|
||||
var runtime_zero: usize = 0;
|
||||
comptime expectEqual([]const u32, @TypeOf(c_ptr[runtime_zero..1]));
|
||||
comptime expectEqual(*const [1]u32, @TypeOf(c_ptr[0..1]));
|
||||
|
||||
for (c_ptr[0..5]) |*cl| {
|
||||
expectEqual(@as(u32, 42), cl.*);
|
||||
|
@ -107,7 +109,9 @@ test "obtaining a null terminated slice" {
|
|||
const ptr2 = buf[0..runtime_len :0];
|
||||
// ptr2 is a null-terminated slice
|
||||
comptime expect(@TypeOf(ptr2) == [:0]u8);
|
||||
comptime expect(@TypeOf(ptr2[0..2]) == []u8);
|
||||
comptime expect(@TypeOf(ptr2[0..2]) == *[2]u8);
|
||||
var runtime_zero: usize = 0;
|
||||
comptime expect(@TypeOf(ptr2[runtime_zero..2]) == []u8);
|
||||
}
|
||||
|
||||
test "empty array to slice" {
|
||||
|
@ -126,3 +130,150 @@ test "empty array to slice" {
|
|||
S.doTheTest();
|
||||
comptime S.doTheTest();
|
||||
}
|
||||
|
||||
test "@ptrCast slice to pointer" {
|
||||
const S = struct {
|
||||
fn doTheTest() void {
|
||||
var array align(@alignOf(u16)) = [5]u8{ 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
var slice: []u8 = &array;
|
||||
var ptr = @ptrCast(*u16, slice);
|
||||
expect(ptr.* == 65535);
|
||||
}
|
||||
};
|
||||
|
||||
S.doTheTest();
|
||||
comptime S.doTheTest();
|
||||
}
|
||||
|
||||
test "slice syntax resulting in pointer-to-array" {
|
||||
const S = struct {
|
||||
fn doTheTest() void {
|
||||
testArray();
|
||||
testArrayZ();
|
||||
testArray0();
|
||||
testArrayAlign();
|
||||
testPointer();
|
||||
testPointerZ();
|
||||
testPointer0();
|
||||
testPointerAlign();
|
||||
testSlice();
|
||||
testSliceZ();
|
||||
testSlice0();
|
||||
testSliceAlign();
|
||||
}
|
||||
|
||||
fn testArray() void {
|
||||
var array = [5]u8{ 1, 2, 3, 4, 5 };
|
||||
var slice = array[1..3];
|
||||
comptime expect(@TypeOf(slice) == *[2]u8);
|
||||
expect(slice[0] == 2);
|
||||
expect(slice[1] == 3);
|
||||
}
|
||||
|
||||
fn testArrayZ() void {
|
||||
var array = [5:0]u8{ 1, 2, 3, 4, 5 };
|
||||
comptime expect(@TypeOf(array[1..3]) == *[2]u8);
|
||||
comptime expect(@TypeOf(array[1..5]) == *[4:0]u8);
|
||||
comptime expect(@TypeOf(array[1..]) == *[4:0]u8);
|
||||
comptime expect(@TypeOf(array[1..3 :4]) == *[2:4]u8);
|
||||
}
|
||||
|
||||
fn testArray0() void {
|
||||
{
|
||||
var array = [0]u8{};
|
||||
var slice = array[0..0];
|
||||
comptime expect(@TypeOf(slice) == *[0]u8);
|
||||
}
|
||||
{
|
||||
var array = [0:0]u8{};
|
||||
var slice = array[0..0];
|
||||
comptime expect(@TypeOf(slice) == *[0:0]u8);
|
||||
expect(slice[0] == 0);
|
||||
}
|
||||
}
|
||||
|
||||
fn testArrayAlign() void {
|
||||
var array align(4) = [5]u8{ 1, 2, 3, 4, 5 };
|
||||
var slice = array[4..5];
|
||||
comptime expect(@TypeOf(slice) == *align(4) [1]u8);
|
||||
expect(slice[0] == 5);
|
||||
comptime expect(@TypeOf(array[0..2]) == *align(4) [2]u8);
|
||||
}
|
||||
|
||||
fn testPointer() void {
|
||||
var array = [5]u8{ 1, 2, 3, 4, 5 };
|
||||
var pointer: [*]u8 = &array;
|
||||
var slice = pointer[1..3];
|
||||
comptime expect(@TypeOf(slice) == *[2]u8);
|
||||
expect(slice[0] == 2);
|
||||
expect(slice[1] == 3);
|
||||
}
|
||||
|
||||
fn testPointerZ() void {
|
||||
var array = [5:0]u8{ 1, 2, 3, 4, 5 };
|
||||
var pointer: [*:0]u8 = &array;
|
||||
comptime expect(@TypeOf(pointer[1..3]) == *[2]u8);
|
||||
comptime expect(@TypeOf(pointer[1..3 :4]) == *[2:4]u8);
|
||||
}
|
||||
|
||||
fn testPointer0() void {
|
||||
var pointer: [*]u0 = &[1]u0{0};
|
||||
var slice = pointer[0..1];
|
||||
comptime expect(@TypeOf(slice) == *[1]u0);
|
||||
expect(slice[0] == 0);
|
||||
}
|
||||
|
||||
fn testPointerAlign() void {
|
||||
var array align(4) = [5]u8{ 1, 2, 3, 4, 5 };
|
||||
var pointer: [*]align(4) u8 = &array;
|
||||
var slice = pointer[4..5];
|
||||
comptime expect(@TypeOf(slice) == *align(4) [1]u8);
|
||||
expect(slice[0] == 5);
|
||||
comptime expect(@TypeOf(pointer[0..2]) == *align(4) [2]u8);
|
||||
}
|
||||
|
||||
fn testSlice() void {
|
||||
var array = [5]u8{ 1, 2, 3, 4, 5 };
|
||||
var src_slice: []u8 = &array;
|
||||
var slice = src_slice[1..3];
|
||||
comptime expect(@TypeOf(slice) == *[2]u8);
|
||||
expect(slice[0] == 2);
|
||||
expect(slice[1] == 3);
|
||||
}
|
||||
|
||||
fn testSliceZ() void {
|
||||
var array = [5:0]u8{ 1, 2, 3, 4, 5 };
|
||||
var slice: [:0]u8 = &array;
|
||||
comptime expect(@TypeOf(slice[1..3]) == *[2]u8);
|
||||
comptime expect(@TypeOf(slice[1..]) == [:0]u8);
|
||||
comptime expect(@TypeOf(slice[1..3 :4]) == *[2:4]u8);
|
||||
}
|
||||
|
||||
fn testSlice0() void {
|
||||
{
|
||||
var array = [0]u8{};
|
||||
var src_slice: []u8 = &array;
|
||||
var slice = src_slice[0..0];
|
||||
comptime expect(@TypeOf(slice) == *[0]u8);
|
||||
}
|
||||
{
|
||||
var array = [0:0]u8{};
|
||||
var src_slice: [:0]u8 = &array;
|
||||
var slice = src_slice[0..0];
|
||||
comptime expect(@TypeOf(slice) == *[0]u8);
|
||||
}
|
||||
}
|
||||
|
||||
fn testSliceAlign() void {
|
||||
var array align(4) = [5]u8{ 1, 2, 3, 4, 5 };
|
||||
var src_slice: []align(4) u8 = &array;
|
||||
var slice = src_slice[4..5];
|
||||
comptime expect(@TypeOf(slice) == *align(4) [1]u8);
|
||||
expect(slice[0] == 5);
|
||||
comptime expect(@TypeOf(src_slice[0..2]) == *align(4) [2]u8);
|
||||
}
|
||||
};
|
||||
|
||||
S.doTheTest();
|
||||
comptime S.doTheTest();
|
||||
}
|
||||
|
|
|
@ -409,8 +409,8 @@ const Bitfields = packed struct {
|
|||
test "native bit field understands endianness" {
|
||||
var all: u64 = 0x7765443322221111;
|
||||
var bytes: [8]u8 = undefined;
|
||||
@memcpy(bytes[0..].ptr, @ptrCast([*]u8, &all), 8);
|
||||
var bitfields = @ptrCast(*Bitfields, bytes[0..].ptr).*;
|
||||
@memcpy(&bytes, @ptrCast([*]u8, &all), 8);
|
||||
var bitfields = @ptrCast(*Bitfields, &bytes).*;
|
||||
|
||||
expect(bitfields.f1 == 0x1111);
|
||||
expect(bitfields.f2 == 0x2222);
|
||||
|
|
Loading…
Reference in New Issue