authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-02-01 23:31:52-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-02-01 23:31:52-05:00
log6b7ad22981867cbf6ec40d540f5571f276d6801b
tree4c1665cf0c03fcaa5d6c2a09aa49c49f5b804236
parente712d5f03e6e3ddde6a4a6f7d2d82e786efd543a
parent629c3108aa71f94bd26dba8d4f20c9f3a3945bd4
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #14477 from Vexu/fixes

Improve `@ptrCast` errors, fix some bugs

30 files changed, 280 insertions(+), 36 deletions(-)

doc/langref.html.in+16
......@@ -8809,6 +8809,15 @@ pub const PrefetchOptions = struct {
88098809 {#link|Optional Pointers#} are allowed. Casting an optional pointer which is {#link|null#}
88108810 to a non-optional pointer invokes safety-checked {#link|Undefined Behavior#}.
88118811 </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>
88128821 {#header_close#}
88138822
88148823 {#header_open|@ptrToInt#}
......@@ -8821,6 +8830,13 @@ pub const PrefetchOptions = struct {
88218830
88228831 {#header_close#}
88238832
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
88248840 {#header_open|@rem#}
88258841 <pre>{#syntax#}@rem(numerator: T, denominator: T) T{#endsyntax#}</pre>
88268842 <p>
lib/std/child_process.zig+2-2
......@@ -1164,7 +1164,7 @@ fn windowsCreateProcessPathExt(
11641164 var app_name_unicode_string = windows.UNICODE_STRING{
11651165 .Length = app_name_len_bytes,
11661166 .MaximumLength = app_name_len_bytes,
1167 .Buffer = @intToPtr([*]u16, @ptrToInt(app_name_wildcard.ptr)),
1167 .Buffer = @qualCast([*:0]u16, app_name_wildcard.ptr),
11681168 };
11691169 const rc = windows.ntdll.NtQueryDirectoryFile(
11701170 dir.fd,
......@@ -1261,7 +1261,7 @@ fn windowsCreateProcessPathExt(
12611261 var app_name_unicode_string = windows.UNICODE_STRING{
12621262 .Length = app_name_len_bytes,
12631263 .MaximumLength = app_name_len_bytes,
1264 .Buffer = @intToPtr([*]u16, @ptrToInt(app_name_appended.ptr)),
1264 .Buffer = @qualCast([*:0]u16, app_name_appended.ptr),
12651265 };
12661266
12671267 // 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 {
17631763 var nt_name = w.UNICODE_STRING{
17641764 .Length = path_len_bytes,
17651765 .MaximumLength = path_len_bytes,
1766 .Buffer = @intToPtr([*]u16, @ptrToInt(sub_path_w)),
1766 .Buffer = @qualCast([*:0]u16, sub_path_w),
17671767 };
17681768 var attr = w.OBJECT_ATTRIBUTES{
17691769 .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
45134513 var nt_name = windows.UNICODE_STRING{
45144514 .Length = path_len_bytes,
45154515 .MaximumLength = path_len_bytes,
4516 .Buffer = @intToPtr([*]u16, @ptrToInt(sub_path_w)),
4516 .Buffer = @qualCast([*:0]u16, sub_path_w),
45174517 };
45184518 var attr = windows.OBJECT_ATTRIBUTES{
45194519 .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
8585 var nt_name = UNICODE_STRING{
8686 .Length = path_len_bytes,
8787 .MaximumLength = path_len_bytes,
88 .Buffer = @intToPtr([*]u16, @ptrToInt(sub_path_w.ptr)),
88 .Buffer = @qualCast([*]u16, sub_path_w.ptr),
8989 };
9090 var attr = OBJECT_ATTRIBUTES{
9191 .Length = @sizeOf(OBJECT_ATTRIBUTES),
......@@ -634,7 +634,7 @@ pub fn SetCurrentDirectory(path_name: []const u16) SetCurrentDirectoryError!void
634634 var nt_name = UNICODE_STRING{
635635 .Length = path_len_bytes,
636636 .MaximumLength = path_len_bytes,
637 .Buffer = @intToPtr([*]u16, @ptrToInt(path_name.ptr)),
637 .Buffer = @qualCast([*]u16, path_name.ptr),
638638 };
639639
640640 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
766766 var nt_name = UNICODE_STRING{
767767 .Length = path_len_bytes,
768768 .MaximumLength = path_len_bytes,
769 .Buffer = @intToPtr([*]u16, @ptrToInt(sub_path_w.ptr)),
769 .Buffer = @qualCast([*]u16, sub_path_w.ptr),
770770 };
771771 var attr = OBJECT_ATTRIBUTES{
772772 .Length = @sizeOf(OBJECT_ATTRIBUTES),
......@@ -876,7 +876,7 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil
876876 .Length = path_len_bytes,
877877 .MaximumLength = path_len_bytes,
878878 // 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),
880880 };
881881
882882 if (sub_path_w[0] == '.' and sub_path_w[1] == 0) {
......@@ -1414,7 +1414,7 @@ pub fn sendmsg(
14141414}
14151415
14161416pub 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) };
14181418 var bytes_send: DWORD = undefined;
14191419 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) {
14201420 return ws2_32.SOCKET_ERROR;
......@@ -1876,13 +1876,13 @@ pub fn eqlIgnoreCaseWTF16(a: []const u16, b: []const u16) bool {
18761876 const a_string = UNICODE_STRING{
18771877 .Length = a_bytes,
18781878 .MaximumLength = a_bytes,
1879 .Buffer = @intToPtr([*]u16, @ptrToInt(a.ptr)),
1879 .Buffer = @qualCast([*]u16, a.ptr),
18801880 };
18811881 const b_bytes = @intCast(u16, b.len * 2);
18821882 const b_string = UNICODE_STRING{
18831883 .Length = b_bytes,
18841884 .MaximumLength = b_bytes,
1885 .Buffer = @intToPtr([*]u16, @ptrToInt(b.ptr)),
1885 .Buffer = @qualCast([*]u16, b.ptr),
18861886 };
18871887 return ntdll.RtlEqualUnicodeString(&a_string, &b_string, TRUE) == TRUE;
18881888}
lib/std/zig/c_translation.zig+1-1
......@@ -75,7 +75,7 @@ fn castPtr(comptime DestType: type, target: anytype) DestType {
7575 const source = ptrInfo(@TypeOf(target));
7676
7777 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)
7979 else if (@typeInfo(dest.child) == .Opaque)
8080 // dest.alignment would error out
8181 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
25302530 .bit_size_of,
25312531 .typeof_log2_int_type,
25322532 .ptr_to_int,
2533 .qual_cast,
25332534 .align_of,
25342535 .bool_to_int,
25352536 .embed_file,
......@@ -4278,7 +4279,34 @@ fn testDecl(
42784279 var num_namespaces_out: u32 = 0;
42794280 var capturing_namespace: ?*Scope.Namespace = null;
42804281 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 },
42824310 .gen_zir => s = s.cast(GenZir).?.parent,
42834311 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
42844312 .namespace, .enum_namespace => {
......@@ -8010,6 +8038,7 @@ fn builtinCall(
80108038 .float_cast => return typeCast(gz, scope, ri, node, params[0], params[1], .float_cast),
80118039 .int_cast => return typeCast(gz, scope, ri, node, params[0], params[1], .int_cast),
80128040 .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),
80138042 .truncate => return typeCast(gz, scope, ri, node, params[0], params[1], .truncate),
80148043 // zig fmt: on
80158044
......@@ -8692,6 +8721,7 @@ fn callExpr(
86928721 defer arg_block.unstack();
86938722
86948723 // `call_inst` is reused to provide the param type.
8724 arg_block.rl_ty_inst = call_inst;
86958725 const arg_ref = try expr(&arg_block, &arg_block.base, .{ .rl = .{ .coerced_ty = call_inst }, .ctx = .fn_arg }, param_node);
86968726 _ = try arg_block.addBreak(.break_inline, call_index, arg_ref);
86978727
......@@ -10840,7 +10870,12 @@ const GenZir = struct {
1084010870 // we emit ZIR for the block break instructions to have the result values,
1084110871 // and then rvalue() on that to pass the value to the result location.
1084210872 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| {
1084410879 gz.rl_ty_inst = ty_inst;
1084510880 gz.break_result_info = parent_ri;
1084610881 },
src/BuiltinFn.zig+8
......@@ -75,6 +75,7 @@ pub const Tag = enum {
7575 prefetch,
7676 ptr_cast,
7777 ptr_to_int,
78 qual_cast,
7879 rem,
7980 return_address,
8081 select,
......@@ -674,6 +675,13 @@ pub const list = list: {
674675 .param_count = 1,
675676 },
676677 },
678 .{
679 "@qualCast",
680 .{
681 .tag = .qual_cast,
682 .param_count = 2,
683 },
684 },
677685 .{
678686 "@rem",
679687 .{
src/Sema.zig+92-9
......@@ -1015,6 +1015,7 @@ fn analyzeBodyInner(
10151015 .float_cast => try sema.zirFloatCast(block, inst),
10161016 .int_cast => try sema.zirIntCast(block, inst),
10171017 .ptr_cast => try sema.zirPtrCast(block, inst),
1018 .qual_cast => try sema.zirQualCast(block, inst),
10181019 .truncate => try sema.zirTruncate(block, inst),
10191020 .align_cast => try sema.zirAlignCast(block, inst),
10201021 .has_decl => try sema.zirHasDecl(block, inst),
......@@ -3294,7 +3295,7 @@ fn ensureResultUsed(
32943295 const msg = msg: {
32953296 const msg = try sema.errMsg(block, src, "error is ignored", .{});
32963297 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'", .{});
32983299 break :msg msg;
32993300 };
33003301 return sema.failWithOwnedErrorMsg(msg);
......@@ -3325,7 +3326,7 @@ fn zirEnsureResultNonError(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
33253326 const msg = msg: {
33263327 const msg = try sema.errMsg(block, src, "error is discarded", .{});
33273328 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'", .{});
33293330 break :msg msg;
33303331 };
33313332 return sema.failWithOwnedErrorMsg(msg);
......@@ -6874,6 +6875,8 @@ fn analyzeInlineCallArg(
68746875 if (err == error.AnalysisFail and param_block.comptime_reason != null) try param_block.comptime_reason.?.explain(sema, sema.err);
68756876 return err;
68766877 };
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");
68776880 }
68786881 const casted_arg = sema.coerceExtra(arg_block, param_ty, uncasted_arg, arg_src, .{ .param_src = .{
68796882 .func_inst = func_inst,
......@@ -6947,6 +6950,9 @@ fn analyzeInlineCallArg(
69476950 .val = arg_val,
69486951 };
69496952 } else {
6953 if (zir_tags[inst] == .param_anytype_comptime) {
6954 _ = try sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "parameter is comptime");
6955 }
69506956 sema.inst_map.putAssumeCapacityNoClobber(inst, uncasted_arg);
69516957 }
69526958
......@@ -8467,7 +8473,7 @@ fn handleExternLibName(
84678473 return sema.fail(
84688474 block,
84698475 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'.",
84718477 .{ lib_name, lib_name },
84728478 );
84738479 }
......@@ -9004,7 +9010,18 @@ fn zirParam(
90049010 if (is_comptime and sema.preallocated_new_func != null) {
90059011 // We have a comptime value for this parameter so it should be elided from the
90069012 // 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 };
90089025 sema.inst_map.putAssumeCapacity(inst, coerced_arg);
90099026 return;
90109027 }
......@@ -19519,13 +19536,34 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1951919536 const operand_info = operand_ty.ptrInfo().data;
1952019537 const dest_info = dest_ty.ptrInfo().data;
1952119538 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);
1952319547 }
1952419548 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);
1952619557 }
1952719558 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);
1952919567 }
1953019568
1953119569 const dest_is_slice = dest_ty.isSlice();
......@@ -19580,6 +19618,8 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1958019618 try sema.errNote(block, dest_ty_src, msg, "'{}' has alignment '{d}'", .{
1958119619 dest_ty.fmt(sema.mod), dest_align,
1958219620 });
19621
19622 try sema.errNote(block, src, msg, "consider using '@alignCast'", .{});
1958319623 break :msg msg;
1958419624 };
1958519625 return sema.failWithOwnedErrorMsg(msg);
......@@ -19615,6 +19655,49 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1961519655 return block.addBitCast(aligned_dest_ty, ptr);
1961619656}
1961719657
19658fn 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
1961819701fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
1961919702 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1962019703 const src = inst_data.src();
......@@ -25131,7 +25214,7 @@ fn coerceExtra(
2513125214 (try sema.coerceInMemoryAllowed(block, inst_ty.errorUnionPayload(), dest_ty, false, target, dest_ty_src, inst_src)) == .ok)
2513225215 {
2513325216 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'", .{});
2513525218 }
2513625219
2513725220 // ?T to T
......@@ -25140,7 +25223,7 @@ fn coerceExtra(
2514025223 (try sema.coerceInMemoryAllowed(block, inst_ty.optionalChild(&buf), dest_ty, false, target, dest_ty_src, inst_src)) == .ok)
2514125224 {
2514225225 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'", .{});
2514425227 }
2514525228
2514625229 try in_memory_result.report(sema, block, inst_src, msg);
src/TypedValue.zig+4-1
......@@ -176,7 +176,9 @@ pub fn print(
176176
177177 var i: u32 = 0;
178178 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;
180182 }
181183
182184 const truncated = if (len > max_string_len) " (truncated)" else "";
......@@ -390,6 +392,7 @@ pub fn print(
390392 while (i < max_len) : (i += 1) {
391393 var elem_buf: Value.ElemValueBuffer = undefined;
392394 const elem_val = payload.ptr.elemValueBuffer(mod, i, &elem_buf);
395 if (elem_val.isUndef()) break :str;
393396 buf[i] = std.math.cast(u8, elem_val.toUnsignedInt(target)) orelse break :str;
394397 }
395398
src/Zir.zig+6
......@@ -857,6 +857,9 @@ pub const Inst = struct {
857857 /// Implements the `@ptrCast` builtin.
858858 /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand.
859859 ptr_cast,
860 /// Implements the `@qualCast` builtin.
861 /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand.
862 qual_cast,
860863 /// Implements the `@truncate` builtin.
861864 /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand.
862865 truncate,
......@@ -1195,6 +1198,7 @@ pub const Inst = struct {
11951198 .float_cast,
11961199 .int_cast,
11971200 .ptr_cast,
1201 .qual_cast,
11981202 .truncate,
11991203 .align_cast,
12001204 .has_field,
......@@ -1484,6 +1488,7 @@ pub const Inst = struct {
14841488 .float_cast,
14851489 .int_cast,
14861490 .ptr_cast,
1491 .qual_cast,
14871492 .truncate,
14881493 .align_cast,
14891494 .has_field,
......@@ -1755,6 +1760,7 @@ pub const Inst = struct {
17551760 .float_cast = .pl_node,
17561761 .int_cast = .pl_node,
17571762 .ptr_cast = .pl_node,
1763 .qual_cast = .pl_node,
17581764 .truncate = .pl_node,
17591765 .align_cast = .pl_node,
17601766 .typeof_builtin = .pl_node,
src/print_zir.zig+1
......@@ -332,6 +332,7 @@ const Writer = struct {
332332 .float_cast,
333333 .int_cast,
334334 .ptr_cast,
335 .qual_cast,
335336 .truncate,
336337 .align_cast,
337338 .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" {
11251125 };
11261126 try expect(S.foo(123).b == 123);
11271127}
1128
1129test "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" {
292292 const Node = union { a: usize };
293293 try expect(@sizeOf(?Node) == @sizeOf(Node) + @alignOf(Node));
294294}
295
296test "@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 {
2020//
2121// :11:27: error: expected type 'u8', found '?u8'
2222// :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 @@
1const std = @import("std");
2const MyStruct = struct {
3 a: i32,
4 b: i32,
5
6 pub fn getA(self: *List) i32 {
7 return self.items(.c);
8 }
9};
10const List = std.MultiArrayList(MyStruct);
11pub 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 {
1010// target=native
1111//
1212// :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 {
2626// :11:15: error: expected type 'u32', found '@typeInfo(@typeInfo(@TypeOf(tmp.bar)).Fn.return_type.?).ErrorUnion.error_set!u32'
2727// :10:17: note: function cannot return an error
2828// :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'
3030// :15:14: error: expected type 'u32', found '@typeInfo(@typeInfo(@TypeOf(tmp.bar)).Fn.return_type.?).ErrorUnion.error_set!u32'
3131// :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; }
88// target=native
99//
1010// :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 {
1818// target=native
1919//
2020// :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'
2222// :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'
2424// :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 {
1111// :3:17: error: cast increases pointer alignment
1212// :3:32: note: '*u8' has alignment '1'
1313// :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 @@
1inline fn needComptime(comptime a: u64) void {
2 if (a != 0) @compileError("foo");
3}
4fn acceptRuntime(value: u64) void {
5 needComptime(value);
6}
7pub 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 @@
1export 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 @@
1pub 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 {
1010//
1111// :4:9: error: expected type '*anyopaque', found '?*anyopaque'
1212// :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'
1414// :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 {
99// target=native
1010//
1111// :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 {
2020//
2121// :12:25: error: expected type 'u32', found '@typeInfo(@typeInfo(@TypeOf(tmp.get_uval)).Fn.return_type.?).ErrorUnion.error_set!u32'
2222// :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 {
1717//
1818// :3:36: error: expected type 'i32', found '?i32'
1919// :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 {
1717//
1818// :3:36: error: expected type 'i32', found '?i32'
1919// :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'