| author | |
| committer | |
| log | af958e95cc0a78404e604400f509ea0c219614d1 |
| tree | 899f3b4d0a2de3c89b9fb5d66fd4934a38cdad9f |
| parent | fd57487e3593dfd0bc9c62a945bcf57f16ff6fae |
Improve error messages, fix dependency loops40 files changed, 377 insertions(+), 94 deletions(-)
lib/std/fs.zig-2| ... | @@ -809,8 +809,6 @@ pub const IterableDir = struct { | ... | @@ -809,8 +809,6 @@ pub const IterableDir = struct { |
| 809 | // and we avoid the code complexity here. | 809 | // and we avoid the code complexity here. |
| 810 | const w = os.wasi; | 810 | const w = os.wasi; |
| 811 | start_over: while (true) { | 811 | start_over: while (true) { |
| 812 | // TODO https://github.com/ziglang/zig/issues/12498 | ||
| 813 | _ = @sizeOf(w.dirent_t) + 1; | ||
| 814 | // According to the WASI spec, the last entry might be truncated, | 812 | // According to the WASI spec, the last entry might be truncated, |
| 815 | // so we need to check if the left buffer contains the whole dirent. | 813 | // so we need to check if the left buffer contains the whole dirent. |
| 816 | if (self.end_index - self.index < @sizeOf(w.dirent_t)) { | 814 | if (self.end_index - self.index < @sizeOf(w.dirent_t)) { |
src/AstGen.zig+41-7| ... | @@ -2625,7 +2625,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As | ... | @@ -2625,7 +2625,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As |
| 2625 | .compile_error, | 2625 | .compile_error, |
| 2626 | .ret_node, | 2626 | .ret_node, |
| 2627 | .ret_load, | 2627 | .ret_load, |
| 2628 | .ret_tok, | 2628 | .ret_implicit, |
| 2629 | .ret_err_value, | 2629 | .ret_err_value, |
| 2630 | .@"unreachable", | 2630 | .@"unreachable", |
| 2631 | .repeat, | 2631 | .repeat, |
| ... | @@ -3689,6 +3689,29 @@ fn fnDecl( | ... | @@ -3689,6 +3689,29 @@ fn fnDecl( |
| 3689 | if (param.anytype_ellipsis3) |tok| { | 3689 | if (param.anytype_ellipsis3) |tok| { |
| 3690 | return astgen.failTok(tok, "missing parameter name", .{}); | 3690 | return astgen.failTok(tok, "missing parameter name", .{}); |
| 3691 | } else { | 3691 | } else { |
| 3692 | ambiguous: { | ||
| 3693 | if (tree.nodes.items(.tag)[param.type_expr] != .identifier) break :ambiguous; | ||
| 3694 | const main_token = tree.nodes.items(.main_token)[param.type_expr]; | ||
| 3695 | const identifier_str = tree.tokenSlice(main_token); | ||
| 3696 | if (isPrimitive(identifier_str)) break :ambiguous; | ||
| 3697 | return astgen.failNodeNotes( | ||
| 3698 | param.type_expr, | ||
| 3699 | "missing parameter name or type", | ||
| 3700 | .{}, | ||
| 3701 | &[_]u32{ | ||
| 3702 | try astgen.errNoteNode( | ||
| 3703 | param.type_expr, | ||
| 3704 | "if this is a name, annotate its type '{s}: T'", | ||
| 3705 | .{identifier_str}, | ||
| 3706 | ), | ||
| 3707 | try astgen.errNoteNode( | ||
| 3708 | param.type_expr, | ||
| 3709 | "if this is a type, give it a name '<name>: {s}'", | ||
| 3710 | .{identifier_str}, | ||
| 3711 | ), | ||
| 3712 | }, | ||
| 3713 | ); | ||
| 3714 | } | ||
| 3692 | return astgen.failNode(param.type_expr, "missing parameter name", .{}); | 3715 | return astgen.failNode(param.type_expr, "missing parameter name", .{}); |
| 3693 | } | 3716 | } |
| 3694 | } else 0; | 3717 | } else 0; |
| ... | @@ -3884,9 +3907,8 @@ fn fnDecl( | ... | @@ -3884,9 +3907,8 @@ fn fnDecl( |
| 3884 | // As our last action before the return, "pop" the error trace if needed | 3907 | // As our last action before the return, "pop" the error trace if needed |
| 3885 | _ = try gz.addRestoreErrRetIndex(.ret, .always); | 3908 | _ = try gz.addRestoreErrRetIndex(.ret, .always); |
| 3886 | 3909 | ||
| 3887 | // Since we are adding the return instruction here, we must handle the coercion. | 3910 | // Add implicit return at end of function. |
| 3888 | // We do this by using the `ret_tok` instruction. | 3911 | _ = try fn_gz.addUnTok(.ret_implicit, .void_value, tree.lastToken(body_node)); |
| 3889 | _ = try fn_gz.addUnTok(.ret_tok, .void_value, tree.lastToken(body_node)); | ||
| 3890 | } | 3912 | } |
| 3891 | 3913 | ||
| 3892 | break :func try decl_gz.addFunc(.{ | 3914 | break :func try decl_gz.addFunc(.{ |
| ... | @@ -4330,9 +4352,8 @@ fn testDecl( | ... | @@ -4330,9 +4352,8 @@ fn testDecl( |
| 4330 | // As our last action before the return, "pop" the error trace if needed | 4352 | // As our last action before the return, "pop" the error trace if needed |
| 4331 | _ = try gz.addRestoreErrRetIndex(.ret, .always); | 4353 | _ = try gz.addRestoreErrRetIndex(.ret, .always); |
| 4332 | 4354 | ||
| 4333 | // Since we are adding the return instruction here, we must handle the coercion. | 4355 | // Add implicit return at end of function. |
| 4334 | // We do this by using the `ret_tok` instruction. | 4356 | _ = try fn_block.addUnTok(.ret_implicit, .void_value, tree.lastToken(body_node)); |
| 4335 | _ = try fn_block.addUnTok(.ret_tok, .void_value, tree.lastToken(body_node)); | ||
| 4336 | } | 4357 | } |
| 4337 | 4358 | ||
| 4338 | const func_inst = try decl_block.addFunc(.{ | 4359 | const func_inst = try decl_block.addFunc(.{ |
| ... | @@ -5580,6 +5601,14 @@ fn simpleBinOp( | ... | @@ -5580,6 +5601,14 @@ fn simpleBinOp( |
| 5580 | const tree = astgen.tree; | 5601 | const tree = astgen.tree; |
| 5581 | const node_datas = tree.nodes.items(.data); | 5602 | const node_datas = tree.nodes.items(.data); |
| 5582 | 5603 | ||
| 5604 | if (op_inst_tag == .cmp_neq or op_inst_tag == .cmp_eq) { | ||
| 5605 | const node_tags = tree.nodes.items(.tag); | ||
| 5606 | const str = if (op_inst_tag == .cmp_eq) "==" else "!="; | ||
| 5607 | if (node_tags[node_datas[node].lhs] == .string_literal or | ||
| 5608 | node_tags[node_datas[node].rhs] == .string_literal) | ||
| 5609 | return astgen.failNode(node, "cannot compare strings with {s}", .{str}); | ||
| 5610 | } | ||
| 5611 | |||
| 5583 | const lhs = try reachableExpr(gz, scope, .{ .rl = .none }, node_datas[node].lhs, node); | 5612 | const lhs = try reachableExpr(gz, scope, .{ .rl = .none }, node_datas[node].lhs, node); |
| 5584 | var line: u32 = undefined; | 5613 | var line: u32 = undefined; |
| 5585 | var column: u32 = undefined; | 5614 | var column: u32 = undefined; |
| ... | @@ -6577,6 +6606,11 @@ fn switchExpr( | ... | @@ -6577,6 +6606,11 @@ fn switchExpr( |
| 6577 | continue; | 6606 | continue; |
| 6578 | } | 6607 | } |
| 6579 | 6608 | ||
| 6609 | for (case.ast.values) |val| { | ||
| 6610 | if (node_tags[val] == .string_literal) | ||
| 6611 | return astgen.failNode(val, "cannot switch on strings", .{}); | ||
| 6612 | } | ||
| 6613 | |||
| 6580 | if (case.ast.values.len == 1 and node_tags[case.ast.values[0]] != .switch_range) { | 6614 | if (case.ast.values.len == 1 and node_tags[case.ast.values[0]] != .switch_range) { |
| 6581 | scalar_cases_len += 1; | 6615 | scalar_cases_len += 1; |
| 6582 | } else { | 6616 | } else { |
src/Module.zig+2| ... | @@ -938,6 +938,7 @@ pub const Struct = struct { | ... | @@ -938,6 +938,7 @@ pub const Struct = struct { |
| 938 | known_non_opv: bool, | 938 | known_non_opv: bool, |
| 939 | requires_comptime: PropertyBoolean = .unknown, | 939 | requires_comptime: PropertyBoolean = .unknown, |
| 940 | have_field_inits: bool = false, | 940 | have_field_inits: bool = false, |
| 941 | assumed_runtime_bits: bool = false, | ||
| 941 | 942 | ||
| 942 | pub const Fields = std.StringArrayHashMapUnmanaged(Field); | 943 | pub const Fields = std.StringArrayHashMapUnmanaged(Field); |
| 943 | 944 | ||
| ... | @@ -1203,6 +1204,7 @@ pub const Union = struct { | ... | @@ -1203,6 +1204,7 @@ pub const Union = struct { |
| 1203 | fully_resolved, | 1204 | fully_resolved, |
| 1204 | }, | 1205 | }, |
| 1205 | requires_comptime: PropertyBoolean = .unknown, | 1206 | requires_comptime: PropertyBoolean = .unknown, |
| 1207 | assumed_runtime_bits: bool = false, | ||
| 1206 | 1208 | ||
| 1207 | pub const Field = struct { | 1209 | pub const Field = struct { |
| 1208 | /// undefined until `status` is `have_field_types` or `have_layout`. | 1210 | /// undefined until `status` is `have_field_types` or `have_layout`. |
src/Sema.zig+106-27| ... | @@ -195,8 +195,8 @@ pub const Block = struct { | ... | @@ -195,8 +195,8 @@ pub const Block = struct { |
| 195 | try sema.errNote(ci.block, ci.src, parent, prefix ++ "it is inside a @cImport", .{}); | 195 | try sema.errNote(ci.block, ci.src, parent, prefix ++ "it is inside a @cImport", .{}); |
| 196 | }, | 196 | }, |
| 197 | .comptime_ret_ty => |rt| { | 197 | .comptime_ret_ty => |rt| { |
| 198 | const src_loc = if (try sema.funcDeclSrc(rt.func)) |capture| blk: { | 198 | const src_loc = if (try sema.funcDeclSrc(rt.func)) |fn_decl| blk: { |
| 199 | var src_loc = capture; | 199 | var src_loc = fn_decl.srcLoc(); |
| 200 | src_loc.lazy = .{ .node_offset_fn_type_ret_ty = 0 }; | 200 | src_loc.lazy = .{ .node_offset_fn_type_ret_ty = 0 }; |
| 201 | break :blk src_loc; | 201 | break :blk src_loc; |
| 202 | } else blk: { | 202 | } else blk: { |
| ... | @@ -1000,7 +1000,7 @@ fn analyzeBodyInner( | ... | @@ -1000,7 +1000,7 @@ fn analyzeBodyInner( |
| 1000 | // These functions match the return type of analyzeBody so that we can | 1000 | // These functions match the return type of analyzeBody so that we can |
| 1001 | // tail call them here. | 1001 | // tail call them here. |
| 1002 | .compile_error => break sema.zirCompileError(block, inst), | 1002 | .compile_error => break sema.zirCompileError(block, inst), |
| 1003 | .ret_tok => break sema.zirRetTok(block, inst), | 1003 | .ret_implicit => break sema.zirRetImplicit(block, inst), |
| 1004 | .ret_node => break sema.zirRetNode(block, inst), | 1004 | .ret_node => break sema.zirRetNode(block, inst), |
| 1005 | .ret_load => break sema.zirRetLoad(block, inst), | 1005 | .ret_load => break sema.zirRetLoad(block, inst), |
| 1006 | .ret_err_value => break sema.zirRetErrValue(block, inst), | 1006 | .ret_err_value => break sema.zirRetErrValue(block, inst), |
| ... | @@ -5745,7 +5745,7 @@ fn lookupInNamespace( | ... | @@ -5745,7 +5745,7 @@ fn lookupInNamespace( |
| 5745 | return null; | 5745 | return null; |
| 5746 | } | 5746 | } |
| 5747 | 5747 | ||
| 5748 | fn funcDeclSrc(sema: *Sema, func_inst: Air.Inst.Ref) !?Module.SrcLoc { | 5748 | fn funcDeclSrc(sema: *Sema, func_inst: Air.Inst.Ref) !?*Decl { |
| 5749 | const func_val = (try sema.resolveMaybeUndefVal(func_inst)) orelse return null; | 5749 | const func_val = (try sema.resolveMaybeUndefVal(func_inst)) orelse return null; |
| 5750 | if (func_val.isUndef()) return null; | 5750 | if (func_val.isUndef()) return null; |
| 5751 | const owner_decl_index = switch (func_val.tag()) { | 5751 | const owner_decl_index = switch (func_val.tag()) { |
| ... | @@ -5754,8 +5754,7 @@ fn funcDeclSrc(sema: *Sema, func_inst: Air.Inst.Ref) !?Module.SrcLoc { | ... | @@ -5754,8 +5754,7 @@ fn funcDeclSrc(sema: *Sema, func_inst: Air.Inst.Ref) !?Module.SrcLoc { |
| 5754 | .decl_ref => sema.mod.declPtr(func_val.castTag(.decl_ref).?.data).val.castTag(.function).?.data.owner_decl, | 5754 | .decl_ref => sema.mod.declPtr(func_val.castTag(.decl_ref).?.data).val.castTag(.function).?.data.owner_decl, |
| 5755 | else => return null, | 5755 | else => return null, |
| 5756 | }; | 5756 | }; |
| 5757 | const owner_decl = sema.mod.declPtr(owner_decl_index); | 5757 | return sema.mod.declPtr(owner_decl_index); |
| 5758 | return owner_decl.srcLoc(); | ||
| 5759 | } | 5758 | } |
| 5760 | 5759 | ||
| 5761 | pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref { | 5760 | pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref { |
| ... | @@ -5933,7 +5932,7 @@ fn zirCall( | ... | @@ -5933,7 +5932,7 @@ fn zirCall( |
| 5933 | break :check_args; | 5932 | break :check_args; |
| 5934 | } | 5933 | } |
| 5935 | 5934 | ||
| 5936 | const decl_src = try sema.funcDeclSrc(func); | 5935 | const maybe_decl = try sema.funcDeclSrc(func); |
| 5937 | const member_str = if (bound_arg_src != null) "member function " else ""; | 5936 | const member_str = if (bound_arg_src != null) "member function " else ""; |
| 5938 | const variadic_str = if (func_ty_info.is_var_args) "at least " else ""; | 5937 | const variadic_str = if (func_ty_info.is_var_args) "at least " else ""; |
| 5939 | const msg = msg: { | 5938 | const msg = msg: { |
| ... | @@ -5950,7 +5949,7 @@ fn zirCall( | ... | @@ -5950,7 +5949,7 @@ fn zirCall( |
| 5950 | ); | 5949 | ); |
| 5951 | errdefer msg.destroy(sema.gpa); | 5950 | errdefer msg.destroy(sema.gpa); |
| 5952 | 5951 | ||
| 5953 | if (decl_src) |some| try sema.mod.errNoteNonLazy(some, msg, "function declared here", .{}); | 5952 | if (maybe_decl) |fn_decl| try sema.mod.errNoteNonLazy(fn_decl.srcLoc(), msg, "function declared here", .{}); |
| 5954 | break :msg msg; | 5953 | break :msg msg; |
| 5955 | }; | 5954 | }; |
| 5956 | return sema.failWithOwnedErrorMsg(msg); | 5955 | return sema.failWithOwnedErrorMsg(msg); |
| ... | @@ -6144,7 +6143,7 @@ fn analyzeCall( | ... | @@ -6144,7 +6143,7 @@ fn analyzeCall( |
| 6144 | const func_ty_info = func_ty.fnInfo(); | 6143 | const func_ty_info = func_ty.fnInfo(); |
| 6145 | const cc = func_ty_info.cc; | 6144 | const cc = func_ty_info.cc; |
| 6146 | if (cc == .Naked) { | 6145 | if (cc == .Naked) { |
| 6147 | const decl_src = try sema.funcDeclSrc(func); | 6146 | const maybe_decl = try sema.funcDeclSrc(func); |
| 6148 | const msg = msg: { | 6147 | const msg = msg: { |
| 6149 | const msg = try sema.errMsg( | 6148 | const msg = try sema.errMsg( |
| 6150 | block, | 6149 | block, |
| ... | @@ -6154,7 +6153,7 @@ fn analyzeCall( | ... | @@ -6154,7 +6153,7 @@ fn analyzeCall( |
| 6154 | ); | 6153 | ); |
| 6155 | errdefer msg.destroy(sema.gpa); | 6154 | errdefer msg.destroy(sema.gpa); |
| 6156 | 6155 | ||
| 6157 | if (decl_src) |some| try sema.mod.errNoteNonLazy(some, msg, "function declared here", .{}); | 6156 | if (maybe_decl) |fn_decl| try sema.mod.errNoteNonLazy(fn_decl.srcLoc(), msg, "function declared here", .{}); |
| 6158 | break :msg msg; | 6157 | break :msg msg; |
| 6159 | }; | 6158 | }; |
| 6160 | return sema.failWithOwnedErrorMsg(msg); | 6159 | return sema.failWithOwnedErrorMsg(msg); |
| ... | @@ -6388,6 +6387,7 @@ fn analyzeCall( | ... | @@ -6388,6 +6387,7 @@ fn analyzeCall( |
| 6388 | &should_memoize, | 6387 | &should_memoize, |
| 6389 | memoized_call_key, | 6388 | memoized_call_key, |
| 6390 | func_ty_info.param_types, | 6389 | func_ty_info.param_types, |
| 6390 | func, | ||
| 6391 | ) catch |err| switch (err) { | 6391 | ) catch |err| switch (err) { |
| 6392 | error.NeededSourceLocation => { | 6392 | error.NeededSourceLocation => { |
| 6393 | _ = sema.inst_map.remove(inst); | 6393 | _ = sema.inst_map.remove(inst); |
| ... | @@ -6404,6 +6404,7 @@ fn analyzeCall( | ... | @@ -6404,6 +6404,7 @@ fn analyzeCall( |
| 6404 | &should_memoize, | 6404 | &should_memoize, |
| 6405 | memoized_call_key, | 6405 | memoized_call_key, |
| 6406 | func_ty_info.param_types, | 6406 | func_ty_info.param_types, |
| 6407 | func, | ||
| 6407 | ); | 6408 | ); |
| 6408 | return error.AnalysisFail; | 6409 | return error.AnalysisFail; |
| 6409 | }, | 6410 | }, |
| ... | @@ -6546,12 +6547,17 @@ fn analyzeCall( | ... | @@ -6546,12 +6547,17 @@ fn analyzeCall( |
| 6546 | const args = try sema.arena.alloc(Air.Inst.Ref, uncasted_args.len); | 6547 | const args = try sema.arena.alloc(Air.Inst.Ref, uncasted_args.len); |
| 6547 | for (uncasted_args) |uncasted_arg, i| { | 6548 | for (uncasted_args) |uncasted_arg, i| { |
| 6548 | if (i < fn_params_len) { | 6549 | if (i < fn_params_len) { |
| 6550 | const opts: CoerceOpts = .{ .param_src = .{ | ||
| 6551 | .func_inst = func, | ||
| 6552 | .param_i = @intCast(u32, i), | ||
| 6553 | } }; | ||
| 6549 | const param_ty = func_ty.fnParamType(i); | 6554 | const param_ty = func_ty.fnParamType(i); |
| 6550 | args[i] = sema.analyzeCallArg( | 6555 | args[i] = sema.analyzeCallArg( |
| 6551 | block, | 6556 | block, |
| 6552 | .unneeded, | 6557 | .unneeded, |
| 6553 | param_ty, | 6558 | param_ty, |
| 6554 | uncasted_arg, | 6559 | uncasted_arg, |
| 6560 | opts, | ||
| 6555 | ) catch |err| switch (err) { | 6561 | ) catch |err| switch (err) { |
| 6556 | error.NeededSourceLocation => { | 6562 | error.NeededSourceLocation => { |
| 6557 | const decl = sema.mod.declPtr(block.src_decl); | 6563 | const decl = sema.mod.declPtr(block.src_decl); |
| ... | @@ -6560,6 +6566,7 @@ fn analyzeCall( | ... | @@ -6560,6 +6566,7 @@ fn analyzeCall( |
| 6560 | Module.argSrc(call_src.node_offset.x, sema.gpa, decl, i, bound_arg_src), | 6566 | Module.argSrc(call_src.node_offset.x, sema.gpa, decl, i, bound_arg_src), |
| 6561 | param_ty, | 6567 | param_ty, |
| 6562 | uncasted_arg, | 6568 | uncasted_arg, |
| 6569 | opts, | ||
| 6563 | ); | 6570 | ); |
| 6564 | return error.AnalysisFail; | 6571 | return error.AnalysisFail; |
| 6565 | }, | 6572 | }, |
| ... | @@ -6641,6 +6648,7 @@ fn analyzeInlineCallArg( | ... | @@ -6641,6 +6648,7 @@ fn analyzeInlineCallArg( |
| 6641 | should_memoize: *bool, | 6648 | should_memoize: *bool, |
| 6642 | memoized_call_key: Module.MemoizedCall.Key, | 6649 | memoized_call_key: Module.MemoizedCall.Key, |
| 6643 | raw_param_types: []const Type, | 6650 | raw_param_types: []const Type, |
| 6651 | func_inst: Air.Inst.Ref, | ||
| 6644 | ) !void { | 6652 | ) !void { |
| 6645 | const zir_tags = sema.code.instructions.items(.tag); | 6653 | const zir_tags = sema.code.instructions.items(.tag); |
| 6646 | switch (zir_tags[inst]) { | 6654 | switch (zir_tags[inst]) { |
| ... | @@ -6665,7 +6673,13 @@ fn analyzeInlineCallArg( | ... | @@ -6665,7 +6673,13 @@ fn analyzeInlineCallArg( |
| 6665 | return err; | 6673 | return err; |
| 6666 | }; | 6674 | }; |
| 6667 | } | 6675 | } |
| 6668 | const casted_arg = try sema.coerce(arg_block, param_ty, uncasted_arg, arg_src); | 6676 | const casted_arg = sema.coerceExtra(arg_block, param_ty, uncasted_arg, arg_src, .{ .param_src = .{ |
| 6677 | .func_inst = func_inst, | ||
| 6678 | .param_i = @intCast(u32, arg_i.*), | ||
| 6679 | } }) catch |err| switch (err) { | ||
| 6680 | error.NotCoercible => unreachable, | ||
| 6681 | else => |e| return e, | ||
| 6682 | }; | ||
| 6669 | 6683 | ||
| 6670 | if (is_comptime_call) { | 6684 | if (is_comptime_call) { |
| 6671 | try sema.inst_map.putNoClobber(sema.gpa, inst, casted_arg); | 6685 | try sema.inst_map.putNoClobber(sema.gpa, inst, casted_arg); |
| ... | @@ -6755,9 +6769,13 @@ fn analyzeCallArg( | ... | @@ -6755,9 +6769,13 @@ fn analyzeCallArg( |
| 6755 | arg_src: LazySrcLoc, | 6769 | arg_src: LazySrcLoc, |
| 6756 | param_ty: Type, | 6770 | param_ty: Type, |
| 6757 | uncasted_arg: Air.Inst.Ref, | 6771 | uncasted_arg: Air.Inst.Ref, |
| 6772 | opts: CoerceOpts, | ||
| 6758 | ) !Air.Inst.Ref { | 6773 | ) !Air.Inst.Ref { |
| 6759 | try sema.resolveTypeFully(param_ty); | 6774 | try sema.resolveTypeFully(param_ty); |
| 6760 | return sema.coerce(block, param_ty, uncasted_arg, arg_src); | 6775 | return sema.coerceExtra(block, param_ty, uncasted_arg, arg_src, opts) catch |err| switch (err) { |
| 6776 | error.NotCoercible => unreachable, | ||
| 6777 | else => |e| return e, | ||
| 6778 | }; | ||
| 6761 | } | 6779 | } |
| 6762 | 6780 | ||
| 6763 | fn analyzeGenericCallArg( | 6781 | fn analyzeGenericCallArg( |
| ... | @@ -16398,7 +16416,7 @@ fn zirRetErrValue( | ... | @@ -16398,7 +16416,7 @@ fn zirRetErrValue( |
| 16398 | return sema.analyzeRet(block, result_inst, src); | 16416 | return sema.analyzeRet(block, result_inst, src); |
| 16399 | } | 16417 | } |
| 16400 | 16418 | ||
| 16401 | fn zirRetTok( | 16419 | fn zirRetImplicit( |
| 16402 | sema: *Sema, | 16420 | sema: *Sema, |
| 16403 | block: *Block, | 16421 | block: *Block, |
| 16404 | inst: Zir.Inst.Index, | 16422 | inst: Zir.Inst.Index, |
| ... | @@ -16408,9 +16426,33 @@ fn zirRetTok( | ... | @@ -16408,9 +16426,33 @@ fn zirRetTok( |
| 16408 | 16426 | ||
| 16409 | const inst_data = sema.code.instructions.items(.data)[inst].un_tok; | 16427 | const inst_data = sema.code.instructions.items(.data)[inst].un_tok; |
| 16410 | const operand = try sema.resolveInst(inst_data.operand); | 16428 | const operand = try sema.resolveInst(inst_data.operand); |
| 16411 | const src = inst_data.src(); | ||
| 16412 | 16429 | ||
| 16413 | return sema.analyzeRet(block, operand, src); | 16430 | const r_brace_src = inst_data.src(); |
| 16431 | const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 }; | ||
| 16432 | const base_tag = sema.fn_ret_ty.baseZigTypeTag(); | ||
| 16433 | if (base_tag == .NoReturn) { | ||
| 16434 | const msg = msg: { | ||
| 16435 | const msg = try sema.errMsg(block, ret_ty_src, "function declared '{}' implicitly returns", .{ | ||
| 16436 | sema.fn_ret_ty.fmt(sema.mod), | ||
| 16437 | }); | ||
| 16438 | errdefer msg.destroy(sema.gpa); | ||
| 16439 | try sema.errNote(block, r_brace_src, msg, "control flow reaches end of body here", .{}); | ||
| 16440 | break :msg msg; | ||
| 16441 | }; | ||
| 16442 | return sema.failWithOwnedErrorMsg(msg); | ||
| 16443 | } else if (base_tag != .Void) { | ||
| 16444 | const msg = msg: { | ||
| 16445 | const msg = try sema.errMsg(block, ret_ty_src, "function with non-void return type '{}' implicitly returns", .{ | ||
| 16446 | sema.fn_ret_ty.fmt(sema.mod), | ||
| 16447 | }); | ||
| 16448 | errdefer msg.destroy(sema.gpa); | ||
| 16449 | try sema.errNote(block, r_brace_src, msg, "control flow reaches end of body here", .{}); | ||
| 16450 | break :msg msg; | ||
| 16451 | }; | ||
| 16452 | return sema.failWithOwnedErrorMsg(msg); | ||
| 16453 | } | ||
| 16454 | |||
| 16455 | return sema.analyzeRet(block, operand, .unneeded); | ||
| 16414 | } | 16456 | } |
| 16415 | 16457 | ||
| 16416 | fn zirRetNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Index { | 16458 | fn zirRetNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Index { |
| ... | @@ -16677,7 +16719,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -16677,7 +16719,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 16677 | const bitoffset_src: LazySrcLoc = .{ .node_offset_ptr_bitoffset = extra.data.src_node }; | 16719 | const bitoffset_src: LazySrcLoc = .{ .node_offset_ptr_bitoffset = extra.data.src_node }; |
| 16678 | const hostsize_src: LazySrcLoc = .{ .node_offset_ptr_hostsize = extra.data.src_node }; | 16720 | const hostsize_src: LazySrcLoc = .{ .node_offset_ptr_hostsize = extra.data.src_node }; |
| 16679 | 16721 | ||
| 16680 | const unresolved_elem_ty = blk: { | 16722 | const elem_ty = blk: { |
| 16681 | const air_inst = try sema.resolveInst(extra.data.elem_type); | 16723 | const air_inst = try sema.resolveInst(extra.data.elem_type); |
| 16682 | const ty = sema.analyzeAsType(block, elem_ty_src, air_inst) catch |err| { | 16724 | const ty = sema.analyzeAsType(block, elem_ty_src, air_inst) catch |err| { |
| 16683 | if (err == error.AnalysisFail and sema.err != null and sema.typeOf(air_inst).isSinglePointer()) { | 16725 | if (err == error.AnalysisFail and sema.err != null and sema.typeOf(air_inst).isSinglePointer()) { |
| ... | @@ -16706,7 +16748,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -16706,7 +16748,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 16706 | // Check if this happens to be the lazy alignment of our element type, in | 16748 | // Check if this happens to be the lazy alignment of our element type, in |
| 16707 | // which case we can make this 0 without resolving it. | 16749 | // which case we can make this 0 without resolving it. |
| 16708 | if (val.castTag(.lazy_align)) |payload| { | 16750 | if (val.castTag(.lazy_align)) |payload| { |
| 16709 | if (payload.data.eql(unresolved_elem_ty, sema.mod)) { | 16751 | if (payload.data.eql(elem_ty, sema.mod)) { |
| 16710 | break :blk 0; | 16752 | break :blk 0; |
| 16711 | } | 16753 | } |
| 16712 | } | 16754 | } |
| ... | @@ -16739,14 +16781,6 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -16739,14 +16781,6 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 16739 | return sema.fail(block, bitoffset_src, "bit offset starts after end of host integer", .{}); | 16781 | return sema.fail(block, bitoffset_src, "bit offset starts after end of host integer", .{}); |
| 16740 | } | 16782 | } |
| 16741 | 16783 | ||
| 16742 | const elem_ty = if (abi_align == 0) | ||
| 16743 | unresolved_elem_ty | ||
| 16744 | else t: { | ||
| 16745 | const elem_ty = try sema.resolveTypeFields(unresolved_elem_ty); | ||
| 16746 | try sema.resolveTypeLayout(elem_ty); | ||
| 16747 | break :t elem_ty; | ||
| 16748 | }; | ||
| 16749 | |||
| 16750 | if (elem_ty.zigTypeTag() == .NoReturn) { | 16784 | if (elem_ty.zigTypeTag() == .NoReturn) { |
| 16751 | return sema.fail(block, elem_ty_src, "pointer to noreturn not allowed", .{}); | 16785 | return sema.fail(block, elem_ty_src, "pointer to noreturn not allowed", .{}); |
| 16752 | } else if (elem_ty.zigTypeTag() == .Fn) { | 16786 | } else if (elem_ty.zigTypeTag() == .Fn) { |
| ... | @@ -20173,7 +20207,7 @@ fn analyzeShuffle( | ... | @@ -20173,7 +20207,7 @@ fn analyzeShuffle( |
| 20173 | var buf: Value.ElemValueBuffer = undefined; | 20207 | var buf: Value.ElemValueBuffer = undefined; |
| 20174 | const elem = mask.elemValueBuffer(sema.mod, i, &buf); | 20208 | const elem = mask.elemValueBuffer(sema.mod, i, &buf); |
| 20175 | if (elem.isUndef()) continue; | 20209 | if (elem.isUndef()) continue; |
| 20176 | const int = elem.toSignedInt(); | 20210 | const int = elem.toSignedInt(sema.mod.getTarget()); |
| 20177 | var unsigned: u32 = undefined; | 20211 | var unsigned: u32 = undefined; |
| 20178 | var chosen: u32 = undefined; | 20212 | var chosen: u32 = undefined; |
| 20179 | if (int >= 0) { | 20213 | if (int >= 0) { |
| ... | @@ -20215,7 +20249,7 @@ fn analyzeShuffle( | ... | @@ -20215,7 +20249,7 @@ fn analyzeShuffle( |
| 20215 | values[i] = Value.undef; | 20249 | values[i] = Value.undef; |
| 20216 | continue; | 20250 | continue; |
| 20217 | } | 20251 | } |
| 20218 | const int = mask_elem_val.toSignedInt(); | 20252 | const int = mask_elem_val.toSignedInt(sema.mod.getTarget()); |
| 20219 | const unsigned = if (int >= 0) @intCast(u32, int) else @intCast(u32, ~int); | 20253 | const unsigned = if (int >= 0) @intCast(u32, int) else @intCast(u32, ~int); |
| 20220 | if (int >= 0) { | 20254 | if (int >= 0) { |
| 20221 | values[i] = try a_val.elemValue(sema.mod, sema.arena, unsigned); | 20255 | values[i] = try a_val.elemValue(sema.mod, sema.arena, unsigned); |
| ... | @@ -23957,6 +23991,25 @@ const CoerceOpts = struct { | ... | @@ -23957,6 +23991,25 @@ const CoerceOpts = struct { |
| 23957 | is_ret: bool = false, | 23991 | is_ret: bool = false, |
| 23958 | /// Should coercion to comptime_int ermit an error message. | 23992 | /// Should coercion to comptime_int ermit an error message. |
| 23959 | no_cast_to_comptime_int: bool = false, | 23993 | no_cast_to_comptime_int: bool = false, |
| 23994 | |||
| 23995 | param_src: struct { | ||
| 23996 | func_inst: Air.Inst.Ref = .none, | ||
| 23997 | param_i: u32 = undefined, | ||
| 23998 | |||
| 23999 | fn get(info: @This(), sema: *Sema) !?Module.SrcLoc { | ||
| 24000 | if (info.func_inst == .none) return null; | ||
| 24001 | const fn_decl = (try sema.funcDeclSrc(info.func_inst)) orelse return null; | ||
| 24002 | const param_src = Module.paramSrc(0, sema.gpa, fn_decl, info.param_i); | ||
| 24003 | if (param_src == .node_offset_param) { | ||
| 24004 | return Module.SrcLoc{ | ||
| 24005 | .file_scope = fn_decl.getFileScope(), | ||
| 24006 | .parent_decl_node = fn_decl.src_node, | ||
| 24007 | .lazy = LazySrcLoc.nodeOffset(param_src.node_offset_param), | ||
| 24008 | }; | ||
| 24009 | } | ||
| 24010 | return param_src.toSrcLoc(fn_decl); | ||
| 24011 | } | ||
| 24012 | } = .{}, | ||
| 23960 | }; | 24013 | }; |
| 23961 | 24014 | ||
| 23962 | fn coerceExtra( | 24015 | fn coerceExtra( |
| ... | @@ -24610,6 +24663,10 @@ fn coerceExtra( | ... | @@ -24610,6 +24663,10 @@ fn coerceExtra( |
| 24610 | } | 24663 | } |
| 24611 | } | 24664 | } |
| 24612 | 24665 | ||
| 24666 | if (try opts.param_src.get(sema)) |param_src| { | ||
| 24667 | try sema.mod.errNoteNonLazy(param_src, msg, "parameter type declared here", .{}); | ||
| 24668 | } | ||
| 24669 | |||
| 24613 | // TODO maybe add "cannot store an error in type '{}'" note | 24670 | // TODO maybe add "cannot store an error in type '{}'" note |
| 24614 | 24671 | ||
| 24615 | break :msg msg; | 24672 | break :msg msg; |
| ... | @@ -28212,6 +28269,7 @@ fn cmpNumeric( | ... | @@ -28212,6 +28269,7 @@ fn cmpNumeric( |
| 28212 | 28269 | ||
| 28213 | var lhs_bits: usize = undefined; | 28270 | var lhs_bits: usize = undefined; |
| 28214 | if (try sema.resolveMaybeUndefVal(lhs)) |lhs_val| { | 28271 | if (try sema.resolveMaybeUndefVal(lhs)) |lhs_val| { |
| 28272 | try sema.resolveLazyValue(lhs_val); | ||
| 28215 | if (lhs_val.isUndef()) | 28273 | if (lhs_val.isUndef()) |
| 28216 | return sema.addConstUndef(Type.bool); | 28274 | return sema.addConstUndef(Type.bool); |
| 28217 | if (lhs_val.isNan()) switch (op) { | 28275 | if (lhs_val.isNan()) switch (op) { |
| ... | @@ -28265,6 +28323,7 @@ fn cmpNumeric( | ... | @@ -28265,6 +28323,7 @@ fn cmpNumeric( |
| 28265 | 28323 | ||
| 28266 | var rhs_bits: usize = undefined; | 28324 | var rhs_bits: usize = undefined; |
| 28267 | if (try sema.resolveMaybeUndefVal(rhs)) |rhs_val| { | 28325 | if (try sema.resolveMaybeUndefVal(rhs)) |rhs_val| { |
| 28326 | try sema.resolveLazyValue(rhs_val); | ||
| 28268 | if (rhs_val.isUndef()) | 28327 | if (rhs_val.isUndef()) |
| 28269 | return sema.addConstUndef(Type.bool); | 28328 | return sema.addConstUndef(Type.bool); |
| 28270 | if (rhs_val.isNan()) switch (op) { | 28329 | if (rhs_val.isNan()) switch (op) { |
| ... | @@ -29132,6 +29191,16 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void { | ... | @@ -29132,6 +29191,16 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void { |
| 29132 | 29191 | ||
| 29133 | struct_obj.status = .have_layout; | 29192 | struct_obj.status = .have_layout; |
| 29134 | _ = try sema.resolveTypeRequiresComptime(resolved_ty); | 29193 | _ = try sema.resolveTypeRequiresComptime(resolved_ty); |
| 29194 | |||
| 29195 | if (struct_obj.assumed_runtime_bits and !resolved_ty.hasRuntimeBits()) { | ||
| 29196 | const msg = try Module.ErrorMsg.create( | ||
| 29197 | sema.gpa, | ||
| 29198 | struct_obj.srcLoc(sema.mod), | ||
| 29199 | "struct layout depends on it having runtime bits", | ||
| 29200 | .{}, | ||
| 29201 | ); | ||
| 29202 | return sema.failWithOwnedErrorMsg(msg); | ||
| 29203 | } | ||
| 29135 | } | 29204 | } |
| 29136 | // otherwise it's a tuple; no need to resolve anything | 29205 | // otherwise it's a tuple; no need to resolve anything |
| 29137 | } | 29206 | } |
| ... | @@ -29296,6 +29365,16 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void { | ... | @@ -29296,6 +29365,16 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void { |
| 29296 | } | 29365 | } |
| 29297 | union_obj.status = .have_layout; | 29366 | union_obj.status = .have_layout; |
| 29298 | _ = try sema.resolveTypeRequiresComptime(resolved_ty); | 29367 | _ = try sema.resolveTypeRequiresComptime(resolved_ty); |
| 29368 | |||
| 29369 | if (union_obj.assumed_runtime_bits and !resolved_ty.hasRuntimeBits()) { | ||
| 29370 | const msg = try Module.ErrorMsg.create( | ||
| 29371 | sema.gpa, | ||
| 29372 | union_obj.srcLoc(sema.mod), | ||
| 29373 | "union layout depends on it having runtime bits", | ||
| 29374 | .{}, | ||
| 29375 | ); | ||
| 29376 | return sema.failWithOwnedErrorMsg(msg); | ||
| 29377 | } | ||
| 29299 | } | 29378 | } |
| 29300 | 29379 | ||
| 29301 | // In case of querying the ABI alignment of this struct, we will ask | 29380 | // In case of querying the ABI alignment of this struct, we will ask |
src/Zir.zig+4-4| ... | @@ -519,7 +519,7 @@ pub const Inst = struct { | ... | @@ -519,7 +519,7 @@ pub const Inst = struct { |
| 519 | /// Includes an operand as the return value. | 519 | /// Includes an operand as the return value. |
| 520 | /// Includes a token source location. | 520 | /// Includes a token source location. |
| 521 | /// Uses the `un_tok` union field. | 521 | /// Uses the `un_tok` union field. |
| 522 | ret_tok, | 522 | ret_implicit, |
| 523 | /// Sends control flow back to the function's callee. | 523 | /// Sends control flow back to the function's callee. |
| 524 | /// The return operand is `error.foo` where `foo` is given by the string. | 524 | /// The return operand is `error.foo` where `foo` is given by the string. |
| 525 | /// If the current function has an inferred error set, the error given by the | 525 | /// If the current function has an inferred error set, the error given by the |
| ... | @@ -1256,7 +1256,7 @@ pub const Inst = struct { | ... | @@ -1256,7 +1256,7 @@ pub const Inst = struct { |
| 1256 | .compile_error, | 1256 | .compile_error, |
| 1257 | .ret_node, | 1257 | .ret_node, |
| 1258 | .ret_load, | 1258 | .ret_load, |
| 1259 | .ret_tok, | 1259 | .ret_implicit, |
| 1260 | .ret_err_value, | 1260 | .ret_err_value, |
| 1261 | .@"unreachable", | 1261 | .@"unreachable", |
| 1262 | .repeat, | 1262 | .repeat, |
| ... | @@ -1530,7 +1530,7 @@ pub const Inst = struct { | ... | @@ -1530,7 +1530,7 @@ pub const Inst = struct { |
| 1530 | .compile_error, | 1530 | .compile_error, |
| 1531 | .ret_node, | 1531 | .ret_node, |
| 1532 | .ret_load, | 1532 | .ret_load, |
| 1533 | .ret_tok, | 1533 | .ret_implicit, |
| 1534 | .ret_err_value, | 1534 | .ret_err_value, |
| 1535 | .ret_ptr, | 1535 | .ret_ptr, |
| 1536 | .ret_type, | 1536 | .ret_type, |
| ... | @@ -1659,7 +1659,7 @@ pub const Inst = struct { | ... | @@ -1659,7 +1659,7 @@ pub const Inst = struct { |
| 1659 | .ref = .un_tok, | 1659 | .ref = .un_tok, |
| 1660 | .ret_node = .un_node, | 1660 | .ret_node = .un_node, |
| 1661 | .ret_load = .un_node, | 1661 | .ret_load = .un_node, |
| 1662 | .ret_tok = .un_tok, | 1662 | .ret_implicit = .un_tok, |
| 1663 | .ret_err_value = .str_tok, | 1663 | .ret_err_value = .str_tok, |
| 1664 | .ret_err_value_code = .str_tok, | 1664 | .ret_err_value_code = .str_tok, |
| 1665 | .ret_ptr = .node, | 1665 | .ret_ptr = .node, |
src/arch/aarch64/CodeGen.zig+1-1| ... | @@ -6083,7 +6083,7 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { | ... | @@ -6083,7 +6083,7 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { |
| 6083 | if (info.bits <= 64) { | 6083 | if (info.bits <= 64) { |
| 6084 | const unsigned = switch (info.signedness) { | 6084 | const unsigned = switch (info.signedness) { |
| 6085 | .signed => blk: { | 6085 | .signed => blk: { |
| 6086 | const signed = typed_value.val.toSignedInt(); | 6086 | const signed = typed_value.val.toSignedInt(target); |
| 6087 | break :blk @bitCast(u64, signed); | 6087 | break :blk @bitCast(u64, signed); |
| 6088 | }, | 6088 | }, |
| 6089 | .unsigned => typed_value.val.toUnsignedInt(target), | 6089 | .unsigned => typed_value.val.toUnsignedInt(target), |
src/arch/arm/CodeGen.zig+1-1| ... | @@ -6121,7 +6121,7 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { | ... | @@ -6121,7 +6121,7 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { |
| 6121 | if (info.bits <= ptr_bits) { | 6121 | if (info.bits <= ptr_bits) { |
| 6122 | const unsigned = switch (info.signedness) { | 6122 | const unsigned = switch (info.signedness) { |
| 6123 | .signed => blk: { | 6123 | .signed => blk: { |
| 6124 | const signed = @intCast(i32, typed_value.val.toSignedInt()); | 6124 | const signed = @intCast(i32, typed_value.val.toSignedInt(target)); |
| 6125 | break :blk @bitCast(u32, signed); | 6125 | break :blk @bitCast(u32, signed); |
| 6126 | }, | 6126 | }, |
| 6127 | .unsigned => @intCast(u32, typed_value.val.toUnsignedInt(target)), | 6127 | .unsigned => @intCast(u32, typed_value.val.toUnsignedInt(target)), |
src/arch/sparc64/CodeGen.zig+1-1| ... | @@ -3786,7 +3786,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { | ... | @@ -3786,7 +3786,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { |
| 3786 | if (info.bits <= 64) { | 3786 | if (info.bits <= 64) { |
| 3787 | const unsigned = switch (info.signedness) { | 3787 | const unsigned = switch (info.signedness) { |
| 3788 | .signed => blk: { | 3788 | .signed => blk: { |
| 3789 | const signed = typed_value.val.toSignedInt(); | 3789 | const signed = typed_value.val.toSignedInt(target); |
| 3790 | break :blk @bitCast(u64, signed); | 3790 | break :blk @bitCast(u64, signed); |
| 3791 | }, | 3791 | }, |
| 3792 | .unsigned => typed_value.val.toUnsignedInt(target), | 3792 | .unsigned => typed_value.val.toUnsignedInt(target), |
src/arch/wasm/CodeGen.zig+5-5| ... | @@ -2604,11 +2604,11 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue { | ... | @@ -2604,11 +2604,11 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue { |
| 2604 | switch (int_info.signedness) { | 2604 | switch (int_info.signedness) { |
| 2605 | .signed => switch (int_info.bits) { | 2605 | .signed => switch (int_info.bits) { |
| 2606 | 0...32 => return WValue{ .imm32 = @intCast(u32, toTwosComplement( | 2606 | 0...32 => return WValue{ .imm32 = @intCast(u32, toTwosComplement( |
| 2607 | val.toSignedInt(), | 2607 | val.toSignedInt(target), |
| 2608 | @intCast(u6, int_info.bits), | 2608 | @intCast(u6, int_info.bits), |
| 2609 | )) }, | 2609 | )) }, |
| 2610 | 33...64 => return WValue{ .imm64 = toTwosComplement( | 2610 | 33...64 => return WValue{ .imm64 = toTwosComplement( |
| 2611 | val.toSignedInt(), | 2611 | val.toSignedInt(target), |
| 2612 | @intCast(u7, int_info.bits), | 2612 | @intCast(u7, int_info.bits), |
| 2613 | ) }, | 2613 | ) }, |
| 2614 | else => unreachable, | 2614 | else => unreachable, |
| ... | @@ -2758,15 +2758,15 @@ fn valueAsI32(func: *const CodeGen, val: Value, ty: Type) i32 { | ... | @@ -2758,15 +2758,15 @@ fn valueAsI32(func: *const CodeGen, val: Value, ty: Type) i32 { |
| 2758 | } | 2758 | } |
| 2759 | }, | 2759 | }, |
| 2760 | .Int => switch (ty.intInfo(func.target).signedness) { | 2760 | .Int => switch (ty.intInfo(func.target).signedness) { |
| 2761 | .signed => return @truncate(i32, val.toSignedInt()), | 2761 | .signed => return @truncate(i32, val.toSignedInt(target)), |
| 2762 | .unsigned => return @bitCast(i32, @truncate(u32, val.toUnsignedInt(target))), | 2762 | .unsigned => return @bitCast(i32, @truncate(u32, val.toUnsignedInt(target))), |
| 2763 | }, | 2763 | }, |
| 2764 | .ErrorSet => { | 2764 | .ErrorSet => { |
| 2765 | const kv = func.bin_file.base.options.module.?.getErrorValue(val.getError().?) catch unreachable; // passed invalid `Value` to function | 2765 | const kv = func.bin_file.base.options.module.?.getErrorValue(val.getError().?) catch unreachable; // passed invalid `Value` to function |
| 2766 | return @bitCast(i32, kv.value); | 2766 | return @bitCast(i32, kv.value); |
| 2767 | }, | 2767 | }, |
| 2768 | .Bool => return @intCast(i32, val.toSignedInt()), | 2768 | .Bool => return @intCast(i32, val.toSignedInt(target)), |
| 2769 | .Pointer => return @intCast(i32, val.toSignedInt()), | 2769 | .Pointer => return @intCast(i32, val.toSignedInt(target)), |
| 2770 | else => unreachable, // Programmer called this function for an illegal type | 2770 | else => unreachable, // Programmer called this function for an illegal type |
| 2771 | } | 2771 | } |
| 2772 | } | 2772 | } |
src/arch/x86_64/CodeGen.zig+1-1| ... | @@ -7007,7 +7007,7 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { | ... | @@ -7007,7 +7007,7 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { |
| 7007 | .Int => { | 7007 | .Int => { |
| 7008 | const info = typed_value.ty.intInfo(self.target.*); | 7008 | const info = typed_value.ty.intInfo(self.target.*); |
| 7009 | if (info.bits <= ptr_bits and info.signedness == .signed) { | 7009 | if (info.bits <= ptr_bits and info.signedness == .signed) { |
| 7010 | return MCValue{ .immediate = @bitCast(u64, typed_value.val.toSignedInt()) }; | 7010 | return MCValue{ .immediate = @bitCast(u64, typed_value.val.toSignedInt(target)) }; |
| 7011 | } | 7011 | } |
| 7012 | if (!(info.bits > ptr_bits or info.signedness == .signed)) { | 7012 | if (!(info.bits > ptr_bits or info.signedness == .signed)) { |
| 7013 | return MCValue{ .immediate = typed_value.val.toUnsignedInt(target) }; | 7013 | return MCValue{ .immediate = typed_value.val.toUnsignedInt(target) }; |
src/codegen.zig+7-7| ... | @@ -459,7 +459,7 @@ pub fn generateSymbol( | ... | @@ -459,7 +459,7 @@ pub fn generateSymbol( |
| 459 | if (info.bits <= 8) { | 459 | if (info.bits <= 8) { |
| 460 | const x: u8 = switch (info.signedness) { | 460 | const x: u8 = switch (info.signedness) { |
| 461 | .unsigned => @intCast(u8, typed_value.val.toUnsignedInt(target)), | 461 | .unsigned => @intCast(u8, typed_value.val.toUnsignedInt(target)), |
| 462 | .signed => @bitCast(u8, @intCast(i8, typed_value.val.toSignedInt())), | 462 | .signed => @bitCast(u8, @intCast(i8, typed_value.val.toSignedInt(target))), |
| 463 | }; | 463 | }; |
| 464 | try code.append(x); | 464 | try code.append(x); |
| 465 | return Result{ .appended = {} }; | 465 | return Result{ .appended = {} }; |
| ... | @@ -488,13 +488,13 @@ pub fn generateSymbol( | ... | @@ -488,13 +488,13 @@ pub fn generateSymbol( |
| 488 | }, | 488 | }, |
| 489 | .signed => { | 489 | .signed => { |
| 490 | if (info.bits <= 16) { | 490 | if (info.bits <= 16) { |
| 491 | const x = @intCast(i16, typed_value.val.toSignedInt()); | 491 | const x = @intCast(i16, typed_value.val.toSignedInt(target)); |
| 492 | mem.writeInt(i16, try code.addManyAsArray(2), x, endian); | 492 | mem.writeInt(i16, try code.addManyAsArray(2), x, endian); |
| 493 | } else if (info.bits <= 32) { | 493 | } else if (info.bits <= 32) { |
| 494 | const x = @intCast(i32, typed_value.val.toSignedInt()); | 494 | const x = @intCast(i32, typed_value.val.toSignedInt(target)); |
| 495 | mem.writeInt(i32, try code.addManyAsArray(4), x, endian); | 495 | mem.writeInt(i32, try code.addManyAsArray(4), x, endian); |
| 496 | } else { | 496 | } else { |
| 497 | const x = typed_value.val.toSignedInt(); | 497 | const x = typed_value.val.toSignedInt(target); |
| 498 | mem.writeInt(i64, try code.addManyAsArray(8), x, endian); | 498 | mem.writeInt(i64, try code.addManyAsArray(8), x, endian); |
| 499 | } | 499 | } |
| 500 | }, | 500 | }, |
| ... | @@ -536,13 +536,13 @@ pub fn generateSymbol( | ... | @@ -536,13 +536,13 @@ pub fn generateSymbol( |
| 536 | }, | 536 | }, |
| 537 | .signed => { | 537 | .signed => { |
| 538 | if (info.bits <= 16) { | 538 | if (info.bits <= 16) { |
| 539 | const x = @intCast(i16, int_val.toSignedInt()); | 539 | const x = @intCast(i16, int_val.toSignedInt(target)); |
| 540 | mem.writeInt(i16, try code.addManyAsArray(2), x, endian); | 540 | mem.writeInt(i16, try code.addManyAsArray(2), x, endian); |
| 541 | } else if (info.bits <= 32) { | 541 | } else if (info.bits <= 32) { |
| 542 | const x = @intCast(i32, int_val.toSignedInt()); | 542 | const x = @intCast(i32, int_val.toSignedInt(target)); |
| 543 | mem.writeInt(i32, try code.addManyAsArray(4), x, endian); | 543 | mem.writeInt(i32, try code.addManyAsArray(4), x, endian); |
| 544 | } else { | 544 | } else { |
| 545 | const x = int_val.toSignedInt(); | 545 | const x = int_val.toSignedInt(target); |
| 546 | mem.writeInt(i64, try code.addManyAsArray(8), x, endian); | 546 | mem.writeInt(i64, try code.addManyAsArray(8), x, endian); |
| 547 | } | 547 | } |
| 548 | }, | 548 | }, |
src/codegen/llvm.zig+1-1| ... | @@ -8934,7 +8934,7 @@ pub const FuncGen = struct { | ... | @@ -8934,7 +8934,7 @@ pub const FuncGen = struct { |
| 8934 | if (elem.isUndef()) { | 8934 | if (elem.isUndef()) { |
| 8935 | val.* = llvm_i32.getUndef(); | 8935 | val.* = llvm_i32.getUndef(); |
| 8936 | } else { | 8936 | } else { |
| 8937 | const int = elem.toSignedInt(); | 8937 | const int = elem.toSignedInt(self.dg.module.getTarget()); |
| 8938 | const unsigned = if (int >= 0) @intCast(u32, int) else @intCast(u32, ~int + a_len); | 8938 | const unsigned = if (int >= 0) @intCast(u32, int) else @intCast(u32, ~int + a_len); |
| 8939 | val.* = llvm_i32.constInt(unsigned, .False); | 8939 | val.* = llvm_i32.constInt(unsigned, .False); |
| 8940 | } | 8940 | } |
src/codegen/spirv.zig+1-1| ... | @@ -345,7 +345,7 @@ pub const DeclGen = struct { | ... | @@ -345,7 +345,7 @@ pub const DeclGen = struct { |
| 345 | 345 | ||
| 346 | // Note, value is required to be sign-extended, so we don't need to mask off the upper bits. | 346 | // Note, value is required to be sign-extended, so we don't need to mask off the upper bits. |
| 347 | // See https://www.khronos.org/registry/SPIR-V/specs/unified1/SPIRV.html#Literal | 347 | // See https://www.khronos.org/registry/SPIR-V/specs/unified1/SPIRV.html#Literal |
| 348 | var int_bits = if (ty.isSignedInt()) @bitCast(u64, val.toSignedInt()) else val.toUnsignedInt(target); | 348 | var int_bits = if (ty.isSignedInt()) @bitCast(u64, val.toSignedInt(target)) else val.toUnsignedInt(target); |
| 349 | 349 | ||
| 350 | const value: spec.LiteralContextDependentNumber = switch (backing_bits) { | 350 | const value: spec.LiteralContextDependentNumber = switch (backing_bits) { |
| 351 | 1...32 => .{ .uint32 = @truncate(u32, int_bits) }, | 351 | 1...32 => .{ .uint32 = @truncate(u32, int_bits) }, |
src/link/Dwarf.zig+1-1| ... | @@ -409,7 +409,7 @@ pub const DeclState = struct { | ... | @@ -409,7 +409,7 @@ pub const DeclState = struct { |
| 409 | // See https://github.com/ziglang/zig/issues/645 | 409 | // See https://github.com/ziglang/zig/issues/645 |
| 410 | var int_buffer: Value.Payload.U64 = undefined; | 410 | var int_buffer: Value.Payload.U64 = undefined; |
| 411 | const field_int_val = value.enumToInt(ty, &int_buffer); | 411 | const field_int_val = value.enumToInt(ty, &int_buffer); |
| 412 | break :value @bitCast(u64, field_int_val.toSignedInt()); | 412 | break :value @bitCast(u64, field_int_val.toSignedInt(target)); |
| 413 | } else @intCast(u64, field_i); | 413 | } else @intCast(u64, field_i); |
| 414 | mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), value, target_endian); | 414 | mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), value, target_endian); |
| 415 | } | 415 | } |
src/print_zir.zig+1-1| ... | @@ -235,7 +235,7 @@ const Writer = struct { | ... | @@ -235,7 +235,7 @@ const Writer = struct { |
| 235 | => try self.writeUnNode(stream, inst), | 235 | => try self.writeUnNode(stream, inst), |
| 236 | 236 | ||
| 237 | .ref, | 237 | .ref, |
| 238 | .ret_tok, | 238 | .ret_implicit, |
| 239 | .closure_capture, | 239 | .closure_capture, |
| 240 | .switch_capture_tag, | 240 | .switch_capture_tag, |
| 241 | => try self.writeUnTok(stream, inst), | 241 | => try self.writeUnTok(stream, inst), |
src/type.zig+46-8| ... | @@ -160,6 +160,17 @@ pub const Type = extern union { | ... | @@ -160,6 +160,17 @@ pub const Type = extern union { |
| 160 | } | 160 | } |
| 161 | } | 161 | } |
| 162 | 162 | ||
| 163 | pub fn baseZigTypeTag(self: Type) std.builtin.TypeId { | ||
| 164 | return switch (self.zigTypeTag()) { | ||
| 165 | .ErrorUnion => self.errorUnionPayload().baseZigTypeTag(), | ||
| 166 | .Optional => { | ||
| 167 | var buf: Payload.ElemType = undefined; | ||
| 168 | return self.optionalChild(&buf).baseZigTypeTag(); | ||
| 169 | }, | ||
| 170 | else => |t| t, | ||
| 171 | }; | ||
| 172 | } | ||
| 173 | |||
| 163 | pub fn isSelfComparable(ty: Type, is_equality_cmp: bool) bool { | 174 | pub fn isSelfComparable(ty: Type, is_equality_cmp: bool) bool { |
| 164 | return switch (ty.zigTypeTag()) { | 175 | return switch (ty.zigTypeTag()) { |
| 165 | .Int, | 176 | .Int, |
| ... | @@ -2459,6 +2470,7 @@ pub const Type = extern union { | ... | @@ -2459,6 +2470,7 @@ pub const Type = extern union { |
| 2459 | if (struct_obj.status == .field_types_wip) { | 2470 | if (struct_obj.status == .field_types_wip) { |
| 2460 | // In this case, we guess that hasRuntimeBits() for this type is true, | 2471 | // In this case, we guess that hasRuntimeBits() for this type is true, |
| 2461 | // and then later if our guess was incorrect, we emit a compile error. | 2472 | // and then later if our guess was incorrect, we emit a compile error. |
| 2473 | struct_obj.assumed_runtime_bits = true; | ||
| 2462 | return true; | 2474 | return true; |
| 2463 | } | 2475 | } |
| 2464 | switch (strat) { | 2476 | switch (strat) { |
| ... | @@ -2491,6 +2503,12 @@ pub const Type = extern union { | ... | @@ -2491,6 +2503,12 @@ pub const Type = extern union { |
| 2491 | 2503 | ||
| 2492 | .@"union" => { | 2504 | .@"union" => { |
| 2493 | const union_obj = ty.castTag(.@"union").?.data; | 2505 | const union_obj = ty.castTag(.@"union").?.data; |
| 2506 | if (union_obj.status == .field_types_wip) { | ||
| 2507 | // In this case, we guess that hasRuntimeBits() for this type is true, | ||
| 2508 | // and then later if our guess was incorrect, we emit a compile error. | ||
| 2509 | union_obj.assumed_runtime_bits = true; | ||
| 2510 | return true; | ||
| 2511 | } | ||
| 2494 | switch (strat) { | 2512 | switch (strat) { |
| 2495 | .sema => |sema| _ = try sema.resolveTypeFields(ty), | 2513 | .sema => |sema| _ = try sema.resolveTypeFields(ty), |
| 2496 | .eager => assert(union_obj.haveFieldTypes()), | 2514 | .eager => assert(union_obj.haveFieldTypes()), |
| ... | @@ -3027,8 +3045,9 @@ pub const Type = extern union { | ... | @@ -3027,8 +3045,9 @@ pub const Type = extern union { |
| 3027 | const struct_obj = ty.castTag(.@"struct").?.data; | 3045 | const struct_obj = ty.castTag(.@"struct").?.data; |
| 3028 | if (opt_sema) |sema| { | 3046 | if (opt_sema) |sema| { |
| 3029 | if (struct_obj.status == .field_types_wip) { | 3047 | if (struct_obj.status == .field_types_wip) { |
| 3030 | // We'll guess "pointer-aligned" and if we guess wrong, emit | 3048 | // We'll guess "pointer-aligned", if the struct has an |
| 3031 | // a compile error later. | 3049 | // underaligned pointer field then some allocations |
| 3050 | // might require explicit alignment. | ||
| 3032 | return AbiAlignmentAdvanced{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) }; | 3051 | return AbiAlignmentAdvanced{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) }; |
| 3033 | } | 3052 | } |
| 3034 | _ = try sema.resolveTypeFields(ty); | 3053 | _ = try sema.resolveTypeFields(ty); |
| ... | @@ -3153,8 +3172,9 @@ pub const Type = extern union { | ... | @@ -3153,8 +3172,9 @@ pub const Type = extern union { |
| 3153 | }; | 3172 | }; |
| 3154 | if (opt_sema) |sema| { | 3173 | if (opt_sema) |sema| { |
| 3155 | if (union_obj.status == .field_types_wip) { | 3174 | if (union_obj.status == .field_types_wip) { |
| 3156 | // We'll guess "pointer-aligned" and if we guess wrong, emit | 3175 | // We'll guess "pointer-aligned", if the union has an |
| 3157 | // a compile error later. | 3176 | // underaligned pointer field then some allocations |
| 3177 | // might require explicit alignment. | ||
| 3158 | return AbiAlignmentAdvanced{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) }; | 3178 | return AbiAlignmentAdvanced{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) }; |
| 3159 | } | 3179 | } |
| 3160 | _ = try sema.resolveTypeFields(ty); | 3180 | _ = try sema.resolveTypeFields(ty); |
| ... | @@ -5233,7 +5253,12 @@ pub const Type = extern union { | ... | @@ -5233,7 +5253,12 @@ pub const Type = extern union { |
| 5233 | .@"struct" => { | 5253 | .@"struct" => { |
| 5234 | const struct_obj = ty.castTag(.@"struct").?.data; | 5254 | const struct_obj = ty.castTag(.@"struct").?.data; |
| 5235 | switch (struct_obj.requires_comptime) { | 5255 | switch (struct_obj.requires_comptime) { |
| 5236 | .wip, .unknown => unreachable, // This function asserts types already resolved. | 5256 | .wip, .unknown => { |
| 5257 | // Return false to avoid incorrect dependency loops. | ||
| 5258 | // This will be handled correctly once merged with | ||
| 5259 | // `Sema.typeRequiresComptime`. | ||
| 5260 | return false; | ||
| 5261 | }, | ||
| 5237 | .no => return false, | 5262 | .no => return false, |
| 5238 | .yes => return true, | 5263 | .yes => return true, |
| 5239 | } | 5264 | } |
| ... | @@ -5242,7 +5267,12 @@ pub const Type = extern union { | ... | @@ -5242,7 +5267,12 @@ pub const Type = extern union { |
| 5242 | .@"union", .union_safety_tagged, .union_tagged => { | 5267 | .@"union", .union_safety_tagged, .union_tagged => { |
| 5243 | const union_obj = ty.cast(Type.Payload.Union).?.data; | 5268 | const union_obj = ty.cast(Type.Payload.Union).?.data; |
| 5244 | switch (union_obj.requires_comptime) { | 5269 | switch (union_obj.requires_comptime) { |
| 5245 | .wip, .unknown => unreachable, // This function asserts types already resolved. | 5270 | .wip, .unknown => { |
| 5271 | // Return false to avoid incorrect dependency loops. | ||
| 5272 | // This will be handled correctly once merged with | ||
| 5273 | // `Sema.typeRequiresComptime`. | ||
| 5274 | return false; | ||
| 5275 | }, | ||
| 5246 | .no => return false, | 5276 | .no => return false, |
| 5247 | .yes => return true, | 5277 | .yes => return true, |
| 5248 | } | 5278 | } |
| ... | @@ -6454,8 +6484,16 @@ pub const Type = extern union { | ... | @@ -6454,8 +6484,16 @@ pub const Type = extern union { |
| 6454 | // type, we change it to 0 here. If this causes an assertion trip because the | 6484 | // type, we change it to 0 here. If this causes an assertion trip because the |
| 6455 | // pointee type needs to be resolved more, that needs to be done before calling | 6485 | // pointee type needs to be resolved more, that needs to be done before calling |
| 6456 | // this ptr() function. | 6486 | // this ptr() function. |
| 6457 | if (d.@"align" != 0 and d.@"align" == d.pointee_type.abiAlignment(target)) { | 6487 | if (d.@"align" != 0) canonicalize: { |
| 6458 | d.@"align" = 0; | 6488 | if (d.pointee_type.castTag(.@"struct")) |struct_ty| { |
| 6489 | if (!struct_ty.data.haveLayout()) break :canonicalize; | ||
| 6490 | } | ||
| 6491 | if (d.pointee_type.cast(Payload.Union)) |union_ty| { | ||
| 6492 | if (!union_ty.data.haveLayout()) break :canonicalize; | ||
| 6493 | } | ||
| 6494 | if (d.@"align" == d.pointee_type.abiAlignment(target)) { | ||
| 6495 | d.@"align" = 0; | ||
| 6496 | } | ||
| 6459 | } | 6497 | } |
| 6460 | 6498 | ||
| 6461 | // Canonicalize host_size. If it matches the bit size of the pointee type, | 6499 | // Canonicalize host_size. If it matches the bit size of the pointee type, |
src/value.zig+16-7| ... | @@ -187,7 +187,7 @@ pub const Value = extern union { | ... | @@ -187,7 +187,7 @@ pub const Value = extern union { |
| 187 | bound_fn, | 187 | bound_fn, |
| 188 | /// The ABI alignment of the payload type. | 188 | /// The ABI alignment of the payload type. |
| 189 | lazy_align, | 189 | lazy_align, |
| 190 | /// The ABI alignment of the payload type. | 190 | /// The ABI size of the payload type. |
| 191 | lazy_size, | 191 | lazy_size, |
| 192 | 192 | ||
| 193 | pub const last_no_payload_tag = Tag.empty_array; | 193 | pub const last_no_payload_tag = Tag.empty_array; |
| ... | @@ -1201,8 +1201,8 @@ pub const Value = extern union { | ... | @@ -1201,8 +1201,8 @@ pub const Value = extern union { |
| 1201 | } | 1201 | } |
| 1202 | 1202 | ||
| 1203 | /// Asserts the value is an integer and it fits in a i64 | 1203 | /// Asserts the value is an integer and it fits in a i64 |
| 1204 | pub fn toSignedInt(self: Value) i64 { | 1204 | pub fn toSignedInt(val: Value, target: Target) i64 { |
| 1205 | switch (self.tag()) { | 1205 | switch (val.tag()) { |
| 1206 | .zero, | 1206 | .zero, |
| 1207 | .bool_false, | 1207 | .bool_false, |
| 1208 | .the_only_possible_value, // i0, u0 | 1208 | .the_only_possible_value, // i0, u0 |
| ... | @@ -1212,10 +1212,19 @@ pub const Value = extern union { | ... | @@ -1212,10 +1212,19 @@ pub const Value = extern union { |
| 1212 | .bool_true, | 1212 | .bool_true, |
| 1213 | => return 1, | 1213 | => return 1, |
| 1214 | 1214 | ||
| 1215 | .int_u64 => return @intCast(i64, self.castTag(.int_u64).?.data), | 1215 | .int_u64 => return @intCast(i64, val.castTag(.int_u64).?.data), |
| 1216 | .int_i64 => return self.castTag(.int_i64).?.data, | 1216 | .int_i64 => return val.castTag(.int_i64).?.data, |
| 1217 | .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().to(i64) catch unreachable, | 1217 | .int_big_positive => return val.castTag(.int_big_positive).?.asBigInt().to(i64) catch unreachable, |
| 1218 | .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().to(i64) catch unreachable, | 1218 | .int_big_negative => return val.castTag(.int_big_negative).?.asBigInt().to(i64) catch unreachable, |
| 1219 | |||
| 1220 | .lazy_align => { | ||
| 1221 | const ty = val.castTag(.lazy_align).?.data; | ||
| 1222 | return @intCast(i64, ty.abiAlignment(target)); | ||
| 1223 | }, | ||
| 1224 | .lazy_size => { | ||
| 1225 | const ty = val.castTag(.lazy_size).?.data; | ||
| 1226 | return @intCast(i64, ty.abiSize(target)); | ||
| 1227 | }, | ||
| 1219 | 1228 | ||
| 1220 | .undef => unreachable, | 1229 | .undef => unreachable, |
| 1221 | else => unreachable, | 1230 | else => unreachable, |
test/behavior.zig+1| ... | @@ -90,6 +90,7 @@ test { | ... | @@ -90,6 +90,7 @@ test { |
| 90 | _ = @import("behavior/bugs/12430.zig"); | 90 | _ = @import("behavior/bugs/12430.zig"); |
| 91 | _ = @import("behavior/bugs/12486.zig"); | 91 | _ = @import("behavior/bugs/12486.zig"); |
| 92 | _ = @import("behavior/bugs/12488.zig"); | 92 | _ = @import("behavior/bugs/12488.zig"); |
| 93 | _ = @import("behavior/bugs/12498.zig"); | ||
| 93 | _ = @import("behavior/bugs/12551.zig"); | 94 | _ = @import("behavior/bugs/12551.zig"); |
| 94 | _ = @import("behavior/bugs/12644.zig"); | 95 | _ = @import("behavior/bugs/12644.zig"); |
| 95 | _ = @import("behavior/bugs/12680.zig"); | 96 | _ = @import("behavior/bugs/12680.zig"); |
test/behavior/bugs/12498.zig created+8| ... | @@ -0,0 +1,8 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | const S = struct { a: usize }; | ||
| 5 | test "lazy abi size used in comparison" { | ||
| 6 | var rhs: i32 = 100; | ||
| 7 | try expect(@sizeOf(S) < rhs); | ||
| 8 | } | ||
test/behavior/struct.zig+12| ... | @@ -1418,3 +1418,15 @@ test "address of zero-bit field is equal to address of only field" { | ... | @@ -1418,3 +1418,15 @@ test "address of zero-bit field is equal to address of only field" { |
| 1418 | try std.testing.expectEqual(&a, a_ptr); | 1418 | try std.testing.expectEqual(&a, a_ptr); |
| 1419 | } | 1419 | } |
| 1420 | } | 1420 | } |
| 1421 | |||
| 1422 | test "struct field has a pointer to an aligned version of itself" { | ||
| 1423 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | ||
| 1424 | |||
| 1425 | const E = struct { | ||
| 1426 | next: *align(1) @This(), | ||
| 1427 | }; | ||
| 1428 | var e: E = undefined; | ||
| 1429 | e = .{ .next = &e }; | ||
| 1430 | |||
| 1431 | try expect(&e == e.next); | ||
| 1432 | } |
test/cases/aarch64-macos/hello_world_with_updates.1.zig+2-2| ... | @@ -2,5 +2,5 @@ pub export fn main() noreturn {} | ... | @@ -2,5 +2,5 @@ pub export fn main() noreturn {} |
| 2 | 2 | ||
| 3 | // error | 3 | // error |
| 4 | // | 4 | // |
| 5 | // :1:32: error: function declared 'noreturn' returns | 5 | // :1:22: error: function declared 'noreturn' implicitly returns |
| 6 | // :1:22: note: 'noreturn' declared here | 6 | // :1:32: note: control flow reaches end of body here |
test/cases/compile_errors/calling_var_args_extern_function_passing_array_instead_of_pointer.zig+1| ... | @@ -8,3 +8,4 @@ pub extern fn foo(format: *const u8, ...) void; | ... | @@ -8,3 +8,4 @@ pub extern fn foo(format: *const u8, ...) void; |
| 8 | // target=native | 8 | // target=native |
| 9 | // | 9 | // |
| 10 | // :2:16: error: expected type '*const u8', found '[5:0]u8' | 10 | // :2:16: error: expected type '*const u8', found '[5:0]u8' |
| 11 | // :4:27: note: parameter type declared here |
test/cases/compile_errors/casting_bit_offset_pointer_to_regular_pointer.zig+1| ... | @@ -21,3 +21,4 @@ export fn entry() usize { return @sizeOf(@TypeOf(&foo)); } | ... | @@ -21,3 +21,4 @@ export fn entry() usize { return @sizeOf(@TypeOf(&foo)); } |
| 21 | // :8:16: error: expected type '*const u3', found '*align(0:3:1) const u3' | 21 | // :8:16: error: expected type '*const u3', found '*align(0:3:1) const u3' |
| 22 | // :8:16: note: pointer host size '1' cannot cast into pointer host size '0' | 22 | // :8:16: note: pointer host size '1' cannot cast into pointer host size '0' |
| 23 | // :8:16: note: pointer bit offset '3' cannot cast into pointer bit offset '0' | 23 | // :8:16: note: pointer bit offset '3' cannot cast into pointer bit offset '0' |
| 24 | // :11:11: note: parameter type declared here |
test/cases/compile_errors/closure_get_in_param_ty_instantiate_incorrectly.zig+1| ... | @@ -22,3 +22,4 @@ pub export fn entry() void { | ... | @@ -22,3 +22,4 @@ pub export fn entry() void { |
| 22 | // target=native | 22 | // target=native |
| 23 | // | 23 | // |
| 24 | // :17:25: error: expected type 'u32', found 'type' | 24 | // :17:25: error: expected type 'u32', found 'type' |
| 25 | // :3:21: note: parameter type declared here |
test/cases/compile_errors/control_reaches_end_of_non-void_function.zig deleted-9| ... | @@ -1,9 +0,0 @@ | ||
| 1 | fn a() i32 {} | ||
| 2 | export fn entry() void { _ = a(); } | ||
| 3 | |||
| 4 | // error | ||
| 5 | // backend=stage2 | ||
| 6 | // target=native | ||
| 7 | // | ||
| 8 | // :1:13: error: expected type 'i32', found 'void' | ||
| 9 | // :1:8: note: function return type declared here | ||
test/cases/compile_errors/disallow_coercion_from_non-null-terminated_pointer_to_null-terminated_pointer.zig+1| ... | @@ -11,3 +11,4 @@ pub export fn entry() void { | ... | @@ -11,3 +11,4 @@ pub export fn entry() void { |
| 11 | // | 11 | // |
| 12 | // :5:14: error: expected type '[*:0]const u8', found '[*]const u8' | 12 | // :5:14: error: expected type '[*:0]const u8', found '[*]const u8' |
| 13 | // :5:14: note: destination pointer requires '0' sentinel | 13 | // :5:14: note: destination pointer requires '0' sentinel |
| 14 | // :1:20: note: parameter type declared here |
test/cases/compile_errors/double_pointer_to_anyopaque_pointer.zig+1| ... | @@ -24,5 +24,6 @@ pub export fn entry3() void { | ... | @@ -24,5 +24,6 @@ pub export fn entry3() void { |
| 24 | // :4:35: note: cannot implicitly cast double pointer '*const *const usize' to anyopaque pointer '*const anyopaque' | 24 | // :4:35: note: cannot implicitly cast double pointer '*const *const usize' to anyopaque pointer '*const anyopaque' |
| 25 | // :9:10: error: expected type '?*anyopaque', found '*[*:0]u8' | 25 | // :9:10: error: expected type '?*anyopaque', found '*[*:0]u8' |
| 26 | // :9:10: note: cannot implicitly cast double pointer '*[*:0]u8' to anyopaque pointer '?*anyopaque' | 26 | // :9:10: note: cannot implicitly cast double pointer '*[*:0]u8' to anyopaque pointer '?*anyopaque' |
| 27 | // :11:12: note: parameter type declared here | ||
| 27 | // :15:35: error: expected type '*const anyopaque', found '*?*usize' | 28 | // :15:35: error: expected type '*const anyopaque', found '*?*usize' |
| 28 | // :15:35: note: cannot implicitly cast double pointer '*?*usize' to anyopaque pointer '*const anyopaque' | 29 | // :15:35: note: cannot implicitly cast double pointer '*?*usize' to anyopaque pointer '*const anyopaque' |
test/cases/compile_errors/implicitly_increasing_pointer_alignment.zig+1| ... | @@ -18,3 +18,4 @@ fn bar(x: *u32) void { | ... | @@ -18,3 +18,4 @@ fn bar(x: *u32) void { |
| 18 | // | 18 | // |
| 19 | // :8:9: error: expected type '*u32', found '*align(1) u32' | 19 | // :8:9: error: expected type '*u32', found '*align(1) u32' |
| 20 | // :8:9: note: pointer alignment '1' cannot cast into pointer alignment '4' | 20 | // :8:9: note: pointer alignment '1' cannot cast into pointer alignment '4' |
| 21 | // :11:11: note: parameter type declared here |
test/cases/compile_errors/invalid_compare_string.zig created+29| ... | @@ -0,0 +1,29 @@ | ||
| 1 | comptime { | ||
| 2 | var a = "foo"; | ||
| 3 | if (a == "foo") unreachable; | ||
| 4 | } | ||
| 5 | comptime { | ||
| 6 | var a = "foo"; | ||
| 7 | if (a == ("foo")) unreachable; // intentionally allow | ||
| 8 | } | ||
| 9 | comptime { | ||
| 10 | var a = "foo"; | ||
| 11 | switch (a) { | ||
| 12 | "foo" => unreachable, | ||
| 13 | else => {}, | ||
| 14 | } | ||
| 15 | } | ||
| 16 | comptime { | ||
| 17 | var a = "foo"; | ||
| 18 | switch (a) { | ||
| 19 | ("foo") => unreachable, // intentionally allow | ||
| 20 | else => {}, | ||
| 21 | } | ||
| 22 | } | ||
| 23 | |||
| 24 | // error | ||
| 25 | // backend=stage2 | ||
| 26 | // target=native | ||
| 27 | // | ||
| 28 | // :3:11: error: cannot compare strings with == | ||
| 29 | // :12:9: error: cannot switch on strings | ||
test/cases/compile_errors/invalid_dependency_on_struct_size.zig created+19| ... | @@ -0,0 +1,19 @@ | ||
| 1 | comptime { | ||
| 2 | const S = struct { | ||
| 3 | const Foo = struct { | ||
| 4 | y: Bar, | ||
| 5 | }; | ||
| 6 | const Bar = struct { | ||
| 7 | y: if (@sizeOf(Foo) == 0) u64 else void, | ||
| 8 | }; | ||
| 9 | }; | ||
| 10 | |||
| 11 | _ = @sizeOf(S.Foo) + 1; | ||
| 12 | } | ||
| 13 | |||
| 14 | // error | ||
| 15 | // backend=stage2 | ||
| 16 | // target=native | ||
| 17 | // | ||
| 18 | // :6:21: error: struct layout depends on it having runtime bits | ||
| 19 | // :4:13: note: while checking this field | ||
test/cases/compile_errors/missing_parameter_name.zig created+19| ... | @@ -0,0 +1,19 @@ | ||
| 1 | fn f2(u64) u64 { | ||
| 2 | return x; | ||
| 3 | } | ||
| 4 | fn f3(*x) u64 { | ||
| 5 | return x; | ||
| 6 | } | ||
| 7 | fn f1(x) u64 { | ||
| 8 | return x; | ||
| 9 | } | ||
| 10 | |||
| 11 | // error | ||
| 12 | // backend=stage2 | ||
| 13 | // target=native | ||
| 14 | // | ||
| 15 | // :1:7: error: missing parameter name | ||
| 16 | // :4:7: error: missing parameter name | ||
| 17 | // :7:7: error: missing parameter name or type | ||
| 18 | // :7:7: note: if this is a name, annotate its type 'x: T' | ||
| 19 | // :7:7: note: if this is a type, give it a name '<name>: x' | ||
test/cases/compile_errors/pass_const_ptr_to_mutable_ptr_fn.zig+1| ... | @@ -16,3 +16,4 @@ export fn entry() usize { return @sizeOf(@TypeOf(&foo)); } | ... | @@ -16,3 +16,4 @@ export fn entry() usize { return @sizeOf(@TypeOf(&foo)); } |
| 16 | // | 16 | // |
| 17 | // :4:19: error: expected type '*[]const u8', found '*const []const u8' | 17 | // :4:19: error: expected type '*[]const u8', found '*const []const u8' |
| 18 | // :4:19: note: cast discards const qualifier | 18 | // :4:19: note: cast discards const qualifier |
| 19 | // :6:14: note: parameter type declared here |
test/cases/compile_errors/struct_init_passed_to_type_param.zig+1| ... | @@ -12,3 +12,4 @@ export const value = hi(MyStruct{ .x = 12 }); | ... | @@ -12,3 +12,4 @@ export const value = hi(MyStruct{ .x = 12 }); |
| 12 | // | 12 | // |
| 13 | // :7:33: error: expected type 'type', found 'tmp.MyStruct' | 13 | // :7:33: error: expected type 'type', found 'tmp.MyStruct' |
| 14 | // :1:18: note: struct declared here | 14 | // :1:18: note: struct declared here |
| 15 | // :3:19: note: parameter type declared here |
test/cases/compile_errors/struct_type_mismatch_in_arg.zig created+18| ... | @@ -0,0 +1,18 @@ | ||
| 1 | const Foo = struct { i: i32 }; | ||
| 2 | const Bar = struct { j: i32 }; | ||
| 3 | |||
| 4 | pub fn helper(_: Foo, _: Bar) void { } | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | helper(Bar { .j = 10 }, Bar { .j = 10 }); | ||
| 8 | helper(Bar { .i = 10 }, Bar { .j = 10 }); | ||
| 9 | } | ||
| 10 | |||
| 11 | // error | ||
| 12 | // backend=stage2 | ||
| 13 | // target=native | ||
| 14 | // | ||
| 15 | // :7:16: error: expected type 'tmp.Foo', found 'tmp.Bar' | ||
| 16 | // :1:13: note: struct declared here | ||
| 17 | // :2:13: note: struct declared here | ||
| 18 | // :4:18: note: parameter type declared here | ||
test/cases/compile_errors/switch_on_slice.zig+1-1| ... | @@ -1,7 +1,7 @@ | ... | @@ -1,7 +1,7 @@ |
| 1 | pub export fn entry() void { | 1 | pub export fn entry() void { |
| 2 | var a: [:0]const u8 = "foo"; | 2 | var a: [:0]const u8 = "foo"; |
| 3 | switch (a) { | 3 | switch (a) { |
| 4 | "--version", "version" => unreachable, | 4 | ("--version"), ("version") => unreachable, |
| 5 | else => {}, | 5 | else => {}, |
| 6 | } | 6 | } |
| 7 | } | 7 | } |
test/cases/compile_errors/type_error_in_implicit_return.zig created+17| ... | @@ -0,0 +1,17 @@ | ||
| 1 | fn f1(x: bool) u32 { | ||
| 2 | if (x) return 1; | ||
| 3 | } | ||
| 4 | fn f2() noreturn {} | ||
| 5 | pub export fn entry() void { | ||
| 6 | _ = f1(true); | ||
| 7 | _ = f2(); | ||
| 8 | } | ||
| 9 | |||
| 10 | // error | ||
| 11 | // backend=stage2 | ||
| 12 | // target=native | ||
| 13 | // | ||
| 14 | // :1:16: error: function with non-void return type 'u32' implicitly returns | ||
| 15 | // :3:1: note: control flow reaches end of body here | ||
| 16 | // :4:9: error: function declared 'noreturn' implicitly returns | ||
| 17 | // :4:19: note: control flow reaches end of body here | ||
test/cases/compile_errors/wrong_pointer_coerced_to_pointer_to_opaque_{}.zig+1| ... | @@ -12,3 +12,4 @@ export fn foo() void { | ... | @@ -12,3 +12,4 @@ export fn foo() void { |
| 12 | // :5:9: error: expected type '*tmp.Derp', found '*anyopaque' | 12 | // :5:9: error: expected type '*tmp.Derp', found '*anyopaque' |
| 13 | // :5:9: note: pointer type child 'anyopaque' cannot cast into pointer type child 'tmp.Derp' | 13 | // :5:9: note: pointer type child 'anyopaque' cannot cast into pointer type child 'tmp.Derp' |
| 14 | // :1:14: note: opaque declared here | 14 | // :1:14: note: opaque declared here |
| 15 | // :2:18: note: parameter type declared here |
test/cases/x86_64-linux/hello_world_with_updates.1.zig+3-3| ... | @@ -1,6 +1,6 @@ | ... | @@ -1,6 +1,6 @@ |
| 1 | pub export fn _start() noreturn {} | 1 | pub export fn main() noreturn {} |
| 2 | 2 | ||
| 3 | // error | 3 | // error |
| 4 | // | 4 | // |
| 5 | // :1:34: error: function declared 'noreturn' returns | 5 | // :1:22: error: function declared 'noreturn' implicitly returns |
| 6 | // :1:24: note: 'noreturn' declared here | 6 | // :1:32: note: control flow reaches end of body here |
test/cases/x86_64-macos/hello_world_with_updates.1.zig+2-2| ... | @@ -2,5 +2,5 @@ pub export fn main() noreturn {} | ... | @@ -2,5 +2,5 @@ pub export fn main() noreturn {} |
| 2 | 2 | ||
| 3 | // error | 3 | // error |
| 4 | // | 4 | // |
| 5 | // :1:32: error: function declared 'noreturn' returns | 5 | // :1:22: error: function declared 'noreturn' implicitly returns |
| 6 | // :1:22: note: 'noreturn' declared here | 6 | // :1:32: note: control flow reaches end of body here |
test/cases/x86_64-windows/hello_world_with_updates.1.zig+2-2| ... | @@ -2,5 +2,5 @@ pub export fn main() noreturn {} | ... | @@ -2,5 +2,5 @@ pub export fn main() noreturn {} |
| 2 | 2 | ||
| 3 | // error | 3 | // error |
| 4 | // | 4 | // |
| 5 | // :1:32: error: function declared 'noreturn' returns | 5 | // :1:22: error: function declared 'noreturn' implicitly returns |
| 6 | // :1:22: note: 'noreturn' declared here | 6 | // :1:32: note: control flow reaches end of body here |