| author | |
| committer | |
| log | dc04e97098010f590d109e6e70d4afe79cd8f01b |
| tree | bed11818fd80fe7b4557f4253c8d5562de773624 |
| parent | 555a2c03286507ffe4bd3bea2154dbfb719ebef1 |
| parent | 160367e0ddcb36b6957e603d869507b9d7542edc |
| signature |
slicing with comptime start and end indexes results in pointer-to-array41 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; |
| 2093 | test "global variable alignment" { | 2093 | test "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 | } |
| 2099 | 2100 | ||
| 2100 | fn derp() align(@sizeOf(usize) * 2) i32 { return 1234; } | 2101 | fn 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 at | 2188 | // 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); |
| 2193 | 2195 | ||
| ... | @@ -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#} |
| 2210 | const assert = @import("std").debug.assert; | 2212 | const std = @import("std"); |
| 2211 | const mem = @import("std").mem; | 2213 | const assert = std.debug.assert; |
| 2212 | const fmt = @import("std").fmt; | 2214 | const mem = std.mem; |
| 2215 | const fmt = std.fmt; | ||
| 2213 | 2216 | ||
| 2214 | test "using slices for strings" { | 2217 | test "using slices for strings" { |
| 2215 | // Zig has no concept of strings. String literals are arrays of u8, and | 2218 | // 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 u8 | 2221 | // 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 }); |
| 2226 | 2230 | ||
| 2227 | // Generally, you can use UTF-8 and not worry about whether something is a | 2231 | // 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 need | 2232 | // 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); | ||
| 2243 | 2249 | ||
| 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 | |||
| 2250 | test "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#} |
| 2261 | 2257 |
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 { |
| 15 | 15 | ||
| 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. |
| 17 | fn encryptBlock(xk: []const u32, dst: []u8, src: []const u8) void { | 17 | fn 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]); |
| 22 | 22 | ||
| 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]; |
| 60 | 60 | ||
| 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 | } |
| 66 | 66 | ||
| 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. |
| 68 | pub fn decryptBlock(xk: []const u32, dst: []u8, src: []const u8) void { | 68 | pub 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]); |
| 73 | 73 | ||
| 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]; |
| 111 | 111 | ||
| 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 | } |
| 117 | 117 | ||
| 118 | fn xorBytes(dst: []u8, a: []const u8, b: []const u8) usize { | 118 | fn 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); |
| 159 | 159 | ||
| 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]; |
| 124 | 124 | ||
| 125 | for (rr) |s, j| { | 125 | for (rr) |s, j| { |
| 126 | // TODO https://github.com/ziglang/zig/issues/863 | 126 | mem.writeIntLittle(u32, out[4 * j ..][0..4], s); |
| 127 | mem.writeIntSliceLittle(u32, out[4 * j .. 4 * j + 4], s); | ||
| 128 | } | 127 | } |
| 129 | } | 128 | } |
| 130 | 129 | ||
| ... | @@ -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; |
| 136 | 135 | ||
| 137 | for (m) |*r, i| { | 136 | for (m) |*r, i| { |
| 138 | // TODO https://github.com/ziglang/zig/issues/863 | 137 | r.* = mem.readIntLittle(u32, b[4 * i ..][0..4]); |
| 139 | r.* = mem.readIntSliceLittle(u32, b[4 * i .. 4 * i + 4]); | ||
| 140 | } | 138 | } |
| 141 | 139 | ||
| 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]; |
| 359 | 357 | ||
| 360 | for (rr) |s, j| { | 358 | for (rr) |s, j| { |
| 361 | // TODO https://github.com/ziglang/zig/issues/863 | 359 | mem.writeIntLittle(u64, out[8 * j ..][0..8], s); |
| 362 | mem.writeIntSliceLittle(u64, out[8 * j .. 8 * j + 8], s); | ||
| 363 | } | 360 | } |
| 364 | } | 361 | } |
| 365 | 362 | ||
| ... | @@ -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; |
| 371 | 368 | ||
| 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 | } |
| 375 | 372 | ||
| 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 | } |
| 62 | 62 | ||
| 63 | for (x) |_, i| { | 63 | for (x) |_, i| { |
| 64 | // TODO https://github.com/ziglang/zig/issues/863 | 64 | 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 | } |
| 68 | 67 | ||
| ... | @@ -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 |
| 73 | 72 | ||
| 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 | }; |
| 81 | 80 | ||
| 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; |
| 122 | 121 | ||
| 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]); |
| 131 | 130 | ||
| 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 | } |
| 138 | 137 | ||
| ... | @@ -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; |
| 149 | 148 | ||
| 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]); |
| 158 | 157 | ||
| 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]); |
| 163 | 162 | ||
| 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 machine | 164 | // 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..]); |
| 113 | 113 | ||
| 114 | for (d.s) |s, j| { | 114 | for (d.s) |s, j| { |
| 115 | // TODO https://github.com/ziglang/zig/issues/863 | 115 | mem.writeIntLittle(u32, out[4 * j ..][0..4], s); |
| 116 | mem.writeIntSliceLittle(u32, out[4 * j .. 4 * j + 4], s); | ||
| 117 | } | 116 | } |
| 118 | } | 117 | } |
| 119 | 118 |
lib/std/crypto/poly1305.zig+14-15| ... | @@ -3,11 +3,11 @@ | ... | @@ -3,11 +3,11 @@ |
| 3 | // https://monocypher.org/ | 3 | // https://monocypher.org/ |
| 4 | 4 | ||
| 5 | const std = @import("../std.zig"); | 5 | const std = @import("../std.zig"); |
| 6 | const builtin = @import("builtin"); | 6 | const builtin = std.builtin; |
| 7 | 7 | ||
| 8 | const Endian = builtin.Endian; | 8 | const Endian = builtin.Endian; |
| 9 | const readIntSliceLittle = std.mem.readIntSliceLittle; | 9 | const readIntLittle = std.mem.readIntLittle; |
| 10 | const writeIntSliceLittle = std.mem.writeIntSliceLittle; | 10 | const writeIntLittle = std.mem.writeIntLittle; |
| 11 | 11 | ||
| 12 | pub const Poly1305 = struct { | 12 | pub 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 | } |
| 77 | 77 | ||
| ... | @@ -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_00000000 | 210 | const uu2 = (uu1 >> 32) + ctx.h[2] + ctx.pad[2]; // <= 2_00000000 |
| 211 | const uu3 = (uu2 >> 32) + ctx.h[3] + ctx.pad[3]; // <= 2_00000000 | 211 | const uu3 = (uu2 >> 32) + ctx.h[3] + ctx.pad[3]; // <= 2_00000000 |
| 212 | 212 | ||
| 213 | // TODO https://github.com/ziglang/zig/issues/863 | 213 | 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)); | ||
| 218 | 217 | ||
| 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..]); |
| 110 | 110 | ||
| 111 | for (d.s) |s, j| { | 111 | for (d.s) |s, j| { |
| 112 | // TODO https://github.com/ziglang/zig/issues/863 | 112 | mem.writeIntBig(u32, out[4 * j ..][0..4], s); |
| 113 | mem.writeIntSliceBig(u32, out[4 * j .. 4 * j + 4], s); | ||
| 114 | } | 113 | } |
| 115 | } | 114 | } |
| 116 | 115 |
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]; |
| 168 | 168 | ||
| 169 | for (rr) |s, j| { | 169 | for (rr) |s, j| { |
| 170 | // TODO https://github.com/ziglang/zig/issues/863 | 170 | mem.writeIntBig(u32, out[4 * j ..][0..4], s); |
| 171 | mem.writeIntSliceBig(u32, out[4 * j .. 4 * j + 4], s); | ||
| 172 | } | 171 | } |
| 173 | } | 172 | } |
| 174 | 173 | ||
| ... | @@ -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]; |
| 510 | 509 | ||
| 511 | for (rr) |s, j| { | 510 | for (rr) |s, j| { |
| 512 | // TODO https://github.com/ziglang/zig/issues/863 | 511 | mem.writeIntBig(u64, out[8 * j ..][0..8], s); |
| 513 | mem.writeIntSliceBig(u64, out[8 * j .. 8 * j + 8], s); | ||
| 514 | } | 512 | } |
| 515 | } | 513 | } |
| 516 | 514 |
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; |
| 121 | 121 | ||
| 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 | } |
| 125 | 125 | ||
| 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 | } |
| 168 | 168 | ||
| 169 | for (s) |r, i| { | 169 | for (s) |r, i| { |
| 170 | // TODO https://github.com/ziglang/zig/issues/863 | 170 | mem.writeIntLittle(u64, d[8 * i ..][0..8], r); |
| 171 | mem.writeIntSliceLittle(u64, d[8 * i .. 8 * i + 8], r); | ||
| 172 | } | 171 | } |
| 173 | } | 172 | } |
| 174 | 173 |
lib/std/crypto/x25519.zig+20-21| ... | @@ -7,8 +7,8 @@ const builtin = @import("builtin"); | ... | @@ -7,8 +7,8 @@ const builtin = @import("builtin"); |
| 7 | const fmt = std.fmt; | 7 | const fmt = std.fmt; |
| 8 | 8 | ||
| 9 | const Endian = builtin.Endian; | 9 | const Endian = builtin.Endian; |
| 10 | const readIntSliceLittle = std.mem.readIntSliceLittle; | 10 | const readIntLittle = std.mem.readIntLittle; |
| 11 | const writeIntSliceLittle = std.mem.writeIntSliceLittle; | 11 | const writeIntLittle = std.mem.writeIntLittle; |
| 12 | 12 | ||
| 13 | // Based on Supercop's ref10 implementation. | 13 | // Based on Supercop's ref10 implementation. |
| 14 | pub const X25519 = struct { | 14 | pub const X25519 = struct { |
| ... | @@ -255,16 +255,16 @@ const Fe = struct { | ... | @@ -255,16 +255,16 @@ const Fe = struct { |
| 255 | 255 | ||
| 256 | var t: [10]i64 = undefined; | 256 | var t: [10]i64 = undefined; |
| 257 | 257 | ||
| 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; |
| 268 | 268 | ||
| 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 | } |
| 546 | 546 | ||
| 547 | // TODO https://github.com/ziglang/zig/issues/863 | 547 | 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)); | ||
| 556 | 555 | ||
| 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 | } |
| 1229 | 1230 |
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 | }, |
| 42 | 42 | ||
| 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); |
| 41 | 41 | ||
| 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]); |
| 44 | 44 | ||
| 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); |
| 113 | 113 | ||
| 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; |
| 116 | 116 | ||
| 117 | // TODO this is a workaround, should be able to supply the value without a separate variable | 117 | // 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{ |
| 11 | 11 | ||
| 12 | fn read_bytes(comptime bytes: u8, data: []const u8) u64 { | 12 | fn 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 | } |
| 16 | 16 | ||
| 17 | fn read_8bytes_swapped(data: []const u8) u64 { | 17 | fn 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 | }; |
| 2251 | 2251 | ||
| 2252 | pub const StringifyError = error{ | ||
| 2253 | TooMuchData, | ||
| 2254 | DifferentData, | ||
| 2255 | }; | ||
| 2256 | |||
| 2252 | pub fn stringify( | 2257 | pub 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)) { |
| 560 | 560 | ||
| 561 | test "span" { | 561 | test "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) { |
| 824 | pub fn readIntSliceNative(comptime T: type, bytes: []const u8) T { | 824 | pub 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/863 | 827 | return readIntNative(T, bytes[0..n]); |
| 828 | return readIntNative(T, @ptrCast(*const [n]u8, bytes.ptr)); | ||
| 829 | } | 828 | } |
| 830 | 829 | ||
| 831 | /// Asserts that bytes.len >= T.bit_count / 8. Reads the integer starting from index 0 | 830 | /// 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 |
| 863 | pub fn readIntSlice(comptime T: type, bytes: []const u8, endian: builtin.Endian) T { | 862 | pub 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/863 | 865 | return readInt(T, bytes[0..n], endian); |
| 867 | return readInt(T, @ptrCast(*const [n]u8, bytes.ptr), endian); | ||
| 868 | } | 866 | } |
| 869 | 867 | ||
| 870 | test "comptime read/write int" { | 868 | test "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 | } |
| 1587 | 1585 | ||
| 1588 | fn AsBytesReturnType(comptime P: type) type { | 1586 | fn 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)); |
| 1591 | 1589 | ||
| 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); |
| 1594 | 1592 | ||
| 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 | } |
| 1600 | 1598 | ||
| 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 | } |
| 1605 | 1603 | ||
| 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. |
| 1607 | pub fn asBytes(ptr: var) AsBytesReturnType(@TypeOf(ptr)) { | 1605 | pub 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 | } |
| 1751 | 1749 | ||
| 1752 | pub fn bytesAsSlice(comptime T: type, bytes: var) BytesAsSliceReturnType(T, @TypeOf(bytes)) { | 1750 | pub 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 @ptrCast | 1751 | // let's not give an undefined pointer to @ptrCast |
| 1756 | // it may be equal to zero and fail a null check | 1752 | // 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 | } |
| 1760 | 1756 | ||
| 1761 | const bytesType = @TypeOf(bytesSlice); | 1757 | const Bytes = @TypeOf(bytes); |
| 1762 | const alignment = comptime meta.alignment(bytesType); | 1758 | const alignment = comptime meta.alignment(Bytes); |
| 1763 | 1759 | ||
| 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; |
| 1765 | 1761 | ||
| 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 | } |
| 1768 | 1764 | ||
| 1769 | test "bytesAsSlice" { | 1765 | test "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 | } |
| 1776 | 1782 | ||
| 1777 | test "bytesAsSlice keeps pointer alignment" { | 1783 | test "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 | } |
| 1782 | 1796 | ||
| 1783 | test "bytesAsSlice on a packed struct" { | 1797 | test "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 | } |
| 1814 | 1828 | ||
| 1815 | pub fn sliceAsBytes(slice: var) SliceAsBytesReturnType(@TypeOf(slice)) { | 1829 | pub 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; | ||
| 1818 | 1831 | ||
| 1819 | // let's not give an undefined pointer to @ptrCast | 1832 | // let's not give an undefined pointer to @ptrCast |
| 1820 | // it may be equal to zero and fail a null check | 1833 | // 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 | } |
| 1824 | 1837 | ||
| 1825 | const sliceType = @TypeOf(actualSlice); | 1838 | const alignment = comptime meta.alignment(Slice); |
| 1826 | const alignment = comptime meta.alignment(sliceType); | ||
| 1827 | 1839 | ||
| 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; |
| 1829 | 1841 | ||
| 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 | } |
| 1832 | 1844 | ||
| 1833 | test "sliceAsBytes" { | 1845 | test "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 | } |
| 1899 | 1911 | ||
| 1900 | fn 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 | ||
| 1908 | pub 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 | |||
| 1920 | test "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 address | 1912 | /// 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. |
| 1935 | pub fn alignForward(addr: usize, alignment: usize) usize { | 1914 | pub 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 | } |
| 110 | 110 | ||
| ... | @@ -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 | } |
| 117 | 117 | ||
| 118 | /// Given a type with a sentinel e.g. `[:0]u8`, returns the sentinel | 118 | /// Given a "memory span" type, returns the "element type". |
| 119 | pub fn Sentinel(comptime T: type) Child(T) { | 119 | pub 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 | |||
| 134 | test "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. | ||
| 144 | pub 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 | } |
| 137 | 161 | ||
| 138 | test "std.meta.Sentinel" { | 162 | test "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 | |||
| 167 | fn 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 | } |
| 143 | 178 | ||
| 144 | pub fn containerLayout(comptime T: type) TypeInfo.ContainerLayout { | 179 | pub 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 { |
| 230 | 230 | ||
| 231 | test "std.meta.trait.isSingleItemPtr" { | 231 | test "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 | } |
| 237 | 238 | ||
| 238 | pub fn isManyItemPtr(comptime T: type) bool { | 239 | pub 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 { |
| 259 | 260 | ||
| 260 | test "std.meta.trait.isSlice" { | 261 | test "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 { |
| 276 | 278 | ||
| 277 | test "std.meta.trait.isIndexable" { | 279 | test "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); |
| 280 | 282 | ||
| 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/863 | 615 | 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 parsing | 820 | // 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 | } |
| 960 | 959 | ||
| 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); |
| 963 | 965 | ||
| 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 parsing | 1017 | // 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 desciption | 1276 | // 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 pair | 256 | // 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 | } |
| 632 | 632 | ||
| 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. |
| 634 | pub fn utf8ToUtf16LeStringLiteral(comptime utf8: []const u8) *const [calcUtf16LeLen(utf8) :0] u16 { | 634 | pub 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 | } |
| 661 | 661 | ||
| 662 | test "utf8ToUtf16LeStringLiteral" { | 662 | test "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`. |
| 1745 | fn escapeChar(c: u8, char_buf: *[4]u8) []const u8 { | 1745 | fn 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 them | 1754 | // into their respective hex representation |
| 1755 | // into their respective hex representation | 1755 | 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 unreachable | 1757 | else |
| 1758 | else | 1758 | 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 | } |
| 1763 | 1761 |
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_ptr | 258 | // 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 | }; |
| 261 | 266 | ||
| 262 | enum ConstPtrMut { | 267 | enum 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 | }; |
| 3711 | 3717 |
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 | } |
| 781 | 781 | ||
| 782 | ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, ZigValue *sentinel) { | 782 | ZigType *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 | } |
| 793 | 795 | ||
| 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 | } | ||
| 795 | 801 | ||
| 796 | ZigType *entry = new_type_table_entry(ZigTypeIdArray); | 802 | ZigType *entry = new_type_table_entry(ZigTypeIdArray); |
| 797 | 803 | ||
| ... | @@ -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)); |
| 805 | 811 | ||
| 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; |
| 810 | 815 | ||
| 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 | } |
| 4484 | 4489 | ||
| 4485 | uint32_t get_ptr_align(CodeGen *g, ZigType *type) { | 4490 | uint32_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 | } |
| 4502 | 4514 | ||
| 4503 | bool get_ptr_const(ZigType *type) { | 4515 | bool 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 errors | 7030 | // 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 |
| 76 | 76 | ||
| 77 | ZigType *get_src_ptr_type(ZigType *type); | 77 | ZigType *get_src_ptr_type(ZigType *type); |
| 78 | uint32_t get_ptr_align(CodeGen *g, ZigType *type); | 78 | uint32_t get_ptr_align(CodeGen *g, ZigType *type); |
| 79 | bool get_ptr_const(ZigType *type); | 79 | bool get_ptr_const(CodeGen *g, ZigType *type); |
| 80 | ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry); | 80 | ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry); |
| 81 | ZigType *container_ref_type(ZigType *type_entry); | 81 | ZigType *container_ref_type(ZigType *type_entry); |
| 82 | bool type_is_complete(ZigType *type_entry); | 82 | bool 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); |
| 5420 | 5420 | ||
| 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); |
| 5424 | 5422 | ||
| 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; | ||
| 5427 | 5431 | ||
| 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, ""); |
| 5462 | 5468 | ||
| 5463 | // TODO if runtime safety is on, store 0xaaaaaaa in ptr field | 5469 | // 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 | } |
| 5468 | 5474 | ||
| 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); | ||
| 5477 | 5488 | ||
| 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); |
| 5481 | 5492 | ||
| 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 | } |
| 5495 | 5507 | ||
| 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 | } |
| 5502 | 5523 | ||
| 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); |
| 5507 | 5534 | ||
| 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); | ||
| 5514 | 5541 | ||
| 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 | } |
| 5549 | 5576 | ||
| 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); | ||
| 5553 | 5586 | ||
| 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); |
| 5557 | 5590 | ||
| 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 | } |
| 851 | 869 | ||
| 852 | static 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 the | 870 | // This function returns true when you can change the type of a ZigValue and the |
| 858 | // value remains meaningful. | 871 | // value remains meaningful. |
| 859 | static bool types_have_same_zig_comptime_repr(CodeGen *codegen, ZigType *expected, ZigType *actual) { | 872 | static bool types_have_same_zig_comptime_repr(CodeGen *codegen, ZigType *expected, ZigType *actual) { |
| ... | @@ -3719,7 +3732,8 @@ static IrInstSrc *ir_build_slice_src(IrBuilderSrc *irb, Scope *scope, AstNode *s | ... | @@ -3719,7 +3732,8 @@ static IrInstSrc *ir_build_slice_src(IrBuilderSrc *irb, Scope *scope, AstNode *s |
| 3719 | } | 3732 | } |
| 3720 | 3733 | ||
| 3721 | static IrInstGen *ir_build_slice_gen(IrAnalyze *ira, IrInst *source_instruction, ZigType *slice_type, | 3734 | static 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; | ||
| 3732 | 3747 | ||
| 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); |
| 3737 | 3752 | ||
| 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; |
| 12678 | 12693 | ||
| 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 | //} | ||
| 12680 | 12715 | ||
| 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 | } |
| 12684 | 12719 | ||
| 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 | } |
| 12695 | 12724 | ||
| 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; | ||
| 12708 | 12735 | ||
| 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 | } |
| 12716 | 12770 | ||
| 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 | } |
| 14583 | 14637 | ||
| 14584 | // *[N]T to ?[]const T | 14638 | // *[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 | } |
| 19922 | 19977 | ||
| ... | @@ -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 | } |
| 20540 | 20621 | ||
| 20622 | static 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 | |||
| 20541 | static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemPtr *elem_ptr_instruction) { | 20660 | static 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 possible | 20798 | uint32_t chosen_align; |
| 20680 | 20799 | 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 |
| 25440 | static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align) { | 25543 | static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align) { |
| 25441 | Error err; | 25544 | Error err; |
| 25442 | 25545 | ||
| 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 | } |
| 25449 | 25563 | ||
| 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 | } |
| 26120 | 26237 | ||
| 26238 | static 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 | |||
| 26121 | static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *instruction) { | 26248 | static 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 | } |
| 26150 | 26279 | ||
| 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; |
| 26153 | 26283 | ||
| ... | @@ -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 | } |
| 26208 | 26339 | ||
| 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 | } |
| 26420 | done_with_return_type: | ||
| 26226 | 26421 | ||
| 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 | } |
| 26402 | 26599 | ||
| 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); | ||
| 26406 | 26601 | ||
| 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 | } | ||
| 26408 | 26615 | ||
| 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 | } |
| 26453 | 26664 | ||
| 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 | } |
| 26459 | 26669 | ||
| 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); |
| 26476 | 26672 | ||
| ... | @@ -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 | } |
| 26482 | 26678 | ||
| 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 | } |
| 26486 | 26700 | ||
| 26487 | static IrInstGen *ir_analyze_instruction_has_field(IrAnalyze *ira, IrInstSrcHasField *instruction) { | 26701 | static IrInstGen *ir_analyze_instruction_has_field(IrAnalyze *ira, IrInstSrcHasField *instruction) { |
| ... | @@ -27507,10 +27721,18 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn | ... | @@ -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 to | 27721 | // 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. |
| 27509 | 27723 | ||
| 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 | } |
| 27515 | 27737 | ||
| 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 | } |
| 27522 | 27744 | ||
| 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; |
| 27540 | 27762 | ||
| 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 | } |
| 27551 | 27776 | ||
| 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 | }); |
| 105 | 105 | ||
| 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"); |
| 5 | var foo: u8 align(4) = 100; | 5 | var foo: u8 align(4) = 100; |
| 6 | 6 | ||
| 7 | test "global variable alignment" { | 7 | test "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 | } |
| 13 | 20 | ||
| 14 | fn derp() align(@sizeOf(usize) * 2) i32 { | 21 | fn 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" { |
| 171 | 178 | ||
| 172 | // because pointer is align 2 and u32 align % 2 == 0 we can assume align 2 | 179 | // 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); | ||
| 180 | 188 | ||
| 181 | // has to use ABI alignment because index known at runtime only | 189 | // 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 | } |
| 187 | fn testIndex(smaller: [*]align(2) u32, index: usize, comptime T: type) void { | 195 | fn 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 { |
| 435 | 435 | ||
| 436 | test "implicit cast from [*]T to ?*c_void" { | 436 | test "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 | } |
| 441 | 442 |
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" { |
| 524 | test "comptime slice of pointer preserves comptime var" { | 524 | test "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; |
| 104 | 104 | ||
| 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); |
| 107 | 107 | ||
| 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 | } |
| 567 | 567 | ||
| 568 | test "slice string literal has type []const u8" { | 568 | test "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 | } |
| 575 | 579 | ||
| 576 | test "pointer child field" { | 580 | test "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); |
| 165 | 166 | ||
| 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 | } |
| 169 | 170 | ||
| 170 | test "assign null directly to C pointer and test null equality" { | 171 | test "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 | } |
| 18 | 18 | ||
| 19 | test "reinterpret bytes of an array into an extern struct" { | 19 | test "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; |
| 7 | const x = @intToPtr([*]i32, 0x1000)[0..0x500]; | 7 | const x = @intToPtr([*]i32, 0x1000)[0..0x500]; |
| 8 | const y = x[0x100..]; | 8 | const y = x[0x100..]; |
| 9 | test "compile time slice of pointer to hard coded address" { | 9 | test "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); |
| 12 | 12 | ||
| 13 | expect(@ptrToInt(y.ptr) == 0x1100); | 13 | expect(@ptrToInt(y) == 0x1100); |
| 14 | expect(y.len == 0x400); | 14 | expect(y.len == 0x400); |
| 15 | } | 15 | } |
| 16 | 16 | ||
| ... | @@ -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); |
| 49 | 49 | ||
| 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])); | ||
| 51 | 53 | ||
| 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 slice | 110 | // 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 | } |
| 112 | 116 | ||
| 113 | test "empty array to slice" { | 117 | test "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 | |||
| 134 | test "@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 | |||
| 148 | test "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 { |
| 409 | test "native bit field understands endianness" { | 409 | test "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).*; |
| 414 | 414 | ||
| 415 | expect(bitfields.f1 == 0x1111); | 415 | expect(bitfields.f1 == 0x1111); |
| 416 | expect(bitfields.f2 == 0x2222); | 416 | expect(bitfields.f2 == 0x2222); |