authorgravatar for garrisonhh@pm.mearrisonhh <garrisonhh@pm.me> 2024-03-05 13:55:21-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-03-05 18:55:21+00:00
log1e67f5021159ed1d9888cf2d0b9f04ef73222f7d
tree558cba121b5bb9ea207c458a7c1a8e0ae3f8f36c
parent7d41a5cbcf88e50747dd6d70d1d7dfb846e75efb
signaturebadge-check Signed by PGP key B5690EEEBB952194

Sema: fix compiler crash `@ptrCast`ing optional slice


2 files changed, 57 insertions(+), 1 deletions(-)

src/Sema.zig+31-1
...@@ -22779,7 +22779,11 @@ fn ptrCastFull(...@@ -22779,7 +22779,11 @@ fn ptrCastFull(
22779 }22779 }
2278022780
22781 const ptr = if (src_info.flags.size == .Slice and dest_info.flags.size != .Slice) ptr: {22781 const ptr = if (src_info.flags.size == .Slice and dest_info.flags.size != .Slice) ptr: {
22782 break :ptr try sema.analyzeSlicePtr(block, operand_src, operand, operand_ty);22782 if (operand_ty.zigTypeTag(mod) == .Optional) {
22783 break :ptr try sema.analyzeOptionalSlicePtr(block, operand_src, operand, operand_ty);
22784 } else {
22785 break :ptr try sema.analyzeSlicePtr(block, operand_src, operand, operand_ty);
22786 }
22783 } else operand;22787 } else operand;
2278422788
22785 const dest_ptr_ty = if (dest_info.flags.size == .Slice and src_info.flags.size != .Slice) blk: {22789 const dest_ptr_ty = if (dest_info.flags.size == .Slice and src_info.flags.size != .Slice) blk: {
...@@ -32564,6 +32568,32 @@ fn analyzeSlicePtr(...@@ -32564,6 +32568,32 @@ fn analyzeSlicePtr(
32564 return block.addTyOp(.slice_ptr, result_ty, slice);32568 return block.addTyOp(.slice_ptr, result_ty, slice);
32565}32569}
3256632570
32571fn analyzeOptionalSlicePtr(
32572 sema: *Sema,
32573 block: *Block,
32574 opt_slice_src: LazySrcLoc,
32575 opt_slice: Air.Inst.Ref,
32576 opt_slice_ty: Type,
32577) CompileError!Air.Inst.Ref {
32578 const mod = sema.mod;
32579 const result_ty = opt_slice_ty.optionalChild(mod).slicePtrFieldType(mod);
32580
32581 if (try sema.resolveValue(opt_slice)) |opt_val| {
32582 if (opt_val.isUndef(mod)) return mod.undefRef(result_ty);
32583 const slice_ptr: InternPool.Index = if (opt_val.optionalValue(mod)) |val|
32584 val.slicePtr(mod).toIntern()
32585 else
32586 .null_value;
32587
32588 return Air.internedToRef(slice_ptr);
32589 }
32590
32591 try sema.requireRuntimeBlock(block, opt_slice_src, null);
32592
32593 const slice = try block.addTyOp(.optional_payload, opt_slice_ty, opt_slice);
32594 return block.addTyOp(.slice_ptr, result_ty, slice);
32595}
32596
32567fn analyzeSliceLen(32597fn analyzeSliceLen(
32568 sema: *Sema,32598 sema: *Sema,
32569 block: *Block,32599 block: *Block,
test/behavior/cast.zig+26
...@@ -1550,6 +1550,32 @@ test "optional pointer coerced to optional allowzero pointer" {...@@ -1550,6 +1550,32 @@ test "optional pointer coerced to optional allowzero pointer" {
1550 try expect(@intFromPtr(q.?) == 4);1550 try expect(@intFromPtr(q.?) == 4);
1551}1551}
15521552
1553test "optional slice coerced to allowzero many pointer" {
1554 const a: ?[]const u32 = null;
1555 const b: [*]allowzero const u8 = @ptrCast(a);
1556 const c = @intFromPtr(b);
1557 try std.testing.expect(c == 0);
1558}
1559
1560test "optional slice passed as parameter coerced to allowzero many pointer" {
1561 const ns = struct {
1562 const Color = struct {
1563 r: u8,
1564 g: u8,
1565 b: u8,
1566 a: u8,
1567 };
1568
1569 fn foo(pixels: ?[]const Color) !void {
1570 const data: [*]allowzero const u8 = @ptrCast(pixels);
1571 const int = @intFromPtr(data);
1572 try std.testing.expect(int == 0);
1573 }
1574 };
1575
1576 try ns.foo(null);
1577}
1578
1553test "single item pointer to pointer to array to slice" {1579test "single item pointer to pointer to array to slice" {
1554 var x: i32 = 1234;1580 var x: i32 = 1234;
1555 try expect(@as([]const i32, @as(*[1]i32, &x))[0] == 1234);1581 try expect(@as([]const i32, @as(*[1]i32, &x))[0] == 1234);