split @qualCast into @constCast and @volatileCast

This commit is contained in:
Veikka Tuominen 2023-02-13 16:19:17 +02:00
parent 4e6f21e2cb
commit 7199d7c777
18 changed files with 127 additions and 88 deletions

View File

@ -8129,6 +8129,13 @@ test "main" {
{#code_end#}
{#header_close#}
{#header_open|@constCast#}
<pre>{#syntax#}@constCast(value: anytype) DestType{#endsyntax#}</pre>
<p>
Remove {#syntax#}const{#endsyntax#} qualifier from a pointer.
</p>
{#header_close#}
{#header_open|@ctz#}
<pre>{#syntax#}@ctz(operand: anytype){#endsyntax#}</pre>
<p>{#syntax#}@TypeOf(operand){#endsyntax#} must be an integer type or an integer vector type.</p>
@ -8814,7 +8821,8 @@ pub const PrefetchOptions = struct {
{#syntax#}@ptrCast{#endsyntax#} cannot be used for:
</p>
<ul>
<li>Removing {#syntax#}const{#endsyntax#} or {#syntax#}volatile{#endsyntax#} qualifier, use {#link|@qualCast#}.</li>
<li>Removing {#syntax#}const{#endsyntax#} qualifier, use {#link|@constCast#}.</li>
<li>Removing {#syntax#}volatile{#endsyntax#} qualifier, use {#link|@volatileCast#}.</li>
<li>Changing pointer address space, use {#link|@addrSpaceCast#}.</li>
<li>Increasing pointer alignment, use {#link|@alignCast#}.</li>
<li>Casting a non-slice pointer to a slice, use slicing syntax {#syntax#}ptr[start..end]{#endsyntax#}.</li>
@ -8831,13 +8839,6 @@ pub const PrefetchOptions = struct {
{#header_close#}
{#header_open|@qualCast#}
<pre>{#syntax#}@qualCast(comptime DestType: type, value: anytype) DestType{#endsyntax#}</pre>
<p>
Remove {#syntax#}const{#endsyntax#} or {#syntax#}volatile{#endsyntax#} qualifier from a pointer.
</p>
{#header_close#}
{#header_open|@rem#}
<pre>{#syntax#}@rem(numerator: T, denominator: T) T{#endsyntax#}</pre>
<p>
@ -9525,6 +9526,13 @@ fn foo(comptime T: type, ptr: *T) T {
<pre>{#syntax#}@Vector(len: comptime_int, Element: type) type{#endsyntax#}</pre>
<p>Creates {#link|Vectors#}.</p>
{#header_close#}
{#header_open|@volatileCast#}
<pre>{#syntax#}@volatileCast(value: anytype) DestType{#endsyntax#}</pre>
<p>
Remove {#syntax#}volatile{#endsyntax#} qualifier from a pointer.
</p>
{#header_close#}
{#header_close#}
{#header_open|Build Mode#}

View File

@ -1354,8 +1354,12 @@ const NAV_MODES = {
payloadHtml += "ptrCast";
break;
}
case "qual_cast": {
payloadHtml += "qualCast";
case "const_cast": {
payloadHtml += "constCast";
break;
}
case "volatile_cast": {
payloadHtml += "volatileCast";
break;
}
case "truncate": {

View File

@ -1164,7 +1164,7 @@ fn windowsCreateProcessPathExt(
var app_name_unicode_string = windows.UNICODE_STRING{
.Length = app_name_len_bytes,
.MaximumLength = app_name_len_bytes,
.Buffer = @qualCast([*:0]u16, app_name_wildcard.ptr),
.Buffer = @constCast(app_name_wildcard.ptr),
};
const rc = windows.ntdll.NtQueryDirectoryFile(
dir.fd,
@ -1261,7 +1261,7 @@ fn windowsCreateProcessPathExt(
var app_name_unicode_string = windows.UNICODE_STRING{
.Length = app_name_len_bytes,
.MaximumLength = app_name_len_bytes,
.Buffer = @qualCast([*:0]u16, app_name_appended.ptr),
.Buffer = @constCast(app_name_appended.ptr),
};
// Re-use the directory handle but this time we call with the appended app name

View File

@ -1763,7 +1763,7 @@ pub const Dir = struct {
var nt_name = w.UNICODE_STRING{
.Length = path_len_bytes,
.MaximumLength = path_len_bytes,
.Buffer = @qualCast([*:0]u16, sub_path_w),
.Buffer = @constCast(sub_path_w),
};
var attr = w.OBJECT_ATTRIBUTES{
.Length = @sizeOf(w.OBJECT_ATTRIBUTES),

View File

@ -112,7 +112,7 @@ pub fn destroy(self: Allocator, ptr: anytype) void {
const info = @typeInfo(@TypeOf(ptr)).Pointer;
const T = info.child;
if (@sizeOf(T) == 0) return;
const non_const_ptr = @intToPtr([*]u8, @ptrToInt(ptr));
const non_const_ptr = @ptrCast([*]u8, @constCast(ptr));
self.rawFree(non_const_ptr[0..@sizeOf(T)], math.log2(info.alignment), @returnAddress());
}
@ -297,7 +297,7 @@ pub fn free(self: Allocator, memory: anytype) void {
const bytes = mem.sliceAsBytes(memory);
const bytes_len = bytes.len + if (Slice.sentinel != null) @sizeOf(Slice.child) else 0;
if (bytes_len == 0) return;
const non_const_ptr = @intToPtr([*]u8, @ptrToInt(bytes.ptr));
const non_const_ptr = @constCast(bytes.ptr);
// TODO: https://github.com/ziglang/zig/issues/4298
@memset(non_const_ptr, undefined, bytes_len);
self.rawFree(non_const_ptr[0..bytes_len], log2a(Slice.alignment), @returnAddress());

View File

@ -4513,7 +4513,7 @@ pub fn faccessatW(dirfd: fd_t, sub_path_w: [*:0]const u16, mode: u32, flags: u32
var nt_name = windows.UNICODE_STRING{
.Length = path_len_bytes,
.MaximumLength = path_len_bytes,
.Buffer = @qualCast([*:0]u16, sub_path_w),
.Buffer = @constCast(sub_path_w),
};
var attr = windows.OBJECT_ATTRIBUTES{
.Length = @sizeOf(windows.OBJECT_ATTRIBUTES),

View File

@ -85,7 +85,7 @@ pub fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!HAN
var nt_name = UNICODE_STRING{
.Length = path_len_bytes,
.MaximumLength = path_len_bytes,
.Buffer = @qualCast([*]u16, sub_path_w.ptr),
.Buffer = @constCast(sub_path_w.ptr),
};
var attr = OBJECT_ATTRIBUTES{
.Length = @sizeOf(OBJECT_ATTRIBUTES),
@ -634,7 +634,7 @@ pub fn SetCurrentDirectory(path_name: []const u16) SetCurrentDirectoryError!void
var nt_name = UNICODE_STRING{
.Length = path_len_bytes,
.MaximumLength = path_len_bytes,
.Buffer = @qualCast([*]u16, path_name.ptr),
.Buffer = @constCast(path_name.ptr),
};
const rc = ntdll.RtlSetCurrentDirectory_U(&nt_name);
@ -766,7 +766,7 @@ pub fn ReadLink(dir: ?HANDLE, sub_path_w: []const u16, out_buffer: []u8) ReadLin
var nt_name = UNICODE_STRING{
.Length = path_len_bytes,
.MaximumLength = path_len_bytes,
.Buffer = @qualCast([*]u16, sub_path_w.ptr),
.Buffer = @constCast(sub_path_w.ptr),
};
var attr = OBJECT_ATTRIBUTES{
.Length = @sizeOf(OBJECT_ATTRIBUTES),
@ -876,7 +876,7 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil
.Length = path_len_bytes,
.MaximumLength = path_len_bytes,
// The Windows API makes this mutable, but it will not mutate here.
.Buffer = @qualCast([*]u16, sub_path_w.ptr),
.Buffer = @constCast(sub_path_w.ptr),
};
if (sub_path_w[0] == '.' and sub_path_w[1] == 0) {
@ -1414,7 +1414,7 @@ pub fn sendmsg(
}
pub fn sendto(s: ws2_32.SOCKET, buf: [*]const u8, len: usize, flags: u32, to: ?*const ws2_32.sockaddr, to_len: ws2_32.socklen_t) i32 {
var buffer = ws2_32.WSABUF{ .len = @truncate(u31, len), .buf = @qualCast([*]u8, buf) };
var buffer = ws2_32.WSABUF{ .len = @truncate(u31, len), .buf = @constCast(buf) };
var bytes_send: DWORD = undefined;
if (ws2_32.WSASendTo(s, @ptrCast([*]ws2_32.WSABUF, &buffer), 1, &bytes_send, flags, to, @intCast(i32, to_len), null, null) == ws2_32.SOCKET_ERROR) {
return ws2_32.SOCKET_ERROR;
@ -1876,13 +1876,13 @@ pub fn eqlIgnoreCaseWTF16(a: []const u16, b: []const u16) bool {
const a_string = UNICODE_STRING{
.Length = a_bytes,
.MaximumLength = a_bytes,
.Buffer = @qualCast([*]u16, a.ptr),
.Buffer = @constCast(a.ptr),
};
const b_bytes = @intCast(u16, b.len * 2);
const b_string = UNICODE_STRING{
.Length = b_bytes,
.MaximumLength = b_bytes,
.Buffer = @qualCast([*]u16, b.ptr),
.Buffer = @constCast(b.ptr),
};
return ntdll.RtlEqualUnicodeString(&a_string, &b_string, TRUE) == TRUE;
}

View File

@ -74,8 +74,10 @@ fn castPtr(comptime DestType: type, target: anytype) DestType {
const dest = ptrInfo(DestType);
const source = ptrInfo(@TypeOf(target));
if (source.is_const and !dest.is_const or source.is_volatile and !dest.is_volatile)
return @qualCast(DestType, target)
if (source.is_const and !dest.is_const)
return @constCast(target)
else if (source.is_volatile and !dest.is_volatile)
return @volatileCast(target)
else if (@typeInfo(dest.child) == .Opaque)
// dest.alignment would error out
return @ptrCast(DestType, target)

View File

@ -2531,7 +2531,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
.bit_size_of,
.typeof_log2_int_type,
.ptr_to_int,
.qual_cast,
.align_of,
.bool_to_int,
.embed_file,
@ -8039,7 +8038,6 @@ fn builtinCall(
.float_cast => return typeCast(gz, scope, ri, node, params[0], params[1], .float_cast),
.int_cast => return typeCast(gz, scope, ri, node, params[0], params[1], .int_cast),
.ptr_cast => return typeCast(gz, scope, ri, node, params[0], params[1], .ptr_cast),
.qual_cast => return typeCast(gz, scope, ri, node, params[0], params[1], .qual_cast),
.truncate => return typeCast(gz, scope, ri, node, params[0], params[1], .truncate),
// zig fmt: on
@ -8115,6 +8113,22 @@ fn builtinCall(
});
return rvalue(gz, ri, result, node);
},
.const_cast => {
const operand = try expr(gz, scope, .{ .rl = .none }, params[0]);
const result = try gz.addExtendedPayload(.const_cast, Zir.Inst.UnNode{
.node = gz.nodeIndexToRelative(node),
.operand = operand,
});
return rvalue(gz, ri, result, node);
},
.volatile_cast => {
const operand = try expr(gz, scope, .{ .rl = .none }, params[0]);
const result = try gz.addExtendedPayload(.volatile_cast, Zir.Inst.UnNode{
.node = gz.nodeIndexToRelative(node),
.operand = operand,
});
return rvalue(gz, ri, result, node);
},
// zig fmt: off
.has_decl => return hasDeclOrField(gz, scope, ri, node, params[0], params[1], .has_decl),

View File

@ -1400,7 +1400,6 @@ fn walkInstruction(
.float_cast,
.int_cast,
.ptr_cast,
.qual_cast,
.truncate,
.align_cast,
.has_decl,
@ -2983,6 +2982,8 @@ fn walkInstruction(
.error_to_int,
.int_to_error,
.reify,
.const_cast,
.volatile_cast,
=> {
const extra = file.zir.extraData(Zir.Inst.UnNode, extended.operand).data;
const bin_index = self.exprs.items.len;

View File

@ -28,6 +28,7 @@ pub const Tag = enum {
cmpxchg_weak,
compile_error,
compile_log,
const_cast,
ctz,
c_undef,
c_va_arg,
@ -75,7 +76,6 @@ pub const Tag = enum {
prefetch,
ptr_cast,
ptr_to_int,
qual_cast,
rem,
return_address,
select,
@ -116,6 +116,7 @@ pub const Tag = enum {
TypeOf,
union_init,
Vector,
volatile_cast,
};
pub const MemLocRequirement = enum {
@ -345,6 +346,13 @@ pub const list = list: {
.param_count = null,
},
},
.{
"@constCast",
.{
.tag = .const_cast,
.param_count = 1,
},
},
.{
"@ctz",
.{
@ -675,13 +683,6 @@ pub const list = list: {
.param_count = 1,
},
},
.{
"@qualCast",
.{
.tag = .qual_cast,
.param_count = 2,
},
},
.{
"@rem",
.{
@ -964,5 +965,12 @@ pub const list = list: {
.param_count = 2,
},
},
.{
"@volatileCast",
.{
.tag = .volatile_cast,
.param_count = 1,
},
},
});
};

View File

@ -1015,7 +1015,6 @@ fn analyzeBodyInner(
.float_cast => try sema.zirFloatCast(block, inst),
.int_cast => try sema.zirIntCast(block, inst),
.ptr_cast => try sema.zirPtrCast(block, inst),
.qual_cast => try sema.zirQualCast(block, inst),
.truncate => try sema.zirTruncate(block, inst),
.align_cast => try sema.zirAlignCast(block, inst),
.has_decl => try sema.zirHasDecl(block, inst),
@ -1147,6 +1146,8 @@ fn analyzeBodyInner(
.c_va_copy => try sema.zirCVaCopy( block, extended),
.c_va_end => try sema.zirCVaEnd( block, extended),
.c_va_start => try sema.zirCVaStart( block, extended),
.const_cast, => try sema.zirConstCast( block, extended),
.volatile_cast, => try sema.zirVolatileCast( block, extended),
// zig fmt: on
.fence => {
@ -19545,7 +19546,7 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
const msg = try sema.errMsg(block, src, "cast discards const qualifier", .{});
errdefer msg.destroy(sema.gpa);
try sema.errNote(block, src, msg, "consider using '@qualCast'", .{});
try sema.errNote(block, src, msg, "consider using '@constCast'", .{});
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
@ -19555,7 +19556,7 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
const msg = try sema.errMsg(block, src, "cast discards volatile qualifier", .{});
errdefer msg.destroy(sema.gpa);
try sema.errNote(block, src, msg, "consider using '@qualCast'", .{});
try sema.errNote(block, src, msg, "consider using '@volatileCast'", .{});
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
@ -19660,41 +19661,38 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
return block.addBitCast(aligned_dest_ty, ptr);
}
fn zirQualCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const src = inst_data.src();
const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);
const operand = try sema.resolveInst(extra.rhs);
fn zirConstCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
const src = LazySrcLoc.nodeOffset(extra.node);
const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
const operand = try sema.resolveInst(extra.operand);
const operand_ty = sema.typeOf(operand);
try sema.checkPtrType(block, dest_ty_src, dest_ty);
try sema.checkPtrOperand(block, operand_src, operand_ty);
var operand_payload = operand_ty.ptrInfo();
var dest_info = dest_ty.ptrInfo();
var ptr_info = operand_ty.ptrInfo().data;
ptr_info.mutable = true;
const dest_ty = try Type.ptr(sema.arena, sema.mod, ptr_info);
operand_payload.data.mutable = dest_info.data.mutable;
operand_payload.data.@"volatile" = dest_info.data.@"volatile";
const altered_operand_ty = Type.initPayload(&operand_payload.base);
if (!altered_operand_ty.eql(dest_ty, sema.mod)) {
const msg = msg: {
const msg = try sema.errMsg(block, src, "'@qualCast' can only modify 'const' and 'volatile' qualifiers", .{});
errdefer msg.destroy(sema.gpa);
dest_info.data.mutable = !operand_ty.isConstPtr();
dest_info.data.@"volatile" = operand_ty.isVolatilePtr();
const altered_dest_ty = Type.initPayload(&dest_info.base);
try sema.errNote(block, src, msg, "expected type '{}'", .{altered_dest_ty.fmt(sema.mod)});
try sema.errNote(block, src, msg, "got type '{}'", .{operand_ty.fmt(sema.mod)});
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
if (try sema.resolveMaybeUndefVal(operand)) |operand_val| {
return sema.addConstant(dest_ty, operand_val);
}
try sema.requireRuntimeBlock(block, src, null);
return block.addBitCast(dest_ty, operand);
}
fn zirVolatileCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
const src = LazySrcLoc.nodeOffset(extra.node);
const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
const operand = try sema.resolveInst(extra.operand);
const operand_ty = sema.typeOf(operand);
try sema.checkPtrOperand(block, operand_src, operand_ty);
var ptr_info = operand_ty.ptrInfo().data;
ptr_info.@"volatile" = false;
const dest_ty = try Type.ptr(sema.arena, sema.mod, ptr_info);
if (try sema.resolveMaybeUndefVal(operand)) |operand_val| {
return sema.addConstant(dest_ty, operand_val);
}

View File

@ -857,9 +857,6 @@ pub const Inst = struct {
/// Implements the `@ptrCast` builtin.
/// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand.
ptr_cast,
/// Implements the `@qualCast` builtin.
/// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand.
qual_cast,
/// Implements the `@truncate` builtin.
/// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand.
truncate,
@ -1198,7 +1195,6 @@ pub const Inst = struct {
.float_cast,
.int_cast,
.ptr_cast,
.qual_cast,
.truncate,
.align_cast,
.has_field,
@ -1488,7 +1484,6 @@ pub const Inst = struct {
.float_cast,
.int_cast,
.ptr_cast,
.qual_cast,
.truncate,
.align_cast,
.has_field,
@ -1760,7 +1755,6 @@ pub const Inst = struct {
.float_cast = .pl_node,
.int_cast = .pl_node,
.ptr_cast = .pl_node,
.qual_cast = .pl_node,
.truncate = .pl_node,
.align_cast = .pl_node,
.typeof_builtin = .pl_node,
@ -2004,6 +1998,12 @@ pub const Inst = struct {
/// Implement builtin `@cVaStart`.
/// `operand` is `src_node: i32`.
c_va_start,
/// Implements the `@constCast` builtin.
/// `operand` is payload index to `UnNode`.
const_cast,
/// Implements the `@volatileCast` builtin.
/// `operand` is payload index to `UnNode`.
volatile_cast,
pub const InstData = struct {
opcode: Extended,

View File

@ -332,7 +332,6 @@ const Writer = struct {
.float_cast,
.int_cast,
.ptr_cast,
.qual_cast,
.truncate,
.align_cast,
.div_exact,
@ -507,6 +506,8 @@ const Writer = struct {
.reify,
.c_va_copy,
.c_va_end,
.const_cast,
.volatile_cast,
=> {
const inst_data = self.code.extraData(Zir.Inst.UnNode, extended.operand).data;
const src = LazySrcLoc.nodeOffset(inst_data.node);

Binary file not shown.

View File

@ -1553,3 +1553,18 @@ test "peer type resolution forms error union" {
} else @intCast(u32, foo);
try expect(try result == 123);
}
test "@constCast without a result location" {
const x: i32 = 1234;
const y = @constCast(&x);
try expect(@TypeOf(y) == *i32);
try expect(y.* == 1234);
}
test "@volatileCast without a result location" {
var x: i32 = 1234;
var y: *volatile i32 = &x;
const z = @volatileCast(y);
try expect(@TypeOf(z) == *i32);
try expect(z.* == 1234);
}

View File

@ -1,12 +0,0 @@
pub export fn entry() void {
var a: [*:0]const volatile u16 = undefined;
_ = @qualCast([*]u16, a);
}
// error
// backend=stage2
// target=native
//
// :3:9: error: '@qualCast' can only modify 'const' and 'volatile' qualifiers
// :3:9: note: expected type '[*]const volatile u16'
// :3:9: note: got type '[*:0]const volatile u16'

View File

@ -9,4 +9,4 @@ export fn entry() void {
// target=native
//
// :3:15: error: cast discards const qualifier
// :3:15: note: consider using '@qualCast'
// :3:15: note: consider using '@constCast'