authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-03-19 18:06:16-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-03-19 18:06:16-04:00
logdc04e97098010f590d109e6e70d4afe79cd8f01b
treebed11818fd80fe7b4557f4253c8d5562de773624
parent555a2c03286507ffe4bd3bea2154dbfb719ebef1
parent160367e0ddcb36b6957e603d869507b9d7542edc
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #4752 from ziglang/slice-array

slicing with comptime start and end indexes results in pointer-to-array

41 files changed, 906 insertions(+), 431 deletions(-)

doc/langref.html.in+16-20
...@@ -2093,8 +2093,9 @@ var foo: u8 align(4) = 100;...@@ -2093,8 +2093,9 @@ var foo: u8 align(4) = 100;
2093test "global variable alignment" {2093test "global variable alignment" {
2094 assert(@TypeOf(&foo).alignment == 4);2094 assert(@TypeOf(&foo).alignment == 4);
2095 assert(@TypeOf(&foo) == *align(4) u8);2095 assert(@TypeOf(&foo) == *align(4) u8);
2096 const slice = @as(*[1]u8, &foo)[0..];2096 const as_pointer_to_array: *[1]u8 = &foo;
2097 assert(@TypeOf(slice) == []align(4) u8);2097 const as_slice: []u8 = as_pointer_to_array;
2098 assert(@TypeOf(as_slice) == []align(4) u8);
2098}2099}
20992100
2100fn derp() align(@sizeOf(usize) * 2) i32 { return 1234; }2101fn derp() align(@sizeOf(usize) * 2) i32 { return 1234; }
...@@ -2187,7 +2188,8 @@ test "basic slices" {...@@ -2187,7 +2188,8 @@ test "basic slices" {
2187 // a slice is that the array's length is part of the type and known at2188 // a slice is that the array's length is part of the type and known at
2188 // compile-time, whereas the slice's length is known at runtime.2189 // compile-time, whereas the slice's length is known at runtime.
2189 // Both can be accessed with the `len` field.2190 // Both can be accessed with the `len` field.
2190 const slice = array[0..array.len];2191 var known_at_runtime_zero: usize = 0;
2192 const slice = array[known_at_runtime_zero..array.len];
2191 assert(&slice[0] == &array[0]);2193 assert(&slice[0] == &array[0]);
2192 assert(slice.len == array.len);2194 assert(slice.len == array.len);
21932195
...@@ -2207,13 +2209,15 @@ test "basic slices" {...@@ -2207,13 +2209,15 @@ test "basic slices" {
2207 {#code_end#}2209 {#code_end#}
2208 <p>This is one reason we prefer slices to pointers.</p>2210 <p>This is one reason we prefer slices to pointers.</p>
2209 {#code_begin|test|slices#}2211 {#code_begin|test|slices#}
2210const assert = @import("std").debug.assert;2212const std = @import("std");
2211const mem = @import("std").mem;2213const assert = std.debug.assert;
2212const fmt = @import("std").fmt;2214const mem = std.mem;
2215const fmt = std.fmt;
22132216
2214test "using slices for strings" {2217test "using slices for strings" {
2215 // Zig has no concept of strings. String literals are arrays of u8, and2218 // Zig has no concept of strings. String literals are const pointers to
2216 // in general the string type is []u8 (slice of u8).2219 // arrays of u8, and by convention parameters that are "strings" are
2220 // expected to be UTF-8 encoded slices of u8.
2217 // Here we coerce [5]u8 to []const u82221 // Here we coerce [5]u8 to []const u8
2218 const hello: []const u8 = "hello";2222 const hello: []const u8 = "hello";
2219 const world: []const u8 = "世界";2223 const world: []const u8 = "世界";
...@@ -2222,7 +2226,7 @@ test "using slices for strings" {...@@ -2222,7 +2226,7 @@ test "using slices for strings" {
2222 // You can use slice syntax on an array to convert an array into a slice.2226 // You can use slice syntax on an array to convert an array into a slice.
2223 const all_together_slice = all_together[0..];2227 const all_together_slice = all_together[0..];
2224 // String concatenation example.2228 // String concatenation example.
2225 const hello_world = try fmt.bufPrint(all_together_slice, "{} {}", .{hello, world});2229 const hello_world = try fmt.bufPrint(all_together_slice, "{} {}", .{ hello, world });
22262230
2227 // Generally, you can use UTF-8 and not worry about whether something is a2231 // Generally, you can use UTF-8 and not worry about whether something is a
2228 // string. If you don't need to deal with individual characters, no need2232 // string. If you don't need to deal with individual characters, no need
...@@ -2239,23 +2243,15 @@ test "slice pointer" {...@@ -2239,23 +2243,15 @@ test "slice pointer" {
2239 slice[2] = 3;2243 slice[2] = 3;
2240 assert(slice[2] == 3);2244 assert(slice[2] == 3);
2241 // The slice is mutable because we sliced a mutable pointer.2245 // The slice is mutable because we sliced a mutable pointer.
2242 assert(@TypeOf(slice) == []u8);2246 // Furthermore, it is actually a pointer to an array, since the start
2247 // and end indexes were both comptime-known.
2248 assert(@TypeOf(slice) == *[5]u8);
22432249
2244 // You can also slice a slice:2250 // You can also slice a slice:
2245 const slice2 = slice[2..3];2251 const slice2 = slice[2..3];
2246 assert(slice2.len == 1);2252 assert(slice2.len == 1);
2247 assert(slice2[0] == 3);2253 assert(slice2[0] == 3);
2248}2254}
2249
2250test "slice widening" {
2251 // Zig supports slice widening and slice narrowing. Cast a slice of u8
2252 // to a slice of anything else, and Zig will perform the length conversion.
2253 const array align(@alignOf(u32)) = [_]u8{ 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13 };
2254 const slice = mem.bytesAsSlice(u32, array[0..]);
2255 assert(slice.len == 2);
2256 assert(slice[0] == 0x12121212);
2257 assert(slice[1] == 0x13131313);
2258}
2259 {#code_end#}2255 {#code_end#}
2260 {#see_also|Pointers|for|Arrays#}2256 {#see_also|Pointers|for|Arrays#}
22612257
lib/std/crypto/aes.zig+19-19
...@@ -15,10 +15,10 @@ fn rotw(w: u32) u32 {...@@ -15,10 +15,10 @@ fn rotw(w: u32) u32 {
1515
16// Encrypt one block from src into dst, using the expanded key xk.16// Encrypt one block from src into dst, using the expanded key xk.
17fn encryptBlock(xk: []const u32, dst: []u8, src: []const u8) void {17fn encryptBlock(xk: []const u32, dst: []u8, src: []const u8) void {
18 var s0 = mem.readIntSliceBig(u32, src[0..4]);18 var s0 = mem.readIntBig(u32, src[0..4]);
19 var s1 = mem.readIntSliceBig(u32, src[4..8]);19 var s1 = mem.readIntBig(u32, src[4..8]);
20 var s2 = mem.readIntSliceBig(u32, src[8..12]);20 var s2 = mem.readIntBig(u32, src[8..12]);
21 var s3 = mem.readIntSliceBig(u32, src[12..16]);21 var s3 = mem.readIntBig(u32, src[12..16]);
2222
23 // First round just XORs input with key.23 // First round just XORs input with key.
24 s0 ^= xk[0];24 s0 ^= xk[0];
...@@ -58,18 +58,18 @@ fn encryptBlock(xk: []const u32, dst: []u8, src: []const u8) void {...@@ -58,18 +58,18 @@ fn encryptBlock(xk: []const u32, dst: []u8, src: []const u8) void {
58 s2 ^= xk[k + 2];58 s2 ^= xk[k + 2];
59 s3 ^= xk[k + 3];59 s3 ^= xk[k + 3];
6060
61 mem.writeIntSliceBig(u32, dst[0..4], s0);61 mem.writeIntBig(u32, dst[0..4], s0);
62 mem.writeIntSliceBig(u32, dst[4..8], s1);62 mem.writeIntBig(u32, dst[4..8], s1);
63 mem.writeIntSliceBig(u32, dst[8..12], s2);63 mem.writeIntBig(u32, dst[8..12], s2);
64 mem.writeIntSliceBig(u32, dst[12..16], s3);64 mem.writeIntBig(u32, dst[12..16], s3);
65}65}
6666
67// Decrypt one block from src into dst, using the expanded key xk.67// Decrypt one block from src into dst, using the expanded key xk.
68pub fn decryptBlock(xk: []const u32, dst: []u8, src: []const u8) void {68pub fn decryptBlock(xk: []const u32, dst: []u8, src: []const u8) void {
69 var s0 = mem.readIntSliceBig(u32, src[0..4]);69 var s0 = mem.readIntBig(u32, src[0..4]);
70 var s1 = mem.readIntSliceBig(u32, src[4..8]);70 var s1 = mem.readIntBig(u32, src[4..8]);
71 var s2 = mem.readIntSliceBig(u32, src[8..12]);71 var s2 = mem.readIntBig(u32, src[8..12]);
72 var s3 = mem.readIntSliceBig(u32, src[12..16]);72 var s3 = mem.readIntBig(u32, src[12..16]);
7373
74 // First round just XORs input with key.74 // First round just XORs input with key.
75 s0 ^= xk[0];75 s0 ^= xk[0];
...@@ -109,10 +109,10 @@ pub fn decryptBlock(xk: []const u32, dst: []u8, src: []const u8) void {...@@ -109,10 +109,10 @@ pub fn decryptBlock(xk: []const u32, dst: []u8, src: []const u8) void {
109 s2 ^= xk[k + 2];109 s2 ^= xk[k + 2];
110 s3 ^= xk[k + 3];110 s3 ^= xk[k + 3];
111111
112 mem.writeIntSliceBig(u32, dst[0..4], s0);112 mem.writeIntBig(u32, dst[0..4], s0);
113 mem.writeIntSliceBig(u32, dst[4..8], s1);113 mem.writeIntBig(u32, dst[4..8], s1);
114 mem.writeIntSliceBig(u32, dst[8..12], s2);114 mem.writeIntBig(u32, dst[8..12], s2);
115 mem.writeIntSliceBig(u32, dst[12..16], s3);115 mem.writeIntBig(u32, dst[12..16], s3);
116}116}
117117
118fn xorBytes(dst: []u8, a: []const u8, b: []const u8) usize {118fn xorBytes(dst: []u8, a: []const u8, b: []const u8) usize {
...@@ -154,8 +154,8 @@ fn AES(comptime keysize: usize) type {...@@ -154,8 +154,8 @@ fn AES(comptime keysize: usize) type {
154 var n: usize = 0;154 var n: usize = 0;
155 while (n < src.len) {155 while (n < src.len) {
156 ctx.encrypt(keystream[0..], ctrbuf[0..]);156 ctx.encrypt(keystream[0..], ctrbuf[0..]);
157 var ctr_i = std.mem.readIntSliceBig(u128, ctrbuf[0..]);157 var ctr_i = std.mem.readIntBig(u128, ctrbuf[0..]);
158 std.mem.writeIntSliceBig(u128, ctrbuf[0..], ctr_i +% 1);158 std.mem.writeIntBig(u128, ctrbuf[0..], ctr_i +% 1);
159159
160 n += xorBytes(dst[n..], src[n..], &keystream);160 n += xorBytes(dst[n..], src[n..], &keystream);
161 }161 }
...@@ -251,7 +251,7 @@ fn expandKey(key: []const u8, enc: []u32, dec: []u32) void {...@@ -251,7 +251,7 @@ fn expandKey(key: []const u8, enc: []u32, dec: []u32) void {
251 var i: usize = 0;251 var i: usize = 0;
252 var nk = key.len / 4;252 var nk = key.len / 4;
253 while (i < nk) : (i += 1) {253 while (i < nk) : (i += 1) {
254 enc[i] = mem.readIntSliceBig(u32, key[4 * i .. 4 * i + 4]);254 enc[i] = mem.readIntBig(u32, key[4 * i ..][0..4]);
255 }255 }
256 while (i < enc.len) : (i += 1) {256 while (i < enc.len) : (i += 1) {
257 var t = enc[i - 1];257 var t = enc[i - 1];
lib/std/crypto/blake2.zig+4-7
...@@ -123,8 +123,7 @@ fn Blake2s(comptime out_len: usize) type {...@@ -123,8 +123,7 @@ fn Blake2s(comptime out_len: usize) type {
123 const rr = d.h[0 .. out_len / 32];123 const rr = d.h[0 .. out_len / 32];
124124
125 for (rr) |s, j| {125 for (rr) |s, j| {
126 // TODO https://github.com/ziglang/zig/issues/863126 mem.writeIntLittle(u32, out[4 * j ..][0..4], s);
127 mem.writeIntSliceLittle(u32, out[4 * j .. 4 * j + 4], s);
128 }127 }
129 }128 }
130129
...@@ -135,8 +134,7 @@ fn Blake2s(comptime out_len: usize) type {...@@ -135,8 +134,7 @@ fn Blake2s(comptime out_len: usize) type {
135 var v: [16]u32 = undefined;134 var v: [16]u32 = undefined;
136135
137 for (m) |*r, i| {136 for (m) |*r, i| {
138 // TODO https://github.com/ziglang/zig/issues/863137 r.* = mem.readIntLittle(u32, b[4 * i ..][0..4]);
139 r.* = mem.readIntSliceLittle(u32, b[4 * i .. 4 * i + 4]);
140 }138 }
141139
142 var k: usize = 0;140 var k: usize = 0;
...@@ -358,8 +356,7 @@ fn Blake2b(comptime out_len: usize) type {...@@ -358,8 +356,7 @@ fn Blake2b(comptime out_len: usize) type {
358 const rr = d.h[0 .. out_len / 64];356 const rr = d.h[0 .. out_len / 64];
359357
360 for (rr) |s, j| {358 for (rr) |s, j| {
361 // TODO https://github.com/ziglang/zig/issues/863359 mem.writeIntLittle(u64, out[8 * j ..][0..8], s);
362 mem.writeIntSliceLittle(u64, out[8 * j .. 8 * j + 8], s);
363 }360 }
364 }361 }
365362
...@@ -370,7 +367,7 @@ fn Blake2b(comptime out_len: usize) type {...@@ -370,7 +367,7 @@ fn Blake2b(comptime out_len: usize) type {
370 var v: [16]u64 = undefined;367 var v: [16]u64 = undefined;
371368
372 for (m) |*r, i| {369 for (m) |*r, i| {
373 r.* = mem.readIntSliceLittle(u64, b[8 * i .. 8 * i + 8]);370 r.* = mem.readIntLittle(u64, b[8 * i ..][0..8]);
374 }371 }
375372
376 var k: usize = 0;373 var k: usize = 0;
lib/std/crypto/chacha20.zig+30-31
...@@ -61,8 +61,7 @@ fn salsa20_wordtobyte(out: []u8, input: [16]u32) void {...@@ -61,8 +61,7 @@ fn salsa20_wordtobyte(out: []u8, input: [16]u32) void {
61 }61 }
6262
63 for (x) |_, i| {63 for (x) |_, i| {
64 // TODO https://github.com/ziglang/zig/issues/86364 mem.writeIntLittle(u32, out[4 * i ..][0..4], x[i] +% input[i]);
65 mem.writeIntSliceLittle(u32, out[4 * i .. 4 * i + 4], x[i] +% input[i]);
66 }65 }
67}66}
6867
...@@ -73,10 +72,10 @@ fn chaCha20_internal(out: []u8, in: []const u8, key: [8]u32, counter: [4]u32) vo...@@ -73,10 +72,10 @@ fn chaCha20_internal(out: []u8, in: []const u8, key: [8]u32, counter: [4]u32) vo
7372
74 const c = "expand 32-byte k";73 const c = "expand 32-byte k";
75 const constant_le = [_]u32{74 const constant_le = [_]u32{
76 mem.readIntSliceLittle(u32, c[0..4]),75 mem.readIntLittle(u32, c[0..4]),
77 mem.readIntSliceLittle(u32, c[4..8]),76 mem.readIntLittle(u32, c[4..8]),
78 mem.readIntSliceLittle(u32, c[8..12]),77 mem.readIntLittle(u32, c[8..12]),
79 mem.readIntSliceLittle(u32, c[12..16]),78 mem.readIntLittle(u32, c[12..16]),
80 };79 };
8180
82 mem.copy(u32, ctx[0..], constant_le[0..4]);81 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:...@@ -120,19 +119,19 @@ pub fn chaCha20IETF(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce:
120 var k: [8]u32 = undefined;119 var k: [8]u32 = undefined;
121 var c: [4]u32 = undefined;120 var c: [4]u32 = undefined;
122121
123 k[0] = mem.readIntSliceLittle(u32, key[0..4]);122 k[0] = mem.readIntLittle(u32, key[0..4]);
124 k[1] = mem.readIntSliceLittle(u32, key[4..8]);123 k[1] = mem.readIntLittle(u32, key[4..8]);
125 k[2] = mem.readIntSliceLittle(u32, key[8..12]);124 k[2] = mem.readIntLittle(u32, key[8..12]);
126 k[3] = mem.readIntSliceLittle(u32, key[12..16]);125 k[3] = mem.readIntLittle(u32, key[12..16]);
127 k[4] = mem.readIntSliceLittle(u32, key[16..20]);126 k[4] = mem.readIntLittle(u32, key[16..20]);
128 k[5] = mem.readIntSliceLittle(u32, key[20..24]);127 k[5] = mem.readIntLittle(u32, key[20..24]);
129 k[6] = mem.readIntSliceLittle(u32, key[24..28]);128 k[6] = mem.readIntLittle(u32, key[24..28]);
130 k[7] = mem.readIntSliceLittle(u32, key[28..32]);129 k[7] = mem.readIntLittle(u32, key[28..32]);
131130
132 c[0] = counter;131 c[0] = counter;
133 c[1] = mem.readIntSliceLittle(u32, nonce[0..4]);132 c[1] = mem.readIntLittle(u32, nonce[0..4]);
134 c[2] = mem.readIntSliceLittle(u32, nonce[4..8]);133 c[2] = mem.readIntLittle(u32, nonce[4..8]);
135 c[3] = mem.readIntSliceLittle(u32, nonce[8..12]);134 c[3] = mem.readIntLittle(u32, nonce[8..12]);
136 chaCha20_internal(out, in, k, c);135 chaCha20_internal(out, in, k, c);
137}136}
138137
...@@ -147,19 +146,19 @@ pub fn chaCha20With64BitNonce(out: []u8, in: []const u8, counter: u64, key: [32]...@@ -147,19 +146,19 @@ pub fn chaCha20With64BitNonce(out: []u8, in: []const u8, counter: u64, key: [32]
147 var k: [8]u32 = undefined;146 var k: [8]u32 = undefined;
148 var c: [4]u32 = undefined;147 var c: [4]u32 = undefined;
149148
150 k[0] = mem.readIntSliceLittle(u32, key[0..4]);149 k[0] = mem.readIntLittle(u32, key[0..4]);
151 k[1] = mem.readIntSliceLittle(u32, key[4..8]);150 k[1] = mem.readIntLittle(u32, key[4..8]);
152 k[2] = mem.readIntSliceLittle(u32, key[8..12]);151 k[2] = mem.readIntLittle(u32, key[8..12]);
153 k[3] = mem.readIntSliceLittle(u32, key[12..16]);152 k[3] = mem.readIntLittle(u32, key[12..16]);
154 k[4] = mem.readIntSliceLittle(u32, key[16..20]);153 k[4] = mem.readIntLittle(u32, key[16..20]);
155 k[5] = mem.readIntSliceLittle(u32, key[20..24]);154 k[5] = mem.readIntLittle(u32, key[20..24]);
156 k[6] = mem.readIntSliceLittle(u32, key[24..28]);155 k[6] = mem.readIntLittle(u32, key[24..28]);
157 k[7] = mem.readIntSliceLittle(u32, key[28..32]);156 k[7] = mem.readIntLittle(u32, key[28..32]);
158157
159 c[0] = @truncate(u32, counter);158 c[0] = @truncate(u32, counter);
160 c[1] = @truncate(u32, counter >> 32);159 c[1] = @truncate(u32, counter >> 32);
161 c[2] = mem.readIntSliceLittle(u32, nonce[0..4]);160 c[2] = mem.readIntLittle(u32, nonce[0..4]);
162 c[3] = mem.readIntSliceLittle(u32, nonce[4..8]);161 c[3] = mem.readIntLittle(u32, nonce[4..8]);
163162
164 const block_size = (1 << 6);163 const block_size = (1 << 6);
165 // The full block size is greater than the address space on a 32bit machine164 // 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,...@@ -463,8 +462,8 @@ pub fn chacha20poly1305Seal(dst: []u8, plaintext: []const u8, data: []const u8,
463 mac.update(zeros[0..padding]);462 mac.update(zeros[0..padding]);
464 }463 }
465 var lens: [16]u8 = undefined;464 var lens: [16]u8 = undefined;
466 mem.writeIntSliceLittle(u64, lens[0..8], data.len);465 mem.writeIntLittle(u64, lens[0..8], data.len);
467 mem.writeIntSliceLittle(u64, lens[8..16], plaintext.len);466 mem.writeIntLittle(u64, lens[8..16], plaintext.len);
468 mac.update(lens[0..]);467 mac.update(lens[0..]);
469 mac.final(dst[plaintext.len..]);468 mac.final(dst[plaintext.len..]);
470}469}
...@@ -500,8 +499,8 @@ pub fn chacha20poly1305Open(dst: []u8, msgAndTag: []const u8, data: []const u8,...@@ -500,8 +499,8 @@ pub fn chacha20poly1305Open(dst: []u8, msgAndTag: []const u8, data: []const u8,
500 mac.update(zeros[0..padding]);499 mac.update(zeros[0..padding]);
501 }500 }
502 var lens: [16]u8 = undefined;501 var lens: [16]u8 = undefined;
503 mem.writeIntSliceLittle(u64, lens[0..8], data.len);502 mem.writeIntLittle(u64, lens[0..8], data.len);
504 mem.writeIntSliceLittle(u64, lens[8..16], ciphertext.len);503 mem.writeIntLittle(u64, lens[8..16], ciphertext.len);
505 mac.update(lens[0..]);504 mac.update(lens[0..]);
506 var computedTag: [16]u8 = undefined;505 var computedTag: [16]u8 = undefined;
507 mac.final(computedTag[0..]);506 mac.final(computedTag[0..]);
lib/std/crypto/md5.zig+1-2
...@@ -112,8 +112,7 @@ pub const Md5 = struct {...@@ -112,8 +112,7 @@ pub const Md5 = struct {
112 d.round(d.buf[0..]);112 d.round(d.buf[0..]);
113113
114 for (d.s) |s, j| {114 for (d.s) |s, j| {
115 // TODO https://github.com/ziglang/zig/issues/863115 mem.writeIntLittle(u32, out[4 * j ..][0..4], s);
116 mem.writeIntSliceLittle(u32, out[4 * j .. 4 * j + 4], s);
117 }116 }
118 }117 }
119118
lib/std/crypto/poly1305.zig+14-15
...@@ -3,11 +3,11 @@...@@ -3,11 +3,11 @@
3// https://monocypher.org/3// https://monocypher.org/
44
5const std = @import("../std.zig");5const std = @import("../std.zig");
6const builtin = @import("builtin");6const builtin = std.builtin;
77
8const Endian = builtin.Endian;8const Endian = builtin.Endian;
9const readIntSliceLittle = std.mem.readIntSliceLittle;9const readIntLittle = std.mem.readIntLittle;
10const writeIntSliceLittle = std.mem.writeIntSliceLittle;10const writeIntLittle = std.mem.writeIntLittle;
1111
12pub const Poly1305 = struct {12pub const Poly1305 = struct {
13 const Self = @This();13 const Self = @This();
...@@ -59,19 +59,19 @@ pub const Poly1305 = struct {...@@ -59,19 +59,19 @@ pub const Poly1305 = struct {
59 {59 {
60 var i: usize = 0;60 var i: usize = 0;
61 while (i < 1) : (i += 1) {61 while (i < 1) : (i += 1) {
62 ctx.r[0] = readIntSliceLittle(u32, key[0..4]) & 0x0fffffff;62 ctx.r[0] = readIntLittle(u32, key[0..4]) & 0x0fffffff;
63 }63 }
64 }64 }
65 {65 {
66 var i: usize = 1;66 var i: usize = 1;
67 while (i < 4) : (i += 1) {67 while (i < 4) : (i += 1) {
68 ctx.r[i] = readIntSliceLittle(u32, key[i * 4 .. i * 4 + 4]) & 0x0ffffffc;68 ctx.r[i] = readIntLittle(u32, key[i * 4 ..][0..4]) & 0x0ffffffc;
69 }69 }
70 }70 }
71 {71 {
72 var i: usize = 0;72 var i: usize = 0;
73 while (i < 4) : (i += 1) {73 while (i < 4) : (i += 1) {
74 ctx.pad[i] = readIntSliceLittle(u32, key[i * 4 + 16 .. i * 4 + 16 + 4]);74 ctx.pad[i] = readIntLittle(u32, key[i * 4 + 16 ..][0..4]);
75 }75 }
76 }76 }
7777
...@@ -168,10 +168,10 @@ pub const Poly1305 = struct {...@@ -168,10 +168,10 @@ pub const Poly1305 = struct {
168 const nb_blocks = nmsg.len >> 4;168 const nb_blocks = nmsg.len >> 4;
169 var i: usize = 0;169 var i: usize = 0;
170 while (i < nb_blocks) : (i += 1) {170 while (i < nb_blocks) : (i += 1) {
171 ctx.c[0] = readIntSliceLittle(u32, nmsg[0..4]);171 ctx.c[0] = readIntLittle(u32, nmsg[0..4]);
172 ctx.c[1] = readIntSliceLittle(u32, nmsg[4..8]);172 ctx.c[1] = readIntLittle(u32, nmsg[4..8]);
173 ctx.c[2] = readIntSliceLittle(u32, nmsg[8..12]);173 ctx.c[2] = readIntLittle(u32, nmsg[8..12]);
174 ctx.c[3] = readIntSliceLittle(u32, nmsg[12..16]);174 ctx.c[3] = readIntLittle(u32, nmsg[12..16]);
175 polyBlock(ctx);175 polyBlock(ctx);
176 nmsg = nmsg[16..];176 nmsg = nmsg[16..];
177 }177 }
...@@ -210,11 +210,10 @@ pub const Poly1305 = struct {...@@ -210,11 +210,10 @@ pub const Poly1305 = struct {
210 const uu2 = (uu1 >> 32) + ctx.h[2] + ctx.pad[2]; // <= 2_00000000210 const uu2 = (uu1 >> 32) + ctx.h[2] + ctx.pad[2]; // <= 2_00000000
211 const uu3 = (uu2 >> 32) + ctx.h[3] + ctx.pad[3]; // <= 2_00000000211 const uu3 = (uu2 >> 32) + ctx.h[3] + ctx.pad[3]; // <= 2_00000000
212212
213 // TODO https://github.com/ziglang/zig/issues/863213 writeIntLittle(u32, out[0..4], @truncate(u32, uu0));
214 writeIntSliceLittle(u32, out[0..], @truncate(u32, uu0));214 writeIntLittle(u32, out[4..8], @truncate(u32, uu1));
215 writeIntSliceLittle(u32, out[4..], @truncate(u32, uu1));215 writeIntLittle(u32, out[8..12], @truncate(u32, uu2));
216 writeIntSliceLittle(u32, out[8..], @truncate(u32, uu2));216 writeIntLittle(u32, out[12..16], @truncate(u32, uu3));
217 writeIntSliceLittle(u32, out[12..], @truncate(u32, uu3));
218217
219 ctx.secureZero();218 ctx.secureZero();
220 }219 }
lib/std/crypto/sha1.zig+1-2
...@@ -109,8 +109,7 @@ pub const Sha1 = struct {...@@ -109,8 +109,7 @@ pub const Sha1 = struct {
109 d.round(d.buf[0..]);109 d.round(d.buf[0..]);
110110
111 for (d.s) |s, j| {111 for (d.s) |s, j| {
112 // TODO https://github.com/ziglang/zig/issues/863112 mem.writeIntBig(u32, out[4 * j ..][0..4], s);
113 mem.writeIntSliceBig(u32, out[4 * j .. 4 * j + 4], s);
114 }113 }
115 }114 }
116115
lib/std/crypto/sha2.zig+2-4
...@@ -167,8 +167,7 @@ fn Sha2_32(comptime params: Sha2Params32) type {...@@ -167,8 +167,7 @@ fn Sha2_32(comptime params: Sha2Params32) type {
167 const rr = d.s[0 .. params.out_len / 32];167 const rr = d.s[0 .. params.out_len / 32];
168168
169 for (rr) |s, j| {169 for (rr) |s, j| {
170 // TODO https://github.com/ziglang/zig/issues/863170 mem.writeIntBig(u32, out[4 * j ..][0..4], s);
171 mem.writeIntSliceBig(u32, out[4 * j .. 4 * j + 4], s);
172 }171 }
173 }172 }
174173
...@@ -509,8 +508,7 @@ fn Sha2_64(comptime params: Sha2Params64) type {...@@ -509,8 +508,7 @@ fn Sha2_64(comptime params: Sha2Params64) type {
509 const rr = d.s[0 .. params.out_len / 64];508 const rr = d.s[0 .. params.out_len / 64];
510509
511 for (rr) |s, j| {510 for (rr) |s, j| {
512 // TODO https://github.com/ziglang/zig/issues/863511 mem.writeIntBig(u64, out[8 * j ..][0..8], s);
513 mem.writeIntSliceBig(u64, out[8 * j .. 8 * j + 8], s);
514 }512 }
515 }513 }
516514
lib/std/crypto/sha3.zig+2-3
...@@ -120,7 +120,7 @@ fn keccak_f(comptime F: usize, d: []u8) void {...@@ -120,7 +120,7 @@ fn keccak_f(comptime F: usize, d: []u8) void {
120 var c = [_]u64{0} ** 5;120 var c = [_]u64{0} ** 5;
121121
122 for (s) |*r, i| {122 for (s) |*r, i| {
123 r.* = mem.readIntSliceLittle(u64, d[8 * i .. 8 * i + 8]);123 r.* = mem.readIntLittle(u64, d[8 * i ..][0..8]);
124 }124 }
125125
126 comptime var x: usize = 0;126 comptime var x: usize = 0;
...@@ -167,8 +167,7 @@ fn keccak_f(comptime F: usize, d: []u8) void {...@@ -167,8 +167,7 @@ fn keccak_f(comptime F: usize, d: []u8) void {
167 }167 }
168168
169 for (s) |r, i| {169 for (s) |r, i| {
170 // TODO https://github.com/ziglang/zig/issues/863170 mem.writeIntLittle(u64, d[8 * i ..][0..8], r);
171 mem.writeIntSliceLittle(u64, d[8 * i .. 8 * i + 8], r);
172 }171 }
173}172}
174173
lib/std/crypto/x25519.zig+20-21
...@@ -7,8 +7,8 @@ const builtin = @import("builtin");...@@ -7,8 +7,8 @@ const builtin = @import("builtin");
7const fmt = std.fmt;7const fmt = std.fmt;
88
9const Endian = builtin.Endian;9const Endian = builtin.Endian;
10const readIntSliceLittle = std.mem.readIntSliceLittle;10const readIntLittle = std.mem.readIntLittle;
11const writeIntSliceLittle = std.mem.writeIntSliceLittle;11const writeIntLittle = std.mem.writeIntLittle;
1212
13// Based on Supercop's ref10 implementation.13// Based on Supercop's ref10 implementation.
14pub const X25519 = struct {14pub const X25519 = struct {
...@@ -255,16 +255,16 @@ const Fe = struct {...@@ -255,16 +255,16 @@ const Fe = struct {
255255
256 var t: [10]i64 = undefined;256 var t: [10]i64 = undefined;
257257
258 t[0] = readIntSliceLittle(u32, s[0..4]);258 t[0] = readIntLittle(u32, s[0..4]);
259 t[1] = @as(u32, readIntSliceLittle(u24, s[4..7])) << 6;259 t[1] = @as(u32, readIntLittle(u24, s[4..7])) << 6;
260 t[2] = @as(u32, readIntSliceLittle(u24, s[7..10])) << 5;260 t[2] = @as(u32, readIntLittle(u24, s[7..10])) << 5;
261 t[3] = @as(u32, readIntSliceLittle(u24, s[10..13])) << 3;261 t[3] = @as(u32, readIntLittle(u24, s[10..13])) << 3;
262 t[4] = @as(u32, readIntSliceLittle(u24, s[13..16])) << 2;262 t[4] = @as(u32, readIntLittle(u24, s[13..16])) << 2;
263 t[5] = readIntSliceLittle(u32, s[16..20]);263 t[5] = readIntLittle(u32, s[16..20]);
264 t[6] = @as(u32, readIntSliceLittle(u24, s[20..23])) << 7;264 t[6] = @as(u32, readIntLittle(u24, s[20..23])) << 7;
265 t[7] = @as(u32, readIntSliceLittle(u24, s[23..26])) << 5;265 t[7] = @as(u32, readIntLittle(u24, s[23..26])) << 5;
266 t[8] = @as(u32, readIntSliceLittle(u24, s[26..29])) << 4;266 t[8] = @as(u32, readIntLittle(u24, s[26..29])) << 4;
267 t[9] = (@as(u32, readIntSliceLittle(u24, s[29..32])) & 0x7fffff) << 2;267 t[9] = (@as(u32, readIntLittle(u24, s[29..32])) & 0x7fffff) << 2;
268268
269 carry1(h, t[0..]);269 carry1(h, t[0..]);
270 }270 }
...@@ -544,15 +544,14 @@ const Fe = struct {...@@ -544,15 +544,14 @@ const Fe = struct {
544 ut[i] = @bitCast(u32, @intCast(i32, t[i]));544 ut[i] = @bitCast(u32, @intCast(i32, t[i]));
545 }545 }
546546
547 // TODO https://github.com/ziglang/zig/issues/863547 writeIntLittle(u32, s[0..4], (ut[0] >> 0) | (ut[1] << 26));
548 writeIntSliceLittle(u32, s[0..4], (ut[0] >> 0) | (ut[1] << 26));548 writeIntLittle(u32, s[4..8], (ut[1] >> 6) | (ut[2] << 19));
549 writeIntSliceLittle(u32, s[4..8], (ut[1] >> 6) | (ut[2] << 19));549 writeIntLittle(u32, s[8..12], (ut[2] >> 13) | (ut[3] << 13));
550 writeIntSliceLittle(u32, s[8..12], (ut[2] >> 13) | (ut[3] << 13));550 writeIntLittle(u32, s[12..16], (ut[3] >> 19) | (ut[4] << 6));
551 writeIntSliceLittle(u32, s[12..16], (ut[3] >> 19) | (ut[4] << 6));551 writeIntLittle(u32, s[16..20], (ut[5] >> 0) | (ut[6] << 25));
552 writeIntSliceLittle(u32, s[16..20], (ut[5] >> 0) | (ut[6] << 25));552 writeIntLittle(u32, s[20..24], (ut[6] >> 7) | (ut[7] << 19));
553 writeIntSliceLittle(u32, s[20..24], (ut[6] >> 7) | (ut[7] << 19));553 writeIntLittle(u32, s[24..28], (ut[7] >> 13) | (ut[8] << 12));
554 writeIntSliceLittle(u32, s[24..28], (ut[7] >> 13) | (ut[8] << 12));554 writeIntLittle(u32, s[28..32], (ut[8] >> 20) | (ut[9] << 6));
555 writeIntSliceLittle(u32, s[28..], (ut[8] >> 20) | (ut[9] << 6));
556555
557 std.mem.secureZero(i64, t[0..]);556 std.mem.secureZero(i64, t[0..]);
558 }557 }
lib/std/fmt.zig+2-1
...@@ -1223,7 +1223,8 @@ test "slice" {...@@ -1223,7 +1223,8 @@ test "slice" {
1223 try testFmt("slice: abc\n", "slice: {}\n", .{value});1223 try testFmt("slice: abc\n", "slice: {}\n", .{value});
1224 }1224 }
1225 {1225 {
1226 const value = @intToPtr([*]align(1) const []const u8, 0xdeadbeef)[0..0];1226 var runtime_zero: usize = 0;
1227 const value = @intToPtr([*]align(1) const []const u8, 0xdeadbeef)[runtime_zero..runtime_zero];
1227 try testFmt("slice: []const u8@deadbeef\n", "slice: {}\n", .{value});1228 try testFmt("slice: []const u8@deadbeef\n", "slice: {}\n", .{value});
1228 }1229 }
12291230
lib/std/fs.zig+1-1
...@@ -341,7 +341,7 @@ pub const Dir = struct {...@@ -341,7 +341,7 @@ pub const Dir = struct {
341 if (self.index >= self.end_index) {341 if (self.index >= self.end_index) {
342 const rc = os.system.getdirentries(342 const rc = os.system.getdirentries(
343 self.dir.fd,343 self.dir.fd,
344 self.buf[0..].ptr,344 &self.buf,
345 self.buf.len,345 self.buf.len,
346 &self.seek,346 &self.seek,
347 );347 );
lib/std/hash/auto_hash.zig+8-4
...@@ -40,7 +40,9 @@ pub fn hashPointer(hasher: var, key: var, comptime strat: HashStrategy) void {...@@ -40,7 +40,9 @@ pub fn hashPointer(hasher: var, key: var, comptime strat: HashStrategy) void {
40 .DeepRecursive => hashArray(hasher, key, .DeepRecursive),40 .DeepRecursive => hashArray(hasher, key, .DeepRecursive),
41 },41 },
4242
43 .Many, .C, => switch (strat) {43 .Many,
44 .C,
45 => switch (strat) {
44 .Shallow => hash(hasher, @ptrToInt(key), .Shallow),46 .Shallow => hash(hasher, @ptrToInt(key), .Shallow),
45 else => @compileError(47 else => @compileError(
46 \\ unknown-length pointers and C pointers cannot be hashed deeply.48 \\ unknown-length pointers and C pointers cannot be hashed deeply.
...@@ -236,9 +238,11 @@ test "hash slice shallow" {...@@ -236,9 +238,11 @@ test "hash slice shallow" {
236 defer std.testing.allocator.destroy(array1);238 defer std.testing.allocator.destroy(array1);
237 array1.* = [_]u32{ 1, 2, 3, 4, 5, 6 };239 array1.* = [_]u32{ 1, 2, 3, 4, 5, 6 };
238 const array2 = [_]u32{ 1, 2, 3, 4, 5, 6 };240 const array2 = [_]u32{ 1, 2, 3, 4, 5, 6 };
239 const a = array1[0..];241 // TODO audit deep/shallow - maybe it has the wrong behavior with respect to array pointers and slices
240 const b = array2[0..];242 var runtime_zero: usize = 0;
241 const c = array1[0..3];243 const a = array1[runtime_zero..];
244 const b = array2[runtime_zero..];
245 const c = array1[runtime_zero..3];
242 testing.expect(testHashShallow(a) == testHashShallow(a));246 testing.expect(testHashShallow(a) == testHashShallow(a));
243 testing.expect(testHashShallow(a) != testHashShallow(array1));247 testing.expect(testHashShallow(a) != testHashShallow(array1));
244 testing.expect(testHashShallow(a) != testHashShallow(b));248 testing.expect(testHashShallow(a) != testHashShallow(b));
lib/std/hash/siphash.zig+3-3
...@@ -39,8 +39,8 @@ fn SipHashStateless(comptime T: type, comptime c_rounds: usize, comptime d_round...@@ -39,8 +39,8 @@ fn SipHashStateless(comptime T: type, comptime c_rounds: usize, comptime d_round
39 pub fn init(key: []const u8) Self {39 pub fn init(key: []const u8) Self {
40 assert(key.len >= 16);40 assert(key.len >= 16);
4141
42 const k0 = mem.readIntSliceLittle(u64, key[0..8]);42 const k0 = mem.readIntLittle(u64, key[0..8]);
43 const k1 = mem.readIntSliceLittle(u64, key[8..16]);43 const k1 = mem.readIntLittle(u64, key[8..16]);
4444
45 var d = Self{45 var d = Self{
46 .v0 = k0 ^ 0x736f6d6570736575,46 .v0 = k0 ^ 0x736f6d6570736575,
...@@ -111,7 +111,7 @@ fn SipHashStateless(comptime T: type, comptime c_rounds: usize, comptime d_round...@@ -111,7 +111,7 @@ fn SipHashStateless(comptime T: type, comptime c_rounds: usize, comptime d_round
111 fn round(self: *Self, b: []const u8) void {111 fn round(self: *Self, b: []const u8) void {
112 assert(b.len == 8);112 assert(b.len == 8);
113113
114 const m = mem.readIntSliceLittle(u64, b[0..]);114 const m = mem.readIntLittle(u64, b[0..8]);
115 self.v3 ^= m;115 self.v3 ^= m;
116116
117 // TODO this is a workaround, should be able to supply the value without a separate variable117 // TODO this is a workaround, should be able to supply the value without a separate variable
lib/std/hash/wyhash.zig+1-1
...@@ -11,7 +11,7 @@ const primes = [_]u64{...@@ -11,7 +11,7 @@ const primes = [_]u64{
1111
12fn read_bytes(comptime bytes: u8, data: []const u8) u64 {12fn read_bytes(comptime bytes: u8, data: []const u8) u64 {
13 const T = std.meta.IntType(false, 8 * bytes);13 const T = std.meta.IntType(false, 8 * bytes);
14 return mem.readIntSliceLittle(T, data[0..bytes]);14 return mem.readIntLittle(T, data[0..bytes]);
15}15}
1616
17fn read_8bytes_swapped(data: []const u8) u64 {17fn read_8bytes_swapped(data: []const u8) u64 {
lib/std/json.zig+16-7
...@@ -2249,11 +2249,16 @@ pub const StringifyOptions = struct {...@@ -2249,11 +2249,16 @@ pub const StringifyOptions = struct {
2249 // TODO: allow picking if []u8 is string or array?2249 // TODO: allow picking if []u8 is string or array?
2250};2250};
22512251
2252pub const StringifyError = error{
2253 TooMuchData,
2254 DifferentData,
2255};
2256
2252pub fn stringify(2257pub fn stringify(
2253 value: var,2258 value: var,
2254 options: StringifyOptions,2259 options: StringifyOptions,
2255 out_stream: var,2260 out_stream: var,
2256) !void {2261) StringifyError!void {
2257 const T = @TypeOf(value);2262 const T = @TypeOf(value);
2258 switch (@typeInfo(T)) {2263 switch (@typeInfo(T)) {
2259 .Float, .ComptimeFloat => {2264 .Float, .ComptimeFloat => {
...@@ -2320,9 +2325,15 @@ pub fn stringify(...@@ -2320,9 +2325,15 @@ pub fn stringify(
2320 return;2325 return;
2321 },2326 },
2322 .Pointer => |ptr_info| switch (ptr_info.size) {2327 .Pointer => |ptr_info| switch (ptr_info.size) {
2323 .One => {2328 .One => switch (@typeInfo(ptr_info.child)) {
2324 // TODO: avoid loops?2329 .Array => {
2325 return try stringify(value.*, options, out_stream);2330 const Slice = []const std.meta.Elem(ptr_info.child);
2331 return stringify(@as(Slice, value), options, out_stream);
2332 },
2333 else => {
2334 // TODO: avoid loops?
2335 return stringify(value.*, options, out_stream);
2336 },
2326 },2337 },
2327 // TODO: .Many when there is a sentinel (waiting for https://github.com/ziglang/zig/pull/3972)2338 // TODO: .Many when there is a sentinel (waiting for https://github.com/ziglang/zig/pull/3972)
2328 .Slice => {2339 .Slice => {
...@@ -2381,9 +2392,7 @@ pub fn stringify(...@@ -2381,9 +2392,7 @@ pub fn stringify(
2381 },2392 },
2382 else => @compileError("Unable to stringify type '" ++ @typeName(T) ++ "'"),2393 else => @compileError("Unable to stringify type '" ++ @typeName(T) ++ "'"),
2383 },2394 },
2384 .Array => |info| {2395 .Array => return stringify(&value, options, out_stream),
2385 return try stringify(value[0..], options, out_stream);
2386 },
2387 else => @compileError("Unable to stringify type '" ++ @typeName(T) ++ "'"),2396 else => @compileError("Unable to stringify type '" ++ @typeName(T) ++ "'"),
2388 }2397 }
2389 unreachable;2398 unreachable;
lib/std/mem.zig+46-67
...@@ -560,7 +560,7 @@ pub fn span(ptr: var) Span(@TypeOf(ptr)) {...@@ -560,7 +560,7 @@ pub fn span(ptr: var) Span(@TypeOf(ptr)) {
560560
561test "span" {561test "span" {
562 var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 };562 var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 };
563 const ptr = array[0..2 :3].ptr;563 const ptr = @as([*:3]u16, array[0..2 :3]);
564 testing.expect(eql(u16, span(ptr), &[_]u16{ 1, 2 }));564 testing.expect(eql(u16, span(ptr), &[_]u16{ 1, 2 }));
565 testing.expect(eql(u16, span(&array), &[_]u16{ 1, 2, 3, 4, 5 }));565 testing.expect(eql(u16, span(&array), &[_]u16{ 1, 2, 3, 4, 5 }));
566}566}
...@@ -602,7 +602,7 @@ test "len" {...@@ -602,7 +602,7 @@ test "len" {
602 testing.expect(len(&array) == 5);602 testing.expect(len(&array) == 5);
603 testing.expect(len(array[0..3]) == 3);603 testing.expect(len(array[0..3]) == 3);
604 array[2] = 0;604 array[2] = 0;
605 const ptr = array[0..2 :0].ptr;605 const ptr = @as([*:0]u16, array[0..2 :0]);
606 testing.expect(len(ptr) == 2);606 testing.expect(len(ptr) == 2);
607 }607 }
608 {608 {
...@@ -824,8 +824,7 @@ pub const readIntBig = switch (builtin.endian) {...@@ -824,8 +824,7 @@ pub const readIntBig = switch (builtin.endian) {
824pub fn readIntSliceNative(comptime T: type, bytes: []const u8) T {824pub fn readIntSliceNative(comptime T: type, bytes: []const u8) T {
825 const n = @divExact(T.bit_count, 8);825 const n = @divExact(T.bit_count, 8);
826 assert(bytes.len >= n);826 assert(bytes.len >= n);
827 // TODO https://github.com/ziglang/zig/issues/863827 return readIntNative(T, bytes[0..n]);
828 return readIntNative(T, @ptrCast(*const [n]u8, bytes.ptr));
829}828}
830829
831/// Asserts that bytes.len >= T.bit_count / 8. Reads the integer starting from index 0830/// 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...@@ -863,8 +862,7 @@ pub fn readInt(comptime T: type, bytes: *const [@divExact(T.bit_count, 8)]u8, en
863pub fn readIntSlice(comptime T: type, bytes: []const u8, endian: builtin.Endian) T {862pub fn readIntSlice(comptime T: type, bytes: []const u8, endian: builtin.Endian) T {
864 const n = @divExact(T.bit_count, 8);863 const n = @divExact(T.bit_count, 8);
865 assert(bytes.len >= n);864 assert(bytes.len >= n);
866 // TODO https://github.com/ziglang/zig/issues/863865 return readInt(T, bytes[0..n], endian);
867 return readInt(T, @ptrCast(*const [n]u8, bytes.ptr), endian);
868}866}
869867
870test "comptime read/write int" {868test "comptime read/write int" {
...@@ -1586,24 +1584,24 @@ pub fn nativeToBig(comptime T: type, x: T) T {...@@ -1586,24 +1584,24 @@ pub fn nativeToBig(comptime T: type, x: T) T {
1586}1584}
15871585
1588fn AsBytesReturnType(comptime P: type) type {1586fn AsBytesReturnType(comptime P: type) type {
1589 if (comptime !trait.isSingleItemPtr(P))1587 if (!trait.isSingleItemPtr(P))
1590 @compileError("expected single item pointer, passed " ++ @typeName(P));1588 @compileError("expected single item pointer, passed " ++ @typeName(P));
15911589
1592 const size = @as(usize, @sizeOf(meta.Child(P)));1590 const size = @sizeOf(meta.Child(P));
1593 const alignment = comptime meta.alignment(P);1591 const alignment = meta.alignment(P);
15941592
1595 if (alignment == 0) {1593 if (alignment == 0) {
1596 if (comptime trait.isConstPtr(P))1594 if (trait.isConstPtr(P))
1597 return *const [size]u8;1595 return *const [size]u8;
1598 return *[size]u8;1596 return *[size]u8;
1599 }1597 }
16001598
1601 if (comptime trait.isConstPtr(P))1599 if (trait.isConstPtr(P))
1602 return *align(alignment) const [size]u8;1600 return *align(alignment) const [size]u8;
1603 return *align(alignment) [size]u8;1601 return *align(alignment) [size]u8;
1604}1602}
16051603
1606///Given a pointer to a single item, returns a slice of the underlying bytes, preserving constness.1604/// Given a pointer to a single item, returns a slice of the underlying bytes, preserving constness.
1607pub fn asBytes(ptr: var) AsBytesReturnType(@TypeOf(ptr)) {1605pub fn asBytes(ptr: var) AsBytesReturnType(@TypeOf(ptr)) {
1608 const P = @TypeOf(ptr);1606 const P = @TypeOf(ptr);
1609 return @ptrCast(AsBytesReturnType(P), ptr);1607 return @ptrCast(AsBytesReturnType(P), ptr);
...@@ -1750,34 +1748,50 @@ fn BytesAsSliceReturnType(comptime T: type, comptime bytesType: type) type {...@@ -1750,34 +1748,50 @@ fn BytesAsSliceReturnType(comptime T: type, comptime bytesType: type) type {
1750}1748}
17511749
1752pub fn bytesAsSlice(comptime T: type, bytes: var) BytesAsSliceReturnType(T, @TypeOf(bytes)) {1750pub fn bytesAsSlice(comptime T: type, bytes: var) BytesAsSliceReturnType(T, @TypeOf(bytes)) {
1753 const bytesSlice = if (comptime trait.isPtrTo(.Array)(@TypeOf(bytes))) bytes[0..] else bytes;
1754
1755 // let's not give an undefined pointer to @ptrCast1751 // let's not give an undefined pointer to @ptrCast
1756 // it may be equal to zero and fail a null check1752 // it may be equal to zero and fail a null check
1757 if (bytesSlice.len == 0) {1753 if (bytes.len == 0) {
1758 return &[0]T{};1754 return &[0]T{};
1759 }1755 }
17601756
1761 const bytesType = @TypeOf(bytesSlice);1757 const Bytes = @TypeOf(bytes);
1762 const alignment = comptime meta.alignment(bytesType);1758 const alignment = comptime meta.alignment(Bytes);
17631759
1764 const castTarget = if (comptime trait.isConstPtr(bytesType)) [*]align(alignment) const T else [*]align(alignment) T;1760 const cast_target = if (comptime trait.isConstPtr(Bytes)) [*]align(alignment) const T else [*]align(alignment) T;
17651761
1766 return @ptrCast(castTarget, bytesSlice.ptr)[0..@divExact(bytes.len, @sizeOf(T))];1762 return @ptrCast(cast_target, bytes)[0..@divExact(bytes.len, @sizeOf(T))];
1767}1763}
17681764
1769test "bytesAsSlice" {1765test "bytesAsSlice" {
1770 const bytes = [_]u8{ 0xDE, 0xAD, 0xBE, 0xEF };1766 {
1771 const slice = bytesAsSlice(u16, bytes[0..]);1767 const bytes = [_]u8{ 0xDE, 0xAD, 0xBE, 0xEF };
1772 testing.expect(slice.len == 2);1768 const slice = bytesAsSlice(u16, bytes[0..]);
1773 testing.expect(bigToNative(u16, slice[0]) == 0xDEAD);1769 testing.expect(slice.len == 2);
1774 testing.expect(bigToNative(u16, slice[1]) == 0xBEEF);1770 testing.expect(bigToNative(u16, slice[0]) == 0xDEAD);
1771 testing.expect(bigToNative(u16, slice[1]) == 0xBEEF);
1772 }
1773 {
1774 const bytes = [_]u8{ 0xDE, 0xAD, 0xBE, 0xEF };
1775 var runtime_zero: usize = 0;
1776 const slice = bytesAsSlice(u16, bytes[runtime_zero..]);
1777 testing.expect(slice.len == 2);
1778 testing.expect(bigToNative(u16, slice[0]) == 0xDEAD);
1779 testing.expect(bigToNative(u16, slice[1]) == 0xBEEF);
1780 }
1775}1781}
17761782
1777test "bytesAsSlice keeps pointer alignment" {1783test "bytesAsSlice keeps pointer alignment" {
1778 var bytes = [_]u8{ 0x01, 0x02, 0x03, 0x04 };1784 {
1779 const numbers = bytesAsSlice(u32, bytes[0..]);1785 var bytes = [_]u8{ 0x01, 0x02, 0x03, 0x04 };
1780 comptime testing.expect(@TypeOf(numbers) == []align(@alignOf(@TypeOf(bytes))) u32);1786 const numbers = bytesAsSlice(u32, bytes[0..]);
1787 comptime testing.expect(@TypeOf(numbers) == []align(@alignOf(@TypeOf(bytes))) u32);
1788 }
1789 {
1790 var bytes = [_]u8{ 0x01, 0x02, 0x03, 0x04 };
1791 var runtime_zero: usize = 0;
1792 const numbers = bytesAsSlice(u32, bytes[runtime_zero..]);
1793 comptime testing.expect(@TypeOf(numbers) == []align(@alignOf(@TypeOf(bytes))) u32);
1794 }
1781}1795}
17821796
1783test "bytesAsSlice on a packed struct" {1797test "bytesAsSlice on a packed struct" {
...@@ -1813,21 +1827,19 @@ fn SliceAsBytesReturnType(comptime sliceType: type) type {...@@ -1813,21 +1827,19 @@ fn SliceAsBytesReturnType(comptime sliceType: type) type {
1813}1827}
18141828
1815pub fn sliceAsBytes(slice: var) SliceAsBytesReturnType(@TypeOf(slice)) {1829pub fn sliceAsBytes(slice: var) SliceAsBytesReturnType(@TypeOf(slice)) {
1816 const actualSlice = if (comptime trait.isPtrTo(.Array)(@TypeOf(slice))) slice[0..] else slice;1830 const Slice = @TypeOf(slice);
1817 const actualSliceTypeInfo = @typeInfo(@TypeOf(actualSlice)).Pointer;
18181831
1819 // let's not give an undefined pointer to @ptrCast1832 // let's not give an undefined pointer to @ptrCast
1820 // it may be equal to zero and fail a null check1833 // it may be equal to zero and fail a null check
1821 if (actualSlice.len == 0 and actualSliceTypeInfo.sentinel == null) {1834 if (slice.len == 0 and comptime meta.sentinel(Slice) == null) {
1822 return &[0]u8{};1835 return &[0]u8{};
1823 }1836 }
18241837
1825 const sliceType = @TypeOf(actualSlice);1838 const alignment = comptime meta.alignment(Slice);
1826 const alignment = comptime meta.alignment(sliceType);
18271839
1828 const castTarget = if (comptime trait.isConstPtr(sliceType)) [*]align(alignment) const u8 else [*]align(alignment) u8;1840 const cast_target = if (comptime trait.isConstPtr(Slice)) [*]align(alignment) const u8 else [*]align(alignment) u8;
18291841
1830 return @ptrCast(castTarget, actualSlice.ptr)[0 .. actualSlice.len * @sizeOf(comptime meta.Child(sliceType))];1842 return @ptrCast(cast_target, slice)[0 .. slice.len * @sizeOf(meta.Elem(Slice))];
1831}1843}
18321844
1833test "sliceAsBytes" {1845test "sliceAsBytes" {
...@@ -1897,39 +1909,6 @@ test "sliceAsBytes and bytesAsSlice back" {...@@ -1897,39 +1909,6 @@ test "sliceAsBytes and bytesAsSlice back" {
1897 testing.expect(bytes[11] == math.maxInt(u8));1909 testing.expect(bytes[11] == math.maxInt(u8));
1898}1910}
18991911
1900fn SubArrayPtrReturnType(comptime T: type, comptime length: usize) type {
1901 if (trait.isConstPtr(T))
1902 return *const [length]meta.Child(meta.Child(T));
1903 return *[length]meta.Child(meta.Child(T));
1904}
1905
1906/// Given a pointer to an array, returns a pointer to a portion of that array, preserving constness.
1907/// TODO this will be obsoleted by https://github.com/ziglang/zig/issues/863
1908pub fn subArrayPtr(
1909 ptr: var,
1910 comptime start: usize,
1911 comptime length: usize,
1912) SubArrayPtrReturnType(@TypeOf(ptr), length) {
1913 assert(start + length <= ptr.*.len);
1914
1915 const ReturnType = SubArrayPtrReturnType(@TypeOf(ptr), length);
1916 const T = meta.Child(meta.Child(@TypeOf(ptr)));
1917 return @ptrCast(ReturnType, &ptr[start]);
1918}
1919
1920test "subArrayPtr" {
1921 const a1: [6]u8 = "abcdef".*;
1922 const sub1 = subArrayPtr(&a1, 2, 3);
1923 testing.expect(eql(u8, sub1, "cde"));
1924
1925 var a2: [6]u8 = "abcdef".*;
1926 var sub2 = subArrayPtr(&a2, 2, 3);
1927
1928 testing.expect(eql(u8, sub2, "cde"));
1929 sub2[1] = 'X';
1930 testing.expect(eql(u8, &a2, "abcXef"));
1931}
1932
1933/// Round an address up to the nearest aligned address1912/// Round an address up to the nearest aligned address
1934/// The alignment must be a power of 2 and greater than 0.1913/// The alignment must be a power of 2 and greater than 0.
1935pub fn alignForward(addr: usize, alignment: usize) usize {1914pub fn alignForward(addr: usize, alignment: usize) usize {
lib/std/meta.zig+50-15
...@@ -104,7 +104,7 @@ pub fn Child(comptime T: type) type {...@@ -104,7 +104,7 @@ pub fn Child(comptime T: type) type {
104 .Array => |info| info.child,104 .Array => |info| info.child,
105 .Pointer => |info| info.child,105 .Pointer => |info| info.child,
106 .Optional => |info| info.child,106 .Optional => |info| info.child,
107 else => @compileError("Expected pointer, optional, or array type, " ++ "found '" ++ @typeName(T) ++ "'"),107 else => @compileError("Expected pointer, optional, or array type, found '" ++ @typeName(T) ++ "'"),
108 };108 };
109}109}
110110
...@@ -115,30 +115,65 @@ test "std.meta.Child" {...@@ -115,30 +115,65 @@ test "std.meta.Child" {
115 testing.expect(Child(?u8) == u8);115 testing.expect(Child(?u8) == u8);
116}116}
117117
118/// Given a type with a sentinel e.g. `[:0]u8`, returns the sentinel118/// Given a "memory span" type, returns the "element type".
119pub fn Sentinel(comptime T: type) Child(T) {119pub fn Elem(comptime T: type) type {
120 // comptime asserts that ptr has a sentinel
121 switch (@typeInfo(T)) {120 switch (@typeInfo(T)) {
122 .Array => |arrayInfo| {121 .Array => |info| return info.child,
123 return comptime arrayInfo.sentinel.?;122 .Pointer => |info| switch (info.size) {
123 .One => switch (@typeInfo(info.child)) {
124 .Array => |array_info| return array_info.child,
125 else => {},
126 },
127 .Many, .C, .Slice => return info.child,
124 },128 },
125 .Pointer => |ptrInfo| {129 else => {},
126 switch (ptrInfo.size) {130 }
127 .Many, .Slice => {131 @compileError("Expected pointer, slice, or array, found '" ++ @typeName(T) ++ "'");
128 return comptime ptrInfo.sentinel.?;132}
133
134test "std.meta.Elem" {
135 testing.expect(Elem([1]u8) == u8);
136 testing.expect(Elem([*]u8) == u8);
137 testing.expect(Elem([]u8) == u8);
138 testing.expect(Elem(*[10]u8) == u8);
139}
140
141/// Given a type which can have a sentinel e.g. `[:0]u8`, returns the sentinel value,
142/// or `null` if there is not one.
143/// Types which cannot possibly have a sentinel will be a compile error.
144pub fn sentinel(comptime T: type) ?Elem(T) {
145 switch (@typeInfo(T)) {
146 .Array => |info| return info.sentinel,
147 .Pointer => |info| {
148 switch (info.size) {
149 .Many, .Slice => return info.sentinel,
150 .One => switch (@typeInfo(info.child)) {
151 .Array => |array_info| return array_info.sentinel,
152 else => {},
129 },153 },
130 else => {},154 else => {},
131 }155 }
132 },156 },
133 else => {},157 else => {},
134 }158 }
135 @compileError("not a sentinel type, found '" ++ @typeName(T) ++ "'");159 @compileError("type '" ++ @typeName(T) ++ "' cannot possibly have a sentinel");
136}160}
137161
138test "std.meta.Sentinel" {162test "std.meta.sentinel" {
139 testing.expectEqual(@as(u8, 0), Sentinel([:0]u8));163 testSentinel();
140 testing.expectEqual(@as(u8, 0), Sentinel([*:0]u8));164 comptime testSentinel();
141 testing.expectEqual(@as(u8, 0), Sentinel([5:0]u8));165}
166
167fn testSentinel() void {
168 testing.expectEqual(@as(u8, 0), sentinel([:0]u8).?);
169 testing.expectEqual(@as(u8, 0), sentinel([*:0]u8).?);
170 testing.expectEqual(@as(u8, 0), sentinel([5:0]u8).?);
171 testing.expectEqual(@as(u8, 0), sentinel(*const [5:0]u8).?);
172
173 testing.expect(sentinel([]u8) == null);
174 testing.expect(sentinel([*]u8) == null);
175 testing.expect(sentinel([5]u8) == null);
176 testing.expect(sentinel(*const [5]u8) == null);
142}177}
143178
144pub fn containerLayout(comptime T: type) TypeInfo.ContainerLayout {179pub fn containerLayout(comptime T: type) TypeInfo.ContainerLayout {
lib/std/meta/trait.zig+7-5
...@@ -230,9 +230,10 @@ pub fn isSingleItemPtr(comptime T: type) bool {...@@ -230,9 +230,10 @@ pub fn isSingleItemPtr(comptime T: type) bool {
230230
231test "std.meta.trait.isSingleItemPtr" {231test "std.meta.trait.isSingleItemPtr" {
232 const array = [_]u8{0} ** 10;232 const array = [_]u8{0} ** 10;
233 testing.expect(isSingleItemPtr(@TypeOf(&array[0])));233 comptime testing.expect(isSingleItemPtr(@TypeOf(&array[0])));
234 testing.expect(!isSingleItemPtr(@TypeOf(array)));234 comptime testing.expect(!isSingleItemPtr(@TypeOf(array)));
235 testing.expect(!isSingleItemPtr(@TypeOf(array[0..1])));235 var runtime_zero: usize = 0;
236 testing.expect(!isSingleItemPtr(@TypeOf(array[runtime_zero..1])));
236}237}
237238
238pub fn isManyItemPtr(comptime T: type) bool {239pub fn isManyItemPtr(comptime T: type) bool {
...@@ -259,7 +260,8 @@ pub fn isSlice(comptime T: type) bool {...@@ -259,7 +260,8 @@ pub fn isSlice(comptime T: type) bool {
259260
260test "std.meta.trait.isSlice" {261test "std.meta.trait.isSlice" {
261 const array = [_]u8{0} ** 10;262 const array = [_]u8{0} ** 10;
262 testing.expect(isSlice(@TypeOf(array[0..])));263 var runtime_zero: usize = 0;
264 testing.expect(isSlice(@TypeOf(array[runtime_zero..])));
263 testing.expect(!isSlice(@TypeOf(array)));265 testing.expect(!isSlice(@TypeOf(array)));
264 testing.expect(!isSlice(@TypeOf(&array[0])));266 testing.expect(!isSlice(@TypeOf(&array[0])));
265}267}
...@@ -276,7 +278,7 @@ pub fn isIndexable(comptime T: type) bool {...@@ -276,7 +278,7 @@ pub fn isIndexable(comptime T: type) bool {
276278
277test "std.meta.trait.isIndexable" {279test "std.meta.trait.isIndexable" {
278 const array = [_]u8{0} ** 10;280 const array = [_]u8{0} ** 10;
279 const slice = array[0..];281 const slice = @as([]const u8, &array);
280282
281 testing.expect(isIndexable(@TypeOf(array)));283 testing.expect(isIndexable(@TypeOf(array)));
282 testing.expect(isIndexable(@TypeOf(&array)));284 testing.expect(isIndexable(@TypeOf(&array)));
lib/std/net.zig+7-5
...@@ -612,8 +612,7 @@ fn linuxLookupName(...@@ -612,8 +612,7 @@ fn linuxLookupName(
612 } else {612 } else {
613 mem.copy(u8, &sa6.addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff");613 mem.copy(u8, &sa6.addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff");
614 mem.copy(u8, &da6.addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff");614 mem.copy(u8, &da6.addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff");
615 // TODO https://github.com/ziglang/zig/issues/863615 mem.writeIntNative(u32, da6.addr[12..], addr.addr.in.addr);
616 mem.writeIntNative(u32, @ptrCast(*[4]u8, da6.addr[12..].ptr), addr.addr.in.addr);
617 da4.addr = addr.addr.in.addr;616 da4.addr = addr.addr.in.addr;
618 da = @ptrCast(*os.sockaddr, &da4);617 da = @ptrCast(*os.sockaddr, &da4);
619 dalen = @sizeOf(os.sockaddr_in);618 dalen = @sizeOf(os.sockaddr_in);
...@@ -821,7 +820,7 @@ fn linuxLookupNameFromHosts(...@@ -821,7 +820,7 @@ fn linuxLookupNameFromHosts(
821 // Skip to the delimiter in the stream, to fix parsing820 // Skip to the delimiter in the stream, to fix parsing
822 try stream.skipUntilDelimiterOrEof('\n');821 try stream.skipUntilDelimiterOrEof('\n');
823 // Use the truncated line. A truncated comment or hostname will be handled correctly.822 // Use the truncated line. A truncated comment or hostname will be handled correctly.
824 break :blk line_buf[0..];823 break :blk @as([]u8, &line_buf); // TODO the cast should not be necessary
825 },824 },
826 else => |e| return e,825 else => |e| return e,
827 }) |line| {826 }) |line| {
...@@ -958,7 +957,10 @@ fn linuxLookupNameFromDns(...@@ -958,7 +957,10 @@ fn linuxLookupNameFromDns(
958 }957 }
959 }958 }
960959
961 var ap = [2][]u8{ apbuf[0][0..0], apbuf[1][0..0] };960 var ap = [2][]u8{ apbuf[0], apbuf[1] };
961 ap[0].len = 0;
962 ap[1].len = 0;
963
962 try resMSendRc(qp[0..nq], ap[0..nq], apbuf[0..nq], rc);964 try resMSendRc(qp[0..nq], ap[0..nq], apbuf[0..nq], rc);
963965
964 var i: usize = 0;966 var i: usize = 0;
...@@ -1015,7 +1017,7 @@ fn getResolvConf(allocator: *mem.Allocator, rc: *ResolvConf) !void {...@@ -1015,7 +1017,7 @@ fn getResolvConf(allocator: *mem.Allocator, rc: *ResolvConf) !void {
1015 // Skip to the delimiter in the stream, to fix parsing1017 // Skip to the delimiter in the stream, to fix parsing
1016 try stream.skipUntilDelimiterOrEof('\n');1018 try stream.skipUntilDelimiterOrEof('\n');
1017 // Give an empty line to the while loop, which will be skipped.1019 // Give an empty line to the while loop, which will be skipped.
1018 break :blk line_buf[0..0];1020 break :blk @as([]u8, line_buf[0..0]); // TODO the cast should not be necessary
1019 },1021 },
1020 else => |e| return e,1022 else => |e| return e,
1021 }) |line| {1023 }) |line| {
lib/std/os/windows.zig+9-1
...@@ -1276,7 +1276,15 @@ pub fn unexpectedError(err: Win32Error) std.os.UnexpectedError {...@@ -1276,7 +1276,15 @@ pub fn unexpectedError(err: Win32Error) std.os.UnexpectedError {
1276 // 614 is the length of the longest windows error desciption1276 // 614 is the length of the longest windows error desciption
1277 var buf_u16: [614]u16 = undefined;1277 var buf_u16: [614]u16 = undefined;
1278 var buf_u8: [614]u8 = undefined;1278 var buf_u8: [614]u8 = undefined;
1279 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);1279 const len = kernel32.FormatMessageW(
1280 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
1281 null,
1282 err,
1283 MAKELANGID(LANG.NEUTRAL, SUBLANG.DEFAULT),
1284 &buf_u16,
1285 buf_u16.len / @sizeOf(TCHAR),
1286 null,
1287 );
1280 _ = std.unicode.utf16leToUtf8(&buf_u8, buf_u16[0..len]) catch unreachable;1288 _ = std.unicode.utf16leToUtf8(&buf_u8, buf_u16[0..len]) catch unreachable;
1281 std.debug.warn("error.Unexpected: GetLastError({}): {}\n", .{ @enumToInt(err), buf_u8[0..len] });1289 std.debug.warn("error.Unexpected: GetLastError({}): {}\n", .{ @enumToInt(err), buf_u8[0..len] });
1282 std.debug.dumpCurrentStackTrace(null);1290 std.debug.dumpCurrentStackTrace(null);
lib/std/rand.zig+1-1
...@@ -5,7 +5,7 @@...@@ -5,7 +5,7 @@
5// ```5// ```
6// var buf: [8]u8 = undefined;6// var buf: [8]u8 = undefined;
7// try std.crypto.randomBytes(buf[0..]);7// try std.crypto.randomBytes(buf[0..]);
8// const seed = mem.readIntSliceLittle(u64, buf[0..8]);8// const seed = mem.readIntLittle(u64, buf[0..8]);
9//9//
10// var r = DefaultPrng.init(seed);10// var r = DefaultPrng.init(seed);
11//11//
lib/std/unicode.zig+10-10
...@@ -251,12 +251,12 @@ pub const Utf16LeIterator = struct {...@@ -251,12 +251,12 @@ pub const Utf16LeIterator = struct {
251 pub fn nextCodepoint(it: *Utf16LeIterator) !?u21 {251 pub fn nextCodepoint(it: *Utf16LeIterator) !?u21 {
252 assert(it.i <= it.bytes.len);252 assert(it.i <= it.bytes.len);
253 if (it.i == it.bytes.len) return null;253 if (it.i == it.bytes.len) return null;
254 const c0: u21 = mem.readIntSliceLittle(u16, it.bytes[it.i .. it.i + 2]);254 const c0: u21 = mem.readIntLittle(u16, it.bytes[it.i..][0..2]);
255 if (c0 & ~@as(u21, 0x03ff) == 0xd800) {255 if (c0 & ~@as(u21, 0x03ff) == 0xd800) {
256 // surrogate pair256 // surrogate pair
257 it.i += 2;257 it.i += 2;
258 if (it.i >= it.bytes.len) return error.DanglingSurrogateHalf;258 if (it.i >= it.bytes.len) return error.DanglingSurrogateHalf;
259 const c1: u21 = mem.readIntSliceLittle(u16, it.bytes[it.i .. it.i + 2]);259 const c1: u21 = mem.readIntLittle(u16, it.bytes[it.i..][0..2]);
260 if (c1 & ~@as(u21, 0x03ff) != 0xdc00) return error.ExpectedSecondSurrogateHalf;260 if (c1 & ~@as(u21, 0x03ff) != 0xdc00) return error.ExpectedSecondSurrogateHalf;
261 it.i += 2;261 it.i += 2;
262 return 0x10000 + (((c0 & 0x03ff) << 10) | (c1 & 0x03ff));262 return 0x10000 + (((c0 & 0x03ff) << 10) | (c1 & 0x03ff));
...@@ -630,11 +630,11 @@ test "utf8ToUtf16LeWithNull" {...@@ -630,11 +630,11 @@ test "utf8ToUtf16LeWithNull" {
630 }630 }
631}631}
632632
633/// Converts a UTF-8 string literal into a UTF-16LE string literal. 633/// Converts a UTF-8 string literal into a UTF-16LE string literal.
634pub fn utf8ToUtf16LeStringLiteral(comptime utf8: []const u8) *const [calcUtf16LeLen(utf8) :0] u16 {634pub fn utf8ToUtf16LeStringLiteral(comptime utf8: []const u8) *const [calcUtf16LeLen(utf8):0]u16 {
635 comptime {635 comptime {
636 const len: usize = calcUtf16LeLen(utf8);636 const len: usize = calcUtf16LeLen(utf8);
637 var utf16le: [len :0]u16 = [_ :0]u16{0} ** len;637 var utf16le: [len:0]u16 = [_:0]u16{0} ** len;
638 const utf16le_len = utf8ToUtf16Le(&utf16le, utf8[0..]) catch |err| @compileError(err);638 const utf16le_len = utf8ToUtf16Le(&utf16le, utf8[0..]) catch |err| @compileError(err);
639 assert(len == utf16le_len);639 assert(len == utf16le_len);
640 return &utf16le;640 return &utf16le;
...@@ -660,8 +660,8 @@ fn calcUtf16LeLen(utf8: []const u8) usize {...@@ -660,8 +660,8 @@ fn calcUtf16LeLen(utf8: []const u8) usize {
660}660}
661661
662test "utf8ToUtf16LeStringLiteral" {662test "utf8ToUtf16LeStringLiteral" {
663{663 {
664 const bytes = [_:0]u16{ 0x41 };664 const bytes = [_:0]u16{0x41};
665 const utf16 = utf8ToUtf16LeStringLiteral("A");665 const utf16 = utf8ToUtf16LeStringLiteral("A");
666 testing.expectEqualSlices(u16, &bytes, utf16);666 testing.expectEqualSlices(u16, &bytes, utf16);
667 testing.expect(utf16[1] == 0);667 testing.expect(utf16[1] == 0);
...@@ -673,19 +673,19 @@ test "utf8ToUtf16LeStringLiteral" {...@@ -673,19 +673,19 @@ test "utf8ToUtf16LeStringLiteral" {
673 testing.expect(utf16[2] == 0);673 testing.expect(utf16[2] == 0);
674 }674 }
675 {675 {
676 const bytes = [_:0]u16{ 0x02FF };676 const bytes = [_:0]u16{0x02FF};
677 const utf16 = utf8ToUtf16LeStringLiteral("\u{02FF}");677 const utf16 = utf8ToUtf16LeStringLiteral("\u{02FF}");
678 testing.expectEqualSlices(u16, &bytes, utf16);678 testing.expectEqualSlices(u16, &bytes, utf16);
679 testing.expect(utf16[1] == 0);679 testing.expect(utf16[1] == 0);
680 }680 }
681 {681 {
682 const bytes = [_:0]u16{ 0x7FF };682 const bytes = [_:0]u16{0x7FF};
683 const utf16 = utf8ToUtf16LeStringLiteral("\u{7FF}");683 const utf16 = utf8ToUtf16LeStringLiteral("\u{7FF}");
684 testing.expectEqualSlices(u16, &bytes, utf16);684 testing.expectEqualSlices(u16, &bytes, utf16);
685 testing.expect(utf16[1] == 0);685 testing.expect(utf16[1] == 0);
686 }686 }
687 {687 {
688 const bytes = [_:0]u16{ 0x801 };688 const bytes = [_:0]u16{0x801};
689 const utf16 = utf8ToUtf16LeStringLiteral("\u{801}");689 const utf16 = utf8ToUtf16LeStringLiteral("\u{801}");
690 testing.expectEqualSlices(u16, &bytes, utf16);690 testing.expectEqualSlices(u16, &bytes, utf16);
691 testing.expect(utf16[1] == 0);691 testing.expect(utf16[1] == 0);
src-self-hosted/stage2.zig+1-1
...@@ -128,7 +128,7 @@ export fn stage2_translate_c(...@@ -128,7 +128,7 @@ export fn stage2_translate_c(
128 args_end: [*]?[*]const u8,128 args_end: [*]?[*]const u8,
129 resources_path: [*:0]const u8,129 resources_path: [*:0]const u8,
130) Error {130) Error {
131 var errors = @as([*]translate_c.ClangErrMsg, undefined)[0..0];131 var errors: []translate_c.ClangErrMsg = &[0]translate_c.ClangErrMsg{};
132 out_ast.* = translate_c.translate(std.heap.c_allocator, args_begin, args_end, &errors, resources_path) catch |err| switch (err) {132 out_ast.* = translate_c.translate(std.heap.c_allocator, args_begin, args_end, &errors, resources_path) catch |err| switch (err) {
133 error.SemanticAnalyzeFail => {133 error.SemanticAnalyzeFail => {
134 out_errors_ptr.* = errors.ptr;134 out_errors_ptr.* = errors.ptr;
src-self-hosted/translate_c.zig+12-14
...@@ -1744,20 +1744,18 @@ fn writeEscapedString(buf: []u8, s: []const u8) void {...@@ -1744,20 +1744,18 @@ fn writeEscapedString(buf: []u8, s: []const u8) void {
1744// Returns either a string literal or a slice of `buf`.1744// Returns either a string literal or a slice of `buf`.
1745fn escapeChar(c: u8, char_buf: *[4]u8) []const u8 {1745fn escapeChar(c: u8, char_buf: *[4]u8) []const u8 {
1746 return switch (c) {1746 return switch (c) {
1747 '\"' => "\\\""[0..],1747 '\"' => "\\\"",
1748 '\'' => "\\'"[0..],1748 '\'' => "\\'",
1749 '\\' => "\\\\"[0..],1749 '\\' => "\\\\",
1750 '\n' => "\\n"[0..],1750 '\n' => "\\n",
1751 '\r' => "\\r"[0..],1751 '\r' => "\\r",
1752 '\t' => "\\t"[0..],1752 '\t' => "\\t",
1753 else => {1753 // Handle the remaining escapes Zig doesn't support by turning them
1754 // Handle the remaining escapes Zig doesn't support by turning them1754 // into their respective hex representation
1755 // into their respective hex representation1755 else => if (std.ascii.isCntrl(c))
1756 if (std.ascii.isCntrl(c))1756 std.fmt.bufPrint(char_buf, "\\x{x:0<2}", .{c}) catch unreachable
1757 return std.fmt.bufPrint(char_buf[0..], "\\x{x:0<2}", .{c}) catch unreachable1757 else
1758 else1758 std.fmt.bufPrint(char_buf, "{c}", .{c}) catch unreachable,
1759 return std.fmt.bufPrint(char_buf[0..], "{c}", .{c}) catch unreachable;
1760 },
1761 };1759 };
1762}1760}
17631761
src/all_types.hpp+6
...@@ -231,6 +231,7 @@ enum ConstPtrSpecial {...@@ -231,6 +231,7 @@ enum ConstPtrSpecial {
231 // The pointer is a reference to a single object.231 // The pointer is a reference to a single object.
232 ConstPtrSpecialRef,232 ConstPtrSpecialRef,
233 // The pointer points to an element in an underlying array.233 // The pointer points to an element in an underlying array.
234 // Not to be confused with ConstPtrSpecialSubArray.
234 ConstPtrSpecialBaseArray,235 ConstPtrSpecialBaseArray,
235 // The pointer points to a field in an underlying struct.236 // The pointer points to a field in an underlying struct.
236 ConstPtrSpecialBaseStruct,237 ConstPtrSpecialBaseStruct,
...@@ -257,6 +258,10 @@ enum ConstPtrSpecial {...@@ -257,6 +258,10 @@ enum ConstPtrSpecial {
257 // types to be the same, so all optionals of pointer types use x_ptr258 // types to be the same, so all optionals of pointer types use x_ptr
258 // instead of x_optional.259 // instead of x_optional.
259 ConstPtrSpecialNull,260 ConstPtrSpecialNull,
261 // The pointer points to a sub-array (not an individual element).
262 // Not to be confused with ConstPtrSpecialBaseArray. However, it uses the same
263 // union payload struct (base_array).
264 ConstPtrSpecialSubArray,
260};265};
261266
262enum ConstPtrMut {267enum ConstPtrMut {
...@@ -3706,6 +3711,7 @@ struct IrInstGenSlice {...@@ -3706,6 +3711,7 @@ struct IrInstGenSlice {
3706 IrInstGen *start;3711 IrInstGen *start;
3707 IrInstGen *end;3712 IrInstGen *end;
3708 IrInstGen *result_loc;3713 IrInstGen *result_loc;
3714 ZigValue *sentinel;
3709 bool safety_check_on;3715 bool safety_check_on;
3710};3716};
37113717
src/analyze.cpp+32-6
...@@ -780,6 +780,8 @@ ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payloa...@@ -780,6 +780,8 @@ ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payloa
780}780}
781781
782ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, ZigValue *sentinel) {782ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, ZigValue *sentinel) {
783 Error err;
784
783 TypeId type_id = {};785 TypeId type_id = {};
784 type_id.id = ZigTypeIdArray;786 type_id.id = ZigTypeIdArray;
785 type_id.data.array.codegen = g;787 type_id.data.array.codegen = g;
...@@ -791,7 +793,11 @@ ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, Zi...@@ -791,7 +793,11 @@ ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, Zi
791 return existing_entry->value;793 return existing_entry->value;
792 }794 }
793795
794 assert(type_is_resolved(child_type, ResolveStatusSizeKnown));796 size_t full_array_size = array_size + ((sentinel != nullptr) ? 1 : 0);
797
798 if (full_array_size != 0 && (err = type_resolve(g, child_type, ResolveStatusSizeKnown))) {
799 codegen_report_errors_and_exit(g);
800 }
795801
796 ZigType *entry = new_type_table_entry(ZigTypeIdArray);802 ZigType *entry = new_type_table_entry(ZigTypeIdArray);
797803
...@@ -803,9 +809,8 @@ ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, Zi...@@ -803,9 +809,8 @@ ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, Zi
803 }809 }
804 buf_appendf(&entry->name, "]%s", buf_ptr(&child_type->name));810 buf_appendf(&entry->name, "]%s", buf_ptr(&child_type->name));
805811
806 size_t full_array_size = array_size + ((sentinel != nullptr) ? 1 : 0);
807 entry->size_in_bits = child_type->size_in_bits * full_array_size;812 entry->size_in_bits = child_type->size_in_bits * full_array_size;
808 entry->abi_align = child_type->abi_align;813 entry->abi_align = (full_array_size == 0) ? 0 : child_type->abi_align;
809 entry->abi_size = child_type->abi_size * full_array_size;814 entry->abi_size = child_type->abi_size * full_array_size;
810815
811 entry->data.array.child_type = child_type;816 entry->data.array.child_type = child_type;
...@@ -4483,7 +4488,14 @@ static uint32_t get_async_frame_align_bytes(CodeGen *g) {...@@ -4483,7 +4488,14 @@ static uint32_t get_async_frame_align_bytes(CodeGen *g) {
4483}4488}
44844489
4485uint32_t get_ptr_align(CodeGen *g, ZigType *type) {4490uint32_t get_ptr_align(CodeGen *g, ZigType *type) {
4486 ZigType *ptr_type = get_src_ptr_type(type);4491 ZigType *ptr_type;
4492 if (type->id == ZigTypeIdStruct) {
4493 assert(type->data.structure.special == StructSpecialSlice);
4494 TypeStructField *ptr_field = type->data.structure.fields[slice_ptr_index];
4495 ptr_type = resolve_struct_field_type(g, ptr_field);
4496 } else {
4497 ptr_type = get_src_ptr_type(type);
4498 }
4487 if (ptr_type->id == ZigTypeIdPointer) {4499 if (ptr_type->id == ZigTypeIdPointer) {
4488 return (ptr_type->data.pointer.explicit_alignment == 0) ?4500 return (ptr_type->data.pointer.explicit_alignment == 0) ?
4489 get_abi_alignment(g, ptr_type->data.pointer.child_type) : ptr_type->data.pointer.explicit_alignment;4501 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) {...@@ -4500,8 +4512,15 @@ uint32_t get_ptr_align(CodeGen *g, ZigType *type) {
4500 }4512 }
4501}4513}
45024514
4503bool get_ptr_const(ZigType *type) {4515bool get_ptr_const(CodeGen *g, ZigType *type) {
4504 ZigType *ptr_type = get_src_ptr_type(type);4516 ZigType *ptr_type;
4517 if (type->id == ZigTypeIdStruct) {
4518 assert(type->data.structure.special == StructSpecialSlice);
4519 TypeStructField *ptr_field = type->data.structure.fields[slice_ptr_index];
4520 ptr_type = resolve_struct_field_type(g, ptr_field);
4521 } else {
4522 ptr_type = get_src_ptr_type(type);
4523 }
4505 if (ptr_type->id == ZigTypeIdPointer) {4524 if (ptr_type->id == ZigTypeIdPointer) {
4506 return ptr_type->data.pointer.is_const;4525 return ptr_type->data.pointer.is_const;
4507 } else if (ptr_type->id == ZigTypeIdFn) {4526 } else if (ptr_type->id == ZigTypeIdFn) {
...@@ -5277,6 +5296,11 @@ static uint32_t hash_const_val_ptr(ZigValue *const_val) {...@@ -5277,6 +5296,11 @@ static uint32_t hash_const_val_ptr(ZigValue *const_val) {
5277 hash_val += hash_ptr(const_val->data.x_ptr.data.base_array.array_val);5296 hash_val += hash_ptr(const_val->data.x_ptr.data.base_array.array_val);
5278 hash_val += hash_size(const_val->data.x_ptr.data.base_array.elem_index);5297 hash_val += hash_size(const_val->data.x_ptr.data.base_array.elem_index);
5279 return hash_val;5298 return hash_val;
5299 case ConstPtrSpecialSubArray:
5300 hash_val += (uint32_t)2643358777;
5301 hash_val += hash_ptr(const_val->data.x_ptr.data.base_array.array_val);
5302 hash_val += hash_size(const_val->data.x_ptr.data.base_array.elem_index);
5303 return hash_val;
5280 case ConstPtrSpecialBaseStruct:5304 case ConstPtrSpecialBaseStruct:
5281 hash_val += (uint32_t)3518317043;5305 hash_val += (uint32_t)3518317043;
5282 hash_val += hash_ptr(const_val->data.x_ptr.data.base_struct.struct_val);5306 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) {...@@ -6743,6 +6767,7 @@ bool const_values_equal_ptr(ZigValue *a, ZigValue *b) {
6743 return false;6767 return false;
6744 return true;6768 return true;
6745 case ConstPtrSpecialBaseArray:6769 case ConstPtrSpecialBaseArray:
6770 case ConstPtrSpecialSubArray:
6746 if (a->data.x_ptr.data.base_array.array_val != b->data.x_ptr.data.base_array.array_val) {6771 if (a->data.x_ptr.data.base_array.array_val != b->data.x_ptr.data.base_array.array_val) {
6747 return false;6772 return false;
6748 }6773 }
...@@ -7000,6 +7025,7 @@ static void render_const_val_ptr(CodeGen *g, Buf *buf, ZigValue *const_val, ZigT...@@ -7000,6 +7025,7 @@ static void render_const_val_ptr(CodeGen *g, Buf *buf, ZigValue *const_val, ZigT
7000 render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr));7025 render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr));
7001 return;7026 return;
7002 case ConstPtrSpecialBaseArray:7027 case ConstPtrSpecialBaseArray:
7028 case ConstPtrSpecialSubArray:
7003 buf_appendf(buf, "*");7029 buf_appendf(buf, "*");
7004 // TODO we need a source node for const_ptr_pointee because it can generate compile errors7030 // TODO we need a source node for const_ptr_pointee because it can generate compile errors
7005 render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr));7031 render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr));
src/analyze.hpp+1-1
...@@ -76,7 +76,7 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node, bool all...@@ -76,7 +76,7 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node, bool all
7676
77ZigType *get_src_ptr_type(ZigType *type);77ZigType *get_src_ptr_type(ZigType *type);
78uint32_t get_ptr_align(CodeGen *g, ZigType *type);78uint32_t get_ptr_align(CodeGen *g, ZigType *type);
79bool get_ptr_const(ZigType *type);79bool get_ptr_const(CodeGen *g, ZigType *type);
80ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry);80ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry);
81ZigType *container_ref_type(ZigType *type_entry);81ZigType *container_ref_type(ZigType *type_entry);
82bool type_is_complete(ZigType *type_entry);82bool type_is_complete(ZigType *type_entry);
src/codegen.cpp+59-25
...@@ -5418,12 +5418,16 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI...@@ -5418,12 +5418,16 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI
5418 ZigType *array_type = array_ptr_type->data.pointer.child_type;5418 ZigType *array_type = array_ptr_type->data.pointer.child_type;
5419 LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type, array_ptr_type);5419 LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type, array_ptr_type);
54205420
5421 LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc);
5422
5423 bool want_runtime_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base);5421 bool want_runtime_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base);
54245422
5425 ZigType *res_slice_ptr_type = instruction->base.value->type->data.structure.fields[slice_ptr_index]->type_entry;5423 ZigType *result_type = instruction->base.value->type;
5426 ZigValue *sentinel = res_slice_ptr_type->data.pointer.sentinel;5424 if (!type_has_bits(g, result_type)) {
5425 return nullptr;
5426 }
5427
5428 // This is not whether the result type has a sentinel, but whether there should be a sentinel check,
5429 // e.g. if they used [a..b :s] syntax.
5430 ZigValue *sentinel = instruction->sentinel;
54275431
5428 if (array_type->id == ZigTypeIdArray ||5432 if (array_type->id == ZigTypeIdArray ||
5429 (array_type->id == ZigTypeIdPointer && array_type->data.pointer.ptr_len == PtrLenSingle))5433 (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...@@ -5458,6 +5462,8 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI
5458 }5462 }
5459 }5463 }
5460 if (!type_has_bits(g, array_type)) {5464 if (!type_has_bits(g, array_type)) {
5465 LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc);
5466
5461 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, "");5467 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, "");
54625468
5463 // TODO if runtime safety is on, store 0xaaaaaaa in ptr field5469 // 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...@@ -5466,20 +5472,26 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI
5466 return tmp_struct_ptr;5472 return tmp_struct_ptr;
5467 }5473 }
54685474
5469
5470 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_ptr_index, "");
5471 LLVMValueRef indices[] = {5475 LLVMValueRef indices[] = {
5472 LLVMConstNull(g->builtin_types.entry_usize->llvm_type),5476 LLVMConstNull(g->builtin_types.entry_usize->llvm_type),
5473 start_val,5477 start_val,
5474 };5478 };
5475 LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, "");5479 LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, "");
5476 gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false);5480 if (result_type->id == ZigTypeIdPointer) {
5481 ir_assert(instruction->result_loc == nullptr, &instruction->base);
5482 LLVMTypeRef result_ptr_type = get_llvm_type(g, result_type);
5483 return LLVMBuildBitCast(g->builder, slice_start_ptr, result_ptr_type, "");
5484 } else {
5485 LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc);
5486 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_ptr_index, "");
5487 gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false);
54775488
5478 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, "");5489 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, "");
5479 LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, "");5490 LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, "");
5480 gen_store_untyped(g, len_value, len_field_ptr, 0, false);5491 gen_store_untyped(g, len_value, len_field_ptr, 0, false);
54815492
5482 return tmp_struct_ptr;5493 return tmp_struct_ptr;
5494 }
5483 } else if (array_type->id == ZigTypeIdPointer) {5495 } else if (array_type->id == ZigTypeIdPointer) {
5484 assert(array_type->data.pointer.ptr_len != PtrLenSingle);5496 assert(array_type->data.pointer.ptr_len != PtrLenSingle);
5485 LLVMValueRef start_val = ir_llvm_value(g, instruction->start);5497 LLVMValueRef start_val = ir_llvm_value(g, instruction->start);
...@@ -5493,24 +5505,39 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI...@@ -5493,24 +5505,39 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI
5493 }5505 }
5494 }5506 }
54955507
5496 if (type_has_bits(g, array_type)) {5508 if (!type_has_bits(g, array_type)) {
5497 size_t gen_ptr_index = instruction->base.value->type->data.structure.fields[slice_ptr_index]->gen_index;5509 LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc);
5498 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_ptr_index, "");5510 size_t gen_len_index = result_type->data.structure.fields[slice_len_index]->gen_index;
5499 LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, &start_val, 1, "");5511 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_len_index, "");
5500 gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false);5512 LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, "");
5513 gen_store_untyped(g, len_value, len_field_ptr, 0, false);
5514 return tmp_struct_ptr;
5515 }
5516
5517 LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, &start_val, 1, "");
5518 if (result_type->id == ZigTypeIdPointer) {
5519 ir_assert(instruction->result_loc == nullptr, &instruction->base);
5520 LLVMTypeRef result_ptr_type = get_llvm_type(g, result_type);
5521 return LLVMBuildBitCast(g->builder, slice_start_ptr, result_ptr_type, "");
5501 }5522 }
55025523
5503 size_t gen_len_index = instruction->base.value->type->data.structure.fields[slice_len_index]->gen_index;5524 LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc);
5525
5526 size_t gen_ptr_index = result_type->data.structure.fields[slice_ptr_index]->gen_index;
5527 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_ptr_index, "");
5528 gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false);
5529
5530 size_t gen_len_index = result_type->data.structure.fields[slice_len_index]->gen_index;
5504 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_len_index, "");5531 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_len_index, "");
5505 LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, "");5532 LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, "");
5506 gen_store_untyped(g, len_value, len_field_ptr, 0, false);5533 gen_store_untyped(g, len_value, len_field_ptr, 0, false);
55075534
5508 return tmp_struct_ptr;5535 return tmp_struct_ptr;
5536
5509 } else if (array_type->id == ZigTypeIdStruct) {5537 } else if (array_type->id == ZigTypeIdStruct) {
5510 assert(array_type->data.structure.special == StructSpecialSlice);5538 assert(array_type->data.structure.special == StructSpecialSlice);
5511 assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind);5539 assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind);
5512 assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind);5540 assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind);
5513 assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(tmp_struct_ptr))) == LLVMStructTypeKind);
55145541
5515 size_t ptr_index = array_type->data.structure.fields[slice_ptr_index]->gen_index;5542 size_t ptr_index = array_type->data.structure.fields[slice_ptr_index]->gen_index;
5516 assert(ptr_index != SIZE_MAX);5543 assert(ptr_index != SIZE_MAX);
...@@ -5547,15 +5574,22 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI...@@ -5547,15 +5574,22 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI
5547 }5574 }
5548 }5575 }
55495576
5550 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, (unsigned)ptr_index, "");
5551 LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr, &start_val, 1, "");5577 LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr, &start_val, 1, "");
5552 gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false);5578 if (result_type->id == ZigTypeIdPointer) {
5579 ir_assert(instruction->result_loc == nullptr, &instruction->base);
5580 LLVMTypeRef result_ptr_type = get_llvm_type(g, result_type);
5581 return LLVMBuildBitCast(g->builder, slice_start_ptr, result_ptr_type, "");
5582 } else {
5583 LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc);
5584 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, (unsigned)ptr_index, "");
5585 gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false);
55535586
5554 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, (unsigned)len_index, "");5587 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, (unsigned)len_index, "");
5555 LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, "");5588 LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, "");
5556 gen_store_untyped(g, len_value, len_field_ptr, 0, false);5589 gen_store_untyped(g, len_value, len_field_ptr, 0, false);
55575590
5558 return tmp_struct_ptr;5591 return tmp_struct_ptr;
5592 }
5559 } else {5593 } else {
5560 zig_unreachable();5594 zig_unreachable();
5561 }5595 }
...@@ -6640,7 +6674,6 @@ static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ZigValue *array_co...@@ -6640,7 +6674,6 @@ static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ZigValue *array_co
6640 };6674 };
6641 return LLVMConstInBoundsGEP(base_ptr, indices, 2);6675 return LLVMConstInBoundsGEP(base_ptr, indices, 2);
6642 } else {6676 } else {
6643 assert(parent->id == ConstParentIdScalar);
6644 return base_ptr;6677 return base_ptr;
6645 }6678 }
6646}6679}
...@@ -6868,6 +6901,7 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ZigValue *const_val, const cha...@@ -6868,6 +6901,7 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ZigValue *const_val, const cha
6868 return const_val->llvm_value;6901 return const_val->llvm_value;
6869 }6902 }
6870 case ConstPtrSpecialBaseArray:6903 case ConstPtrSpecialBaseArray:
6904 case ConstPtrSpecialSubArray:
6871 {6905 {
6872 ZigValue *array_const_val = const_val->data.x_ptr.data.base_array.array_val;6906 ZigValue *array_const_val = const_val->data.x_ptr.data.base_array.array_val;
6873 assert(array_const_val->type->id == ZigTypeIdArray);6907 assert(array_const_val->type->id == ZigTypeIdArray);
src/ir.cpp+324-91
...@@ -784,14 +784,32 @@ static ZigValue *const_ptr_pointee_unchecked_no_isf(CodeGen *g, ZigValue *const_...@@ -784,14 +784,32 @@ static ZigValue *const_ptr_pointee_unchecked_no_isf(CodeGen *g, ZigValue *const_
784 break;784 break;
785 case ConstPtrSpecialBaseArray: {785 case ConstPtrSpecialBaseArray: {
786 ZigValue *array_val = const_val->data.x_ptr.data.base_array.array_val;786 ZigValue *array_val = const_val->data.x_ptr.data.base_array.array_val;
787 if (const_val->data.x_ptr.data.base_array.elem_index == array_val->type->data.array.len) {787 size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index;
788 if (elem_index == array_val->type->data.array.len) {
788 result = array_val->type->data.array.sentinel;789 result = array_val->type->data.array.sentinel;
789 } else {790 } else {
790 expand_undef_array(g, array_val);791 expand_undef_array(g, array_val);
791 result = &array_val->data.x_array.data.s_none.elements[const_val->data.x_ptr.data.base_array.elem_index];792 result = &array_val->data.x_array.data.s_none.elements[elem_index];
792 }793 }
793 break;794 break;
794 }795 }
796 case ConstPtrSpecialSubArray: {
797 ZigValue *array_val = const_val->data.x_ptr.data.base_array.array_val;
798 size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index;
799
800 // TODO handle sentinel terminated arrays
801 expand_undef_array(g, array_val);
802 result = g->pass1_arena->create<ZigValue>();
803 result->special = array_val->special;
804 result->type = get_array_type(g, array_val->type->data.array.child_type,
805 array_val->type->data.array.len - elem_index, nullptr);
806 result->data.x_array.special = ConstArraySpecialNone;
807 result->data.x_array.data.s_none.elements = &array_val->data.x_array.data.s_none.elements[elem_index];
808 result->parent.id = ConstParentIdArray;
809 result->parent.data.p_array.array_val = array_val;
810 result->parent.data.p_array.elem_index = elem_index;
811 break;
812 }
795 case ConstPtrSpecialBaseStruct: {813 case ConstPtrSpecialBaseStruct: {
796 ZigValue *struct_val = const_val->data.x_ptr.data.base_struct.struct_val;814 ZigValue *struct_val = const_val->data.x_ptr.data.base_struct.struct_val;
797 expand_undef_struct(g, struct_val);815 expand_undef_struct(g, struct_val);
...@@ -849,11 +867,6 @@ static bool is_slice(ZigType *type) {...@@ -849,11 +867,6 @@ static bool is_slice(ZigType *type) {
849 return type->id == ZigTypeIdStruct && type->data.structure.special == StructSpecialSlice;867 return type->id == ZigTypeIdStruct && type->data.structure.special == StructSpecialSlice;
850}868}
851869
852static bool slice_is_const(ZigType *type) {
853 assert(is_slice(type));
854 return type->data.structure.fields[slice_ptr_index]->type_entry->data.pointer.is_const;
855}
856
857// This function returns true when you can change the type of a ZigValue and the870// This function returns true when you can change the type of a ZigValue and the
858// value remains meaningful.871// value remains meaningful.
859static bool types_have_same_zig_comptime_repr(CodeGen *codegen, ZigType *expected, ZigType *actual) {872static 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...@@ -3719,7 +3732,8 @@ static IrInstSrc *ir_build_slice_src(IrBuilderSrc *irb, Scope *scope, AstNode *s
3719}3732}
37203733
3721static IrInstGen *ir_build_slice_gen(IrAnalyze *ira, IrInst *source_instruction, ZigType *slice_type,3734static IrInstGen *ir_build_slice_gen(IrAnalyze *ira, IrInst *source_instruction, ZigType *slice_type,
3722 IrInstGen *ptr, IrInstGen *start, IrInstGen *end, bool safety_check_on, IrInstGen *result_loc)3735 IrInstGen *ptr, IrInstGen *start, IrInstGen *end, bool safety_check_on, IrInstGen *result_loc,
3736 ZigValue *sentinel)
3723{3737{
3724 IrInstGenSlice *instruction = ir_build_inst_gen<IrInstGenSlice>(3738 IrInstGenSlice *instruction = ir_build_inst_gen<IrInstGenSlice>(
3725 &ira->new_irb, source_instruction->scope, source_instruction->source_node);3739 &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,...@@ -3729,11 +3743,12 @@ static IrInstGen *ir_build_slice_gen(IrAnalyze *ira, IrInst *source_instruction,
3729 instruction->end = end;3743 instruction->end = end;
3730 instruction->safety_check_on = safety_check_on;3744 instruction->safety_check_on = safety_check_on;
3731 instruction->result_loc = result_loc;3745 instruction->result_loc = result_loc;
3746 instruction->sentinel = sentinel;
37323747
3733 ir_ref_inst_gen(ptr, ira->new_irb.current_basic_block);3748 ir_ref_inst_gen(ptr, ira->new_irb.current_basic_block);
3734 ir_ref_inst_gen(start, ira->new_irb.current_basic_block);3749 ir_ref_inst_gen(start, ira->new_irb.current_basic_block);
3735 if (end) ir_ref_inst_gen(end, ira->new_irb.current_basic_block);3750 if (end != nullptr) ir_ref_inst_gen(end, ira->new_irb.current_basic_block);
3736 ir_ref_inst_gen(result_loc, ira->new_irb.current_basic_block);3751 if (result_loc != nullptr) ir_ref_inst_gen(result_loc, ira->new_irb.current_basic_block);
37373752
3738 return &instruction->base;3753 return &instruction->base;
3739}3754}
...@@ -12677,41 +12692,80 @@ static IrInstGen *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInst* sourc...@@ -12677,41 +12692,80 @@ static IrInstGen *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInst* sourc
12677 Error err;12692 Error err;
1267812693
12679 assert(array_ptr->value->type->id == ZigTypeIdPointer);12694 assert(array_ptr->value->type->id == ZigTypeIdPointer);
12695 assert(array_ptr->value->type->data.pointer.child_type->id == ZigTypeIdArray);
12696
12697 ZigType *array_type = array_ptr->value->type->data.pointer.child_type;
12698 size_t array_len = array_type->data.array.len;
12699
12700 // A zero-sized array can be casted regardless of the destination alignment, or
12701 // whether the pointer is undefined, and the result is always comptime known.
12702 // TODO However, this is exposing a result location bug that I failed to solve on the first try.
12703 // If you want to try to fix the bug, uncomment this block and get the tests passing.
12704 //if (array_len == 0 && array_type->data.array.sentinel == nullptr) {
12705 // ZigValue *undef_array = ira->codegen->pass1_arena->create<ZigValue>();
12706 // undef_array->special = ConstValSpecialUndef;
12707 // undef_array->type = array_type;
12708
12709 // IrInstGen *result = ir_const(ira, source_instr, wanted_type);
12710 // init_const_slice(ira->codegen, result->value, undef_array, 0, 0, false);
12711 // result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = ConstPtrMutComptimeConst;
12712 // result->value->type = wanted_type;
12713 // return result;
12714 //}
1268012715
12681 if ((err = type_resolve(ira->codegen, array_ptr->value->type, ResolveStatusAlignmentKnown))) {12716 if ((err = type_resolve(ira->codegen, array_ptr->value->type, ResolveStatusAlignmentKnown))) {
12682 return ira->codegen->invalid_inst_gen;12717 return ira->codegen->invalid_inst_gen;
12683 }12718 }
1268412719
12685 assert(array_ptr->value->type->data.pointer.child_type->id == ZigTypeIdArray);
12686
12687 const size_t array_len = array_ptr->value->type->data.pointer.child_type->data.array.len;
12688
12689 // A zero-sized array can always be casted irregardless of the destination
12690 // alignment
12691 if (array_len != 0) {12720 if (array_len != 0) {
12692 wanted_type = adjust_slice_align(ira->codegen, wanted_type,12721 wanted_type = adjust_slice_align(ira->codegen, wanted_type,
12693 get_ptr_align(ira->codegen, array_ptr->value->type));12722 get_ptr_align(ira->codegen, array_ptr->value->type));
12694 }12723 }
1269512724
12696 if (instr_is_comptime(array_ptr)) {12725 if (instr_is_comptime(array_ptr)) {
12697 ZigValue *array_ptr_val = ir_resolve_const(ira, array_ptr, UndefBad);12726 UndefAllowed undef_allowed = (array_len == 0) ? UndefOk : UndefBad;
12727 ZigValue *array_ptr_val = ir_resolve_const(ira, array_ptr, undef_allowed);
12698 if (array_ptr_val == nullptr)12728 if (array_ptr_val == nullptr)
12699 return ira->codegen->invalid_inst_gen;12729 return ira->codegen->invalid_inst_gen;
12700 ZigValue *pointee = const_ptr_pointee(ira, ira->codegen, array_ptr_val, source_instr->source_node);12730 ir_assert(is_slice(wanted_type), source_instr);
12701 if (pointee == nullptr)12731 if (array_ptr_val->special == ConstValSpecialUndef) {
12702 return ira->codegen->invalid_inst_gen;12732 ZigValue *undef_array = ira->codegen->pass1_arena->create<ZigValue>();
12703 if (pointee->special != ConstValSpecialRuntime) {12733 undef_array->special = ConstValSpecialUndef;
12704 assert(array_ptr_val->type->id == ZigTypeIdPointer);12734 undef_array->type = array_type;
12705 ZigType *array_type = array_ptr_val->type->data.pointer.child_type;
12706 assert(is_slice(wanted_type));
12707 bool is_const = wanted_type->data.structure.fields[slice_ptr_index]->type_entry->data.pointer.is_const;
1270812735
12709 IrInstGen *result = ir_const(ira, source_instr, wanted_type);12736 IrInstGen *result = ir_const(ira, source_instr, wanted_type);
12710 init_const_slice(ira->codegen, result->value, pointee, 0, array_type->data.array.len, is_const);12737 init_const_slice(ira->codegen, result->value, undef_array, 0, 0, false);
12711 result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = array_ptr_val->data.x_ptr.mut;12738 result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = ConstPtrMutComptimeConst;
12712 result->value->type = wanted_type;12739 result->value->type = wanted_type;
12713 return result;12740 return result;
12714 }12741 }
12742 bool wanted_const = wanted_type->data.structure.fields[slice_ptr_index]->type_entry->data.pointer.is_const;
12743 // Optimization to avoid creating unnecessary ZigValue in const_ptr_pointee
12744 if (array_ptr_val->data.x_ptr.special == ConstPtrSpecialSubArray) {
12745 ZigValue *array_val = array_ptr_val->data.x_ptr.data.base_array.array_val;
12746 if (array_val->special != ConstValSpecialRuntime) {
12747 IrInstGen *result = ir_const(ira, source_instr, wanted_type);
12748 init_const_slice(ira->codegen, result->value, array_val,
12749 array_ptr_val->data.x_ptr.data.base_array.elem_index,
12750 array_type->data.array.len, wanted_const);
12751 result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = array_ptr_val->data.x_ptr.mut;
12752 result->value->type = wanted_type;
12753 return result;
12754 }
12755 } else {
12756 ZigValue *pointee = const_ptr_pointee(ira, ira->codegen, array_ptr_val, source_instr->source_node);
12757 if (pointee == nullptr)
12758 return ira->codegen->invalid_inst_gen;
12759 if (pointee->special != ConstValSpecialRuntime) {
12760 assert(array_ptr_val->type->id == ZigTypeIdPointer);
12761
12762 IrInstGen *result = ir_const(ira, source_instr, wanted_type);
12763 init_const_slice(ira->codegen, result->value, pointee, 0, array_type->data.array.len, wanted_const);
12764 result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = array_ptr_val->data.x_ptr.mut;
12765 result->value->type = wanted_type;
12766 return result;
12767 }
12768 }
12715 }12769 }
1271612770
12717 if (result_loc == nullptr) result_loc = no_result_loc();12771 if (result_loc == nullptr) result_loc = no_result_loc();
...@@ -14581,7 +14635,7 @@ static IrInstGen *ir_analyze_cast(IrAnalyze *ira, IrInst *source_instr,...@@ -14581,7 +14635,7 @@ static IrInstGen *ir_analyze_cast(IrAnalyze *ira, IrInst *source_instr,
14581 return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type);14635 return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type);
14582 }14636 }
1458314637
14584 // *[N]T to ?[]const T14638 // *[N]T to ?[]T
14585 if (wanted_type->id == ZigTypeIdOptional &&14639 if (wanted_type->id == ZigTypeIdOptional &&
14586 is_slice(wanted_type->data.maybe.child_type) &&14640 is_slice(wanted_type->data.maybe.child_type) &&
14587 actual_type->id == ZigTypeIdPointer &&14641 actual_type->id == ZigTypeIdPointer &&
...@@ -19917,6 +19971,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source...@@ -19917,6 +19971,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source
19917 buf_write_value_bytes(codegen, (uint8_t*)buf_ptr(&buf), pointee);19971 buf_write_value_bytes(codegen, (uint8_t*)buf_ptr(&buf), pointee);
19918 if ((err = buf_read_value_bytes(ira, codegen, source_node, (uint8_t*)buf_ptr(&buf), out_val)))19972 if ((err = buf_read_value_bytes(ira, codegen, source_node, (uint8_t*)buf_ptr(&buf), out_val)))
19919 return err;19973 return err;
19974 buf_deinit(&buf);
19920 return ErrorNone;19975 return ErrorNone;
19921 }19976 }
1992219977
...@@ -19936,6 +19991,31 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source...@@ -19936,6 +19991,31 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source
19936 dst_size, buf_ptr(&pointee->type->name), src_size));19991 dst_size, buf_ptr(&pointee->type->name), src_size));
19937 return ErrorSemanticAnalyzeFail;19992 return ErrorSemanticAnalyzeFail;
19938 }19993 }
19994 case ConstPtrSpecialSubArray: {
19995 ZigValue *array_val = ptr_val->data.x_ptr.data.base_array.array_val;
19996 assert(array_val->type->id == ZigTypeIdArray);
19997 if (array_val->data.x_array.special != ConstArraySpecialNone)
19998 zig_panic("TODO");
19999 if (dst_size > src_size) {
20000 size_t elem_index = ptr_val->data.x_ptr.data.base_array.elem_index;
20001 opt_ir_add_error_node(ira, codegen, source_node,
20002 buf_sprintf("attempt to read %" ZIG_PRI_usize " bytes from %s at index %" ZIG_PRI_usize " which is %" ZIG_PRI_usize " bytes",
20003 dst_size, buf_ptr(&array_val->type->name), elem_index, src_size));
20004 return ErrorSemanticAnalyzeFail;
20005 }
20006 size_t elem_size = src_size;
20007 size_t elem_count = (dst_size % elem_size == 0) ? (dst_size / elem_size) : (dst_size / elem_size + 1);
20008 Buf buf = BUF_INIT;
20009 buf_resize(&buf, elem_count * elem_size);
20010 for (size_t i = 0; i < elem_count; i += 1) {
20011 ZigValue *elem_val = &array_val->data.x_array.data.s_none.elements[i];
20012 buf_write_value_bytes(codegen, (uint8_t*)buf_ptr(&buf) + (i * elem_size), elem_val);
20013 }
20014 if ((err = buf_read_value_bytes(ira, codegen, source_node, (uint8_t*)buf_ptr(&buf), out_val)))
20015 return err;
20016 buf_deinit(&buf);
20017 return ErrorNone;
20018 }
19939 case ConstPtrSpecialBaseArray: {20019 case ConstPtrSpecialBaseArray: {
19940 ZigValue *array_val = ptr_val->data.x_ptr.data.base_array.array_val;20020 ZigValue *array_val = ptr_val->data.x_ptr.data.base_array.array_val;
19941 assert(array_val->type->id == ZigTypeIdArray);20021 assert(array_val->type->id == ZigTypeIdArray);
...@@ -19959,6 +20039,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source...@@ -19959,6 +20039,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source
19959 }20039 }
19960 if ((err = buf_read_value_bytes(ira, codegen, source_node, (uint8_t*)buf_ptr(&buf), out_val)))20040 if ((err = buf_read_value_bytes(ira, codegen, source_node, (uint8_t*)buf_ptr(&buf), out_val)))
19961 return err;20041 return err;
20042 buf_deinit(&buf);
19962 return ErrorNone;20043 return ErrorNone;
19963 }20044 }
19964 case ConstPtrSpecialBaseStruct:20045 case ConstPtrSpecialBaseStruct:
...@@ -20538,6 +20619,44 @@ static ZigType *adjust_ptr_allow_zero(CodeGen *g, ZigType *ptr_type, bool allow_...@@ -20538,6 +20619,44 @@ static ZigType *adjust_ptr_allow_zero(CodeGen *g, ZigType *ptr_type, bool allow_
20538 allow_zero);20619 allow_zero);
20539}20620}
2054020621
20622static Error compute_elem_align(IrAnalyze *ira, ZigType *elem_type, uint32_t base_ptr_align,
20623 uint64_t elem_index, uint32_t *result)
20624{
20625 Error err;
20626
20627 if (base_ptr_align == 0) {
20628 *result = 0;
20629 return ErrorNone;
20630 }
20631
20632 // figure out the largest alignment possible
20633 if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusSizeKnown)))
20634 return err;
20635
20636 uint64_t elem_size = type_size(ira->codegen, elem_type);
20637 uint64_t abi_align = get_abi_alignment(ira->codegen, elem_type);
20638 uint64_t ptr_align = base_ptr_align;
20639
20640 uint64_t chosen_align = abi_align;
20641 if (ptr_align >= abi_align) {
20642 while (ptr_align > abi_align) {
20643 if ((elem_index * elem_size) % ptr_align == 0) {
20644 chosen_align = ptr_align;
20645 break;
20646 }
20647 ptr_align >>= 1;
20648 }
20649 } else if (elem_size >= ptr_align && elem_size % ptr_align == 0) {
20650 chosen_align = ptr_align;
20651 } else {
20652 // can't get here because guaranteed elem_size >= abi_align
20653 zig_unreachable();
20654 }
20655
20656 *result = chosen_align;
20657 return ErrorNone;
20658}
20659
20541static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemPtr *elem_ptr_instruction) {20660static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemPtr *elem_ptr_instruction) {
20542 Error err;20661 Error err;
20543 IrInstGen *array_ptr = elem_ptr_instruction->array_ptr->child;20662 IrInstGen *array_ptr = elem_ptr_instruction->array_ptr->child;
...@@ -20676,29 +20795,11 @@ static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemP...@@ -20676,29 +20795,11 @@ static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemP
20676 get_ptr_align(ira->codegen, ptr_type), 0, host_vec_len, false, (uint32_t)index,20795 get_ptr_align(ira->codegen, ptr_type), 0, host_vec_len, false, (uint32_t)index,
20677 nullptr, nullptr);20796 nullptr, nullptr);
20678 } else if (return_type->data.pointer.explicit_alignment != 0) {20797 } else if (return_type->data.pointer.explicit_alignment != 0) {
20679 // figure out the largest alignment possible20798 uint32_t chosen_align;
2068020799 if ((err = compute_elem_align(ira, return_type->data.pointer.child_type,
20681 if ((err = type_resolve(ira->codegen, return_type->data.pointer.child_type, ResolveStatusSizeKnown)))20800 return_type->data.pointer.explicit_alignment, index, &chosen_align)))
20801 {
20682 return ira->codegen->invalid_inst_gen;20802 return ira->codegen->invalid_inst_gen;
20683
20684 uint64_t elem_size = type_size(ira->codegen, return_type->data.pointer.child_type);
20685 uint64_t abi_align = get_abi_alignment(ira->codegen, return_type->data.pointer.child_type);
20686 uint64_t ptr_align = get_ptr_align(ira->codegen, return_type);
20687
20688 uint64_t chosen_align = abi_align;
20689 if (ptr_align >= abi_align) {
20690 while (ptr_align > abi_align) {
20691 if ((index * elem_size) % ptr_align == 0) {
20692 chosen_align = ptr_align;
20693 break;
20694 }
20695 ptr_align >>= 1;
20696 }
20697 } else if (elem_size >= ptr_align && elem_size % ptr_align == 0) {
20698 chosen_align = ptr_align;
20699 } else {
20700 // can't get here because guaranteed elem_size >= abi_align
20701 zig_unreachable();
20702 }20803 }
20703 return_type = adjust_ptr_align(ira->codegen, return_type, chosen_align);20804 return_type = adjust_ptr_align(ira->codegen, return_type, chosen_align);
20704 }20805 }
...@@ -20819,6 +20920,7 @@ static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemP...@@ -20819,6 +20920,7 @@ static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemP
20819 }20920 }
20820 break;20921 break;
20821 case ConstPtrSpecialBaseArray:20922 case ConstPtrSpecialBaseArray:
20923 case ConstPtrSpecialSubArray:
20822 {20924 {
20823 size_t offset = array_ptr_val->data.x_ptr.data.base_array.elem_index;20925 size_t offset = array_ptr_val->data.x_ptr.data.base_array.elem_index;
20824 new_index = offset + index;20926 new_index = offset + index;
...@@ -20889,6 +20991,7 @@ static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemP...@@ -20889,6 +20991,7 @@ static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemP
20889 out_val->data.x_ptr.special = ConstPtrSpecialRef;20991 out_val->data.x_ptr.special = ConstPtrSpecialRef;
20890 out_val->data.x_ptr.data.ref.pointee = ptr_field->data.x_ptr.data.ref.pointee;20992 out_val->data.x_ptr.data.ref.pointee = ptr_field->data.x_ptr.data.ref.pointee;
20891 break;20993 break;
20994 case ConstPtrSpecialSubArray:
20892 case ConstPtrSpecialBaseArray:20995 case ConstPtrSpecialBaseArray:
20893 {20996 {
20894 size_t offset = ptr_field->data.x_ptr.data.base_array.elem_index;20997 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...@@ -25440,11 +25543,22 @@ static IrInstGen *ir_analyze_instruction_err_set_cast(IrAnalyze *ira, IrInstSrcE
25440static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align) {25543static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align) {
25441 Error err;25544 Error err;
2544225545
25443 ZigType *ptr_type = get_src_ptr_type(ty);25546 ZigType *ptr_type;
25547 if (is_slice(ty)) {
25548 TypeStructField *ptr_field = ty->data.structure.fields[slice_ptr_index];
25549 ptr_type = resolve_struct_field_type(ira->codegen, ptr_field);
25550 } else {
25551 ptr_type = get_src_ptr_type(ty);
25552 }
25444 assert(ptr_type != nullptr);25553 assert(ptr_type != nullptr);
25445 if (ptr_type->id == ZigTypeIdPointer) {25554 if (ptr_type->id == ZigTypeIdPointer) {
25446 if ((err = type_resolve(ira->codegen, ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown)))25555 if ((err = type_resolve(ira->codegen, ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown)))
25447 return err;25556 return err;
25557 } else if (is_slice(ptr_type)) {
25558 TypeStructField *ptr_field = ptr_type->data.structure.fields[slice_ptr_index];
25559 ZigType *slice_ptr_type = resolve_struct_field_type(ira->codegen, ptr_field);
25560 if ((err = type_resolve(ira->codegen, slice_ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown)))
25561 return err;
25448 }25562 }
2544925563
25450 *result_align = get_ptr_align(ira->codegen, ty);25564 *result_align = get_ptr_align(ira->codegen, ty);
...@@ -25899,6 +26013,7 @@ static IrInstGen *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstSrcMemset...@@ -25899,6 +26013,7 @@ static IrInstGen *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstSrcMemset
25899 start = 0;26013 start = 0;
25900 bound_end = 1;26014 bound_end = 1;
25901 break;26015 break;
26016 case ConstPtrSpecialSubArray:
25902 case ConstPtrSpecialBaseArray:26017 case ConstPtrSpecialBaseArray:
25903 {26018 {
25904 ZigValue *array_val = dest_ptr_val->data.x_ptr.data.base_array.array_val;26019 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...@@ -26032,6 +26147,7 @@ static IrInstGen *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstSrcMemcpy
26032 dest_start = 0;26147 dest_start = 0;
26033 dest_end = 1;26148 dest_end = 1;
26034 break;26149 break;
26150 case ConstPtrSpecialSubArray:
26035 case ConstPtrSpecialBaseArray:26151 case ConstPtrSpecialBaseArray:
26036 {26152 {
26037 ZigValue *array_val = dest_ptr_val->data.x_ptr.data.base_array.array_val;26153 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...@@ -26075,6 +26191,7 @@ static IrInstGen *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstSrcMemcpy
26075 src_start = 0;26191 src_start = 0;
26076 src_end = 1;26192 src_end = 1;
26077 break;26193 break;
26194 case ConstPtrSpecialSubArray:
26078 case ConstPtrSpecialBaseArray:26195 case ConstPtrSpecialBaseArray:
26079 {26196 {
26080 ZigValue *array_val = src_ptr_val->data.x_ptr.data.base_array.array_val;26197 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...@@ -26118,7 +26235,19 @@ static IrInstGen *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstSrcMemcpy
26118 return ir_build_memcpy_gen(ira, &instruction->base.base, casted_dest_ptr, casted_src_ptr, casted_count);26235 return ir_build_memcpy_gen(ira, &instruction->base.base, casted_dest_ptr, casted_src_ptr, casted_count);
26119}26236}
2612026237
26238static ZigType *get_result_loc_type(IrAnalyze *ira, ResultLoc *result_loc) {
26239 if (result_loc == nullptr) return nullptr;
26240
26241 if (result_loc->id == ResultLocIdCast) {
26242 return ir_resolve_type(ira, result_loc->source_instruction->child);
26243 }
26244
26245 return nullptr;
26246}
26247
26121static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *instruction) {26248static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *instruction) {
26249 Error err;
26250
26122 IrInstGen *ptr_ptr = instruction->ptr->child;26251 IrInstGen *ptr_ptr = instruction->ptr->child;
26123 if (type_is_invalid(ptr_ptr->value->type))26252 if (type_is_invalid(ptr_ptr->value->type))
26124 return ira->codegen->invalid_inst_gen;26253 return ira->codegen->invalid_inst_gen;
...@@ -26148,6 +26277,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i...@@ -26148,6 +26277,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
26148 end = nullptr;26277 end = nullptr;
26149 }26278 }
2615026279
26280 ZigValue *slice_sentinel_val = nullptr;
26151 ZigType *non_sentinel_slice_ptr_type;26281 ZigType *non_sentinel_slice_ptr_type;
26152 ZigType *elem_type;26282 ZigType *elem_type;
2615326283
...@@ -26198,6 +26328,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i...@@ -26198,6 +26328,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
26198 }26328 }
26199 } else if (is_slice(array_type)) {26329 } else if (is_slice(array_type)) {
26200 ZigType *maybe_sentineled_slice_ptr_type = array_type->data.structure.fields[slice_ptr_index]->type_entry;26330 ZigType *maybe_sentineled_slice_ptr_type = array_type->data.structure.fields[slice_ptr_index]->type_entry;
26331 slice_sentinel_val = maybe_sentineled_slice_ptr_type->data.pointer.sentinel;
26201 non_sentinel_slice_ptr_type = adjust_ptr_sentinel(ira->codegen, maybe_sentineled_slice_ptr_type, nullptr);26332 non_sentinel_slice_ptr_type = adjust_ptr_sentinel(ira->codegen, maybe_sentineled_slice_ptr_type, nullptr);
26202 elem_type = non_sentinel_slice_ptr_type->data.pointer.child_type;26333 elem_type = non_sentinel_slice_ptr_type->data.pointer.child_type;
26203 } else {26334 } else {
...@@ -26206,7 +26337,6 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i...@@ -26206,7 +26337,6 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
26206 return ira->codegen->invalid_inst_gen;26337 return ira->codegen->invalid_inst_gen;
26207 }26338 }
2620826339
26209 ZigType *return_type;
26210 ZigValue *sentinel_val = nullptr;26340 ZigValue *sentinel_val = nullptr;
26211 if (instruction->sentinel) {26341 if (instruction->sentinel) {
26212 IrInstGen *uncasted_sentinel = instruction->sentinel->child;26342 IrInstGen *uncasted_sentinel = instruction->sentinel->child;
...@@ -26218,11 +26348,76 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i...@@ -26218,11 +26348,76 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
26218 sentinel_val = ir_resolve_const(ira, sentinel, UndefBad);26348 sentinel_val = ir_resolve_const(ira, sentinel, UndefBad);
26219 if (sentinel_val == nullptr)26349 if (sentinel_val == nullptr)
26220 return ira->codegen->invalid_inst_gen;26350 return ira->codegen->invalid_inst_gen;
26221 ZigType *slice_ptr_type = adjust_ptr_sentinel(ira->codegen, non_sentinel_slice_ptr_type, sentinel_val);26351 }
26352
26353 ZigType *child_array_type = (array_type->id == ZigTypeIdPointer &&
26354 array_type->data.pointer.ptr_len == PtrLenSingle) ? array_type->data.pointer.child_type : array_type;
26355
26356 ZigType *return_type;
26357
26358 // If start index and end index are both comptime known, then the result type is a pointer to array
26359 // not a slice. However, if the start or end index is a lazy value, and the result location is a slice,
26360 // then the pointer-to-array would be casted to a slice anyway. So, we preserve the laziness of these
26361 // values by making the return type a slice.
26362 ZigType *res_loc_type = get_result_loc_type(ira, instruction->result_loc);
26363 bool result_loc_is_slice = (res_loc_type != nullptr && is_slice(res_loc_type));
26364 bool end_is_known = !result_loc_is_slice &&
26365 ((end != nullptr && value_is_comptime(end->value)) ||
26366 (end == nullptr && child_array_type->id == ZigTypeIdArray));
26367
26368 ZigValue *array_sentinel = sentinel_val;
26369 if (end_is_known) {
26370 uint64_t end_scalar;
26371 if (end != nullptr) {
26372 ZigValue *end_val = ir_resolve_const(ira, end, UndefBad);
26373 if (!end_val)
26374 return ira->codegen->invalid_inst_gen;
26375 end_scalar = bigint_as_u64(&end_val->data.x_bigint);
26376 } else {
26377 end_scalar = child_array_type->data.array.len;
26378 }
26379 array_sentinel = (child_array_type->id == ZigTypeIdArray && end_scalar == child_array_type->data.array.len)
26380 ? child_array_type->data.array.sentinel : sentinel_val;
26381
26382 if (value_is_comptime(casted_start->value)) {
26383 ZigValue *start_val = ir_resolve_const(ira, casted_start, UndefBad);
26384 if (!start_val)
26385 return ira->codegen->invalid_inst_gen;
26386
26387 uint64_t start_scalar = bigint_as_u64(&start_val->data.x_bigint);
26388
26389 if (start_scalar > end_scalar) {
26390 ir_add_error(ira, &instruction->base.base, buf_sprintf("out of bounds slice"));
26391 return ira->codegen->invalid_inst_gen;
26392 }
26393
26394 uint32_t base_ptr_align = non_sentinel_slice_ptr_type->data.pointer.explicit_alignment;
26395 uint32_t ptr_byte_alignment = 0;
26396 if (end_scalar > start_scalar) {
26397 if ((err = compute_elem_align(ira, elem_type, base_ptr_align, start_scalar, &ptr_byte_alignment)))
26398 return ira->codegen->invalid_inst_gen;
26399 }
26400
26401 ZigType *return_array_type = get_array_type(ira->codegen, elem_type, end_scalar - start_scalar,
26402 array_sentinel);
26403 return_type = get_pointer_to_type_extra(ira->codegen, return_array_type,
26404 non_sentinel_slice_ptr_type->data.pointer.is_const,
26405 non_sentinel_slice_ptr_type->data.pointer.is_volatile,
26406 PtrLenSingle, ptr_byte_alignment, 0, 0, false);
26407 goto done_with_return_type;
26408 }
26409 } else if (array_sentinel == nullptr && end == nullptr) {
26410 array_sentinel = slice_sentinel_val;
26411 }
26412 if (array_sentinel != nullptr) {
26413 // TODO deal with non-abi-alignment here
26414 ZigType *slice_ptr_type = adjust_ptr_sentinel(ira->codegen, non_sentinel_slice_ptr_type, array_sentinel);
26222 return_type = get_slice_type(ira->codegen, slice_ptr_type);26415 return_type = get_slice_type(ira->codegen, slice_ptr_type);
26223 } else {26416 } else {
26417 // TODO deal with non-abi-alignment here
26224 return_type = get_slice_type(ira->codegen, non_sentinel_slice_ptr_type);26418 return_type = get_slice_type(ira->codegen, non_sentinel_slice_ptr_type);
26225 }26419 }
26420done_with_return_type:
2622626421
26227 if (instr_is_comptime(ptr_ptr) &&26422 if (instr_is_comptime(ptr_ptr) &&
26228 value_is_comptime(casted_start->value) &&26423 value_is_comptime(casted_start->value) &&
...@@ -26233,12 +26428,8 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i...@@ -26233,12 +26428,8 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
26233 size_t abs_offset;26428 size_t abs_offset;
26234 size_t rel_end;26429 size_t rel_end;
26235 bool ptr_is_undef = false;26430 bool ptr_is_undef = false;
26236 if (array_type->id == ZigTypeIdArray ||26431 if (child_array_type->id == ZigTypeIdArray) {
26237 (array_type->id == ZigTypeIdPointer && array_type->data.pointer.ptr_len == PtrLenSingle))
26238 {
26239 if (array_type->id == ZigTypeIdPointer) {26432 if (array_type->id == ZigTypeIdPointer) {
26240 ZigType *child_array_type = array_type->data.pointer.child_type;
26241 assert(child_array_type->id == ZigTypeIdArray);
26242 parent_ptr = const_ptr_pointee(ira, ira->codegen, ptr_ptr->value, instruction->base.base.source_node);26433 parent_ptr = const_ptr_pointee(ira, ira->codegen, ptr_ptr->value, instruction->base.base.source_node);
26243 if (parent_ptr == nullptr)26434 if (parent_ptr == nullptr)
26244 return ira->codegen->invalid_inst_gen;26435 return ira->codegen->invalid_inst_gen;
...@@ -26249,6 +26440,10 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i...@@ -26249,6 +26440,10 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
26249 abs_offset = 0;26440 abs_offset = 0;
26250 rel_end = SIZE_MAX;26441 rel_end = SIZE_MAX;
26251 ptr_is_undef = true;26442 ptr_is_undef = true;
26443 } else if (parent_ptr->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) {
26444 array_val = nullptr;
26445 abs_offset = 0;
26446 rel_end = SIZE_MAX;
26252 } else {26447 } else {
26253 array_val = const_ptr_pointee(ira, ira->codegen, parent_ptr, instruction->base.base.source_node);26448 array_val = const_ptr_pointee(ira, ira->codegen, parent_ptr, instruction->base.base.source_node);
26254 if (array_val == nullptr)26449 if (array_val == nullptr)
...@@ -26291,6 +26486,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i...@@ -26291,6 +26486,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
26291 rel_end = 1;26486 rel_end = 1;
26292 }26487 }
26293 break;26488 break;
26489 case ConstPtrSpecialSubArray:
26294 case ConstPtrSpecialBaseArray:26490 case ConstPtrSpecialBaseArray:
26295 array_val = parent_ptr->data.x_ptr.data.base_array.array_val;26491 array_val = parent_ptr->data.x_ptr.data.base_array.array_val;
26296 abs_offset = parent_ptr->data.x_ptr.data.base_array.elem_index;26492 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...@@ -26341,6 +26537,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
26341 abs_offset = SIZE_MAX;26537 abs_offset = SIZE_MAX;
26342 rel_end = 1;26538 rel_end = 1;
26343 break;26539 break;
26540 case ConstPtrSpecialSubArray:
26344 case ConstPtrSpecialBaseArray:26541 case ConstPtrSpecialBaseArray:
26345 array_val = parent_ptr->data.x_ptr.data.base_array.array_val;26542 array_val = parent_ptr->data.x_ptr.data.base_array.array_val;
26346 abs_offset = parent_ptr->data.x_ptr.data.base_array.elem_index;26543 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...@@ -26401,15 +26598,28 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
26401 }26598 }
2640226599
26403 IrInstGen *result = ir_const(ira, &instruction->base.base, return_type);26600 IrInstGen *result = ir_const(ira, &instruction->base.base, return_type);
26404 ZigValue *out_val = result->value;
26405 out_val->data.x_struct.fields = alloc_const_vals_ptrs(ira->codegen, 2);
2640626601
26407 ZigValue *ptr_val = out_val->data.x_struct.fields[slice_ptr_index];26602 ZigValue *ptr_val;
26603 if (return_type->id == ZigTypeIdPointer) {
26604 // pointer to array
26605 ptr_val = result->value;
26606 } else {
26607 // slice
26608 result->value->data.x_struct.fields = alloc_const_vals_ptrs(ira->codegen, 2);
26609
26610 ptr_val = result->value->data.x_struct.fields[slice_ptr_index];
26611
26612 ZigValue *len_val = result->value->data.x_struct.fields[slice_len_index];
26613 init_const_usize(ira->codegen, len_val, end_scalar - start_scalar);
26614 }
2640826615
26616 bool return_type_is_const = non_sentinel_slice_ptr_type->data.pointer.is_const;
26409 if (array_val) {26617 if (array_val) {
26410 size_t index = abs_offset + start_scalar;26618 size_t index = abs_offset + start_scalar;
26411 bool is_const = slice_is_const(return_type);26619 init_const_ptr_array(ira->codegen, ptr_val, array_val, index, return_type_is_const, PtrLenUnknown);
26412 init_const_ptr_array(ira->codegen, ptr_val, array_val, index, is_const, PtrLenUnknown);26620 if (return_type->id == ZigTypeIdPointer) {
26621 ptr_val->data.x_ptr.special = ConstPtrSpecialSubArray;
26622 }
26413 if (array_type->id == ZigTypeIdArray) {26623 if (array_type->id == ZigTypeIdArray) {
26414 ptr_val->data.x_ptr.mut = ptr_ptr->value->data.x_ptr.mut;26624 ptr_val->data.x_ptr.mut = ptr_ptr->value->data.x_ptr.mut;
26415 } else if (is_slice(array_type)) {26625 } else if (is_slice(array_type)) {
...@@ -26419,16 +26629,17 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i...@@ -26419,16 +26629,17 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
26419 }26629 }
26420 } else if (ptr_is_undef) {26630 } else if (ptr_is_undef) {
26421 ptr_val->type = get_pointer_to_type(ira->codegen, parent_ptr->type->data.pointer.child_type,26631 ptr_val->type = get_pointer_to_type(ira->codegen, parent_ptr->type->data.pointer.child_type,
26422 slice_is_const(return_type));26632 return_type_is_const);
26423 ptr_val->special = ConstValSpecialUndef;26633 ptr_val->special = ConstValSpecialUndef;
26424 } else switch (parent_ptr->data.x_ptr.special) {26634 } else switch (parent_ptr->data.x_ptr.special) {
26425 case ConstPtrSpecialInvalid:26635 case ConstPtrSpecialInvalid:
26426 case ConstPtrSpecialDiscard:26636 case ConstPtrSpecialDiscard:
26427 zig_unreachable();26637 zig_unreachable();
26428 case ConstPtrSpecialRef:26638 case ConstPtrSpecialRef:
26429 init_const_ptr_ref(ira->codegen, ptr_val,26639 init_const_ptr_ref(ira->codegen, ptr_val, parent_ptr->data.x_ptr.data.ref.pointee,
26430 parent_ptr->data.x_ptr.data.ref.pointee, slice_is_const(return_type));26640 return_type_is_const);
26431 break;26641 break;
26642 case ConstPtrSpecialSubArray:
26432 case ConstPtrSpecialBaseArray:26643 case ConstPtrSpecialBaseArray:
26433 zig_unreachable();26644 zig_unreachable();
26434 case ConstPtrSpecialBaseStruct:26645 case ConstPtrSpecialBaseStruct:
...@@ -26443,7 +26654,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i...@@ -26443,7 +26654,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
26443 init_const_ptr_hard_coded_addr(ira->codegen, ptr_val,26654 init_const_ptr_hard_coded_addr(ira->codegen, ptr_val,
26444 parent_ptr->type->data.pointer.child_type,26655 parent_ptr->type->data.pointer.child_type,
26445 parent_ptr->data.x_ptr.data.hard_coded_addr.addr + start_scalar,26656 parent_ptr->data.x_ptr.data.hard_coded_addr.addr + start_scalar,
26446 slice_is_const(return_type));26657 return_type_is_const);
26447 break;26658 break;
26448 case ConstPtrSpecialFunction:26659 case ConstPtrSpecialFunction:
26449 zig_panic("TODO");26660 zig_panic("TODO");
...@@ -26451,26 +26662,11 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i...@@ -26451,26 +26662,11 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
26451 zig_panic("TODO");26662 zig_panic("TODO");
26452 }26663 }
2645326664
26454 ZigValue *len_val = out_val->data.x_struct.fields[slice_len_index];26665 // In the case of pointer-to-array, we must restore this because above it overwrites ptr_val->type
26455 init_const_usize(ira->codegen, len_val, end_scalar - start_scalar);26666 result->value->type = return_type;
26456
26457 return result;26667 return result;
26458 }26668 }
2645926669
26460 IrInstGen *result_loc = ir_resolve_result(ira, &instruction->base.base, instruction->result_loc,
26461 return_type, nullptr, true, true);
26462 if (result_loc != nullptr) {
26463 if (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable) {
26464 return result_loc;
26465 }
26466 IrInstGen *dummy_value = ir_const(ira, &instruction->base.base, return_type);
26467 dummy_value->value->special = ConstValSpecialRuntime;
26468 IrInstGen *dummy_result = ir_implicit_cast2(ira, &instruction->base.base,
26469 dummy_value, result_loc->value->type->data.pointer.child_type);
26470 if (type_is_invalid(dummy_result->value->type))
26471 return ira->codegen->invalid_inst_gen;
26472 }
26473
26474 if (generate_non_null_assert) {26670 if (generate_non_null_assert) {
26475 IrInstGen *ptr_val = ir_get_deref(ira, &instruction->base.base, ptr_ptr, nullptr);26671 IrInstGen *ptr_val = ir_get_deref(ira, &instruction->base.base, ptr_ptr, nullptr);
2647626672
...@@ -26480,8 +26676,26 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i...@@ -26480,8 +26676,26 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
26480 ir_build_assert_non_null(ira, &instruction->base.base, ptr_val);26676 ir_build_assert_non_null(ira, &instruction->base.base, ptr_val);
26481 }26677 }
2648226678
26679 IrInstGen *result_loc = nullptr;
26680
26681 if (return_type->id != ZigTypeIdPointer) {
26682 result_loc = ir_resolve_result(ira, &instruction->base.base, instruction->result_loc,
26683 return_type, nullptr, true, true);
26684 if (result_loc != nullptr) {
26685 if (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable) {
26686 return result_loc;
26687 }
26688 IrInstGen *dummy_value = ir_const(ira, &instruction->base.base, return_type);
26689 dummy_value->value->special = ConstValSpecialRuntime;
26690 IrInstGen *dummy_result = ir_implicit_cast2(ira, &instruction->base.base,
26691 dummy_value, result_loc->value->type->data.pointer.child_type);
26692 if (type_is_invalid(dummy_result->value->type))
26693 return ira->codegen->invalid_inst_gen;
26694 }
26695 }
26696
26483 return ir_build_slice_gen(ira, &instruction->base.base, return_type, ptr_ptr,26697 return ir_build_slice_gen(ira, &instruction->base.base, return_type, ptr_ptr,
26484 casted_start, end, instruction->safety_check_on, result_loc);26698 casted_start, end, instruction->safety_check_on, result_loc, sentinel_val);
26485}26699}
2648626700
26487static IrInstGen *ir_analyze_instruction_has_field(IrAnalyze *ira, IrInstSrcHasField *instruction) {26701static 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...@@ -27507,10 +27721,18 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn
27507 // We have a check for zero bits later so we use get_src_ptr_type to27721 // We have a check for zero bits later so we use get_src_ptr_type to
27508 // validate src_type and dest_type.27722 // validate src_type and dest_type.
2750927723
27510 ZigType *src_ptr_type = get_src_ptr_type(src_type);27724 ZigType *if_slice_ptr_type;
27511 if (src_ptr_type == nullptr) {27725 if (is_slice(src_type)) {
27512 ir_add_error(ira, ptr_src, buf_sprintf("expected pointer, found '%s'", buf_ptr(&src_type->name)));27726 TypeStructField *ptr_field = src_type->data.structure.fields[slice_ptr_index];
27513 return ira->codegen->invalid_inst_gen;27727 if_slice_ptr_type = resolve_struct_field_type(ira->codegen, ptr_field);
27728 } else {
27729 if_slice_ptr_type = src_type;
27730
27731 ZigType *src_ptr_type = get_src_ptr_type(src_type);
27732 if (src_ptr_type == nullptr) {
27733 ir_add_error(ira, ptr_src, buf_sprintf("expected pointer, found '%s'", buf_ptr(&src_type->name)));
27734 return ira->codegen->invalid_inst_gen;
27735 }
27514 }27736 }
2751527737
27516 ZigType *dest_ptr_type = get_src_ptr_type(dest_type);27738 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...@@ -27520,7 +27742,7 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn
27520 return ira->codegen->invalid_inst_gen;27742 return ira->codegen->invalid_inst_gen;
27521 }27743 }
2752227744
27523 if (get_ptr_const(src_type) && !get_ptr_const(dest_type)) {27745 if (get_ptr_const(ira->codegen, src_type) && !get_ptr_const(ira->codegen, dest_type)) {
27524 ir_add_error(ira, source_instr, buf_sprintf("cast discards const qualifier"));27746 ir_add_error(ira, source_instr, buf_sprintf("cast discards const qualifier"));
27525 return ira->codegen->invalid_inst_gen;27747 return ira->codegen->invalid_inst_gen;
27526 }27748 }
...@@ -27538,7 +27760,10 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn...@@ -27538,7 +27760,10 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn
27538 if ((err = type_resolve(ira->codegen, src_type, ResolveStatusZeroBitsKnown)))27760 if ((err = type_resolve(ira->codegen, src_type, ResolveStatusZeroBitsKnown)))
27539 return ira->codegen->invalid_inst_gen;27761 return ira->codegen->invalid_inst_gen;
2754027762
27541 if (type_has_bits(ira->codegen, dest_type) && !type_has_bits(ira->codegen, src_type) && safety_check_on) {27763 if (safety_check_on &&
27764 type_has_bits(ira->codegen, dest_type) &&
27765 !type_has_bits(ira->codegen, if_slice_ptr_type))
27766 {
27542 ErrorMsg *msg = ir_add_error(ira, source_instr,27767 ErrorMsg *msg = ir_add_error(ira, source_instr,
27543 buf_sprintf("'%s' and '%s' do not have the same in-memory representation",27768 buf_sprintf("'%s' and '%s' do not have the same in-memory representation",
27544 buf_ptr(&src_type->name), buf_ptr(&dest_type->name)));27769 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...@@ -27549,6 +27774,14 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn
27549 return ira->codegen->invalid_inst_gen;27774 return ira->codegen->invalid_inst_gen;
27550 }27775 }
2755127776
27777 // For slices, follow the `ptr` field.
27778 if (is_slice(src_type)) {
27779 TypeStructField *ptr_field = src_type->data.structure.fields[slice_ptr_index];
27780 IrInstGen *ptr_ref = ir_get_ref(ira, source_instr, ptr, true, false);
27781 IrInstGen *ptr_ptr = ir_analyze_struct_field_ptr(ira, source_instr, ptr_field, ptr_ref, src_type, false);
27782 ptr = ir_get_deref(ira, source_instr, ptr_ptr, nullptr);
27783 }
27784
27552 if (instr_is_comptime(ptr)) {27785 if (instr_is_comptime(ptr)) {
27553 bool dest_allows_addr_zero = ptr_allows_addr_zero(dest_type);27786 bool dest_allows_addr_zero = ptr_allows_addr_zero(dest_type);
27554 UndefAllowed is_undef_allowed = dest_allows_addr_zero ? UndefOk : UndefBad;27787 UndefAllowed is_undef_allowed = dest_allows_addr_zero ? UndefOk : UndefBad;
test/compare_output.zig+1-1
...@@ -292,7 +292,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -292,7 +292,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
292 \\pub export fn main() c_int {292 \\pub export fn main() c_int {
293 \\ var array = [_]u32{ 1, 7, 3, 2, 0, 9, 4, 8, 6, 5 };293 \\ var array = [_]u32{ 1, 7, 3, 2, 0, 9, 4, 8, 6, 5 };
294 \\294 \\
295 \\ c.qsort(@ptrCast(?*c_void, array[0..].ptr), @intCast(c_ulong, array.len), @sizeOf(i32), compare_fn);295 \\ c.qsort(@ptrCast(?*c_void, &array), @intCast(c_ulong, array.len), @sizeOf(i32), compare_fn);
296 \\296 \\
297 \\ for (array) |item, i| {297 \\ for (array) |item, i| {
298 \\ if (item != i) {298 \\ if (item != i) {
test/compile_errors.zig+2-14
...@@ -103,18 +103,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -103,18 +103,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
103 "tmp.zig:3:23: error: pointer to size 0 type has no address",103 "tmp.zig:3:23: error: pointer to size 0 type has no address",
104 });104 });
105105
106 cases.addTest("slice to pointer conversion mismatch",
107 \\pub fn bytesAsSlice(bytes: var) [*]align(1) const u16 {
108 \\ return @ptrCast([*]align(1) const u16, bytes.ptr)[0..1];
109 \\}
110 \\test "bytesAsSlice" {
111 \\ const bytes = [_]u8{ 0xDE, 0xAD, 0xBE, 0xEF };
112 \\ const slice = bytesAsSlice(bytes[0..]);
113 \\}
114 , &[_][]const u8{
115 "tmp.zig:2:54: error: expected type '[*]align(1) const u16', found '[]align(1) const u16'",
116 });
117
118 cases.addTest("access invalid @typeInfo decl",106 cases.addTest("access invalid @typeInfo decl",
119 \\const A = B;107 \\const A = B;
120 \\test "Crash" {108 \\test "Crash" {
...@@ -1918,8 +1906,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1918,8 +1906,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1918 cases.add("reading past end of pointer casted array",1906 cases.add("reading past end of pointer casted array",
1919 \\comptime {1907 \\comptime {
1920 \\ const array: [4]u8 = "aoeu".*;1908 \\ const array: [4]u8 = "aoeu".*;
1921 \\ const slice = array[1..];1909 \\ const sub_array = array[1..];
1922 \\ const int_ptr = @ptrCast(*const u24, slice.ptr);1910 \\ const int_ptr = @ptrCast(*const u24, sub_array);
1923 \\ const deref = int_ptr.*;1911 \\ const deref = int_ptr.*;
1924 \\}1912 \\}
1925 , &[_][]const u8{1913 , &[_][]const u8{
test/runtime_safety.zig+1-1
...@@ -69,7 +69,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -69,7 +69,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
69 \\}69 \\}
70 \\pub fn main() void {70 \\pub fn main() void {
71 \\ var buf: [4]u8 = undefined;71 \\ var buf: [4]u8 = undefined;
72 \\ const ptr = buf[0..].ptr;72 \\ const ptr: [*]u8 = &buf;
73 \\ const slice = ptr[0..3 :0];73 \\ const slice = ptr[0..3 :0];
74 \\}74 \\}
75 );75 );
test/stage1/behavior/align.zig+22-14
...@@ -5,10 +5,17 @@ const builtin = @import("builtin");...@@ -5,10 +5,17 @@ const builtin = @import("builtin");
5var foo: u8 align(4) = 100;5var foo: u8 align(4) = 100;
66
7test "global variable alignment" {7test "global variable alignment" {
8 expect(@TypeOf(&foo).alignment == 4);8 comptime expect(@TypeOf(&foo).alignment == 4);
9 expect(@TypeOf(&foo) == *align(4) u8);9 comptime expect(@TypeOf(&foo) == *align(4) u8);
10 const slice = @as(*[1]u8, &foo)[0..];10 {
11 expect(@TypeOf(slice) == []align(4) u8);11 const slice = @as(*[1]u8, &foo)[0..];
12 comptime expect(@TypeOf(slice) == *align(4) [1]u8);
13 }
14 {
15 var runtime_zero: usize = 0;
16 const slice = @as(*[1]u8, &foo)[runtime_zero..];
17 comptime expect(@TypeOf(slice) == []align(4) u8);
18 }
12}19}
1320
14fn derp() align(@sizeOf(usize) * 2) i32 {21fn derp() align(@sizeOf(usize) * 2) i32 {
...@@ -171,18 +178,19 @@ test "runtime known array index has best alignment possible" {...@@ -171,18 +178,19 @@ test "runtime known array index has best alignment possible" {
171178
172 // because pointer is align 2 and u32 align % 2 == 0 we can assume align 2179 // because pointer is align 2 and u32 align % 2 == 0 we can assume align 2
173 var smaller align(2) = [_]u32{ 1, 2, 3, 4 };180 var smaller align(2) = [_]u32{ 1, 2, 3, 4 };
174 comptime expect(@TypeOf(smaller[0..]) == []align(2) u32);181 var runtime_zero: usize = 0;
175 comptime expect(@TypeOf(smaller[0..].ptr) == [*]align(2) u32);182 comptime expect(@TypeOf(smaller[runtime_zero..]) == []align(2) u32);
176 testIndex(smaller[0..].ptr, 0, *align(2) u32);183 comptime expect(@TypeOf(smaller[runtime_zero..].ptr) == [*]align(2) u32);
177 testIndex(smaller[0..].ptr, 1, *align(2) u32);184 testIndex(smaller[runtime_zero..].ptr, 0, *align(2) u32);
178 testIndex(smaller[0..].ptr, 2, *align(2) u32);185 testIndex(smaller[runtime_zero..].ptr, 1, *align(2) u32);
179 testIndex(smaller[0..].ptr, 3, *align(2) u32);186 testIndex(smaller[runtime_zero..].ptr, 2, *align(2) u32);
187 testIndex(smaller[runtime_zero..].ptr, 3, *align(2) u32);
180188
181 // has to use ABI alignment because index known at runtime only189 // has to use ABI alignment because index known at runtime only
182 testIndex2(array[0..].ptr, 0, *u8);190 testIndex2(array[runtime_zero..].ptr, 0, *u8);
183 testIndex2(array[0..].ptr, 1, *u8);191 testIndex2(array[runtime_zero..].ptr, 1, *u8);
184 testIndex2(array[0..].ptr, 2, *u8);192 testIndex2(array[runtime_zero..].ptr, 2, *u8);
185 testIndex2(array[0..].ptr, 3, *u8);193 testIndex2(array[runtime_zero..].ptr, 3, *u8);
186}194}
187fn testIndex(smaller: [*]align(2) u32, index: usize, comptime T: type) void {195fn testIndex(smaller: [*]align(2) u32, index: usize, comptime T: type) void {
188 comptime expect(@TypeOf(&smaller[index]) == T);196 comptime expect(@TypeOf(&smaller[index]) == T);
test/stage1/behavior/cast.zig+2-1
...@@ -435,7 +435,8 @@ fn incrementVoidPtrValue(value: ?*c_void) void {...@@ -435,7 +435,8 @@ fn incrementVoidPtrValue(value: ?*c_void) void {
435435
436test "implicit cast from [*]T to ?*c_void" {436test "implicit cast from [*]T to ?*c_void" {
437 var a = [_]u8{ 3, 2, 1 };437 var a = [_]u8{ 3, 2, 1 };
438 incrementVoidPtrArray(a[0..].ptr, 3);438 var runtime_zero: usize = 0;
439 incrementVoidPtrArray(a[runtime_zero..].ptr, 3);
439 expect(std.mem.eql(u8, &a, &[_]u8{ 4, 3, 2 }));440 expect(std.mem.eql(u8, &a, &[_]u8{ 4, 3, 2 }));
440}441}
441442
test/stage1/behavior/eval.zig+1-1
...@@ -524,7 +524,7 @@ test "comptime slice of slice preserves comptime var" {...@@ -524,7 +524,7 @@ test "comptime slice of slice preserves comptime var" {
524test "comptime slice of pointer preserves comptime var" {524test "comptime slice of pointer preserves comptime var" {
525 comptime {525 comptime {
526 var buff: [10]u8 = undefined;526 var buff: [10]u8 = undefined;
527 var a = buff[0..].ptr;527 var a = @ptrCast([*]u8, &buff);
528 a[0..1][0] = 1;528 a[0..1][0] = 1;
529 expect(buff[0..][0..][0] == 1);529 expect(buff[0..][0..][0] == 1);
530 }530 }
test/stage1/behavior/misc.zig+9-5
...@@ -102,8 +102,8 @@ test "memcpy and memset intrinsics" {...@@ -102,8 +102,8 @@ test "memcpy and memset intrinsics" {
102 var foo: [20]u8 = undefined;102 var foo: [20]u8 = undefined;
103 var bar: [20]u8 = undefined;103 var bar: [20]u8 = undefined;
104104
105 @memset(foo[0..].ptr, 'A', foo.len);105 @memset(&foo, 'A', foo.len);
106 @memcpy(bar[0..].ptr, foo[0..].ptr, bar.len);106 @memcpy(&bar, &foo, bar.len);
107107
108 if (bar[11] != 'A') unreachable;108 if (bar[11] != 'A') unreachable;
109}109}
...@@ -565,12 +565,16 @@ test "volatile load and store" {...@@ -565,12 +565,16 @@ test "volatile load and store" {
565 expect(ptr.* == 1235);565 expect(ptr.* == 1235);
566}566}
567567
568test "slice string literal has type []const u8" {568test "slice string literal has correct type" {
569 comptime {569 comptime {
570 expect(@TypeOf("aoeu"[0..]) == []const u8);570 expect(@TypeOf("aoeu"[0..]) == *const [4:0]u8);
571 const array = [_]i32{ 1, 2, 3, 4 };571 const array = [_]i32{ 1, 2, 3, 4 };
572 expect(@TypeOf(array[0..]) == []const i32);572 expect(@TypeOf(array[0..]) == *const [4]i32);
573 }573 }
574 var runtime_zero: usize = 0;
575 comptime expect(@TypeOf("aoeu"[runtime_zero..]) == [:0]const u8);
576 const array = [_]i32{ 1, 2, 3, 4 };
577 comptime expect(@TypeOf(array[runtime_zero..]) == []const i32);
574}578}
575579
576test "pointer child field" {580test "pointer child field" {
test/stage1/behavior/pointers.zig+5-4
...@@ -159,12 +159,13 @@ test "allowzero pointer and slice" {...@@ -159,12 +159,13 @@ test "allowzero pointer and slice" {
159 var opt_ptr: ?[*]allowzero i32 = ptr;159 var opt_ptr: ?[*]allowzero i32 = ptr;
160 expect(opt_ptr != null);160 expect(opt_ptr != null);
161 expect(@ptrToInt(ptr) == 0);161 expect(@ptrToInt(ptr) == 0);
162 var slice = ptr[0..10];162 var runtime_zero: usize = 0;
163 expect(@TypeOf(slice) == []allowzero i32);163 var slice = ptr[runtime_zero..10];
164 comptime expect(@TypeOf(slice) == []allowzero i32);
164 expect(@ptrToInt(&slice[5]) == 20);165 expect(@ptrToInt(&slice[5]) == 20);
165166
166 expect(@typeInfo(@TypeOf(ptr)).Pointer.is_allowzero);167 comptime expect(@typeInfo(@TypeOf(ptr)).Pointer.is_allowzero);
167 expect(@typeInfo(@TypeOf(slice)).Pointer.is_allowzero);168 comptime expect(@typeInfo(@TypeOf(slice)).Pointer.is_allowzero);
168}169}
169170
170test "assign null directly to C pointer and test null equality" {171test "assign null directly to C pointer and test null equality" {
test/stage1/behavior/ptrcast.zig+1-1
...@@ -13,7 +13,7 @@ fn testReinterpretBytesAsInteger() void {...@@ -13,7 +13,7 @@ fn testReinterpretBytesAsInteger() void {
13 builtin.Endian.Little => 0xab785634,13 builtin.Endian.Little => 0xab785634,
14 builtin.Endian.Big => 0x345678ab,14 builtin.Endian.Big => 0x345678ab,
15 };15 };
16 expect(@ptrCast(*align(1) const u32, bytes[1..5].ptr).* == expected);16 expect(@ptrCast(*align(1) const u32, bytes[1..5]).* == expected);
17}17}
1818
19test "reinterpret bytes of an array into an extern struct" {19test "reinterpret bytes of an array into an extern struct" {
test/stage1/behavior/slice.zig+155-4
...@@ -7,10 +7,10 @@ const mem = std.mem;...@@ -7,10 +7,10 @@ const mem = std.mem;
7const x = @intToPtr([*]i32, 0x1000)[0..0x500];7const x = @intToPtr([*]i32, 0x1000)[0..0x500];
8const y = x[0x100..];8const y = x[0x100..];
9test "compile time slice of pointer to hard coded address" {9test "compile time slice of pointer to hard coded address" {
10 expect(@ptrToInt(x.ptr) == 0x1000);10 expect(@ptrToInt(x) == 0x1000);
11 expect(x.len == 0x500);11 expect(x.len == 0x500);
1212
13 expect(@ptrToInt(y.ptr) == 0x1100);13 expect(@ptrToInt(y) == 0x1100);
14 expect(y.len == 0x400);14 expect(y.len == 0x400);
15}15}
1616
...@@ -47,7 +47,9 @@ test "C pointer slice access" {...@@ -47,7 +47,9 @@ test "C pointer slice access" {
47 var buf: [10]u32 = [1]u32{42} ** 10;47 var buf: [10]u32 = [1]u32{42} ** 10;
48 const c_ptr = @ptrCast([*c]const u32, &buf);48 const c_ptr = @ptrCast([*c]const u32, &buf);
4949
50 comptime expectEqual([]const u32, @TypeOf(c_ptr[0..1]));50 var runtime_zero: usize = 0;
51 comptime expectEqual([]const u32, @TypeOf(c_ptr[runtime_zero..1]));
52 comptime expectEqual(*const [1]u32, @TypeOf(c_ptr[0..1]));
5153
52 for (c_ptr[0..5]) |*cl| {54 for (c_ptr[0..5]) |*cl| {
53 expectEqual(@as(u32, 42), cl.*);55 expectEqual(@as(u32, 42), cl.*);
...@@ -107,7 +109,9 @@ test "obtaining a null terminated slice" {...@@ -107,7 +109,9 @@ test "obtaining a null terminated slice" {
107 const ptr2 = buf[0..runtime_len :0];109 const ptr2 = buf[0..runtime_len :0];
108 // ptr2 is a null-terminated slice110 // ptr2 is a null-terminated slice
109 comptime expect(@TypeOf(ptr2) == [:0]u8);111 comptime expect(@TypeOf(ptr2) == [:0]u8);
110 comptime expect(@TypeOf(ptr2[0..2]) == []u8);112 comptime expect(@TypeOf(ptr2[0..2]) == *[2]u8);
113 var runtime_zero: usize = 0;
114 comptime expect(@TypeOf(ptr2[runtime_zero..2]) == []u8);
111}115}
112116
113test "empty array to slice" {117test "empty array to slice" {
...@@ -126,3 +130,150 @@ test "empty array to slice" {...@@ -126,3 +130,150 @@ test "empty array to slice" {
126 S.doTheTest();130 S.doTheTest();
127 comptime S.doTheTest();131 comptime S.doTheTest();
128}132}
133
134test "@ptrCast slice to pointer" {
135 const S = struct {
136 fn doTheTest() void {
137 var array align(@alignOf(u16)) = [5]u8{ 0xff, 0xff, 0xff, 0xff, 0xff };
138 var slice: []u8 = &array;
139 var ptr = @ptrCast(*u16, slice);
140 expect(ptr.* == 65535);
141 }
142 };
143
144 S.doTheTest();
145 comptime S.doTheTest();
146}
147
148test "slice syntax resulting in pointer-to-array" {
149 const S = struct {
150 fn doTheTest() void {
151 testArray();
152 testArrayZ();
153 testArray0();
154 testArrayAlign();
155 testPointer();
156 testPointerZ();
157 testPointer0();
158 testPointerAlign();
159 testSlice();
160 testSliceZ();
161 testSlice0();
162 testSliceAlign();
163 }
164
165 fn testArray() void {
166 var array = [5]u8{ 1, 2, 3, 4, 5 };
167 var slice = array[1..3];
168 comptime expect(@TypeOf(slice) == *[2]u8);
169 expect(slice[0] == 2);
170 expect(slice[1] == 3);
171 }
172
173 fn testArrayZ() void {
174 var array = [5:0]u8{ 1, 2, 3, 4, 5 };
175 comptime expect(@TypeOf(array[1..3]) == *[2]u8);
176 comptime expect(@TypeOf(array[1..5]) == *[4:0]u8);
177 comptime expect(@TypeOf(array[1..]) == *[4:0]u8);
178 comptime expect(@TypeOf(array[1..3 :4]) == *[2:4]u8);
179 }
180
181 fn testArray0() void {
182 {
183 var array = [0]u8{};
184 var slice = array[0..0];
185 comptime expect(@TypeOf(slice) == *[0]u8);
186 }
187 {
188 var array = [0:0]u8{};
189 var slice = array[0..0];
190 comptime expect(@TypeOf(slice) == *[0:0]u8);
191 expect(slice[0] == 0);
192 }
193 }
194
195 fn testArrayAlign() void {
196 var array align(4) = [5]u8{ 1, 2, 3, 4, 5 };
197 var slice = array[4..5];
198 comptime expect(@TypeOf(slice) == *align(4) [1]u8);
199 expect(slice[0] == 5);
200 comptime expect(@TypeOf(array[0..2]) == *align(4) [2]u8);
201 }
202
203 fn testPointer() void {
204 var array = [5]u8{ 1, 2, 3, 4, 5 };
205 var pointer: [*]u8 = &array;
206 var slice = pointer[1..3];
207 comptime expect(@TypeOf(slice) == *[2]u8);
208 expect(slice[0] == 2);
209 expect(slice[1] == 3);
210 }
211
212 fn testPointerZ() void {
213 var array = [5:0]u8{ 1, 2, 3, 4, 5 };
214 var pointer: [*:0]u8 = &array;
215 comptime expect(@TypeOf(pointer[1..3]) == *[2]u8);
216 comptime expect(@TypeOf(pointer[1..3 :4]) == *[2:4]u8);
217 }
218
219 fn testPointer0() void {
220 var pointer: [*]u0 = &[1]u0{0};
221 var slice = pointer[0..1];
222 comptime expect(@TypeOf(slice) == *[1]u0);
223 expect(slice[0] == 0);
224 }
225
226 fn testPointerAlign() void {
227 var array align(4) = [5]u8{ 1, 2, 3, 4, 5 };
228 var pointer: [*]align(4) u8 = &array;
229 var slice = pointer[4..5];
230 comptime expect(@TypeOf(slice) == *align(4) [1]u8);
231 expect(slice[0] == 5);
232 comptime expect(@TypeOf(pointer[0..2]) == *align(4) [2]u8);
233 }
234
235 fn testSlice() void {
236 var array = [5]u8{ 1, 2, 3, 4, 5 };
237 var src_slice: []u8 = &array;
238 var slice = src_slice[1..3];
239 comptime expect(@TypeOf(slice) == *[2]u8);
240 expect(slice[0] == 2);
241 expect(slice[1] == 3);
242 }
243
244 fn testSliceZ() void {
245 var array = [5:0]u8{ 1, 2, 3, 4, 5 };
246 var slice: [:0]u8 = &array;
247 comptime expect(@TypeOf(slice[1..3]) == *[2]u8);
248 comptime expect(@TypeOf(slice[1..]) == [:0]u8);
249 comptime expect(@TypeOf(slice[1..3 :4]) == *[2:4]u8);
250 }
251
252 fn testSlice0() void {
253 {
254 var array = [0]u8{};
255 var src_slice: []u8 = &array;
256 var slice = src_slice[0..0];
257 comptime expect(@TypeOf(slice) == *[0]u8);
258 }
259 {
260 var array = [0:0]u8{};
261 var src_slice: [:0]u8 = &array;
262 var slice = src_slice[0..0];
263 comptime expect(@TypeOf(slice) == *[0]u8);
264 }
265 }
266
267 fn testSliceAlign() void {
268 var array align(4) = [5]u8{ 1, 2, 3, 4, 5 };
269 var src_slice: []align(4) u8 = &array;
270 var slice = src_slice[4..5];
271 comptime expect(@TypeOf(slice) == *align(4) [1]u8);
272 expect(slice[0] == 5);
273 comptime expect(@TypeOf(src_slice[0..2]) == *align(4) [2]u8);
274 }
275 };
276
277 S.doTheTest();
278 comptime S.doTheTest();
279}
test/stage1/behavior/struct.zig+2-2
...@@ -409,8 +409,8 @@ const Bitfields = packed struct {...@@ -409,8 +409,8 @@ const Bitfields = packed struct {
409test "native bit field understands endianness" {409test "native bit field understands endianness" {
410 var all: u64 = 0x7765443322221111;410 var all: u64 = 0x7765443322221111;
411 var bytes: [8]u8 = undefined;411 var bytes: [8]u8 = undefined;
412 @memcpy(bytes[0..].ptr, @ptrCast([*]u8, &all), 8);412 @memcpy(&bytes, @ptrCast([*]u8, &all), 8);
413 var bitfields = @ptrCast(*Bitfields, bytes[0..].ptr).*;413 var bitfields = @ptrCast(*Bitfields, &bytes).*;
414414
415 expect(bitfields.f1 == 0x1111);415 expect(bitfields.f1 == 0x1111);
416 expect(bitfields.f2 == 0x2222);416 expect(bitfields.f2 == 0x2222);