| author | |
| committer | |
| log | fdbb0fb7b9c08ebff1b7e45ef89f7160f350d44c |
| tree | 714f2766c64ace45df1f7d67ca70be0c88193184 |
| parent | c43ac67f82cb5a022df67729aa1e6bebc22cfff2 |
| parent | b500e0eb179218f5eb03408c09b5e5a928f0c46e |
| signature |
Improve error messages, fix dependency loops40 files changed, 378 insertions(+), 95 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| ... | @@ -2632,7 +2632,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As | ... | @@ -2632,7 +2632,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As |
| 2632 | .compile_error, | 2632 | .compile_error, |
| 2633 | .ret_node, | 2633 | .ret_node, |
| 2634 | .ret_load, | 2634 | .ret_load, |
| 2635 | .ret_tok, | 2635 | .ret_implicit, |
| 2636 | .ret_err_value, | 2636 | .ret_err_value, |
| 2637 | .@"unreachable", | 2637 | .@"unreachable", |
| 2638 | .repeat, | 2638 | .repeat, |
| ... | @@ -3696,6 +3696,29 @@ fn fnDecl( | ... | @@ -3696,6 +3696,29 @@ fn fnDecl( |
| 3696 | if (param.anytype_ellipsis3) |tok| { | 3696 | if (param.anytype_ellipsis3) |tok| { |
| 3697 | return astgen.failTok(tok, "missing parameter name", .{}); | 3697 | return astgen.failTok(tok, "missing parameter name", .{}); |
| 3698 | } else { | 3698 | } else { |
| 3699 | ambiguous: { | ||
| 3700 | if (tree.nodes.items(.tag)[param.type_expr] != .identifier) break :ambiguous; | ||
| 3701 | const main_token = tree.nodes.items(.main_token)[param.type_expr]; | ||
| 3702 | const identifier_str = tree.tokenSlice(main_token); | ||
| 3703 | if (isPrimitive(identifier_str)) break :ambiguous; | ||
| 3704 | return astgen.failNodeNotes( | ||
| 3705 | param.type_expr, | ||
| 3706 | "missing parameter name or type", | ||
| 3707 | .{}, | ||
| 3708 | &[_]u32{ | ||
| 3709 | try astgen.errNoteNode( | ||
| 3710 | param.type_expr, | ||
| 3711 | "if this is a name, annotate its type '{s}: T'", | ||
| 3712 | .{identifier_str}, | ||
| 3713 | ), | ||
| 3714 | try astgen.errNoteNode( | ||
| 3715 | param.type_expr, | ||
| 3716 | "if this is a type, give it a name '<name>: {s}'", | ||
| 3717 | .{identifier_str}, | ||
| 3718 | ), | ||
| 3719 | }, | ||
| 3720 | ); | ||
| 3721 | } | ||
| 3699 | return astgen.failNode(param.type_expr, "missing parameter name", .{}); | 3722 | return astgen.failNode(param.type_expr, "missing parameter name", .{}); |
| 3700 | } | 3723 | } |
| 3701 | } else 0; | 3724 | } else 0; |
| ... | @@ -3891,9 +3914,8 @@ fn fnDecl( | ... | @@ -3891,9 +3914,8 @@ fn fnDecl( |
| 3891 | // As our last action before the return, "pop" the error trace if needed | 3914 | // As our last action before the return, "pop" the error trace if needed |
| 3892 | _ = try gz.addRestoreErrRetIndex(.ret, .always); | 3915 | _ = try gz.addRestoreErrRetIndex(.ret, .always); |
| 3893 | 3916 | ||
| 3894 | // Since we are adding the return instruction here, we must handle the coercion. | 3917 | // Add implicit return at end of function. |
| 3895 | // We do this by using the `ret_tok` instruction. | 3918 | _ = try fn_gz.addUnTok(.ret_implicit, .void_value, tree.lastToken(body_node)); |
| 3896 | _ = try fn_gz.addUnTok(.ret_tok, .void_value, tree.lastToken(body_node)); | ||
| 3897 | } | 3919 | } |
| 3898 | 3920 | ||
| 3899 | break :func try decl_gz.addFunc(.{ | 3921 | break :func try decl_gz.addFunc(.{ |
| ... | @@ -4311,9 +4333,8 @@ fn testDecl( | ... | @@ -4311,9 +4333,8 @@ fn testDecl( |
| 4311 | // As our last action before the return, "pop" the error trace if needed | 4333 | // As our last action before the return, "pop" the error trace if needed |
| 4312 | _ = try gz.addRestoreErrRetIndex(.ret, .always); | 4334 | _ = try gz.addRestoreErrRetIndex(.ret, .always); |
| 4313 | 4335 | ||
| 4314 | // Since we are adding the return instruction here, we must handle the coercion. | 4336 | // Add implicit return at end of function. |
| 4315 | // We do this by using the `ret_tok` instruction. | 4337 | _ = try fn_block.addUnTok(.ret_implicit, .void_value, tree.lastToken(body_node)); |
| 4316 | _ = try fn_block.addUnTok(.ret_tok, .void_value, tree.lastToken(body_node)); | ||
| 4317 | } | 4338 | } |
| 4318 | 4339 | ||
| 4319 | const func_inst = try decl_block.addFunc(.{ | 4340 | const func_inst = try decl_block.addFunc(.{ |
| ... | @@ -5605,6 +5626,14 @@ fn simpleBinOp( | ... | @@ -5605,6 +5626,14 @@ fn simpleBinOp( |
| 5605 | const tree = astgen.tree; | 5626 | const tree = astgen.tree; |
| 5606 | const node_datas = tree.nodes.items(.data); | 5627 | const node_datas = tree.nodes.items(.data); |
| 5607 | 5628 | ||
| 5629 | if (op_inst_tag == .cmp_neq or op_inst_tag == .cmp_eq) { | ||
| 5630 | const node_tags = tree.nodes.items(.tag); | ||
| 5631 | const str = if (op_inst_tag == .cmp_eq) "==" else "!="; | ||
| 5632 | if (node_tags[node_datas[node].lhs] == .string_literal or | ||
| 5633 | node_tags[node_datas[node].rhs] == .string_literal) | ||
| 5634 | return astgen.failNode(node, "cannot compare strings with {s}", .{str}); | ||
| 5635 | } | ||
| 5636 | |||
| 5608 | const lhs = try reachableExpr(gz, scope, .{ .rl = .none }, node_datas[node].lhs, node); | 5637 | const lhs = try reachableExpr(gz, scope, .{ .rl = .none }, node_datas[node].lhs, node); |
| 5609 | var line: u32 = undefined; | 5638 | var line: u32 = undefined; |
| 5610 | var column: u32 = undefined; | 5639 | var column: u32 = undefined; |
| ... | @@ -6602,6 +6631,11 @@ fn switchExpr( | ... | @@ -6602,6 +6631,11 @@ fn switchExpr( |
| 6602 | continue; | 6631 | continue; |
| 6603 | } | 6632 | } |
| 6604 | 6633 | ||
| 6634 | for (case.ast.values) |val| { | ||
| 6635 | if (node_tags[val] == .string_literal) | ||
| 6636 | return astgen.failNode(val, "cannot switch on strings", .{}); | ||
| 6637 | } | ||
| 6638 | |||
| 6605 | if (case.ast.values.len == 1 and node_tags[case.ast.values[0]] != .switch_range) { | 6639 | if (case.ast.values.len == 1 and node_tags[case.ast.values[0]] != .switch_range) { |
| 6606 | scalar_cases_len += 1; | 6640 | scalar_cases_len += 1; |
| 6607 | } else { | 6641 | } else { |
src/Module.zig+2| ... | @@ -940,6 +940,7 @@ pub const Struct = struct { | ... | @@ -940,6 +940,7 @@ pub const Struct = struct { |
| 940 | requires_comptime: PropertyBoolean = .unknown, | 940 | requires_comptime: PropertyBoolean = .unknown, |
| 941 | have_field_inits: bool = false, | 941 | have_field_inits: bool = false, |
| 942 | is_tuple: bool, | 942 | is_tuple: bool, |
| 943 | assumed_runtime_bits: bool = false, | ||
| 943 | 944 | ||
| 944 | pub const Fields = std.StringArrayHashMapUnmanaged(Field); | 945 | pub const Fields = std.StringArrayHashMapUnmanaged(Field); |
| 945 | 946 | ||
| ... | @@ -1205,6 +1206,7 @@ pub const Union = struct { | ... | @@ -1205,6 +1206,7 @@ pub const Union = struct { |
| 1205 | fully_resolved, | 1206 | fully_resolved, |
| 1206 | }, | 1207 | }, |
| 1207 | requires_comptime: PropertyBoolean = .unknown, | 1208 | requires_comptime: PropertyBoolean = .unknown, |
| 1209 | assumed_runtime_bits: bool = false, | ||
| 1208 | 1210 | ||
| 1209 | pub const Field = struct { | 1211 | pub const Field = struct { |
| 1210 | /// undefined until `status` is `have_field_types` or `have_layout`. | 1212 | /// undefined until `status` is `have_field_types` or `have_layout`. |
src/Sema.zig+106-27| ... | @@ -291,8 +291,8 @@ pub const Block = struct { | ... | @@ -291,8 +291,8 @@ pub const Block = struct { |
| 291 | try sema.errNote(ci.block, ci.src, parent, prefix ++ "it is inside a @cImport", .{}); | 291 | try sema.errNote(ci.block, ci.src, parent, prefix ++ "it is inside a @cImport", .{}); |
| 292 | }, | 292 | }, |
| 293 | .comptime_ret_ty => |rt| { | 293 | .comptime_ret_ty => |rt| { |
| 294 | const src_loc = if (try sema.funcDeclSrc(rt.func)) |capture| blk: { | 294 | const src_loc = if (try sema.funcDeclSrc(rt.func)) |fn_decl| blk: { |
| 295 | var src_loc = capture; | 295 | var src_loc = fn_decl.srcLoc(); |
| 296 | src_loc.lazy = .{ .node_offset_fn_type_ret_ty = 0 }; | 296 | src_loc.lazy = .{ .node_offset_fn_type_ret_ty = 0 }; |
| 297 | break :blk src_loc; | 297 | break :blk src_loc; |
| 298 | } else blk: { | 298 | } else blk: { |
| ... | @@ -1098,7 +1098,7 @@ fn analyzeBodyInner( | ... | @@ -1098,7 +1098,7 @@ fn analyzeBodyInner( |
| 1098 | // These functions match the return type of analyzeBody so that we can | 1098 | // These functions match the return type of analyzeBody so that we can |
| 1099 | // tail call them here. | 1099 | // tail call them here. |
| 1100 | .compile_error => break sema.zirCompileError(block, inst), | 1100 | .compile_error => break sema.zirCompileError(block, inst), |
| 1101 | .ret_tok => break sema.zirRetTok(block, inst), | 1101 | .ret_implicit => break sema.zirRetImplicit(block, inst), |
| 1102 | .ret_node => break sema.zirRetNode(block, inst), | 1102 | .ret_node => break sema.zirRetNode(block, inst), |
| 1103 | .ret_load => break sema.zirRetLoad(block, inst), | 1103 | .ret_load => break sema.zirRetLoad(block, inst), |
| 1104 | .ret_err_value => break sema.zirRetErrValue(block, inst), | 1104 | .ret_err_value => break sema.zirRetErrValue(block, inst), |
| ... | @@ -5843,7 +5843,7 @@ fn lookupInNamespace( | ... | @@ -5843,7 +5843,7 @@ fn lookupInNamespace( |
| 5843 | return null; | 5843 | return null; |
| 5844 | } | 5844 | } |
| 5845 | 5845 | ||
| 5846 | fn funcDeclSrc(sema: *Sema, func_inst: Air.Inst.Ref) !?Module.SrcLoc { | 5846 | fn funcDeclSrc(sema: *Sema, func_inst: Air.Inst.Ref) !?*Decl { |
| 5847 | const func_val = (try sema.resolveMaybeUndefVal(func_inst)) orelse return null; | 5847 | const func_val = (try sema.resolveMaybeUndefVal(func_inst)) orelse return null; |
| 5848 | if (func_val.isUndef()) return null; | 5848 | if (func_val.isUndef()) return null; |
| 5849 | const owner_decl_index = switch (func_val.tag()) { | 5849 | const owner_decl_index = switch (func_val.tag()) { |
| ... | @@ -5852,8 +5852,7 @@ fn funcDeclSrc(sema: *Sema, func_inst: Air.Inst.Ref) !?Module.SrcLoc { | ... | @@ -5852,8 +5852,7 @@ fn funcDeclSrc(sema: *Sema, func_inst: Air.Inst.Ref) !?Module.SrcLoc { |
| 5852 | .decl_ref => sema.mod.declPtr(func_val.castTag(.decl_ref).?.data).val.castTag(.function).?.data.owner_decl, | 5852 | .decl_ref => sema.mod.declPtr(func_val.castTag(.decl_ref).?.data).val.castTag(.function).?.data.owner_decl, |
| 5853 | else => return null, | 5853 | else => return null, |
| 5854 | }; | 5854 | }; |
| 5855 | const owner_decl = sema.mod.declPtr(owner_decl_index); | 5855 | return sema.mod.declPtr(owner_decl_index); |
| 5856 | return owner_decl.srcLoc(); | ||
| 5857 | } | 5856 | } |
| 5858 | 5857 | ||
| 5859 | pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref { | 5858 | pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref { |
| ... | @@ -6031,7 +6030,7 @@ fn zirCall( | ... | @@ -6031,7 +6030,7 @@ fn zirCall( |
| 6031 | break :check_args; | 6030 | break :check_args; |
| 6032 | } | 6031 | } |
| 6033 | 6032 | ||
| 6034 | const decl_src = try sema.funcDeclSrc(func); | 6033 | const maybe_decl = try sema.funcDeclSrc(func); |
| 6035 | const member_str = if (bound_arg_src != null) "member function " else ""; | 6034 | const member_str = if (bound_arg_src != null) "member function " else ""; |
| 6036 | const variadic_str = if (func_ty_info.is_var_args) "at least " else ""; | 6035 | const variadic_str = if (func_ty_info.is_var_args) "at least " else ""; |
| 6037 | const msg = msg: { | 6036 | const msg = msg: { |
| ... | @@ -6048,7 +6047,7 @@ fn zirCall( | ... | @@ -6048,7 +6047,7 @@ fn zirCall( |
| 6048 | ); | 6047 | ); |
| 6049 | errdefer msg.destroy(sema.gpa); | 6048 | errdefer msg.destroy(sema.gpa); |
| 6050 | 6049 | ||
| 6051 | if (decl_src) |some| try sema.mod.errNoteNonLazy(some, msg, "function declared here", .{}); | 6050 | if (maybe_decl) |fn_decl| try sema.mod.errNoteNonLazy(fn_decl.srcLoc(), msg, "function declared here", .{}); |
| 6052 | break :msg msg; | 6051 | break :msg msg; |
| 6053 | }; | 6052 | }; |
| 6054 | return sema.failWithOwnedErrorMsg(msg); | 6053 | return sema.failWithOwnedErrorMsg(msg); |
| ... | @@ -6242,7 +6241,7 @@ fn analyzeCall( | ... | @@ -6242,7 +6241,7 @@ fn analyzeCall( |
| 6242 | const func_ty_info = func_ty.fnInfo(); | 6241 | const func_ty_info = func_ty.fnInfo(); |
| 6243 | const cc = func_ty_info.cc; | 6242 | const cc = func_ty_info.cc; |
| 6244 | if (cc == .Naked) { | 6243 | if (cc == .Naked) { |
| 6245 | const decl_src = try sema.funcDeclSrc(func); | 6244 | const maybe_decl = try sema.funcDeclSrc(func); |
| 6246 | const msg = msg: { | 6245 | const msg = msg: { |
| 6247 | const msg = try sema.errMsg( | 6246 | const msg = try sema.errMsg( |
| 6248 | block, | 6247 | block, |
| ... | @@ -6252,7 +6251,7 @@ fn analyzeCall( | ... | @@ -6252,7 +6251,7 @@ fn analyzeCall( |
| 6252 | ); | 6251 | ); |
| 6253 | errdefer msg.destroy(sema.gpa); | 6252 | errdefer msg.destroy(sema.gpa); |
| 6254 | 6253 | ||
| 6255 | if (decl_src) |some| try sema.mod.errNoteNonLazy(some, msg, "function declared here", .{}); | 6254 | if (maybe_decl) |fn_decl| try sema.mod.errNoteNonLazy(fn_decl.srcLoc(), msg, "function declared here", .{}); |
| 6256 | break :msg msg; | 6255 | break :msg msg; |
| 6257 | }; | 6256 | }; |
| 6258 | return sema.failWithOwnedErrorMsg(msg); | 6257 | return sema.failWithOwnedErrorMsg(msg); |
| ... | @@ -6488,6 +6487,7 @@ fn analyzeCall( | ... | @@ -6488,6 +6487,7 @@ fn analyzeCall( |
| 6488 | &should_memoize, | 6487 | &should_memoize, |
| 6489 | memoized_call_key, | 6488 | memoized_call_key, |
| 6490 | func_ty_info.param_types, | 6489 | func_ty_info.param_types, |
| 6490 | func, | ||
| 6491 | ) catch |err| switch (err) { | 6491 | ) catch |err| switch (err) { |
| 6492 | error.NeededSourceLocation => { | 6492 | error.NeededSourceLocation => { |
| 6493 | _ = sema.inst_map.remove(inst); | 6493 | _ = sema.inst_map.remove(inst); |
| ... | @@ -6504,6 +6504,7 @@ fn analyzeCall( | ... | @@ -6504,6 +6504,7 @@ fn analyzeCall( |
| 6504 | &should_memoize, | 6504 | &should_memoize, |
| 6505 | memoized_call_key, | 6505 | memoized_call_key, |
| 6506 | func_ty_info.param_types, | 6506 | func_ty_info.param_types, |
| 6507 | func, | ||
| 6507 | ); | 6508 | ); |
| 6508 | return error.AnalysisFail; | 6509 | return error.AnalysisFail; |
| 6509 | }, | 6510 | }, |
| ... | @@ -6646,12 +6647,17 @@ fn analyzeCall( | ... | @@ -6646,12 +6647,17 @@ fn analyzeCall( |
| 6646 | const args = try sema.arena.alloc(Air.Inst.Ref, uncasted_args.len); | 6647 | const args = try sema.arena.alloc(Air.Inst.Ref, uncasted_args.len); |
| 6647 | for (uncasted_args) |uncasted_arg, i| { | 6648 | for (uncasted_args) |uncasted_arg, i| { |
| 6648 | if (i < fn_params_len) { | 6649 | if (i < fn_params_len) { |
| 6650 | const opts: CoerceOpts = .{ .param_src = .{ | ||
| 6651 | .func_inst = func, | ||
| 6652 | .param_i = @intCast(u32, i), | ||
| 6653 | } }; | ||
| 6649 | const param_ty = func_ty.fnParamType(i); | 6654 | const param_ty = func_ty.fnParamType(i); |
| 6650 | args[i] = sema.analyzeCallArg( | 6655 | args[i] = sema.analyzeCallArg( |
| 6651 | block, | 6656 | block, |
| 6652 | .unneeded, | 6657 | .unneeded, |
| 6653 | param_ty, | 6658 | param_ty, |
| 6654 | uncasted_arg, | 6659 | uncasted_arg, |
| 6660 | opts, | ||
| 6655 | ) catch |err| switch (err) { | 6661 | ) catch |err| switch (err) { |
| 6656 | error.NeededSourceLocation => { | 6662 | error.NeededSourceLocation => { |
| 6657 | const decl = sema.mod.declPtr(block.src_decl); | 6663 | const decl = sema.mod.declPtr(block.src_decl); |
| ... | @@ -6660,6 +6666,7 @@ fn analyzeCall( | ... | @@ -6660,6 +6666,7 @@ fn analyzeCall( |
| 6660 | Module.argSrc(call_src.node_offset.x, sema.gpa, decl, i, bound_arg_src), | 6666 | Module.argSrc(call_src.node_offset.x, sema.gpa, decl, i, bound_arg_src), |
| 6661 | param_ty, | 6667 | param_ty, |
| 6662 | uncasted_arg, | 6668 | uncasted_arg, |
| 6669 | opts, | ||
| 6663 | ); | 6670 | ); |
| 6664 | return error.AnalysisFail; | 6671 | return error.AnalysisFail; |
| 6665 | }, | 6672 | }, |
| ... | @@ -6741,6 +6748,7 @@ fn analyzeInlineCallArg( | ... | @@ -6741,6 +6748,7 @@ fn analyzeInlineCallArg( |
| 6741 | should_memoize: *bool, | 6748 | should_memoize: *bool, |
| 6742 | memoized_call_key: Module.MemoizedCall.Key, | 6749 | memoized_call_key: Module.MemoizedCall.Key, |
| 6743 | raw_param_types: []const Type, | 6750 | raw_param_types: []const Type, |
| 6751 | func_inst: Air.Inst.Ref, | ||
| 6744 | ) !void { | 6752 | ) !void { |
| 6745 | const zir_tags = sema.code.instructions.items(.tag); | 6753 | const zir_tags = sema.code.instructions.items(.tag); |
| 6746 | switch (zir_tags[inst]) { | 6754 | switch (zir_tags[inst]) { |
| ... | @@ -6765,7 +6773,13 @@ fn analyzeInlineCallArg( | ... | @@ -6765,7 +6773,13 @@ fn analyzeInlineCallArg( |
| 6765 | return err; | 6773 | return err; |
| 6766 | }; | 6774 | }; |
| 6767 | } | 6775 | } |
| 6768 | const casted_arg = try sema.coerce(arg_block, param_ty, uncasted_arg, arg_src); | 6776 | const casted_arg = sema.coerceExtra(arg_block, param_ty, uncasted_arg, arg_src, .{ .param_src = .{ |
| 6777 | .func_inst = func_inst, | ||
| 6778 | .param_i = @intCast(u32, arg_i.*), | ||
| 6779 | } }) catch |err| switch (err) { | ||
| 6780 | error.NotCoercible => unreachable, | ||
| 6781 | else => |e| return e, | ||
| 6782 | }; | ||
| 6769 | 6783 | ||
| 6770 | if (is_comptime_call) { | 6784 | if (is_comptime_call) { |
| 6771 | sema.inst_map.putAssumeCapacityNoClobber(inst, casted_arg); | 6785 | sema.inst_map.putAssumeCapacityNoClobber(inst, casted_arg); |
| ... | @@ -6855,9 +6869,13 @@ fn analyzeCallArg( | ... | @@ -6855,9 +6869,13 @@ fn analyzeCallArg( |
| 6855 | arg_src: LazySrcLoc, | 6869 | arg_src: LazySrcLoc, |
| 6856 | param_ty: Type, | 6870 | param_ty: Type, |
| 6857 | uncasted_arg: Air.Inst.Ref, | 6871 | uncasted_arg: Air.Inst.Ref, |
| 6872 | opts: CoerceOpts, | ||
| 6858 | ) !Air.Inst.Ref { | 6873 | ) !Air.Inst.Ref { |
| 6859 | try sema.resolveTypeFully(param_ty); | 6874 | try sema.resolveTypeFully(param_ty); |
| 6860 | return sema.coerce(block, param_ty, uncasted_arg, arg_src); | 6875 | return sema.coerceExtra(block, param_ty, uncasted_arg, arg_src, opts) catch |err| switch (err) { |
| 6876 | error.NotCoercible => unreachable, | ||
| 6877 | else => |e| return e, | ||
| 6878 | }; | ||
| 6861 | } | 6879 | } |
| 6862 | 6880 | ||
| 6863 | fn analyzeGenericCallArg( | 6881 | fn analyzeGenericCallArg( |
| ... | @@ -16546,7 +16564,7 @@ fn zirRetErrValue( | ... | @@ -16546,7 +16564,7 @@ fn zirRetErrValue( |
| 16546 | return sema.analyzeRet(block, result_inst, src); | 16564 | return sema.analyzeRet(block, result_inst, src); |
| 16547 | } | 16565 | } |
| 16548 | 16566 | ||
| 16549 | fn zirRetTok( | 16567 | fn zirRetImplicit( |
| 16550 | sema: *Sema, | 16568 | sema: *Sema, |
| 16551 | block: *Block, | 16569 | block: *Block, |
| 16552 | inst: Zir.Inst.Index, | 16570 | inst: Zir.Inst.Index, |
| ... | @@ -16556,9 +16574,33 @@ fn zirRetTok( | ... | @@ -16556,9 +16574,33 @@ fn zirRetTok( |
| 16556 | 16574 | ||
| 16557 | const inst_data = sema.code.instructions.items(.data)[inst].un_tok; | 16575 | const inst_data = sema.code.instructions.items(.data)[inst].un_tok; |
| 16558 | const operand = try sema.resolveInst(inst_data.operand); | 16576 | const operand = try sema.resolveInst(inst_data.operand); |
| 16559 | const src = inst_data.src(); | ||
| 16560 | 16577 | ||
| 16561 | return sema.analyzeRet(block, operand, src); | 16578 | const r_brace_src = inst_data.src(); |
| 16579 | const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 }; | ||
| 16580 | const base_tag = sema.fn_ret_ty.baseZigTypeTag(); | ||
| 16581 | if (base_tag == .NoReturn) { | ||
| 16582 | const msg = msg: { | ||
| 16583 | const msg = try sema.errMsg(block, ret_ty_src, "function declared '{}' implicitly returns", .{ | ||
| 16584 | sema.fn_ret_ty.fmt(sema.mod), | ||
| 16585 | }); | ||
| 16586 | errdefer msg.destroy(sema.gpa); | ||
| 16587 | try sema.errNote(block, r_brace_src, msg, "control flow reaches end of body here", .{}); | ||
| 16588 | break :msg msg; | ||
| 16589 | }; | ||
| 16590 | return sema.failWithOwnedErrorMsg(msg); | ||
| 16591 | } else if (base_tag != .Void) { | ||
| 16592 | const msg = msg: { | ||
| 16593 | const msg = try sema.errMsg(block, ret_ty_src, "function with non-void return type '{}' implicitly returns", .{ | ||
| 16594 | sema.fn_ret_ty.fmt(sema.mod), | ||
| 16595 | }); | ||
| 16596 | errdefer msg.destroy(sema.gpa); | ||
| 16597 | try sema.errNote(block, r_brace_src, msg, "control flow reaches end of body here", .{}); | ||
| 16598 | break :msg msg; | ||
| 16599 | }; | ||
| 16600 | return sema.failWithOwnedErrorMsg(msg); | ||
| 16601 | } | ||
| 16602 | |||
| 16603 | return sema.analyzeRet(block, operand, .unneeded); | ||
| 16562 | } | 16604 | } |
| 16563 | 16605 | ||
| 16564 | fn zirRetNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Index { | 16606 | fn zirRetNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Index { |
| ... | @@ -16825,7 +16867,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -16825,7 +16867,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 16825 | const bitoffset_src: LazySrcLoc = .{ .node_offset_ptr_bitoffset = extra.data.src_node }; | 16867 | const bitoffset_src: LazySrcLoc = .{ .node_offset_ptr_bitoffset = extra.data.src_node }; |
| 16826 | const hostsize_src: LazySrcLoc = .{ .node_offset_ptr_hostsize = extra.data.src_node }; | 16868 | const hostsize_src: LazySrcLoc = .{ .node_offset_ptr_hostsize = extra.data.src_node }; |
| 16827 | 16869 | ||
| 16828 | const unresolved_elem_ty = blk: { | 16870 | const elem_ty = blk: { |
| 16829 | const air_inst = try sema.resolveInst(extra.data.elem_type); | 16871 | const air_inst = try sema.resolveInst(extra.data.elem_type); |
| 16830 | const ty = sema.analyzeAsType(block, elem_ty_src, air_inst) catch |err| { | 16872 | const ty = sema.analyzeAsType(block, elem_ty_src, air_inst) catch |err| { |
| 16831 | if (err == error.AnalysisFail and sema.err != null and sema.typeOf(air_inst).isSinglePointer()) { | 16873 | if (err == error.AnalysisFail and sema.err != null and sema.typeOf(air_inst).isSinglePointer()) { |
| ... | @@ -16854,7 +16896,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -16854,7 +16896,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 16854 | // Check if this happens to be the lazy alignment of our element type, in | 16896 | // Check if this happens to be the lazy alignment of our element type, in |
| 16855 | // which case we can make this 0 without resolving it. | 16897 | // which case we can make this 0 without resolving it. |
| 16856 | if (val.castTag(.lazy_align)) |payload| { | 16898 | if (val.castTag(.lazy_align)) |payload| { |
| 16857 | if (payload.data.eql(unresolved_elem_ty, sema.mod)) { | 16899 | if (payload.data.eql(elem_ty, sema.mod)) { |
| 16858 | break :blk 0; | 16900 | break :blk 0; |
| 16859 | } | 16901 | } |
| 16860 | } | 16902 | } |
| ... | @@ -16887,14 +16929,6 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -16887,14 +16929,6 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 16887 | return sema.fail(block, bitoffset_src, "bit offset starts after end of host integer", .{}); | 16929 | return sema.fail(block, bitoffset_src, "bit offset starts after end of host integer", .{}); |
| 16888 | } | 16930 | } |
| 16889 | 16931 | ||
| 16890 | const elem_ty = if (abi_align == 0) | ||
| 16891 | unresolved_elem_ty | ||
| 16892 | else t: { | ||
| 16893 | const elem_ty = try sema.resolveTypeFields(unresolved_elem_ty); | ||
| 16894 | try sema.resolveTypeLayout(elem_ty); | ||
| 16895 | break :t elem_ty; | ||
| 16896 | }; | ||
| 16897 | |||
| 16898 | if (elem_ty.zigTypeTag() == .NoReturn) { | 16932 | if (elem_ty.zigTypeTag() == .NoReturn) { |
| 16899 | return sema.fail(block, elem_ty_src, "pointer to noreturn not allowed", .{}); | 16933 | return sema.fail(block, elem_ty_src, "pointer to noreturn not allowed", .{}); |
| 16900 | } else if (elem_ty.zigTypeTag() == .Fn) { | 16934 | } else if (elem_ty.zigTypeTag() == .Fn) { |
| ... | @@ -20270,7 +20304,7 @@ fn analyzeShuffle( | ... | @@ -20270,7 +20304,7 @@ fn analyzeShuffle( |
| 20270 | var buf: Value.ElemValueBuffer = undefined; | 20304 | var buf: Value.ElemValueBuffer = undefined; |
| 20271 | const elem = mask.elemValueBuffer(sema.mod, i, &buf); | 20305 | const elem = mask.elemValueBuffer(sema.mod, i, &buf); |
| 20272 | if (elem.isUndef()) continue; | 20306 | if (elem.isUndef()) continue; |
| 20273 | const int = elem.toSignedInt(); | 20307 | const int = elem.toSignedInt(sema.mod.getTarget()); |
| 20274 | var unsigned: u32 = undefined; | 20308 | var unsigned: u32 = undefined; |
| 20275 | var chosen: u32 = undefined; | 20309 | var chosen: u32 = undefined; |
| 20276 | if (int >= 0) { | 20310 | if (int >= 0) { |
| ... | @@ -20312,7 +20346,7 @@ fn analyzeShuffle( | ... | @@ -20312,7 +20346,7 @@ fn analyzeShuffle( |
| 20312 | values[i] = Value.undef; | 20346 | values[i] = Value.undef; |
| 20313 | continue; | 20347 | continue; |
| 20314 | } | 20348 | } |
| 20315 | const int = mask_elem_val.toSignedInt(); | 20349 | const int = mask_elem_val.toSignedInt(sema.mod.getTarget()); |
| 20316 | const unsigned = if (int >= 0) @intCast(u32, int) else @intCast(u32, ~int); | 20350 | const unsigned = if (int >= 0) @intCast(u32, int) else @intCast(u32, ~int); |
| 20317 | if (int >= 0) { | 20351 | if (int >= 0) { |
| 20318 | values[i] = try a_val.elemValue(sema.mod, sema.arena, unsigned); | 20352 | values[i] = try a_val.elemValue(sema.mod, sema.arena, unsigned); |
| ... | @@ -24040,6 +24074,25 @@ const CoerceOpts = struct { | ... | @@ -24040,6 +24074,25 @@ const CoerceOpts = struct { |
| 24040 | is_ret: bool = false, | 24074 | is_ret: bool = false, |
| 24041 | /// Should coercion to comptime_int ermit an error message. | 24075 | /// Should coercion to comptime_int ermit an error message. |
| 24042 | no_cast_to_comptime_int: bool = false, | 24076 | no_cast_to_comptime_int: bool = false, |
| 24077 | |||
| 24078 | param_src: struct { | ||
| 24079 | func_inst: Air.Inst.Ref = .none, | ||
| 24080 | param_i: u32 = undefined, | ||
| 24081 | |||
| 24082 | fn get(info: @This(), sema: *Sema) !?Module.SrcLoc { | ||
| 24083 | if (info.func_inst == .none) return null; | ||
| 24084 | const fn_decl = (try sema.funcDeclSrc(info.func_inst)) orelse return null; | ||
| 24085 | const param_src = Module.paramSrc(0, sema.gpa, fn_decl, info.param_i); | ||
| 24086 | if (param_src == .node_offset_param) { | ||
| 24087 | return Module.SrcLoc{ | ||
| 24088 | .file_scope = fn_decl.getFileScope(), | ||
| 24089 | .parent_decl_node = fn_decl.src_node, | ||
| 24090 | .lazy = LazySrcLoc.nodeOffset(param_src.node_offset_param), | ||
| 24091 | }; | ||
| 24092 | } | ||
| 24093 | return param_src.toSrcLoc(fn_decl); | ||
| 24094 | } | ||
| 24095 | } = .{}, | ||
| 24043 | }; | 24096 | }; |
| 24044 | 24097 | ||
| 24045 | fn coerceExtra( | 24098 | fn coerceExtra( |
| ... | @@ -24699,6 +24752,10 @@ fn coerceExtra( | ... | @@ -24699,6 +24752,10 @@ fn coerceExtra( |
| 24699 | } | 24752 | } |
| 24700 | } | 24753 | } |
| 24701 | 24754 | ||
| 24755 | if (try opts.param_src.get(sema)) |param_src| { | ||
| 24756 | try sema.mod.errNoteNonLazy(param_src, msg, "parameter type declared here", .{}); | ||
| 24757 | } | ||
| 24758 | |||
| 24702 | // TODO maybe add "cannot store an error in type '{}'" note | 24759 | // TODO maybe add "cannot store an error in type '{}'" note |
| 24703 | 24760 | ||
| 24704 | break :msg msg; | 24761 | break :msg msg; |
| ... | @@ -28307,6 +28364,7 @@ fn cmpNumeric( | ... | @@ -28307,6 +28364,7 @@ fn cmpNumeric( |
| 28307 | 28364 | ||
| 28308 | var lhs_bits: usize = undefined; | 28365 | var lhs_bits: usize = undefined; |
| 28309 | if (try sema.resolveMaybeUndefVal(lhs)) |lhs_val| { | 28366 | if (try sema.resolveMaybeUndefVal(lhs)) |lhs_val| { |
| 28367 | try sema.resolveLazyValue(lhs_val); | ||
| 28310 | if (lhs_val.isUndef()) | 28368 | if (lhs_val.isUndef()) |
| 28311 | return sema.addConstUndef(Type.bool); | 28369 | return sema.addConstUndef(Type.bool); |
| 28312 | if (lhs_val.isNan()) switch (op) { | 28370 | if (lhs_val.isNan()) switch (op) { |
| ... | @@ -28365,6 +28423,7 @@ fn cmpNumeric( | ... | @@ -28365,6 +28423,7 @@ fn cmpNumeric( |
| 28365 | 28423 | ||
| 28366 | var rhs_bits: usize = undefined; | 28424 | var rhs_bits: usize = undefined; |
| 28367 | if (try sema.resolveMaybeUndefVal(rhs)) |rhs_val| { | 28425 | if (try sema.resolveMaybeUndefVal(rhs)) |rhs_val| { |
| 28426 | try sema.resolveLazyValue(rhs_val); | ||
| 28368 | if (rhs_val.isUndef()) | 28427 | if (rhs_val.isUndef()) |
| 28369 | return sema.addConstUndef(Type.bool); | 28428 | return sema.addConstUndef(Type.bool); |
| 28370 | if (rhs_val.isNan()) switch (op) { | 28429 | if (rhs_val.isNan()) switch (op) { |
| ... | @@ -29237,6 +29296,16 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void { | ... | @@ -29237,6 +29296,16 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void { |
| 29237 | 29296 | ||
| 29238 | struct_obj.status = .have_layout; | 29297 | struct_obj.status = .have_layout; |
| 29239 | _ = try sema.resolveTypeRequiresComptime(resolved_ty); | 29298 | _ = try sema.resolveTypeRequiresComptime(resolved_ty); |
| 29299 | |||
| 29300 | if (struct_obj.assumed_runtime_bits and !resolved_ty.hasRuntimeBits()) { | ||
| 29301 | const msg = try Module.ErrorMsg.create( | ||
| 29302 | sema.gpa, | ||
| 29303 | struct_obj.srcLoc(sema.mod), | ||
| 29304 | "struct layout depends on it having runtime bits", | ||
| 29305 | .{}, | ||
| 29306 | ); | ||
| 29307 | return sema.failWithOwnedErrorMsg(msg); | ||
| 29308 | } | ||
| 29240 | } | 29309 | } |
| 29241 | // otherwise it's a tuple; no need to resolve anything | 29310 | // otherwise it's a tuple; no need to resolve anything |
| 29242 | } | 29311 | } |
| ... | @@ -29401,6 +29470,16 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void { | ... | @@ -29401,6 +29470,16 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void { |
| 29401 | } | 29470 | } |
| 29402 | union_obj.status = .have_layout; | 29471 | union_obj.status = .have_layout; |
| 29403 | _ = try sema.resolveTypeRequiresComptime(resolved_ty); | 29472 | _ = try sema.resolveTypeRequiresComptime(resolved_ty); |
| 29473 | |||
| 29474 | if (union_obj.assumed_runtime_bits and !resolved_ty.hasRuntimeBits()) { | ||
| 29475 | const msg = try Module.ErrorMsg.create( | ||
| 29476 | sema.gpa, | ||
| 29477 | union_obj.srcLoc(sema.mod), | ||
| 29478 | "union layout depends on it having runtime bits", | ||
| 29479 | .{}, | ||
| 29480 | ); | ||
| 29481 | return sema.failWithOwnedErrorMsg(msg); | ||
| 29482 | } | ||
| 29404 | } | 29483 | } |
| 29405 | 29484 | ||
| 29406 | // In case of querying the ABI alignment of this struct, we will ask | 29485 | // 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| ... | @@ -6113,7 +6113,7 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { | ... | @@ -6113,7 +6113,7 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { |
| 6113 | if (info.bits <= 64) { | 6113 | if (info.bits <= 64) { |
| 6114 | const unsigned = switch (info.signedness) { | 6114 | const unsigned = switch (info.signedness) { |
| 6115 | .signed => blk: { | 6115 | .signed => blk: { |
| 6116 | const signed = typed_value.val.toSignedInt(); | 6116 | const signed = typed_value.val.toSignedInt(target); |
| 6117 | break :blk @bitCast(u64, signed); | 6117 | break :blk @bitCast(u64, signed); |
| 6118 | }, | 6118 | }, |
| 6119 | .unsigned => typed_value.val.toUnsignedInt(target), | 6119 | .unsigned => typed_value.val.toUnsignedInt(target), |
src/arch/arm/CodeGen.zig+1-1| ... | @@ -6070,7 +6070,7 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { | ... | @@ -6070,7 +6070,7 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { |
| 6070 | if (info.bits <= ptr_bits) { | 6070 | if (info.bits <= ptr_bits) { |
| 6071 | const unsigned = switch (info.signedness) { | 6071 | const unsigned = switch (info.signedness) { |
| 6072 | .signed => blk: { | 6072 | .signed => blk: { |
| 6073 | const signed = @intCast(i32, typed_value.val.toSignedInt()); | 6073 | const signed = @intCast(i32, typed_value.val.toSignedInt(target)); |
| 6074 | break :blk @bitCast(u32, signed); | 6074 | break :blk @bitCast(u32, signed); |
| 6075 | }, | 6075 | }, |
| 6076 | .unsigned => @intCast(u32, typed_value.val.toUnsignedInt(target)), | 6076 | .unsigned => @intCast(u32, typed_value.val.toUnsignedInt(target)), |
src/arch/sparc64/CodeGen.zig+1-1| ... | @@ -3751,7 +3751,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { | ... | @@ -3751,7 +3751,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { |
| 3751 | if (info.bits <= 64) { | 3751 | if (info.bits <= 64) { |
| 3752 | const unsigned = switch (info.signedness) { | 3752 | const unsigned = switch (info.signedness) { |
| 3753 | .signed => blk: { | 3753 | .signed => blk: { |
| 3754 | const signed = typed_value.val.toSignedInt(); | 3754 | const signed = typed_value.val.toSignedInt(target); |
| 3755 | break :blk @bitCast(u64, signed); | 3755 | break :blk @bitCast(u64, signed); |
| 3756 | }, | 3756 | }, |
| 3757 | .unsigned => typed_value.val.toUnsignedInt(target), | 3757 | .unsigned => typed_value.val.toUnsignedInt(target), |
src/arch/wasm/CodeGen.zig+5-5| ... | @@ -2670,11 +2670,11 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue { | ... | @@ -2670,11 +2670,11 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue { |
| 2670 | switch (int_info.signedness) { | 2670 | switch (int_info.signedness) { |
| 2671 | .signed => switch (int_info.bits) { | 2671 | .signed => switch (int_info.bits) { |
| 2672 | 0...32 => return WValue{ .imm32 = @intCast(u32, toTwosComplement( | 2672 | 0...32 => return WValue{ .imm32 = @intCast(u32, toTwosComplement( |
| 2673 | val.toSignedInt(), | 2673 | val.toSignedInt(target), |
| 2674 | @intCast(u6, int_info.bits), | 2674 | @intCast(u6, int_info.bits), |
| 2675 | )) }, | 2675 | )) }, |
| 2676 | 33...64 => return WValue{ .imm64 = toTwosComplement( | 2676 | 33...64 => return WValue{ .imm64 = toTwosComplement( |
| 2677 | val.toSignedInt(), | 2677 | val.toSignedInt(target), |
| 2678 | @intCast(u7, int_info.bits), | 2678 | @intCast(u7, int_info.bits), |
| 2679 | ) }, | 2679 | ) }, |
| 2680 | else => unreachable, | 2680 | else => unreachable, |
| ... | @@ -2841,15 +2841,15 @@ fn valueAsI32(func: *const CodeGen, val: Value, ty: Type) i32 { | ... | @@ -2841,15 +2841,15 @@ fn valueAsI32(func: *const CodeGen, val: Value, ty: Type) i32 { |
| 2841 | } | 2841 | } |
| 2842 | }, | 2842 | }, |
| 2843 | .Int => switch (ty.intInfo(func.target).signedness) { | 2843 | .Int => switch (ty.intInfo(func.target).signedness) { |
| 2844 | .signed => return @truncate(i32, val.toSignedInt()), | 2844 | .signed => return @truncate(i32, val.toSignedInt(target)), |
| 2845 | .unsigned => return @bitCast(i32, @truncate(u32, val.toUnsignedInt(target))), | 2845 | .unsigned => return @bitCast(i32, @truncate(u32, val.toUnsignedInt(target))), |
| 2846 | }, | 2846 | }, |
| 2847 | .ErrorSet => { | 2847 | .ErrorSet => { |
| 2848 | const kv = func.bin_file.base.options.module.?.getErrorValue(val.getError().?) catch unreachable; // passed invalid `Value` to function | 2848 | const kv = func.bin_file.base.options.module.?.getErrorValue(val.getError().?) catch unreachable; // passed invalid `Value` to function |
| 2849 | return @bitCast(i32, kv.value); | 2849 | return @bitCast(i32, kv.value); |
| 2850 | }, | 2850 | }, |
| 2851 | .Bool => return @intCast(i32, val.toSignedInt()), | 2851 | .Bool => return @intCast(i32, val.toSignedInt(target)), |
| 2852 | .Pointer => return @intCast(i32, val.toSignedInt()), | 2852 | .Pointer => return @intCast(i32, val.toSignedInt(target)), |
| 2853 | else => unreachable, // Programmer called this function for an illegal type | 2853 | else => unreachable, // Programmer called this function for an illegal type |
| 2854 | } | 2854 | } |
| 2855 | } | 2855 | } |
src/arch/x86_64/CodeGen.zig+1-1| ... | @@ -6862,7 +6862,7 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { | ... | @@ -6862,7 +6862,7 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { |
| 6862 | .Int => { | 6862 | .Int => { |
| 6863 | const info = typed_value.ty.intInfo(self.target.*); | 6863 | const info = typed_value.ty.intInfo(self.target.*); |
| 6864 | if (info.bits <= ptr_bits and info.signedness == .signed) { | 6864 | if (info.bits <= ptr_bits and info.signedness == .signed) { |
| 6865 | return MCValue{ .immediate = @bitCast(u64, typed_value.val.toSignedInt()) }; | 6865 | return MCValue{ .immediate = @bitCast(u64, typed_value.val.toSignedInt(target)) }; |
| 6866 | } | 6866 | } |
| 6867 | if (!(info.bits > ptr_bits or info.signedness == .signed)) { | 6867 | if (!(info.bits > ptr_bits or info.signedness == .signed)) { |
| 6868 | return MCValue{ .immediate = typed_value.val.toUnsignedInt(target) }; | 6868 | return MCValue{ .immediate = typed_value.val.toUnsignedInt(target) }; |
src/codegen.zig+7-7| ... | @@ -472,7 +472,7 @@ pub fn generateSymbol( | ... | @@ -472,7 +472,7 @@ pub fn generateSymbol( |
| 472 | if (info.bits <= 8) { | 472 | if (info.bits <= 8) { |
| 473 | const x: u8 = switch (info.signedness) { | 473 | const x: u8 = switch (info.signedness) { |
| 474 | .unsigned => @intCast(u8, typed_value.val.toUnsignedInt(target)), | 474 | .unsigned => @intCast(u8, typed_value.val.toUnsignedInt(target)), |
| 475 | .signed => @bitCast(u8, @intCast(i8, typed_value.val.toSignedInt())), | 475 | .signed => @bitCast(u8, @intCast(i8, typed_value.val.toSignedInt(target))), |
| 476 | }; | 476 | }; |
| 477 | try code.append(x); | 477 | try code.append(x); |
| 478 | return Result{ .appended = {} }; | 478 | return Result{ .appended = {} }; |
| ... | @@ -501,13 +501,13 @@ pub fn generateSymbol( | ... | @@ -501,13 +501,13 @@ pub fn generateSymbol( |
| 501 | }, | 501 | }, |
| 502 | .signed => { | 502 | .signed => { |
| 503 | if (info.bits <= 16) { | 503 | if (info.bits <= 16) { |
| 504 | const x = @intCast(i16, typed_value.val.toSignedInt()); | 504 | const x = @intCast(i16, typed_value.val.toSignedInt(target)); |
| 505 | mem.writeInt(i16, try code.addManyAsArray(2), x, endian); | 505 | mem.writeInt(i16, try code.addManyAsArray(2), x, endian); |
| 506 | } else if (info.bits <= 32) { | 506 | } else if (info.bits <= 32) { |
| 507 | const x = @intCast(i32, typed_value.val.toSignedInt()); | 507 | const x = @intCast(i32, typed_value.val.toSignedInt(target)); |
| 508 | mem.writeInt(i32, try code.addManyAsArray(4), x, endian); | 508 | mem.writeInt(i32, try code.addManyAsArray(4), x, endian); |
| 509 | } else { | 509 | } else { |
| 510 | const x = typed_value.val.toSignedInt(); | 510 | const x = typed_value.val.toSignedInt(target); |
| 511 | mem.writeInt(i64, try code.addManyAsArray(8), x, endian); | 511 | mem.writeInt(i64, try code.addManyAsArray(8), x, endian); |
| 512 | } | 512 | } |
| 513 | }, | 513 | }, |
| ... | @@ -549,13 +549,13 @@ pub fn generateSymbol( | ... | @@ -549,13 +549,13 @@ pub fn generateSymbol( |
| 549 | }, | 549 | }, |
| 550 | .signed => { | 550 | .signed => { |
| 551 | if (info.bits <= 16) { | 551 | if (info.bits <= 16) { |
| 552 | const x = @intCast(i16, int_val.toSignedInt()); | 552 | const x = @intCast(i16, int_val.toSignedInt(target)); |
| 553 | mem.writeInt(i16, try code.addManyAsArray(2), x, endian); | 553 | mem.writeInt(i16, try code.addManyAsArray(2), x, endian); |
| 554 | } else if (info.bits <= 32) { | 554 | } else if (info.bits <= 32) { |
| 555 | const x = @intCast(i32, int_val.toSignedInt()); | 555 | const x = @intCast(i32, int_val.toSignedInt(target)); |
| 556 | mem.writeInt(i32, try code.addManyAsArray(4), x, endian); | 556 | mem.writeInt(i32, try code.addManyAsArray(4), x, endian); |
| 557 | } else { | 557 | } else { |
| 558 | const x = int_val.toSignedInt(); | 558 | const x = int_val.toSignedInt(target); |
| 559 | mem.writeInt(i64, try code.addManyAsArray(8), x, endian); | 559 | mem.writeInt(i64, try code.addManyAsArray(8), x, endian); |
| 560 | } | 560 | } |
| 561 | }, | 561 | }, |
src/codegen/llvm.zig+1-1| ... | @@ -8932,7 +8932,7 @@ pub const FuncGen = struct { | ... | @@ -8932,7 +8932,7 @@ pub const FuncGen = struct { |
| 8932 | if (elem.isUndef()) { | 8932 | if (elem.isUndef()) { |
| 8933 | val.* = llvm_i32.getUndef(); | 8933 | val.* = llvm_i32.getUndef(); |
| 8934 | } else { | 8934 | } else { |
| 8935 | const int = elem.toSignedInt(); | 8935 | const int = elem.toSignedInt(self.dg.module.getTarget()); |
| 8936 | const unsigned = if (int >= 0) @intCast(u32, int) else @intCast(u32, ~int + a_len); | 8936 | const unsigned = if (int >= 0) @intCast(u32, int) else @intCast(u32, ~int + a_len); |
| 8937 | val.* = llvm_i32.constInt(unsigned, .False); | 8937 | val.* = llvm_i32.constInt(unsigned, .False); |
| 8938 | } | 8938 | } |
src/codegen/spirv.zig+2-2| ... | @@ -360,7 +360,7 @@ pub const DeclGen = struct { | ... | @@ -360,7 +360,7 @@ pub const DeclGen = struct { |
| 360 | 360 | ||
| 361 | // Note, value is required to be sign-extended, so we don't need to mask off the upper bits. | 361 | // Note, value is required to be sign-extended, so we don't need to mask off the upper bits. |
| 362 | // See https://www.khronos.org/registry/SPIR-V/specs/unified1/SPIRV.html#Literal | 362 | // See https://www.khronos.org/registry/SPIR-V/specs/unified1/SPIRV.html#Literal |
| 363 | var int_bits = if (ty.isSignedInt()) @bitCast(u64, val.toSignedInt()) else val.toUnsignedInt(target); | 363 | var int_bits = if (ty.isSignedInt()) @bitCast(u64, val.toSignedInt(target)) else val.toUnsignedInt(target); |
| 364 | 364 | ||
| 365 | const value: spec.LiteralContextDependentNumber = switch (backing_bits) { | 365 | const value: spec.LiteralContextDependentNumber = switch (backing_bits) { |
| 366 | 1...32 => .{ .uint32 = @truncate(u32, int_bits) }, | 366 | 1...32 => .{ .uint32 = @truncate(u32, int_bits) }, |
| ... | @@ -763,7 +763,7 @@ pub const DeclGen = struct { | ... | @@ -763,7 +763,7 @@ pub const DeclGen = struct { |
| 763 | if (elem.isUndef()) { | 763 | if (elem.isUndef()) { |
| 764 | self.func.body.writeOperand(spec.LiteralInteger, 0xFFFF_FFFF); | 764 | self.func.body.writeOperand(spec.LiteralInteger, 0xFFFF_FFFF); |
| 765 | } else { | 765 | } else { |
| 766 | const int = elem.toSignedInt(); | 766 | const int = elem.toSignedInt(self.getTarget()); |
| 767 | const unsigned = if (int >= 0) @intCast(u32, int) else @intCast(u32, ~int + a_len); | 767 | const unsigned = if (int >= 0) @intCast(u32, int) else @intCast(u32, ~int + a_len); |
| 768 | self.func.body.writeOperand(spec.LiteralInteger, unsigned); | 768 | self.func.body.writeOperand(spec.LiteralInteger, unsigned); |
| 769 | } | 769 | } |
src/link/Dwarf.zig+1-1| ... | @@ -410,7 +410,7 @@ pub const DeclState = struct { | ... | @@ -410,7 +410,7 @@ pub const DeclState = struct { |
| 410 | // See https://github.com/ziglang/zig/issues/645 | 410 | // See https://github.com/ziglang/zig/issues/645 |
| 411 | var int_buffer: Value.Payload.U64 = undefined; | 411 | var int_buffer: Value.Payload.U64 = undefined; |
| 412 | const field_int_val = value.enumToInt(ty, &int_buffer); | 412 | const field_int_val = value.enumToInt(ty, &int_buffer); |
| 413 | break :value @bitCast(u64, field_int_val.toSignedInt()); | 413 | break :value @bitCast(u64, field_int_val.toSignedInt(target)); |
| 414 | } else @intCast(u64, field_i); | 414 | } else @intCast(u64, field_i); |
| 415 | mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), value, target_endian); | 415 | mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), value, target_endian); |
| 416 | } | 416 | } |
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); |
| ... | @@ -5234,7 +5254,12 @@ pub const Type = extern union { | ... | @@ -5234,7 +5254,12 @@ pub const Type = extern union { |
| 5234 | .@"struct" => { | 5254 | .@"struct" => { |
| 5235 | const struct_obj = ty.castTag(.@"struct").?.data; | 5255 | const struct_obj = ty.castTag(.@"struct").?.data; |
| 5236 | switch (struct_obj.requires_comptime) { | 5256 | switch (struct_obj.requires_comptime) { |
| 5237 | .wip, .unknown => unreachable, // This function asserts types already resolved. | 5257 | .wip, .unknown => { |
| 5258 | // Return false to avoid incorrect dependency loops. | ||
| 5259 | // This will be handled correctly once merged with | ||
| 5260 | // `Sema.typeRequiresComptime`. | ||
| 5261 | return false; | ||
| 5262 | }, | ||
| 5238 | .no => return false, | 5263 | .no => return false, |
| 5239 | .yes => return true, | 5264 | .yes => return true, |
| 5240 | } | 5265 | } |
| ... | @@ -5243,7 +5268,12 @@ pub const Type = extern union { | ... | @@ -5243,7 +5268,12 @@ pub const Type = extern union { |
| 5243 | .@"union", .union_safety_tagged, .union_tagged => { | 5268 | .@"union", .union_safety_tagged, .union_tagged => { |
| 5244 | const union_obj = ty.cast(Type.Payload.Union).?.data; | 5269 | const union_obj = ty.cast(Type.Payload.Union).?.data; |
| 5245 | switch (union_obj.requires_comptime) { | 5270 | switch (union_obj.requires_comptime) { |
| 5246 | .wip, .unknown => unreachable, // This function asserts types already resolved. | 5271 | .wip, .unknown => { |
| 5272 | // Return false to avoid incorrect dependency loops. | ||
| 5273 | // This will be handled correctly once merged with | ||
| 5274 | // `Sema.typeRequiresComptime`. | ||
| 5275 | return false; | ||
| 5276 | }, | ||
| 5247 | .no => return false, | 5277 | .no => return false, |
| 5248 | .yes => return true, | 5278 | .yes => return true, |
| 5249 | } | 5279 | } |
| ... | @@ -6472,8 +6502,16 @@ pub const Type = extern union { | ... | @@ -6472,8 +6502,16 @@ pub const Type = extern union { |
| 6472 | // type, we change it to 0 here. If this causes an assertion trip because the | 6502 | // type, we change it to 0 here. If this causes an assertion trip because the |
| 6473 | // pointee type needs to be resolved more, that needs to be done before calling | 6503 | // pointee type needs to be resolved more, that needs to be done before calling |
| 6474 | // this ptr() function. | 6504 | // this ptr() function. |
| 6475 | if (d.@"align" != 0 and d.@"align" == d.pointee_type.abiAlignment(target)) { | 6505 | if (d.@"align" != 0) canonicalize: { |
| 6476 | d.@"align" = 0; | 6506 | if (d.pointee_type.castTag(.@"struct")) |struct_ty| { |
| 6507 | if (!struct_ty.data.haveLayout()) break :canonicalize; | ||
| 6508 | } | ||
| 6509 | if (d.pointee_type.cast(Payload.Union)) |union_ty| { | ||
| 6510 | if (!union_ty.data.haveLayout()) break :canonicalize; | ||
| 6511 | } | ||
| 6512 | if (d.@"align" == d.pointee_type.abiAlignment(target)) { | ||
| 6513 | d.@"align" = 0; | ||
| 6514 | } | ||
| 6477 | } | 6515 | } |
| 6478 | 6516 | ||
| 6479 | // Canonicalize host_size. If it matches the bit size of the pointee type, | 6517 | // 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| ... | @@ -1406,3 +1406,15 @@ test "address of zero-bit field is equal to address of only field" { | ... | @@ -1406,3 +1406,15 @@ test "address of zero-bit field is equal to address of only field" { |
| 1406 | try std.testing.expectEqual(&a, a_ptr); | 1406 | try std.testing.expectEqual(&a, a_ptr); |
| 1407 | } | 1407 | } |
| 1408 | } | 1408 | } |
| 1409 | |||
| 1410 | test "struct field has a pointer to an aligned version of itself" { | ||
| 1411 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | ||
| 1412 | |||
| 1413 | const E = struct { | ||
| 1414 | next: *align(1) @This(), | ||
| 1415 | }; | ||
| 1416 | var e: E = undefined; | ||
| 1417 | e = .{ .next = &e }; | ||
| 1418 | |||
| 1419 | try expect(&e == e.next); | ||
| 1420 | } |
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 |