Commit db4c06ce60

Michael Dusan <michael.dusan@gmail.com>
2020-04-03 17:41:55
stage1: add compile errors for sentinel slicing
closes #3963
1 parent f1425fd
Changed files (4)
src/ir.cpp
@@ -26583,7 +26583,6 @@ done_with_return_type:
                 if (parent_ptr == nullptr)
                     return ira->codegen->invalid_inst_gen;
 
-
                 if (parent_ptr->special == ConstValSpecialUndef) {
                     array_val = nullptr;
                     abs_offset = 0;
@@ -26746,6 +26745,113 @@ done_with_return_type:
             return ira->codegen->invalid_inst_gen;
         }
 
+        // check sentinel when target is comptime-known
+        {
+            if (!sentinel_val)
+                goto exit_check_sentinel;
+
+            switch (ptr_ptr->value->data.x_ptr.mut) {
+                case ConstPtrMutComptimeConst:
+                case ConstPtrMutComptimeVar:
+                    break;
+                case ConstPtrMutRuntimeVar:
+                case ConstPtrMutInfer:
+                    goto exit_check_sentinel;
+            }
+
+            // prepare check parameters
+            ZigValue *target = const_ptr_pointee(ira, ira->codegen, ptr_ptr->value, instruction->base.base.source_node);
+            if (target == nullptr)
+                return ira->codegen->invalid_inst_gen;
+
+            uint64_t target_len = 0;
+            ZigValue *target_sentinel = nullptr;
+            ZigValue *target_elements = nullptr;
+
+            for (;;) {
+                if (target->type->id == ZigTypeIdArray) {
+                    // handle `[N]T`
+                    target_len = target->type->data.array.len;
+                    target_sentinel = target->type->data.array.sentinel;
+                    target_elements = target->data.x_array.data.s_none.elements;
+                    break;
+                } else if (target->type->id == ZigTypeIdPointer && target->type->data.pointer.child_type->id == ZigTypeIdArray) {
+                    // handle `*[N]T`
+                    target = const_ptr_pointee(ira, ira->codegen, target, instruction->base.base.source_node);
+                    if (target == nullptr)
+                        return ira->codegen->invalid_inst_gen;
+                    assert(target->type->id == ZigTypeIdArray);
+                    continue;
+                } else if (target->type->id == ZigTypeIdPointer) {
+                    // handle `[*]T`
+                    // handle `[*c]T`
+                    switch (target->data.x_ptr.special) {
+                        case ConstPtrSpecialInvalid:
+                        case ConstPtrSpecialDiscard:
+                            zig_unreachable();
+                        case ConstPtrSpecialRef:
+                            target = target->data.x_ptr.data.ref.pointee;
+                            assert(target->type->id == ZigTypeIdArray);
+                            continue;
+                        case ConstPtrSpecialBaseArray:
+                        case ConstPtrSpecialSubArray:
+                            target = target->data.x_ptr.data.base_array.array_val;
+                            assert(target->type->id == ZigTypeIdArray);
+                            continue;
+                        case ConstPtrSpecialBaseStruct:
+                            zig_panic("TODO slice const inner struct");
+                        case ConstPtrSpecialBaseErrorUnionCode:
+                            zig_panic("TODO slice const inner error union code");
+                        case ConstPtrSpecialBaseErrorUnionPayload:
+                            zig_panic("TODO slice const inner error union payload");
+                        case ConstPtrSpecialBaseOptionalPayload:
+                            zig_panic("TODO slice const inner optional payload");
+                        case ConstPtrSpecialHardCodedAddr:
+                            // skip check
+                            goto exit_check_sentinel;
+                        case ConstPtrSpecialFunction:
+                            zig_panic("TODO slice of ptr cast from function");
+                        case ConstPtrSpecialNull:
+                            zig_panic("TODO slice of null ptr");
+                    }
+                    break;
+                } else if (is_slice(target->type)) {
+                    // handle `[]T`
+                    target = target->data.x_struct.fields[slice_ptr_index];
+                    assert(target->type->id == ZigTypeIdPointer);
+                    continue;
+                }
+
+                zig_unreachable();
+            }
+
+            // perform check
+            if (target_sentinel == nullptr) {
+                if (end_scalar >= target_len) {
+                    ir_add_error(ira, &instruction->base.base, buf_sprintf("slice-sentinel is out of bounds"));
+                    return ira->codegen->invalid_inst_gen;
+                }
+                if (!const_values_equal(ira->codegen, sentinel_val, &target_elements[end_scalar])) {
+                    ir_add_error(ira, &instruction->base.base, buf_sprintf("slice-sentinel does not match memory at target index"));
+                    return ira->codegen->invalid_inst_gen;
+                }
+            } else {
+                assert(end_scalar <= target_len);
+                if (end_scalar == target_len) {
+                    if (!const_values_equal(ira->codegen, sentinel_val, target_sentinel)) {
+                        ir_add_error(ira, &instruction->base.base, buf_sprintf("slice-sentinel does not match target-sentinel"));
+                        return ira->codegen->invalid_inst_gen;
+                    }
+                } else {
+                    if (!const_values_equal(ira->codegen, sentinel_val, &target_elements[end_scalar])) {
+                        ir_add_error(ira, &instruction->base.base, buf_sprintf("slice-sentinel does not match memory at target index"));
+                        return ira->codegen->invalid_inst_gen;
+                    }
+                }
+            }
+        }
+        exit_check_sentinel:
+
         IrInstGen *result = ir_const(ira, &instruction->base.base, return_type);
 
         ZigValue *ptr_val;
test/stage1/behavior/slice_sentinel_comptime.zig
@@ -0,0 +1,199 @@
+test "comptime slice-sentinel in bounds (unterminated)" {
+    // array
+    comptime {
+        var target = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        const slice = target[0..3 :'d'];
+    }
+
+    // ptr_array
+    comptime {
+        var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        var target = &buf;
+        const slice = target[0..3 :'d'];
+    }
+
+    // vector_ConstPtrSpecialBaseArray
+    comptime {
+        var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        var target: [*]u8 = &buf;
+        const slice = target[0..3 :'d'];
+    }
+
+    // vector_ConstPtrSpecialRef
+    comptime {
+        var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        var target: [*]u8 = @ptrCast([*]u8, &buf);
+        const slice = target[0..3 :'d'];
+    }
+
+    // cvector_ConstPtrSpecialBaseArray
+    comptime {
+        var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        var target: [*c]u8 = &buf;
+        const slice = target[0..3 :'d'];
+    }
+
+    // cvector_ConstPtrSpecialRef
+    comptime {
+        var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        var target: [*c]u8 = @ptrCast([*c]u8, &buf);
+        const slice = target[0..3 :'d'];
+    }
+
+    // slice
+    comptime {
+        var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        var target: []u8 = &buf;
+        const slice = target[0..3 :'d'];
+    }
+}
+
+test "comptime slice-sentinel in bounds (end,unterminated)" {
+    // array
+    comptime {
+        var target = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{0xff} ** 10;
+        const slice = target[0..13 :0xff];
+    }
+
+    // ptr_array
+    comptime {
+        var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{0xff} ** 10;
+        var target = &buf;
+        const slice = target[0..13 :0xff];
+    }
+
+    // vector_ConstPtrSpecialBaseArray
+    comptime {
+        var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{0xff} ** 10;
+        var target: [*]u8 = &buf;
+        const slice = target[0..13 :0xff];
+    }
+
+    // vector_ConstPtrSpecialRef
+    comptime {
+        var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{0xff} ** 10;
+        var target: [*]u8 = @ptrCast([*]u8, &buf);
+        const slice = target[0..13 :0xff];
+    }
+
+    // cvector_ConstPtrSpecialBaseArray
+    comptime {
+        var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{0xff} ** 10;
+        var target: [*c]u8 = &buf;
+        const slice = target[0..13 :0xff];
+    }
+
+    // cvector_ConstPtrSpecialRef
+    comptime {
+        var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{0xff} ** 10;
+        var target: [*c]u8 = @ptrCast([*c]u8, &buf);
+        const slice = target[0..13 :0xff];
+    }
+
+    // slice
+    comptime {
+        var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{0xff} ** 10;
+        var target: []u8 = &buf;
+        const slice = target[0..13 :0xff];
+    }
+}
+
+test "comptime slice-sentinel in bounds (terminated)" {
+    // array
+    comptime {
+        var target = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        const slice = target[0..3 :'d'];
+    }
+
+    // ptr_array
+    comptime {
+        var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        var target = &buf;
+        const slice = target[0..3 :'d'];
+    }
+
+    // vector_ConstPtrSpecialBaseArray
+    comptime {
+        var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        var target: [*]u8 = &buf;
+        const slice = target[0..3 :'d'];
+    }
+
+    // vector_ConstPtrSpecialRef
+    comptime {
+        var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        var target: [*]u8 = @ptrCast([*]u8, &buf);
+        const slice = target[0..3 :'d'];
+    }
+
+    // cvector_ConstPtrSpecialBaseArray
+    comptime {
+        var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        var target: [*c]u8 = &buf;
+        const slice = target[0..3 :'d'];
+    }
+
+    // cvector_ConstPtrSpecialRef
+    comptime {
+        var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        var target: [*c]u8 = @ptrCast([*c]u8, &buf);
+        const slice = target[0..3 :'d'];
+    }
+
+    // slice
+    comptime {
+        var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        var target: []u8 = &buf;
+        const slice = target[0..3 :'d'];
+    }
+}
+
+test "comptime slice-sentinel in bounds (on target sentinel)" {
+    // array
+    comptime {
+        var target = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        const slice = target[0..14 :0];
+    }
+
+    // ptr_array
+    comptime {
+        var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        var target = &buf;
+        const slice = target[0..14 :0];
+    }
+
+    // vector_ConstPtrSpecialBaseArray
+    comptime {
+        var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        var target: [*]u8 = &buf;
+        const slice = target[0..14 :0];
+    }
+
+    // vector_ConstPtrSpecialRef
+    comptime {
+        var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        var target: [*]u8 = @ptrCast([*]u8, &buf);
+        const slice = target[0..14 :0];
+    }
+
+    // cvector_ConstPtrSpecialBaseArray
+    comptime {
+        var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        var target: [*c]u8 = &buf;
+        const slice = target[0..14 :0];
+    }
+
+    // cvector_ConstPtrSpecialRef
+    comptime {
+        var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        var target: [*c]u8 = @ptrCast([*c]u8, &buf);
+        const slice = target[0..14 :0];
+    }
+
+    // slice
+    comptime {
+        var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        var target: []u8 = &buf;
+        const slice = target[0..14 :0];
+    }
+}
test/stage1/behavior.zig
@@ -96,6 +96,7 @@ comptime {
     _ = @import("behavior/shuffle.zig");
     _ = @import("behavior/sizeof_and_typeof.zig");
     _ = @import("behavior/slice.zig");
+    _ = @import("behavior/slice_sentinel_comptime.zig");
     _ = @import("behavior/struct.zig");
     _ = @import("behavior/struct_contains_null_ptr_itself.zig");
     _ = @import("behavior/struct_contains_slice_of_itself.zig");
test/compile_errors.zig
@@ -6857,4 +6857,299 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
         "tmp.zig:7:32: error: destination type 'u16' has size 2 but source type '[]u8' has size 16",
         "tmp.zig:7:37: note: referenced here",
     });
+
+    cases.add("comptime slice-sentinel is out of bounds (unterminated)",
+        \\export fn foo_array() void {
+        \\    comptime {
+        \\        var target = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        \\        const slice = target[0..14 :0];
+        \\    }
+        \\}
+        \\export fn foo_ptr_array() void {
+        \\    comptime {
+        \\        var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        \\        var target = &buf;
+        \\        const slice = target[0..14 :0];
+        \\    }
+        \\}
+        \\export fn foo_vector_ConstPtrSpecialBaseArray() void {
+        \\    comptime {
+        \\        var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        \\        var target: [*]u8 = &buf;
+        \\        const slice = target[0..14 :0];
+        \\    }
+        \\}
+        \\export fn foo_vector_ConstPtrSpecialRef() void {
+        \\    comptime {
+        \\        var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        \\        var target: [*]u8 = @ptrCast([*]u8, &buf);
+        \\        const slice = target[0..14 :0];
+        \\    }
+        \\}
+        \\export fn foo_cvector_ConstPtrSpecialBaseArray() void {
+        \\    comptime {
+        \\        var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        \\        var target: [*c]u8 = &buf;
+        \\        const slice = target[0..14 :0];
+        \\    }
+        \\}
+        \\export fn foo_cvector_ConstPtrSpecialRef() void {
+        \\    comptime {
+        \\        var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        \\        var target: [*c]u8 = @ptrCast([*c]u8, &buf);
+        \\        const slice = target[0..14 :0];
+        \\    }
+        \\}
+        \\export fn foo_slice() void {
+        \\    comptime {
+        \\        var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        \\        var target: []u8 = &buf;
+        \\        const slice = target[0..14 :0];
+        \\    }
+        \\}
+    , &[_][]const u8{
+        ":4:29: error: slice-sentinel is out of bounds",
+        ":11:29: error: slice-sentinel is out of bounds",
+        ":18:29: error: slice-sentinel is out of bounds",
+        ":25:29: error: slice-sentinel is out of bounds",
+        ":32:29: error: slice-sentinel is out of bounds",
+        ":39:29: error: slice-sentinel is out of bounds",
+        ":46:29: error: slice-sentinel is out of bounds",
+    });
+
+    cases.add("comptime slice-sentinel is out of bounds (terminated)",
+        \\export fn foo_array() void {
+        \\    comptime {
+        \\        var target = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        \\        const slice = target[0..15 :1];
+        \\    }
+        \\}
+        \\export fn foo_ptr_array() void {
+        \\    comptime {
+        \\        var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        \\        var target = &buf;
+        \\        const slice = target[0..15 :0];
+        \\    }
+        \\}
+        \\export fn foo_vector_ConstPtrSpecialBaseArray() void {
+        \\    comptime {
+        \\        var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        \\        var target: [*]u8 = &buf;
+        \\        const slice = target[0..15 :0];
+        \\    }
+        \\}
+        \\export fn foo_vector_ConstPtrSpecialRef() void {
+        \\    comptime {
+        \\        var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        \\        var target: [*]u8 = @ptrCast([*]u8, &buf);
+        \\        const slice = target[0..15 :0];
+        \\    }
+        \\}
+        \\export fn foo_cvector_ConstPtrSpecialBaseArray() void {
+        \\    comptime {
+        \\        var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        \\        var target: [*c]u8 = &buf;
+        \\        const slice = target[0..15 :0];
+        \\    }
+        \\}
+        \\export fn foo_cvector_ConstPtrSpecialRef() void {
+        \\    comptime {
+        \\        var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        \\        var target: [*c]u8 = @ptrCast([*c]u8, &buf);
+        \\        const slice = target[0..15 :0];
+        \\    }
+        \\}
+        \\export fn foo_slice() void {
+        \\    comptime {
+        \\        var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        \\        var target: []u8 = &buf;
+        \\        const slice = target[0..15 :0];
+        \\    }
+        \\}
+    , &[_][]const u8{
+        ":4:29: error: out of bounds slice",
+        ":11:29: error: out of bounds slice",
+        ":18:29: error: out of bounds slice",
+        ":25:29: error: out of bounds slice",
+        ":32:29: error: out of bounds slice",
+        ":39:29: error: out of bounds slice",
+        ":46:29: error: out of bounds slice",
+    });
+
+    cases.add("comptime slice-sentinel does not match memory at target index (unterminated)",
+        \\export fn foo_array() void {
+        \\    comptime {
+        \\        var target = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        \\        const slice = target[0..3 :0];
+        \\    }
+        \\}
+        \\export fn foo_ptr_array() void {
+        \\    comptime {
+        \\        var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        \\        var target = &buf;
+        \\        const slice = target[0..3 :0];
+        \\    }
+        \\}
+        \\export fn foo_vector_ConstPtrSpecialBaseArray() void {
+        \\    comptime {
+        \\        var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        \\        var target: [*]u8 = &buf;
+        \\        const slice = target[0..3 :0];
+        \\    }
+        \\}
+        \\export fn foo_vector_ConstPtrSpecialRef() void {
+        \\    comptime {
+        \\        var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        \\        var target: [*]u8 = @ptrCast([*]u8, &buf);
+        \\        const slice = target[0..3 :0];
+        \\    }
+        \\}
+        \\export fn foo_cvector_ConstPtrSpecialBaseArray() void {
+        \\    comptime {
+        \\        var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        \\        var target: [*c]u8 = &buf;
+        \\        const slice = target[0..3 :0];
+        \\    }
+        \\}
+        \\export fn foo_cvector_ConstPtrSpecialRef() void {
+        \\    comptime {
+        \\        var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        \\        var target: [*c]u8 = @ptrCast([*c]u8, &buf);
+        \\        const slice = target[0..3 :0];
+        \\    }
+        \\}
+        \\export fn foo_slice() void {
+        \\    comptime {
+        \\        var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        \\        var target: []u8 = &buf;
+        \\        const slice = target[0..3 :0];
+        \\    }
+        \\}
+    , &[_][]const u8{
+        ":4:29: error: slice-sentinel does not match memory at target index",
+        ":11:29: error: slice-sentinel does not match memory at target index",
+        ":18:29: error: slice-sentinel does not match memory at target index",
+        ":25:29: error: slice-sentinel does not match memory at target index",
+        ":32:29: error: slice-sentinel does not match memory at target index",
+        ":39:29: error: slice-sentinel does not match memory at target index",
+        ":46:29: error: slice-sentinel does not match memory at target index",
+    });
+
+    cases.add("comptime slice-sentinel does not match memory at target index (terminated)",
+        \\export fn foo_array() void {
+        \\    comptime {
+        \\        var target = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        \\        const slice = target[0..3 :0];
+        \\    }
+        \\}
+        \\export fn foo_ptr_array() void {
+        \\    comptime {
+        \\        var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        \\        var target = &buf;
+        \\        const slice = target[0..3 :0];
+        \\    }
+        \\}
+        \\export fn foo_vector_ConstPtrSpecialBaseArray() void {
+        \\    comptime {
+        \\        var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        \\        var target: [*]u8 = &buf;
+        \\        const slice = target[0..3 :0];
+        \\    }
+        \\}
+        \\export fn foo_vector_ConstPtrSpecialRef() void {
+        \\    comptime {
+        \\        var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        \\        var target: [*]u8 = @ptrCast([*]u8, &buf);
+        \\        const slice = target[0..3 :0];
+        \\    }
+        \\}
+        \\export fn foo_cvector_ConstPtrSpecialBaseArray() void {
+        \\    comptime {
+        \\        var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        \\        var target: [*c]u8 = &buf;
+        \\        const slice = target[0..3 :0];
+        \\    }
+        \\}
+        \\export fn foo_cvector_ConstPtrSpecialRef() void {
+        \\    comptime {
+        \\        var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        \\        var target: [*c]u8 = @ptrCast([*c]u8, &buf);
+        \\        const slice = target[0..3 :0];
+        \\    }
+        \\}
+        \\export fn foo_slice() void {
+        \\    comptime {
+        \\        var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        \\        var target: []u8 = &buf;
+        \\        const slice = target[0..3 :0];
+        \\    }
+        \\}
+    , &[_][]const u8{
+        ":4:29: error: slice-sentinel does not match memory at target index",
+        ":11:29: error: slice-sentinel does not match memory at target index",
+        ":18:29: error: slice-sentinel does not match memory at target index",
+        ":25:29: error: slice-sentinel does not match memory at target index",
+        ":32:29: error: slice-sentinel does not match memory at target index",
+        ":39:29: error: slice-sentinel does not match memory at target index",
+        ":46:29: error: slice-sentinel does not match memory at target index",
+    });
+
+    cases.add("comptime slice-sentinel does not match target-sentinel",
+        \\export fn foo_array() void {
+        \\    comptime {
+        \\        var target = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        \\        const slice = target[0..14 :255];
+        \\    }
+        \\}
+        \\export fn foo_ptr_array() void {
+        \\    comptime {
+        \\        var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        \\        var target = &buf;
+        \\        const slice = target[0..14 :255];
+        \\    }
+        \\}
+        \\export fn foo_vector_ConstPtrSpecialBaseArray() void {
+        \\    comptime {
+        \\        var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        \\        var target: [*]u8 = &buf;
+        \\        const slice = target[0..14 :255];
+        \\    }
+        \\}
+        \\export fn foo_vector_ConstPtrSpecialRef() void {
+        \\    comptime {
+        \\        var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        \\        var target: [*]u8 = @ptrCast([*]u8, &buf);
+        \\        const slice = target[0..14 :255];
+        \\    }
+        \\}
+        \\export fn foo_cvector_ConstPtrSpecialBaseArray() void {
+        \\    comptime {
+        \\        var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        \\        var target: [*c]u8 = &buf;
+        \\        const slice = target[0..14 :255];
+        \\    }
+        \\}
+        \\export fn foo_cvector_ConstPtrSpecialRef() void {
+        \\    comptime {
+        \\        var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        \\        var target: [*c]u8 = @ptrCast([*c]u8, &buf);
+        \\        const slice = target[0..14 :255];
+        \\    }
+        \\}
+        \\export fn foo_slice() void {
+        \\    comptime {
+        \\        var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
+        \\        var target: []u8 = &buf;
+        \\        const slice = target[0..14 :255];
+        \\    }
+        \\}
+    , &[_][]const u8{
+        ":4:29: error: slice-sentinel does not match target-sentinel",
+        ":11:29: error: slice-sentinel does not match target-sentinel",
+        ":18:29: error: slice-sentinel does not match target-sentinel",
+        ":25:29: error: slice-sentinel does not match target-sentinel",
+        ":32:29: error: slice-sentinel does not match target-sentinel",
+        ":39:29: error: slice-sentinel does not match target-sentinel",
+        ":46:29: error: slice-sentinel does not match target-sentinel",
+    });
 }