mirror of
https://github.com/ziglang/zig.git
synced 2025-12-15 02:33:07 +00:00
stage2: improve slicing
* Allow slicing many- and c-pointers. * Allow comptime pointer arithmetic on undefined values. * Return the correct type for slicing of slices.
This commit is contained in:
parent
ed7328119f
commit
0942bf73c9
47
src/Sema.zig
47
src/Sema.zig
@ -7989,11 +7989,16 @@ fn analyzePtrArithmetic(
|
|||||||
const offset = try sema.coerce(block, Type.usize, uncasted_offset, offset_src);
|
const offset = try sema.coerce(block, Type.usize, uncasted_offset, offset_src);
|
||||||
// TODO adjust the return type according to alignment and other factors
|
// TODO adjust the return type according to alignment and other factors
|
||||||
const runtime_src = rs: {
|
const runtime_src = rs: {
|
||||||
if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| {
|
if (try sema.resolveMaybeUndefVal(block, ptr_src, ptr)) |ptr_val| {
|
||||||
if (try sema.resolveDefinedValue(block, offset_src, offset)) |offset_val| {
|
if (try sema.resolveMaybeUndefVal(block, offset_src, offset)) |offset_val| {
|
||||||
const ptr_ty = sema.typeOf(ptr);
|
const ptr_ty = sema.typeOf(ptr);
|
||||||
const offset_int = offset_val.toUnsignedInt();
|
|
||||||
const new_ptr_ty = ptr_ty; // TODO modify alignment
|
const new_ptr_ty = ptr_ty; // TODO modify alignment
|
||||||
|
|
||||||
|
if (ptr_val.isUndef() or offset_val.isUndef()) {
|
||||||
|
return sema.addConstUndef(new_ptr_ty);
|
||||||
|
}
|
||||||
|
|
||||||
|
const offset_int = offset_val.toUnsignedInt();
|
||||||
if (ptr_val.getUnsignedInt()) |addr| {
|
if (ptr_val.getUnsignedInt()) |addr| {
|
||||||
const target = sema.mod.getTarget();
|
const target = sema.mod.getTarget();
|
||||||
const elem_ty = ptr_ty.childType();
|
const elem_ty = ptr_ty.childType();
|
||||||
@ -13206,8 +13211,8 @@ fn analyzeSlice(
|
|||||||
var elem_ty = ptr_ptr_child_ty.childType();
|
var elem_ty = ptr_ptr_child_ty.childType();
|
||||||
switch (ptr_ptr_child_ty.zigTypeTag()) {
|
switch (ptr_ptr_child_ty.zigTypeTag()) {
|
||||||
.Array => {},
|
.Array => {},
|
||||||
.Pointer => {
|
.Pointer => switch (ptr_ptr_child_ty.ptrSize()) {
|
||||||
if (ptr_ptr_child_ty.isSinglePointer()) {
|
.One => {
|
||||||
const double_child_ty = ptr_ptr_child_ty.childType();
|
const double_child_ty = ptr_ptr_child_ty.childType();
|
||||||
if (double_child_ty.zigTypeTag() == .Array) {
|
if (double_child_ty.zigTypeTag() == .Array) {
|
||||||
ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src);
|
ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src);
|
||||||
@ -13217,10 +13222,23 @@ fn analyzeSlice(
|
|||||||
} else {
|
} else {
|
||||||
return sema.fail(block, ptr_src, "slice of single-item pointer", .{});
|
return sema.fail(block, ptr_src, "slice of single-item pointer", .{});
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
.Many, .C => {
|
||||||
|
ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src);
|
||||||
|
slice_ty = ptr_ptr_child_ty;
|
||||||
|
array_ty = ptr_ptr_child_ty;
|
||||||
|
elem_ty = ptr_ptr_child_ty.childType();
|
||||||
|
},
|
||||||
|
.Slice => {
|
||||||
|
ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src);
|
||||||
|
slice_ty = ptr_ptr_child_ty;
|
||||||
|
array_ty = ptr_ptr_child_ty;
|
||||||
|
elem_ty = ptr_ptr_child_ty.childType();
|
||||||
|
},
|
||||||
},
|
},
|
||||||
else => return sema.fail(block, ptr_src, "slice of non-array type '{}'", .{ptr_ptr_child_ty}),
|
else => return sema.fail(block, ptr_src, "slice of non-array type '{}'", .{ptr_ptr_child_ty}),
|
||||||
}
|
}
|
||||||
|
|
||||||
const ptr = if (slice_ty.isSlice())
|
const ptr = if (slice_ty.isSlice())
|
||||||
try sema.analyzeSlicePtr(block, src, ptr_or_slice, slice_ty, ptr_src)
|
try sema.analyzeSlicePtr(block, src, ptr_or_slice, slice_ty, ptr_src)
|
||||||
else
|
else
|
||||||
@ -13252,7 +13270,6 @@ fn analyzeSlice(
|
|||||||
|
|
||||||
const new_len = try sema.analyzeArithmetic(block, .sub, end, start, src, end_src, start_src);
|
const new_len = try sema.analyzeArithmetic(block, .sub, end, start, src, end_src, start_src);
|
||||||
|
|
||||||
const opt_new_ptr_val = try sema.resolveDefinedValue(block, ptr_src, new_ptr);
|
|
||||||
const opt_new_len_val = try sema.resolveDefinedValue(block, src, new_len);
|
const opt_new_len_val = try sema.resolveDefinedValue(block, src, new_len);
|
||||||
|
|
||||||
const new_ptr_ty_info = sema.typeOf(new_ptr).ptrInfo().data;
|
const new_ptr_ty_info = sema.typeOf(new_ptr).ptrInfo().data;
|
||||||
@ -13276,11 +13293,21 @@ fn analyzeSlice(
|
|||||||
.size = .One,
|
.size = .One,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (opt_new_ptr_val) |new_ptr_val| {
|
const opt_new_ptr_val = try sema.resolveMaybeUndefVal(block, ptr_src, new_ptr);
|
||||||
return sema.addConstant(return_ty, new_ptr_val);
|
const new_ptr_val = opt_new_ptr_val orelse {
|
||||||
} else {
|
|
||||||
return block.addBitCast(return_ty, new_ptr);
|
return block.addBitCast(return_ty, new_ptr);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!new_ptr_val.isUndef()) {
|
||||||
|
return sema.addConstant(return_ty, new_ptr_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Special case: @as([]i32, undefined)[x..x]
|
||||||
|
if (new_len_int == 0) {
|
||||||
|
return sema.addConstUndef(return_ty);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sema.fail(block, ptr_src, "non-zero length slice of undefined pointer", .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
const return_ty = try Type.ptr(sema.arena, .{
|
const return_ty = try Type.ptr(sema.arena, .{
|
||||||
|
|||||||
@ -109,3 +109,51 @@ test "slice of type" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "generic malloc free" {
|
||||||
|
const a = memAlloc(u8, 10) catch unreachable;
|
||||||
|
memFree(u8, a);
|
||||||
|
}
|
||||||
|
var some_mem: [100]u8 = undefined;
|
||||||
|
fn memAlloc(comptime T: type, n: usize) anyerror![]T {
|
||||||
|
return @ptrCast([*]T, &some_mem[0])[0..n];
|
||||||
|
}
|
||||||
|
fn memFree(comptime T: type, memory: []T) void {
|
||||||
|
_ = memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
test "slice of hardcoded address to pointer" {
|
||||||
|
const S = struct {
|
||||||
|
fn doTheTest() !void {
|
||||||
|
const pointer = @intToPtr([*]u8, 0x04)[0..2];
|
||||||
|
comptime try expect(@TypeOf(pointer) == *[2]u8);
|
||||||
|
const slice: []const u8 = pointer;
|
||||||
|
try expect(@ptrToInt(slice.ptr) == 4);
|
||||||
|
try expect(slice.len == 2);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
try S.doTheTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
test "comptime slice of pointer preserves comptime var" {
|
||||||
|
comptime {
|
||||||
|
var buff: [10]u8 = undefined;
|
||||||
|
var a = @ptrCast([*]u8, &buff);
|
||||||
|
a[0..1][0] = 1;
|
||||||
|
try expect(buff[0..][0..][0] == 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "comptime pointer cast array and then slice" {
|
||||||
|
const array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };
|
||||||
|
|
||||||
|
const ptrA: [*]const u8 = @ptrCast([*]const u8, &array);
|
||||||
|
const sliceA: []const u8 = ptrA[0..2];
|
||||||
|
|
||||||
|
const ptrB: [*]const u8 = &array;
|
||||||
|
const sliceB: []const u8 = ptrB[0..2];
|
||||||
|
|
||||||
|
try expect(sliceA[1] == 2);
|
||||||
|
try expect(sliceB[1] == 2);
|
||||||
|
}
|
||||||
|
|||||||
@ -25,18 +25,6 @@ test "slice string literal has correct type" {
|
|||||||
comptime try expect(@TypeOf(array[runtime_zero..]) == []const i32);
|
comptime try expect(@TypeOf(array[runtime_zero..]) == []const i32);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "generic malloc free" {
|
|
||||||
const a = memAlloc(u8, 10) catch unreachable;
|
|
||||||
memFree(u8, a);
|
|
||||||
}
|
|
||||||
var some_mem: [100]u8 = undefined;
|
|
||||||
fn memAlloc(comptime T: type, n: usize) anyerror![]T {
|
|
||||||
return @ptrCast([*]T, &some_mem[0])[0..n];
|
|
||||||
}
|
|
||||||
fn memFree(comptime T: type, memory: []T) void {
|
|
||||||
_ = memory;
|
|
||||||
}
|
|
||||||
|
|
||||||
test "result location zero sized array inside struct field implicit cast to slice" {
|
test "result location zero sized array inside struct field implicit cast to slice" {
|
||||||
const E = struct {
|
const E = struct {
|
||||||
entries: []u32,
|
entries: []u32,
|
||||||
@ -307,20 +295,6 @@ test "slice syntax resulting in pointer-to-array" {
|
|||||||
comptime try S.doTheTest();
|
comptime try S.doTheTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
test "slice of hardcoded address to pointer" {
|
|
||||||
const S = struct {
|
|
||||||
fn doTheTest() !void {
|
|
||||||
const pointer = @intToPtr([*]u8, 0x04)[0..2];
|
|
||||||
comptime try expect(@TypeOf(pointer) == *[2]u8);
|
|
||||||
const slice: []const u8 = pointer;
|
|
||||||
try expect(@ptrToInt(slice.ptr) == 4);
|
|
||||||
try expect(slice.len == 2);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
try S.doTheTest();
|
|
||||||
}
|
|
||||||
|
|
||||||
test "type coercion of pointer to anon struct literal to pointer to slice" {
|
test "type coercion of pointer to anon struct literal to pointer to slice" {
|
||||||
const S = struct {
|
const S = struct {
|
||||||
const U = union {
|
const U = union {
|
||||||
@ -352,15 +326,6 @@ test "type coercion of pointer to anon struct literal to pointer to slice" {
|
|||||||
comptime try S.doTheTest();
|
comptime try S.doTheTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
test "comptime slice of pointer preserves comptime var" {
|
|
||||||
comptime {
|
|
||||||
var buff: [10]u8 = undefined;
|
|
||||||
var a = @ptrCast([*]u8, &buff);
|
|
||||||
a[0..1][0] = 1;
|
|
||||||
try expect(buff[0..][0..][0] == 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
test "array concat of slices gives slice" {
|
test "array concat of slices gives slice" {
|
||||||
comptime {
|
comptime {
|
||||||
var a: []const u8 = "aoeu";
|
var a: []const u8 = "aoeu";
|
||||||
@ -370,19 +335,6 @@ test "array concat of slices gives slice" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test "comptime pointer cast array and then slice" {
|
|
||||||
const array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };
|
|
||||||
|
|
||||||
const ptrA: [*]const u8 = @ptrCast([*]const u8, &array);
|
|
||||||
const sliceA: []const u8 = ptrA[0..2];
|
|
||||||
|
|
||||||
const ptrB: [*]const u8 = &array;
|
|
||||||
const sliceB: []const u8 = ptrB[0..2];
|
|
||||||
|
|
||||||
try expect(sliceA[1] == 2);
|
|
||||||
try expect(sliceB[1] == 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
test "slice bounds in comptime concatenation" {
|
test "slice bounds in comptime concatenation" {
|
||||||
const bs = comptime blk: {
|
const bs = comptime blk: {
|
||||||
const b = "........1........";
|
const b = "........1........";
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user