authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-05-25 03:12:34-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-05-25 03:12:34-04:00
log83735207850bd526807a39771432be0bc7410414
treede0b8dc27f0824f14134dbece33a088bbffa4001
parenta0775fdaa1e7427dcd6be9b19726d4996344e9fa
parent60af42705d62417c73a13481e60b0861423e77fe
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11699 from ziglang/empty-error-sets

stage2: fixes for error union semantics

14 files changed, 1553 insertions(+), 727 deletions(-)

lib/std/debug.zig+1-1
......@@ -1798,7 +1798,7 @@ fn resetSegfaultHandler() void {
17981798 .mask = os.empty_sigset,
17991799 .flags = 0,
18001800 };
1801 // do nothing if an error happens to avoid a double-panic
1801 // To avoid a double-panic, do nothing if an error happens here.
18021802 updateSegfaultHandler(&act) catch {};
18031803}
18041804
src/Sema.zig+87-16
......@@ -5899,12 +5899,22 @@ fn zirErrorToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
58995899 if (val.isUndef()) {
59005900 return sema.addConstUndef(result_ty);
59015901 }
5902 const payload = try sema.arena.create(Value.Payload.U64);
5903 payload.* = .{
5904 .base = .{ .tag = .int_u64 },
5905 .data = (try sema.mod.getErrorValue(val.castTag(.@"error").?.data.name)).value,
5906 };
5907 return sema.addConstant(result_ty, Value.initPayload(&payload.base));
5902 switch (val.tag()) {
5903 .@"error" => {
5904 const payload = try sema.arena.create(Value.Payload.U64);
5905 payload.* = .{
5906 .base = .{ .tag = .int_u64 },
5907 .data = (try sema.mod.getErrorValue(val.castTag(.@"error").?.data.name)).value,
5908 };
5909 return sema.addConstant(result_ty, Value.initPayload(&payload.base));
5910 },
5911
5912 // This is not a valid combination with the type `anyerror`.
5913 .the_only_possible_value => unreachable,
5914
5915 // Assume it's already encoded as an integer.
5916 else => return sema.addConstant(result_ty, val),
5917 }
59085918 }
59095919
59105920 try sema.requireRuntimeBlock(block, src);
......@@ -6261,19 +6271,24 @@ fn zirErrUnionPayload(
62616271 });
62626272 }
62636273
6274 const result_ty = operand_ty.errorUnionPayload();
62646275 if (try sema.resolveDefinedValue(block, src, operand)) |val| {
62656276 if (val.getError()) |name| {
62666277 return sema.fail(block, src, "caught unexpected error '{s}'", .{name});
62676278 }
62686279 const data = val.castTag(.eu_payload).?.data;
6269 const result_ty = operand_ty.errorUnionPayload();
62706280 return sema.addConstant(result_ty, data);
62716281 }
6282
62726283 try sema.requireRuntimeBlock(block, src);
6273 if (safety_check and block.wantSafety()) {
6284
6285 // If the error set has no fields then no safety check is needed.
6286 if (safety_check and block.wantSafety() and
6287 operand_ty.errorUnionSet().errorSetCardinality() != .zero)
6288 {
62746289 try sema.panicUnwrapError(block, src, operand, .unwrap_errunion_err, .is_non_err);
62756290 }
6276 const result_ty = operand_ty.errorUnionPayload();
6291
62776292 return block.addTyOp(.unwrap_errunion_payload, result_ty, operand);
62786293}
62796294
......@@ -6311,7 +6326,8 @@ fn analyzeErrUnionPayloadPtr(
63116326 });
63126327 }
63136328
6314 const payload_ty = operand_ty.elemType().errorUnionPayload();
6329 const err_union_ty = operand_ty.elemType();
6330 const payload_ty = err_union_ty.errorUnionPayload();
63156331 const operand_pointer_ty = try Type.ptr(sema.arena, sema.mod, .{
63166332 .pointee_type = payload_ty,
63176333 .mutable = !operand_ty.isConstPtr(),
......@@ -6351,9 +6367,14 @@ fn analyzeErrUnionPayloadPtr(
63516367 }
63526368
63536369 try sema.requireRuntimeBlock(block, src);
6354 if (safety_check and block.wantSafety()) {
6370
6371 // If the error set has no fields then no safety check is needed.
6372 if (safety_check and block.wantSafety() and
6373 err_union_ty.errorUnionSet().errorSetCardinality() != .zero)
6374 {
63556375 try sema.panicUnwrapError(block, src, operand, .unwrap_errunion_err_ptr, .is_non_err_ptr);
63566376 }
6377
63576378 const air_tag: Air.Inst.Tag = if (initializing)
63586379 .errunion_payload_ptr_set
63596380 else
......@@ -20929,6 +20950,11 @@ fn analyzeLoad(
2092920950 .Pointer => ptr_ty.childType(),
2093020951 else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty.fmt(sema.mod)}),
2093120952 };
20953
20954 if (try sema.typeHasOnePossibleValue(block, src, elem_ty)) |opv| {
20955 return sema.addConstant(elem_ty, opv);
20956 }
20957
2093220958 if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| {
2093320959 if (try sema.pointerDeref(block, ptr_src, ptr_val, ptr_ty)) |elem_val| {
2093420960 return sema.addConstant(elem_ty, elem_val);
......@@ -23295,16 +23321,11 @@ pub fn typeHasOnePossibleValue(
2329523321 .const_slice,
2329623322 .mut_slice,
2329723323 .anyopaque,
23298 .optional,
2329923324 .optional_single_mut_pointer,
2330023325 .optional_single_const_pointer,
2330123326 .enum_literal,
2330223327 .anyerror_void_error_union,
23303 .error_union,
23304 .error_set,
23305 .error_set_single,
2330623328 .error_set_inferred,
23307 .error_set_merged,
2330823329 .@"opaque",
2330923330 .var_args_param,
2331023331 .manyptr_u8,
......@@ -23333,6 +23354,56 @@ pub fn typeHasOnePossibleValue(
2333323354 .bound_fn,
2333423355 => return null,
2333523356
23357 .optional => {
23358 var buf: Type.Payload.ElemType = undefined;
23359 const child_ty = ty.optionalChild(&buf);
23360 if (child_ty.isNoReturn()) {
23361 return Value.@"null";
23362 } else {
23363 return null;
23364 }
23365 },
23366
23367 .error_union => {
23368 const error_ty = ty.errorUnionSet();
23369 switch (error_ty.errorSetCardinality()) {
23370 .zero => {
23371 const payload_ty = ty.errorUnionPayload();
23372 if (try typeHasOnePossibleValue(sema, block, src, payload_ty)) |payload_val| {
23373 return try Value.Tag.eu_payload.create(sema.arena, payload_val);
23374 } else {
23375 return null;
23376 }
23377 },
23378 .one => {
23379 if (ty.errorUnionPayload().isNoReturn()) {
23380 const error_val = (try typeHasOnePossibleValue(sema, block, src, error_ty)).?;
23381 return error_val;
23382 } else {
23383 return null;
23384 }
23385 },
23386 .many => return null,
23387 }
23388 },
23389
23390 .error_set_single => {
23391 const name = ty.castTag(.error_set_single).?.data;
23392 return try Value.Tag.@"error".create(sema.arena, .{ .name = name });
23393 },
23394 .error_set => {
23395 const err_set_obj = ty.castTag(.error_set).?.data;
23396 const names = err_set_obj.names.keys();
23397 if (names.len > 1) return null;
23398 return try Value.Tag.@"error".create(sema.arena, .{ .name = names[0] });
23399 },
23400 .error_set_merged => {
23401 const name_map = ty.castTag(.error_set_merged).?.data;
23402 const names = name_map.keys();
23403 if (names.len > 1) return null;
23404 return try Value.Tag.@"error".create(sema.arena, .{ .name = names[0] });
23405 },
23406
2333623407 .@"struct" => {
2333723408 const resolved_ty = try sema.resolveTypeFields(block, src, ty);
2333823409 const s = resolved_ty.castTag(.@"struct").?.data;
src/arch/aarch64/CodeGen.zig+69-41
......@@ -3,6 +3,7 @@ const builtin = @import("builtin");
33const mem = std.mem;
44const math = std.math;
55const assert = std.debug.assert;
6const codegen = @import("../../codegen.zig");
67const Air = @import("../../Air.zig");
78const Mir = @import("Mir.zig");
89const Emit = @import("Emit.zig");
......@@ -22,12 +23,14 @@ const leb128 = std.leb;
2223const log = std.log.scoped(.codegen);
2324const build_options = @import("build_options");
2425
25const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError;
26const FnResult = @import("../../codegen.zig").FnResult;
27const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
26const GenerateSymbolError = codegen.GenerateSymbolError;
27const FnResult = codegen.FnResult;
28const DebugInfoOutput = codegen.DebugInfoOutput;
2829
2930const bits = @import("bits.zig");
3031const abi = @import("abi.zig");
32const errUnionPayloadOffset = codegen.errUnionPayloadOffset;
33const errUnionErrorOffset = codegen.errUnionErrorOffset;
3134const RegisterManager = abi.RegisterManager;
3235const RegisterLock = RegisterManager.RegisterLock;
3336const Register = bits.Register;
......@@ -3272,7 +3275,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
32723275
32733276fn ret(self: *Self, mcv: MCValue) !void {
32743277 const ret_ty = self.fn_type.fnReturnType();
3275 try self.setRegOrMem(ret_ty, self.ret_mcv, mcv);
3278 switch (self.ret_mcv) {
3279 .immediate => {
3280 assert(ret_ty.isError());
3281 },
3282 else => {
3283 try self.setRegOrMem(ret_ty, self.ret_mcv, mcv);
3284 },
3285 }
32763286 // Just add space for an instruction, patch this later
32773287 const index = try self.addInst(.{
32783288 .tag = .nop,
......@@ -3601,30 +3611,39 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
36013611 const error_type = ty.errorUnionSet();
36023612 const payload_type = ty.errorUnionPayload();
36033613
3604 if (!error_type.hasRuntimeBits()) {
3614 if (error_type.errorSetCardinality() == .zero) {
36053615 return MCValue{ .immediate = 0 }; // always false
3606 } else if (!payload_type.hasRuntimeBits()) {
3607 if (error_type.abiSize(self.target.*) <= 8) {
3608 const reg_mcv: MCValue = switch (operand) {
3609 .register => operand,
3610 else => .{ .register = try self.copyToTmpRegister(error_type, operand) },
3611 };
3616 }
36123617
3618 const err_off = errUnionErrorOffset(payload_type, self.target.*);
3619 switch (operand) {
3620 .stack_offset => |off| {
3621 const offset = off - @intCast(u32, err_off);
3622 const tmp_reg = try self.copyToTmpRegister(Type.anyerror, .{ .stack_offset = offset });
36133623 _ = try self.addInst(.{
36143624 .tag = .cmp_immediate,
36153625 .data = .{ .r_imm12_sh = .{
3616 .rn = reg_mcv.register,
3626 .rn = tmp_reg,
36173627 .imm12 = 0,
36183628 } },
36193629 });
3620
3621 return MCValue{ .compare_flags_unsigned = .gt };
3622 } else {
3623 return self.fail("TODO isErr for errors with size > 8", .{});
3624 }
3625 } else {
3626 return self.fail("TODO isErr for non-empty payloads", .{});
3630 },
3631 .register => |reg| {
3632 if (err_off > 0 or payload_type.hasRuntimeBitsIgnoreComptime()) {
3633 return self.fail("TODO implement isErr for register operand with payload bits", .{});
3634 }
3635 _ = try self.addInst(.{
3636 .tag = .cmp_immediate,
3637 .data = .{ .r_imm12_sh = .{
3638 .rn = reg,
3639 .imm12 = 0,
3640 } },
3641 });
3642 },
3643 else => return self.fail("TODO implement isErr for {}", .{operand}),
36273644 }
3645
3646 return MCValue{ .compare_flags_unsigned = .gt };
36283647}
36293648
36303649fn isNonErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
......@@ -4483,7 +4502,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
44834502 const ref_int = @enumToInt(inst);
44844503 if (ref_int < Air.Inst.Ref.typed_value_map.len) {
44854504 const tv = Air.Inst.Ref.typed_value_map[ref_int];
4486 if (!tv.ty.hasRuntimeBits()) {
4505 if (!tv.ty.hasRuntimeBitsIgnoreComptime() and !tv.ty.isError()) {
44874506 return MCValue{ .none = {} };
44884507 }
44894508 return self.genTypedValue(tv);
......@@ -4491,7 +4510,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
44914510
44924511 // If the type has no codegen bits, no need to store it.
44934512 const inst_ty = self.air.typeOf(inst);
4494 if (!inst_ty.hasRuntimeBits())
4513 if (!inst_ty.hasRuntimeBitsIgnoreComptime() and !inst_ty.isError())
44954514 return MCValue{ .none = {} };
44964515
44974516 const inst_index = @intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len);
......@@ -4674,32 +4693,38 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
46744693 }
46754694 },
46764695 .ErrorSet => {
4677 const err_name = typed_value.val.castTag(.@"error").?.data.name;
4678 const module = self.bin_file.options.module.?;
4679 const global_error_set = module.global_error_set;
4680 const error_index = global_error_set.get(err_name).?;
4681 return MCValue{ .immediate = error_index };
4696 switch (typed_value.val.tag()) {
4697 .@"error" => {
4698 const err_name = typed_value.val.castTag(.@"error").?.data.name;
4699 const module = self.bin_file.options.module.?;
4700 const global_error_set = module.global_error_set;
4701 const error_index = global_error_set.get(err_name).?;
4702 return MCValue{ .immediate = error_index };
4703 },
4704 else => {
4705 // In this case we are rendering an error union which has a 0 bits payload.
4706 return MCValue{ .immediate = 0 };
4707 },
4708 }
46824709 },
46834710 .ErrorUnion => {
46844711 const error_type = typed_value.ty.errorUnionSet();
46854712 const payload_type = typed_value.ty.errorUnionPayload();
46864713
4687 if (typed_value.val.castTag(.eu_payload)) |pl| {
4688 if (!payload_type.hasRuntimeBits()) {
4689 // We use the error type directly as the type.
4690 return MCValue{ .immediate = 0 };
4691 }
4714 if (error_type.errorSetCardinality() == .zero) {
4715 const payload_val = typed_value.val.castTag(.eu_payload).?.data;
4716 return self.genTypedValue(.{ .ty = payload_type, .val = payload_val });
4717 }
46924718
4693 _ = pl;
4694 return self.fail("TODO implement error union const of type '{}' (non-error)", .{typed_value.ty.fmtDebug()});
4695 } else {
4696 if (!payload_type.hasRuntimeBits()) {
4697 // We use the error type directly as the type.
4698 return self.genTypedValue(.{ .ty = error_type, .val = typed_value.val });
4699 }
4719 const is_pl = typed_value.val.errorUnionIsPayload();
47004720
4701 return self.fail("TODO implement error union const of type '{}' (error)", .{typed_value.ty.fmtDebug()});
4721 if (!payload_type.hasRuntimeBitsIgnoreComptime()) {
4722 // We use the error type directly as the type.
4723 const err_val = if (!is_pl) typed_value.val else Value.initTag(.zero);
4724 return self.genTypedValue(.{ .ty = error_type, .val = err_val });
47024725 }
4726
4727 return self.lowerUnnamedConst(typed_value);
47034728 },
47044729 .Struct => {
47054730 return self.lowerUnnamedConst(typed_value);
......@@ -4796,13 +4821,16 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
47964821
47974822 if (ret_ty.zigTypeTag() == .NoReturn) {
47984823 result.return_value = .{ .unreach = {} };
4799 } else if (!ret_ty.hasRuntimeBits()) {
4824 } else if (!ret_ty.hasRuntimeBitsIgnoreComptime() and !ret_ty.isError()) {
48004825 result.return_value = .{ .none = {} };
48014826 } else switch (cc) {
48024827 .Naked => unreachable,
48034828 .Unspecified, .C => {
48044829 const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*));
4805 if (ret_ty_size <= 8) {
4830 if (ret_ty_size == 0) {
4831 assert(ret_ty.isError());
4832 result.return_value = .{ .immediate = 0 };
4833 } else if (ret_ty_size <= 8) {
48064834 result.return_value = .{ .register = registerAlias(c_abi_int_return_regs[0], ret_ty_size) };
48074835 } else {
48084836 return self.fail("TODO support more return types for ARM backend", .{});
src/arch/arm/CodeGen.zig+64-37
......@@ -3,6 +3,7 @@ const builtin = @import("builtin");
33const mem = std.mem;
44const math = std.math;
55const assert = std.debug.assert;
6const codegen = @import("../../codegen.zig");
67const Air = @import("../../Air.zig");
78const Mir = @import("Mir.zig");
89const Emit = @import("Emit.zig");
......@@ -22,12 +23,14 @@ const leb128 = std.leb;
2223const log = std.log.scoped(.codegen);
2324const build_options = @import("build_options");
2425
25const FnResult = @import("../../codegen.zig").FnResult;
26const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError;
27const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
26const FnResult = codegen.FnResult;
27const GenerateSymbolError = codegen.GenerateSymbolError;
28const DebugInfoOutput = codegen.DebugInfoOutput;
2829
2930const bits = @import("bits.zig");
3031const abi = @import("abi.zig");
32const errUnionPayloadOffset = codegen.errUnionPayloadOffset;
33const errUnionErrorOffset = codegen.errUnionErrorOffset;
3134const RegisterManager = abi.RegisterManager;
3235const RegisterLock = RegisterManager.RegisterLock;
3336const Register = bits.Register;
......@@ -1763,19 +1766,26 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
17631766
17641767/// Given an error union, returns the error
17651768fn errUnionErr(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCValue {
1769 const err_ty = error_union_ty.errorUnionSet();
17661770 const payload_ty = error_union_ty.errorUnionPayload();
1767 if (!payload_ty.hasRuntimeBits()) return error_union_mcv;
1771 if (err_ty.errorSetCardinality() == .zero) {
1772 return MCValue{ .immediate = 0 };
1773 }
1774 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
1775 return error_union_mcv;
1776 }
17681777
1778 const err_offset = @intCast(u32, errUnionErrorOffset(payload_ty, self.target.*));
17691779 switch (error_union_mcv) {
17701780 .register => return self.fail("TODO errUnionErr for registers", .{}),
17711781 .stack_argument_offset => |off| {
1772 return MCValue{ .stack_argument_offset = off };
1782 return MCValue{ .stack_argument_offset = off - err_offset };
17731783 },
17741784 .stack_offset => |off| {
1775 return MCValue{ .stack_offset = off };
1785 return MCValue{ .stack_offset = off - err_offset };
17761786 },
17771787 .memory => |addr| {
1778 return MCValue{ .memory = addr };
1788 return MCValue{ .memory = addr + err_offset };
17791789 },
17801790 else => unreachable, // invalid MCValue for an error union
17811791 }
......@@ -1793,24 +1803,26 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
17931803
17941804/// Given an error union, returns the payload
17951805fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCValue {
1806 const err_ty = error_union_ty.errorUnionSet();
17961807 const payload_ty = error_union_ty.errorUnionPayload();
1797 if (!payload_ty.hasRuntimeBits()) return MCValue.none;
1798
1799 const error_ty = error_union_ty.errorUnionSet();
1800 const error_size = @intCast(u32, error_ty.abiSize(self.target.*));
1801 const eu_align = @intCast(u32, error_union_ty.abiAlignment(self.target.*));
1802 const offset = std.mem.alignForwardGeneric(u32, error_size, eu_align);
1808 if (err_ty.errorSetCardinality() == .zero) {
1809 return error_union_mcv;
1810 }
1811 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
1812 return MCValue.none;
1813 }
18031814
1815 const payload_offset = @intCast(u32, errUnionPayloadOffset(payload_ty, self.target.*));
18041816 switch (error_union_mcv) {
18051817 .register => return self.fail("TODO errUnionPayload for registers", .{}),
18061818 .stack_argument_offset => |off| {
1807 return MCValue{ .stack_argument_offset = off - offset };
1819 return MCValue{ .stack_argument_offset = off - payload_offset };
18081820 },
18091821 .stack_offset => |off| {
1810 return MCValue{ .stack_offset = off - offset };
1822 return MCValue{ .stack_offset = off - payload_offset };
18111823 },
18121824 .memory => |addr| {
1813 return MCValue{ .memory = addr - offset };
1825 return MCValue{ .memory = addr + payload_offset };
18141826 },
18151827 else => unreachable, // invalid MCValue for an error union
18161828 }
......@@ -3478,6 +3490,9 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void {
34783490
34793491 switch (self.ret_mcv) {
34803492 .none => {},
3493 .immediate => {
3494 assert(ret_ty.isError());
3495 },
34813496 .register => |reg| {
34823497 // Return result by value
34833498 try self.genSetReg(ret_ty, reg, operand);
......@@ -3867,7 +3882,7 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
38673882 const error_type = ty.errorUnionSet();
38683883 const error_int_type = Type.initTag(.u16);
38693884
3870 if (!error_type.hasRuntimeBits()) {
3885 if (error_type.errorSetCardinality() == .zero) {
38713886 return MCValue{ .immediate = 0 }; // always false
38723887 }
38733888
......@@ -4975,7 +4990,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
49754990 const ref_int = @enumToInt(inst);
49764991 if (ref_int < Air.Inst.Ref.typed_value_map.len) {
49774992 const tv = Air.Inst.Ref.typed_value_map[ref_int];
4978 if (!tv.ty.hasRuntimeBits()) {
4993 if (!tv.ty.hasRuntimeBitsIgnoreComptime() and !tv.ty.isError()) {
49794994 return MCValue{ .none = {} };
49804995 }
49814996 return self.genTypedValue(tv);
......@@ -4983,7 +4998,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
49834998
49844999 // If the type has no codegen bits, no need to store it.
49855000 const inst_ty = self.air.typeOf(inst);
4986 if (!inst_ty.hasRuntimeBits())
5001 if (!inst_ty.hasRuntimeBitsIgnoreComptime() and !inst_ty.isError())
49875002 return MCValue{ .none = {} };
49885003
49895004 const inst_index = @intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len);
......@@ -5147,26 +5162,35 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
51475162 }
51485163 },
51495164 .ErrorSet => {
5150 const err_name = typed_value.val.castTag(.@"error").?.data.name;
5151 const module = self.bin_file.options.module.?;
5152 const global_error_set = module.global_error_set;
5153 const error_index = global_error_set.get(err_name).?;
5154 return MCValue{ .immediate = error_index };
5165 switch (typed_value.val.tag()) {
5166 .@"error" => {
5167 const err_name = typed_value.val.castTag(.@"error").?.data.name;
5168 const module = self.bin_file.options.module.?;
5169 const global_error_set = module.global_error_set;
5170 const error_index = global_error_set.get(err_name).?;
5171 return MCValue{ .immediate = error_index };
5172 },
5173 else => {
5174 // In this case we are rendering an error union which has a 0 bits payload.
5175 return MCValue{ .immediate = 0 };
5176 },
5177 }
51555178 },
51565179 .ErrorUnion => {
51575180 const error_type = typed_value.ty.errorUnionSet();
51585181 const payload_type = typed_value.ty.errorUnionPayload();
51595182
5160 if (typed_value.val.castTag(.eu_payload)) |_| {
5161 if (!payload_type.hasRuntimeBits()) {
5162 // We use the error type directly as the type.
5163 return MCValue{ .immediate = 0 };
5164 }
5165 } else {
5166 if (!payload_type.hasRuntimeBits()) {
5167 // We use the error type directly as the type.
5168 return self.genTypedValue(.{ .ty = error_type, .val = typed_value.val });
5169 }
5183 if (error_type.errorSetCardinality() == .zero) {
5184 const payload_val = typed_value.val.castTag(.eu_payload).?.data;
5185 return self.genTypedValue(.{ .ty = payload_type, .val = payload_val });
5186 }
5187
5188 const is_pl = typed_value.val.errorUnionIsPayload();
5189
5190 if (!payload_type.hasRuntimeBitsIgnoreComptime()) {
5191 // We use the error type directly as the type.
5192 const err_val = if (!is_pl) typed_value.val else Value.initTag(.zero);
5193 return self.genTypedValue(.{ .ty = error_type, .val = err_val });
51705194 }
51715195 },
51725196
......@@ -5231,7 +5255,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
52315255
52325256 if (ret_ty.zigTypeTag() == .NoReturn) {
52335257 result.return_value = .{ .unreach = {} };
5234 } else if (!ret_ty.hasRuntimeBits()) {
5258 } else if (!ret_ty.hasRuntimeBitsIgnoreComptime()) {
52355259 result.return_value = .{ .none = {} };
52365260 } else {
52375261 const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*));
......@@ -5278,11 +5302,14 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
52785302 .Unspecified => {
52795303 if (ret_ty.zigTypeTag() == .NoReturn) {
52805304 result.return_value = .{ .unreach = {} };
5281 } else if (!ret_ty.hasRuntimeBits()) {
5305 } else if (!ret_ty.hasRuntimeBitsIgnoreComptime() and !ret_ty.isError()) {
52825306 result.return_value = .{ .none = {} };
52835307 } else {
52845308 const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*));
5285 if (ret_ty_size <= 4) {
5309 if (ret_ty_size == 0) {
5310 assert(ret_ty.isError());
5311 result.return_value = .{ .immediate = 0 };
5312 } else if (ret_ty_size <= 4) {
52865313 result.return_value = .{ .register = .r0 };
52875314 } else {
52885315 // The result is returned by reference, not by
src/arch/wasm/CodeGen.zig+110-59
......@@ -22,6 +22,8 @@ const Liveness = @import("../../Liveness.zig");
2222const Mir = @import("Mir.zig");
2323const Emit = @import("Emit.zig");
2424const abi = @import("abi.zig");
25const errUnionPayloadOffset = codegen.errUnionPayloadOffset;
26const errUnionErrorOffset = codegen.errUnionErrorOffset;
2527
2628/// Wasm Value, created when generating an instruction
2729const WValue = union(enum) {
......@@ -636,7 +638,7 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!WValue {
636638 // means we must generate it from a constant.
637639 const val = self.air.value(ref).?;
638640 const ty = self.air.typeOf(ref);
639 if (!ty.hasRuntimeBitsIgnoreComptime() and !ty.isInt()) {
641 if (!ty.hasRuntimeBitsIgnoreComptime() and !ty.isInt() and !ty.isError()) {
640642 gop.value_ptr.* = WValue{ .none = {} };
641643 return gop.value_ptr.*;
642644 }
......@@ -804,6 +806,8 @@ fn genFunctype(gpa: Allocator, fn_info: Type.Payload.Function.Data, target: std.
804806 } else {
805807 try returns.append(typeToValtype(fn_info.return_type, target));
806808 }
809 } else if (fn_info.return_type.isError()) {
810 try returns.append(.i32);
807811 }
808812
809813 // param types
......@@ -1373,13 +1377,18 @@ fn isByRef(ty: Type, target: std.Target) bool {
13731377 .Int => return ty.intInfo(target).bits > 64,
13741378 .Float => return ty.floatBits(target) > 64,
13751379 .ErrorUnion => {
1376 const has_tag = ty.errorUnionSet().hasRuntimeBitsIgnoreComptime();
1377 const has_pl = ty.errorUnionPayload().hasRuntimeBitsIgnoreComptime();
1378 if (!has_tag or !has_pl) return false;
1379 return ty.hasRuntimeBitsIgnoreComptime();
1380 const err_ty = ty.errorUnionSet();
1381 const pl_ty = ty.errorUnionPayload();
1382 if (err_ty.errorSetCardinality() == .zero) {
1383 return isByRef(pl_ty, target);
1384 }
1385 if (!pl_ty.hasRuntimeBitsIgnoreComptime()) {
1386 return false;
1387 }
1388 return true;
13801389 },
13811390 .Optional => {
1382 if (ty.isPtrLikeOptional()) return false;
1391 if (ty.optionalReprIsPayload()) return false;
13831392 var buf: Type.Payload.ElemType = undefined;
13841393 return ty.optionalChild(&buf).hasRuntimeBitsIgnoreComptime();
13851394 },
......@@ -1624,13 +1633,14 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
16241633fn airRet(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
16251634 const un_op = self.air.instructions.items(.data)[inst].un_op;
16261635 const operand = try self.resolveInst(un_op);
1627 const ret_ty = self.decl.ty.fnReturnType();
1636 const fn_info = self.decl.ty.fnInfo();
1637 const ret_ty = fn_info.return_type;
16281638
16291639 // result must be stored in the stack and we return a pointer
16301640 // to the stack instead
16311641 if (self.return_value != .none) {
1632 try self.store(self.return_value, operand, self.decl.ty.fnReturnType(), 0);
1633 } else if (self.decl.ty.fnInfo().cc == .C and ret_ty.hasRuntimeBitsIgnoreComptime()) {
1642 try self.store(self.return_value, operand, ret_ty, 0);
1643 } else if (fn_info.cc == .C and ret_ty.hasRuntimeBitsIgnoreComptime()) {
16341644 switch (ret_ty.zigTypeTag()) {
16351645 // Aggregate types can be lowered as a singular value
16361646 .Struct, .Union => {
......@@ -1650,7 +1660,11 @@ fn airRet(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
16501660 else => try self.emitWValue(operand),
16511661 }
16521662 } else {
1653 try self.emitWValue(operand);
1663 if (!ret_ty.hasRuntimeBitsIgnoreComptime() and ret_ty.isError()) {
1664 try self.addImm32(0);
1665 } else {
1666 try self.emitWValue(operand);
1667 }
16541668 }
16551669 try self.restoreStackPointer();
16561670 try self.addTag(.@"return");
......@@ -1675,7 +1689,13 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
16751689 const un_op = self.air.instructions.items(.data)[inst].un_op;
16761690 const operand = try self.resolveInst(un_op);
16771691 const ret_ty = self.air.typeOf(un_op).childType();
1678 if (!ret_ty.hasRuntimeBitsIgnoreComptime()) return WValue.none;
1692 if (!ret_ty.hasRuntimeBitsIgnoreComptime()) {
1693 if (ret_ty.isError()) {
1694 try self.addImm32(0);
1695 } else {
1696 return WValue.none;
1697 }
1698 }
16791699
16801700 if (!firstParamSRet(self.decl.ty.fnInfo(), self.target)) {
16811701 const result = try self.load(operand, ret_ty, 0);
......@@ -1723,8 +1743,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
17231743
17241744 const sret = if (first_param_sret) blk: {
17251745 const sret_local = try self.allocStack(ret_ty);
1726 const ptr_offset = try self.buildPointerOffset(sret_local, 0, .new);
1727 try self.emitWValue(ptr_offset);
1746 try self.lowerToStack(sret_local);
17281747 break :blk sret_local;
17291748 } else WValue{ .none = {} };
17301749
......@@ -1754,7 +1773,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
17541773 try self.addLabel(.call_indirect, fn_type_index);
17551774 }
17561775
1757 if (self.liveness.isUnused(inst) or !ret_ty.hasRuntimeBitsIgnoreComptime()) {
1776 if (self.liveness.isUnused(inst) or (!ret_ty.hasRuntimeBitsIgnoreComptime() and !ret_ty.isError())) {
17581777 return WValue.none;
17591778 } else if (ret_ty.isNoReturn()) {
17601779 try self.addTag(.@"unreachable");
......@@ -1796,8 +1815,11 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
17961815 .ErrorUnion => {
17971816 const err_ty = ty.errorUnionSet();
17981817 const pl_ty = ty.errorUnionPayload();
1818 if (err_ty.errorSetCardinality() == .zero) {
1819 return self.store(lhs, rhs, pl_ty, 0);
1820 }
17991821 if (!pl_ty.hasRuntimeBitsIgnoreComptime()) {
1800 return self.store(lhs, rhs, err_ty, 0);
1822 return self.store(lhs, rhs, Type.anyerror, 0);
18011823 }
18021824
18031825 const len = @intCast(u32, ty.abiSize(self.target));
......@@ -1812,6 +1834,9 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
18121834 if (!pl_ty.hasRuntimeBitsIgnoreComptime()) {
18131835 return self.store(lhs, rhs, Type.u8, 0);
18141836 }
1837 if (pl_ty.zigTypeTag() == .ErrorSet) {
1838 return self.store(lhs, rhs, Type.anyerror, 0);
1839 }
18151840
18161841 const len = @intCast(u32, ty.abiSize(self.target));
18171842 return self.memcpy(lhs, rhs, .{ .imm32 = len });
......@@ -2178,7 +2203,7 @@ fn lowerParentPtr(self: *Self, ptr_val: Value, ptr_child_ty: Type) InnerError!WV
21782203 const parent_ptr = try self.lowerParentPtr(payload_ptr.container_ptr, payload_ptr.container_ty);
21792204 var buf: Type.Payload.ElemType = undefined;
21802205 const payload_ty = payload_ptr.container_ty.optionalChild(&buf);
2181 if (!payload_ty.hasRuntimeBitsIgnoreComptime() or payload_ty.isPtrLikeOptional()) {
2206 if (!payload_ty.hasRuntimeBitsIgnoreComptime() or payload_ty.optionalReprIsPayload()) {
21822207 return parent_ptr;
21832208 }
21842209
......@@ -2256,6 +2281,7 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
22562281 const target = self.target;
22572282
22582283 switch (ty.zigTypeTag()) {
2284 .Void => return WValue{ .none = {} },
22592285 .Int => {
22602286 const int_info = ty.intInfo(self.target);
22612287 switch (int_info.signedness) {
......@@ -2324,11 +2350,15 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
23242350 },
23252351 .ErrorUnion => {
23262352 const error_type = ty.errorUnionSet();
2353 if (error_type.errorSetCardinality() == .zero) {
2354 const pl_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef);
2355 return self.lowerConstant(pl_val, ty.errorUnionPayload());
2356 }
23272357 const is_pl = val.errorUnionIsPayload();
23282358 const err_val = if (!is_pl) val else Value.initTag(.zero);
23292359 return self.lowerConstant(err_val, error_type);
23302360 },
2331 .Optional => if (ty.isPtrLikeOptional()) {
2361 .Optional => if (ty.optionalReprIsPayload()) {
23322362 var buf: Type.Payload.ElemType = undefined;
23332363 const pl_ty = ty.optionalChild(&buf);
23342364 if (val.castTag(.opt_payload)) |payload| {
......@@ -2367,7 +2397,7 @@ fn emitUndefined(self: *Self, ty: Type) InnerError!WValue {
23672397 .Optional => {
23682398 var buf: Type.Payload.ElemType = undefined;
23692399 const pl_ty = ty.optionalChild(&buf);
2370 if (ty.isPtrLikeOptional()) {
2400 if (ty.optionalReprIsPayload()) {
23712401 return self.emitUndefined(pl_ty);
23722402 }
23732403 return WValue{ .imm32 = 0xaaaaaaaa };
......@@ -2517,7 +2547,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner
25172547}
25182548
25192549fn cmp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareOperator) InnerError!WValue {
2520 if (ty.zigTypeTag() == .Optional and !ty.isPtrLikeOptional()) {
2550 if (ty.zigTypeTag() == .Optional and !ty.optionalReprIsPayload()) {
25212551 var buf: Type.Payload.ElemType = undefined;
25222552 const payload_ty = ty.optionalChild(&buf);
25232553 if (payload_ty.hasRuntimeBitsIgnoreComptime()) {
......@@ -2889,15 +2919,22 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
28892919fn airIsErr(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!WValue {
28902920 const un_op = self.air.instructions.items(.data)[inst].un_op;
28912921 const operand = try self.resolveInst(un_op);
2892 const err_ty = self.air.typeOf(un_op);
2893 const pl_ty = err_ty.errorUnionPayload();
2922 const err_union_ty = self.air.typeOf(un_op);
2923 const pl_ty = err_union_ty.errorUnionPayload();
2924
2925 if (err_union_ty.errorUnionSet().errorSetCardinality() == .zero) {
2926 switch (opcode) {
2927 .i32_ne => return WValue{ .imm32 = 0 },
2928 .i32_eq => return WValue{ .imm32 = 1 },
2929 else => unreachable,
2930 }
2931 }
28942932
2895 // load the error tag value
28962933 try self.emitWValue(operand);
28972934 if (pl_ty.hasRuntimeBitsIgnoreComptime()) {
28982935 try self.addMemArg(.i32_load16_u, .{
2899 .offset = operand.offset(),
2900 .alignment = err_ty.errorUnionSet().abiAlignment(self.target),
2936 .offset = operand.offset() + @intCast(u32, errUnionErrorOffset(pl_ty, self.target)),
2937 .alignment = Type.anyerror.abiAlignment(self.target),
29012938 });
29022939 }
29032940
......@@ -2905,7 +2942,7 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!W
29052942 try self.addImm32(0);
29062943 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
29072944
2908 const is_err_tmp = try self.allocLocal(Type.initTag(.i32)); // result is always an i32
2945 const is_err_tmp = try self.allocLocal(Type.i32);
29092946 try self.addLabel(.local_set, is_err_tmp.local);
29102947 return is_err_tmp;
29112948}
......@@ -2917,14 +2954,18 @@ fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index, op_is_ptr: bool)
29172954 const op_ty = self.air.typeOf(ty_op.operand);
29182955 const err_ty = if (op_is_ptr) op_ty.childType() else op_ty;
29192956 const payload_ty = err_ty.errorUnionPayload();
2957
2958 if (err_ty.errorUnionSet().errorSetCardinality() == .zero) {
2959 return operand;
2960 }
2961
29202962 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return WValue{ .none = {} };
2921 const err_align = err_ty.abiAlignment(self.target);
2922 const set_size = err_ty.errorUnionSet().abiSize(self.target);
2923 const offset = mem.alignForwardGeneric(u64, set_size, err_align);
2963
2964 const pl_offset = @intCast(u32, errUnionPayloadOffset(payload_ty, self.target));
29242965 if (op_is_ptr or isByRef(payload_ty, self.target)) {
2925 return self.buildPointerOffset(operand, offset, .new);
2966 return self.buildPointerOffset(operand, pl_offset, .new);
29262967 }
2927 return self.load(operand, payload_ty, @intCast(u32, offset));
2968 return self.load(operand, payload_ty, pl_offset);
29282969}
29292970
29302971fn airUnwrapErrUnionError(self: *Self, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!WValue {
......@@ -2935,11 +2976,16 @@ fn airUnwrapErrUnionError(self: *Self, inst: Air.Inst.Index, op_is_ptr: bool) In
29352976 const op_ty = self.air.typeOf(ty_op.operand);
29362977 const err_ty = if (op_is_ptr) op_ty.childType() else op_ty;
29372978 const payload_ty = err_ty.errorUnionPayload();
2979
2980 if (err_ty.errorUnionSet().errorSetCardinality() == .zero) {
2981 return WValue{ .imm32 = 0 };
2982 }
2983
29382984 if (op_is_ptr or !payload_ty.hasRuntimeBitsIgnoreComptime()) {
29392985 return operand;
29402986 }
29412987
2942 return self.load(operand, err_ty.errorUnionSet(), 0);
2988 return self.load(operand, Type.anyerror, @intCast(u32, errUnionErrorOffset(payload_ty, self.target)));
29432989}
29442990
29452991fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
......@@ -2947,22 +2993,26 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
29472993
29482994 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
29492995 const operand = try self.resolveInst(ty_op.operand);
2996 const err_ty = self.air.typeOfIndex(inst);
29502997
2951 const op_ty = self.air.typeOf(ty_op.operand);
2952 if (!op_ty.hasRuntimeBitsIgnoreComptime()) return operand;
2953 const err_union_ty = self.air.getRefType(ty_op.ty);
2954 const err_align = err_union_ty.abiAlignment(self.target);
2955 const set_size = err_union_ty.errorUnionSet().abiSize(self.target);
2956 const offset = mem.alignForwardGeneric(u64, set_size, err_align);
2998 if (err_ty.errorUnionSet().errorSetCardinality() == .zero) {
2999 return operand;
3000 }
29573001
2958 const err_union = try self.allocStack(err_union_ty);
2959 const payload_ptr = try self.buildPointerOffset(err_union, offset, .new);
2960 try self.store(payload_ptr, operand, op_ty, 0);
3002 const pl_ty = self.air.typeOf(ty_op.operand);
3003 if (!pl_ty.hasRuntimeBitsIgnoreComptime()) {
3004 return operand;
3005 }
3006
3007 const err_union = try self.allocStack(err_ty);
3008 const payload_ptr = try self.buildPointerOffset(err_union, @intCast(u32, errUnionPayloadOffset(pl_ty, self.target)), .new);
3009 try self.store(payload_ptr, operand, pl_ty, 0);
29613010
29623011 // ensure we also write '0' to the error part, so any present stack value gets overwritten by it.
29633012 try self.emitWValue(err_union);
29643013 try self.addImm32(0);
2965 try self.addMemArg(.i32_store16, .{ .offset = err_union.offset(), .alignment = 2 });
3014 const err_val_offset = @intCast(u32, errUnionErrorOffset(pl_ty, self.target));
3015 try self.addMemArg(.i32_store16, .{ .offset = err_union.offset() + err_val_offset, .alignment = 2 });
29663016
29673017 return err_union;
29683018}
......@@ -2973,17 +3023,18 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
29733023 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
29743024 const operand = try self.resolveInst(ty_op.operand);
29753025 const err_ty = self.air.getRefType(ty_op.ty);
3026 const pl_ty = err_ty.errorUnionPayload();
29763027
2977 if (!err_ty.errorUnionPayload().hasRuntimeBitsIgnoreComptime()) return operand;
3028 if (!pl_ty.hasRuntimeBitsIgnoreComptime()) {
3029 return operand;
3030 }
29783031
29793032 const err_union = try self.allocStack(err_ty);
2980 try self.store(err_union, operand, err_ty.errorUnionSet(), 0);
3033 // store error value
3034 try self.store(err_union, operand, Type.anyerror, @intCast(u32, errUnionErrorOffset(pl_ty, self.target)));
29813035
29823036 // write 'undefined' to the payload
2983 const err_align = err_ty.abiAlignment(self.target);
2984 const set_size = err_ty.errorUnionSet().abiSize(self.target);
2985 const offset = mem.alignForwardGeneric(u64, set_size, err_align);
2986 const payload_ptr = try self.buildPointerOffset(err_union, offset, .new);
3037 const payload_ptr = try self.buildPointerOffset(err_union, @intCast(u32, errUnionPayloadOffset(pl_ty, self.target)), .new);
29873038 const len = @intCast(u32, err_ty.errorUnionPayload().abiSize(self.target));
29883039 try self.memset(payload_ptr, .{ .imm32 = len }, .{ .imm32 = 0xaaaaaaaa });
29893040
......@@ -3074,7 +3125,7 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode, op_kind: en
30743125
30753126fn isNull(self: *Self, operand: WValue, optional_ty: Type, opcode: wasm.Opcode) InnerError!WValue {
30763127 try self.emitWValue(operand);
3077 if (!optional_ty.isPtrLikeOptional()) {
3128 if (!optional_ty.optionalReprIsPayload()) {
30783129 var buf: Type.Payload.ElemType = undefined;
30793130 const payload_ty = optional_ty.optionalChild(&buf);
30803131 // When payload is zero-bits, we can treat operand as a value, rather than
......@@ -3100,7 +3151,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
31003151 const opt_ty = self.air.typeOf(ty_op.operand);
31013152 const payload_ty = self.air.typeOfIndex(inst);
31023153 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return WValue{ .none = {} };
3103 if (opt_ty.isPtrLikeOptional()) return operand;
3154 if (opt_ty.optionalReprIsPayload()) return operand;
31043155
31053156 const offset = opt_ty.abiSize(self.target) - payload_ty.abiSize(self.target);
31063157
......@@ -3120,7 +3171,7 @@ fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
31203171
31213172 var buf: Type.Payload.ElemType = undefined;
31223173 const payload_ty = opt_ty.optionalChild(&buf);
3123 if (!payload_ty.hasRuntimeBitsIgnoreComptime() or opt_ty.isPtrLikeOptional()) {
3174 if (!payload_ty.hasRuntimeBitsIgnoreComptime() or opt_ty.optionalReprIsPayload()) {
31243175 return operand;
31253176 }
31263177
......@@ -3138,7 +3189,7 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) InnerError!WValue
31383189 return self.fail("TODO: Implement OptionalPayloadPtrSet for optional with zero-sized type {}", .{payload_ty.fmtDebug()});
31393190 }
31403191
3141 if (opt_ty.isPtrLikeOptional()) {
3192 if (opt_ty.optionalReprIsPayload()) {
31423193 return operand;
31433194 }
31443195
......@@ -3169,7 +3220,7 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
31693220
31703221 const operand = try self.resolveInst(ty_op.operand);
31713222 const op_ty = self.air.typeOfIndex(inst);
3172 if (op_ty.isPtrLikeOptional()) {
3223 if (op_ty.optionalReprIsPayload()) {
31733224 return operand;
31743225 }
31753226 const offset = std.math.cast(u32, op_ty.abiSize(self.target) - payload_ty.abiSize(self.target)) catch {
......@@ -3927,12 +3978,16 @@ fn airFptrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
39273978fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
39283979 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
39293980 const err_set_ty = self.air.typeOf(ty_op.operand).childType();
3930 const err_ty = err_set_ty.errorUnionSet();
39313981 const payload_ty = err_set_ty.errorUnionPayload();
39323982 const operand = try self.resolveInst(ty_op.operand);
39333983
39343984 // set error-tag to '0' to annotate error union is non-error
3935 try self.store(operand, .{ .imm32 = 0 }, err_ty, 0);
3985 try self.store(
3986 operand,
3987 .{ .imm32 = 0 },
3988 Type.anyerror,
3989 @intCast(u32, errUnionErrorOffset(payload_ty, self.target)),
3990 );
39363991
39373992 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
39383993
......@@ -3940,11 +3995,7 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) InnerError!WValue
39403995 return operand;
39413996 }
39423997
3943 const err_align = err_set_ty.abiAlignment(self.target);
3944 const set_size = err_ty.abiSize(self.target);
3945 const offset = mem.alignForwardGeneric(u64, set_size, err_align);
3946
3947 return self.buildPointerOffset(operand, @intCast(u32, offset), .new);
3998 return self.buildPointerOffset(operand, @intCast(u32, errUnionPayloadOffset(payload_ty, self.target)), .new);
39483999}
39494000
39504001fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
src/arch/x86_64/CodeGen.zig+161-81
......@@ -2,6 +2,7 @@ const std = @import("std");
22const build_options = @import("build_options");
33const builtin = @import("builtin");
44const assert = std.debug.assert;
5const codegen = @import("../../codegen.zig");
56const leb128 = std.leb;
67const link = @import("../../link.zig");
78const log = std.log.scoped(.codegen);
......@@ -12,11 +13,11 @@ const trace = @import("../../tracy.zig").trace;
1213const Air = @import("../../Air.zig");
1314const Allocator = mem.Allocator;
1415const Compilation = @import("../../Compilation.zig");
15const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
16const DebugInfoOutput = codegen.DebugInfoOutput;
1617const DW = std.dwarf;
1718const ErrorMsg = Module.ErrorMsg;
18const FnResult = @import("../../codegen.zig").FnResult;
19const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError;
19const FnResult = codegen.FnResult;
20const GenerateSymbolError = codegen.GenerateSymbolError;
2021const Emit = @import("Emit.zig");
2122const Liveness = @import("../../Liveness.zig");
2223const Mir = @import("Mir.zig");
......@@ -28,6 +29,8 @@ const Value = @import("../../value.zig").Value;
2829
2930const bits = @import("bits.zig");
3031const abi = @import("abi.zig");
32const errUnionPayloadOffset = codegen.errUnionPayloadOffset;
33const errUnionErrorOffset = codegen.errUnionErrorOffset;
3134
3235const callee_preserved_regs = abi.callee_preserved_regs;
3336const caller_preserved_regs = abi.caller_preserved_regs;
......@@ -854,7 +857,7 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 {
854857 const ptr_ty = self.air.typeOfIndex(inst);
855858 const elem_ty = ptr_ty.elemType();
856859
857 if (!elem_ty.hasRuntimeBits()) {
860 if (!elem_ty.hasRuntimeBitsIgnoreComptime()) {
858861 return self.allocMem(inst, @sizeOf(usize), @alignOf(usize));
859862 }
860863
......@@ -1786,21 +1789,34 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
17861789 const err_ty = err_union_ty.errorUnionSet();
17871790 const payload_ty = err_union_ty.errorUnionPayload();
17881791 const operand = try self.resolveInst(ty_op.operand);
1789 const operand_lock: ?RegisterLock = switch (operand) {
1790 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
1791 else => null,
1792 };
1793 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
17941792
17951793 const result: MCValue = result: {
1796 if (!payload_ty.hasRuntimeBits()) break :result operand;
1794 if (err_ty.errorSetCardinality() == .zero) {
1795 break :result MCValue{ .immediate = 0 };
1796 }
1797
1798 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
1799 break :result operand;
1800 }
1801
1802 const err_off = errUnionErrorOffset(payload_ty, self.target.*);
17971803 switch (operand) {
17981804 .stack_offset => |off| {
1799 break :result MCValue{ .stack_offset = off };
1805 const offset = off - @intCast(i32, err_off);
1806 break :result MCValue{ .stack_offset = offset };
18001807 },
1801 .register => {
1808 .register => |reg| {
18021809 // TODO reuse operand
1803 break :result try self.copyToRegisterWithInstTracking(inst, err_ty, operand);
1810 const lock = self.register_manager.lockRegAssumeUnused(reg);
1811 defer self.register_manager.unlockReg(lock);
1812 const result = try self.copyToRegisterWithInstTracking(inst, err_union_ty, operand);
1813 if (err_off > 0) {
1814 const shift = @intCast(u6, err_off * 8);
1815 try self.genShiftBinOpMir(.shr, err_union_ty, result.register, .{ .immediate = shift });
1816 } else {
1817 try self.truncateRegister(Type.anyerror, result.register);
1818 }
1819 break :result result;
18041820 },
18051821 else => return self.fail("TODO implement unwrap_err_err for {}", .{operand}),
18061822 }
......@@ -1815,32 +1831,37 @@ fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {
18151831 }
18161832 const err_union_ty = self.air.typeOf(ty_op.operand);
18171833 const payload_ty = err_union_ty.errorUnionPayload();
1834 const err_ty = err_union_ty.errorUnionSet();
1835 const operand = try self.resolveInst(ty_op.operand);
1836
18181837 const result: MCValue = result: {
1819 if (!payload_ty.hasRuntimeBits()) break :result MCValue.none;
1838 if (err_ty.errorSetCardinality() == .zero) {
1839 // TODO check if we can reuse
1840 break :result operand;
1841 }
18201842
1821 const operand = try self.resolveInst(ty_op.operand);
1822 const operand_lock: ?RegisterLock = switch (operand) {
1823 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
1824 else => null,
1825 };
1826 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
1843 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
1844 break :result MCValue.none;
1845 }
18271846
1828 const abi_align = err_union_ty.abiAlignment(self.target.*);
1829 const err_ty = err_union_ty.errorUnionSet();
1830 const err_abi_size = mem.alignForwardGeneric(u32, @intCast(u32, err_ty.abiSize(self.target.*)), abi_align);
1847 const payload_off = errUnionPayloadOffset(payload_ty, self.target.*);
18311848 switch (operand) {
18321849 .stack_offset => |off| {
1833 const offset = off - @intCast(i32, err_abi_size);
1850 const offset = off - @intCast(i32, payload_off);
18341851 break :result MCValue{ .stack_offset = offset };
18351852 },
1836 .register => {
1853 .register => |reg| {
18371854 // TODO reuse operand
1838 const shift = @intCast(u6, err_abi_size * @sizeOf(usize));
1855 const lock = self.register_manager.lockRegAssumeUnused(reg);
1856 defer self.register_manager.unlockReg(lock);
18391857 const result = try self.copyToRegisterWithInstTracking(inst, err_union_ty, operand);
1840 try self.genShiftBinOpMir(.shr, Type.usize, result.register, .{ .immediate = shift });
1841 break :result MCValue{
1842 .register = registerAlias(result.register, @intCast(u32, payload_ty.abiSize(self.target.*))),
1843 };
1858 if (payload_off > 0) {
1859 const shift = @intCast(u6, payload_off * 8);
1860 try self.genShiftBinOpMir(.shr, err_union_ty, result.register, .{ .immediate = shift });
1861 } else {
1862 try self.truncateRegister(payload_ty, result.register);
1863 }
1864 break :result result;
18441865 },
18451866 else => return self.fail("TODO implement unwrap_err_payload for {}", .{operand}),
18461867 }
......@@ -1935,24 +1956,37 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
19351956/// T to E!T
19361957fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void {
19371958 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1959
19381960 if (self.liveness.isUnused(inst)) {
19391961 return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });
19401962 }
1963
19411964 const error_union_ty = self.air.getRefType(ty_op.ty);
19421965 const error_ty = error_union_ty.errorUnionSet();
19431966 const payload_ty = error_union_ty.errorUnionPayload();
19441967 const operand = try self.resolveInst(ty_op.operand);
1945 assert(payload_ty.hasRuntimeBits());
19461968
1947 const abi_size = @intCast(u32, error_union_ty.abiSize(self.target.*));
1948 const abi_align = error_union_ty.abiAlignment(self.target.*);
1949 const err_abi_size = @intCast(u32, error_ty.abiSize(self.target.*));
1950 const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align));
1951 const offset = mem.alignForwardGeneric(u32, err_abi_size, abi_align);
1952 try self.genSetStack(error_ty, stack_offset, .{ .immediate = 0 }, .{});
1953 try self.genSetStack(payload_ty, stack_offset - @intCast(i32, offset), operand, .{});
1969 const result: MCValue = result: {
1970 if (error_ty.errorSetCardinality() == .zero) {
1971 break :result operand;
1972 }
1973
1974 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
1975 break :result operand;
1976 }
1977
1978 const abi_size = @intCast(u32, error_union_ty.abiSize(self.target.*));
1979 const abi_align = error_union_ty.abiAlignment(self.target.*);
1980 const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align));
1981 const payload_off = errUnionPayloadOffset(payload_ty, self.target.*);
1982 const err_off = errUnionErrorOffset(payload_ty, self.target.*);
1983 try self.genSetStack(payload_ty, stack_offset - @intCast(i32, payload_off), operand, .{});
1984 try self.genSetStack(Type.anyerror, stack_offset - @intCast(i32, err_off), .{ .immediate = 0 }, .{});
1985
1986 break :result MCValue{ .stack_offset = stack_offset };
1987 };
19541988
1955 return self.finishAir(inst, .{ .stack_offset = stack_offset }, .{ ty_op.operand, .none, .none });
1989 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
19561990}
19571991
19581992/// E to E!T
......@@ -1962,19 +1996,22 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
19621996 return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });
19631997 }
19641998 const error_union_ty = self.air.getRefType(ty_op.ty);
1965 const error_ty = error_union_ty.errorUnionSet();
19661999 const payload_ty = error_union_ty.errorUnionPayload();
1967 const err = try self.resolveInst(ty_op.operand);
2000 const operand = try self.resolveInst(ty_op.operand);
2001
19682002 const result: MCValue = result: {
1969 if (!payload_ty.hasRuntimeBits()) break :result err;
2003 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
2004 break :result operand;
2005 }
19702006
19712007 const abi_size = @intCast(u32, error_union_ty.abiSize(self.target.*));
19722008 const abi_align = error_union_ty.abiAlignment(self.target.*);
1973 const err_abi_size = @intCast(u32, error_ty.abiSize(self.target.*));
19742009 const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align));
1975 const offset = mem.alignForwardGeneric(u32, err_abi_size, abi_align);
1976 try self.genSetStack(error_ty, stack_offset, err, .{});
1977 try self.genSetStack(payload_ty, stack_offset - @intCast(i32, offset), .undef, .{});
2010 const payload_off = errUnionPayloadOffset(payload_ty, self.target.*);
2011 const err_off = errUnionErrorOffset(payload_ty, self.target.*);
2012 try self.genSetStack(Type.anyerror, stack_offset - @intCast(i32, err_off), operand, .{});
2013 try self.genSetStack(payload_ty, stack_offset - @intCast(i32, payload_off), .undef, .{});
2014
19782015 break :result MCValue{ .stack_offset = stack_offset };
19792016 };
19802017
......@@ -2535,7 +2572,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
25352572 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
25362573 const elem_ty = self.air.typeOfIndex(inst);
25372574 const result: MCValue = result: {
2538 if (!elem_ty.hasRuntimeBits())
2575 if (!elem_ty.hasRuntimeBitsIgnoreComptime())
25392576 break :result MCValue.none;
25402577
25412578 const ptr = try self.resolveInst(ty_op.operand);
......@@ -4102,6 +4139,9 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void {
41024139 const operand = try self.resolveInst(un_op);
41034140 const ret_ty = self.fn_type.fnReturnType();
41044141 switch (self.ret_mcv) {
4142 .immediate => {
4143 assert(ret_ty.isError());
4144 },
41054145 .stack_offset => {
41064146 const reg = try self.copyToTmpRegister(Type.usize, self.ret_mcv);
41074147 const reg_lock = self.register_manager.lockRegAssumeUnused(reg);
......@@ -4134,6 +4174,9 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
41344174 const ptr_ty = self.air.typeOf(un_op);
41354175 const elem_ty = ptr_ty.elemType();
41364176 switch (self.ret_mcv) {
4177 .immediate => {
4178 assert(elem_ty.isError());
4179 },
41374180 .stack_offset => {
41384181 const reg = try self.copyToTmpRegister(Type.usize, self.ret_mcv);
41394182 const reg_lock = self.register_manager.lockRegAssumeUnused(reg);
......@@ -4377,7 +4420,6 @@ fn genVarDbgInfo(
43774420fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void {
43784421 switch (self.debug_output) {
43794422 .dwarf => |dw| {
4380 assert(ty.hasRuntimeBits());
43814423 const dbg_info = &dw.dbg_info;
43824424 const index = dbg_info.items.len;
43834425 try dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
......@@ -4604,7 +4646,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValu
46044646 const cmp_ty: Type = if (!ty.isPtrLikeOptional()) blk: {
46054647 var buf: Type.Payload.ElemType = undefined;
46064648 const payload_ty = ty.optionalChild(&buf);
4607 break :blk if (payload_ty.hasRuntimeBits()) Type.bool else ty;
4649 break :blk if (payload_ty.hasRuntimeBitsIgnoreComptime()) Type.bool else ty;
46084650 } else ty;
46094651
46104652 try self.genBinOpMir(.cmp, cmp_ty, operand, MCValue{ .immediate = 0 });
......@@ -4620,25 +4662,36 @@ fn isNonNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCV
46204662
46214663fn isErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue {
46224664 const err_type = ty.errorUnionSet();
4623 const payload_type = ty.errorUnionPayload();
4624 if (!err_type.hasRuntimeBits()) {
4665
4666 if (err_type.errorSetCardinality() == .zero) {
46254667 return MCValue{ .immediate = 0 }; // always false
46264668 }
46274669
46284670 try self.spillCompareFlagsIfOccupied();
46294671 self.compare_flags_inst = inst;
46304672
4631 if (!payload_type.hasRuntimeBits()) {
4632 if (err_type.abiSize(self.target.*) <= 8) {
4633 try self.genBinOpMir(.cmp, err_type, operand, MCValue{ .immediate = 0 });
4634 return MCValue{ .compare_flags_unsigned = .gt };
4635 } else {
4636 return self.fail("TODO isErr for errors with size larger than register size", .{});
4637 }
4638 } else {
4639 try self.genBinOpMir(.cmp, err_type, operand, MCValue{ .immediate = 0 });
4640 return MCValue{ .compare_flags_unsigned = .gt };
4673 const err_off = errUnionErrorOffset(ty.errorUnionPayload(), self.target.*);
4674 switch (operand) {
4675 .stack_offset => |off| {
4676 const offset = off - @intCast(i32, err_off);
4677 try self.genBinOpMir(.cmp, Type.anyerror, .{ .stack_offset = offset }, .{ .immediate = 0 });
4678 },
4679 .register => |reg| {
4680 const maybe_lock = self.register_manager.lockReg(reg);
4681 defer if (maybe_lock) |lock| self.register_manager.unlockReg(lock);
4682 const tmp_reg = try self.copyToTmpRegister(ty, operand);
4683 if (err_off > 0) {
4684 const shift = @intCast(u6, err_off * 8);
4685 try self.genShiftBinOpMir(.shr, ty, tmp_reg, .{ .immediate = shift });
4686 } else {
4687 try self.truncateRegister(Type.anyerror, tmp_reg);
4688 }
4689 try self.genBinOpMir(.cmp, Type.anyerror, .{ .register = tmp_reg }, .{ .immediate = 0 });
4690 },
4691 else => return self.fail("TODO implement isErr for {}", .{operand}),
46414692 }
4693
4694 return MCValue{ .compare_flags_unsigned = .gt };
46424695}
46434696
46444697fn isNonErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue {
......@@ -5461,6 +5514,21 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
54615514 .immediate => |x_big| {
54625515 const base_reg = opts.dest_stack_base orelse .rbp;
54635516 switch (abi_size) {
5517 0 => {
5518 assert(ty.isError());
5519 const payload = try self.addExtra(Mir.ImmPair{
5520 .dest_off = @bitCast(u32, -stack_offset),
5521 .operand = @truncate(u32, x_big),
5522 });
5523 _ = try self.addInst(.{
5524 .tag = .mov_mem_imm,
5525 .ops = Mir.Inst.Ops.encode(.{
5526 .reg1 = base_reg,
5527 .flags = 0b00,
5528 }),
5529 .data = .{ .payload = payload },
5530 });
5531 },
54645532 1, 2, 4 => {
54655533 const payload = try self.addExtra(Mir.ImmPair{
54665534 .dest_off = @bitCast(u32, -stack_offset),
......@@ -6643,7 +6711,7 @@ pub fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
66436711 const ref_int = @enumToInt(inst);
66446712 if (ref_int < Air.Inst.Ref.typed_value_map.len) {
66456713 const tv = Air.Inst.Ref.typed_value_map[ref_int];
6646 if (!tv.ty.hasRuntimeBits()) {
6714 if (!tv.ty.hasRuntimeBitsIgnoreComptime() and !tv.ty.isError()) {
66476715 return MCValue{ .none = {} };
66486716 }
66496717 return self.genTypedValue(tv);
......@@ -6651,7 +6719,7 @@ pub fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
66516719
66526720 // If the type has no codegen bits, no need to store it.
66536721 const inst_ty = self.air.typeOf(inst);
6654 if (!inst_ty.hasRuntimeBits())
6722 if (!inst_ty.hasRuntimeBitsIgnoreComptime() and !inst_ty.isError())
66556723 return MCValue{ .none = {} };
66566724
66576725 const inst_index = @intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len);
......@@ -6780,6 +6848,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
67806848 const target = self.target.*;
67816849
67826850 switch (typed_value.ty.zigTypeTag()) {
6851 .Void => return MCValue{ .none = {} },
67836852 .Pointer => switch (typed_value.ty.ptrSize()) {
67846853 .Slice => {},
67856854 else => {
......@@ -6841,26 +6910,35 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
68416910 }
68426911 },
68436912 .ErrorSet => {
6844 const err_name = typed_value.val.castTag(.@"error").?.data.name;
6845 const module = self.bin_file.options.module.?;
6846 const global_error_set = module.global_error_set;
6847 const error_index = global_error_set.get(err_name).?;
6848 return MCValue{ .immediate = error_index };
6913 switch (typed_value.val.tag()) {
6914 .@"error" => {
6915 const err_name = typed_value.val.castTag(.@"error").?.data.name;
6916 const module = self.bin_file.options.module.?;
6917 const global_error_set = module.global_error_set;
6918 const error_index = global_error_set.get(err_name).?;
6919 return MCValue{ .immediate = error_index };
6920 },
6921 else => {
6922 // In this case we are rendering an error union which has a 0 bits payload.
6923 return MCValue{ .immediate = 0 };
6924 },
6925 }
68496926 },
68506927 .ErrorUnion => {
68516928 const error_type = typed_value.ty.errorUnionSet();
68526929 const payload_type = typed_value.ty.errorUnionPayload();
68536930
6854 if (typed_value.val.castTag(.eu_payload)) |_| {
6855 if (!payload_type.hasRuntimeBits()) {
6856 // We use the error type directly as the type.
6857 return MCValue{ .immediate = 0 };
6858 }
6859 } else {
6860 if (!payload_type.hasRuntimeBits()) {
6861 // We use the error type directly as the type.
6862 return self.genTypedValue(.{ .ty = error_type, .val = typed_value.val });
6863 }
6931 if (error_type.errorSetCardinality() == .zero) {
6932 const payload_val = typed_value.val.castTag(.eu_payload).?.data;
6933 return self.genTypedValue(.{ .ty = payload_type, .val = payload_val });
6934 }
6935
6936 const is_pl = typed_value.val.errorUnionIsPayload();
6937
6938 if (!payload_type.hasRuntimeBitsIgnoreComptime()) {
6939 // We use the error type directly as the type.
6940 const err_val = if (!is_pl) typed_value.val else Value.initTag(.zero);
6941 return self.genTypedValue(.{ .ty = error_type, .val = err_val });
68646942 }
68656943 },
68666944
......@@ -6868,7 +6946,6 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
68686946 .ComptimeFloat => unreachable,
68696947 .Type => unreachable,
68706948 .EnumLiteral => unreachable,
6871 .Void => unreachable,
68726949 .NoReturn => unreachable,
68736950 .Undefined => unreachable,
68746951 .Null => unreachable,
......@@ -6922,11 +6999,14 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
69226999 // Return values
69237000 if (ret_ty.zigTypeTag() == .NoReturn) {
69247001 result.return_value = .{ .unreach = {} };
6925 } else if (!ret_ty.hasRuntimeBits()) {
7002 } else if (!ret_ty.hasRuntimeBitsIgnoreComptime() and !ret_ty.isError()) {
69267003 result.return_value = .{ .none = {} };
69277004 } else {
69287005 const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*));
6929 if (ret_ty_size <= 8) {
7006 if (ret_ty_size == 0) {
7007 assert(ret_ty.isError());
7008 result.return_value = .{ .immediate = 0 };
7009 } else if (ret_ty_size <= 8) {
69307010 const aliased_reg = registerAlias(c_abi_int_return_regs[0], ret_ty_size);
69317011 result.return_value = .{ .register = aliased_reg };
69327012 } else {
src/codegen.zig+67-10
......@@ -442,7 +442,10 @@ pub fn generateSymbol(
442442 .Int => {
443443 const info = typed_value.ty.intInfo(target);
444444 if (info.bits <= 8) {
445 const x = @intCast(u8, typed_value.val.toUnsignedInt(target));
445 const x: u8 = switch (info.signedness) {
446 .unsigned => @intCast(u8, typed_value.val.toUnsignedInt(target)),
447 .signed => @bitCast(u8, @intCast(i8, typed_value.val.toSignedInt())),
448 };
446449 try code.append(x);
447450 return Result{ .appended = {} };
448451 }
......@@ -654,7 +657,7 @@ pub fn generateSymbol(
654657 return Result{ .appended = {} };
655658 }
656659
657 if (typed_value.ty.isPtrLikeOptional()) {
660 if (typed_value.ty.optionalReprIsPayload()) {
658661 if (typed_value.val.castTag(.opt_payload)) |payload| {
659662 switch (try generateSymbol(bin_file, src_loc, .{
660663 .ty = payload_type,
......@@ -702,16 +705,50 @@ pub fn generateSymbol(
702705 .ErrorUnion => {
703706 const error_ty = typed_value.ty.errorUnionSet();
704707 const payload_ty = typed_value.ty.errorUnionPayload();
708
709 if (error_ty.errorSetCardinality() == .zero) {
710 const payload_val = typed_value.val.castTag(.eu_payload).?.data;
711 return generateSymbol(bin_file, src_loc, .{
712 .ty = payload_ty,
713 .val = payload_val,
714 }, code, debug_output, reloc_info);
715 }
716
705717 const is_payload = typed_value.val.errorUnionIsPayload();
706718
719 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
720 const err_val = if (is_payload) Value.initTag(.zero) else typed_value.val;
721 return generateSymbol(bin_file, src_loc, .{
722 .ty = error_ty,
723 .val = err_val,
724 }, code, debug_output, reloc_info);
725 }
726
727 const payload_align = payload_ty.abiAlignment(target);
728 const error_align = Type.anyerror.abiAlignment(target);
707729 const abi_align = typed_value.ty.abiAlignment(target);
708730
731 // error value first when its type is larger than the error union's payload
732 if (error_align > payload_align) {
733 switch (try generateSymbol(bin_file, src_loc, .{
734 .ty = error_ty,
735 .val = if (is_payload) Value.initTag(.zero) else typed_value.val,
736 }, code, debug_output, reloc_info)) {
737 .appended => {},
738 .externally_managed => |external_slice| {
739 code.appendSliceAssumeCapacity(external_slice);
740 },
741 .fail => |em| return Result{ .fail = em },
742 }
743 }
744
745 // emit payload part of the error union
709746 {
710 const error_val = if (!is_payload) typed_value.val else Value.initTag(.zero);
711747 const begin = code.items.len;
748 const payload_val = if (typed_value.val.castTag(.eu_payload)) |val| val.data else Value.initTag(.undef);
712749 switch (try generateSymbol(bin_file, src_loc, .{
713 .ty = error_ty,
714 .val = error_val,
750 .ty = payload_ty,
751 .val = payload_val,
715752 }, code, debug_output, reloc_info)) {
716753 .appended => {},
717754 .externally_managed => |external_slice| {
......@@ -728,12 +765,12 @@ pub fn generateSymbol(
728765 }
729766 }
730767
731 if (payload_ty.hasRuntimeBits()) {
768 // Payload size is larger than error set, so emit our error set last
769 if (error_align <= payload_align) {
732770 const begin = code.items.len;
733 const payload_val = if (typed_value.val.castTag(.eu_payload)) |val| val.data else Value.initTag(.undef);
734771 switch (try generateSymbol(bin_file, src_loc, .{
735 .ty = payload_ty,
736 .val = payload_val,
772 .ty = error_ty,
773 .val = if (is_payload) Value.initTag(.zero) else typed_value.val,
737774 }, code, debug_output, reloc_info)) {
738775 .appended => {},
739776 .externally_managed => |external_slice| {
......@@ -760,7 +797,7 @@ pub fn generateSymbol(
760797 try code.writer().writeInt(u32, kv.value, endian);
761798 },
762799 else => {
763 try code.writer().writeByteNTimes(0, @intCast(usize, typed_value.ty.abiSize(target)));
800 try code.writer().writeByteNTimes(0, @intCast(usize, Type.anyerror.abiSize(target)));
764801 },
765802 }
766803 return Result{ .appended = {} };
......@@ -853,3 +890,23 @@ fn lowerDeclRef(
853890
854891 return Result{ .appended = {} };
855892}
893
894pub fn errUnionPayloadOffset(payload_ty: Type, target: std.Target) u64 {
895 const payload_align = payload_ty.abiAlignment(target);
896 const error_align = Type.anyerror.abiAlignment(target);
897 if (payload_align >= error_align) {
898 return 0;
899 } else {
900 return mem.alignForwardGeneric(u64, Type.anyerror.abiSize(target), payload_align);
901 }
902}
903
904pub fn errUnionErrorOffset(payload_ty: Type, target: std.Target) u64 {
905 const payload_align = payload_ty.abiAlignment(target);
906 const error_align = Type.anyerror.abiAlignment(target);
907 if (payload_align >= error_align) {
908 return mem.alignForwardGeneric(u64, payload_ty.abiSize(target), error_align);
909 } else {
910 return 0;
911 }
912}
src/codegen/c.zig+177-85
......@@ -711,21 +711,24 @@ pub const DeclGen = struct {
711711 .Bool => return writer.print("{}", .{val.toBool()}),
712712 .Optional => {
713713 var opt_buf: Type.Payload.ElemType = undefined;
714 const payload_type = ty.optionalChild(&opt_buf);
715 if (ty.isPtrLikeOptional()) {
716 return dg.renderValue(writer, payload_type, val, location);
717 }
718 if (payload_type.abiSize(target) == 0) {
714 const payload_ty = ty.optionalChild(&opt_buf);
715
716 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
719717 const is_null = val.castTag(.opt_payload) == null;
720718 return writer.print("{}", .{is_null});
721719 }
720
721 if (ty.optionalReprIsPayload()) {
722 return dg.renderValue(writer, payload_ty, val, location);
723 }
724
722725 try writer.writeByte('(');
723726 try dg.renderTypecast(writer, ty);
724727 try writer.writeAll("){");
725728 if (val.castTag(.opt_payload)) |pl| {
726729 const payload_val = pl.data;
727730 try writer.writeAll(" .is_null = false, .payload = ");
728 try dg.renderValue(writer, payload_type, payload_val, location);
731 try dg.renderValue(writer, payload_ty, payload_val, location);
729732 try writer.writeAll(" }");
730733 } else {
731734 try writer.writeAll(" .is_null = true }");
......@@ -749,6 +752,12 @@ pub const DeclGen = struct {
749752 const error_type = ty.errorUnionSet();
750753 const payload_type = ty.errorUnionPayload();
751754
755 if (error_type.errorSetCardinality() == .zero) {
756 // We use the payload directly as the type.
757 const payload_val = val.castTag(.eu_payload).?.data;
758 return dg.renderValue(writer, payload_type, payload_val, location);
759 }
760
752761 if (!payload_type.hasRuntimeBits()) {
753762 // We use the error type directly as the type.
754763 const err_val = if (val.errorUnionIsPayload()) Value.initTag(.zero) else val;
......@@ -894,10 +903,12 @@ pub const DeclGen = struct {
894903 try w.writeAll("ZIG_COLD ");
895904 }
896905 }
897 const return_ty = dg.decl.ty.fnReturnType();
898 if (return_ty.hasRuntimeBits()) {
899 try dg.renderType(w, return_ty);
900 } else if (return_ty.zigTypeTag() == .NoReturn) {
906 const fn_info = dg.decl.ty.fnInfo();
907 if (fn_info.return_type.hasRuntimeBits()) {
908 try dg.renderType(w, fn_info.return_type);
909 } else if (fn_info.return_type.isError()) {
910 try dg.renderType(w, Type.anyerror);
911 } else if (fn_info.return_type.zigTypeTag() == .NoReturn) {
901912 try w.writeAll("zig_noreturn void");
902913 } else {
903914 try w.writeAll("void");
......@@ -905,22 +916,19 @@ pub const DeclGen = struct {
905916 try w.writeAll(" ");
906917 try dg.renderDeclName(w, dg.decl_index);
907918 try w.writeAll("(");
908 const param_len = dg.decl.ty.fnParamLen();
909919
910 var index: usize = 0;
911920 var params_written: usize = 0;
912 while (index < param_len) : (index += 1) {
913 const param_type = dg.decl.ty.fnParamType(index);
921 for (fn_info.param_types) |param_type, index| {
914922 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;
915923 if (params_written > 0) {
916924 try w.writeAll(", ");
917925 }
918926 const name = CValue{ .arg = index };
919 try dg.renderTypeAndName(w, dg.decl.ty.fnParamType(index), name, .Mut, 0);
927 try dg.renderTypeAndName(w, param_type, name, .Mut, 0);
920928 params_written += 1;
921929 }
922930
923 if (dg.decl.ty.fnIsVarArgs()) {
931 if (fn_info.is_var_args) {
924932 if (params_written != 0) try w.writeAll(", ");
925933 try w.writeAll("...");
926934 } else if (params_written == 0) {
......@@ -1156,26 +1164,36 @@ pub const DeclGen = struct {
11561164 }
11571165
11581166 fn renderErrorUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
1159 const child_type = t.errorUnionPayload();
1160 const err_set_type = t.errorUnionSet();
1167 const payload_ty = t.errorUnionPayload();
1168 const error_ty = t.errorUnionSet();
11611169
11621170 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
11631171 defer buffer.deinit();
11641172 const bw = buffer.writer();
11651173
1166 try bw.writeAll("typedef struct { ");
11671174 const payload_name = CValue{ .bytes = "payload" };
1168 try dg.renderTypeAndName(bw, child_type, payload_name, .Mut, 0);
1169 try bw.writeAll("; uint16_t error; } ");
1175 const target = dg.module.getTarget();
1176 const payload_align = payload_ty.abiAlignment(target);
1177 const error_align = Type.anyerror.abiAlignment(target);
1178 if (error_align > payload_align) {
1179 try bw.writeAll("typedef struct { ");
1180 try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0);
1181 try bw.writeAll("; uint16_t error; } ");
1182 } else {
1183 try bw.writeAll("typedef struct { uint16_t error; ");
1184 try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0);
1185 try bw.writeAll("; } ");
1186 }
1187
11701188 const name_index = buffer.items.len;
1171 if (err_set_type.castTag(.error_set_inferred)) |inf_err_set_payload| {
1189 if (error_ty.castTag(.error_set_inferred)) |inf_err_set_payload| {
11721190 const func = inf_err_set_payload.data.func;
11731191 try bw.writeAll("zig_E_");
11741192 try dg.renderDeclName(bw, func.owner_decl);
11751193 try bw.writeAll(";\n");
11761194 } else {
11771195 try bw.print("zig_E_{s}_{s};\n", .{
1178 typeToCIdentifier(err_set_type, dg.module), typeToCIdentifier(child_type, dg.module),
1196 typeToCIdentifier(error_ty, dg.module), typeToCIdentifier(payload_ty, dg.module),
11791197 });
11801198 }
11811199
......@@ -1345,12 +1363,12 @@ pub const DeclGen = struct {
13451363 var opt_buf: Type.Payload.ElemType = undefined;
13461364 const child_type = t.optionalChild(&opt_buf);
13471365
1348 if (t.isPtrLikeOptional()) {
1349 return dg.renderType(w, child_type);
1366 if (!child_type.hasRuntimeBitsIgnoreComptime()) {
1367 return w.writeAll("bool");
13501368 }
13511369
1352 if (child_type.abiSize(target) == 0) {
1353 return w.writeAll("bool");
1370 if (t.optionalReprIsPayload()) {
1371 return dg.renderType(w, child_type);
13541372 }
13551373
13561374 const name = dg.getTypedefName(t) orelse
......@@ -1359,12 +1377,19 @@ pub const DeclGen = struct {
13591377 return w.writeAll(name);
13601378 },
13611379 .ErrorSet => {
1362 comptime assert(Type.initTag(.anyerror).abiSize(builtin.target) == 2);
1380 comptime assert(Type.anyerror.abiSize(builtin.target) == 2);
13631381 return w.writeAll("uint16_t");
13641382 },
13651383 .ErrorUnion => {
1366 if (t.errorUnionPayload().abiSize(target) == 0) {
1367 return dg.renderType(w, t.errorUnionSet());
1384 const error_ty = t.errorUnionSet();
1385 const payload_ty = t.errorUnionPayload();
1386
1387 if (error_ty.errorSetCardinality() == .zero) {
1388 return dg.renderType(w, payload_ty);
1389 }
1390
1391 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
1392 return dg.renderType(w, Type.anyerror);
13681393 }
13691394
13701395 const name = dg.getTypedefName(t) orelse
......@@ -1794,8 +1819,9 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
17941819 .not => try airNot (f, inst),
17951820
17961821 .optional_payload => try airOptionalPayload(f, inst),
1797 .optional_payload_ptr => try airOptionalPayload(f, inst),
1822 .optional_payload_ptr => try airOptionalPayloadPtr(f, inst),
17981823 .optional_payload_ptr_set => try airOptionalPayloadPtrSet(f, inst),
1824 .wrap_optional => try airWrapOptional(f, inst),
17991825
18001826 .is_err => try airIsErr(f, inst, false, "!="),
18011827 .is_non_err => try airIsErr(f, inst, false, "=="),
......@@ -1824,7 +1850,6 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
18241850 .cond_br => try airCondBr(f, inst),
18251851 .br => try airBr(f, inst),
18261852 .switch_br => try airSwitchBr(f, inst),
1827 .wrap_optional => try airWrapOptional(f, inst),
18281853 .struct_field_ptr => try airStructFieldPtr(f, inst),
18291854 .array_to_slice => try airArrayToSlice(f, inst),
18301855 .cmpxchg_weak => try airCmpxchg(f, inst, "weak"),
......@@ -1901,8 +1926,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
19011926 .array_elem_val => try airArrayElemVal(f, inst),
19021927
19031928 .unwrap_errunion_payload => try airUnwrapErrUnionPay(f, inst, ""),
1904 .unwrap_errunion_err => try airUnwrapErrUnionErr(f, inst),
19051929 .unwrap_errunion_payload_ptr => try airUnwrapErrUnionPay(f, inst, "&"),
1930 .unwrap_errunion_err => try airUnwrapErrUnionErr(f, inst),
19061931 .unwrap_errunion_err_ptr => try airUnwrapErrUnionErr(f, inst),
19071932 .wrap_errunion_payload => try airWrapErrUnionPay(f, inst),
19081933 .wrap_errunion_err => try airWrapErrUnionErr(f, inst),
......@@ -2120,11 +2145,14 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
21202145fn airRet(f: *Function, inst: Air.Inst.Index) !CValue {
21212146 const un_op = f.air.instructions.items(.data)[inst].un_op;
21222147 const writer = f.object.writer();
2123 if (f.air.typeOf(un_op).isFnOrHasRuntimeBitsIgnoreComptime()) {
2148 const ret_ty = f.air.typeOf(un_op);
2149 if (ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) {
21242150 const operand = try f.resolveInst(un_op);
21252151 try writer.writeAll("return ");
21262152 try f.writeCValue(writer, operand);
21272153 try writer.writeAll(";\n");
2154 } else if (ret_ty.isError()) {
2155 try writer.writeAll("return 0;");
21282156 } else {
21292157 try writer.writeAll("return;\n");
21302158 }
......@@ -2136,13 +2164,16 @@ fn airRetLoad(f: *Function, inst: Air.Inst.Index) !CValue {
21362164 const writer = f.object.writer();
21372165 const ptr_ty = f.air.typeOf(un_op);
21382166 const ret_ty = ptr_ty.childType();
2139 if (!ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) {
2167 if (ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) {
2168 const ptr = try f.resolveInst(un_op);
2169 try writer.writeAll("return *");
2170 try f.writeCValue(writer, ptr);
2171 try writer.writeAll(";\n");
2172 } else if (ret_ty.isError()) {
2173 try writer.writeAll("return 0;\n");
2174 } else {
21402175 try writer.writeAll("return;\n");
21412176 }
2142 const ptr = try f.resolveInst(un_op);
2143 try writer.writeAll("return *");
2144 try f.writeCValue(writer, ptr);
2145 try writer.writeAll(";\n");
21462177 return CValue.none;
21472178}
21482179
......@@ -2713,19 +2744,20 @@ fn airCall(
27132744 .Pointer => callee_ty.childType(),
27142745 else => unreachable,
27152746 };
2716 const ret_ty = fn_ty.fnReturnType();
2717 const unused_result = f.liveness.isUnused(inst);
27182747 const writer = f.object.writer();
27192748
2720 var result_local: CValue = .none;
2721 if (unused_result) {
2722 if (ret_ty.hasRuntimeBits()) {
2723 try writer.print("(void)", .{});
2749 const result_local: CValue = r: {
2750 if (f.liveness.isUnused(inst)) {
2751 if (loweredFnRetTyHasBits(fn_ty)) {
2752 try writer.print("(void)", .{});
2753 }
2754 break :r .none;
2755 } else {
2756 const local = try f.allocLocal(fn_ty.fnReturnType(), .Const);
2757 try writer.writeAll(" = ");
2758 break :r local;
27242759 }
2725 } else {
2726 result_local = try f.allocLocal(ret_ty, .Const);
2727 try writer.writeAll(" = ");
2728 }
2760 };
27292761
27302762 callee: {
27312763 known: {
......@@ -3116,7 +3148,6 @@ fn airIsNull(
31163148 const un_op = f.air.instructions.items(.data)[inst].un_op;
31173149 const writer = f.object.writer();
31183150 const operand = try f.resolveInst(un_op);
3119 const target = f.object.dg.module.getTarget();
31203151
31213152 const local = try f.allocLocal(Type.initTag(.bool), .Const);
31223153 try writer.writeAll(" = (");
......@@ -3124,16 +3155,18 @@ fn airIsNull(
31243155
31253156 const ty = f.air.typeOf(un_op);
31263157 var opt_buf: Type.Payload.ElemType = undefined;
3127 const payload_type = if (ty.zigTypeTag() == .Pointer)
3158 const payload_ty = if (ty.zigTypeTag() == .Pointer)
31283159 ty.childType().optionalChild(&opt_buf)
31293160 else
31303161 ty.optionalChild(&opt_buf);
31313162
3132 if (ty.isPtrLikeOptional()) {
3163 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
3164 try writer.print("){s} {s} true;\n", .{ deref_suffix, operator });
3165 } else if (ty.isPtrLikeOptional()) {
31333166 // operand is a regular pointer, test `operand !=/== NULL`
31343167 try writer.print("){s} {s} NULL;\n", .{ deref_suffix, operator });
3135 } else if (payload_type.abiSize(target) == 0) {
3136 try writer.print("){s} {s} true;\n", .{ deref_suffix, operator });
3168 } else if (payload_ty.zigTypeTag() == .ErrorSet) {
3169 try writer.print("){s} {s} 0;\n", .{ deref_suffix, operator });
31373170 } else {
31383171 try writer.print("){s}.is_null {s} true;\n", .{ deref_suffix, operator });
31393172 }
......@@ -3141,34 +3174,58 @@ fn airIsNull(
31413174}
31423175
31433176fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {
3144 if (f.liveness.isUnused(inst))
3177 if (f.liveness.isUnused(inst)) return CValue.none;
3178
3179 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
3180 const writer = f.object.writer();
3181 const operand = try f.resolveInst(ty_op.operand);
3182 const opt_ty = f.air.typeOf(ty_op.operand);
3183
3184 var buf: Type.Payload.ElemType = undefined;
3185 const payload_ty = opt_ty.optionalChild(&buf);
3186
3187 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
31453188 return CValue.none;
3189 }
3190
3191 if (opt_ty.optionalReprIsPayload()) {
3192 return operand;
3193 }
3194
3195 const inst_ty = f.air.typeOfIndex(inst);
3196 const local = try f.allocLocal(inst_ty, .Const);
3197 try writer.writeAll(" = (");
3198 try f.writeCValue(writer, operand);
3199 try writer.writeAll(").payload;\n");
3200 return local;
3201}
3202
3203fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue {
3204 if (f.liveness.isUnused(inst)) return CValue.none;
31463205
31473206 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
31483207 const writer = f.object.writer();
31493208 const operand = try f.resolveInst(ty_op.operand);
3150 const operand_ty = f.air.typeOf(ty_op.operand);
3209 const ptr_ty = f.air.typeOf(ty_op.operand);
3210 const opt_ty = ptr_ty.childType();
3211 var buf: Type.Payload.ElemType = undefined;
3212 const payload_ty = opt_ty.optionalChild(&buf);
31513213
3152 const opt_ty = if (operand_ty.zigTypeTag() == .Pointer)
3153 operand_ty.elemType()
3154 else
3155 operand_ty;
3214 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
3215 return operand;
3216 }
31563217
3157 if (opt_ty.isPtrLikeOptional()) {
3218 if (opt_ty.optionalReprIsPayload()) {
31583219 // the operand is just a regular pointer, no need to do anything special.
31593220 // *?*T -> **T and ?*T -> *T are **T -> **T and *T -> *T in C
31603221 return operand;
31613222 }
31623223
31633224 const inst_ty = f.air.typeOfIndex(inst);
3164 const maybe_deref = if (operand_ty.zigTypeTag() == .Pointer) "->" else ".";
3165 const maybe_addrof = if (inst_ty.zigTypeTag() == .Pointer) "&" else "";
3166
31673225 const local = try f.allocLocal(inst_ty, .Const);
3168 try writer.print(" = {s}(", .{maybe_addrof});
3226 try writer.writeAll(" = &(");
31693227 try f.writeCValue(writer, operand);
3170
3171 try writer.print("){s}payload;\n", .{maybe_deref});
3228 try writer.writeAll(")->payload;\n");
31723229 return local;
31733230}
31743231
......@@ -3180,7 +3237,7 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
31803237
31813238 const opt_ty = operand_ty.elemType();
31823239
3183 if (opt_ty.isPtrLikeOptional()) {
3240 if (opt_ty.optionalReprIsPayload()) {
31843241 // The payload and the optional are the same value.
31853242 // Setting to non-null will be done when the payload is set.
31863243 return operand;
......@@ -3307,7 +3364,8 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
33073364 return local;
33083365}
33093366
3310// *(E!T) -> E NOT *E
3367/// *(E!T) -> E
3368/// Note that the result is never a pointer.
33113369fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
33123370 if (f.liveness.isUnused(inst))
33133371 return CValue.none;
......@@ -3319,7 +3377,11 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
33193377 const operand_ty = f.air.typeOf(ty_op.operand);
33203378
33213379 if (operand_ty.zigTypeTag() == .Pointer) {
3322 if (!operand_ty.childType().errorUnionPayload().hasRuntimeBits()) {
3380 const err_union_ty = operand_ty.childType();
3381 if (err_union_ty.errorUnionSet().errorSetCardinality() == .zero) {
3382 return CValue{ .bytes = "0" };
3383 }
3384 if (!err_union_ty.errorUnionPayload().hasRuntimeBits()) {
33233385 return operand;
33243386 }
33253387 const local = try f.allocLocal(inst_ty, .Const);
......@@ -3328,6 +3390,9 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
33283390 try writer.writeAll(";\n");
33293391 return local;
33303392 }
3393 if (operand_ty.errorUnionSet().errorSetCardinality() == .zero) {
3394 return CValue{ .bytes = "0" };
3395 }
33313396 if (!operand_ty.errorUnionPayload().hasRuntimeBits()) {
33323397 return operand;
33333398 }
......@@ -3343,7 +3408,7 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
33433408 return local;
33443409}
33453410
3346fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: []const u8) !CValue {
3411fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: [*:0]const u8) !CValue {
33473412 if (f.liveness.isUnused(inst))
33483413 return CValue.none;
33493414
......@@ -3351,17 +3416,19 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: []cons
33513416 const writer = f.object.writer();
33523417 const operand = try f.resolveInst(ty_op.operand);
33533418 const operand_ty = f.air.typeOf(ty_op.operand);
3419 const operand_is_ptr = operand_ty.zigTypeTag() == .Pointer;
3420 const error_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty;
3421
3422 if (error_union_ty.errorUnionSet().errorSetCardinality() == .zero) {
3423 return operand;
3424 }
33543425
3355 const error_union_ty = if (operand_ty.zigTypeTag() == .Pointer)
3356 operand_ty.childType()
3357 else
3358 operand_ty;
33593426 if (!error_union_ty.errorUnionPayload().hasRuntimeBits()) {
33603427 return CValue.none;
33613428 }
33623429
33633430 const inst_ty = f.air.typeOfIndex(inst);
3364 const maybe_deref = if (operand_ty.zigTypeTag() == .Pointer) "->" else ".";
3431 const maybe_deref = if (operand_is_ptr) "->" else ".";
33653432
33663433 const local = try f.allocLocal(inst_ty, .Const);
33673434 try writer.print(" = {s}(", .{maybe_addrof});
......@@ -3380,8 +3447,7 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {
33803447 const operand = try f.resolveInst(ty_op.operand);
33813448
33823449 const inst_ty = f.air.typeOfIndex(inst);
3383 if (inst_ty.isPtrLikeOptional()) {
3384 // the operand is just a regular pointer, no need to do anything special.
3450 if (inst_ty.optionalReprIsPayload()) {
33853451 return operand;
33863452 }
33873453
......@@ -3421,6 +3487,11 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
34213487 const error_ty = error_union_ty.errorUnionSet();
34223488 const payload_ty = error_union_ty.errorUnionPayload();
34233489
3490 if (error_ty.errorSetCardinality() == .zero) {
3491 // TODO: write undefined bytes through the pointer here
3492 return operand;
3493 }
3494
34243495 // First, set the non-error value.
34253496 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
34263497 try f.writeCValueDeref(writer, operand);
......@@ -3464,6 +3535,9 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
34643535 const operand = try f.resolveInst(ty_op.operand);
34653536
34663537 const inst_ty = f.air.typeOfIndex(inst);
3538 if (inst_ty.errorUnionSet().errorSetCardinality() == .zero) {
3539 return operand;
3540 }
34673541 const local = try f.allocLocal(inst_ty, .Const);
34683542 try writer.writeAll(" = { .error = 0, .payload = ");
34693543 try f.writeCValue(writer, operand);
......@@ -3486,16 +3560,23 @@ fn airIsErr(
34863560 const operand_ty = f.air.typeOf(un_op);
34873561 const local = try f.allocLocal(Type.initTag(.bool), .Const);
34883562 const payload_ty = operand_ty.errorUnionPayload();
3563 const error_ty = operand_ty.errorUnionSet();
3564
34893565 try writer.writeAll(" = ");
3490 if (is_ptr) {
3491 try f.writeCValueDeref(writer, operand);
3566
3567 if (error_ty.errorSetCardinality() == .zero) {
3568 try writer.print("0 {s} 0;\n", .{op_str});
34923569 } else {
3493 try f.writeCValue(writer, operand);
3494 }
3495 if (payload_ty.hasRuntimeBits()) {
3496 try writer.writeAll(".error");
3570 if (is_ptr) {
3571 try f.writeCValueDeref(writer, operand);
3572 } else {
3573 try f.writeCValue(writer, operand);
3574 }
3575 if (payload_ty.hasRuntimeBits()) {
3576 try writer.writeAll(".error");
3577 }
3578 try writer.print(" {s} 0;\n", .{op_str});
34973579 }
3498 try writer.print(" {s} 0;\n", .{op_str});
34993580 return local;
35003581}
35013582
......@@ -4129,3 +4210,14 @@ fn intMin(ty: Type, target: std.Target, buf: []u8) []const u8 {
41294210 },
41304211 }
41314212}
4213
4214fn loweredFnRetTyHasBits(fn_ty: Type) bool {
4215 const ret_ty = fn_ty.fnReturnType();
4216 if (ret_ty.hasRuntimeBitsIgnoreComptime()) {
4217 return true;
4218 }
4219 if (ret_ty.isError()) {
4220 return true;
4221 }
4222 return false;
4223}
src/codegen/llvm.zig+396-301
......@@ -745,7 +745,7 @@ pub const Object = struct {
745745 const param = llvm_func.getParam(llvm_arg_i);
746746 llvm_arg_i += 1;
747747
748 const param_llvm_ty = try dg.llvmType(param_ty);
748 const param_llvm_ty = try dg.lowerType(param_ty);
749749 const abi_size = @intCast(c_uint, param_ty.abiSize(target));
750750 const int_llvm_ty = dg.context.intType(abi_size * 8);
751751 const int_ptr_llvm_ty = int_llvm_ty.pointerType(0);
......@@ -775,7 +775,7 @@ pub const Object = struct {
775775 .Struct => {
776776 const fields = param_ty.structFields().values();
777777 if (is_by_ref) {
778 const param_llvm_ty = try dg.llvmType(param_ty);
778 const param_llvm_ty = try dg.lowerType(param_ty);
779779 const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty);
780780 arg_ptr.setAlignment(param_ty.abiAlignment(target));
781781
......@@ -1390,7 +1390,7 @@ pub const Object = struct {
13901390 gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_ty);
13911391 return di_ty;
13921392 }
1393 if (ty.isPtrLikeOptional()) {
1393 if (ty.optionalReprIsPayload()) {
13941394 const ptr_di_ty = try o.lowerDebugType(child_ty, resolve);
13951395 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
13961396 try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(ptr_di_ty), .{ .mod = o.module });
......@@ -1470,10 +1470,25 @@ pub const Object = struct {
14701470 return full_di_ty;
14711471 },
14721472 .ErrorUnion => {
1473 const err_set_ty = ty.errorUnionSet();
14741473 const payload_ty = ty.errorUnionPayload();
1474 switch (ty.errorUnionSet().errorSetCardinality()) {
1475 .zero => {
1476 const payload_di_ty = try o.lowerDebugType(payload_ty, .full);
1477 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
1478 try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(payload_di_ty), .{ .mod = o.module });
1479 return payload_di_ty;
1480 },
1481 .one => {
1482 if (payload_ty.isNoReturn()) {
1483 const di_type = dib.createBasicType("void", 0, DW.ATE.signed);
1484 gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_type);
1485 return di_type;
1486 }
1487 },
1488 .many => {},
1489 }
14751490 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
1476 const err_set_di_ty = try o.lowerDebugType(err_set_ty, .full);
1491 const err_set_di_ty = try o.lowerDebugType(Type.anyerror, .full);
14771492 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
14781493 try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(err_set_di_ty), .{ .mod = o.module });
14791494 return err_set_di_ty;
......@@ -1496,56 +1511,51 @@ pub const Object = struct {
14961511 break :blk fwd_decl;
14971512 };
14981513
1499 const err_set_size = err_set_ty.abiSize(target);
1500 const err_set_align = err_set_ty.abiAlignment(target);
1514 const error_size = Type.anyerror.abiSize(target);
1515 const error_align = Type.anyerror.abiAlignment(target);
15011516 const payload_size = payload_ty.abiSize(target);
15021517 const payload_align = payload_ty.abiAlignment(target);
15031518
1504 var offset: u64 = 0;
1505 offset += err_set_size;
1506 offset = std.mem.alignForwardGeneric(u64, offset, payload_align);
1507 const payload_offset = offset;
1508
1509 var len: u8 = 2;
1510 var fields: [3]*llvm.DIType = .{
1511 dib.createMemberType(
1512 fwd_decl.toScope(),
1513 "tag",
1514 di_file,
1515 line,
1516 err_set_size * 8, // size in bits
1517 err_set_align * 8, // align in bits
1518 0, // offset in bits
1519 0, // flags
1520 try o.lowerDebugType(err_set_ty, .full),
1521 ),
1522 dib.createMemberType(
1523 fwd_decl.toScope(),
1524 "value",
1525 di_file,
1526 line,
1527 payload_size * 8, // size in bits
1528 payload_align * 8, // align in bits
1529 payload_offset * 8, // offset in bits
1530 0, // flags
1531 try o.lowerDebugType(payload_ty, .full),
1532 ),
1533 undefined,
1534 };
1535
1536 const error_size = Type.anyerror.abiSize(target);
1537 if (payload_align > error_size) {
1538 fields[2] = fields[1];
1539 const pad_len = @intCast(u32, payload_align - error_size);
1540 fields[1] = dib.createArrayType(
1541 pad_len * 8,
1542 8,
1543 try o.lowerDebugType(Type.u8, .full),
1544 @intCast(c_int, pad_len),
1545 );
1546 len += 1;
1519 var error_index: u32 = undefined;
1520 var payload_index: u32 = undefined;
1521 var error_offset: u64 = undefined;
1522 var payload_offset: u64 = undefined;
1523 if (error_align > payload_align) {
1524 error_index = 0;
1525 payload_index = 1;
1526 error_offset = 0;
1527 payload_offset = std.mem.alignForwardGeneric(u64, error_size, payload_align);
1528 } else {
1529 payload_index = 0;
1530 error_index = 1;
1531 payload_offset = 0;
1532 error_offset = std.mem.alignForwardGeneric(u64, payload_size, error_align);
15471533 }
15481534
1535 var fields: [2]*llvm.DIType = undefined;
1536 fields[error_index] = dib.createMemberType(
1537 fwd_decl.toScope(),
1538 "tag",
1539 di_file,
1540 line,
1541 error_size * 8, // size in bits
1542 error_align * 8, // align in bits
1543 error_offset * 8, // offset in bits
1544 0, // flags
1545 try o.lowerDebugType(Type.anyerror, .full),
1546 );
1547 fields[payload_index] = dib.createMemberType(
1548 fwd_decl.toScope(),
1549 "value",
1550 di_file,
1551 line,
1552 payload_size * 8, // size in bits
1553 payload_align * 8, // align in bits
1554 payload_offset * 8, // offset in bits
1555 0, // flags
1556 try o.lowerDebugType(payload_ty, .full),
1557 );
1558
15491559 const full_di_ty = dib.createStructType(
15501560 compile_unit_scope,
15511561 name.ptr,
......@@ -1556,7 +1566,7 @@ pub const Object = struct {
15561566 0, // flags
15571567 null, // derived from
15581568 &fields,
1559 len,
1569 fields.len,
15601570 0, // run time lang
15611571 null, // vtable holder
15621572 "", // unique id
......@@ -2094,7 +2104,7 @@ pub const DeclGen = struct {
20942104 break :init_val decl.val;
20952105 };
20962106 if (init_val.tag() != .unreachable_value) {
2097 const llvm_init = try dg.genTypedValue(.{ .ty = decl.ty, .val = init_val });
2107 const llvm_init = try dg.lowerValue(.{ .ty = decl.ty, .val = init_val });
20982108 if (global.globalGetValueType() == llvm_init.typeOf()) {
20992109 global.setInitializer(llvm_init);
21002110 } else {
......@@ -2165,7 +2175,7 @@ pub const DeclGen = struct {
21652175 const target = dg.module.getTarget();
21662176 const sret = firstParamSRet(fn_info, target);
21672177
2168 const fn_type = try dg.llvmType(zig_fn_type);
2178 const fn_type = try dg.lowerType(zig_fn_type);
21692179
21702180 const fqn = try decl.getFullyQualifiedName(dg.module);
21712181 defer dg.gpa.free(fqn);
......@@ -2192,7 +2202,7 @@ pub const DeclGen = struct {
21922202 dg.addArgAttr(llvm_fn, 0, "nonnull"); // Sret pointers must not be address 0
21932203 dg.addArgAttr(llvm_fn, 0, "noalias");
21942204
2195 const raw_llvm_ret_ty = try dg.llvmType(fn_info.return_type);
2205 const raw_llvm_ret_ty = try dg.lowerType(fn_info.return_type);
21962206 llvm_fn.addSretAttr(0, raw_llvm_ret_ty);
21972207 }
21982208
......@@ -2285,7 +2295,7 @@ pub const DeclGen = struct {
22852295 const fqn = try decl.getFullyQualifiedName(dg.module);
22862296 defer dg.gpa.free(fqn);
22872297
2288 const llvm_type = try dg.llvmType(decl.ty);
2298 const llvm_type = try dg.lowerType(decl.ty);
22892299 const llvm_addrspace = dg.llvmAddressSpace(decl.@"addrspace");
22902300 const llvm_global = dg.object.llvm_module.addGlobalInAddressSpace(llvm_type, fqn, llvm_addrspace);
22912301 gop.value_ptr.* = llvm_global;
......@@ -2339,15 +2349,15 @@ pub const DeclGen = struct {
23392349 }
23402350
23412351 fn isUnnamedType(dg: *DeclGen, ty: Type, val: *const llvm.Value) bool {
2342 // Once `llvmType` succeeds, successive calls to it with the same Zig type
2343 // are guaranteed to succeed. So if a call to `llvmType` fails here it means
2352 // Once `lowerType` succeeds, successive calls to it with the same Zig type
2353 // are guaranteed to succeed. So if a call to `lowerType` fails here it means
23442354 // it is the first time lowering the type, which means the value can't possible
23452355 // have that type.
2346 const llvm_ty = dg.llvmType(ty) catch return true;
2356 const llvm_ty = dg.lowerType(ty) catch return true;
23472357 return val.typeOf() != llvm_ty;
23482358 }
23492359
2350 fn llvmType(dg: *DeclGen, t: Type) Allocator.Error!*const llvm.Type {
2360 fn lowerType(dg: *DeclGen, t: Type) Allocator.Error!*const llvm.Type {
23512361 const gpa = dg.gpa;
23522362 const target = dg.module.getTarget();
23532363 switch (t.zigTypeTag()) {
......@@ -2379,8 +2389,8 @@ pub const DeclGen = struct {
23792389 const ptr_type = t.slicePtrFieldType(&buf);
23802390
23812391 const fields: [2]*const llvm.Type = .{
2382 try dg.llvmType(ptr_type),
2383 try dg.llvmType(Type.usize),
2392 try dg.lowerType(ptr_type),
2393 try dg.lowerType(Type.usize),
23842394 };
23852395 return dg.context.structType(&fields, fields.len, .False);
23862396 }
......@@ -2396,7 +2406,7 @@ pub const DeclGen = struct {
23962406 else => elem_ty.hasRuntimeBitsIgnoreComptime(),
23972407 };
23982408 const llvm_elem_ty = if (lower_elem_ty)
2399 try dg.llvmType(elem_ty)
2409 try dg.lowerType(elem_ty)
24002410 else
24012411 dg.context.intType(8);
24022412 return llvm_elem_ty.pointerType(llvm_addrspace);
......@@ -2424,12 +2434,12 @@ pub const DeclGen = struct {
24242434 .Array => {
24252435 const elem_ty = t.childType();
24262436 assert(elem_ty.onePossibleValue() == null);
2427 const elem_llvm_ty = try dg.llvmType(elem_ty);
2437 const elem_llvm_ty = try dg.lowerType(elem_ty);
24282438 const total_len = t.arrayLen() + @boolToInt(t.sentinel() != null);
24292439 return elem_llvm_ty.arrayType(@intCast(c_uint, total_len));
24302440 },
24312441 .Vector => {
2432 const elem_type = try dg.llvmType(t.childType());
2442 const elem_type = try dg.lowerType(t.childType());
24332443 return elem_type.vectorType(t.vectorLen());
24342444 },
24352445 .Optional => {
......@@ -2438,8 +2448,8 @@ pub const DeclGen = struct {
24382448 if (!child_ty.hasRuntimeBitsIgnoreComptime()) {
24392449 return dg.context.intType(1);
24402450 }
2441 const payload_llvm_ty = try dg.llvmType(child_ty);
2442 if (t.isPtrLikeOptional()) {
2451 const payload_llvm_ty = try dg.lowerType(child_ty);
2452 if (t.optionalReprIsPayload()) {
24432453 return payload_llvm_ty;
24442454 }
24452455
......@@ -2449,28 +2459,33 @@ pub const DeclGen = struct {
24492459 return dg.context.structType(&fields, fields.len, .False);
24502460 },
24512461 .ErrorUnion => {
2452 const error_type = t.errorUnionSet();
2453 const payload_type = t.errorUnionPayload();
2454 const llvm_error_type = try dg.llvmType(error_type);
2455 if (!payload_type.hasRuntimeBitsIgnoreComptime()) {
2456 return llvm_error_type;
2462 const payload_ty = t.errorUnionPayload();
2463 switch (t.errorUnionSet().errorSetCardinality()) {
2464 .zero => return dg.lowerType(payload_ty),
2465 .one => {
2466 if (payload_ty.isNoReturn()) {
2467 return dg.context.voidType();
2468 }
2469 },
2470 .many => {},
2471 }
2472 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
2473 return try dg.lowerType(Type.anyerror);
24572474 }
2458 const llvm_payload_type = try dg.llvmType(payload_type);
2475 const llvm_error_type = try dg.lowerType(Type.anyerror);
2476 const llvm_payload_type = try dg.lowerType(payload_ty);
24592477
2460 const payload_align = payload_type.abiAlignment(target);
2461 const error_size = error_type.abiSize(target);
2462 if (payload_align > error_size) {
2463 const pad_type = dg.context.intType(8).arrayType(@intCast(u32, payload_align - error_size));
2464 const fields: [3]*const llvm.Type = .{ llvm_error_type, pad_type, llvm_payload_type };
2478 const payload_align = payload_ty.abiAlignment(target);
2479 const error_align = Type.anyerror.abiAlignment(target);
2480 if (error_align > payload_align) {
2481 const fields: [2]*const llvm.Type = .{ llvm_error_type, llvm_payload_type };
24652482 return dg.context.structType(&fields, fields.len, .False);
24662483 } else {
2467 const fields: [2]*const llvm.Type = .{ llvm_error_type, llvm_payload_type };
2484 const fields: [2]*const llvm.Type = .{ llvm_payload_type, llvm_error_type };
24682485 return dg.context.structType(&fields, fields.len, .False);
24692486 }
24702487 },
2471 .ErrorSet => {
2472 return dg.context.intType(16);
2473 },
2488 .ErrorSet => return dg.context.intType(16),
24742489 .Struct => {
24752490 const gop = try dg.object.type_map.getOrPutContext(gpa, t, .{ .mod = dg.module });
24762491 if (gop.found_existing) return gop.value_ptr.*;
......@@ -2507,7 +2522,7 @@ pub const DeclGen = struct {
25072522 const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len));
25082523 try llvm_field_types.append(gpa, llvm_array_ty);
25092524 }
2510 const field_llvm_ty = try dg.llvmType(field_ty);
2525 const field_llvm_ty = try dg.lowerType(field_ty);
25112526 try llvm_field_types.append(gpa, field_llvm_ty);
25122527
25132528 offset += field_ty.abiSize(target);
......@@ -2536,7 +2551,7 @@ pub const DeclGen = struct {
25362551 if (struct_obj.layout == .Packed) {
25372552 var buf: Type.Payload.Bits = undefined;
25382553 const int_ty = struct_obj.packedIntegerType(target, &buf);
2539 const int_llvm_ty = try dg.llvmType(int_ty);
2554 const int_llvm_ty = try dg.lowerType(int_ty);
25402555 gop.value_ptr.* = int_llvm_ty;
25412556 return int_llvm_ty;
25422557 }
......@@ -2571,7 +2586,7 @@ pub const DeclGen = struct {
25712586 const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len));
25722587 try llvm_field_types.append(gpa, llvm_array_ty);
25732588 }
2574 const field_llvm_ty = try dg.llvmType(field.ty);
2589 const field_llvm_ty = try dg.lowerType(field.ty);
25752590 try llvm_field_types.append(gpa, field_llvm_ty);
25762591
25772592 offset += field.ty.abiSize(target);
......@@ -2606,7 +2621,7 @@ pub const DeclGen = struct {
26062621 const union_obj = t.cast(Type.Payload.Union).?.data;
26072622
26082623 if (layout.payload_size == 0) {
2609 const enum_tag_llvm_ty = try dg.llvmType(union_obj.tag_ty);
2624 const enum_tag_llvm_ty = try dg.lowerType(union_obj.tag_ty);
26102625 gop.value_ptr.* = enum_tag_llvm_ty;
26112626 return enum_tag_llvm_ty;
26122627 }
......@@ -2618,7 +2633,7 @@ pub const DeclGen = struct {
26182633 gop.value_ptr.* = llvm_union_ty; // must be done before any recursive calls
26192634
26202635 const aligned_field = union_obj.fields.values()[layout.most_aligned_field];
2621 const llvm_aligned_field_ty = try dg.llvmType(aligned_field.ty);
2636 const llvm_aligned_field_ty = try dg.lowerType(aligned_field.ty);
26222637
26232638 const llvm_payload_ty = t: {
26242639 if (layout.most_aligned_field_size == layout.payload_size) {
......@@ -2637,7 +2652,7 @@ pub const DeclGen = struct {
26372652 llvm_union_ty.structSetBody(&llvm_fields, llvm_fields.len, .False);
26382653 return llvm_union_ty;
26392654 }
2640 const enum_tag_llvm_ty = try dg.llvmType(union_obj.tag_ty);
2655 const enum_tag_llvm_ty = try dg.lowerType(union_obj.tag_ty);
26412656
26422657 // Put the tag before or after the payload depending on which one's
26432658 // alignment is greater.
......@@ -2659,7 +2674,7 @@ pub const DeclGen = struct {
26592674 llvm_union_ty.structSetBody(&llvm_fields, llvm_fields_len, .False);
26602675 return llvm_union_ty;
26612676 },
2662 .Fn => return llvmTypeFn(dg, t),
2677 .Fn => return lowerTypeFn(dg, t),
26632678 .ComptimeInt => unreachable,
26642679 .ComptimeFloat => unreachable,
26652680 .Type => unreachable,
......@@ -2674,7 +2689,7 @@ pub const DeclGen = struct {
26742689 }
26752690 }
26762691
2677 fn llvmTypeFn(dg: *DeclGen, fn_ty: Type) Allocator.Error!*const llvm.Type {
2692 fn lowerTypeFn(dg: *DeclGen, fn_ty: Type) Allocator.Error!*const llvm.Type {
26782693 const target = dg.module.getTarget();
26792694 const fn_info = fn_ty.fnInfo();
26802695 const llvm_ret_ty = try lowerFnRetTy(dg, fn_info);
......@@ -2683,7 +2698,7 @@ pub const DeclGen = struct {
26832698 defer llvm_params.deinit();
26842699
26852700 if (firstParamSRet(fn_info, target)) {
2686 const llvm_sret_ty = try dg.llvmType(fn_info.return_type);
2701 const llvm_sret_ty = try dg.lowerType(fn_info.return_type);
26872702 try llvm_params.append(llvm_sret_ty.pointerType(0));
26882703 }
26892704
......@@ -2695,7 +2710,7 @@ pub const DeclGen = struct {
26952710 .data = dg.object.getStackTraceType(),
26962711 };
26972712 const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
2698 try llvm_params.append(try dg.llvmType(ptr_ty));
2713 try llvm_params.append(try dg.lowerType(ptr_ty));
26992714 }
27002715
27012716 var it = iterateParamTypes(dg, fn_info);
......@@ -2703,11 +2718,11 @@ pub const DeclGen = struct {
27032718 .no_bits => continue,
27042719 .byval => {
27052720 const param_ty = fn_info.param_types[it.zig_index - 1];
2706 try llvm_params.append(try dg.llvmType(param_ty));
2721 try llvm_params.append(try dg.lowerType(param_ty));
27072722 },
27082723 .byref => {
27092724 const param_ty = fn_info.param_types[it.zig_index - 1];
2710 const raw_llvm_ty = try dg.llvmType(param_ty);
2725 const raw_llvm_ty = try dg.lowerType(param_ty);
27112726 try llvm_params.append(raw_llvm_ty.pointerType(0));
27122727 },
27132728 .abi_sized_int => {
......@@ -2749,7 +2764,7 @@ pub const DeclGen = struct {
27492764 // one field; in this case keep the type information
27502765 // to avoid the potentially costly ptrtoint/bitcast.
27512766 if (bits_used == 0 and field_abi_bits == int_bits) {
2752 const llvm_field_ty = try dg.llvmType(field.ty);
2767 const llvm_field_ty = try dg.lowerType(field.ty);
27532768 llvm_params.appendAssumeCapacity(llvm_field_ty);
27542769 field_i += 1;
27552770 if (field_i >= fields.len) {
......@@ -2787,16 +2802,16 @@ pub const DeclGen = struct {
27872802 );
27882803 }
27892804
2790 fn genTypedValue(dg: *DeclGen, tv: TypedValue) Error!*const llvm.Value {
2805 fn lowerValue(dg: *DeclGen, tv: TypedValue) Error!*const llvm.Value {
27912806 if (tv.val.isUndef()) {
2792 const llvm_type = try dg.llvmType(tv.ty);
2807 const llvm_type = try dg.lowerType(tv.ty);
27932808 return llvm_type.getUndef();
27942809 }
27952810 const target = dg.module.getTarget();
27962811
27972812 switch (tv.ty.zigTypeTag()) {
27982813 .Bool => {
2799 const llvm_type = try dg.llvmType(tv.ty);
2814 const llvm_type = try dg.lowerType(tv.ty);
28002815 return if (tv.val.toBool()) llvm_type.constAllOnes() else llvm_type.constNull();
28012816 },
28022817 // TODO this duplicates code with Pointer but they should share the handling
......@@ -2857,7 +2872,7 @@ pub const DeclGen = struct {
28572872 return unsigned_val;
28582873 },
28592874 .Float => {
2860 const llvm_ty = try dg.llvmType(tv.ty);
2875 const llvm_ty = try dg.lowerType(tv.ty);
28612876 switch (tv.ty.floatBits(target)) {
28622877 16, 32, 64 => return llvm_ty.constReal(tv.val.toFloat(f64)),
28632878 80 => {
......@@ -2894,7 +2909,7 @@ pub const DeclGen = struct {
28942909 const decl = dg.module.declPtr(decl_index);
28952910 dg.module.markDeclAlive(decl);
28962911 const val = try dg.resolveGlobalDecl(decl_index);
2897 const llvm_var_type = try dg.llvmType(tv.ty);
2912 const llvm_var_type = try dg.lowerType(tv.ty);
28982913 const llvm_addrspace = dg.llvmAddressSpace(decl.@"addrspace");
28992914 const llvm_type = llvm_var_type.pointerType(llvm_addrspace);
29002915 return val.constBitCast(llvm_type);
......@@ -2903,11 +2918,11 @@ pub const DeclGen = struct {
29032918 const slice = tv.val.castTag(.slice).?.data;
29042919 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
29052920 const fields: [2]*const llvm.Value = .{
2906 try dg.genTypedValue(.{
2921 try dg.lowerValue(.{
29072922 .ty = tv.ty.slicePtrFieldType(&buf),
29082923 .val = slice.ptr,
29092924 }),
2910 try dg.genTypedValue(.{
2925 try dg.lowerValue(.{
29112926 .ty = Type.usize,
29122927 .val = slice.len,
29132928 }),
......@@ -2915,15 +2930,15 @@ pub const DeclGen = struct {
29152930 return dg.context.constStruct(&fields, fields.len, .False);
29162931 },
29172932 .int_u64, .one, .int_big_positive => {
2918 const llvm_usize = try dg.llvmType(Type.usize);
2933 const llvm_usize = try dg.lowerType(Type.usize);
29192934 const llvm_int = llvm_usize.constInt(tv.val.toUnsignedInt(target), .False);
2920 return llvm_int.constIntToPtr(try dg.llvmType(tv.ty));
2935 return llvm_int.constIntToPtr(try dg.lowerType(tv.ty));
29212936 },
29222937 .field_ptr, .opt_payload_ptr, .eu_payload_ptr, .elem_ptr => {
29232938 return dg.lowerParentPtr(tv.val, tv.ty.childType());
29242939 },
29252940 .null_value, .zero => {
2926 const llvm_type = try dg.llvmType(tv.ty);
2941 const llvm_type = try dg.lowerType(tv.ty);
29272942 return llvm_type.constNull();
29282943 },
29292944 else => |tag| return dg.todo("implement const of pointer type '{}' ({})", .{
......@@ -2978,7 +2993,7 @@ pub const DeclGen = struct {
29782993 defer gpa.free(llvm_elems);
29792994 var need_unnamed = false;
29802995 for (elem_vals[0..len]) |elem_val, i| {
2981 llvm_elems[i] = try dg.genTypedValue(.{ .ty = elem_ty, .val = elem_val });
2996 llvm_elems[i] = try dg.lowerValue(.{ .ty = elem_ty, .val = elem_val });
29822997 need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[i]);
29832998 }
29842999 if (need_unnamed) {
......@@ -2988,7 +3003,7 @@ pub const DeclGen = struct {
29883003 .True,
29893004 );
29903005 } else {
2991 const llvm_elem_ty = try dg.llvmType(elem_ty);
3006 const llvm_elem_ty = try dg.lowerType(elem_ty);
29923007 return llvm_elem_ty.constArray(
29933008 llvm_elems.ptr,
29943009 @intCast(c_uint, llvm_elems.len),
......@@ -3008,13 +3023,13 @@ pub const DeclGen = struct {
30083023 var need_unnamed = false;
30093024 if (len != 0) {
30103025 for (llvm_elems[0..len]) |*elem| {
3011 elem.* = try dg.genTypedValue(.{ .ty = elem_ty, .val = val });
3026 elem.* = try dg.lowerValue(.{ .ty = elem_ty, .val = val });
30123027 }
30133028 need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[0]);
30143029 }
30153030
30163031 if (sentinel) |sent| {
3017 llvm_elems[len] = try dg.genTypedValue(.{ .ty = elem_ty, .val = sent });
3032 llvm_elems[len] = try dg.lowerValue(.{ .ty = elem_ty, .val = sent });
30183033 need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[len]);
30193034 }
30203035
......@@ -3025,7 +3040,7 @@ pub const DeclGen = struct {
30253040 .True,
30263041 );
30273042 } else {
3028 const llvm_elem_ty = try dg.llvmType(elem_ty);
3043 const llvm_elem_ty = try dg.lowerType(elem_ty);
30293044 return llvm_elem_ty.constArray(
30303045 llvm_elems.ptr,
30313046 @intCast(c_uint, llvm_elems.len),
......@@ -3035,13 +3050,13 @@ pub const DeclGen = struct {
30353050 .empty_array_sentinel => {
30363051 const elem_ty = tv.ty.elemType();
30373052 const sent_val = tv.ty.sentinel().?;
3038 const sentinel = try dg.genTypedValue(.{ .ty = elem_ty, .val = sent_val });
3053 const sentinel = try dg.lowerValue(.{ .ty = elem_ty, .val = sent_val });
30393054 const llvm_elems: [1]*const llvm.Value = .{sentinel};
30403055 const need_unnamed = dg.isUnnamedType(elem_ty, llvm_elems[0]);
30413056 if (need_unnamed) {
30423057 return dg.context.constStruct(&llvm_elems, llvm_elems.len, .True);
30433058 } else {
3044 const llvm_elem_ty = try dg.llvmType(elem_ty);
3059 const llvm_elem_ty = try dg.lowerType(elem_ty);
30453060 return llvm_elem_ty.constArray(&llvm_elems, llvm_elems.len);
30463061 }
30473062 },
......@@ -3056,19 +3071,19 @@ pub const DeclGen = struct {
30563071 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
30573072 return non_null_bit;
30583073 }
3059 if (tv.ty.isPtrLikeOptional()) {
3074 if (tv.ty.optionalReprIsPayload()) {
30603075 if (tv.val.castTag(.opt_payload)) |payload| {
3061 return dg.genTypedValue(.{ .ty = payload_ty, .val = payload.data });
3076 return dg.lowerValue(.{ .ty = payload_ty, .val = payload.data });
30623077 } else if (is_pl) {
3063 return dg.genTypedValue(.{ .ty = payload_ty, .val = tv.val });
3078 return dg.lowerValue(.{ .ty = payload_ty, .val = tv.val });
30643079 } else {
3065 const llvm_ty = try dg.llvmType(tv.ty);
3080 const llvm_ty = try dg.lowerType(tv.ty);
30663081 return llvm_ty.constNull();
30673082 }
30683083 }
30693084 assert(payload_ty.zigTypeTag() != .Fn);
30703085 const fields: [2]*const llvm.Value = .{
3071 try dg.genTypedValue(.{
3086 try dg.lowerValue(.{
30723087 .ty = payload_ty,
30733088 .val = if (tv.val.castTag(.opt_payload)) |pl| pl.data else Value.initTag(.undef),
30743089 }),
......@@ -3087,7 +3102,7 @@ pub const DeclGen = struct {
30873102 return dg.resolveLlvmFunction(fn_decl_index);
30883103 },
30893104 .ErrorSet => {
3090 const llvm_ty = try dg.llvmType(tv.ty);
3105 const llvm_ty = try dg.lowerType(Type.anyerror);
30913106 switch (tv.val.tag()) {
30923107 .@"error" => {
30933108 const err_name = tv.val.castTag(.@"error").?.data.name;
......@@ -3101,40 +3116,39 @@ pub const DeclGen = struct {
31013116 }
31023117 },
31033118 .ErrorUnion => {
3104 const error_type = tv.ty.errorUnionSet();
31053119 const payload_type = tv.ty.errorUnionPayload();
3120 if (tv.ty.errorUnionSet().errorSetCardinality() == .zero) {
3121 const payload_val = tv.val.castTag(.eu_payload).?.data;
3122 return dg.lowerValue(.{ .ty = payload_type, .val = payload_val });
3123 }
31063124 const is_pl = tv.val.errorUnionIsPayload();
31073125
31083126 if (!payload_type.hasRuntimeBitsIgnoreComptime()) {
31093127 // We use the error type directly as the type.
31103128 const err_val = if (!is_pl) tv.val else Value.initTag(.zero);
3111 return dg.genTypedValue(.{ .ty = error_type, .val = err_val });
3129 return dg.lowerValue(.{ .ty = Type.anyerror, .val = err_val });
31123130 }
3113 var len: u8 = 2;
3114 var fields: [3]*const llvm.Value = .{
3115 try dg.genTypedValue(.{
3116 .ty = error_type,
3117 .val = if (is_pl) Value.initTag(.zero) else tv.val,
3118 }),
3119 try dg.genTypedValue(.{
3120 .ty = payload_type,
3121 .val = if (tv.val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef),
3122 }),
3123 undefined,
3124 };
31253131
31263132 const payload_align = payload_type.abiAlignment(target);
3127 const error_size = error_type.abiSize(target);
3128 if (payload_align > error_size) {
3129 fields[2] = fields[1];
3130 const pad_type = dg.context.intType(8).arrayType(@intCast(u32, payload_align - error_size));
3131 fields[1] = pad_type.getUndef();
3132 len += 1;
3133 const error_align = Type.anyerror.abiAlignment(target);
3134 const llvm_error_value = try dg.lowerValue(.{
3135 .ty = Type.anyerror,
3136 .val = if (is_pl) Value.initTag(.zero) else tv.val,
3137 });
3138 const llvm_payload_value = try dg.lowerValue(.{
3139 .ty = payload_type,
3140 .val = if (tv.val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef),
3141 });
3142 if (error_align > payload_align) {
3143 const fields: [2]*const llvm.Value = .{ llvm_error_value, llvm_payload_value };
3144 return dg.context.constStruct(&fields, fields.len, .False);
3145 } else {
3146 const fields: [2]*const llvm.Value = .{ llvm_payload_value, llvm_error_value };
3147 return dg.context.constStruct(&fields, fields.len, .False);
31333148 }
3134 return dg.context.constStruct(&fields, len, .False);
31353149 },
31363150 .Struct => {
3137 const llvm_struct_ty = try dg.llvmType(tv.ty);
3151 const llvm_struct_ty = try dg.lowerType(tv.ty);
31383152 const field_vals = tv.val.castTag(.aggregate).?.data;
31393153 const gpa = dg.gpa;
31403154
......@@ -3167,7 +3181,7 @@ pub const DeclGen = struct {
31673181 llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef());
31683182 }
31693183
3170 const field_llvm_val = try dg.genTypedValue(.{
3184 const field_llvm_val = try dg.lowerValue(.{
31713185 .ty = field_ty,
31723186 .val = field_vals[i],
31733187 });
......@@ -3215,7 +3229,7 @@ pub const DeclGen = struct {
32153229 const field = fields[i];
32163230 if (!field.ty.hasRuntimeBitsIgnoreComptime()) continue;
32173231
3218 const non_int_val = try dg.genTypedValue(.{
3232 const non_int_val = try dg.lowerValue(.{
32193233 .ty = field.ty,
32203234 .val = field_val,
32213235 });
......@@ -3259,7 +3273,7 @@ pub const DeclGen = struct {
32593273 llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef());
32603274 }
32613275
3262 const field_llvm_val = try dg.genTypedValue(.{
3276 const field_llvm_val = try dg.lowerValue(.{
32633277 .ty = field.ty,
32643278 .val = field_vals[i],
32653279 });
......@@ -3294,13 +3308,13 @@ pub const DeclGen = struct {
32943308 }
32953309 },
32963310 .Union => {
3297 const llvm_union_ty = try dg.llvmType(tv.ty);
3311 const llvm_union_ty = try dg.lowerType(tv.ty);
32983312 const tag_and_val = tv.val.castTag(.@"union").?.data;
32993313
33003314 const layout = tv.ty.unionGetLayout(target);
33013315
33023316 if (layout.payload_size == 0) {
3303 return genTypedValue(dg, .{
3317 return lowerValue(dg, .{
33043318 .ty = tv.ty.unionTagType().?,
33053319 .val = tag_and_val.tag,
33063320 });
......@@ -3314,7 +3328,7 @@ pub const DeclGen = struct {
33143328 const padding_len = @intCast(c_uint, layout.payload_size);
33153329 break :p dg.context.intType(8).arrayType(padding_len).getUndef();
33163330 }
3317 const field = try genTypedValue(dg, .{ .ty = field_ty, .val = tag_and_val.val });
3331 const field = try lowerValue(dg, .{ .ty = field_ty, .val = tag_and_val.val });
33183332 const field_size = field_ty.abiSize(target);
33193333 if (field_size == layout.payload_size) {
33203334 break :p field;
......@@ -3340,7 +3354,7 @@ pub const DeclGen = struct {
33403354 return llvm_union_ty.constNamedStruct(&fields, fields.len);
33413355 }
33423356 }
3343 const llvm_tag_value = try genTypedValue(dg, .{
3357 const llvm_tag_value = try lowerValue(dg, .{
33443358 .ty = tv.ty.unionTagType().?,
33453359 .val = tag_and_val.tag,
33463360 });
......@@ -3377,7 +3391,7 @@ pub const DeclGen = struct {
33773391 .data = bytes[i],
33783392 };
33793393
3380 elem.* = try dg.genTypedValue(.{
3394 elem.* = try dg.lowerValue(.{
33813395 .ty = elem_ty,
33823396 .val = Value.initPayload(&byte_payload.base),
33833397 });
......@@ -3397,7 +3411,7 @@ pub const DeclGen = struct {
33973411 const llvm_elems = try dg.gpa.alloc(*const llvm.Value, vector_len);
33983412 defer dg.gpa.free(llvm_elems);
33993413 for (llvm_elems) |*elem, i| {
3400 elem.* = try dg.genTypedValue(.{ .ty = elem_ty, .val = elem_vals[i] });
3414 elem.* = try dg.lowerValue(.{ .ty = elem_ty, .val = elem_vals[i] });
34013415 }
34023416 return llvm.constVector(
34033417 llvm_elems.ptr,
......@@ -3412,7 +3426,7 @@ pub const DeclGen = struct {
34123426 const llvm_elems = try dg.gpa.alloc(*const llvm.Value, len);
34133427 defer dg.gpa.free(llvm_elems);
34143428 for (llvm_elems) |*elem| {
3415 elem.* = try dg.genTypedValue(.{ .ty = elem_ty, .val = val });
3429 elem.* = try dg.lowerValue(.{ .ty = elem_ty, .val = val });
34163430 }
34173431 return llvm.constVector(
34183432 llvm_elems.ptr,
......@@ -3462,7 +3476,7 @@ pub const DeclGen = struct {
34623476 if (ptr_child_ty.eql(decl.ty, dg.module)) {
34633477 return llvm_ptr;
34643478 } else {
3465 return llvm_ptr.constBitCast((try dg.llvmType(ptr_child_ty)).pointerType(0));
3479 return llvm_ptr.constBitCast((try dg.lowerType(ptr_child_ty)).pointerType(0));
34663480 }
34673481 }
34683482
......@@ -3484,15 +3498,15 @@ pub const DeclGen = struct {
34843498 },
34853499 .int_i64 => {
34863500 const int = ptr_val.castTag(.int_i64).?.data;
3487 const llvm_usize = try dg.llvmType(Type.usize);
3501 const llvm_usize = try dg.lowerType(Type.usize);
34883502 const llvm_int = llvm_usize.constInt(@bitCast(u64, int), .False);
3489 return llvm_int.constIntToPtr((try dg.llvmType(ptr_child_ty)).pointerType(0));
3503 return llvm_int.constIntToPtr((try dg.lowerType(ptr_child_ty)).pointerType(0));
34903504 },
34913505 .int_u64 => {
34923506 const int = ptr_val.castTag(.int_u64).?.data;
3493 const llvm_usize = try dg.llvmType(Type.usize);
3507 const llvm_usize = try dg.lowerType(Type.usize);
34943508 const llvm_int = llvm_usize.constInt(int, .False);
3495 return llvm_int.constIntToPtr((try dg.llvmType(ptr_child_ty)).pointerType(0));
3509 return llvm_int.constIntToPtr((try dg.lowerType(ptr_child_ty)).pointerType(0));
34963510 },
34973511 .field_ptr => blk: {
34983512 const field_ptr = ptr_val.castTag(.field_ptr).?.data;
......@@ -3541,7 +3555,7 @@ pub const DeclGen = struct {
35413555 const parent_llvm_ptr = try dg.lowerParentPtr(elem_ptr.array_ptr, elem_ptr.elem_ty);
35423556 bitcast_needed = !elem_ptr.elem_ty.eql(ptr_child_ty, dg.module);
35433557
3544 const llvm_usize = try dg.llvmType(Type.usize);
3558 const llvm_usize = try dg.lowerType(Type.usize);
35453559 const indices: [1]*const llvm.Value = .{
35463560 llvm_usize.constInt(elem_ptr.index, .False),
35473561 };
......@@ -3555,7 +3569,9 @@ pub const DeclGen = struct {
35553569 const payload_ty = opt_payload_ptr.container_ty.optionalChild(&buf);
35563570 bitcast_needed = !payload_ty.eql(ptr_child_ty, dg.module);
35573571
3558 if (!payload_ty.hasRuntimeBitsIgnoreComptime() or payload_ty.isPtrLikeOptional()) {
3572 if (!payload_ty.hasRuntimeBitsIgnoreComptime() or
3573 payload_ty.optionalReprIsPayload())
3574 {
35593575 // In this case, we represent pointer to optional the same as pointer
35603576 // to the payload.
35613577 break :blk parent_llvm_ptr;
......@@ -3592,7 +3608,7 @@ pub const DeclGen = struct {
35923608 else => unreachable,
35933609 };
35943610 if (bitcast_needed) {
3595 return llvm_ptr.constBitCast((try dg.llvmType(ptr_child_ty)).pointerType(0));
3611 return llvm_ptr.constBitCast((try dg.lowerType(ptr_child_ty)).pointerType(0));
35963612 } else {
35973613 return llvm_ptr;
35983614 }
......@@ -3611,11 +3627,11 @@ pub const DeclGen = struct {
36113627 .data = tv.val.sliceLen(self.module),
36123628 };
36133629 const fields: [2]*const llvm.Value = .{
3614 try self.genTypedValue(.{
3630 try self.lowerValue(.{
36153631 .ty = ptr_ty,
36163632 .val = tv.val,
36173633 }),
3618 try self.genTypedValue(.{
3634 try self.lowerValue(.{
36193635 .ty = Type.usize,
36203636 .val = Value.initPayload(&slice_len.base),
36213637 }),
......@@ -3647,7 +3663,7 @@ pub const DeclGen = struct {
36473663 else
36483664 try self.resolveGlobalDecl(decl_index);
36493665
3650 const llvm_type = try self.llvmType(tv.ty);
3666 const llvm_type = try self.lowerType(tv.ty);
36513667 if (tv.ty.zigTypeTag() == .Int) {
36523668 return llvm_val.constPtrToInt(llvm_type);
36533669 } else {
......@@ -3662,8 +3678,8 @@ pub const DeclGen = struct {
36623678 // The value cannot be undefined, because we use the `nonnull` annotation
36633679 // for non-optional pointers. We also need to respect the alignment, even though
36643680 // the address will never be dereferenced.
3665 const llvm_usize = try dg.llvmType(Type.usize);
3666 const llvm_ptr_ty = try dg.llvmType(ptr_ty);
3681 const llvm_usize = try dg.lowerType(Type.usize);
3682 const llvm_ptr_ty = try dg.lowerType(ptr_ty);
36673683 if (alignment != 0) {
36683684 return llvm_usize.constInt(alignment, .False).constIntToPtr(llvm_ptr_ty);
36693685 }
......@@ -3842,7 +3858,7 @@ pub const FuncGen = struct {
38423858
38433859 const val = self.air.value(inst).?;
38443860 const ty = self.air.typeOf(inst);
3845 const llvm_val = try self.dg.genTypedValue(.{ .ty = ty, .val = val });
3861 const llvm_val = try self.dg.lowerValue(.{ .ty = ty, .val = val });
38463862 if (!isByRef(ty)) {
38473863 gop.value_ptr.* = llvm_val;
38483864 return llvm_val;
......@@ -3860,7 +3876,7 @@ pub const FuncGen = struct {
38603876 // Because of LLVM limitations for lowering certain types such as unions,
38613877 // the type of global constants might not match the type it is supposed to
38623878 // be, and so we must bitcast the pointer at the usage sites.
3863 const wanted_llvm_ty = try self.dg.llvmType(ty);
3879 const wanted_llvm_ty = try self.dg.lowerType(ty);
38643880 const wanted_llvm_ptr_ty = wanted_llvm_ty.pointerType(0);
38653881 const casted_ptr = global.constBitCast(wanted_llvm_ptr_ty);
38663882 gop.value_ptr.* = casted_ptr;
......@@ -4084,7 +4100,7 @@ pub const FuncGen = struct {
40844100 defer llvm_args.deinit();
40854101
40864102 const ret_ptr = if (!sret) null else blk: {
4087 const llvm_ret_ty = try self.dg.llvmType(return_type);
4103 const llvm_ret_ty = try self.dg.lowerType(return_type);
40884104 const ret_ptr = self.buildAlloca(llvm_ret_ty);
40894105 ret_ptr.setAlignment(return_type.abiAlignment(target));
40904106 try llvm_args.append(ret_ptr);
......@@ -4116,7 +4132,7 @@ pub const FuncGen = struct {
41164132 // which is always lowered to an LLVM type of `*i8`.
41174133 // 2. The argument is a global which does act as a pointer, however
41184134 // a bitcast is needed in order for the LLVM types to match.
4119 const llvm_param_ty = try self.dg.llvmType(param_ty);
4135 const llvm_param_ty = try self.dg.lowerType(param_ty);
41204136 const casted_ptr = self.builder.buildBitCast(llvm_arg, llvm_param_ty, "");
41214137 try llvm_args.append(casted_ptr);
41224138 } else {
......@@ -4163,7 +4179,7 @@ pub const FuncGen = struct {
41634179 );
41644180 const int_ptr = self.buildAlloca(int_llvm_ty);
41654181 int_ptr.setAlignment(alignment);
4166 const param_llvm_ty = try self.dg.llvmType(param_ty);
4182 const param_llvm_ty = try self.dg.lowerType(param_ty);
41674183 const casted_ptr = self.builder.buildBitCast(int_ptr, param_llvm_ty.pointerType(0), "");
41684184 const store_inst = self.builder.buildStore(llvm_arg, casted_ptr);
41694185 store_inst.setAlignment(alignment);
......@@ -4274,7 +4290,7 @@ pub const FuncGen = struct {
42744290 return null;
42754291 }
42764292
4277 const llvm_ret_ty = try self.dg.llvmType(return_type);
4293 const llvm_ret_ty = try self.dg.lowerType(return_type);
42784294
42794295 if (ret_ptr) |rp| {
42804296 call.setCallSret(llvm_ret_ty);
......@@ -4338,11 +4354,19 @@ pub const FuncGen = struct {
43384354 _ = self.builder.buildRetVoid();
43394355 return null;
43404356 }
4357 const fn_info = self.dg.decl.ty.fnInfo();
43414358 if (!ret_ty.hasRuntimeBitsIgnoreComptime()) {
4342 _ = self.builder.buildRetVoid();
4359 if (fn_info.return_type.isError()) {
4360 // Functions with an empty error set are emitted with an error code
4361 // return type and return zero so they can be function pointers coerced
4362 // to functions that return anyerror.
4363 const err_int = try self.dg.lowerType(Type.anyerror);
4364 _ = self.builder.buildRet(err_int.constInt(0, .False));
4365 } else {
4366 _ = self.builder.buildRetVoid();
4367 }
43434368 return null;
43444369 }
4345 const fn_info = self.dg.decl.ty.fnInfo();
43464370 const abi_ret_ty = try lowerFnRetTy(self.dg, fn_info);
43474371 const operand = try self.resolveInst(un_op);
43484372 const llvm_ret_ty = operand.typeOf();
......@@ -4369,15 +4393,27 @@ pub const FuncGen = struct {
43694393 const un_op = self.air.instructions.items(.data)[inst].un_op;
43704394 const ptr_ty = self.air.typeOf(un_op);
43714395 const ret_ty = ptr_ty.childType();
4372 if (!ret_ty.hasRuntimeBitsIgnoreComptime() or self.ret_ptr != null) {
4396 const fn_info = self.dg.decl.ty.fnInfo();
4397 if (!ret_ty.hasRuntimeBitsIgnoreComptime()) {
4398 if (fn_info.return_type.isError()) {
4399 // Functions with an empty error set are emitted with an error code
4400 // return type and return zero so they can be function pointers coerced
4401 // to functions that return anyerror.
4402 const err_int = try self.dg.lowerType(Type.anyerror);
4403 _ = self.builder.buildRet(err_int.constInt(0, .False));
4404 } else {
4405 _ = self.builder.buildRetVoid();
4406 }
4407 return null;
4408 }
4409 if (self.ret_ptr != null) {
43734410 _ = self.builder.buildRetVoid();
43744411 return null;
43754412 }
43764413 const ptr = try self.resolveInst(un_op);
43774414 const target = self.dg.module.getTarget();
4378 const fn_info = self.dg.decl.ty.fnInfo();
43794415 const abi_ret_ty = try lowerFnRetTy(self.dg, fn_info);
4380 const llvm_ret_ty = try self.dg.llvmType(ret_ty);
4416 const llvm_ret_ty = try self.dg.lowerType(ret_ty);
43814417 const casted_ptr = if (abi_ret_ty == llvm_ret_ty) ptr else p: {
43824418 const ptr_abi_ty = abi_ret_ty.pointerType(0);
43834419 break :p self.builder.buildBitCast(ptr, ptr_abi_ty, "");
......@@ -4439,7 +4475,9 @@ pub const FuncGen = struct {
44394475 .Int, .Bool, .Pointer, .ErrorSet => scalar_ty,
44404476 .Optional => blk: {
44414477 const payload_ty = operand_ty.optionalChild(&opt_buffer);
4442 if (!payload_ty.hasRuntimeBitsIgnoreComptime() or operand_ty.isPtrLikeOptional()) {
4478 if (!payload_ty.hasRuntimeBitsIgnoreComptime() or
4479 operand_ty.optionalReprIsPayload())
4480 {
44434481 break :blk operand_ty;
44444482 }
44454483 // We need to emit instructions to check for equality/inequality
......@@ -4556,7 +4594,7 @@ pub const FuncGen = struct {
45564594 const is_body = inst_ty.zigTypeTag() == .Fn;
45574595 if (!is_body and !inst_ty.hasRuntimeBitsIgnoreComptime()) return null;
45584596
4559 const raw_llvm_ty = try self.dg.llvmType(inst_ty);
4597 const raw_llvm_ty = try self.dg.lowerType(inst_ty);
45604598
45614599 const llvm_ty = ty: {
45624600 // If the zig tag type is a function, this represents an actual function body; not
......@@ -4696,9 +4734,9 @@ pub const FuncGen = struct {
46964734 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
46974735 const operand_ty = self.air.typeOf(ty_op.operand);
46984736 const array_ty = operand_ty.childType();
4699 const llvm_usize = try self.dg.llvmType(Type.usize);
4737 const llvm_usize = try self.dg.lowerType(Type.usize);
47004738 const len = llvm_usize.constInt(array_ty.arrayLen(), .False);
4701 const slice_llvm_ty = try self.dg.llvmType(self.air.typeOfIndex(inst));
4739 const slice_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst));
47024740 if (!array_ty.hasRuntimeBitsIgnoreComptime()) {
47034741 return self.builder.buildInsertValue(slice_llvm_ty.getUndef(), len, 1, "");
47044742 }
......@@ -4723,7 +4761,7 @@ pub const FuncGen = struct {
47234761
47244762 const dest_ty = self.air.typeOfIndex(inst);
47254763 const dest_scalar_ty = dest_ty.scalarType();
4726 const dest_llvm_ty = try self.dg.llvmType(dest_ty);
4764 const dest_llvm_ty = try self.dg.lowerType(dest_ty);
47274765 const target = self.dg.module.getTarget();
47284766
47294767 if (intrinsicsAllowed(dest_scalar_ty, target)) {
......@@ -4774,7 +4812,7 @@ pub const FuncGen = struct {
47744812
47754813 const dest_ty = self.air.typeOfIndex(inst);
47764814 const dest_scalar_ty = dest_ty.scalarType();
4777 const dest_llvm_ty = try self.dg.llvmType(dest_ty);
4815 const dest_llvm_ty = try self.dg.lowerType(dest_ty);
47784816
47794817 if (intrinsicsAllowed(operand_scalar_ty, target)) {
47804818 // TODO set fast math flag
......@@ -4801,7 +4839,7 @@ pub const FuncGen = struct {
48014839 compiler_rt_dest_abbrev,
48024840 }) catch unreachable;
48034841
4804 const operand_llvm_ty = try self.dg.llvmType(operand_ty);
4842 const operand_llvm_ty = try self.dg.lowerType(operand_ty);
48054843 const param_types = [1]*const llvm.Type{operand_llvm_ty};
48064844 const libc_fn = self.getLibcFunction(fn_name, &param_types, libc_ret_ty);
48074845 const params = [1]*const llvm.Value{operand};
......@@ -4962,7 +5000,7 @@ pub const FuncGen = struct {
49625000 const containing_int = struct_llvm_val;
49635001 const shift_amt = containing_int.typeOf().constInt(bit_offset, .False);
49645002 const shifted_value = self.builder.buildLShr(containing_int, shift_amt, "");
4965 const elem_llvm_ty = try self.dg.llvmType(field_ty);
5003 const elem_llvm_ty = try self.dg.lowerType(field_ty);
49665004 if (field_ty.zigTypeTag() == .Float) {
49675005 const elem_bits = @intCast(c_uint, field_ty.bitSize(target));
49685006 const same_size_int = self.context.intType(elem_bits);
......@@ -4994,7 +5032,7 @@ pub const FuncGen = struct {
49945032 return self.load(field_ptr, field_ptr_ty);
49955033 },
49965034 .Union => {
4997 const llvm_field_ty = try self.dg.llvmType(field_ty);
5035 const llvm_field_ty = try self.dg.lowerType(field_ty);
49985036 const layout = struct_ty.unionGetLayout(target);
49995037 const payload_index = @boolToInt(layout.tag_align >= layout.payload_align);
50005038 const union_field_ptr = self.builder.buildStructGEP(struct_llvm_val, payload_index, "");
......@@ -5021,7 +5059,7 @@ pub const FuncGen = struct {
50215059 const struct_ty = self.air.getRefType(ty_pl.ty).childType();
50225060 const field_offset = struct_ty.structFieldOffset(extra.field_index, target);
50235061
5024 const res_ty = try self.dg.llvmType(self.air.getRefType(ty_pl.ty));
5062 const res_ty = try self.dg.lowerType(self.air.getRefType(ty_pl.ty));
50255063 if (field_offset == 0) {
50265064 return self.builder.buildBitCast(field_ptr, res_ty, "");
50275065 }
......@@ -5351,7 +5389,7 @@ pub const FuncGen = struct {
53515389 }
53525390
53535391 const ret_ty = self.air.typeOfIndex(inst);
5354 const ret_llvm_ty = try self.dg.llvmType(ret_ty);
5392 const ret_llvm_ty = try self.dg.lowerType(ret_ty);
53555393 const llvm_fn_ty = llvm.functionType(
53565394 ret_llvm_ty,
53575395 llvm_param_types.ptr,
......@@ -5392,8 +5430,8 @@ pub const FuncGen = struct {
53925430 const operand = try self.resolveInst(un_op);
53935431 const operand_ty = self.air.typeOf(un_op);
53945432 const optional_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty;
5395 if (optional_ty.isPtrLikeOptional()) {
5396 const optional_llvm_ty = try self.dg.llvmType(optional_ty);
5433 if (optional_ty.optionalReprIsPayload()) {
5434 const optional_llvm_ty = try self.dg.lowerType(optional_ty);
53975435 const loaded = if (operand_is_ptr) self.builder.buildLoad(operand, "") else operand;
53985436 return self.builder.buildICmp(pred, loaded, optional_llvm_ty.constNull(), "");
53995437 }
......@@ -5430,21 +5468,33 @@ pub const FuncGen = struct {
54305468 const operand = try self.resolveInst(un_op);
54315469 const err_union_ty = self.air.typeOf(un_op);
54325470 const payload_ty = err_union_ty.errorUnionPayload();
5433 const err_set_ty = try self.dg.llvmType(Type.initTag(.anyerror));
5471 const err_set_ty = try self.dg.lowerType(Type.initTag(.anyerror));
54345472 const zero = err_set_ty.constNull();
54355473
5474 if (err_union_ty.errorUnionSet().errorSetCardinality() == .zero) {
5475 const llvm_i1 = self.context.intType(1);
5476 switch (op) {
5477 .EQ => return llvm_i1.constInt(1, .False), // 0 == 0
5478 .NE => return llvm_i1.constInt(0, .False), // 0 != 0
5479 else => unreachable,
5480 }
5481 }
5482
54365483 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
54375484 const loaded = if (operand_is_ptr) self.builder.buildLoad(operand, "") else operand;
54385485 return self.builder.buildICmp(op, loaded, zero, "");
54395486 }
54405487
5488 const target = self.dg.module.getTarget();
5489 const err_field_index = errUnionErrorOffset(payload_ty, target);
5490
54415491 if (operand_is_ptr or isByRef(err_union_ty)) {
5442 const err_field_ptr = self.builder.buildStructGEP(operand, 0, "");
5492 const err_field_ptr = self.builder.buildStructGEP(operand, err_field_index, "");
54435493 const loaded = self.builder.buildLoad(err_field_ptr, "");
54445494 return self.builder.buildICmp(op, loaded, zero, "");
54455495 }
54465496
5447 const loaded = self.builder.buildExtractValue(operand, 0, "");
5497 const loaded = self.builder.buildExtractValue(operand, err_field_index, "");
54485498 return self.builder.buildICmp(op, loaded, zero, "");
54495499 }
54505500
......@@ -5462,10 +5512,10 @@ pub const FuncGen = struct {
54625512 // a pointer to a zero-bit value.
54635513
54645514 // TODO once we update to LLVM 14 this bitcast won't be necessary.
5465 const res_ptr_ty = try self.dg.llvmType(result_ty);
5515 const res_ptr_ty = try self.dg.lowerType(result_ty);
54665516 return self.builder.buildBitCast(operand, res_ptr_ty, "");
54675517 }
5468 if (optional_ty.isPtrLikeOptional()) {
5518 if (optional_ty.optionalReprIsPayload()) {
54695519 // The payload and the optional are the same value.
54705520 return operand;
54715521 }
......@@ -5490,10 +5540,10 @@ pub const FuncGen = struct {
54905540 _ = self.builder.buildStore(non_null_bit, operand);
54915541
54925542 // TODO once we update to LLVM 14 this bitcast won't be necessary.
5493 const res_ptr_ty = try self.dg.llvmType(result_ty);
5543 const res_ptr_ty = try self.dg.lowerType(result_ty);
54945544 return self.builder.buildBitCast(operand, res_ptr_ty, "");
54955545 }
5496 if (optional_ty.isPtrLikeOptional()) {
5546 if (optional_ty.optionalReprIsPayload()) {
54975547 // The payload and the optional are the same value.
54985548 // Setting to non-null will be done when the payload is set.
54995549 return operand;
......@@ -5527,7 +5577,7 @@ pub const FuncGen = struct {
55275577 const payload_ty = self.air.typeOfIndex(inst);
55285578 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return null;
55295579
5530 if (optional_ty.isPtrLikeOptional()) {
5580 if (optional_ty.optionalReprIsPayload()) {
55315581 // Payload value is the same as the optional value.
55325582 return operand;
55335583 }
......@@ -5544,17 +5594,23 @@ pub const FuncGen = struct {
55445594
55455595 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
55465596 const operand = try self.resolveInst(ty_op.operand);
5547 const result_ty = self.air.getRefType(ty_op.ty);
5597 const operand_ty = self.air.typeOf(ty_op.operand);
5598 const error_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty;
5599 // If the error set has no fields, then the payload and the error
5600 // union are the same value.
5601 if (error_union_ty.errorUnionSet().errorSetCardinality() == .zero) {
5602 return operand;
5603 }
5604 const result_ty = self.air.typeOfIndex(inst);
55485605 const payload_ty = if (operand_is_ptr) result_ty.childType() else result_ty;
5549
55505606 const target = self.dg.module.getTarget();
5551 const offset: u8 = if (payload_ty.abiAlignment(target) > Type.anyerror.abiSize(target)) 2 else 1;
5607 const offset = errUnionPayloadOffset(payload_ty, target);
55525608
55535609 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
55545610 if (!operand_is_ptr) return null;
55555611
55565612 // TODO once we update to LLVM 14 this bitcast won't be necessary.
5557 const res_ptr_ty = try self.dg.llvmType(result_ty);
5613 const res_ptr_ty = try self.dg.lowerType(result_ty);
55585614 return self.builder.buildBitCast(operand, res_ptr_ty, "");
55595615 }
55605616 if (operand_is_ptr or isByRef(payload_ty)) {
......@@ -5574,54 +5630,69 @@ pub const FuncGen = struct {
55745630 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
55755631 const operand = try self.resolveInst(ty_op.operand);
55765632 const operand_ty = self.air.typeOf(ty_op.operand);
5577 const err_set_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty;
5633 const err_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty;
5634 if (err_union_ty.errorUnionSet().errorSetCardinality() == .zero) {
5635 const err_llvm_ty = try self.dg.lowerType(Type.anyerror);
5636 if (operand_is_ptr) {
5637 return self.builder.buildBitCast(operand, err_llvm_ty.pointerType(0), "");
5638 } else {
5639 return err_llvm_ty.constInt(0, .False);
5640 }
5641 }
55785642
5579 const payload_ty = err_set_ty.errorUnionPayload();
5643 const payload_ty = err_union_ty.errorUnionPayload();
55805644 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
55815645 if (!operand_is_ptr) return operand;
55825646 return self.builder.buildLoad(operand, "");
55835647 }
55845648
5585 if (operand_is_ptr or isByRef(err_set_ty)) {
5586 const err_field_ptr = self.builder.buildStructGEP(operand, 0, "");
5649 const target = self.dg.module.getTarget();
5650 const offset = errUnionErrorOffset(payload_ty, target);
5651
5652 if (operand_is_ptr or isByRef(err_union_ty)) {
5653 const err_field_ptr = self.builder.buildStructGEP(operand, offset, "");
55875654 return self.builder.buildLoad(err_field_ptr, "");
55885655 }
55895656
5590 return self.builder.buildExtractValue(operand, 0, "");
5657 return self.builder.buildExtractValue(operand, offset, "");
55915658 }
55925659
55935660 fn airErrUnionPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
55945661 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
55955662 const operand = try self.resolveInst(ty_op.operand);
5596 const error_set_ty = self.air.typeOf(ty_op.operand).childType();
5663 const error_union_ty = self.air.typeOf(ty_op.operand).childType();
55975664
5598 const error_ty = error_set_ty.errorUnionSet();
5599 const payload_ty = error_set_ty.errorUnionPayload();
5600 const non_error_val = try self.dg.genTypedValue(.{ .ty = error_ty, .val = Value.zero });
5665 if (error_union_ty.errorUnionSet().errorSetCardinality() == .zero) {
5666 // TODO: write undefined bytes through the pointer here
5667 return operand;
5668 }
5669 const payload_ty = error_union_ty.errorUnionPayload();
5670 const non_error_val = try self.dg.lowerValue(.{ .ty = Type.anyerror, .val = Value.zero });
56015671 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
5602 // We have a pointer to a i1. We need to set it to 1 and then return the same pointer.
56035672 _ = self.builder.buildStore(non_error_val, operand);
56045673 return operand;
56055674 }
56065675 const index_type = self.context.intType(32);
5676 const target = self.dg.module.getTarget();
56075677 {
5678 const error_offset = errUnionErrorOffset(payload_ty, target);
56085679 // First set the non-error value.
56095680 const indices: [2]*const llvm.Value = .{
56105681 index_type.constNull(), // dereference the pointer
5611 index_type.constNull(), // first field is the payload
5682 index_type.constInt(error_offset, .False),
56125683 };
56135684 const non_null_ptr = self.builder.buildInBoundsGEP(operand, &indices, indices.len, "");
5614 _ = self.builder.buildStore(non_error_val, non_null_ptr);
5685 const store_inst = self.builder.buildStore(non_error_val, non_null_ptr);
5686 store_inst.setAlignment(Type.anyerror.abiAlignment(target));
56155687 }
56165688 // Then return the payload pointer (only if it is used).
56175689 if (self.liveness.isUnused(inst))
56185690 return null;
56195691
5620 const target = self.dg.module.getTarget();
5621 const payload_offset: u8 = if (payload_ty.abiAlignment(target) > Type.anyerror.abiSize(target)) 2 else 1;
5692 const payload_offset = errUnionPayloadOffset(payload_ty, target);
56225693 const indices: [2]*const llvm.Value = .{
56235694 index_type.constNull(), // dereference the pointer
5624 index_type.constInt(payload_offset, .False), // second field is the payload
5695 index_type.constInt(payload_offset, .False),
56255696 };
56265697 return self.builder.buildInBoundsGEP(operand, &indices, indices.len, "");
56275698 }
......@@ -5646,8 +5717,10 @@ pub const FuncGen = struct {
56465717 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return non_null_bit;
56475718 const operand = try self.resolveInst(ty_op.operand);
56485719 const optional_ty = self.air.typeOfIndex(inst);
5649 if (optional_ty.isPtrLikeOptional()) return operand;
5650 const llvm_optional_ty = try self.dg.llvmType(optional_ty);
5720 if (optional_ty.optionalReprIsPayload()) {
5721 return operand;
5722 }
5723 const llvm_optional_ty = try self.dg.lowerType(optional_ty);
56515724 if (isByRef(optional_ty)) {
56525725 const optional_ptr = self.buildAlloca(llvm_optional_ty);
56535726 const payload_ptr = self.builder.buildStructGEP(optional_ptr, 0, "");
......@@ -5669,21 +5742,26 @@ pub const FuncGen = struct {
56695742 if (self.liveness.isUnused(inst)) return null;
56705743
56715744 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
5672 const payload_ty = self.air.typeOf(ty_op.operand);
5745 const inst_ty = self.air.typeOfIndex(inst);
56735746 const operand = try self.resolveInst(ty_op.operand);
5747 if (inst_ty.errorUnionSet().errorSetCardinality() == .zero) {
5748 return operand;
5749 }
5750 const payload_ty = self.air.typeOf(ty_op.operand);
56745751 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
56755752 return operand;
56765753 }
5677 const inst_ty = self.air.typeOfIndex(inst);
5678 const ok_err_code = self.context.intType(16).constNull();
5679 const err_un_llvm_ty = try self.dg.llvmType(inst_ty);
5754 const ok_err_code = (try self.dg.lowerType(Type.anyerror)).constNull();
5755 const err_un_llvm_ty = try self.dg.lowerType(inst_ty);
56805756
56815757 const target = self.dg.module.getTarget();
5682 const payload_offset: u8 = if (payload_ty.abiAlignment(target) > Type.anyerror.abiSize(target)) 2 else 1;
5758 const payload_offset = errUnionPayloadOffset(payload_ty, target);
5759 const error_offset = errUnionErrorOffset(payload_ty, target);
56835760 if (isByRef(inst_ty)) {
56845761 const result_ptr = self.buildAlloca(err_un_llvm_ty);
5685 const err_ptr = self.builder.buildStructGEP(result_ptr, 0, "");
5686 _ = self.builder.buildStore(ok_err_code, err_ptr);
5762 const err_ptr = self.builder.buildStructGEP(result_ptr, error_offset, "");
5763 const store_inst = self.builder.buildStore(ok_err_code, err_ptr);
5764 store_inst.setAlignment(Type.anyerror.abiAlignment(target));
56875765 const payload_ptr = self.builder.buildStructGEP(result_ptr, payload_offset, "");
56885766 var ptr_ty_payload: Type.Payload.ElemType = .{
56895767 .base = .{ .tag = .single_mut_pointer },
......@@ -5694,7 +5772,7 @@ pub const FuncGen = struct {
56945772 return result_ptr;
56955773 }
56965774
5697 const partial = self.builder.buildInsertValue(err_un_llvm_ty.getUndef(), ok_err_code, 0, "");
5775 const partial = self.builder.buildInsertValue(err_un_llvm_ty.getUndef(), ok_err_code, error_offset, "");
56985776 return self.builder.buildInsertValue(partial, operand, payload_offset, "");
56995777 }
57005778
......@@ -5708,14 +5786,16 @@ pub const FuncGen = struct {
57085786 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
57095787 return operand;
57105788 }
5711 const err_un_llvm_ty = try self.dg.llvmType(err_un_ty);
5789 const err_un_llvm_ty = try self.dg.lowerType(err_un_ty);
57125790
57135791 const target = self.dg.module.getTarget();
5714 const payload_offset: u8 = if (payload_ty.abiAlignment(target) > Type.anyerror.abiSize(target)) 2 else 1;
5792 const payload_offset = errUnionPayloadOffset(payload_ty, target);
5793 const error_offset = errUnionErrorOffset(payload_ty, target);
57155794 if (isByRef(err_un_ty)) {
57165795 const result_ptr = self.buildAlloca(err_un_llvm_ty);
5717 const err_ptr = self.builder.buildStructGEP(result_ptr, 0, "");
5718 _ = self.builder.buildStore(operand, err_ptr);
5796 const err_ptr = self.builder.buildStructGEP(result_ptr, error_offset, "");
5797 const store_inst = self.builder.buildStore(operand, err_ptr);
5798 store_inst.setAlignment(Type.anyerror.abiAlignment(target));
57195799 const payload_ptr = self.builder.buildStructGEP(result_ptr, payload_offset, "");
57205800 var ptr_ty_payload: Type.Payload.ElemType = .{
57215801 .base = .{ .tag = .single_mut_pointer },
......@@ -5728,7 +5808,7 @@ pub const FuncGen = struct {
57285808 return result_ptr;
57295809 }
57305810
5731 const partial = self.builder.buildInsertValue(err_un_llvm_ty.getUndef(), operand, 0, "");
5811 const partial = self.builder.buildInsertValue(err_un_llvm_ty.getUndef(), operand, error_offset, "");
57325812 // TODO set payload bytes to undef
57335813 return partial;
57345814 }
......@@ -5791,7 +5871,7 @@ pub const FuncGen = struct {
57915871 const ptr = try self.resolveInst(bin_op.lhs);
57925872 const len = try self.resolveInst(bin_op.rhs);
57935873 const inst_ty = self.air.typeOfIndex(inst);
5794 const llvm_slice_ty = try self.dg.llvmType(inst_ty);
5874 const llvm_slice_ty = try self.dg.lowerType(inst_ty);
57955875
57965876 // In case of slicing a global, the result type looks something like `{ i8*, i64 }`
57975877 // but `ptr` is pointing to the global directly. If it's an array, we would want to
......@@ -5799,7 +5879,7 @@ pub const FuncGen = struct {
57995879 // This prevents an assertion failure.
58005880 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
58015881 const ptr_ty = inst_ty.slicePtrFieldType(&buf);
5802 const ptr_llvm_ty = try self.dg.llvmType(ptr_ty);
5882 const ptr_llvm_ty = try self.dg.lowerType(ptr_ty);
58035883 const casted_ptr = self.builder.buildBitCast(ptr, ptr_llvm_ty, "");
58045884 const partial = self.builder.buildInsertValue(llvm_slice_ty.getUndef(), casted_ptr, 0, "");
58055885 return self.builder.buildInsertValue(partial, len, 1, "");
......@@ -5965,7 +6045,7 @@ pub const FuncGen = struct {
59656045 // const d = @divTrunc(a, b);
59666046 // const r = @rem(a, b);
59676047 // return if (r == 0) d else d - ((a < 0) ^ (b < 0));
5968 const result_llvm_ty = try self.dg.llvmType(inst_ty);
6048 const result_llvm_ty = try self.dg.lowerType(inst_ty);
59696049 const zero = result_llvm_ty.constNull();
59706050 const div_trunc = self.builder.buildSDiv(lhs, rhs, "");
59716051 const rem = self.builder.buildSRem(lhs, rhs, "");
......@@ -6015,7 +6095,7 @@ pub const FuncGen = struct {
60156095 const lhs = try self.resolveInst(bin_op.lhs);
60166096 const rhs = try self.resolveInst(bin_op.rhs);
60176097 const inst_ty = self.air.typeOfIndex(inst);
6018 const inst_llvm_ty = try self.dg.llvmType(inst_ty);
6098 const inst_llvm_ty = try self.dg.lowerType(inst_ty);
60196099 const scalar_ty = inst_ty.scalarType();
60206100
60216101 if (scalar_ty.isRuntimeFloat()) {
......@@ -6099,8 +6179,8 @@ pub const FuncGen = struct {
60996179
61006180 const intrinsic_name = if (scalar_ty.isSignedInt()) signed_intrinsic else unsigned_intrinsic;
61016181
6102 const llvm_lhs_ty = try self.dg.llvmType(lhs_ty);
6103 const llvm_dest_ty = try self.dg.llvmType(dest_ty);
6182 const llvm_lhs_ty = try self.dg.lowerType(lhs_ty);
6183 const llvm_dest_ty = try self.dg.lowerType(dest_ty);
61046184
61056185 const tg = self.dg.module.getTarget();
61066186
......@@ -6208,7 +6288,7 @@ pub const FuncGen = struct {
62086288 ) !*const llvm.Value {
62096289 const target = self.dg.module.getTarget();
62106290 const scalar_ty = ty.scalarType();
6211 const scalar_llvm_ty = try self.dg.llvmType(scalar_ty);
6291 const scalar_llvm_ty = try self.dg.lowerType(scalar_ty);
62126292
62136293 if (intrinsicsAllowed(scalar_ty, target)) {
62146294 const llvm_predicate: llvm.RealPredicate = switch (pred) {
......@@ -6308,8 +6388,8 @@ pub const FuncGen = struct {
63086388 ) !*const llvm.Value {
63096389 const target = self.dg.module.getTarget();
63106390 const scalar_ty = ty.scalarType();
6311 const llvm_ty = try self.dg.llvmType(ty);
6312 const scalar_llvm_ty = try self.dg.llvmType(scalar_ty);
6391 const llvm_ty = try self.dg.lowerType(ty);
6392 const scalar_llvm_ty = try self.dg.lowerType(scalar_ty);
63136393
63146394 const intrinsics_allowed = op != .tan and intrinsicsAllowed(scalar_ty, target);
63156395 var fn_name_buf: [64]u8 = undefined;
......@@ -6403,12 +6483,12 @@ pub const FuncGen = struct {
64036483 const rhs_scalar_ty = rhs_ty.scalarType();
64046484
64056485 const dest_ty = self.air.typeOfIndex(inst);
6406 const llvm_dest_ty = try self.dg.llvmType(dest_ty);
6486 const llvm_dest_ty = try self.dg.lowerType(dest_ty);
64076487
64086488 const tg = self.dg.module.getTarget();
64096489
64106490 const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_scalar_ty.bitSize(tg))
6411 self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_ty), "")
6491 self.builder.buildZExt(rhs, try self.dg.lowerType(lhs_ty), "")
64126492 else
64136493 rhs;
64146494
......@@ -6468,7 +6548,7 @@ pub const FuncGen = struct {
64686548 const tg = self.dg.module.getTarget();
64696549
64706550 const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_scalar_ty.bitSize(tg))
6471 self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_ty), "")
6551 self.builder.buildZExt(rhs, try self.dg.lowerType(lhs_ty), "")
64726552 else
64736553 rhs;
64746554 if (lhs_scalar_ty.isSignedInt()) return self.builder.buildNSWShl(lhs, casted_rhs, "");
......@@ -6491,7 +6571,7 @@ pub const FuncGen = struct {
64916571 const tg = self.dg.module.getTarget();
64926572
64936573 const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_scalar_ty.bitSize(tg))
6494 self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_type), "")
6574 self.builder.buildZExt(rhs, try self.dg.lowerType(lhs_type), "")
64956575 else
64966576 rhs;
64976577 return self.builder.buildShl(lhs, casted_rhs, "");
......@@ -6513,7 +6593,7 @@ pub const FuncGen = struct {
65136593 const tg = self.dg.module.getTarget();
65146594
65156595 const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_scalar_ty.bitSize(tg))
6516 self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_ty), "")
6596 self.builder.buildZExt(rhs, try self.dg.lowerType(lhs_ty), "")
65176597 else
65186598 rhs;
65196599 if (lhs_scalar_ty.isSignedInt()) return self.builder.buildSShlSat(lhs, casted_rhs, "");
......@@ -6536,7 +6616,7 @@ pub const FuncGen = struct {
65366616 const tg = self.dg.module.getTarget();
65376617
65386618 const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_scalar_ty.bitSize(tg))
6539 self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_ty), "")
6619 self.builder.buildZExt(rhs, try self.dg.lowerType(lhs_ty), "")
65406620 else
65416621 rhs;
65426622 const is_signed_int = lhs_scalar_ty.isSignedInt();
......@@ -6564,7 +6644,7 @@ pub const FuncGen = struct {
65646644 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
65656645 const dest_ty = self.air.typeOfIndex(inst);
65666646 const dest_info = dest_ty.intInfo(target);
6567 const dest_llvm_ty = try self.dg.llvmType(dest_ty);
6647 const dest_llvm_ty = try self.dg.lowerType(dest_ty);
65686648 const operand = try self.resolveInst(ty_op.operand);
65696649 const operand_ty = self.air.typeOf(ty_op.operand);
65706650 const operand_info = operand_ty.intInfo(target);
......@@ -6586,7 +6666,7 @@ pub const FuncGen = struct {
65866666
65876667 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
65886668 const operand = try self.resolveInst(ty_op.operand);
6589 const dest_llvm_ty = try self.dg.llvmType(self.air.typeOfIndex(inst));
6669 const dest_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst));
65906670 return self.builder.buildTrunc(operand, dest_llvm_ty, "");
65916671 }
65926672
......@@ -6604,7 +6684,7 @@ pub const FuncGen = struct {
66046684 if (!backendSupportsF80(target) and (src_bits == 80 or dest_bits == 80)) {
66056685 return softF80TruncOrExt(self, operand, src_bits, dest_bits);
66066686 }
6607 const dest_llvm_ty = try self.dg.llvmType(dest_ty);
6687 const dest_llvm_ty = try self.dg.lowerType(dest_ty);
66086688 return self.builder.buildFPTrunc(operand, dest_llvm_ty, "");
66096689 }
66106690
......@@ -6622,7 +6702,7 @@ pub const FuncGen = struct {
66226702 if (!backendSupportsF80(target) and (src_bits == 80 or dest_bits == 80)) {
66236703 return softF80TruncOrExt(self, operand, src_bits, dest_bits);
66246704 }
6625 const dest_llvm_ty = try self.dg.llvmType(self.air.typeOfIndex(inst));
6705 const dest_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst));
66266706 return self.builder.buildFPExt(operand, dest_llvm_ty, "");
66276707 }
66286708
......@@ -6632,7 +6712,7 @@ pub const FuncGen = struct {
66326712
66336713 const un_op = self.air.instructions.items(.data)[inst].un_op;
66346714 const operand = try self.resolveInst(un_op);
6635 const dest_llvm_ty = try self.dg.llvmType(self.air.typeOfIndex(inst));
6715 const dest_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst));
66366716 return self.builder.buildPtrToInt(operand, dest_llvm_ty, "");
66376717 }
66386718
......@@ -6640,12 +6720,12 @@ pub const FuncGen = struct {
66406720 if (self.liveness.isUnused(inst)) return null;
66416721
66426722 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
6643 const operand = try self.resolveInst(ty_op.operand);
66446723 const operand_ty = self.air.typeOf(ty_op.operand);
66456724 const inst_ty = self.air.typeOfIndex(inst);
6725 const operand = try self.resolveInst(ty_op.operand);
66466726 const operand_is_ref = isByRef(operand_ty);
66476727 const result_is_ref = isByRef(inst_ty);
6648 const llvm_dest_ty = try self.dg.llvmType(inst_ty);
6728 const llvm_dest_ty = try self.dg.lowerType(inst_ty);
66496729 const target = self.dg.module.getTarget();
66506730
66516731 if (operand_is_ref and result_is_ref) {
......@@ -6665,14 +6745,14 @@ pub const FuncGen = struct {
66656745 const array_ptr = self.buildAlloca(llvm_dest_ty);
66666746 const bitcast_ok = elem_ty.bitSize(target) == elem_ty.abiSize(target) * 8;
66676747 if (bitcast_ok) {
6668 const llvm_vector_ty = try self.dg.llvmType(operand_ty);
6748 const llvm_vector_ty = try self.dg.lowerType(operand_ty);
66696749 const casted_ptr = self.builder.buildBitCast(array_ptr, llvm_vector_ty.pointerType(0), "");
66706750 const llvm_store = self.builder.buildStore(operand, casted_ptr);
66716751 llvm_store.setAlignment(inst_ty.abiAlignment(target));
66726752 } else {
66736753 // If the ABI size of the element type is not evenly divisible by size in bits;
66746754 // a simple bitcast will not work, and we fall back to extractelement.
6675 const llvm_usize = try self.dg.llvmType(Type.usize);
6755 const llvm_usize = try self.dg.lowerType(Type.usize);
66766756 const llvm_u32 = self.context.intType(32);
66776757 const zero = llvm_usize.constNull();
66786758 const vector_len = operand_ty.arrayLen();
......@@ -6689,7 +6769,7 @@ pub const FuncGen = struct {
66896769 return array_ptr;
66906770 } else if (operand_ty.zigTypeTag() == .Array and inst_ty.zigTypeTag() == .Vector) {
66916771 const elem_ty = operand_ty.childType();
6692 const llvm_vector_ty = try self.dg.llvmType(inst_ty);
6772 const llvm_vector_ty = try self.dg.lowerType(inst_ty);
66936773 if (!operand_is_ref) {
66946774 return self.dg.todo("implement bitcast non-ref array to vector", .{});
66956775 }
......@@ -6706,7 +6786,7 @@ pub const FuncGen = struct {
67066786 } else {
67076787 // If the ABI size of the element type is not evenly divisible by size in bits;
67086788 // a simple bitcast will not work, and we fall back to extractelement.
6709 const llvm_usize = try self.dg.llvmType(Type.usize);
6789 const llvm_usize = try self.dg.lowerType(Type.usize);
67106790 const llvm_u32 = self.context.intType(32);
67116791 const zero = llvm_usize.constNull();
67126792 const vector_len = operand_ty.arrayLen();
......@@ -6738,7 +6818,7 @@ pub const FuncGen = struct {
67386818 const alignment = @maximum(operand_ty.abiAlignment(target), inst_ty.abiAlignment(target));
67396819 const result_ptr = self.buildAlloca(llvm_dest_ty);
67406820 result_ptr.setAlignment(alignment);
6741 const operand_llvm_ty = try self.dg.llvmType(operand_ty);
6821 const operand_llvm_ty = try self.dg.lowerType(operand_ty);
67426822 const casted_ptr = self.builder.buildBitCast(result_ptr, operand_llvm_ty.pointerType(0), "");
67436823 const store_inst = self.builder.buildStore(operand, casted_ptr);
67446824 store_inst.setAlignment(alignment);
......@@ -6752,7 +6832,7 @@ pub const FuncGen = struct {
67526832 const alignment = @maximum(operand_ty.abiAlignment(target), inst_ty.abiAlignment(target));
67536833 const result_ptr = self.buildAlloca(llvm_dest_ty);
67546834 result_ptr.setAlignment(alignment);
6755 const operand_llvm_ty = try self.dg.llvmType(operand_ty);
6835 const operand_llvm_ty = try self.dg.lowerType(operand_ty);
67566836 const casted_ptr = self.builder.buildBitCast(result_ptr, operand_llvm_ty.pointerType(0), "");
67576837 const store_inst = self.builder.buildStore(operand, casted_ptr);
67586838 store_inst.setAlignment(alignment);
......@@ -6826,7 +6906,7 @@ pub const FuncGen = struct {
68266906 const pointee_type = ptr_ty.childType();
68276907 if (!pointee_type.isFnOrHasRuntimeBitsIgnoreComptime()) return self.dg.lowerPtrToVoid(ptr_ty);
68286908
6829 const pointee_llvm_ty = try self.dg.llvmType(pointee_type);
6909 const pointee_llvm_ty = try self.dg.lowerType(pointee_type);
68306910 const alloca_inst = self.buildAlloca(pointee_llvm_ty);
68316911 const target = self.dg.module.getTarget();
68326912 const alignment = ptr_ty.ptrAlignment(target);
......@@ -6840,7 +6920,7 @@ pub const FuncGen = struct {
68406920 const ret_ty = ptr_ty.childType();
68416921 if (!ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) return self.dg.lowerPtrToVoid(ptr_ty);
68426922 if (self.ret_ptr) |ret_ptr| return ret_ptr;
6843 const ret_llvm_ty = try self.dg.llvmType(ret_ty);
6923 const ret_llvm_ty = try self.dg.lowerType(ret_ty);
68446924 const target = self.dg.module.getTarget();
68456925 const alloca_inst = self.buildAlloca(ret_llvm_ty);
68466926 alloca_inst.setAlignment(ptr_ty.ptrAlignment(target));
......@@ -6871,7 +6951,7 @@ pub const FuncGen = struct {
68716951 const dest_ptr_u8 = self.builder.buildBitCast(dest_ptr, ptr_u8_llvm_ty, "");
68726952 const fill_char = u8_llvm_ty.constInt(0xaa, .False);
68736953 const dest_ptr_align = ptr_ty.ptrAlignment(target);
6874 const usize_llvm_ty = try self.dg.llvmType(Type.usize);
6954 const usize_llvm_ty = try self.dg.lowerType(Type.usize);
68756955 const len = usize_llvm_ty.constInt(operand_size, .False);
68766956 _ = self.builder.buildMemSet(dest_ptr_u8, fill_char, len, dest_ptr_align, ptr_ty.isVolatilePtr());
68776957 if (self.dg.module.comp.bin_file.options.valgrind) {
......@@ -6908,7 +6988,7 @@ pub const FuncGen = struct {
69086988 const llvm_fn = self.getIntrinsic("llvm.returnaddress", &.{});
69096989 const params = [_]*const llvm.Value{llvm_i32.constNull()};
69106990 const ptr_val = self.builder.buildCall(llvm_fn, &params, params.len, .Fast, .Auto, "");
6911 const llvm_usize = try self.dg.llvmType(Type.usize);
6991 const llvm_usize = try self.dg.lowerType(Type.usize);
69126992 return self.builder.buildPtrToInt(ptr_val, llvm_usize, "");
69136993 }
69146994
......@@ -6926,7 +7006,7 @@ pub const FuncGen = struct {
69267006
69277007 const params = [_]*const llvm.Value{llvm_i32.constNull()};
69287008 const ptr_val = self.builder.buildCall(llvm_fn, &params, params.len, .Fast, .Auto, "");
6929 const llvm_usize = try self.dg.llvmType(Type.usize);
7009 const llvm_usize = try self.dg.lowerType(Type.usize);
69307010 return self.builder.buildPtrToInt(ptr_val, llvm_usize, "");
69317011 }
69327012
......@@ -6971,15 +7051,15 @@ pub const FuncGen = struct {
69717051
69727052 var payload = self.builder.buildExtractValue(result, 0, "");
69737053 if (opt_abi_ty != null) {
6974 payload = self.builder.buildTrunc(payload, try self.dg.llvmType(operand_ty), "");
7054 payload = self.builder.buildTrunc(payload, try self.dg.lowerType(operand_ty), "");
69757055 }
69767056 const success_bit = self.builder.buildExtractValue(result, 1, "");
69777057
6978 if (optional_ty.isPtrLikeOptional()) {
7058 if (optional_ty.optionalReprIsPayload()) {
69797059 return self.builder.buildSelect(success_bit, payload.typeOf().constNull(), payload, "");
69807060 }
69817061
6982 const optional_llvm_ty = try self.dg.llvmType(optional_ty);
7062 const optional_llvm_ty = try self.dg.lowerType(optional_ty);
69837063 const non_null_bit = self.builder.buildNot(success_bit, "");
69847064 const partial = self.builder.buildInsertValue(optional_llvm_ty.getUndef(), payload, 0, "");
69857065 return self.builder.buildInsertValue(partial, non_null_bit, 1, "");
......@@ -7015,7 +7095,7 @@ pub const FuncGen = struct {
70157095 ordering,
70167096 single_threaded,
70177097 );
7018 const operand_llvm_ty = try self.dg.llvmType(operand_ty);
7098 const operand_llvm_ty = try self.dg.lowerType(operand_ty);
70197099 if (is_float) {
70207100 return self.builder.buildBitCast(uncasted_result, operand_llvm_ty, "");
70217101 } else {
......@@ -7028,7 +7108,7 @@ pub const FuncGen = struct {
70287108 }
70297109
70307110 // It's a pointer but we need to treat it as an int.
7031 const usize_llvm_ty = try self.dg.llvmType(Type.usize);
7111 const usize_llvm_ty = try self.dg.lowerType(Type.usize);
70327112 const casted_ptr = self.builder.buildBitCast(ptr, usize_llvm_ty.pointerType(0), "");
70337113 const casted_operand = self.builder.buildPtrToInt(operand, usize_llvm_ty, "");
70347114 const uncasted_result = self.builder.buildAtomicRmw(
......@@ -7038,7 +7118,7 @@ pub const FuncGen = struct {
70387118 ordering,
70397119 single_threaded,
70407120 );
7041 const operand_llvm_ty = try self.dg.llvmType(operand_ty);
7121 const operand_llvm_ty = try self.dg.lowerType(operand_ty);
70427122 return self.builder.buildIntToPtr(uncasted_result, operand_llvm_ty, "");
70437123 }
70447124
......@@ -7057,7 +7137,7 @@ pub const FuncGen = struct {
70577137 const casted_ptr = self.builder.buildBitCast(ptr, abi_ty.pointerType(0), "");
70587138 const load_inst = (try self.load(casted_ptr, ptr_ty)).?;
70597139 load_inst.setOrdering(ordering);
7060 return self.builder.buildTrunc(load_inst, try self.dg.llvmType(operand_ty), "");
7140 return self.builder.buildTrunc(load_inst, try self.dg.lowerType(operand_ty), "");
70617141 }
70627142 const load_inst = (try self.load(ptr, ptr_ty)).?;
70637143 load_inst.setOrdering(ordering);
......@@ -7198,13 +7278,13 @@ pub const FuncGen = struct {
71987278 const operand = try self.resolveInst(ty_op.operand);
71997279
72007280 const llvm_i1 = self.context.intType(1);
7201 const operand_llvm_ty = try self.dg.llvmType(operand_ty);
7281 const operand_llvm_ty = try self.dg.lowerType(operand_ty);
72027282 const fn_val = self.getIntrinsic(llvm_fn_name, &.{operand_llvm_ty});
72037283
72047284 const params = [_]*const llvm.Value{ operand, llvm_i1.constNull() };
72057285 const wrong_size_result = self.builder.buildCall(fn_val, &params, params.len, .C, .Auto, "");
72067286 const result_ty = self.air.typeOfIndex(inst);
7207 const result_llvm_ty = try self.dg.llvmType(result_ty);
7287 const result_llvm_ty = try self.dg.lowerType(result_ty);
72087288
72097289 const target = self.dg.module.getTarget();
72107290 const bits = operand_ty.intInfo(target).bits;
......@@ -7226,12 +7306,12 @@ pub const FuncGen = struct {
72267306 const operand = try self.resolveInst(ty_op.operand);
72277307
72287308 const params = [_]*const llvm.Value{operand};
7229 const operand_llvm_ty = try self.dg.llvmType(operand_ty);
7309 const operand_llvm_ty = try self.dg.lowerType(operand_ty);
72307310 const fn_val = self.getIntrinsic(llvm_fn_name, &.{operand_llvm_ty});
72317311
72327312 const wrong_size_result = self.builder.buildCall(fn_val, &params, params.len, .C, .Auto, "");
72337313 const result_ty = self.air.typeOfIndex(inst);
7234 const result_llvm_ty = try self.dg.llvmType(result_ty);
7314 const result_llvm_ty = try self.dg.lowerType(result_ty);
72357315
72367316 const target = self.dg.module.getTarget();
72377317 const bits = operand_ty.intInfo(target).bits;
......@@ -7255,7 +7335,7 @@ pub const FuncGen = struct {
72557335 assert(bits % 8 == 0);
72567336
72577337 var operand = try self.resolveInst(ty_op.operand);
7258 var operand_llvm_ty = try self.dg.llvmType(operand_ty);
7338 var operand_llvm_ty = try self.dg.lowerType(operand_ty);
72597339
72607340 if (bits % 16 == 8) {
72617341 // If not an even byte-multiple, we need zero-extend + shift-left 1 byte
......@@ -7289,7 +7369,7 @@ pub const FuncGen = struct {
72897369 const wrong_size_result = self.builder.buildCall(fn_val, &params, params.len, .C, .Auto, "");
72907370
72917371 const result_ty = self.air.typeOfIndex(inst);
7292 const result_llvm_ty = try self.dg.llvmType(result_ty);
7372 const result_llvm_ty = try self.dg.lowerType(result_ty);
72937373 const result_bits = result_ty.intInfo(target).bits;
72947374 if (bits > result_bits) {
72957375 return self.builder.buildTrunc(wrong_size_result, result_llvm_ty, "");
......@@ -7332,14 +7412,14 @@ pub const FuncGen = struct {
73327412 }
73337413
73347414 const slice_ty = Type.initTag(.const_slice_u8_sentinel_0);
7335 const llvm_ret_ty = try self.dg.llvmType(slice_ty);
7336 const usize_llvm_ty = try self.dg.llvmType(Type.usize);
7415 const llvm_ret_ty = try self.dg.lowerType(slice_ty);
7416 const usize_llvm_ty = try self.dg.lowerType(Type.usize);
73377417 const target = self.dg.module.getTarget();
73387418 const slice_alignment = slice_ty.abiAlignment(target);
73397419
73407420 var int_tag_type_buffer: Type.Payload.Bits = undefined;
73417421 const int_tag_ty = enum_ty.intTagType(&int_tag_type_buffer);
7342 const param_types = [_]*const llvm.Type{try self.dg.llvmType(int_tag_ty)};
7422 const param_types = [_]*const llvm.Type{try self.dg.lowerType(int_tag_ty)};
73437423
73447424 const fn_type = llvm.functionType(llvm_ret_ty, &param_types, param_types.len, .False);
73457425 const fn_val = self.dg.object.llvm_module.addFunction(llvm_fn_name, fn_type);
......@@ -7396,7 +7476,7 @@ pub const FuncGen = struct {
73967476 .base = .{ .tag = .enum_field_index },
73977477 .data = @intCast(u32, field_index),
73987478 };
7399 break :int try self.dg.genTypedValue(.{
7479 break :int try self.dg.lowerValue(.{
74007480 .ty = enum_ty,
74017481 .val = Value.initPayload(&tag_val_payload.base),
74027482 });
......@@ -7421,8 +7501,8 @@ pub const FuncGen = struct {
74217501
74227502 // Function signature: fn (anyerror) bool
74237503
7424 const ret_llvm_ty = try self.dg.llvmType(Type.bool);
7425 const anyerror_llvm_ty = try self.dg.llvmType(Type.anyerror);
7504 const ret_llvm_ty = try self.dg.lowerType(Type.bool);
7505 const anyerror_llvm_ty = try self.dg.lowerType(Type.anyerror);
74267506 const param_types = [_]*const llvm.Type{anyerror_llvm_ty};
74277507
74287508 const fn_type = llvm.functionType(ret_llvm_ty, &param_types, param_types.len, .False);
......@@ -7531,7 +7611,7 @@ pub const FuncGen = struct {
75317611 .Add => switch (scalar_ty.zigTypeTag()) {
75327612 .Int => return self.builder.buildAddReduce(operand),
75337613 .Float => {
7534 const scalar_llvm_ty = try self.dg.llvmType(scalar_ty);
7614 const scalar_llvm_ty = try self.dg.lowerType(scalar_ty);
75357615 const neutral_value = scalar_llvm_ty.constReal(-0.0);
75367616 return self.builder.buildFPAddReduce(neutral_value, operand);
75377617 },
......@@ -7540,7 +7620,7 @@ pub const FuncGen = struct {
75407620 .Mul => switch (scalar_ty.zigTypeTag()) {
75417621 .Int => return self.builder.buildMulReduce(operand),
75427622 .Float => {
7543 const scalar_llvm_ty = try self.dg.llvmType(scalar_ty);
7623 const scalar_llvm_ty = try self.dg.lowerType(scalar_ty);
75447624 const neutral_value = scalar_llvm_ty.constReal(1.0);
75457625 return self.builder.buildFPMulReduce(neutral_value, operand);
75467626 },
......@@ -7556,7 +7636,7 @@ pub const FuncGen = struct {
75567636 const result_ty = self.air.typeOfIndex(inst);
75577637 const len = @intCast(usize, result_ty.arrayLen());
75587638 const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]);
7559 const llvm_result_ty = try self.dg.llvmType(result_ty);
7639 const llvm_result_ty = try self.dg.lowerType(result_ty);
75607640 const target = self.dg.module.getTarget();
75617641
75627642 switch (result_ty.zigTypeTag()) {
......@@ -7644,7 +7724,7 @@ pub const FuncGen = struct {
76447724 .Array => {
76457725 assert(isByRef(result_ty));
76467726
7647 const llvm_usize = try self.dg.llvmType(Type.usize);
7727 const llvm_usize = try self.dg.lowerType(Type.usize);
76487728 const alloca_inst = self.buildAlloca(llvm_result_ty);
76497729 alloca_inst.setAlignment(result_ty.abiAlignment(target));
76507730
......@@ -7679,7 +7759,7 @@ pub const FuncGen = struct {
76797759 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
76807760 const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data;
76817761 const union_ty = self.air.typeOfIndex(inst);
7682 const union_llvm_ty = try self.dg.llvmType(union_ty);
7762 const union_llvm_ty = try self.dg.lowerType(union_ty);
76837763 const target = self.dg.module.getTarget();
76847764 const layout = union_ty.unionGetLayout(target);
76857765 if (layout.payload_size == 0) {
......@@ -7699,8 +7779,8 @@ pub const FuncGen = struct {
76997779 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
77007780 assert(union_obj.haveFieldTypes());
77017781 const field = union_obj.fields.values()[extra.field_index];
7702 const field_llvm_ty = try self.dg.llvmType(field.ty);
7703 const tag_llvm_ty = try self.dg.llvmType(union_obj.tag_ty);
7782 const field_llvm_ty = try self.dg.lowerType(field.ty);
7783 const tag_llvm_ty = try self.dg.lowerType(union_obj.tag_ty);
77047784 const field_size = field.ty.abiSize(target);
77057785 const field_align = field.normalAlignment(target);
77067786
......@@ -7936,7 +8016,7 @@ pub const FuncGen = struct {
79368016
79378017 const slice_ty = Type.initTag(.const_slice_u8_sentinel_0);
79388018 const slice_alignment = slice_ty.abiAlignment(self.dg.module.getTarget());
7939 const llvm_slice_ty = try self.dg.llvmType(slice_ty);
8019 const llvm_slice_ty = try self.dg.lowerType(slice_ty);
79408020 const llvm_slice_ptr_ty = llvm_slice_ty.pointerType(0); // TODO: Address space
79418021
79428022 const error_name_table_global = self.dg.object.llvm_module.addGlobal(llvm_slice_ptr_ty, "__zig_err_name_table");
......@@ -8000,7 +8080,7 @@ pub const FuncGen = struct {
80008080 // out the relevant bits when accessing the pointee.
80018081 // Here we perform a bitcast because we want to use the host_size
80028082 // as the llvm pointer element type.
8003 const result_llvm_ty = try self.dg.llvmType(self.air.typeOfIndex(inst));
8083 const result_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst));
80048084 // TODO this can be removed if we change host_size to be bits instead
80058085 // of bytes.
80068086 return self.builder.buildBitCast(struct_ptr, result_llvm_ty, "");
......@@ -8015,7 +8095,7 @@ pub const FuncGen = struct {
80158095 // end of the struct. Treat our struct pointer as an array of two and get
80168096 // the index to the element at index `1` to get a pointer to the end of
80178097 // the struct.
8018 const llvm_usize = try self.dg.llvmType(Type.usize);
8098 const llvm_usize = try self.dg.lowerType(Type.usize);
80198099 const llvm_index = llvm_usize.constInt(1, .False);
80208100 const indices: [1]*const llvm.Value = .{llvm_index};
80218101 return self.builder.buildInBoundsGEP(struct_ptr, &indices, indices.len, "");
......@@ -8036,7 +8116,7 @@ pub const FuncGen = struct {
80368116 ) !?*const llvm.Value {
80378117 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
80388118 const field = &union_obj.fields.values()[field_index];
8039 const result_llvm_ty = try self.dg.llvmType(self.air.typeOfIndex(inst));
8119 const result_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst));
80408120 if (!field.ty.hasRuntimeBitsIgnoreComptime()) {
80418121 return null;
80428122 }
......@@ -8075,7 +8155,7 @@ pub const FuncGen = struct {
80758155 const ptr_volatile = llvm.Bool.fromBool(ptr_ty.isVolatilePtr());
80768156 if (info.host_size == 0) {
80778157 if (isByRef(info.pointee_type)) {
8078 const elem_llvm_ty = try self.dg.llvmType(info.pointee_type);
8158 const elem_llvm_ty = try self.dg.lowerType(info.pointee_type);
80798159 const result_align = info.pointee_type.abiAlignment(target);
80808160 const max_align = @maximum(result_align, ptr_alignment);
80818161 const result_ptr = self.buildAlloca(elem_llvm_ty);
......@@ -8108,7 +8188,7 @@ pub const FuncGen = struct {
81088188 const elem_bits = @intCast(c_uint, ptr_ty.elemType().bitSize(target));
81098189 const shift_amt = containing_int.typeOf().constInt(info.bit_offset, .False);
81108190 const shifted_value = self.builder.buildLShr(containing_int, shift_amt, "");
8111 const elem_llvm_ty = try self.dg.llvmType(info.pointee_type);
8191 const elem_llvm_ty = try self.dg.lowerType(info.pointee_type);
81128192
81138193 if (isByRef(info.pointee_type)) {
81148194 const result_align = info.pointee_type.abiAlignment(target);
......@@ -8546,7 +8626,14 @@ fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool
85468626/// be effectively bitcasted to the actual return type.
85478627fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm.Type {
85488628 if (!fn_info.return_type.hasRuntimeBitsIgnoreComptime()) {
8549 return dg.context.voidType();
8629 // If the return type is an error set or an error union, then we make this
8630 // anyerror return type instead, so that it can be coerced into a function
8631 // pointer type which has anyerror as the return type.
8632 if (fn_info.return_type.isError()) {
8633 return dg.lowerType(Type.anyerror);
8634 } else {
8635 return dg.context.voidType();
8636 }
85508637 }
85518638 const target = dg.module.getTarget();
85528639 switch (fn_info.cc) {
......@@ -8554,7 +8641,7 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm.
85548641 if (isByRef(fn_info.return_type)) {
85558642 return dg.context.voidType();
85568643 } else {
8557 return dg.llvmType(fn_info.return_type);
8644 return dg.lowerType(fn_info.return_type);
85588645 }
85598646 },
85608647 .C => {
......@@ -8575,24 +8662,24 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm.
85758662 else => false,
85768663 };
85778664 switch (target.cpu.arch) {
8578 .mips, .mipsel => return dg.llvmType(fn_info.return_type),
8665 .mips, .mipsel => return dg.lowerType(fn_info.return_type),
85798666 .x86_64 => switch (target.os.tag) {
85808667 .windows => switch (x86_64_abi.classifyWindows(fn_info.return_type, target)) {
85818668 .integer => {
85828669 if (is_scalar) {
8583 return dg.llvmType(fn_info.return_type);
8670 return dg.lowerType(fn_info.return_type);
85848671 } else {
85858672 const abi_size = fn_info.return_type.abiSize(target);
85868673 return dg.context.intType(@intCast(c_uint, abi_size * 8));
85878674 }
85888675 },
85898676 .memory => return dg.context.voidType(),
8590 .sse => return dg.llvmType(fn_info.return_type),
8677 .sse => return dg.lowerType(fn_info.return_type),
85918678 else => unreachable,
85928679 },
85938680 else => {
85948681 if (is_scalar) {
8595 return dg.llvmType(fn_info.return_type);
8682 return dg.lowerType(fn_info.return_type);
85968683 }
85978684 const classes = x86_64_abi.classifySystemV(fn_info.return_type, target);
85988685 if (classes[0] == .memory) {
......@@ -8633,10 +8720,10 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm.
86338720 },
86348721 },
86358722 // TODO investigate C ABI for other architectures
8636 else => return dg.llvmType(fn_info.return_type),
8723 else => return dg.lowerType(fn_info.return_type),
86378724 }
86388725 },
8639 else => return dg.llvmType(fn_info.return_type),
8726 else => return dg.lowerType(fn_info.return_type),
86408727 }
86418728}
86428729
......@@ -8991,3 +9078,11 @@ fn buildAllocaInner(
89919078
89929079 return builder.buildAlloca(llvm_ty, "");
89939080}
9081
9082fn errUnionPayloadOffset(payload_ty: Type, target: std.Target) u1 {
9083 return @boolToInt(Type.anyerror.abiAlignment(target) > payload_ty.abiAlignment(target));
9084}
9085
9086fn errUnionErrorOffset(payload_ty: Type, target: std.Target) u1 {
9087 return @boolToInt(Type.anyerror.abiAlignment(target) <= payload_ty.abiAlignment(target));
9088}
src/link/Dwarf.zig+6-4
......@@ -498,9 +498,11 @@ pub const DeclState = struct {
498498 .ErrorUnion => {
499499 const error_ty = ty.errorUnionSet();
500500 const payload_ty = ty.errorUnionPayload();
501 const payload_align = payload_ty.abiAlignment(target);
502 const error_align = Type.anyerror.abiAlignment(target);
501503 const abi_size = ty.abiSize(target);
502 const abi_align = ty.abiAlignment(target);
503 const payload_off = mem.alignForwardGeneric(u64, error_ty.abiSize(target), abi_align);
504 const payload_off = if (error_align >= payload_align) Type.anyerror.abiSize(target) else 0;
505 const error_off = if (error_align >= payload_align) 0 else payload_ty.abiSize(target);
504506
505507 // DW.AT.structure_type
506508 try dbg_info_buffer.append(@enumToInt(AbbrevKind.struct_type));
......@@ -534,7 +536,7 @@ pub const DeclState = struct {
534536 try dbg_info_buffer.resize(index + 4);
535537 try self.addTypeReloc(atom, error_ty, @intCast(u32, index), null);
536538 // DW.AT.data_member_location, DW.FORM.sdata
537 try dbg_info_buffer.append(0);
539 try leb128.writeULEB128(dbg_info_buffer.writer(), error_off);
538540
539541 // DW.AT.structure_type delimit children
540542 try dbg_info_buffer.append(0);
......@@ -2293,7 +2295,7 @@ fn addDbgInfoErrorSet(
22932295 // DW.AT.enumeration_type
22942296 try dbg_info_buffer.append(@enumToInt(AbbrevKind.enum_type));
22952297 // DW.AT.byte_size, DW.FORM.sdata
2296 const abi_size = ty.abiSize(target);
2298 const abi_size = Type.anyerror.abiSize(target);
22972299 try leb128.writeULEB128(dbg_info_buffer.writer(), abi_size);
22982300 // DW.AT.name, DW.FORM.string
22992301 const name = try ty.nameAllocArena(arena, module);
src/type.zig+298-60
......@@ -2317,10 +2317,7 @@ pub const Type = extern union {
23172317 .const_slice_u8_sentinel_0,
23182318 .array_u8_sentinel_0,
23192319 .anyerror_void_error_union,
2320 .error_set,
2321 .error_set_single,
23222320 .error_set_inferred,
2323 .error_set_merged,
23242321 .manyptr_u8,
23252322 .manyptr_const_u8,
23262323 .manyptr_const_u8_sentinel_0,
......@@ -2361,12 +2358,23 @@ pub const Type = extern union {
23612358 .fn_void_no_args,
23622359 .fn_naked_noreturn_no_args,
23632360 .fn_ccc_void_no_args,
2361 .error_set_single,
23642362 => return false,
23652363
2364 .error_set => {
2365 const err_set_obj = ty.castTag(.error_set).?.data;
2366 const names = err_set_obj.names.keys();
2367 return names.len > 1;
2368 },
2369 .error_set_merged => {
2370 const name_map = ty.castTag(.error_set_merged).?.data;
2371 const names = name_map.keys();
2372 return names.len > 1;
2373 },
2374
23662375 // These types have more than one possible value, so the result is the same as
23672376 // asking whether they are comptime-only types.
23682377 .anyframe_T,
2369 .optional,
23702378 .optional_single_mut_pointer,
23712379 .optional_single_const_pointer,
23722380 .single_const_pointer,
......@@ -2388,6 +2396,41 @@ pub const Type = extern union {
23882396 }
23892397 },
23902398
2399 .optional => {
2400 var buf: Payload.ElemType = undefined;
2401 const child_ty = ty.optionalChild(&buf);
2402 if (child_ty.isNoReturn()) {
2403 // Then the optional is comptime-known to be null.
2404 return false;
2405 }
2406 if (ignore_comptime_only) {
2407 return true;
2408 } else if (sema_kit) |sk| {
2409 return !(try sk.sema.typeRequiresComptime(sk.block, sk.src, child_ty));
2410 } else {
2411 return !comptimeOnly(child_ty);
2412 }
2413 },
2414
2415 .error_union => {
2416 // This code needs to be kept in sync with the equivalent switch prong
2417 // in abiSizeAdvanced.
2418 const data = ty.castTag(.error_union).?.data;
2419 switch (data.error_set.errorSetCardinality()) {
2420 .zero => return hasRuntimeBitsAdvanced(data.payload, ignore_comptime_only, sema_kit),
2421 .one => return !data.payload.isNoReturn(),
2422 .many => {
2423 if (ignore_comptime_only) {
2424 return true;
2425 } else if (sema_kit) |sk| {
2426 return !(try sk.sema.typeRequiresComptime(sk.block, sk.src, ty));
2427 } else {
2428 return !comptimeOnly(ty);
2429 }
2430 },
2431 }
2432 },
2433
23912434 .@"struct" => {
23922435 const struct_obj = ty.castTag(.@"struct").?.data;
23932436 if (sema_kit) |sk| {
......@@ -2467,12 +2510,6 @@ pub const Type = extern union {
24672510
24682511 .int_signed, .int_unsigned => return ty.cast(Payload.Bits).?.data != 0,
24692512
2470 .error_union => {
2471 const payload = ty.castTag(.error_union).?.data;
2472 return (try payload.error_set.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit)) or
2473 (try payload.payload.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit));
2474 },
2475
24762513 .tuple, .anon_struct => {
24772514 const tuple = ty.tupleFields();
24782515 for (tuple.types) |field_ty, i| {
......@@ -2647,13 +2684,22 @@ pub const Type = extern union {
26472684 };
26482685 }
26492686
2650 pub fn isNoReturn(self: Type) bool {
2651 const definitely_correct_result =
2652 self.tag_if_small_enough != .bound_fn and
2653 self.zigTypeTag() == .NoReturn;
2654 const fast_result = self.tag_if_small_enough == Tag.noreturn;
2655 assert(fast_result == definitely_correct_result);
2656 return fast_result;
2687 /// TODO add enums with no fields here
2688 pub fn isNoReturn(ty: Type) bool {
2689 switch (ty.tag()) {
2690 .noreturn => return true,
2691 .error_set => {
2692 const err_set_obj = ty.castTag(.error_set).?.data;
2693 const names = err_set_obj.names.keys();
2694 return names.len == 0;
2695 },
2696 .error_set_merged => {
2697 const name_map = ty.castTag(.error_set_merged).?.data;
2698 const names = name_map.keys();
2699 return names.len == 0;
2700 },
2701 else => return false,
2702 }
26572703 }
26582704
26592705 /// Returns 0 if the pointer is naturally aligned and the element type is 0-bit.
......@@ -2852,13 +2898,30 @@ pub const Type = extern union {
28522898 else => unreachable,
28532899 },
28542900
2855 .error_set,
2856 .error_set_single,
2901 // TODO revisit this when we have the concept of the error tag type
28572902 .anyerror_void_error_union,
28582903 .anyerror,
28592904 .error_set_inferred,
2860 .error_set_merged,
2861 => return AbiAlignmentAdvanced{ .scalar = 2 }, // TODO revisit this when we have the concept of the error tag type
2905 => return AbiAlignmentAdvanced{ .scalar = 2 },
2906
2907 .error_set => {
2908 const err_set_obj = ty.castTag(.error_set).?.data;
2909 const names = err_set_obj.names.keys();
2910 if (names.len <= 1) {
2911 return AbiAlignmentAdvanced{ .scalar = 0 };
2912 } else {
2913 return AbiAlignmentAdvanced{ .scalar = 2 };
2914 }
2915 },
2916 .error_set_merged => {
2917 const name_map = ty.castTag(.error_set_merged).?.data;
2918 const names = name_map.keys();
2919 if (names.len <= 1) {
2920 return AbiAlignmentAdvanced{ .scalar = 0 };
2921 } else {
2922 return AbiAlignmentAdvanced{ .scalar = 2 };
2923 }
2924 },
28622925
28632926 .array, .array_sentinel => return ty.elemType().abiAlignmentAdvanced(target, strat),
28642927
......@@ -2881,8 +2944,16 @@ pub const Type = extern union {
28812944 var buf: Payload.ElemType = undefined;
28822945 const child_type = ty.optionalChild(&buf);
28832946
2884 if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr()) {
2885 return AbiAlignmentAdvanced{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) };
2947 switch (child_type.zigTypeTag()) {
2948 .Pointer => return AbiAlignmentAdvanced{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) },
2949 .ErrorSet => switch (child_type.errorSetCardinality()) {
2950 // `?error{}` is comptime-known to be null.
2951 .zero => return AbiAlignmentAdvanced{ .scalar = 0 },
2952 .one => return AbiAlignmentAdvanced{ .scalar = 1 },
2953 .many => return abiAlignmentAdvanced(Type.anyerror, target, strat),
2954 },
2955 .NoReturn => return AbiAlignmentAdvanced{ .scalar = 0 },
2956 else => {},
28862957 }
28872958
28882959 switch (strat) {
......@@ -2900,31 +2971,35 @@ pub const Type = extern union {
29002971 },
29012972
29022973 .error_union => {
2974 // This code needs to be kept in sync with the equivalent switch prong
2975 // in abiSizeAdvanced.
29032976 const data = ty.castTag(.error_union).?.data;
2977 switch (data.error_set.errorSetCardinality()) {
2978 .zero => return abiAlignmentAdvanced(data.payload, target, strat),
2979 .one => {
2980 if (data.payload.isNoReturn()) {
2981 return AbiAlignmentAdvanced{ .scalar = 0 };
2982 }
2983 },
2984 .many => {},
2985 }
2986 const code_align = abiAlignment(Type.anyerror, target);
29042987 switch (strat) {
29052988 .eager, .sema_kit => {
2906 if (!(try data.error_set.hasRuntimeBitsAdvanced(false, sema_kit))) {
2907 return data.payload.abiAlignmentAdvanced(target, strat);
2908 } else if (!(try data.payload.hasRuntimeBitsAdvanced(false, sema_kit))) {
2909 return data.error_set.abiAlignmentAdvanced(target, strat);
2989 if (!(try data.payload.hasRuntimeBitsAdvanced(false, sema_kit))) {
2990 return AbiAlignmentAdvanced{ .scalar = code_align };
29102991 }
29112992 return AbiAlignmentAdvanced{ .scalar = @maximum(
2993 code_align,
29122994 (try data.payload.abiAlignmentAdvanced(target, strat)).scalar,
2913 (try data.error_set.abiAlignmentAdvanced(target, strat)).scalar,
29142995 ) };
29152996 },
29162997 .lazy => |arena| {
29172998 switch (try data.payload.abiAlignmentAdvanced(target, strat)) {
29182999 .scalar => |payload_align| {
2919 if (payload_align == 0) {
2920 return data.error_set.abiAlignmentAdvanced(target, strat);
2921 }
2922 switch (try data.error_set.abiAlignmentAdvanced(target, strat)) {
2923 .scalar => |err_set_align| {
2924 return AbiAlignmentAdvanced{ .scalar = @maximum(payload_align, err_set_align) };
2925 },
2926 .val => {},
2927 }
3000 return AbiAlignmentAdvanced{
3001 .scalar = @maximum(code_align, payload_align),
3002 };
29283003 },
29293004 .val => {},
29303005 }
......@@ -3018,6 +3093,7 @@ pub const Type = extern union {
30183093 .@"undefined",
30193094 .enum_literal,
30203095 .type_info,
3096 .error_set_single,
30213097 => return AbiAlignmentAdvanced{ .scalar = 0 },
30223098
30233099 .noreturn,
......@@ -3136,6 +3212,7 @@ pub const Type = extern union {
31363212 .empty_struct_literal,
31373213 .empty_struct,
31383214 .void,
3215 .error_set_single,
31393216 => return AbiSizeAdvanced{ .scalar = 0 },
31403217
31413218 .@"struct", .tuple, .anon_struct => switch (ty.containerLayout()) {
......@@ -3291,14 +3368,30 @@ pub const Type = extern union {
32913368 },
32923369
32933370 // TODO revisit this when we have the concept of the error tag type
3294 .error_set,
3295 .error_set_single,
32963371 .anyerror_void_error_union,
32973372 .anyerror,
32983373 .error_set_inferred,
3299 .error_set_merged,
33003374 => return AbiSizeAdvanced{ .scalar = 2 },
33013375
3376 .error_set => {
3377 const err_set_obj = ty.castTag(.error_set).?.data;
3378 const names = err_set_obj.names.keys();
3379 if (names.len <= 1) {
3380 return AbiSizeAdvanced{ .scalar = 0 };
3381 } else {
3382 return AbiSizeAdvanced{ .scalar = 2 };
3383 }
3384 },
3385 .error_set_merged => {
3386 const name_map = ty.castTag(.error_set_merged).?.data;
3387 const names = name_map.keys();
3388 if (names.len <= 1) {
3389 return AbiSizeAdvanced{ .scalar = 0 };
3390 } else {
3391 return AbiSizeAdvanced{ .scalar = 2 };
3392 }
3393 },
3394
33023395 .i16, .u16 => return AbiSizeAdvanced{ .scalar = intAbiSize(16, target) },
33033396 .i32, .u32 => return AbiSizeAdvanced{ .scalar = intAbiSize(32, target) },
33043397 .i64, .u64 => return AbiSizeAdvanced{ .scalar = intAbiSize(64, target) },
......@@ -3312,37 +3405,81 @@ pub const Type = extern union {
33123405 .optional => {
33133406 var buf: Payload.ElemType = undefined;
33143407 const child_type = ty.optionalChild(&buf);
3408
3409 if (child_type.isNoReturn()) {
3410 return AbiSizeAdvanced{ .scalar = 0 };
3411 }
3412
33153413 if (!child_type.hasRuntimeBits()) return AbiSizeAdvanced{ .scalar = 1 };
33163414
3317 if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr() and !child_type.isSlice())
3318 return AbiSizeAdvanced{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) };
3415 switch (child_type.zigTypeTag()) {
3416 .Pointer => {
3417 const ptr_info = child_type.ptrInfo().data;
3418 const has_null = switch (ptr_info.size) {
3419 .Slice, .C => true,
3420 else => ptr_info.@"allowzero",
3421 };
3422 if (!has_null) {
3423 const ptr_size_bytes = @divExact(target.cpu.arch.ptrBitWidth(), 8);
3424 return AbiSizeAdvanced{ .scalar = ptr_size_bytes };
3425 }
3426 },
3427 .ErrorSet => return abiSizeAdvanced(Type.anyerror, target, strat),
3428 else => {},
3429 }
33193430
33203431 // Optional types are represented as a struct with the child type as the first
33213432 // field and a boolean as the second. Since the child type's abi alignment is
33223433 // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal
33233434 // to the child type's ABI alignment.
3324 return AbiSizeAdvanced{ .scalar = child_type.abiAlignment(target) + child_type.abiSize(target) };
3435 return AbiSizeAdvanced{
3436 .scalar = child_type.abiAlignment(target) + child_type.abiSize(target),
3437 };
33253438 },
33263439
33273440 .error_union => {
3441 // This code needs to be kept in sync with the equivalent switch prong
3442 // in abiAlignmentAdvanced.
33283443 const data = ty.castTag(.error_union).?.data;
3329 if (!data.error_set.hasRuntimeBits() and !data.payload.hasRuntimeBits()) {
3330 return AbiSizeAdvanced{ .scalar = 0 };
3331 } else if (!data.error_set.hasRuntimeBits()) {
3332 return AbiSizeAdvanced{ .scalar = data.payload.abiSize(target) };
3333 } else if (!data.payload.hasRuntimeBits()) {
3334 return AbiSizeAdvanced{ .scalar = data.error_set.abiSize(target) };
3444 // Here we need to care whether or not the error set is *empty* or whether
3445 // it only has *one possible value*. In the former case, it means there
3446 // cannot possibly be an error, meaning the ABI size is equivalent to the
3447 // payload ABI size. In the latter case, we need to account for the "tag"
3448 // because even if both the payload type and the error set type of an
3449 // error union have no runtime bits, an error union still has
3450 // 1 bit of data which is whether or not the value is an error.
3451 // Zig still uses the error code encoding at runtime, even when only 1 bit
3452 // would suffice. This prevents coercions from needing to branch.
3453 switch (data.error_set.errorSetCardinality()) {
3454 .zero => return abiSizeAdvanced(data.payload, target, strat),
3455 .one => {
3456 if (data.payload.isNoReturn()) {
3457 return AbiSizeAdvanced{ .scalar = 0 };
3458 }
3459 },
3460 .many => {},
3461 }
3462 const code_size = abiSize(Type.anyerror, target);
3463 if (!data.payload.hasRuntimeBits()) {
3464 // Same as anyerror.
3465 return AbiSizeAdvanced{ .scalar = code_size };
33353466 }
3336 const code_align = abiAlignment(data.error_set, target);
3467 const code_align = abiAlignment(Type.anyerror, target);
33373468 const payload_align = abiAlignment(data.payload, target);
3338 const big_align = @maximum(code_align, payload_align);
33393469 const payload_size = abiSize(data.payload, target);
33403470
33413471 var size: u64 = 0;
3342 size += abiSize(data.error_set, target);
3343 size = std.mem.alignForwardGeneric(u64, size, payload_align);
3344 size += payload_size;
3345 size = std.mem.alignForwardGeneric(u64, size, big_align);
3472 if (code_align > payload_align) {
3473 size += code_size;
3474 size = std.mem.alignForwardGeneric(u64, size, payload_align);
3475 size += payload_size;
3476 size = std.mem.alignForwardGeneric(u64, size, code_align);
3477 } else {
3478 size += payload_size;
3479 size = std.mem.alignForwardGeneric(u64, size, code_align);
3480 size += code_size;
3481 size = std.mem.alignForwardGeneric(u64, size, payload_align);
3482 }
33463483 return AbiSizeAdvanced{ .scalar = size };
33473484 },
33483485 }
......@@ -3832,8 +3969,39 @@ pub const Type = extern union {
38323969 return ty.ptrInfo().data.@"allowzero";
38333970 }
38343971
3972 /// See also `isPtrLikeOptional`.
3973 pub fn optionalReprIsPayload(ty: Type) bool {
3974 switch (ty.tag()) {
3975 .optional_single_const_pointer,
3976 .optional_single_mut_pointer,
3977 .c_const_pointer,
3978 .c_mut_pointer,
3979 => return true,
3980
3981 .optional => {
3982 const child_ty = ty.castTag(.optional).?.data;
3983 switch (child_ty.zigTypeTag()) {
3984 .Pointer => {
3985 const info = child_ty.ptrInfo().data;
3986 switch (info.size) {
3987 .Slice, .C => return false,
3988 .Many, .One => return !info.@"allowzero",
3989 }
3990 },
3991 .ErrorSet => return true,
3992 else => return false,
3993 }
3994 },
3995
3996 .pointer => return ty.castTag(.pointer).?.data.size == .C,
3997
3998 else => return false,
3999 }
4000 }
4001
38354002 /// Returns true if the type is optional and would be lowered to a single pointer
38364003 /// address value, using 0 for null. Note that this returns true for C pointers.
4004 /// See also `hasOptionalRepr`.
38374005 pub fn isPtrLikeOptional(self: Type) bool {
38384006 switch (self.tag()) {
38394007 .optional_single_const_pointer,
......@@ -4166,6 +4334,35 @@ pub const Type = extern union {
41664334 };
41674335 }
41684336
4337 const ErrorSetCardinality = enum { zero, one, many };
4338
4339 pub fn errorSetCardinality(ty: Type) ErrorSetCardinality {
4340 switch (ty.tag()) {
4341 .anyerror => return .many,
4342 .error_set_inferred => return .many,
4343 .error_set_single => return .one,
4344 .error_set => {
4345 const err_set_obj = ty.castTag(.error_set).?.data;
4346 const names = err_set_obj.names.keys();
4347 switch (names.len) {
4348 0 => return .zero,
4349 1 => return .one,
4350 else => return .many,
4351 }
4352 },
4353 .error_set_merged => {
4354 const name_map = ty.castTag(.error_set_merged).?.data;
4355 const names = name_map.keys();
4356 switch (names.len) {
4357 0 => return .zero,
4358 1 => return .one,
4359 else => return .many,
4360 }
4361 },
4362 else => unreachable,
4363 }
4364 }
4365
41694366 /// Returns true if it is an error set that includes anyerror, false otherwise.
41704367 /// Note that the result may be a false negative if the type did not get error set
41714368 /// resolution prior to this call.
......@@ -4658,16 +4855,11 @@ pub const Type = extern union {
46584855 .const_slice,
46594856 .mut_slice,
46604857 .anyopaque,
4661 .optional,
46624858 .optional_single_mut_pointer,
46634859 .optional_single_const_pointer,
46644860 .enum_literal,
46654861 .anyerror_void_error_union,
4666 .error_union,
4667 .error_set,
4668 .error_set_single,
46694862 .error_set_inferred,
4670 .error_set_merged,
46714863 .@"opaque",
46724864 .var_args_param,
46734865 .manyptr_u8,
......@@ -4696,6 +4888,52 @@ pub const Type = extern union {
46964888 .bound_fn,
46974889 => return null,
46984890
4891 .optional => {
4892 var buf: Payload.ElemType = undefined;
4893 const child_ty = ty.optionalChild(&buf);
4894 if (child_ty.isNoReturn()) {
4895 return Value.@"null";
4896 } else {
4897 return null;
4898 }
4899 },
4900
4901 .error_union => {
4902 const error_ty = ty.errorUnionSet();
4903 switch (error_ty.errorSetCardinality()) {
4904 .zero => {
4905 const payload_ty = ty.errorUnionPayload();
4906 if (onePossibleValue(payload_ty)) |payload_val| {
4907 _ = payload_val;
4908 return Value.initTag(.the_only_possible_value);
4909 } else {
4910 return null;
4911 }
4912 },
4913 .one => {
4914 if (ty.errorUnionPayload().isNoReturn()) {
4915 const error_val = onePossibleValue(error_ty).?;
4916 return error_val;
4917 } else {
4918 return null;
4919 }
4920 },
4921 .many => return null,
4922 }
4923 },
4924
4925 .error_set_single => return Value.initTag(.the_only_possible_value),
4926 .error_set => {
4927 const err_set_obj = ty.castTag(.error_set).?.data;
4928 if (err_set_obj.names.count() > 1) return null;
4929 return Value.initTag(.the_only_possible_value);
4930 },
4931 .error_set_merged => {
4932 const name_map = ty.castTag(.error_set_merged).?.data;
4933 if (name_map.count() > 1) return null;
4934 return Value.initTag(.the_only_possible_value);
4935 },
4936
46994937 .@"struct" => {
47004938 const s = ty.castTag(.@"struct").?.data;
47014939 assert(s.haveFieldTypes());
test/behavior/error.zig+97-5
......@@ -121,7 +121,7 @@ test "debug info for optional error set" {
121121 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
122122 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
123123
124 const SomeError = error{Hello};
124 const SomeError = error{ Hello, Hello2 };
125125 var a_local_variable: ?SomeError = null;
126126 _ = a_local_variable;
127127}
......@@ -148,18 +148,46 @@ test "implicit cast to optional to error union to return result loc" {
148148 //comptime S.entry(); TODO
149149}
150150
151test "error: fn returning empty error set can be passed as fn returning any error" {
151test "fn returning empty error set can be passed as fn returning any error" {
152 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
153 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
154 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
155
152156 entry();
153157 comptime entry();
154158}
155159
160test "fn returning empty error set can be passed as fn returning any error - pointer" {
161 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
162 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
163 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
164 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
165
166 entryPtr();
167 comptime entryPtr();
168}
169
156170fn entry() void {
157171 foo2(bar2);
158172}
159173
174fn entryPtr() void {
175 var ptr = &bar2;
176 fooPtr(ptr);
177}
178
160179fn foo2(f: fn () anyerror!void) void {
161180 const x = f();
162 x catch {};
181 x catch {
182 @panic("fail");
183 };
184}
185
186fn fooPtr(f: *const fn () anyerror!void) void {
187 const x = f();
188 x catch {
189 @panic("fail");
190 };
163191}
164192
165193fn bar2() (error{}!void) {}
......@@ -239,7 +267,10 @@ fn testComptimeTestErrorEmptySet(x: EmptyErrorSet!i32) !void {
239267}
240268
241269test "comptime err to int of error set with only 1 possible value" {
242 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
270 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
271 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
272 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
273 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
243274
244275 testErrToIntWithOnePossibleValue(error.A, @errorToInt(error.A));
245276 comptime testErrToIntWithOnePossibleValue(error.A, @errorToInt(error.A));
......@@ -409,9 +440,11 @@ test "return function call to error set from error union function" {
409440}
410441
411442test "optional error set is the same size as error set" {
412 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
443 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
444 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
413445
414446 comptime try expect(@sizeOf(?anyerror) == @sizeOf(anyerror));
447 comptime try expect(@alignOf(?anyerror) == @alignOf(anyerror));
415448 const S = struct {
416449 fn returnsOptErrSet() ?anyerror {
417450 return null;
......@@ -421,6 +454,65 @@ test "optional error set is the same size as error set" {
421454 comptime try expect(S.returnsOptErrSet() == null);
422455}
423456
457test "optional error set with only one error is the same size as bool" {
458 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
459 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
460 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
461
462 const E = error{only};
463 comptime try expect(@sizeOf(?E) == @sizeOf(bool));
464 comptime try expect(@alignOf(?E) == @alignOf(bool));
465 const S = struct {
466 fn gimmeNull() ?E {
467 return null;
468 }
469 fn gimmeErr() ?E {
470 return error.only;
471 }
472 };
473 try expect(S.gimmeNull() == null);
474 try expect(error.only == S.gimmeErr().?);
475 comptime try expect(S.gimmeNull() == null);
476 comptime try expect(error.only == S.gimmeErr().?);
477}
478
479test "optional empty error set" {
480 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
481
482 comptime try expect(@sizeOf(error{}!void) == @sizeOf(void));
483 comptime try expect(@alignOf(error{}!void) == @alignOf(void));
484
485 var x: ?error{} = undefined;
486 if (x != null) {
487 @compileError("test failed");
488 }
489}
490
491test "empty error set plus zero-bit payload" {
492 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
493 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
494 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
495
496 comptime try expect(@sizeOf(error{}!void) == @sizeOf(void));
497 comptime try expect(@alignOf(error{}!void) == @alignOf(void));
498
499 var x: error{}!void = undefined;
500 if (x) |payload| {
501 if (payload != {}) {
502 @compileError("test failed");
503 }
504 } else |_| {
505 @compileError("test failed");
506 }
507 const S = struct {
508 fn empty() error{}!void {}
509 fn inferred() !void {
510 return empty();
511 }
512 };
513 try S.inferred();
514}
515
424516test "nested catch" {
425517 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
426518 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
test/behavior/eval.zig-27
......@@ -425,7 +425,6 @@ test "f64 at compile time is lossy" {
425425}
426426
427427test {
428 if (builtin.zig_backend != .stage1 and builtin.os.tag == .macos) return error.SkipZigTest;
429428 comptime try expect(@as(f128, 1 << 113) == 10384593717069655257060992658440192);
430429}
431430
......@@ -573,28 +572,6 @@ test "inlined loop has array literal with elided runtime scope on first iteratio
573572 }
574573}
575574
576test "call method on bound fn referring to var instance" {
577 if (builtin.zig_backend != .stage1) {
578 // Let's delay solving this one; I want to try to eliminate bound functions from
579 // the language.
580 return error.SkipZigTest; // TODO
581 }
582
583 try expect(bound_fn() == 1237);
584}
585
586const SimpleStruct = struct {
587 field: i32,
588
589 fn method(self: *const SimpleStruct) i32 {
590 return self.field + 3;
591 }
592};
593
594var simple_struct = SimpleStruct{ .field = 1234 };
595
596const bound_fn = simple_struct.method;
597
598575test "ptr to local array argument at comptime" {
599576 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
600577 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
......@@ -669,8 +646,6 @@ pub fn TypeWithCompTimeSlice(comptime field_name: []const u8) type {
669646}
670647
671648test "comptime function with mutable pointer is not memoized" {
672 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
673
674649 comptime {
675650 var x: i32 = 1;
676651 const ptr = &x;
......@@ -685,8 +660,6 @@ fn increment(value: *i32) void {
685660}
686661
687662test "const ptr to comptime mutable data is not memoized" {
688 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
689
690663 comptime {
691664 var foo = SingleFieldStruct{ .x = 1 };
692665 try expect(foo.read_x() == 1);
test/cases/compile_errors/call method on bound fn referring to var instance.zig created+20
......@@ -0,0 +1,20 @@
1export fn entry() void {
2 bad(bound_fn() == 1237);
3}
4const SimpleStruct = struct {
5 field: i32,
6
7 fn method(self: *const SimpleStruct) i32 {
8 return self.field + 3;
9 }
10};
11var simple_struct = SimpleStruct{ .field = 1234 };
12const bound_fn = simple_struct.method;
13fn bad(ok: bool) void {
14 _ = ok;
15}
16// error
17// target=native
18// backend=stage2
19//
20// :12:18: error: unable to resolve comptime value