| ... | ... | @@ -749,6 +749,12 @@ pub const DeclGen = struct { |
| 749 | 749 | const error_type = ty.errorUnionSet(); |
| 750 | 750 | const payload_type = ty.errorUnionPayload(); |
| 751 | 751 | |
| 752 | if (error_type.errorSetCardinality() == .zero) { |
| 753 | // We use the payload directly as the type. |
| 754 | const payload_val = val.castTag(.eu_payload).?.data; |
| 755 | return dg.renderValue(writer, payload_type, payload_val, location); |
| 756 | } |
| 757 | |
| 752 | 758 | if (!payload_type.hasRuntimeBits()) { |
| 753 | 759 | // We use the error type directly as the type. |
| 754 | 760 | const err_val = if (val.errorUnionIsPayload()) Value.initTag(.zero) else val; |
| ... | ... | @@ -894,10 +900,12 @@ pub const DeclGen = struct { |
| 894 | 900 | try w.writeAll("ZIG_COLD "); |
| 895 | 901 | } |
| 896 | 902 | } |
| 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) { |
| 903 | const fn_info = dg.decl.ty.fnInfo(); |
| 904 | if (fn_info.return_type.hasRuntimeBits()) { |
| 905 | try dg.renderType(w, fn_info.return_type); |
| 906 | } else if (fn_info.return_type.isError()) { |
| 907 | try dg.renderType(w, Type.anyerror); |
| 908 | } else if (fn_info.return_type.zigTypeTag() == .NoReturn) { |
| 901 | 909 | try w.writeAll("zig_noreturn void"); |
| 902 | 910 | } else { |
| 903 | 911 | try w.writeAll("void"); |
| ... | ... | @@ -905,22 +913,19 @@ pub const DeclGen = struct { |
| 905 | 913 | try w.writeAll(" "); |
| 906 | 914 | try dg.renderDeclName(w, dg.decl_index); |
| 907 | 915 | try w.writeAll("("); |
| 908 | | const param_len = dg.decl.ty.fnParamLen(); |
| 909 | 916 | |
| 910 | | var index: usize = 0; |
| 911 | 917 | var params_written: usize = 0; |
| 912 | | while (index < param_len) : (index += 1) { |
| 913 | | const param_type = dg.decl.ty.fnParamType(index); |
| 918 | for (fn_info.param_types) |param_type, index| { |
| 914 | 919 | if (!param_type.hasRuntimeBitsIgnoreComptime()) continue; |
| 915 | 920 | if (params_written > 0) { |
| 916 | 921 | try w.writeAll(", "); |
| 917 | 922 | } |
| 918 | 923 | const name = CValue{ .arg = index }; |
| 919 | | try dg.renderTypeAndName(w, dg.decl.ty.fnParamType(index), name, .Mut, 0); |
| 924 | try dg.renderTypeAndName(w, param_type, name, .Mut, 0); |
| 920 | 925 | params_written += 1; |
| 921 | 926 | } |
| 922 | 927 | |
| 923 | | if (dg.decl.ty.fnIsVarArgs()) { |
| 928 | if (fn_info.is_var_args) { |
| 924 | 929 | if (params_written != 0) try w.writeAll(", "); |
| 925 | 930 | try w.writeAll("..."); |
| 926 | 931 | } else if (params_written == 0) { |
| ... | ... | @@ -1156,26 +1161,36 @@ pub const DeclGen = struct { |
| 1156 | 1161 | } |
| 1157 | 1162 | |
| 1158 | 1163 | fn renderErrorUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { |
| 1159 | | const child_type = t.errorUnionPayload(); |
| 1160 | | const err_set_type = t.errorUnionSet(); |
| 1164 | const payload_ty = t.errorUnionPayload(); |
| 1165 | const error_ty = t.errorUnionSet(); |
| 1161 | 1166 | |
| 1162 | 1167 | var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); |
| 1163 | 1168 | defer buffer.deinit(); |
| 1164 | 1169 | const bw = buffer.writer(); |
| 1165 | 1170 | |
| 1166 | | try bw.writeAll("typedef struct { "); |
| 1167 | 1171 | const payload_name = CValue{ .bytes = "payload" }; |
| 1168 | | try dg.renderTypeAndName(bw, child_type, payload_name, .Mut, 0); |
| 1169 | | try bw.writeAll("; uint16_t error; } "); |
| 1172 | const target = dg.module.getTarget(); |
| 1173 | const payload_align = payload_ty.abiAlignment(target); |
| 1174 | const error_align = Type.anyerror.abiAlignment(target); |
| 1175 | if (error_align > payload_align) { |
| 1176 | try bw.writeAll("typedef struct { "); |
| 1177 | try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0); |
| 1178 | try bw.writeAll("; uint16_t error; } "); |
| 1179 | } else { |
| 1180 | try bw.writeAll("typedef struct { uint16_t error; "); |
| 1181 | try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0); |
| 1182 | try bw.writeAll("; } "); |
| 1183 | } |
| 1184 | |
| 1170 | 1185 | const name_index = buffer.items.len; |
| 1171 | | if (err_set_type.castTag(.error_set_inferred)) |inf_err_set_payload| { |
| 1186 | if (error_ty.castTag(.error_set_inferred)) |inf_err_set_payload| { |
| 1172 | 1187 | const func = inf_err_set_payload.data.func; |
| 1173 | 1188 | try bw.writeAll("zig_E_"); |
| 1174 | 1189 | try dg.renderDeclName(bw, func.owner_decl); |
| 1175 | 1190 | try bw.writeAll(";\n"); |
| 1176 | 1191 | } else { |
| 1177 | 1192 | try bw.print("zig_E_{s}_{s};\n", .{ |
| 1178 | | typeToCIdentifier(err_set_type, dg.module), typeToCIdentifier(child_type, dg.module), |
| 1193 | typeToCIdentifier(error_ty, dg.module), typeToCIdentifier(payload_ty, dg.module), |
| 1179 | 1194 | }); |
| 1180 | 1195 | } |
| 1181 | 1196 | |
| ... | ... | @@ -1359,12 +1374,19 @@ pub const DeclGen = struct { |
| 1359 | 1374 | return w.writeAll(name); |
| 1360 | 1375 | }, |
| 1361 | 1376 | .ErrorSet => { |
| 1362 | | comptime assert(Type.initTag(.anyerror).abiSize(builtin.target) == 2); |
| 1377 | comptime assert(Type.anyerror.abiSize(builtin.target) == 2); |
| 1363 | 1378 | return w.writeAll("uint16_t"); |
| 1364 | 1379 | }, |
| 1365 | 1380 | .ErrorUnion => { |
| 1366 | | if (t.errorUnionPayload().abiSize(target) == 0) { |
| 1367 | | return dg.renderType(w, t.errorUnionSet()); |
| 1381 | const error_ty = t.errorUnionSet(); |
| 1382 | const payload_ty = t.errorUnionPayload(); |
| 1383 | |
| 1384 | if (error_ty.errorSetCardinality() == .zero) { |
| 1385 | return dg.renderType(w, payload_ty); |
| 1386 | } |
| 1387 | |
| 1388 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { |
| 1389 | return dg.renderType(w, Type.anyerror); |
| 1368 | 1390 | } |
| 1369 | 1391 | |
| 1370 | 1392 | const name = dg.getTypedefName(t) orelse |
| ... | ... | @@ -1901,8 +1923,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO |
| 1901 | 1923 | .array_elem_val => try airArrayElemVal(f, inst), |
| 1902 | 1924 | |
| 1903 | 1925 | .unwrap_errunion_payload => try airUnwrapErrUnionPay(f, inst, ""), |
| 1904 | | .unwrap_errunion_err => try airUnwrapErrUnionErr(f, inst), |
| 1905 | 1926 | .unwrap_errunion_payload_ptr => try airUnwrapErrUnionPay(f, inst, "&"), |
| 1927 | .unwrap_errunion_err => try airUnwrapErrUnionErr(f, inst), |
| 1906 | 1928 | .unwrap_errunion_err_ptr => try airUnwrapErrUnionErr(f, inst), |
| 1907 | 1929 | .wrap_errunion_payload => try airWrapErrUnionPay(f, inst), |
| 1908 | 1930 | .wrap_errunion_err => try airWrapErrUnionErr(f, inst), |
| ... | ... | @@ -2120,11 +2142,14 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2120 | 2142 | fn airRet(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2121 | 2143 | const un_op = f.air.instructions.items(.data)[inst].un_op; |
| 2122 | 2144 | const writer = f.object.writer(); |
| 2123 | | if (f.air.typeOf(un_op).isFnOrHasRuntimeBitsIgnoreComptime()) { |
| 2145 | const ret_ty = f.air.typeOf(un_op); |
| 2146 | if (ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) { |
| 2124 | 2147 | const operand = try f.resolveInst(un_op); |
| 2125 | 2148 | try writer.writeAll("return "); |
| 2126 | 2149 | try f.writeCValue(writer, operand); |
| 2127 | 2150 | try writer.writeAll(";\n"); |
| 2151 | } else if (ret_ty.isError()) { |
| 2152 | try writer.writeAll("return 0;"); |
| 2128 | 2153 | } else { |
| 2129 | 2154 | try writer.writeAll("return;\n"); |
| 2130 | 2155 | } |
| ... | ... | @@ -2136,13 +2161,16 @@ fn airRetLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2136 | 2161 | const writer = f.object.writer(); |
| 2137 | 2162 | const ptr_ty = f.air.typeOf(un_op); |
| 2138 | 2163 | const ret_ty = ptr_ty.childType(); |
| 2139 | | if (!ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) { |
| 2164 | if (ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) { |
| 2165 | const ptr = try f.resolveInst(un_op); |
| 2166 | try writer.writeAll("return *"); |
| 2167 | try f.writeCValue(writer, ptr); |
| 2168 | try writer.writeAll(";\n"); |
| 2169 | } else if (ret_ty.isError()) { |
| 2170 | try writer.writeAll("return 0;\n"); |
| 2171 | } else { |
| 2140 | 2172 | try writer.writeAll("return;\n"); |
| 2141 | 2173 | } |
| 2142 | | const ptr = try f.resolveInst(un_op); |
| 2143 | | try writer.writeAll("return *"); |
| 2144 | | try f.writeCValue(writer, ptr); |
| 2145 | | try writer.writeAll(";\n"); |
| 2146 | 2174 | return CValue.none; |
| 2147 | 2175 | } |
| 2148 | 2176 | |
| ... | ... | @@ -2713,19 +2741,20 @@ fn airCall( |
| 2713 | 2741 | .Pointer => callee_ty.childType(), |
| 2714 | 2742 | else => unreachable, |
| 2715 | 2743 | }; |
| 2716 | | const ret_ty = fn_ty.fnReturnType(); |
| 2717 | | const unused_result = f.liveness.isUnused(inst); |
| 2718 | 2744 | const writer = f.object.writer(); |
| 2719 | 2745 | |
| 2720 | | var result_local: CValue = .none; |
| 2721 | | if (unused_result) { |
| 2722 | | if (ret_ty.hasRuntimeBits()) { |
| 2723 | | try writer.print("(void)", .{}); |
| 2746 | const result_local: CValue = r: { |
| 2747 | if (f.liveness.isUnused(inst)) { |
| 2748 | if (loweredFnRetTyHasBits(fn_ty)) { |
| 2749 | try writer.print("(void)", .{}); |
| 2750 | } |
| 2751 | break :r .none; |
| 2752 | } else { |
| 2753 | const local = try f.allocLocal(fn_ty.fnReturnType(), .Const); |
| 2754 | try writer.writeAll(" = "); |
| 2755 | break :r local; |
| 2724 | 2756 | } |
| 2725 | | } else { |
| 2726 | | result_local = try f.allocLocal(ret_ty, .Const); |
| 2727 | | try writer.writeAll(" = "); |
| 2728 | | } |
| 2757 | }; |
| 2729 | 2758 | |
| 2730 | 2759 | callee: { |
| 2731 | 2760 | known: { |
| ... | ... | @@ -3307,7 +3336,8 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3307 | 3336 | return local; |
| 3308 | 3337 | } |
| 3309 | 3338 | |
| 3310 | | // *(E!T) -> E NOT *E |
| 3339 | /// *(E!T) -> E |
| 3340 | /// Note that the result is never a pointer. |
| 3311 | 3341 | fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3312 | 3342 | if (f.liveness.isUnused(inst)) |
| 3313 | 3343 | return CValue.none; |
| ... | ... | @@ -3319,7 +3349,11 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3319 | 3349 | const operand_ty = f.air.typeOf(ty_op.operand); |
| 3320 | 3350 | |
| 3321 | 3351 | if (operand_ty.zigTypeTag() == .Pointer) { |
| 3322 | | if (!operand_ty.childType().errorUnionPayload().hasRuntimeBits()) { |
| 3352 | const err_union_ty = operand_ty.childType(); |
| 3353 | if (err_union_ty.errorUnionSet().errorSetCardinality() == .zero) { |
| 3354 | return CValue{ .bytes = "0" }; |
| 3355 | } |
| 3356 | if (!err_union_ty.errorUnionPayload().hasRuntimeBits()) { |
| 3323 | 3357 | return operand; |
| 3324 | 3358 | } |
| 3325 | 3359 | const local = try f.allocLocal(inst_ty, .Const); |
| ... | ... | @@ -3328,6 +3362,9 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3328 | 3362 | try writer.writeAll(";\n"); |
| 3329 | 3363 | return local; |
| 3330 | 3364 | } |
| 3365 | if (operand_ty.errorUnionSet().errorSetCardinality() == .zero) { |
| 3366 | return CValue{ .bytes = "0" }; |
| 3367 | } |
| 3331 | 3368 | if (!operand_ty.errorUnionPayload().hasRuntimeBits()) { |
| 3332 | 3369 | return operand; |
| 3333 | 3370 | } |
| ... | ... | @@ -3343,7 +3380,7 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3343 | 3380 | return local; |
| 3344 | 3381 | } |
| 3345 | 3382 | |
| 3346 | | fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: []const u8) !CValue { |
| 3383 | fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: [*:0]const u8) !CValue { |
| 3347 | 3384 | if (f.liveness.isUnused(inst)) |
| 3348 | 3385 | return CValue.none; |
| 3349 | 3386 | |
| ... | ... | @@ -3351,17 +3388,19 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: []cons |
| 3351 | 3388 | const writer = f.object.writer(); |
| 3352 | 3389 | const operand = try f.resolveInst(ty_op.operand); |
| 3353 | 3390 | const operand_ty = f.air.typeOf(ty_op.operand); |
| 3391 | const operand_is_ptr = operand_ty.zigTypeTag() == .Pointer; |
| 3392 | const error_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty; |
| 3393 | |
| 3394 | if (error_union_ty.errorUnionSet().errorSetCardinality() == .zero) { |
| 3395 | return operand; |
| 3396 | } |
| 3354 | 3397 | |
| 3355 | | const error_union_ty = if (operand_ty.zigTypeTag() == .Pointer) |
| 3356 | | operand_ty.childType() |
| 3357 | | else |
| 3358 | | operand_ty; |
| 3359 | 3398 | if (!error_union_ty.errorUnionPayload().hasRuntimeBits()) { |
| 3360 | 3399 | return CValue.none; |
| 3361 | 3400 | } |
| 3362 | 3401 | |
| 3363 | 3402 | const inst_ty = f.air.typeOfIndex(inst); |
| 3364 | | const maybe_deref = if (operand_ty.zigTypeTag() == .Pointer) "->" else "."; |
| 3403 | const maybe_deref = if (operand_is_ptr) "->" else "."; |
| 3365 | 3404 | |
| 3366 | 3405 | const local = try f.allocLocal(inst_ty, .Const); |
| 3367 | 3406 | try writer.print(" = {s}(", .{maybe_addrof}); |
| ... | ... | @@ -3421,6 +3460,11 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3421 | 3460 | const error_ty = error_union_ty.errorUnionSet(); |
| 3422 | 3461 | const payload_ty = error_union_ty.errorUnionPayload(); |
| 3423 | 3462 | |
| 3463 | if (error_ty.errorSetCardinality() == .zero) { |
| 3464 | // TODO: write undefined bytes through the pointer here |
| 3465 | return operand; |
| 3466 | } |
| 3467 | |
| 3424 | 3468 | // First, set the non-error value. |
| 3425 | 3469 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { |
| 3426 | 3470 | try f.writeCValueDeref(writer, operand); |
| ... | ... | @@ -3464,6 +3508,9 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3464 | 3508 | const operand = try f.resolveInst(ty_op.operand); |
| 3465 | 3509 | |
| 3466 | 3510 | const inst_ty = f.air.typeOfIndex(inst); |
| 3511 | if (inst_ty.errorUnionSet().errorSetCardinality() == .zero) { |
| 3512 | return operand; |
| 3513 | } |
| 3467 | 3514 | const local = try f.allocLocal(inst_ty, .Const); |
| 3468 | 3515 | try writer.writeAll(" = { .error = 0, .payload = "); |
| 3469 | 3516 | try f.writeCValue(writer, operand); |
| ... | ... | @@ -3486,16 +3533,23 @@ fn airIsErr( |
| 3486 | 3533 | const operand_ty = f.air.typeOf(un_op); |
| 3487 | 3534 | const local = try f.allocLocal(Type.initTag(.bool), .Const); |
| 3488 | 3535 | const payload_ty = operand_ty.errorUnionPayload(); |
| 3536 | const error_ty = operand_ty.errorUnionSet(); |
| 3537 | |
| 3489 | 3538 | try writer.writeAll(" = "); |
| 3490 | | if (is_ptr) { |
| 3491 | | try f.writeCValueDeref(writer, operand); |
| 3539 | |
| 3540 | if (error_ty.errorSetCardinality() == .zero) { |
| 3541 | try writer.print("0 {s} 0;\n", .{op_str}); |
| 3492 | 3542 | } else { |
| 3493 | | try f.writeCValue(writer, operand); |
| 3494 | | } |
| 3495 | | if (payload_ty.hasRuntimeBits()) { |
| 3496 | | try writer.writeAll(".error"); |
| 3543 | if (is_ptr) { |
| 3544 | try f.writeCValueDeref(writer, operand); |
| 3545 | } else { |
| 3546 | try f.writeCValue(writer, operand); |
| 3547 | } |
| 3548 | if (payload_ty.hasRuntimeBits()) { |
| 3549 | try writer.writeAll(".error"); |
| 3550 | } |
| 3551 | try writer.print(" {s} 0;\n", .{op_str}); |
| 3497 | 3552 | } |
| 3498 | | try writer.print(" {s} 0;\n", .{op_str}); |
| 3499 | 3553 | return local; |
| 3500 | 3554 | } |
| 3501 | 3555 | |
| ... | ... | @@ -4129,3 +4183,14 @@ fn intMin(ty: Type, target: std.Target, buf: []u8) []const u8 { |
| 4129 | 4183 | }, |
| 4130 | 4184 | } |
| 4131 | 4185 | } |
| 4186 | |
| 4187 | fn loweredFnRetTyHasBits(fn_ty: Type) bool { |
| 4188 | const ret_ty = fn_ty.fnReturnType(); |
| 4189 | if (ret_ty.hasRuntimeBitsIgnoreComptime()) { |
| 4190 | return true; |
| 4191 | } |
| 4192 | if (ret_ty.isError()) { |
| 4193 | return true; |
| 4194 | } |
| 4195 | return false; |
| 4196 | } |