diff --git a/src/Sema.zig b/src/Sema.zig index fc5a17acce..bf0aacabe5 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -22779,7 +22779,11 @@ fn ptrCastFull( } const ptr = if (src_info.flags.size == .Slice and dest_info.flags.size != .Slice) ptr: { - break :ptr try sema.analyzeSlicePtr(block, operand_src, operand, operand_ty); + if (operand_ty.zigTypeTag(mod) == .Optional) { + break :ptr try sema.analyzeOptionalSlicePtr(block, operand_src, operand, operand_ty); + } else { + break :ptr try sema.analyzeSlicePtr(block, operand_src, operand, operand_ty); + } } else operand; const dest_ptr_ty = if (dest_info.flags.size == .Slice and src_info.flags.size != .Slice) blk: { @@ -32564,6 +32568,32 @@ fn analyzeSlicePtr( return block.addTyOp(.slice_ptr, result_ty, slice); } +fn analyzeOptionalSlicePtr( + sema: *Sema, + block: *Block, + opt_slice_src: LazySrcLoc, + opt_slice: Air.Inst.Ref, + opt_slice_ty: Type, +) CompileError!Air.Inst.Ref { + const mod = sema.mod; + const result_ty = opt_slice_ty.optionalChild(mod).slicePtrFieldType(mod); + + if (try sema.resolveValue(opt_slice)) |opt_val| { + if (opt_val.isUndef(mod)) return mod.undefRef(result_ty); + const slice_ptr: InternPool.Index = if (opt_val.optionalValue(mod)) |val| + val.slicePtr(mod).toIntern() + else + .null_value; + + return Air.internedToRef(slice_ptr); + } + + try sema.requireRuntimeBlock(block, opt_slice_src, null); + + const slice = try block.addTyOp(.optional_payload, opt_slice_ty, opt_slice); + return block.addTyOp(.slice_ptr, result_ty, slice); +} + fn analyzeSliceLen( sema: *Sema, block: *Block, diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig index 19e5ebb3c1..e35f04696a 100644 --- a/test/behavior/cast.zig +++ b/test/behavior/cast.zig @@ -1550,6 +1550,32 @@ test "optional pointer coerced to optional allowzero pointer" { try expect(@intFromPtr(q.?) == 4); } +test "optional slice coerced to allowzero many pointer" { + const a: ?[]const u32 = null; + const b: [*]allowzero const u8 = @ptrCast(a); + const c = @intFromPtr(b); + try std.testing.expect(c == 0); +} + +test "optional slice passed as parameter coerced to allowzero many pointer" { + const ns = struct { + const Color = struct { + r: u8, + g: u8, + b: u8, + a: u8, + }; + + fn foo(pixels: ?[]const Color) !void { + const data: [*]allowzero const u8 = @ptrCast(pixels); + const int = @intFromPtr(data); + try std.testing.expect(int == 0); + } + }; + + try ns.foo(null); +} + test "single item pointer to pointer to array to slice" { var x: i32 = 1234; try expect(@as([]const i32, @as(*[1]i32, &x))[0] == 1234);