authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2021-10-24 16:34:42+02:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2021-10-25 20:41:15+02:00
log0942bf73c90eabf87d0ca965b50beb0fd9a8fc8c
tree52576cb867ea0baad15b87d0a4ca4591d7226f02
parented7328119f2194f1b64085c08c88a5a656bfc597

stage2: improve slicing

* 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(
79897989 const offset = try sema.coerce(block, Type.usize, uncasted_offset, offset_src);
79907990 // TODO adjust the return type according to alignment and other factors
79917991 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| {
79947994 const ptr_ty = sema.typeOf(ptr);
7995 const offset_int = offset_val.toUnsignedInt();
79967995 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();
79978002 if (ptr_val.getUnsignedInt()) |addr| {
79988003 const target = sema.mod.getTarget();
79998004 const elem_ty = ptr_ty.childType();
......@@ -13206,8 +13211,8 @@ fn analyzeSlice(
1320613211 var elem_ty = ptr_ptr_child_ty.childType();
1320713212 switch (ptr_ptr_child_ty.zigTypeTag()) {
1320813213 .Array => {},
13209 .Pointer => {
13210 if (ptr_ptr_child_ty.isSinglePointer()) {
13214 .Pointer => switch (ptr_ptr_child_ty.ptrSize()) {
13215 .One => {
1321113216 const double_child_ty = ptr_ptr_child_ty.childType();
1321213217 if (double_child_ty.zigTypeTag() == .Array) {
1321313218 ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src);
......@@ -13217,10 +13222,23 @@ fn analyzeSlice(
1321713222 } else {
1321813223 return sema.fail(block, ptr_src, "slice of single-item pointer", .{});
1321913224 }
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 },
1322113238 },
1322213239 else => return sema.fail(block, ptr_src, "slice of non-array type '{}'", .{ptr_ptr_child_ty}),
1322313240 }
13241
1322413242 const ptr = if (slice_ty.isSlice())
1322513243 try sema.analyzeSlicePtr(block, src, ptr_or_slice, slice_ty, ptr_src)
1322613244 else
......@@ -13252,7 +13270,6 @@ fn analyzeSlice(
1325213270
1325313271 const new_len = try sema.analyzeArithmetic(block, .sub, end, start, src, end_src, start_src);
1325413272
13255 const opt_new_ptr_val = try sema.resolveDefinedValue(block, ptr_src, new_ptr);
1325613273 const opt_new_len_val = try sema.resolveDefinedValue(block, src, new_len);
1325713274
1325813275 const new_ptr_ty_info = sema.typeOf(new_ptr).ptrInfo().data;
......@@ -13276,11 +13293,21 @@ fn analyzeSlice(
1327613293 .size = .One,
1327713294 });
1327813295
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 {
1328213298 return block.addBitCast(return_ty, new_ptr);
13299 };
13300
13301 if (!new_ptr_val.isUndef()) {
13302 return sema.addConstant(return_ty, new_ptr_val);
1328313303 }
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", .{});
1328413311 }
1328513312
1328613313 const return_ty = try Type.ptr(sema.arena, .{
test/behavior/slice.zig+48
......@@ -109,3 +109,51 @@ test "slice of type" {
109109 }
110110 }
111111}
112
113test "generic malloc free" {
114 const a = memAlloc(u8, 10) catch unreachable;
115 memFree(u8, a);
116}
117var some_mem: [100]u8 = undefined;
118fn memAlloc(comptime T: type, n: usize) anyerror![]T {
119 return @ptrCast([*]T, &some_mem[0])[0..n];
120}
121fn memFree(comptime T: type, memory: []T) void {
122 _ = memory;
123}
124
125test "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
139test "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
148test "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" {
2525 comptime try expect(@TypeOf(array[runtime_zero..]) == []const i32);
2626}
2727
28test "generic malloc free" {
29 const a = memAlloc(u8, 10) catch unreachable;
30 memFree(u8, a);
31}
32var some_mem: [100]u8 = undefined;
33fn memAlloc(comptime T: type, n: usize) anyerror![]T {
34 return @ptrCast([*]T, &some_mem[0])[0..n];
35}
36fn memFree(comptime T: type, memory: []T) void {
37 _ = memory;
38}
39
4028test "result location zero sized array inside struct field implicit cast to slice" {
4129 const E = struct {
4230 entries: []u32,
......@@ -307,20 +295,6 @@ test "slice syntax resulting in pointer-to-array" {
307295 comptime try S.doTheTest();
308296}
309297
310test "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
324298test "type coercion of pointer to anon struct literal to pointer to slice" {
325299 const S = struct {
326300 const U = union {
......@@ -352,15 +326,6 @@ test "type coercion of pointer to anon struct literal to pointer to slice" {
352326 comptime try S.doTheTest();
353327}
354328
355test "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
364329test "array concat of slices gives slice" {
365330 comptime {
366331 var a: []const u8 = "aoeu";
......@@ -370,19 +335,6 @@ test "array concat of slices gives slice" {
370335 }
371336}
372337
373test "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
386338test "slice bounds in comptime concatenation" {
387339 const bs = comptime blk: {
388340 const b = "........1........";