| author | |
| committer | |
| log | 6b7ad22981867cbf6ec40d540f5571f276d6801b |
| tree | 4c1665cf0c03fcaa5d6c2a09aa49c49f5b804236 |
| parent | e712d5f03e6e3ddde6a4a6f7d2d82e786efd543a |
| parent | 629c3108aa71f94bd26dba8d4f20c9f3a3945bd4 |
| signature |
Improve `@ptrCast` errors, fix some bugs30 files changed, 280 insertions(+), 36 deletions(-)
doc/langref.html.in+16| ... | @@ -8809,6 +8809,15 @@ pub const PrefetchOptions = struct { | ... | @@ -8809,6 +8809,15 @@ pub const PrefetchOptions = struct { |
| 8809 | {#link|Optional Pointers#} are allowed. Casting an optional pointer which is {#link|null#} | 8809 | {#link|Optional Pointers#} are allowed. Casting an optional pointer which is {#link|null#} |
| 8810 | to a non-optional pointer invokes safety-checked {#link|Undefined Behavior#}. | 8810 | to a non-optional pointer invokes safety-checked {#link|Undefined Behavior#}. |
| 8811 | </p> | 8811 | </p> |
| 8812 | <p> | ||
| 8813 | {#syntax#}@ptrCast{#endsyntax#} cannot be used for: | ||
| 8814 | </p> | ||
| 8815 | <ul> | ||
| 8816 | <li>Removing {#syntax#}const{#endsyntax#} or {#syntax#}volatile{#endsyntax#} qualifier, use {#link|@qualCast#}.</li> | ||
| 8817 | <li>Changing pointer address space, use {#link|@addrSpaceCast#}.</li> | ||
| 8818 | <li>Increasing pointer alignment, use {#link|@alignCast#}.</li> | ||
| 8819 | <li>Casting a non-slice pointer to a slice, use slicing syntax {#syntax#}ptr[start..end]{#endsyntax#}.</li> | ||
| 8820 | </ul> | ||
| 8812 | {#header_close#} | 8821 | {#header_close#} |
| 8813 | 8822 | ||
| 8814 | {#header_open|@ptrToInt#} | 8823 | {#header_open|@ptrToInt#} |
| ... | @@ -8821,6 +8830,13 @@ pub const PrefetchOptions = struct { | ... | @@ -8821,6 +8830,13 @@ pub const PrefetchOptions = struct { |
| 8821 | 8830 | ||
| 8822 | {#header_close#} | 8831 | {#header_close#} |
| 8823 | 8832 | ||
| 8833 | {#header_open|@qualCast#} | ||
| 8834 | <pre>{#syntax#}@qualCast(comptime DestType: type, value: anytype) DestType{#endsyntax#}</pre> | ||
| 8835 | <p> | ||
| 8836 | Remove {#syntax#}const{#endsyntax#} or {#syntax#}volatile{#endsyntax#} qualifier from a pointer. | ||
| 8837 | </p> | ||
| 8838 | {#header_close#} | ||
| 8839 | |||
| 8824 | {#header_open|@rem#} | 8840 | {#header_open|@rem#} |
| 8825 | <pre>{#syntax#}@rem(numerator: T, denominator: T) T{#endsyntax#}</pre> | 8841 | <pre>{#syntax#}@rem(numerator: T, denominator: T) T{#endsyntax#}</pre> |
| 8826 | <p> | 8842 | <p> |
lib/std/child_process.zig+2-2| ... | @@ -1164,7 +1164,7 @@ fn windowsCreateProcessPathExt( | ... | @@ -1164,7 +1164,7 @@ fn windowsCreateProcessPathExt( |
| 1164 | var app_name_unicode_string = windows.UNICODE_STRING{ | 1164 | var app_name_unicode_string = windows.UNICODE_STRING{ |
| 1165 | .Length = app_name_len_bytes, | 1165 | .Length = app_name_len_bytes, |
| 1166 | .MaximumLength = app_name_len_bytes, | 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 | const rc = windows.ntdll.NtQueryDirectoryFile( | 1169 | const rc = windows.ntdll.NtQueryDirectoryFile( |
| 1170 | dir.fd, | 1170 | dir.fd, |
| ... | @@ -1261,7 +1261,7 @@ fn windowsCreateProcessPathExt( | ... | @@ -1261,7 +1261,7 @@ fn windowsCreateProcessPathExt( |
| 1261 | var app_name_unicode_string = windows.UNICODE_STRING{ | 1261 | var app_name_unicode_string = windows.UNICODE_STRING{ |
| 1262 | .Length = app_name_len_bytes, | 1262 | .Length = app_name_len_bytes, |
| 1263 | .MaximumLength = app_name_len_bytes, | 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 | // Re-use the directory handle but this time we call with the appended app name | 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,7 +1763,7 @@ pub const Dir = struct { |
| 1763 | var nt_name = w.UNICODE_STRING{ | 1763 | var nt_name = w.UNICODE_STRING{ |
| 1764 | .Length = path_len_bytes, | 1764 | .Length = path_len_bytes, |
| 1765 | .MaximumLength = path_len_bytes, | 1765 | .MaximumLength = path_len_bytes, |
| 1766 | .Buffer = @intToPtr([*]u16, @ptrToInt(sub_path_w)), | 1766 | .Buffer = @qualCast([*:0]u16, sub_path_w), |
| 1767 | }; | 1767 | }; |
| 1768 | var attr = w.OBJECT_ATTRIBUTES{ | 1768 | var attr = w.OBJECT_ATTRIBUTES{ |
| 1769 | .Length = @sizeOf(w.OBJECT_ATTRIBUTES), | 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,7 +4513,7 @@ pub fn faccessatW(dirfd: fd_t, sub_path_w: [*:0]const u16, mode: u32, flags: u32 |
| 4513 | var nt_name = windows.UNICODE_STRING{ | 4513 | var nt_name = windows.UNICODE_STRING{ |
| 4514 | .Length = path_len_bytes, | 4514 | .Length = path_len_bytes, |
| 4515 | .MaximumLength = path_len_bytes, | 4515 | .MaximumLength = path_len_bytes, |
| 4516 | .Buffer = @intToPtr([*]u16, @ptrToInt(sub_path_w)), | 4516 | .Buffer = @qualCast([*:0]u16, sub_path_w), |
| 4517 | }; | 4517 | }; |
| 4518 | var attr = windows.OBJECT_ATTRIBUTES{ | 4518 | var attr = windows.OBJECT_ATTRIBUTES{ |
| 4519 | .Length = @sizeOf(windows.OBJECT_ATTRIBUTES), | 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,7 +85,7 @@ pub fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!HAN |
| 85 | var nt_name = UNICODE_STRING{ | 85 | var nt_name = UNICODE_STRING{ |
| 86 | .Length = path_len_bytes, | 86 | .Length = path_len_bytes, |
| 87 | .MaximumLength = path_len_bytes, | 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 | var attr = OBJECT_ATTRIBUTES{ | 90 | var attr = OBJECT_ATTRIBUTES{ |
| 91 | .Length = @sizeOf(OBJECT_ATTRIBUTES), | 91 | .Length = @sizeOf(OBJECT_ATTRIBUTES), |
| ... | @@ -634,7 +634,7 @@ pub fn SetCurrentDirectory(path_name: []const u16) SetCurrentDirectoryError!void | ... | @@ -634,7 +634,7 @@ pub fn SetCurrentDirectory(path_name: []const u16) SetCurrentDirectoryError!void |
| 634 | var nt_name = UNICODE_STRING{ | 634 | var nt_name = UNICODE_STRING{ |
| 635 | .Length = path_len_bytes, | 635 | .Length = path_len_bytes, |
| 636 | .MaximumLength = path_len_bytes, | 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 | const rc = ntdll.RtlSetCurrentDirectory_U(&nt_name); | 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,7 +766,7 @@ pub fn ReadLink(dir: ?HANDLE, sub_path_w: []const u16, out_buffer: []u8) ReadLin |
| 766 | var nt_name = UNICODE_STRING{ | 766 | var nt_name = UNICODE_STRING{ |
| 767 | .Length = path_len_bytes, | 767 | .Length = path_len_bytes, |
| 768 | .MaximumLength = path_len_bytes, | 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 | var attr = OBJECT_ATTRIBUTES{ | 771 | var attr = OBJECT_ATTRIBUTES{ |
| 772 | .Length = @sizeOf(OBJECT_ATTRIBUTES), | 772 | .Length = @sizeOf(OBJECT_ATTRIBUTES), |
| ... | @@ -876,7 +876,7 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil | ... | @@ -876,7 +876,7 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil |
| 876 | .Length = path_len_bytes, | 876 | .Length = path_len_bytes, |
| 877 | .MaximumLength = path_len_bytes, | 877 | .MaximumLength = path_len_bytes, |
| 878 | // The Windows API makes this mutable, but it will not mutate here. | 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 | if (sub_path_w[0] == '.' and sub_path_w[1] == 0) { | 882 | if (sub_path_w[0] == '.' and sub_path_w[1] == 0) { |
| ... | @@ -1414,7 +1414,7 @@ pub fn sendmsg( | ... | @@ -1414,7 +1414,7 @@ pub fn sendmsg( |
| 1414 | } | 1414 | } |
| 1415 | 1415 | ||
| 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 { | 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 | var bytes_send: DWORD = undefined; | 1418 | var bytes_send: DWORD = undefined; |
| 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) { | 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 | return ws2_32.SOCKET_ERROR; | 1420 | return ws2_32.SOCKET_ERROR; |
| ... | @@ -1876,13 +1876,13 @@ pub fn eqlIgnoreCaseWTF16(a: []const u16, b: []const u16) bool { | ... | @@ -1876,13 +1876,13 @@ pub fn eqlIgnoreCaseWTF16(a: []const u16, b: []const u16) bool { |
| 1876 | const a_string = UNICODE_STRING{ | 1876 | const a_string = UNICODE_STRING{ |
| 1877 | .Length = a_bytes, | 1877 | .Length = a_bytes, |
| 1878 | .MaximumLength = a_bytes, | 1878 | .MaximumLength = a_bytes, |
| 1879 | .Buffer = @intToPtr([*]u16, @ptrToInt(a.ptr)), | 1879 | .Buffer = @qualCast([*]u16, a.ptr), |
| 1880 | }; | 1880 | }; |
| 1881 | const b_bytes = @intCast(u16, b.len * 2); | 1881 | const b_bytes = @intCast(u16, b.len * 2); |
| 1882 | const b_string = UNICODE_STRING{ | 1882 | const b_string = UNICODE_STRING{ |
| 1883 | .Length = b_bytes, | 1883 | .Length = b_bytes, |
| 1884 | .MaximumLength = b_bytes, | 1884 | .MaximumLength = b_bytes, |
| 1885 | .Buffer = @intToPtr([*]u16, @ptrToInt(b.ptr)), | 1885 | .Buffer = @qualCast([*]u16, b.ptr), |
| 1886 | }; | 1886 | }; |
| 1887 | return ntdll.RtlEqualUnicodeString(&a_string, &b_string, TRUE) == TRUE; | 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,7 +75,7 @@ fn castPtr(comptime DestType: type, target: anytype) DestType { |
| 75 | const source = ptrInfo(@TypeOf(target)); | 75 | const source = ptrInfo(@TypeOf(target)); |
| 76 | 76 | ||
| 77 | if (source.is_const and !dest.is_const or source.is_volatile and !dest.is_volatile) | 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 | else if (@typeInfo(dest.child) == .Opaque) | 79 | else if (@typeInfo(dest.child) == .Opaque) |
| 80 | // dest.alignment would error out | 80 | // dest.alignment would error out |
| 81 | return @ptrCast(DestType, target) | 81 | return @ptrCast(DestType, target) |
src/AstGen.zig+37-2| ... | @@ -2530,6 +2530,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As | ... | @@ -2530,6 +2530,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As |
| 2530 | .bit_size_of, | 2530 | .bit_size_of, |
| 2531 | .typeof_log2_int_type, | 2531 | .typeof_log2_int_type, |
| 2532 | .ptr_to_int, | 2532 | .ptr_to_int, |
| 2533 | .qual_cast, | ||
| 2533 | .align_of, | 2534 | .align_of, |
| 2534 | .bool_to_int, | 2535 | .bool_to_int, |
| 2535 | .embed_file, | 2536 | .embed_file, |
| ... | @@ -4278,7 +4279,34 @@ fn testDecl( | ... | @@ -4278,7 +4279,34 @@ fn testDecl( |
| 4278 | var num_namespaces_out: u32 = 0; | 4279 | var num_namespaces_out: u32 = 0; |
| 4279 | var capturing_namespace: ?*Scope.Namespace = null; | 4280 | var capturing_namespace: ?*Scope.Namespace = null; |
| 4280 | while (true) switch (s.tag) { | 4281 | while (true) switch (s.tag) { |
| 4281 | .local_val, .local_ptr => unreachable, // a test cannot be in a local scope | 4282 | .local_val => { |
| 4283 | const local_val = s.cast(Scope.LocalVal).?; | ||
| 4284 | if (local_val.name == name_str_index) { | ||
| 4285 | local_val.used = test_name_token; | ||
| 4286 | return astgen.failTokNotes(test_name_token, "cannot test a {s}", .{ | ||
| 4287 | @tagName(local_val.id_cat), | ||
| 4288 | }, &[_]u32{ | ||
| 4289 | try astgen.errNoteTok(local_val.token_src, "{s} declared here", .{ | ||
| 4290 | @tagName(local_val.id_cat), | ||
| 4291 | }), | ||
| 4292 | }); | ||
| 4293 | } | ||
| 4294 | s = local_val.parent; | ||
| 4295 | }, | ||
| 4296 | .local_ptr => { | ||
| 4297 | const local_ptr = s.cast(Scope.LocalPtr).?; | ||
| 4298 | if (local_ptr.name == name_str_index) { | ||
| 4299 | local_ptr.used = test_name_token; | ||
| 4300 | return astgen.failTokNotes(test_name_token, "cannot test a {s}", .{ | ||
| 4301 | @tagName(local_ptr.id_cat), | ||
| 4302 | }, &[_]u32{ | ||
| 4303 | try astgen.errNoteTok(local_ptr.token_src, "{s} declared here", .{ | ||
| 4304 | @tagName(local_ptr.id_cat), | ||
| 4305 | }), | ||
| 4306 | }); | ||
| 4307 | } | ||
| 4308 | s = local_ptr.parent; | ||
| 4309 | }, | ||
| 4282 | .gen_zir => s = s.cast(GenZir).?.parent, | 4310 | .gen_zir => s = s.cast(GenZir).?.parent, |
| 4283 | .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, | 4311 | .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, |
| 4284 | .namespace, .enum_namespace => { | 4312 | .namespace, .enum_namespace => { |
| ... | @@ -8010,6 +8038,7 @@ fn builtinCall( | ... | @@ -8010,6 +8038,7 @@ fn builtinCall( |
| 8010 | .float_cast => return typeCast(gz, scope, ri, node, params[0], params[1], .float_cast), | 8038 | .float_cast => return typeCast(gz, scope, ri, node, params[0], params[1], .float_cast), |
| 8011 | .int_cast => return typeCast(gz, scope, ri, node, params[0], params[1], .int_cast), | 8039 | .int_cast => return typeCast(gz, scope, ri, node, params[0], params[1], .int_cast), |
| 8012 | .ptr_cast => return typeCast(gz, scope, ri, node, params[0], params[1], .ptr_cast), | 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), | ||
| 8013 | .truncate => return typeCast(gz, scope, ri, node, params[0], params[1], .truncate), | 8042 | .truncate => return typeCast(gz, scope, ri, node, params[0], params[1], .truncate), |
| 8014 | // zig fmt: on | 8043 | // zig fmt: on |
| 8015 | 8044 | ||
| ... | @@ -8692,6 +8721,7 @@ fn callExpr( | ... | @@ -8692,6 +8721,7 @@ fn callExpr( |
| 8692 | defer arg_block.unstack(); | 8721 | defer arg_block.unstack(); |
| 8693 | 8722 | ||
| 8694 | // `call_inst` is reused to provide the param type. | 8723 | // `call_inst` is reused to provide the param type. |
| 8724 | arg_block.rl_ty_inst = call_inst; | ||
| 8695 | const arg_ref = try expr(&arg_block, &arg_block.base, .{ .rl = .{ .coerced_ty = call_inst }, .ctx = .fn_arg }, param_node); | 8725 | const arg_ref = try expr(&arg_block, &arg_block.base, .{ .rl = .{ .coerced_ty = call_inst }, .ctx = .fn_arg }, param_node); |
| 8696 | _ = try arg_block.addBreak(.break_inline, call_index, arg_ref); | 8726 | _ = try arg_block.addBreak(.break_inline, call_index, arg_ref); |
| 8697 | 8727 | ||
| ... | @@ -10840,7 +10870,12 @@ const GenZir = struct { | ... | @@ -10840,7 +10870,12 @@ const GenZir = struct { |
| 10840 | // we emit ZIR for the block break instructions to have the result values, | 10870 | // we emit ZIR for the block break instructions to have the result values, |
| 10841 | // and then rvalue() on that to pass the value to the result location. | 10871 | // and then rvalue() on that to pass the value to the result location. |
| 10842 | switch (parent_ri.rl) { | 10872 | switch (parent_ri.rl) { |
| 10843 | .ty, .coerced_ty => |ty_inst| { | 10873 | .coerced_ty => |ty_inst| { |
| 10874 | // Type coercion needs to happend before breaks. | ||
| 10875 | gz.rl_ty_inst = ty_inst; | ||
| 10876 | gz.break_result_info = .{ .rl = .{ .ty = ty_inst } }; | ||
| 10877 | }, | ||
| 10878 | .ty => |ty_inst| { | ||
| 10844 | gz.rl_ty_inst = ty_inst; | 10879 | gz.rl_ty_inst = ty_inst; |
| 10845 | gz.break_result_info = parent_ri; | 10880 | gz.break_result_info = parent_ri; |
| 10846 | }, | 10881 | }, |
src/BuiltinFn.zig+8| ... | @@ -75,6 +75,7 @@ pub const Tag = enum { | ... | @@ -75,6 +75,7 @@ pub const Tag = enum { |
| 75 | prefetch, | 75 | prefetch, |
| 76 | ptr_cast, | 76 | ptr_cast, |
| 77 | ptr_to_int, | 77 | ptr_to_int, |
| 78 | qual_cast, | ||
| 78 | rem, | 79 | rem, |
| 79 | return_address, | 80 | return_address, |
| 80 | select, | 81 | select, |
| ... | @@ -674,6 +675,13 @@ pub const list = list: { | ... | @@ -674,6 +675,13 @@ pub const list = list: { |
| 674 | .param_count = 1, | 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 | "@rem", | 686 | "@rem", |
| 679 | .{ | 687 | .{ |
src/Sema.zig+92-9| ... | @@ -1015,6 +1015,7 @@ fn analyzeBodyInner( | ... | @@ -1015,6 +1015,7 @@ fn analyzeBodyInner( |
| 1015 | .float_cast => try sema.zirFloatCast(block, inst), | 1015 | .float_cast => try sema.zirFloatCast(block, inst), |
| 1016 | .int_cast => try sema.zirIntCast(block, inst), | 1016 | .int_cast => try sema.zirIntCast(block, inst), |
| 1017 | .ptr_cast => try sema.zirPtrCast(block, inst), | 1017 | .ptr_cast => try sema.zirPtrCast(block, inst), |
| 1018 | .qual_cast => try sema.zirQualCast(block, inst), | ||
| 1018 | .truncate => try sema.zirTruncate(block, inst), | 1019 | .truncate => try sema.zirTruncate(block, inst), |
| 1019 | .align_cast => try sema.zirAlignCast(block, inst), | 1020 | .align_cast => try sema.zirAlignCast(block, inst), |
| 1020 | .has_decl => try sema.zirHasDecl(block, inst), | 1021 | .has_decl => try sema.zirHasDecl(block, inst), |
| ... | @@ -3294,7 +3295,7 @@ fn ensureResultUsed( | ... | @@ -3294,7 +3295,7 @@ fn ensureResultUsed( |
| 3294 | const msg = msg: { | 3295 | const msg = msg: { |
| 3295 | const msg = try sema.errMsg(block, src, "error is ignored", .{}); | 3296 | const msg = try sema.errMsg(block, src, "error is ignored", .{}); |
| 3296 | errdefer msg.destroy(sema.gpa); | 3297 | errdefer msg.destroy(sema.gpa); |
| 3297 | try sema.errNote(block, src, msg, "consider using `try`, `catch`, or `if`", .{}); | 3298 | try sema.errNote(block, src, msg, "consider using 'try', 'catch', or 'if'", .{}); |
| 3298 | break :msg msg; | 3299 | break :msg msg; |
| 3299 | }; | 3300 | }; |
| 3300 | return sema.failWithOwnedErrorMsg(msg); | 3301 | return sema.failWithOwnedErrorMsg(msg); |
| ... | @@ -3325,7 +3326,7 @@ fn zirEnsureResultNonError(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com | ... | @@ -3325,7 +3326,7 @@ fn zirEnsureResultNonError(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com |
| 3325 | const msg = msg: { | 3326 | const msg = msg: { |
| 3326 | const msg = try sema.errMsg(block, src, "error is discarded", .{}); | 3327 | const msg = try sema.errMsg(block, src, "error is discarded", .{}); |
| 3327 | errdefer msg.destroy(sema.gpa); | 3328 | errdefer msg.destroy(sema.gpa); |
| 3328 | try sema.errNote(block, src, msg, "consider using `try`, `catch`, or `if`", .{}); | 3329 | try sema.errNote(block, src, msg, "consider using 'try', 'catch', or 'if'", .{}); |
| 3329 | break :msg msg; | 3330 | break :msg msg; |
| 3330 | }; | 3331 | }; |
| 3331 | return sema.failWithOwnedErrorMsg(msg); | 3332 | return sema.failWithOwnedErrorMsg(msg); |
| ... | @@ -6874,6 +6875,8 @@ fn analyzeInlineCallArg( | ... | @@ -6874,6 +6875,8 @@ fn analyzeInlineCallArg( |
| 6874 | if (err == error.AnalysisFail and param_block.comptime_reason != null) try param_block.comptime_reason.?.explain(sema, sema.err); | 6875 | if (err == error.AnalysisFail and param_block.comptime_reason != null) try param_block.comptime_reason.?.explain(sema, sema.err); |
| 6875 | return err; | 6876 | return err; |
| 6876 | }; | 6877 | }; |
| 6878 | } else if (!is_comptime_call and zir_tags[inst] == .param_comptime) { | ||
| 6879 | _ = try sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "parameter is comptime"); | ||
| 6877 | } | 6880 | } |
| 6878 | const casted_arg = sema.coerceExtra(arg_block, param_ty, uncasted_arg, arg_src, .{ .param_src = .{ | 6881 | const casted_arg = sema.coerceExtra(arg_block, param_ty, uncasted_arg, arg_src, .{ .param_src = .{ |
| 6879 | .func_inst = func_inst, | 6882 | .func_inst = func_inst, |
| ... | @@ -6947,6 +6950,9 @@ fn analyzeInlineCallArg( | ... | @@ -6947,6 +6950,9 @@ fn analyzeInlineCallArg( |
| 6947 | .val = arg_val, | 6950 | .val = arg_val, |
| 6948 | }; | 6951 | }; |
| 6949 | } else { | 6952 | } else { |
| 6953 | if (zir_tags[inst] == .param_anytype_comptime) { | ||
| 6954 | _ = try sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "parameter is comptime"); | ||
| 6955 | } | ||
| 6950 | sema.inst_map.putAssumeCapacityNoClobber(inst, uncasted_arg); | 6956 | sema.inst_map.putAssumeCapacityNoClobber(inst, uncasted_arg); |
| 6951 | } | 6957 | } |
| 6952 | 6958 | ||
| ... | @@ -8467,7 +8473,7 @@ fn handleExternLibName( | ... | @@ -8467,7 +8473,7 @@ fn handleExternLibName( |
| 8467 | return sema.fail( | 8473 | return sema.fail( |
| 8468 | block, | 8474 | block, |
| 8469 | src_loc, | 8475 | src_loc, |
| 8470 | "dependency on dynamic library '{s}' requires enabling Position Independent Code. Fixed by `-l{s}` or `-fPIC`.", | 8476 | "dependency on dynamic library '{s}' requires enabling Position Independent Code. Fixed by '-l{s}' or '-fPIC'.", |
| 8471 | .{ lib_name, lib_name }, | 8477 | .{ lib_name, lib_name }, |
| 8472 | ); | 8478 | ); |
| 8473 | } | 8479 | } |
| ... | @@ -9004,7 +9010,18 @@ fn zirParam( | ... | @@ -9004,7 +9010,18 @@ fn zirParam( |
| 9004 | if (is_comptime and sema.preallocated_new_func != null) { | 9010 | if (is_comptime and sema.preallocated_new_func != null) { |
| 9005 | // We have a comptime value for this parameter so it should be elided from the | 9011 | // We have a comptime value for this parameter so it should be elided from the |
| 9006 | // function type of the function instruction in this block. | 9012 | // function type of the function instruction in this block. |
| 9007 | const coerced_arg = try sema.coerce(block, param_ty, arg, src); | 9013 | const coerced_arg = sema.coerce(block, param_ty, arg, .unneeded) catch |err| switch (err) { |
| 9014 | error.NeededSourceLocation => { | ||
| 9015 | // We are instantiating a generic function and a comptime arg | ||
| 9016 | // cannot be coerced to the param type, but since we don't | ||
| 9017 | // have the callee source location return `GenericPoison` | ||
| 9018 | // so that the instantiation is failed and the coercion | ||
| 9019 | // is handled by comptime call logic instead. | ||
| 9020 | assert(sema.is_generic_instantiation); | ||
| 9021 | return error.GenericPoison; | ||
| 9022 | }, | ||
| 9023 | else => return err, | ||
| 9024 | }; | ||
| 9008 | sema.inst_map.putAssumeCapacity(inst, coerced_arg); | 9025 | sema.inst_map.putAssumeCapacity(inst, coerced_arg); |
| 9009 | return; | 9026 | return; |
| 9010 | } | 9027 | } |
| ... | @@ -19519,13 +19536,34 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -19519,13 +19536,34 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 19519 | const operand_info = operand_ty.ptrInfo().data; | 19536 | const operand_info = operand_ty.ptrInfo().data; |
| 19520 | const dest_info = dest_ty.ptrInfo().data; | 19537 | const dest_info = dest_ty.ptrInfo().data; |
| 19521 | if (!operand_info.mutable and dest_info.mutable) { | 19538 | if (!operand_info.mutable and dest_info.mutable) { |
| 19522 | return sema.fail(block, src, "cast discards const qualifier", .{}); | 19539 | const msg = msg: { |
| 19540 | const msg = try sema.errMsg(block, src, "cast discards const qualifier", .{}); | ||
| 19541 | errdefer msg.destroy(sema.gpa); | ||
| 19542 | |||
| 19543 | try sema.errNote(block, src, msg, "consider using '@qualCast'", .{}); | ||
| 19544 | break :msg msg; | ||
| 19545 | }; | ||
| 19546 | return sema.failWithOwnedErrorMsg(msg); | ||
| 19523 | } | 19547 | } |
| 19524 | if (operand_info.@"volatile" and !dest_info.@"volatile") { | 19548 | if (operand_info.@"volatile" and !dest_info.@"volatile") { |
| 19525 | return sema.fail(block, src, "cast discards volatile qualifier", .{}); | 19549 | const msg = msg: { |
| 19550 | const msg = try sema.errMsg(block, src, "cast discards volatile qualifier", .{}); | ||
| 19551 | errdefer msg.destroy(sema.gpa); | ||
| 19552 | |||
| 19553 | try sema.errNote(block, src, msg, "consider using '@qualCast'", .{}); | ||
| 19554 | break :msg msg; | ||
| 19555 | }; | ||
| 19556 | return sema.failWithOwnedErrorMsg(msg); | ||
| 19526 | } | 19557 | } |
| 19527 | if (operand_info.@"addrspace" != dest_info.@"addrspace") { | 19558 | if (operand_info.@"addrspace" != dest_info.@"addrspace") { |
| 19528 | return sema.fail(block, src, "cast changes pointer address space", .{}); | 19559 | const msg = msg: { |
| 19560 | const msg = try sema.errMsg(block, src, "cast changes pointer address space", .{}); | ||
| 19561 | errdefer msg.destroy(sema.gpa); | ||
| 19562 | |||
| 19563 | try sema.errNote(block, src, msg, "consider using '@addrSpaceCast'", .{}); | ||
| 19564 | break :msg msg; | ||
| 19565 | }; | ||
| 19566 | return sema.failWithOwnedErrorMsg(msg); | ||
| 19529 | } | 19567 | } |
| 19530 | 19568 | ||
| 19531 | const dest_is_slice = dest_ty.isSlice(); | 19569 | const dest_is_slice = dest_ty.isSlice(); |
| ... | @@ -19580,6 +19618,8 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -19580,6 +19618,8 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 19580 | try sema.errNote(block, dest_ty_src, msg, "'{}' has alignment '{d}'", .{ | 19618 | try sema.errNote(block, dest_ty_src, msg, "'{}' has alignment '{d}'", .{ |
| 19581 | dest_ty.fmt(sema.mod), dest_align, | 19619 | dest_ty.fmt(sema.mod), dest_align, |
| 19582 | }); | 19620 | }); |
| 19621 | |||
| 19622 | try sema.errNote(block, src, msg, "consider using '@alignCast'", .{}); | ||
| 19583 | break :msg msg; | 19623 | break :msg msg; |
| 19584 | }; | 19624 | }; |
| 19585 | return sema.failWithOwnedErrorMsg(msg); | 19625 | return sema.failWithOwnedErrorMsg(msg); |
| ... | @@ -19615,6 +19655,49 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -19615,6 +19655,49 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 19615 | return block.addBitCast(aligned_dest_ty, ptr); | 19655 | return block.addBitCast(aligned_dest_ty, ptr); |
| 19616 | } | 19656 | } |
| 19617 | 19657 | ||
| 19658 | fn zirQualCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | ||
| 19659 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 19660 | const src = inst_data.src(); | ||
| 19661 | const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | ||
| 19662 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; | ||
| 19663 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; | ||
| 19664 | const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs); | ||
| 19665 | const operand = try sema.resolveInst(extra.rhs); | ||
| 19666 | const operand_ty = sema.typeOf(operand); | ||
| 19667 | |||
| 19668 | try sema.checkPtrType(block, dest_ty_src, dest_ty); | ||
| 19669 | try sema.checkPtrOperand(block, operand_src, operand_ty); | ||
| 19670 | |||
| 19671 | var operand_payload = operand_ty.ptrInfo(); | ||
| 19672 | var dest_info = dest_ty.ptrInfo(); | ||
| 19673 | |||
| 19674 | operand_payload.data.mutable = dest_info.data.mutable; | ||
| 19675 | operand_payload.data.@"volatile" = dest_info.data.@"volatile"; | ||
| 19676 | |||
| 19677 | const altered_operand_ty = Type.initPayload(&operand_payload.base); | ||
| 19678 | if (!altered_operand_ty.eql(dest_ty, sema.mod)) { | ||
| 19679 | const msg = msg: { | ||
| 19680 | const msg = try sema.errMsg(block, src, "'@qualCast' can only modify 'const' and 'volatile' qualifiers", .{}); | ||
| 19681 | errdefer msg.destroy(sema.gpa); | ||
| 19682 | |||
| 19683 | dest_info.data.mutable = !operand_ty.isConstPtr(); | ||
| 19684 | dest_info.data.@"volatile" = operand_ty.isVolatilePtr(); | ||
| 19685 | const altered_dest_ty = Type.initPayload(&dest_info.base); | ||
| 19686 | try sema.errNote(block, src, msg, "expected type '{}'", .{altered_dest_ty.fmt(sema.mod)}); | ||
| 19687 | try sema.errNote(block, src, msg, "got type '{}'", .{operand_ty.fmt(sema.mod)}); | ||
| 19688 | break :msg msg; | ||
| 19689 | }; | ||
| 19690 | return sema.failWithOwnedErrorMsg(msg); | ||
| 19691 | } | ||
| 19692 | |||
| 19693 | if (try sema.resolveMaybeUndefVal(operand)) |operand_val| { | ||
| 19694 | return sema.addConstant(dest_ty, operand_val); | ||
| 19695 | } | ||
| 19696 | |||
| 19697 | try sema.requireRuntimeBlock(block, src, null); | ||
| 19698 | return block.addBitCast(dest_ty, operand); | ||
| 19699 | } | ||
| 19700 | |||
| 19618 | fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 19701 | fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 19619 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 19702 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 19620 | const src = inst_data.src(); | 19703 | const src = inst_data.src(); |
| ... | @@ -25131,7 +25214,7 @@ fn coerceExtra( | ... | @@ -25131,7 +25214,7 @@ fn coerceExtra( |
| 25131 | (try sema.coerceInMemoryAllowed(block, inst_ty.errorUnionPayload(), dest_ty, false, target, dest_ty_src, inst_src)) == .ok) | 25214 | (try sema.coerceInMemoryAllowed(block, inst_ty.errorUnionPayload(), dest_ty, false, target, dest_ty_src, inst_src)) == .ok) |
| 25132 | { | 25215 | { |
| 25133 | try sema.errNote(block, inst_src, msg, "cannot convert error union to payload type", .{}); | 25216 | try sema.errNote(block, inst_src, msg, "cannot convert error union to payload type", .{}); |
| 25134 | try sema.errNote(block, inst_src, msg, "consider using `try`, `catch`, or `if`", .{}); | 25217 | try sema.errNote(block, inst_src, msg, "consider using 'try', 'catch', or 'if'", .{}); |
| 25135 | } | 25218 | } |
| 25136 | 25219 | ||
| 25137 | // ?T to T | 25220 | // ?T to T |
| ... | @@ -25140,7 +25223,7 @@ fn coerceExtra( | ... | @@ -25140,7 +25223,7 @@ fn coerceExtra( |
| 25140 | (try sema.coerceInMemoryAllowed(block, inst_ty.optionalChild(&buf), dest_ty, false, target, dest_ty_src, inst_src)) == .ok) | 25223 | (try sema.coerceInMemoryAllowed(block, inst_ty.optionalChild(&buf), dest_ty, false, target, dest_ty_src, inst_src)) == .ok) |
| 25141 | { | 25224 | { |
| 25142 | try sema.errNote(block, inst_src, msg, "cannot convert optional to payload type", .{}); | 25225 | try sema.errNote(block, inst_src, msg, "cannot convert optional to payload type", .{}); |
| 25143 | try sema.errNote(block, inst_src, msg, "consider using `.?`, `orelse`, or `if`", .{}); | 25226 | try sema.errNote(block, inst_src, msg, "consider using '.?', 'orelse', or 'if'", .{}); |
| 25144 | } | 25227 | } |
| 25145 | 25228 | ||
| 25146 | try in_memory_result.report(sema, block, inst_src, msg); | 25229 | try in_memory_result.report(sema, block, inst_src, msg); |
src/TypedValue.zig+4-1| ... | @@ -176,7 +176,9 @@ pub fn print( | ... | @@ -176,7 +176,9 @@ pub fn print( |
| 176 | 176 | ||
| 177 | var i: u32 = 0; | 177 | var i: u32 = 0; |
| 178 | while (i < max_len) : (i += 1) { | 178 | while (i < max_len) : (i += 1) { |
| 179 | buf[i] = std.math.cast(u8, val.fieldValue(ty, i).toUnsignedInt(target)) orelse break :str; | 179 | const elem = val.fieldValue(ty, i); |
| 180 | if (elem.isUndef()) break :str; | ||
| 181 | buf[i] = std.math.cast(u8, elem.toUnsignedInt(target)) orelse break :str; | ||
| 180 | } | 182 | } |
| 181 | 183 | ||
| 182 | const truncated = if (len > max_string_len) " (truncated)" else ""; | 184 | const truncated = if (len > max_string_len) " (truncated)" else ""; |
| ... | @@ -390,6 +392,7 @@ pub fn print( | ... | @@ -390,6 +392,7 @@ pub fn print( |
| 390 | while (i < max_len) : (i += 1) { | 392 | while (i < max_len) : (i += 1) { |
| 391 | var elem_buf: Value.ElemValueBuffer = undefined; | 393 | var elem_buf: Value.ElemValueBuffer = undefined; |
| 392 | const elem_val = payload.ptr.elemValueBuffer(mod, i, &elem_buf); | 394 | const elem_val = payload.ptr.elemValueBuffer(mod, i, &elem_buf); |
| 395 | if (elem_val.isUndef()) break :str; | ||
| 393 | buf[i] = std.math.cast(u8, elem_val.toUnsignedInt(target)) orelse break :str; | 396 | buf[i] = std.math.cast(u8, elem_val.toUnsignedInt(target)) orelse break :str; |
| 394 | } | 397 | } |
| 395 | 398 |
src/Zir.zig+6| ... | @@ -857,6 +857,9 @@ pub const Inst = struct { | ... | @@ -857,6 +857,9 @@ pub const Inst = struct { |
| 857 | /// Implements the `@ptrCast` builtin. | 857 | /// Implements the `@ptrCast` builtin. |
| 858 | /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand. | 858 | /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand. |
| 859 | ptr_cast, | 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 | /// Implements the `@truncate` builtin. | 863 | /// Implements the `@truncate` builtin. |
| 861 | /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand. | 864 | /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand. |
| 862 | truncate, | 865 | truncate, |
| ... | @@ -1195,6 +1198,7 @@ pub const Inst = struct { | ... | @@ -1195,6 +1198,7 @@ pub const Inst = struct { |
| 1195 | .float_cast, | 1198 | .float_cast, |
| 1196 | .int_cast, | 1199 | .int_cast, |
| 1197 | .ptr_cast, | 1200 | .ptr_cast, |
| 1201 | .qual_cast, | ||
| 1198 | .truncate, | 1202 | .truncate, |
| 1199 | .align_cast, | 1203 | .align_cast, |
| 1200 | .has_field, | 1204 | .has_field, |
| ... | @@ -1484,6 +1488,7 @@ pub const Inst = struct { | ... | @@ -1484,6 +1488,7 @@ pub const Inst = struct { |
| 1484 | .float_cast, | 1488 | .float_cast, |
| 1485 | .int_cast, | 1489 | .int_cast, |
| 1486 | .ptr_cast, | 1490 | .ptr_cast, |
| 1491 | .qual_cast, | ||
| 1487 | .truncate, | 1492 | .truncate, |
| 1488 | .align_cast, | 1493 | .align_cast, |
| 1489 | .has_field, | 1494 | .has_field, |
| ... | @@ -1755,6 +1760,7 @@ pub const Inst = struct { | ... | @@ -1755,6 +1760,7 @@ pub const Inst = struct { |
| 1755 | .float_cast = .pl_node, | 1760 | .float_cast = .pl_node, |
| 1756 | .int_cast = .pl_node, | 1761 | .int_cast = .pl_node, |
| 1757 | .ptr_cast = .pl_node, | 1762 | .ptr_cast = .pl_node, |
| 1763 | .qual_cast = .pl_node, | ||
| 1758 | .truncate = .pl_node, | 1764 | .truncate = .pl_node, |
| 1759 | .align_cast = .pl_node, | 1765 | .align_cast = .pl_node, |
| 1760 | .typeof_builtin = .pl_node, | 1766 | .typeof_builtin = .pl_node, |
src/print_zir.zig+1| ... | @@ -332,6 +332,7 @@ const Writer = struct { | ... | @@ -332,6 +332,7 @@ const Writer = struct { |
| 332 | .float_cast, | 332 | .float_cast, |
| 333 | .int_cast, | 333 | .int_cast, |
| 334 | .ptr_cast, | 334 | .ptr_cast, |
| 335 | .qual_cast, | ||
| 335 | .truncate, | 336 | .truncate, |
| 336 | .align_cast, | 337 | .align_cast, |
| 337 | .div_exact, | 338 | .div_exact, |
stage1/zig1.wasm| Binary files a/stage1/zig1.wasm and b/stage1/zig1.wasm differ | |||
test/behavior/basic.zig+18| ... | @@ -1125,3 +1125,21 @@ test "returning an opaque type from a function" { | ... | @@ -1125,3 +1125,21 @@ test "returning an opaque type from a function" { |
| 1125 | }; | 1125 | }; |
| 1126 | try expect(S.foo(123).b == 123); | 1126 | try expect(S.foo(123).b == 123); |
| 1127 | } | 1127 | } |
| 1128 | |||
| 1129 | test "orelse coercion as function argument" { | ||
| 1130 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | ||
| 1131 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 1132 | |||
| 1133 | const Loc = struct { start: i32 = -1 }; | ||
| 1134 | const Container = struct { | ||
| 1135 | a: ?Loc = null, | ||
| 1136 | fn init(a: Loc) @This() { | ||
| 1137 | return .{ | ||
| 1138 | .a = a, | ||
| 1139 | }; | ||
| 1140 | } | ||
| 1141 | }; | ||
| 1142 | var optional: ?Loc = .{}; | ||
| 1143 | var foo = Container.init(optional orelse .{}); | ||
| 1144 | try expect(foo.a.?.start == -1); | ||
| 1145 | } |
test/behavior/sizeof_and_typeof.zig+9| ... | @@ -292,3 +292,12 @@ test "@sizeOf optional of previously unresolved union" { | ... | @@ -292,3 +292,12 @@ test "@sizeOf optional of previously unresolved union" { |
| 292 | const Node = union { a: usize }; | 292 | const Node = union { a: usize }; |
| 293 | try expect(@sizeOf(?Node) == @sizeOf(Node) + @alignOf(Node)); | 293 | try expect(@sizeOf(?Node) == @sizeOf(Node) + @alignOf(Node)); |
| 294 | } | 294 | } |
| 295 | |||
| 296 | test "@offsetOf zero-bit field" { | ||
| 297 | const S = packed struct { | ||
| 298 | a: u32, | ||
| 299 | b: u0, | ||
| 300 | c: u32, | ||
| 301 | }; | ||
| 302 | try expect(@offsetOf(S, "b") == @offsetOf(S, "c")); | ||
| 303 | } |
test/cases/compile_errors/assigning_to_struct_or_union_fields_that_are_not_optionals_with_a_function_that_returns_an_optional.zig+1-1| ... | @@ -20,4 +20,4 @@ export fn entry() void { | ... | @@ -20,4 +20,4 @@ export fn entry() void { |
| 20 | // | 20 | // |
| 21 | // :11:27: error: expected type 'u8', found '?u8' | 21 | // :11:27: error: expected type 'u8', found '?u8' |
| 22 | // :11:27: note: cannot convert optional to payload type | 22 | // :11:27: note: cannot convert optional to payload type |
| 23 | // :11:27: note: consider using `.?`, `orelse`, or `if` | 23 | // :11:27: note: consider using '.?', 'orelse', or 'if' |
test/cases/compile_errors/comptime_arg_to_generic_fn_callee_error.zig created+21| ... | @@ -0,0 +1,21 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const MyStruct = struct { | ||
| 3 | a: i32, | ||
| 4 | b: i32, | ||
| 5 | |||
| 6 | pub fn getA(self: *List) i32 { | ||
| 7 | return self.items(.c); | ||
| 8 | } | ||
| 9 | }; | ||
| 10 | const List = std.MultiArrayList(MyStruct); | ||
| 11 | pub export fn entry() void { | ||
| 12 | var list = List{}; | ||
| 13 | _ = MyStruct.getA(&list); | ||
| 14 | } | ||
| 15 | |||
| 16 | // error | ||
| 17 | // backend=stage2 | ||
| 18 | // target=native | ||
| 19 | // | ||
| 20 | // :7:28: error: no field named 'c' in enum 'meta.FieldEnum(tmp.MyStruct)' | ||
| 21 | // :?:?: note: enum declared here | ||
test/cases/compile_errors/discarding_error_value.zig+1-1| ... | @@ -10,4 +10,4 @@ fn foo() !void { | ... | @@ -10,4 +10,4 @@ fn foo() !void { |
| 10 | // target=native | 10 | // target=native |
| 11 | // | 11 | // |
| 12 | // :2:12: error: error is discarded | 12 | // :2:12: error: error is discarded |
| 13 | // :2:12: note: consider using `try`, `catch`, or `if` | 13 | // :2:12: note: consider using 'try', 'catch', or 'if' |
test/cases/compile_errors/helpful_return_type_error_message.zig+2-2| ... | @@ -26,7 +26,7 @@ export fn quux() u32 { | ... | @@ -26,7 +26,7 @@ export fn quux() u32 { |
| 26 | // :11:15: error: expected type 'u32', found '@typeInfo(@typeInfo(@TypeOf(tmp.bar)).Fn.return_type.?).ErrorUnion.error_set!u32' | 26 | // :11:15: error: expected type 'u32', found '@typeInfo(@typeInfo(@TypeOf(tmp.bar)).Fn.return_type.?).ErrorUnion.error_set!u32' |
| 27 | // :10:17: note: function cannot return an error | 27 | // :10:17: note: function cannot return an error |
| 28 | // :11:15: note: cannot convert error union to payload type | 28 | // :11:15: note: cannot convert error union to payload type |
| 29 | // :11:15: note: consider using `try`, `catch`, or `if` | 29 | // :11:15: note: consider using 'try', 'catch', or 'if' |
| 30 | // :15:14: error: expected type 'u32', found '@typeInfo(@typeInfo(@TypeOf(tmp.bar)).Fn.return_type.?).ErrorUnion.error_set!u32' | 30 | // :15:14: error: expected type 'u32', found '@typeInfo(@typeInfo(@TypeOf(tmp.bar)).Fn.return_type.?).ErrorUnion.error_set!u32' |
| 31 | // :15:14: note: cannot convert error union to payload type | 31 | // :15:14: note: cannot convert error union to payload type |
| 32 | // :15:14: note: consider using `try`, `catch`, or `if` | 32 | // :15:14: note: consider using 'try', 'catch', or 'if' |
test/cases/compile_errors/ignored_deferred_function_call.zig+1-1| ... | @@ -8,4 +8,4 @@ fn bar() anyerror!i32 { return 0; } | ... | @@ -8,4 +8,4 @@ fn bar() anyerror!i32 { return 0; } |
| 8 | // target=native | 8 | // target=native |
| 9 | // | 9 | // |
| 10 | // :2:14: error: error is ignored | 10 | // :2:14: error: error is ignored |
| 11 | // :2:14: note: consider using `try`, `catch`, or `if` | 11 | // :2:14: note: consider using 'try', 'catch', or 'if' |
test/cases/compile_errors/ignored_expression_in_while_continuation.zig+3-3| ... | @@ -18,8 +18,8 @@ fn bad() anyerror!void { | ... | @@ -18,8 +18,8 @@ fn bad() anyerror!void { |
| 18 | // target=native | 18 | // target=native |
| 19 | // | 19 | // |
| 20 | // :2:24: error: error is ignored | 20 | // :2:24: error: error is ignored |
| 21 | // :2:24: note: consider using `try`, `catch`, or `if` | 21 | // :2:24: note: consider using 'try', 'catch', or 'if' |
| 22 | // :6:25: error: error is ignored | 22 | // :6:25: error: error is ignored |
| 23 | // :6:25: note: consider using `try`, `catch`, or `if` | 23 | // :6:25: note: consider using 'try', 'catch', or 'if' |
| 24 | // :10:25: error: error is ignored | 24 | // :10:25: error: error is ignored |
| 25 | // :10:25: note: consider using `try`, `catch`, or `if` | 25 | // :10:25: note: consider using 'try', 'catch', or 'if' |
test/cases/compile_errors/increase_pointer_alignment_in_ptrCast.zig+1| ... | @@ -11,3 +11,4 @@ export fn entry() u32 { | ... | @@ -11,3 +11,4 @@ export fn entry() u32 { |
| 11 | // :3:17: error: cast increases pointer alignment | 11 | // :3:17: error: cast increases pointer alignment |
| 12 | // :3:32: note: '*u8' has alignment '1' | 12 | // :3:32: note: '*u8' has alignment '1' |
| 13 | // :3:26: note: '*u32' has alignment '4' | 13 | // :3:26: note: '*u32' has alignment '4' |
| 14 | // :3:17: note: consider using '@alignCast' |
test/cases/compile_errors/inline_call_runtime_value_to_comptime_param.zig created+17| ... | @@ -0,0 +1,17 @@ | ||
| 1 | inline fn needComptime(comptime a: u64) void { | ||
| 2 | if (a != 0) @compileError("foo"); | ||
| 3 | } | ||
| 4 | fn acceptRuntime(value: u64) void { | ||
| 5 | needComptime(value); | ||
| 6 | } | ||
| 7 | pub export fn entry() void { | ||
| 8 | var value: u64 = 0; | ||
| 9 | acceptRuntime(value); | ||
| 10 | } | ||
| 11 | |||
| 12 | // error | ||
| 13 | // backend=stage2 | ||
| 14 | // target=native | ||
| 15 | // | ||
| 16 | // :5:18: error: unable to resolve comptime value | ||
| 17 | // :5:18: note: parameter is comptime | ||
test/cases/compile_errors/invalid_decltest.zig created+13| ... | @@ -0,0 +1,13 @@ | ||
| 1 | export fn foo() void { | ||
| 2 | const a = 1; | ||
| 3 | struct { | ||
| 4 | test a {} | ||
| 5 | }; | ||
| 6 | } | ||
| 7 | |||
| 8 | // error | ||
| 9 | // backend=stage2 | ||
| 10 | // target=native | ||
| 11 | // | ||
| 12 | // :4:14: error: cannot test a local constant | ||
| 13 | // :2:11: note: local constant declared here | ||
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/issue_5618_coercion_of_optional_anyopaque_to_anyopaque_must_fail.zig+1-1| ... | @@ -10,5 +10,5 @@ export fn foo() void { | ... | @@ -10,5 +10,5 @@ export fn foo() void { |
| 10 | // | 10 | // |
| 11 | // :4:9: error: expected type '*anyopaque', found '?*anyopaque' | 11 | // :4:9: error: expected type '*anyopaque', found '?*anyopaque' |
| 12 | // :4:9: note: cannot convert optional to payload type | 12 | // :4:9: note: cannot convert optional to payload type |
| 13 | // :4:9: note: consider using `.?`, `orelse`, or `if` | 13 | // :4:9: note: consider using '.?', 'orelse', or 'if' |
| 14 | // :4:9: note: '?*anyopaque' could have null values which are illegal in type '*anyopaque' | 14 | // :4:9: note: '?*anyopaque' could have null values which are illegal in type '*anyopaque' |
test/cases/compile_errors/ptrCast_discards_const_qualifier.zig+1| ... | @@ -9,3 +9,4 @@ export fn entry() void { | ... | @@ -9,3 +9,4 @@ export fn entry() void { |
| 9 | // target=native | 9 | // target=native |
| 10 | // | 10 | // |
| 11 | // :3:15: error: cast discards const qualifier | 11 | // :3:15: error: cast discards const qualifier |
| 12 | // :3:15: note: consider using '@qualCast' |
test/cases/compile_errors/regression_test_2980_base_type_u32_is_not_type_checked_properly_when_assigning_a_value_within_a_struct.zig+1-1| ... | @@ -20,4 +20,4 @@ export fn entry() void { | ... | @@ -20,4 +20,4 @@ export fn entry() void { |
| 20 | // | 20 | // |
| 21 | // :12:25: error: expected type 'u32', found '@typeInfo(@typeInfo(@TypeOf(tmp.get_uval)).Fn.return_type.?).ErrorUnion.error_set!u32' | 21 | // :12:25: error: expected type 'u32', found '@typeInfo(@typeInfo(@TypeOf(tmp.get_uval)).Fn.return_type.?).ErrorUnion.error_set!u32' |
| 22 | // :12:25: note: cannot convert error union to payload type | 22 | // :12:25: note: cannot convert error union to payload type |
| 23 | // :12:25: note: consider using `try`, `catch`, or `if` | 23 | // :12:25: note: consider using 'try', 'catch', or 'if' |
test/cases/compile_errors/result_location_incompatibility_mismatching_handle_is_ptr.zig+1-1| ... | @@ -17,4 +17,4 @@ pub const Container = struct { | ... | @@ -17,4 +17,4 @@ pub const Container = struct { |
| 17 | // | 17 | // |
| 18 | // :3:36: error: expected type 'i32', found '?i32' | 18 | // :3:36: error: expected type 'i32', found '?i32' |
| 19 | // :3:36: note: cannot convert optional to payload type | 19 | // :3:36: note: cannot convert optional to payload type |
| 20 | // :3:36: note: consider using `.?`, `orelse`, or `if` | 20 | // :3:36: note: consider using '.?', 'orelse', or 'if' |
test/cases/compile_errors/result_location_incompatibility_mismatching_handle_is_ptr_generic_call.zig+1-1| ... | @@ -17,4 +17,4 @@ pub const Container = struct { | ... | @@ -17,4 +17,4 @@ pub const Container = struct { |
| 17 | // | 17 | // |
| 18 | // :3:36: error: expected type 'i32', found '?i32' | 18 | // :3:36: error: expected type 'i32', found '?i32' |
| 19 | // :3:36: note: cannot convert optional to payload type | 19 | // :3:36: note: cannot convert optional to payload type |
| 20 | // :3:36: note: consider using `.?`, `orelse`, or `if` | 20 | // :3:36: note: consider using '.?', 'orelse', or 'if' |