diff --git a/doc/langref.html.in b/doc/langref.html.in
index 83215b59ea1f..72e23a1011dd 100644
--- a/doc/langref.html.in
+++ b/doc/langref.html.in
@@ -2649,7 +2649,7 @@ test "Conversion between vectors, arrays, and slices" {
{#syntax#}[*]T{#endsyntax#} - many-item pointer to unknown number of items.
- Supports index syntax: {#syntax#}ptr[i]{#endsyntax#}
- - Supports slice syntax: {#syntax#}ptr[start..end]{#endsyntax#}
+ - Supports slice syntax: {#syntax#}ptr[start..end]{#endsyntax#} and {#syntax#}ptr[start..]{#endsyntax#}
- Supports pointer arithmetic: {#syntax#}ptr + x{#endsyntax#}, {#syntax#}ptr - x{#endsyntax#}
- {#syntax#}T{#endsyntax#} must have a known size, which means that it cannot be
{#syntax#}anyopaque{#endsyntax#} or any other {#link|opaque type|opaque#}.
@@ -2724,6 +2724,10 @@ test "pointer arithmetic with many-item pointer" {
try expect(ptr[0] == 1);
ptr += 1;
try expect(ptr[0] == 2);
+
+ // slicing a many-item pointer without an end is equivalent to
+ // pointer arithmetic: `ptr[start..] == ptr + start`
+ try expect(ptr[1..] == ptr + 1);
}
test "pointer arithmetic with slices" {
diff --git a/src/Sema.zig b/src/Sema.zig
index 047f8c2c96e1..0e2544ba592c 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -32157,7 +32157,7 @@ fn analyzeSlice(
break :e try sema.coerce(block, Type.usize, uncasted_end, end_src);
} else break :e try sema.coerce(block, Type.usize, uncasted_end_opt, end_src);
}
- return sema.fail(block, src, "slice of pointer must include end value", .{});
+ return sema.analyzePtrArithmetic(block, src, ptr, start, .ptr_add, ptr_src, start_src);
};
const sentinel = s: {
diff --git a/test/behavior/slice.zig b/test/behavior/slice.zig
index b195b3a5c1a4..c95bc293ef99 100644
--- a/test/behavior/slice.zig
+++ b/test/behavior/slice.zig
@@ -348,6 +348,41 @@ test "@ptrCast slice to pointer" {
try comptime S.doTheTest();
}
+test "slice multi-pointer without end" {
+ const S = struct {
+ fn doTheTest() !void {
+ try testPointer();
+ try testPointerZ();
+ }
+
+ fn testPointer() !void {
+ var array = [5]u8{ 1, 2, 3, 4, 5 };
+ var pointer: [*]u8 = &array;
+ var slice = pointer[1..];
+ try comptime expect(@TypeOf(slice) == [*]u8);
+ try expect(slice[0] == 2);
+ try expect(slice[1] == 3);
+ }
+
+ fn testPointerZ() !void {
+ var array = [5:0]u8{ 1, 2, 3, 4, 5 };
+ var pointer: [*:0]u8 = &array;
+
+ try comptime expect(@TypeOf(pointer[1..3]) == *[2]u8);
+ try comptime expect(@TypeOf(pointer[1..3 :4]) == *[2:4]u8);
+ try comptime expect(@TypeOf(pointer[1..5 :0]) == *[4:0]u8);
+
+ var slice = pointer[1..];
+ try comptime expect(@TypeOf(slice) == [*:0]u8);
+ try expect(slice[0] == 2);
+ try expect(slice[1] == 3);
+ }
+ };
+
+ try S.doTheTest();
+ try comptime S.doTheTest();
+}
+
test "slice syntax resulting in pointer-to-array" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO