Skip to content

Commit 271452d

Browse files
authored
Merge pull request ziglang#22344 from Techatrix/slice-of-slice
fix incorrect slicing by length detection cases
2 parents 45e4b16 + 5b6326e commit 271452d

File tree

4 files changed

+106
-75
lines changed

4 files changed

+106
-75
lines changed

lib/std/zig/AstGen.zig

+36-75
Original file line numberDiff line numberDiff line change
@@ -876,100 +876,61 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
876876

877877
.for_simple, .@"for" => return forExpr(gz, scope, ri.br(), node, tree.fullFor(node).?, false),
878878

879-
.slice_open => {
880-
const lhs = try expr(gz, scope, .{ .rl = .ref }, node_datas[node].lhs);
881-
882-
const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);
883-
const start = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, node_datas[node].rhs);
884-
try emitDbgStmt(gz, cursor);
885-
const result = try gz.addPlNode(.slice_start, node, Zir.Inst.SliceStart{
886-
.lhs = lhs,
887-
.start = start,
888-
});
889-
return rvalue(gz, ri, result, node);
890-
},
891-
.slice => {
892-
const extra = tree.extraData(node_datas[node].rhs, Ast.Node.Slice);
893-
const lhs_node = node_datas[node].lhs;
894-
const lhs_tag = node_tags[lhs_node];
895-
const lhs_is_slice_sentinel = lhs_tag == .slice_sentinel;
896-
const lhs_is_open_slice = lhs_tag == .slice_open or
897-
(lhs_is_slice_sentinel and tree.extraData(node_datas[lhs_node].rhs, Ast.Node.SliceSentinel).end == 0);
898-
if (lhs_is_open_slice and nodeIsTriviallyZero(tree, extra.start)) {
899-
const lhs = try expr(gz, scope, .{ .rl = .ref }, node_datas[lhs_node].lhs);
900-
901-
const start = if (lhs_is_slice_sentinel) start: {
902-
const lhs_extra = tree.extraData(node_datas[lhs_node].rhs, Ast.Node.SliceSentinel);
903-
break :start try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, lhs_extra.start);
904-
} else try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, node_datas[lhs_node].rhs);
879+
.slice_open,
880+
.slice,
881+
.slice_sentinel,
882+
=> {
883+
const full = tree.fullSlice(node).?;
884+
if (full.ast.end != 0 and
885+
node_tags[full.ast.sliced] == .slice_open and
886+
nodeIsTriviallyZero(tree, full.ast.start))
887+
{
888+
const lhs_extra = tree.sliceOpen(full.ast.sliced).ast;
905889

890+
const lhs = try expr(gz, scope, .{ .rl = .ref }, lhs_extra.sliced);
891+
const start = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, lhs_extra.start);
906892
const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);
907-
const len = if (extra.end != 0) try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, extra.end) else .none;
893+
const len = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, full.ast.end);
894+
const sentinel = if (full.ast.sentinel != 0) try expr(gz, scope, .{ .rl = .none }, full.ast.sentinel) else .none;
908895
try emitDbgStmt(gz, cursor);
909896
const result = try gz.addPlNode(.slice_length, node, Zir.Inst.SliceLength{
910897
.lhs = lhs,
911898
.start = start,
912899
.len = len,
913-
.start_src_node_offset = gz.nodeIndexToRelative(lhs_node),
914-
.sentinel = .none,
900+
.start_src_node_offset = gz.nodeIndexToRelative(full.ast.sliced),
901+
.sentinel = sentinel,
915902
});
916903
return rvalue(gz, ri, result, node);
917904
}
918-
const lhs = try expr(gz, scope, .{ .rl = .ref }, node_datas[node].lhs);
905+
const lhs = try expr(gz, scope, .{ .rl = .ref }, full.ast.sliced);
919906

920907
const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);
921-
const start = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, extra.start);
922-
const end = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, extra.end);
908+
const start = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, full.ast.start);
909+
const end = if (full.ast.end != 0) try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, full.ast.end) else .none;
910+
const sentinel = if (full.ast.sentinel != 0) try expr(gz, scope, .{ .rl = .none }, full.ast.sentinel) else .none;
923911
try emitDbgStmt(gz, cursor);
924-
const result = try gz.addPlNode(.slice_end, node, Zir.Inst.SliceEnd{
925-
.lhs = lhs,
926-
.start = start,
927-
.end = end,
928-
});
929-
return rvalue(gz, ri, result, node);
930-
},
931-
.slice_sentinel => {
932-
const extra = tree.extraData(node_datas[node].rhs, Ast.Node.SliceSentinel);
933-
const lhs_node = node_datas[node].lhs;
934-
const lhs_tag = node_tags[lhs_node];
935-
const lhs_is_slice_sentinel = lhs_tag == .slice_sentinel;
936-
const lhs_is_open_slice = lhs_tag == .slice_open or
937-
(lhs_is_slice_sentinel and tree.extraData(node_datas[lhs_node].rhs, Ast.Node.SliceSentinel).end == 0);
938-
if (lhs_is_open_slice and nodeIsTriviallyZero(tree, extra.start)) {
939-
const lhs = try expr(gz, scope, .{ .rl = .ref }, node_datas[lhs_node].lhs);
940-
941-
const start = if (lhs_is_slice_sentinel) start: {
942-
const lhs_extra = tree.extraData(node_datas[lhs_node].rhs, Ast.Node.SliceSentinel);
943-
break :start try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, lhs_extra.start);
944-
} else try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, node_datas[lhs_node].rhs);
945-
946-
const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);
947-
const len = if (extra.end != 0) try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, extra.end) else .none;
948-
const sentinel = try expr(gz, scope, .{ .rl = .none }, extra.sentinel);
949-
try emitDbgStmt(gz, cursor);
950-
const result = try gz.addPlNode(.slice_length, node, Zir.Inst.SliceLength{
912+
if (sentinel != .none) {
913+
const result = try gz.addPlNode(.slice_sentinel, node, Zir.Inst.SliceSentinel{
951914
.lhs = lhs,
952915
.start = start,
953-
.len = len,
954-
.start_src_node_offset = gz.nodeIndexToRelative(lhs_node),
916+
.end = end,
955917
.sentinel = sentinel,
956918
});
957919
return rvalue(gz, ri, result, node);
920+
} else if (end != .none) {
921+
const result = try gz.addPlNode(.slice_end, node, Zir.Inst.SliceEnd{
922+
.lhs = lhs,
923+
.start = start,
924+
.end = end,
925+
});
926+
return rvalue(gz, ri, result, node);
927+
} else {
928+
const result = try gz.addPlNode(.slice_start, node, Zir.Inst.SliceStart{
929+
.lhs = lhs,
930+
.start = start,
931+
});
932+
return rvalue(gz, ri, result, node);
958933
}
959-
const lhs = try expr(gz, scope, .{ .rl = .ref }, node_datas[node].lhs);
960-
961-
const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);
962-
const start = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, extra.start);
963-
const end = if (extra.end != 0) try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, extra.end) else .none;
964-
const sentinel = try expr(gz, scope, .{ .rl = .none }, extra.sentinel);
965-
try emitDbgStmt(gz, cursor);
966-
const result = try gz.addPlNode(.slice_sentinel, node, Zir.Inst.SliceSentinel{
967-
.lhs = lhs,
968-
.start = start,
969-
.end = end,
970-
.sentinel = sentinel,
971-
});
972-
return rvalue(gz, ri, result, node);
973934
},
974935

975936
.deref => {

test/behavior/slice.zig

+34
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,40 @@ test "comptime slice of slice preserves comptime var" {
9898
}
9999
}
100100

101+
test "open slice of open slice with sentinel" {
102+
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
103+
104+
var slice: [:0]const u8 = "hello";
105+
_ = &slice;
106+
107+
comptime assert(@TypeOf(slice[0..][0.. :0]) == [:0]const u8);
108+
try expect(slice[0..][0.. :0].len == 5);
109+
try expect(slice[0..][0.. :0][0] == 'h');
110+
try expect(slice[0..][0.. :0][5] == 0);
111+
112+
comptime assert(@TypeOf(slice[1..][0.. :0]) == [:0]const u8);
113+
try expect(slice[1..][0.. :0].len == 4);
114+
try expect(slice[1..][0.. :0][0] == 'e');
115+
try expect(slice[1..][0.. :0][4] == 0);
116+
}
117+
118+
test "open slice with sentinel of slice with end index" {
119+
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
120+
121+
var slice: [:0]const u8 = "hello";
122+
_ = &slice;
123+
124+
comptime assert(@TypeOf(slice[0.. :0][0..5]) == *const [5]u8);
125+
try expect(slice[0.. :0][0..5].len == 5);
126+
try expect(slice[0.. :0][0..5][0] == 'h');
127+
try expect(slice[0.. :0][0..5][4] == 'o');
128+
129+
comptime assert(@TypeOf(slice[0.. :0][0..5 :0]) == *const [5:0]u8);
130+
try expect(slice[0.. :0][0..5 :0].len == 5);
131+
try expect(slice[0.. :0][0..5 :0][0] == 'h');
132+
try expect(slice[0.. :0][0..5 :0][5] == 0);
133+
}
134+
101135
test "slice of type" {
102136
comptime {
103137
var types_array = [_]type{ i32, f64, type };
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
const std = @import("std");
2+
3+
pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn {
4+
_ = stack_trace;
5+
if (std.mem.eql(u8, message, "sentinel mismatch: expected 1, found 3")) {
6+
std.process.exit(0);
7+
}
8+
std.process.exit(1);
9+
}
10+
pub fn main() !void {
11+
var buf: [4:0]u8 = .{ 1, 2, 3, 4 };
12+
const slice = buf[0..][0..2 :1];
13+
_ = slice;
14+
return error.TestFailed;
15+
}
16+
// run
17+
// backend=llvm
18+
// target=native
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
const std = @import("std");
2+
3+
pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn {
4+
_ = stack_trace;
5+
if (std.mem.eql(u8, message, "sentinel mismatch: expected 1, found 0")) {
6+
std.process.exit(0);
7+
}
8+
std.process.exit(1);
9+
}
10+
pub fn main() !void {
11+
var buf: [4:0]u8 = .{ 1, 2, 3, 4 };
12+
const slice = buf[0.. :1][0..2];
13+
_ = slice;
14+
return error.TestFailed;
15+
}
16+
// run
17+
// backend=llvm
18+
// target=native

0 commit comments

Comments
 (0)