diff --git a/doc/langref.html.in b/doc/langref.html.in index 9490c4e69d..a74d06ccbf 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -8129,6 +8129,13 @@ test "main" { {#code_end#} {#header_close#} + {#header_open|@constCast#} +
{#syntax#}@constCast(value: anytype) DestType{#endsyntax#}
+ + Remove {#syntax#}const{#endsyntax#} qualifier from a pointer. +
+ {#header_close#} + {#header_open|@ctz#}{#syntax#}@ctz(operand: anytype){#endsyntax#}
{#syntax#}@TypeOf(operand){#endsyntax#} must be an integer type or an integer vector type.
@@ -8814,7 +8821,8 @@ pub const PrefetchOptions = struct { {#syntax#}@ptrCast{#endsyntax#} cannot be used for:{#syntax#}@qualCast(comptime DestType: type, value: anytype) DestType{#endsyntax#}
- - Remove {#syntax#}const{#endsyntax#} or {#syntax#}volatile{#endsyntax#} qualifier from a pointer. -
- {#header_close#} - {#header_open|@rem#}{#syntax#}@rem(numerator: T, denominator: T) T{#endsyntax#}
@@ -9525,6 +9526,13 @@ fn foo(comptime T: type, ptr: *T) T {
{#syntax#}@Vector(len: comptime_int, Element: type) type{#endsyntax#}
Creates {#link|Vectors#}.
{#header_close#} + + {#header_open|@volatileCast#} +{#syntax#}@volatileCast(value: anytype) DestType{#endsyntax#}
+ + Remove {#syntax#}volatile{#endsyntax#} qualifier from a pointer. +
+ {#header_close#} {#header_close#} {#header_open|Build Mode#} diff --git a/lib/docs/main.js b/lib/docs/main.js index fae39c5fba..7a27f9db4f 100644 --- a/lib/docs/main.js +++ b/lib/docs/main.js @@ -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": { diff --git a/lib/std/child_process.zig b/lib/std/child_process.zig index 21d7b4fe3e..003e37d76b 100644 --- a/lib/std/child_process.zig +++ b/lib/std/child_process.zig @@ -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 diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 2300ad044a..52a93a498f 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -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), diff --git a/lib/std/mem/Allocator.zig b/lib/std/mem/Allocator.zig index 6e56607865..63e5e9a1d5 100644 --- a/lib/std/mem/Allocator.zig +++ b/lib/std/mem/Allocator.zig @@ -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()); diff --git a/lib/std/os.zig b/lib/std/os.zig index 3cee30c32d..c5eeb34b1c 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -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), diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig index 93e762827b..711bc9f349 100644 --- a/lib/std/os/windows.zig +++ b/lib/std/os/windows.zig @@ -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; } diff --git a/lib/std/zig/c_translation.zig b/lib/std/zig/c_translation.zig index d33c74d777..6e95ab53ab 100644 --- a/lib/std/zig/c_translation.zig +++ b/lib/std/zig/c_translation.zig @@ -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) diff --git a/src/AstGen.zig b/src/AstGen.zig index 76a681abd3..40eef32d4e 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -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), diff --git a/src/Autodoc.zig b/src/Autodoc.zig index 0c2c39bbcc..44325e3836 100644 --- a/src/Autodoc.zig +++ b/src/Autodoc.zig @@ -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; diff --git a/src/BuiltinFn.zig b/src/BuiltinFn.zig index 80eb739185..20edbabe47 100644 --- a/src/BuiltinFn.zig +++ b/src/BuiltinFn.zig @@ -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, + }, + }, }); }; diff --git a/src/Sema.zig b/src/Sema.zig index 9eef07648d..cf6350e35f 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -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); } diff --git a/src/Zir.zig b/src/Zir.zig index b93422177e..58f9fdff14 100644 --- a/src/Zir.zig +++ b/src/Zir.zig @@ -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, diff --git a/src/print_zir.zig b/src/print_zir.zig index e5fc8815ed..8d97000582 100644 --- a/src/print_zir.zig +++ b/src/print_zir.zig @@ -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); diff --git a/stage1/zig1.wasm b/stage1/zig1.wasm index ef7d7891c9..9a3b25eb30 100644 Binary files a/stage1/zig1.wasm and b/stage1/zig1.wasm differ diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig index 30889aef04..16f3c6e2dd 100644 --- a/test/behavior/cast.zig +++ b/test/behavior/cast.zig @@ -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); +} diff --git a/test/cases/compile_errors/invalid_qualcast.zig b/test/cases/compile_errors/invalid_qualcast.zig deleted file mode 100644 index 20b223b727..0000000000 --- a/test/cases/compile_errors/invalid_qualcast.zig +++ /dev/null @@ -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' diff --git a/test/cases/compile_errors/ptrCast_discards_const_qualifier.zig b/test/cases/compile_errors/ptrCast_discards_const_qualifier.zig index eedef01234..f27f5f4f93 100644 --- a/test/cases/compile_errors/ptrCast_discards_const_qualifier.zig +++ b/test/cases/compile_errors/ptrCast_discards_const_qualifier.zig @@ -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'