| author | |
| committer | |
| log | f16c10a86b7183e99e54a70344f4681211cd52bb |
| tree | aa6c1f3510696eb5ee63dd4ddb17c96cc6dce45b |
| parent | fe4ea31f7e9e1c8caea6a1df107b91e8ea1a7b8a |
13 files changed, 113 insertions(+), 18 deletions(-)
doc/langref.html.in+11-4| ... | ... | @@ -8803,10 +8803,10 @@ pub const PrefetchOptions = struct { |
| 8803 | 8803 | {#syntax#}@ptrCast{#endsyntax#} cannot be used for: |
| 8804 | 8804 | </p> |
| 8805 | 8805 | <ul> |
| 8806 | <li>Removing {#syntax#}const{#endsyntax#} or {#syntax#}volatile{#endsyntax#} qualifier. TODO add a {#syntax#}@qualCast{#endsyntax#} builtin.</li> | |
| 8807 | <li>Changing pointer address space, use {#link|@addrSpaceCast#}</li> | |
| 8808 | <li>Increasing pointer alignment, use {#link|@alignCast#}</li> | |
| 8809 | <li>Casting a non-slice pointer to a slice, use slicing syntax {#syntax#}ptr[start..end]{#endsyntax#}</li> | |
| 8806 | <li>Removing {#syntax#}const{#endsyntax#} or {#syntax#}volatile{#endsyntax#} qualifier, use {#link|@qualCast#}.</li> | |
| 8807 | <li>Changing pointer address space, use {#link|@addrSpaceCast#}.</li> | |
| 8808 | <li>Increasing pointer alignment, use {#link|@alignCast#}.</li> | |
| 8809 | <li>Casting a non-slice pointer to a slice, use slicing syntax {#syntax#}ptr[start..end]{#endsyntax#}.</li> | |
| 8810 | 8810 | </ul> |
| 8811 | 8811 | {#header_close#} |
| 8812 | 8812 | |
| ... | ... | @@ -8820,6 +8820,13 @@ pub const PrefetchOptions = struct { |
| 8820 | 8820 | |
| 8821 | 8821 | {#header_close#} |
| 8822 | 8822 | |
| 8823 | {#header_open|@qualCast#} | |
| 8824 | <pre>{#syntax#}@qualCast(comptime DestType: type, value: anytype) DestType{#endsyntax#}</pre> | |
| 8825 | <p> | |
| 8826 | Remove {#syntax#}const{#endsyntax#} or {#syntax#}volatile{#endsyntax#} qualifier from a pointer. | |
| 8827 | </p> | |
| 8828 | {#header_close#} | |
| 8829 | ||
| 8823 | 8830 | {#header_open|@rem#} |
| 8824 | 8831 | <pre>{#syntax#}@rem(numerator: T, denominator: T) T{#endsyntax#}</pre> |
| 8825 | 8832 | <p> |
lib/std/child_process.zig+2-2| ... | ... | @@ -1164,7 +1164,7 @@ fn windowsCreateProcessPathExt( |
| 1164 | 1164 | var app_name_unicode_string = windows.UNICODE_STRING{ |
| 1165 | 1165 | .Length = app_name_len_bytes, |
| 1166 | 1166 | .MaximumLength = app_name_len_bytes, |
| 1167 | .Buffer = @intToPtr([*]u16, @ptrToInt(app_name_wildcard.ptr)), | |
| 1167 | .Buffer = @qualCast([*:0]u16, app_name_wildcard.ptr), | |
| 1168 | 1168 | }; |
| 1169 | 1169 | const rc = windows.ntdll.NtQueryDirectoryFile( |
| 1170 | 1170 | dir.fd, |
| ... | ... | @@ -1261,7 +1261,7 @@ fn windowsCreateProcessPathExt( |
| 1261 | 1261 | var app_name_unicode_string = windows.UNICODE_STRING{ |
| 1262 | 1262 | .Length = app_name_len_bytes, |
| 1263 | 1263 | .MaximumLength = app_name_len_bytes, |
| 1264 | .Buffer = @intToPtr([*]u16, @ptrToInt(app_name_appended.ptr)), | |
| 1264 | .Buffer = @qualCast([*:0]u16, app_name_appended.ptr), | |
| 1265 | 1265 | }; |
| 1266 | 1266 | |
| 1267 | 1267 | // Re-use the directory handle but this time we call with the appended app name |
lib/std/fs.zig+1-1| ... | ... | @@ -1763,7 +1763,7 @@ pub const Dir = struct { |
| 1763 | 1763 | var nt_name = w.UNICODE_STRING{ |
| 1764 | 1764 | .Length = path_len_bytes, |
| 1765 | 1765 | .MaximumLength = path_len_bytes, |
| 1766 | .Buffer = @intToPtr([*]u16, @ptrToInt(sub_path_w)), | |
| 1766 | .Buffer = @qualCast([*:0]u16, sub_path_w), | |
| 1767 | 1767 | }; |
| 1768 | 1768 | var attr = w.OBJECT_ATTRIBUTES{ |
| 1769 | 1769 | .Length = @sizeOf(w.OBJECT_ATTRIBUTES), |
lib/std/os.zig+1-1| ... | ... | @@ -4513,7 +4513,7 @@ pub fn faccessatW(dirfd: fd_t, sub_path_w: [*:0]const u16, mode: u32, flags: u32 |
| 4513 | 4513 | var nt_name = windows.UNICODE_STRING{ |
| 4514 | 4514 | .Length = path_len_bytes, |
| 4515 | 4515 | .MaximumLength = path_len_bytes, |
| 4516 | .Buffer = @intToPtr([*]u16, @ptrToInt(sub_path_w)), | |
| 4516 | .Buffer = @qualCast([*:0]u16, sub_path_w), | |
| 4517 | 4517 | }; |
| 4518 | 4518 | var attr = windows.OBJECT_ATTRIBUTES{ |
| 4519 | 4519 | .Length = @sizeOf(windows.OBJECT_ATTRIBUTES), |
lib/std/os/windows.zig+7-7| ... | ... | @@ -85,7 +85,7 @@ pub fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!HAN |
| 85 | 85 | var nt_name = UNICODE_STRING{ |
| 86 | 86 | .Length = path_len_bytes, |
| 87 | 87 | .MaximumLength = path_len_bytes, |
| 88 | .Buffer = @intToPtr([*]u16, @ptrToInt(sub_path_w.ptr)), | |
| 88 | .Buffer = @qualCast([*]u16, sub_path_w.ptr), | |
| 89 | 89 | }; |
| 90 | 90 | var attr = OBJECT_ATTRIBUTES{ |
| 91 | 91 | .Length = @sizeOf(OBJECT_ATTRIBUTES), |
| ... | ... | @@ -634,7 +634,7 @@ pub fn SetCurrentDirectory(path_name: []const u16) SetCurrentDirectoryError!void |
| 634 | 634 | var nt_name = UNICODE_STRING{ |
| 635 | 635 | .Length = path_len_bytes, |
| 636 | 636 | .MaximumLength = path_len_bytes, |
| 637 | .Buffer = @intToPtr([*]u16, @ptrToInt(path_name.ptr)), | |
| 637 | .Buffer = @qualCast([*]u16, path_name.ptr), | |
| 638 | 638 | }; |
| 639 | 639 | |
| 640 | 640 | 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 |
| 766 | 766 | var nt_name = UNICODE_STRING{ |
| 767 | 767 | .Length = path_len_bytes, |
| 768 | 768 | .MaximumLength = path_len_bytes, |
| 769 | .Buffer = @intToPtr([*]u16, @ptrToInt(sub_path_w.ptr)), | |
| 769 | .Buffer = @qualCast([*]u16, sub_path_w.ptr), | |
| 770 | 770 | }; |
| 771 | 771 | var attr = OBJECT_ATTRIBUTES{ |
| 772 | 772 | .Length = @sizeOf(OBJECT_ATTRIBUTES), |
| ... | ... | @@ -876,7 +876,7 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil |
| 876 | 876 | .Length = path_len_bytes, |
| 877 | 877 | .MaximumLength = path_len_bytes, |
| 878 | 878 | // The Windows API makes this mutable, but it will not mutate here. |
| 879 | .Buffer = @intToPtr([*]u16, @ptrToInt(sub_path_w.ptr)), | |
| 879 | .Buffer = @qualCast([*]u16, sub_path_w.ptr), | |
| 880 | 880 | }; |
| 881 | 881 | |
| 882 | 882 | if (sub_path_w[0] == '.' and sub_path_w[1] == 0) { |
| ... | ... | @@ -1414,7 +1414,7 @@ pub fn sendmsg( |
| 1414 | 1414 | } |
| 1415 | 1415 | |
| 1416 | 1416 | 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 { |
| 1417 | var buffer = ws2_32.WSABUF{ .len = @truncate(u31, len), .buf = @intToPtr([*]u8, @ptrToInt(buf)) }; | |
| 1417 | var buffer = ws2_32.WSABUF{ .len = @truncate(u31, len), .buf = @qualCast([*]u8, buf) }; | |
| 1418 | 1418 | var bytes_send: DWORD = undefined; |
| 1419 | 1419 | 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) { |
| 1420 | 1420 | return ws2_32.SOCKET_ERROR; |
| ... | ... | @@ -1876,13 +1876,13 @@ pub fn eqlIgnoreCaseWTF16(a: []const u16, b: []const u16) bool { |
| 1876 | 1876 | const a_string = UNICODE_STRING{ |
| 1877 | 1877 | .Length = a_bytes, |
| 1878 | 1878 | .MaximumLength = a_bytes, |
| 1879 | .Buffer = @intToPtr([*]u16, @ptrToInt(a.ptr)), | |
| 1879 | .Buffer = @qualCast([*]u16, a.ptr), | |
| 1880 | 1880 | }; |
| 1881 | 1881 | const b_bytes = @intCast(u16, b.len * 2); |
| 1882 | 1882 | const b_string = UNICODE_STRING{ |
| 1883 | 1883 | .Length = b_bytes, |
| 1884 | 1884 | .MaximumLength = b_bytes, |
| 1885 | .Buffer = @intToPtr([*]u16, @ptrToInt(b.ptr)), | |
| 1885 | .Buffer = @qualCast([*]u16, b.ptr), | |
| 1886 | 1886 | }; |
| 1887 | 1887 | return ntdll.RtlEqualUnicodeString(&a_string, &b_string, TRUE) == TRUE; |
| 1888 | 1888 | } |
lib/std/zig/c_translation.zig+1-1| ... | ... | @@ -75,7 +75,7 @@ fn castPtr(comptime DestType: type, target: anytype) DestType { |
| 75 | 75 | const source = ptrInfo(@TypeOf(target)); |
| 76 | 76 | |
| 77 | 77 | if (source.is_const and !dest.is_const or source.is_volatile and !dest.is_volatile) |
| 78 | return @intToPtr(DestType, @ptrToInt(target)) | |
| 78 | return @qualCast(DestType, target) | |
| 79 | 79 | else if (@typeInfo(dest.child) == .Opaque) |
| 80 | 80 | // dest.alignment would error out |
| 81 | 81 | return @ptrCast(DestType, target) |
src/AstGen.zig+2| ... | ... | @@ -2530,6 +2530,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As |
| 2530 | 2530 | .bit_size_of, |
| 2531 | 2531 | .typeof_log2_int_type, |
| 2532 | 2532 | .ptr_to_int, |
| 2533 | .qual_cast, | |
| 2533 | 2534 | .align_of, |
| 2534 | 2535 | .bool_to_int, |
| 2535 | 2536 | .embed_file, |
| ... | ... | @@ -8037,6 +8038,7 @@ fn builtinCall( |
| 8037 | 8038 | .float_cast => return typeCast(gz, scope, ri, node, params[0], params[1], .float_cast), |
| 8038 | 8039 | .int_cast => return typeCast(gz, scope, ri, node, params[0], params[1], .int_cast), |
| 8039 | 8040 | .ptr_cast => return typeCast(gz, scope, ri, node, params[0], params[1], .ptr_cast), |
| 8041 | .qual_cast => return typeCast(gz, scope, ri, node, params[0], params[1], .qual_cast), | |
| 8040 | 8042 | .truncate => return typeCast(gz, scope, ri, node, params[0], params[1], .truncate), |
| 8041 | 8043 | // zig fmt: on |
| 8042 | 8044 |
src/BuiltinFn.zig+8| ... | ... | @@ -75,6 +75,7 @@ pub const Tag = enum { |
| 75 | 75 | prefetch, |
| 76 | 76 | ptr_cast, |
| 77 | 77 | ptr_to_int, |
| 78 | qual_cast, | |
| 78 | 79 | rem, |
| 79 | 80 | return_address, |
| 80 | 81 | select, |
| ... | ... | @@ -674,6 +675,13 @@ pub const list = list: { |
| 674 | 675 | .param_count = 1, |
| 675 | 676 | }, |
| 676 | 677 | }, |
| 678 | .{ | |
| 679 | "@qualCast", | |
| 680 | .{ | |
| 681 | .tag = .qual_cast, | |
| 682 | .param_count = 2, | |
| 683 | }, | |
| 684 | }, | |
| 677 | 685 | .{ |
| 678 | 686 | "@rem", |
| 679 | 687 | .{ |
src/Sema.zig+60-2| ... | ... | @@ -1015,6 +1015,7 @@ fn analyzeBodyInner( |
| 1015 | 1015 | .float_cast => try sema.zirFloatCast(block, inst), |
| 1016 | 1016 | .int_cast => try sema.zirIntCast(block, inst), |
| 1017 | 1017 | .ptr_cast => try sema.zirPtrCast(block, inst), |
| 1018 | .qual_cast => try sema.zirQualCast(block, inst), | |
| 1018 | 1019 | .truncate => try sema.zirTruncate(block, inst), |
| 1019 | 1020 | .align_cast => try sema.zirAlignCast(block, inst), |
| 1020 | 1021 | .has_decl => try sema.zirHasDecl(block, inst), |
| ... | ... | @@ -19529,10 +19530,24 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 19529 | 19530 | const operand_info = operand_ty.ptrInfo().data; |
| 19530 | 19531 | const dest_info = dest_ty.ptrInfo().data; |
| 19531 | 19532 | if (!operand_info.mutable and dest_info.mutable) { |
| 19532 | return sema.fail(block, src, "cast discards const qualifier", .{}); | |
| 19533 | const msg = msg: { | |
| 19534 | const msg = try sema.errMsg(block, src, "cast discards const qualifier", .{}); | |
| 19535 | errdefer msg.destroy(sema.gpa); | |
| 19536 | ||
| 19537 | try sema.errNote(block, src, msg, "consider using '@qualCast'", .{}); | |
| 19538 | break :msg msg; | |
| 19539 | }; | |
| 19540 | return sema.failWithOwnedErrorMsg(msg); | |
| 19533 | 19541 | } |
| 19534 | 19542 | if (operand_info.@"volatile" and !dest_info.@"volatile") { |
| 19535 | return sema.fail(block, src, "cast discards volatile qualifier", .{}); | |
| 19543 | const msg = msg: { | |
| 19544 | const msg = try sema.errMsg(block, src, "cast discards volatile qualifier", .{}); | |
| 19545 | errdefer msg.destroy(sema.gpa); | |
| 19546 | ||
| 19547 | try sema.errNote(block, src, msg, "consider using '@qualCast'", .{}); | |
| 19548 | break :msg msg; | |
| 19549 | }; | |
| 19550 | return sema.failWithOwnedErrorMsg(msg); | |
| 19536 | 19551 | } |
| 19537 | 19552 | if (operand_info.@"addrspace" != dest_info.@"addrspace") { |
| 19538 | 19553 | const msg = msg: { |
| ... | ... | @@ -19634,6 +19649,49 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 19634 | 19649 | return block.addBitCast(aligned_dest_ty, ptr); |
| 19635 | 19650 | } |
| 19636 | 19651 | |
| 19652 | fn zirQualCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | |
| 19653 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | |
| 19654 | const src = inst_data.src(); | |
| 19655 | const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | |
| 19656 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; | |
| 19657 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; | |
| 19658 | const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs); | |
| 19659 | const operand = try sema.resolveInst(extra.rhs); | |
| 19660 | const operand_ty = sema.typeOf(operand); | |
| 19661 | ||
| 19662 | try sema.checkPtrType(block, dest_ty_src, dest_ty); | |
| 19663 | try sema.checkPtrOperand(block, operand_src, operand_ty); | |
| 19664 | ||
| 19665 | var operand_payload = operand_ty.ptrInfo(); | |
| 19666 | var dest_info = dest_ty.ptrInfo(); | |
| 19667 | ||
| 19668 | operand_payload.data.mutable = dest_info.data.mutable; | |
| 19669 | operand_payload.data.@"volatile" = dest_info.data.@"volatile"; | |
| 19670 | ||
| 19671 | const altered_operand_ty = Type.initPayload(&operand_payload.base); | |
| 19672 | if (!altered_operand_ty.eql(dest_ty, sema.mod)) { | |
| 19673 | const msg = msg: { | |
| 19674 | const msg = try sema.errMsg(block, src, "'@qualCast' can only modify 'const' and 'volatile' qualifiers", .{}); | |
| 19675 | errdefer msg.destroy(sema.gpa); | |
| 19676 | ||
| 19677 | dest_info.data.mutable = !operand_ty.isConstPtr(); | |
| 19678 | dest_info.data.@"volatile" = operand_ty.isVolatilePtr(); | |
| 19679 | const altered_dest_ty = Type.initPayload(&dest_info.base); | |
| 19680 | try sema.errNote(block, src, msg, "expected type '{}'", .{altered_dest_ty.fmt(sema.mod)}); | |
| 19681 | try sema.errNote(block, src, msg, "got type '{}'", .{operand_ty.fmt(sema.mod)}); | |
| 19682 | break :msg msg; | |
| 19683 | }; | |
| 19684 | return sema.failWithOwnedErrorMsg(msg); | |
| 19685 | } | |
| 19686 | ||
| 19687 | if (try sema.resolveMaybeUndefVal(operand)) |operand_val| { | |
| 19688 | return sema.addConstant(dest_ty, operand_val); | |
| 19689 | } | |
| 19690 | ||
| 19691 | try sema.requireRuntimeBlock(block, src, null); | |
| 19692 | return block.addBitCast(dest_ty, operand); | |
| 19693 | } | |
| 19694 | ||
| 19637 | 19695 | fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 19638 | 19696 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 19639 | 19697 | const src = inst_data.src(); |
src/Zir.zig+6| ... | ... | @@ -857,6 +857,9 @@ pub const Inst = struct { |
| 857 | 857 | /// Implements the `@ptrCast` builtin. |
| 858 | 858 | /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand. |
| 859 | 859 | ptr_cast, |
| 860 | /// Implements the `@qualCast` builtin. | |
| 861 | /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand. | |
| 862 | qual_cast, | |
| 860 | 863 | /// Implements the `@truncate` builtin. |
| 861 | 864 | /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand. |
| 862 | 865 | truncate, |
| ... | ... | @@ -1195,6 +1198,7 @@ pub const Inst = struct { |
| 1195 | 1198 | .float_cast, |
| 1196 | 1199 | .int_cast, |
| 1197 | 1200 | .ptr_cast, |
| 1201 | .qual_cast, | |
| 1198 | 1202 | .truncate, |
| 1199 | 1203 | .align_cast, |
| 1200 | 1204 | .has_field, |
| ... | ... | @@ -1484,6 +1488,7 @@ pub const Inst = struct { |
| 1484 | 1488 | .float_cast, |
| 1485 | 1489 | .int_cast, |
| 1486 | 1490 | .ptr_cast, |
| 1491 | .qual_cast, | |
| 1487 | 1492 | .truncate, |
| 1488 | 1493 | .align_cast, |
| 1489 | 1494 | .has_field, |
| ... | ... | @@ -1755,6 +1760,7 @@ pub const Inst = struct { |
| 1755 | 1760 | .float_cast = .pl_node, |
| 1756 | 1761 | .int_cast = .pl_node, |
| 1757 | 1762 | .ptr_cast = .pl_node, |
| 1763 | .qual_cast = .pl_node, | |
| 1758 | 1764 | .truncate = .pl_node, |
| 1759 | 1765 | .align_cast = .pl_node, |
| 1760 | 1766 | .typeof_builtin = .pl_node, |
src/print_zir.zig+1| ... | ... | @@ -332,6 +332,7 @@ const Writer = struct { |
| 332 | 332 | .float_cast, |
| 333 | 333 | .int_cast, |
| 334 | 334 | .ptr_cast, |
| 335 | .qual_cast, | |
| 335 | 336 | .truncate, |
| 336 | 337 | .align_cast, |
| 337 | 338 | .div_exact, |
test/cases/compile_errors/invalid_qualcast.zig created+12| ... | ... | @@ -0,0 +1,12 @@ |
| 1 | pub export fn entry() void { | |
| 2 | var a: [*:0]const volatile u16 = undefined; | |
| 3 | _ = @qualCast([*]u16, a); | |
| 4 | } | |
| 5 | ||
| 6 | // error | |
| 7 | // backend=stage2 | |
| 8 | // target=native | |
| 9 | // | |
| 10 | // :3:9: error: '@qualCast' can only modify 'const' and 'volatile' qualifiers | |
| 11 | // :3:9: note: expected type '[*]const volatile u16' | |
| 12 | // :3:9: note: got type '[*:0]const volatile u16' |
test/cases/compile_errors/ptrCast_discards_const_qualifier.zig+1| ... | ... | @@ -9,3 +9,4 @@ export fn entry() void { |
| 9 | 9 | // target=native |
| 10 | 10 | // |
| 11 | 11 | // :3:15: error: cast discards const qualifier |
| 12 | // :3:15: note: consider using '@qualCast' |