| author | |
| committer | |
| log | 0942bf73c90eabf87d0ca965b50beb0fd9a8fc8c |
| tree | 52576cb867ea0baad15b87d0a4ca4591d7226f02 |
| parent | ed7328119f2194f1b64085c08c88a5a656bfc597 |
* Allow slicing many- and c-pointers.
* Allow comptime pointer arithmetic on undefined values.
* Return the correct type for slicing of slices.3 files changed, 85 insertions(+), 58 deletions(-)
src/Sema.zig+37-10| ... | ... | @@ -7989,11 +7989,16 @@ fn analyzePtrArithmetic( |
| 7989 | 7989 | const offset = try sema.coerce(block, Type.usize, uncasted_offset, offset_src); |
| 7990 | 7990 | // TODO adjust the return type according to alignment and other factors |
| 7991 | 7991 | const runtime_src = rs: { |
| 7992 | if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| { | |
| 7993 | if (try sema.resolveDefinedValue(block, offset_src, offset)) |offset_val| { | |
| 7992 | if (try sema.resolveMaybeUndefVal(block, ptr_src, ptr)) |ptr_val| { | |
| 7993 | if (try sema.resolveMaybeUndefVal(block, offset_src, offset)) |offset_val| { | |
| 7994 | 7994 | const ptr_ty = sema.typeOf(ptr); |
| 7995 | const offset_int = offset_val.toUnsignedInt(); | |
| 7996 | 7995 | const new_ptr_ty = ptr_ty; // TODO modify alignment |
| 7996 | ||
| 7997 | if (ptr_val.isUndef() or offset_val.isUndef()) { | |
| 7998 | return sema.addConstUndef(new_ptr_ty); | |
| 7999 | } | |
| 8000 | ||
| 8001 | const offset_int = offset_val.toUnsignedInt(); | |
| 7997 | 8002 | if (ptr_val.getUnsignedInt()) |addr| { |
| 7998 | 8003 | const target = sema.mod.getTarget(); |
| 7999 | 8004 | const elem_ty = ptr_ty.childType(); |
| ... | ... | @@ -13206,8 +13211,8 @@ fn analyzeSlice( |
| 13206 | 13211 | var elem_ty = ptr_ptr_child_ty.childType(); |
| 13207 | 13212 | switch (ptr_ptr_child_ty.zigTypeTag()) { |
| 13208 | 13213 | .Array => {}, |
| 13209 | .Pointer => { | |
| 13210 | if (ptr_ptr_child_ty.isSinglePointer()) { | |
| 13214 | .Pointer => switch (ptr_ptr_child_ty.ptrSize()) { | |
| 13215 | .One => { | |
| 13211 | 13216 | const double_child_ty = ptr_ptr_child_ty.childType(); |
| 13212 | 13217 | if (double_child_ty.zigTypeTag() == .Array) { |
| 13213 | 13218 | ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src); |
| ... | ... | @@ -13217,10 +13222,23 @@ fn analyzeSlice( |
| 13217 | 13222 | } else { |
| 13218 | 13223 | return sema.fail(block, ptr_src, "slice of single-item pointer", .{}); |
| 13219 | 13224 | } |
| 13220 | } | |
| 13225 | }, | |
| 13226 | .Many, .C => { | |
| 13227 | ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src); | |
| 13228 | slice_ty = ptr_ptr_child_ty; | |
| 13229 | array_ty = ptr_ptr_child_ty; | |
| 13230 | elem_ty = ptr_ptr_child_ty.childType(); | |
| 13231 | }, | |
| 13232 | .Slice => { | |
| 13233 | ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src); | |
| 13234 | slice_ty = ptr_ptr_child_ty; | |
| 13235 | array_ty = ptr_ptr_child_ty; | |
| 13236 | elem_ty = ptr_ptr_child_ty.childType(); | |
| 13237 | }, | |
| 13221 | 13238 | }, |
| 13222 | 13239 | else => return sema.fail(block, ptr_src, "slice of non-array type '{}'", .{ptr_ptr_child_ty}), |
| 13223 | 13240 | } |
| 13241 | ||
| 13224 | 13242 | const ptr = if (slice_ty.isSlice()) |
| 13225 | 13243 | try sema.analyzeSlicePtr(block, src, ptr_or_slice, slice_ty, ptr_src) |
| 13226 | 13244 | else |
| ... | ... | @@ -13252,7 +13270,6 @@ fn analyzeSlice( |
| 13252 | 13270 | |
| 13253 | 13271 | const new_len = try sema.analyzeArithmetic(block, .sub, end, start, src, end_src, start_src); |
| 13254 | 13272 | |
| 13255 | const opt_new_ptr_val = try sema.resolveDefinedValue(block, ptr_src, new_ptr); | |
| 13256 | 13273 | const opt_new_len_val = try sema.resolveDefinedValue(block, src, new_len); |
| 13257 | 13274 | |
| 13258 | 13275 | const new_ptr_ty_info = sema.typeOf(new_ptr).ptrInfo().data; |
| ... | ... | @@ -13276,11 +13293,21 @@ fn analyzeSlice( |
| 13276 | 13293 | .size = .One, |
| 13277 | 13294 | }); |
| 13278 | 13295 | |
| 13279 | if (opt_new_ptr_val) |new_ptr_val| { | |
| 13280 | return sema.addConstant(return_ty, new_ptr_val); | |
| 13281 | } else { | |
| 13296 | const opt_new_ptr_val = try sema.resolveMaybeUndefVal(block, ptr_src, new_ptr); | |
| 13297 | const new_ptr_val = opt_new_ptr_val orelse { | |
| 13282 | 13298 | return block.addBitCast(return_ty, new_ptr); |
| 13299 | }; | |
| 13300 | ||
| 13301 | if (!new_ptr_val.isUndef()) { | |
| 13302 | return sema.addConstant(return_ty, new_ptr_val); | |
| 13283 | 13303 | } |
| 13304 | ||
| 13305 | // Special case: @as([]i32, undefined)[x..x] | |
| 13306 | if (new_len_int == 0) { | |
| 13307 | return sema.addConstUndef(return_ty); | |
| 13308 | } | |
| 13309 | ||
| 13310 | return sema.fail(block, ptr_src, "non-zero length slice of undefined pointer", .{}); | |
| 13284 | 13311 | } |
| 13285 | 13312 | |
| 13286 | 13313 | const return_ty = try Type.ptr(sema.arena, .{ |
test/behavior/slice.zig+48| ... | ... | @@ -109,3 +109,51 @@ test "slice of type" { |
| 109 | 109 | } |
| 110 | 110 | } |
| 111 | 111 | } |
| 112 | ||
| 113 | test "generic malloc free" { | |
| 114 | const a = memAlloc(u8, 10) catch unreachable; | |
| 115 | memFree(u8, a); | |
| 116 | } | |
| 117 | var some_mem: [100]u8 = undefined; | |
| 118 | fn memAlloc(comptime T: type, n: usize) anyerror![]T { | |
| 119 | return @ptrCast([*]T, &some_mem[0])[0..n]; | |
| 120 | } | |
| 121 | fn memFree(comptime T: type, memory: []T) void { | |
| 122 | _ = memory; | |
| 123 | } | |
| 124 | ||
| 125 | test "slice of hardcoded address to pointer" { | |
| 126 | const S = struct { | |
| 127 | fn doTheTest() !void { | |
| 128 | const pointer = @intToPtr([*]u8, 0x04)[0..2]; | |
| 129 | comptime try expect(@TypeOf(pointer) == *[2]u8); | |
| 130 | const slice: []const u8 = pointer; | |
| 131 | try expect(@ptrToInt(slice.ptr) == 4); | |
| 132 | try expect(slice.len == 2); | |
| 133 | } | |
| 134 | }; | |
| 135 | ||
| 136 | try S.doTheTest(); | |
| 137 | } | |
| 138 | ||
| 139 | test "comptime slice of pointer preserves comptime var" { | |
| 140 | comptime { | |
| 141 | var buff: [10]u8 = undefined; | |
| 142 | var a = @ptrCast([*]u8, &buff); | |
| 143 | a[0..1][0] = 1; | |
| 144 | try expect(buff[0..][0..][0] == 1); | |
| 145 | } | |
| 146 | } | |
| 147 | ||
| 148 | test "comptime pointer cast array and then slice" { | |
| 149 | const array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 }; | |
| 150 | ||
| 151 | const ptrA: [*]const u8 = @ptrCast([*]const u8, &array); | |
| 152 | const sliceA: []const u8 = ptrA[0..2]; | |
| 153 | ||
| 154 | const ptrB: [*]const u8 = &array; | |
| 155 | const sliceB: []const u8 = ptrB[0..2]; | |
| 156 | ||
| 157 | try expect(sliceA[1] == 2); | |
| 158 | try expect(sliceB[1] == 2); | |
| 159 | } |
test/behavior/slice_stage1.zig-48| ... | ... | @@ -25,18 +25,6 @@ test "slice string literal has correct type" { |
| 25 | 25 | comptime try expect(@TypeOf(array[runtime_zero..]) == []const i32); |
| 26 | 26 | } |
| 27 | 27 | |
| 28 | test "generic malloc free" { | |
| 29 | const a = memAlloc(u8, 10) catch unreachable; | |
| 30 | memFree(u8, a); | |
| 31 | } | |
| 32 | var some_mem: [100]u8 = undefined; | |
| 33 | fn memAlloc(comptime T: type, n: usize) anyerror![]T { | |
| 34 | return @ptrCast([*]T, &some_mem[0])[0..n]; | |
| 35 | } | |
| 36 | fn memFree(comptime T: type, memory: []T) void { | |
| 37 | _ = memory; | |
| 38 | } | |
| 39 | ||
| 40 | 28 | test "result location zero sized array inside struct field implicit cast to slice" { |
| 41 | 29 | const E = struct { |
| 42 | 30 | entries: []u32, |
| ... | ... | @@ -307,20 +295,6 @@ test "slice syntax resulting in pointer-to-array" { |
| 307 | 295 | comptime try S.doTheTest(); |
| 308 | 296 | } |
| 309 | 297 | |
| 310 | test "slice of hardcoded address to pointer" { | |
| 311 | const S = struct { | |
| 312 | fn doTheTest() !void { | |
| 313 | const pointer = @intToPtr([*]u8, 0x04)[0..2]; | |
| 314 | comptime try expect(@TypeOf(pointer) == *[2]u8); | |
| 315 | const slice: []const u8 = pointer; | |
| 316 | try expect(@ptrToInt(slice.ptr) == 4); | |
| 317 | try expect(slice.len == 2); | |
| 318 | } | |
| 319 | }; | |
| 320 | ||
| 321 | try S.doTheTest(); | |
| 322 | } | |
| 323 | ||
| 324 | 298 | test "type coercion of pointer to anon struct literal to pointer to slice" { |
| 325 | 299 | const S = struct { |
| 326 | 300 | const U = union { |
| ... | ... | @@ -352,15 +326,6 @@ test "type coercion of pointer to anon struct literal to pointer to slice" { |
| 352 | 326 | comptime try S.doTheTest(); |
| 353 | 327 | } |
| 354 | 328 | |
| 355 | test "comptime slice of pointer preserves comptime var" { | |
| 356 | comptime { | |
| 357 | var buff: [10]u8 = undefined; | |
| 358 | var a = @ptrCast([*]u8, &buff); | |
| 359 | a[0..1][0] = 1; | |
| 360 | try expect(buff[0..][0..][0] == 1); | |
| 361 | } | |
| 362 | } | |
| 363 | ||
| 364 | 329 | test "array concat of slices gives slice" { |
| 365 | 330 | comptime { |
| 366 | 331 | var a: []const u8 = "aoeu"; |
| ... | ... | @@ -370,19 +335,6 @@ test "array concat of slices gives slice" { |
| 370 | 335 | } |
| 371 | 336 | } |
| 372 | 337 | |
| 373 | test "comptime pointer cast array and then slice" { | |
| 374 | const array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 }; | |
| 375 | ||
| 376 | const ptrA: [*]const u8 = @ptrCast([*]const u8, &array); | |
| 377 | const sliceA: []const u8 = ptrA[0..2]; | |
| 378 | ||
| 379 | const ptrB: [*]const u8 = &array; | |
| 380 | const sliceB: []const u8 = ptrB[0..2]; | |
| 381 | ||
| 382 | try expect(sliceA[1] == 2); | |
| 383 | try expect(sliceB[1] == 2); | |
| 384 | } | |
| 385 | ||
| 386 | 338 | test "slice bounds in comptime concatenation" { |
| 387 | 339 | const bs = comptime blk: { |
| 388 | 340 | const b = "........1........"; |