| author | |
| committer | |
| log | 0005b346375f1fbe7bc42c22d658e3218bbd599d |
| tree | d88211b36f2be7689a138bf0d5f1a2e62f695323 |
| parent | f80f8a7a7835db5f8b13aab23b4ee79e88c25e63 |
10 files changed, 177 insertions(+), 7 deletions(-)
src/AstGen.zig+12-2| ... | @@ -1237,6 +1237,8 @@ fn blockExprStmts( | ... | @@ -1237,6 +1237,8 @@ fn blockExprStmts( |
| 1237 | .bit_not, | 1237 | .bit_not, |
| 1238 | .error_set, | 1238 | .error_set, |
| 1239 | .error_value, | 1239 | .error_value, |
| 1240 | .error_to_int, | ||
| 1241 | .int_to_error, | ||
| 1240 | .slice_start, | 1242 | .slice_start, |
| 1241 | .slice_end, | 1243 | .slice_end, |
| 1242 | .slice_sentinel, | 1244 | .slice_sentinel, |
| ... | @@ -3370,6 +3372,16 @@ fn builtinCall( | ... | @@ -3370,6 +3372,16 @@ fn builtinCall( |
| 3370 | const result = try gz.addUnNode(.import, target, node); | 3372 | const result = try gz.addUnNode(.import, target, node); |
| 3371 | return rvalue(gz, scope, rl, result, node); | 3373 | return rvalue(gz, scope, rl, result, node); |
| 3372 | }, | 3374 | }, |
| 3375 | .error_to_int => { | ||
| 3376 | const target = try expr(gz, scope, .none, params[0]); | ||
| 3377 | const result = try gz.addUnNode(.error_to_int, target, node); | ||
| 3378 | return rvalue(gz, scope, rl, result, node); | ||
| 3379 | }, | ||
| 3380 | .int_to_error => { | ||
| 3381 | const target = try expr(gz, scope, .{ .ty = .u16_type }, params[0]); | ||
| 3382 | const result = try gz.addUnNode(.int_to_error, target, node); | ||
| 3383 | return rvalue(gz, scope, rl, result, node); | ||
| 3384 | }, | ||
| 3373 | .compile_error => { | 3385 | .compile_error => { |
| 3374 | const target = try expr(gz, scope, .none, params[0]); | 3386 | const target = try expr(gz, scope, .none, params[0]); |
| 3375 | const result = try gz.addUnNode(.compile_error, target, node); | 3387 | const result = try gz.addUnNode(.compile_error, target, node); |
| ... | @@ -3439,7 +3451,6 @@ fn builtinCall( | ... | @@ -3439,7 +3451,6 @@ fn builtinCall( |
| 3439 | .enum_to_int, | 3451 | .enum_to_int, |
| 3440 | .error_name, | 3452 | .error_name, |
| 3441 | .error_return_trace, | 3453 | .error_return_trace, |
| 3442 | .error_to_int, | ||
| 3443 | .err_set_cast, | 3454 | .err_set_cast, |
| 3444 | .@"export", | 3455 | .@"export", |
| 3445 | .fence, | 3456 | .fence, |
| ... | @@ -3448,7 +3459,6 @@ fn builtinCall( | ... | @@ -3448,7 +3459,6 @@ fn builtinCall( |
| 3448 | .has_decl, | 3459 | .has_decl, |
| 3449 | .has_field, | 3460 | .has_field, |
| 3450 | .int_to_enum, | 3461 | .int_to_enum, |
| 3451 | .int_to_error, | ||
| 3452 | .int_to_float, | 3462 | .int_to_float, |
| 3453 | .int_to_ptr, | 3463 | .int_to_ptr, |
| 3454 | .memcpy, | 3464 | .memcpy, |
src/Compilation.zig+3| ... | @@ -941,6 +941,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -941,6 +941,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 941 | }; | 941 | }; |
| 942 | 942 | ||
| 943 | const module = try arena.create(Module); | 943 | const module = try arena.create(Module); |
| 944 | errdefer module.deinit(); | ||
| 944 | module.* = .{ | 945 | module.* = .{ |
| 945 | .gpa = gpa, | 946 | .gpa = gpa, |
| 946 | .comp = comp, | 947 | .comp = comp, |
| ... | @@ -948,7 +949,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -948,7 +949,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 948 | .root_scope = root_scope, | 949 | .root_scope = root_scope, |
| 949 | .zig_cache_artifact_directory = zig_cache_artifact_directory, | 950 | .zig_cache_artifact_directory = zig_cache_artifact_directory, |
| 950 | .emit_h = options.emit_h, | 951 | .emit_h = options.emit_h, |
| 952 | .error_name_list = try std.ArrayListUnmanaged([]const u8).initCapacity(gpa, 1), | ||
| 951 | }; | 953 | }; |
| 954 | module.error_name_list.appendAssumeCapacity("(no error)"); | ||
| 952 | break :blk module; | 955 | break :blk module; |
| 953 | } else blk: { | 956 | } else blk: { |
| 954 | if (options.emit_h != null) return error.NoZigModuleForCHeader; | 957 | if (options.emit_h != null) return error.NoZigModuleForCHeader; |
src/Module.zig+25-3| ... | @@ -80,6 +80,9 @@ deletion_set: ArrayListUnmanaged(*Decl) = .{}, | ... | @@ -80,6 +80,9 @@ deletion_set: ArrayListUnmanaged(*Decl) = .{}, |
| 80 | /// Error tags and their values, tag names are duped with mod.gpa. | 80 | /// Error tags and their values, tag names are duped with mod.gpa. |
| 81 | global_error_set: std.StringHashMapUnmanaged(u16) = .{}, | 81 | global_error_set: std.StringHashMapUnmanaged(u16) = .{}, |
| 82 | 82 | ||
| 83 | /// error u16 -> []const u8 for fast lookups for @intToError at comptime | ||
| 84 | error_name_list: ArrayListUnmanaged([]const u8) = .{}, | ||
| 85 | |||
| 83 | /// Keys are fully qualified paths | 86 | /// Keys are fully qualified paths |
| 84 | import_table: std.StringArrayHashMapUnmanaged(*Scope.File) = .{}, | 87 | import_table: std.StringArrayHashMapUnmanaged(*Scope.File) = .{}, |
| 85 | 88 | ||
| ... | @@ -1570,7 +1573,22 @@ pub const SrcLoc = struct { | ... | @@ -1570,7 +1573,22 @@ pub const SrcLoc = struct { |
| 1570 | const token_starts = tree.tokens.items(.start); | 1573 | const token_starts = tree.tokens.items(.start); |
| 1571 | return token_starts[tok_index]; | 1574 | return token_starts[tok_index]; |
| 1572 | }, | 1575 | }, |
| 1573 | .node_offset_builtin_call_arg0 => @panic("TODO"), | 1576 | .node_offset_builtin_call_arg0 => |node_off| { |
| 1577 | const decl = src_loc.container.decl; | ||
| 1578 | const tree = decl.container.file_scope.base.tree(); | ||
| 1579 | const node_datas = tree.nodes.items(.data); | ||
| 1580 | const node_tags = tree.nodes.items(.tag); | ||
| 1581 | const node = decl.relativeToNodeIndex(node_off); | ||
| 1582 | const param = switch (node_tags[node]) { | ||
| 1583 | .builtin_call_two, .builtin_call_two_comma => node_datas[node].lhs, | ||
| 1584 | .builtin_call, .builtin_call_comma => tree.extra_data[node_datas[node].lhs], | ||
| 1585 | else => unreachable, | ||
| 1586 | }; | ||
| 1587 | const main_tokens = tree.nodes.items(.main_token); | ||
| 1588 | const tok_index = main_tokens[param]; | ||
| 1589 | const token_starts = tree.tokens.items(.start); | ||
| 1590 | return token_starts[tok_index]; | ||
| 1591 | }, | ||
| 1574 | .node_offset_builtin_call_arg1 => @panic("TODO"), | 1592 | .node_offset_builtin_call_arg1 => @panic("TODO"), |
| 1575 | .node_offset_builtin_call_argn => unreachable, // Handled specially in `Sema`. | 1593 | .node_offset_builtin_call_argn => unreachable, // Handled specially in `Sema`. |
| 1576 | .node_offset_array_access_index => @panic("TODO"), | 1594 | .node_offset_array_access_index => @panic("TODO"), |
| ... | @@ -1893,6 +1911,8 @@ pub fn deinit(mod: *Module) void { | ... | @@ -1893,6 +1911,8 @@ pub fn deinit(mod: *Module) void { |
| 1893 | } | 1911 | } |
| 1894 | mod.global_error_set.deinit(gpa); | 1912 | mod.global_error_set.deinit(gpa); |
| 1895 | 1913 | ||
| 1914 | mod.error_name_list.deinit(gpa); | ||
| 1915 | |||
| 1896 | for (mod.import_table.items()) |entry| { | 1916 | for (mod.import_table.items()) |entry| { |
| 1897 | entry.value.destroy(gpa); | 1917 | entry.value.destroy(gpa); |
| 1898 | } | 1918 | } |
| ... | @@ -3346,10 +3366,12 @@ pub fn getErrorValue(mod: *Module, name: []const u8) !std.StringHashMapUnmanaged | ... | @@ -3346,10 +3366,12 @@ pub fn getErrorValue(mod: *Module, name: []const u8) !std.StringHashMapUnmanaged |
| 3346 | const gop = try mod.global_error_set.getOrPut(mod.gpa, name); | 3366 | const gop = try mod.global_error_set.getOrPut(mod.gpa, name); |
| 3347 | if (gop.found_existing) | 3367 | if (gop.found_existing) |
| 3348 | return gop.entry.*; | 3368 | return gop.entry.*; |
| 3349 | errdefer mod.global_error_set.removeAssertDiscard(name); | ||
| 3350 | 3369 | ||
| 3370 | errdefer mod.global_error_set.removeAssertDiscard(name); | ||
| 3371 | try mod.error_name_list.ensureCapacity(mod.gpa, mod.error_name_list.items.len + 1); | ||
| 3351 | gop.entry.key = try mod.gpa.dupe(u8, name); | 3372 | gop.entry.key = try mod.gpa.dupe(u8, name); |
| 3352 | gop.entry.value = @intCast(u16, mod.global_error_set.count() - 1); | 3373 | gop.entry.value = @intCast(u16, mod.error_name_list.items.len); |
| 3374 | mod.error_name_list.appendAssumeCapacity(gop.entry.key); | ||
| 3353 | return gop.entry.*; | 3375 | return gop.entry.*; |
| 3354 | } | 3376 | } |
| 3355 | 3377 |
src/Sema.zig+62| ... | @@ -177,6 +177,8 @@ pub fn analyzeBody( | ... | @@ -177,6 +177,8 @@ pub fn analyzeBody( |
| 177 | .error_set => try sema.zirErrorSet(block, inst), | 177 | .error_set => try sema.zirErrorSet(block, inst), |
| 178 | .error_union_type => try sema.zirErrorUnionType(block, inst), | 178 | .error_union_type => try sema.zirErrorUnionType(block, inst), |
| 179 | .error_value => try sema.zirErrorValue(block, inst), | 179 | .error_value => try sema.zirErrorValue(block, inst), |
| 180 | .error_to_int => try sema.zirErrorToInt(block, inst), | ||
| 181 | .int_to_error => try sema.zirIntToError(block, inst), | ||
| 180 | .field_ptr => try sema.zirFieldPtr(block, inst), | 182 | .field_ptr => try sema.zirFieldPtr(block, inst), |
| 181 | .field_ptr_named => try sema.zirFieldPtrNamed(block, inst), | 183 | .field_ptr_named => try sema.zirFieldPtrNamed(block, inst), |
| 182 | .field_val => try sema.zirFieldVal(block, inst), | 184 | .field_val => try sema.zirFieldVal(block, inst), |
| ... | @@ -1460,6 +1462,65 @@ fn zirErrorValue(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerEr | ... | @@ -1460,6 +1462,65 @@ fn zirErrorValue(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerEr |
| 1460 | }); | 1462 | }); |
| 1461 | } | 1463 | } |
| 1462 | 1464 | ||
| 1465 | fn zirErrorToInt(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | ||
| 1466 | const tracy = trace(@src()); | ||
| 1467 | defer tracy.end(); | ||
| 1468 | |||
| 1469 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | ||
| 1470 | const src = inst_data.src(); | ||
| 1471 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | ||
| 1472 | const op = try sema.resolveInst(inst_data.operand); | ||
| 1473 | const op_coerced = try sema.coerce(block, Type.initTag(.anyerror), op, operand_src); | ||
| 1474 | |||
| 1475 | if (op_coerced.value()) |val| { | ||
| 1476 | const payload = try sema.arena.create(Value.Payload.U64); | ||
| 1477 | payload.* = .{ | ||
| 1478 | .base = .{ .tag = .int_u64 }, | ||
| 1479 | .data = (try sema.mod.getErrorValue(val.castTag(.@"error").?.data.name)).value, | ||
| 1480 | }; | ||
| 1481 | return sema.mod.constInst(sema.arena, src, .{ | ||
| 1482 | .ty = Type.initTag(.u16), | ||
| 1483 | .val = Value.initPayload(&payload.base), | ||
| 1484 | }); | ||
| 1485 | } | ||
| 1486 | |||
| 1487 | try sema.requireRuntimeBlock(block, src); | ||
| 1488 | return block.addUnOp(src, Type.initTag(.u16), .error_to_int, op_coerced); | ||
| 1489 | } | ||
| 1490 | |||
| 1491 | fn zirIntToError(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | ||
| 1492 | const tracy = trace(@src()); | ||
| 1493 | defer tracy.end(); | ||
| 1494 | |||
| 1495 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | ||
| 1496 | const src = inst_data.src(); | ||
| 1497 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | ||
| 1498 | |||
| 1499 | const op = try sema.resolveInst(inst_data.operand); | ||
| 1500 | |||
| 1501 | if (try sema.resolveDefinedValue(block, operand_src, op)) |value| { | ||
| 1502 | const int = value.toUnsignedInt(); | ||
| 1503 | if (int > sema.mod.global_error_set.count() or int == 0) | ||
| 1504 | return sema.mod.fail(&block.base, operand_src, "integer value {d} represents no error", .{int}); | ||
| 1505 | const payload = try sema.arena.create(Value.Payload.Error); | ||
| 1506 | payload.* = .{ | ||
| 1507 | .base = .{ .tag = .@"error" }, | ||
| 1508 | .data = .{ .name = sema.mod.error_name_list.items[int] }, | ||
| 1509 | }; | ||
| 1510 | return sema.mod.constInst(sema.arena, src, .{ | ||
| 1511 | .ty = Type.initTag(.anyerror), | ||
| 1512 | .val = Value.initPayload(&payload.base), | ||
| 1513 | }); | ||
| 1514 | } | ||
| 1515 | try sema.requireRuntimeBlock(block, src); | ||
| 1516 | if (block.wantSafety()) { | ||
| 1517 | return sema.mod.fail(&block.base, src, "TODO: get max errors in compilation", .{}); | ||
| 1518 | // const is_gt_max = @panic("TODO get max errors in compilation"); | ||
| 1519 | // try sema.addSafetyCheck(block, is_gt_max, .invalid_error_code); | ||
| 1520 | } | ||
| 1521 | return block.addUnOp(src, Type.initTag(.anyerror), .int_to_error, op); | ||
| 1522 | } | ||
| 1523 | |||
| 1463 | fn zirMergeErrorSets(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 1524 | fn zirMergeErrorSets(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { |
| 1464 | const tracy = trace(@src()); | 1525 | const tracy = trace(@src()); |
| 1465 | defer tracy.end(); | 1526 | defer tracy.end(); |
| ... | @@ -3242,6 +3303,7 @@ pub const PanicId = enum { | ... | @@ -3242,6 +3303,7 @@ pub const PanicId = enum { |
| 3242 | unreach, | 3303 | unreach, |
| 3243 | unwrap_null, | 3304 | unwrap_null, |
| 3244 | unwrap_errunion, | 3305 | unwrap_errunion, |
| 3306 | invalid_error_code, | ||
| 3245 | }; | 3307 | }; |
| 3246 | 3308 | ||
| 3247 | fn addSafetyCheck(sema: *Sema, parent_block: *Scope.Block, ok: *Inst, panic_id: PanicId) !void { | 3309 | fn addSafetyCheck(sema: *Sema, parent_block: *Scope.Block, ok: *Inst, panic_id: PanicId) !void { |
src/codegen.zig+10| ... | @@ -898,6 +898,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -898,6 +898,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 898 | .is_null_ptr => return self.genIsNullPtr(inst.castTag(.is_null_ptr).?), | 898 | .is_null_ptr => return self.genIsNullPtr(inst.castTag(.is_null_ptr).?), |
| 899 | .is_err => return self.genIsErr(inst.castTag(.is_err).?), | 899 | .is_err => return self.genIsErr(inst.castTag(.is_err).?), |
| 900 | .is_err_ptr => return self.genIsErrPtr(inst.castTag(.is_err_ptr).?), | 900 | .is_err_ptr => return self.genIsErrPtr(inst.castTag(.is_err_ptr).?), |
| 901 | .error_to_int => return self.genErrorToInt(inst.castTag(.error_to_int).?), | ||
| 902 | .int_to_error => return self.genIntToError(inst.castTag(.int_to_error).?), | ||
| 901 | .load => return self.genLoad(inst.castTag(.load).?), | 903 | .load => return self.genLoad(inst.castTag(.load).?), |
| 902 | .loop => return self.genLoop(inst.castTag(.loop).?), | 904 | .loop => return self.genLoop(inst.castTag(.loop).?), |
| 903 | .not => return self.genNot(inst.castTag(.not).?), | 905 | .not => return self.genNot(inst.castTag(.not).?), |
| ... | @@ -2557,6 +2559,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -2557,6 +2559,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2557 | return self.fail(inst.base.src, "TODO load the operand and call genIsErr", .{}); | 2559 | return self.fail(inst.base.src, "TODO load the operand and call genIsErr", .{}); |
| 2558 | } | 2560 | } |
| 2559 | 2561 | ||
| 2562 | fn genErrorToInt(self: *Self, inst: *ir.Inst.UnOp) !MCValue { | ||
| 2563 | return self.resolveInst(inst.operand); | ||
| 2564 | } | ||
| 2565 | |||
| 2566 | fn genIntToError(self: *Self, inst: *ir.Inst.UnOp) !MCValue { | ||
| 2567 | return self.resolveInst(inst.operand); | ||
| 2568 | } | ||
| 2569 | |||
| 2560 | fn genLoop(self: *Self, inst: *ir.Inst.Loop) !MCValue { | 2570 | fn genLoop(self: *Self, inst: *ir.Inst.Loop) !MCValue { |
| 2561 | // A loop is a setup to be able to jump back to the beginning. | 2571 | // A loop is a setup to be able to jump back to the beginning. |
| 2562 | const start_index = self.code.items.len; | 2572 | const start_index = self.code.items.len; |
src/codegen/c.zig+10| ... | @@ -569,6 +569,8 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi | ... | @@ -569,6 +569,8 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi |
| 569 | .optional_payload_ptr => try genOptionalPayload(o, inst.castTag(.optional_payload_ptr).?), | 569 | .optional_payload_ptr => try genOptionalPayload(o, inst.castTag(.optional_payload_ptr).?), |
| 570 | .is_err => try genIsErr(o, inst.castTag(.is_err).?), | 570 | .is_err => try genIsErr(o, inst.castTag(.is_err).?), |
| 571 | .is_err_ptr => try genIsErr(o, inst.castTag(.is_err_ptr).?), | 571 | .is_err_ptr => try genIsErr(o, inst.castTag(.is_err_ptr).?), |
| 572 | .error_to_int => try genErrorToInt(o, inst.castTag(.error_to_int).?), | ||
| 573 | .int_to_error => try genIntToError(o, inst.castTag(.int_to_error).?), | ||
| 572 | .unwrap_errunion_payload => try genUnwrapErrUnionPay(o, inst.castTag(.unwrap_errunion_payload).?), | 574 | .unwrap_errunion_payload => try genUnwrapErrUnionPay(o, inst.castTag(.unwrap_errunion_payload).?), |
| 573 | .unwrap_errunion_err => try genUnwrapErrUnionErr(o, inst.castTag(.unwrap_errunion_err).?), | 575 | .unwrap_errunion_err => try genUnwrapErrUnionErr(o, inst.castTag(.unwrap_errunion_err).?), |
| 574 | .unwrap_errunion_payload_ptr => try genUnwrapErrUnionPay(o, inst.castTag(.unwrap_errunion_payload_ptr).?), | 576 | .unwrap_errunion_payload_ptr => try genUnwrapErrUnionPay(o, inst.castTag(.unwrap_errunion_payload_ptr).?), |
| ... | @@ -1072,6 +1074,14 @@ fn genIsErr(o: *Object, inst: *Inst.UnOp) !CValue { | ... | @@ -1072,6 +1074,14 @@ fn genIsErr(o: *Object, inst: *Inst.UnOp) !CValue { |
| 1072 | return local; | 1074 | return local; |
| 1073 | } | 1075 | } |
| 1074 | 1076 | ||
| 1077 | fn genIntToError(o: *Object, inst: *Inst.UnOp) !CValue { | ||
| 1078 | return o.resolveInst(inst.operand); | ||
| 1079 | } | ||
| 1080 | |||
| 1081 | fn genErrorToInt(o: *Object, inst: *Inst.UnOp) !CValue { | ||
| 1082 | return o.resolveInst(inst.operand); | ||
| 1083 | } | ||
| 1084 | |||
| 1075 | fn IndentWriter(comptime UnderlyingWriter: type) type { | 1085 | fn IndentWriter(comptime UnderlyingWriter: type) type { |
| 1076 | return struct { | 1086 | return struct { |
| 1077 | const Self = @This(); | 1087 | const Self = @This(); |
src/ir.zig+10| ... | @@ -92,6 +92,10 @@ pub const Inst = struct { | ... | @@ -92,6 +92,10 @@ pub const Inst = struct { |
| 92 | is_err, | 92 | is_err, |
| 93 | /// *E!T => bool | 93 | /// *E!T => bool |
| 94 | is_err_ptr, | 94 | is_err_ptr, |
| 95 | /// E => u16 | ||
| 96 | error_to_int, | ||
| 97 | /// u16 => E | ||
| 98 | int_to_error, | ||
| 95 | bool_and, | 99 | bool_and, |
| 96 | bool_or, | 100 | bool_or, |
| 97 | /// Read a value from a pointer. | 101 | /// Read a value from a pointer. |
| ... | @@ -152,6 +156,8 @@ pub const Inst = struct { | ... | @@ -152,6 +156,8 @@ pub const Inst = struct { |
| 152 | .is_null_ptr, | 156 | .is_null_ptr, |
| 153 | .is_err, | 157 | .is_err, |
| 154 | .is_err_ptr, | 158 | .is_err_ptr, |
| 159 | .int_to_error, | ||
| 160 | .error_to_int, | ||
| 155 | .ptrtoint, | 161 | .ptrtoint, |
| 156 | .floatcast, | 162 | .floatcast, |
| 157 | .intcast, | 163 | .intcast, |
| ... | @@ -696,6 +702,8 @@ const DumpTzir = struct { | ... | @@ -696,6 +702,8 @@ const DumpTzir = struct { |
| 696 | .is_null_ptr, | 702 | .is_null_ptr, |
| 697 | .is_err, | 703 | .is_err, |
| 698 | .is_err_ptr, | 704 | .is_err_ptr, |
| 705 | .error_to_int, | ||
| 706 | .int_to_error, | ||
| 699 | .ptrtoint, | 707 | .ptrtoint, |
| 700 | .floatcast, | 708 | .floatcast, |
| 701 | .intcast, | 709 | .intcast, |
| ... | @@ -817,6 +825,8 @@ const DumpTzir = struct { | ... | @@ -817,6 +825,8 @@ const DumpTzir = struct { |
| 817 | .is_null_ptr, | 825 | .is_null_ptr, |
| 818 | .is_err, | 826 | .is_err, |
| 819 | .is_err_ptr, | 827 | .is_err_ptr, |
| 828 | .error_to_int, | ||
| 829 | .int_to_error, | ||
| 820 | .ptrtoint, | 830 | .ptrtoint, |
| 821 | .floatcast, | 831 | .floatcast, |
| 822 | .intcast, | 832 | .intcast, |
src/link/C.zig+1-2| ... | @@ -185,8 +185,7 @@ pub fn flushModule(self: *C, comp: *Compilation) !void { | ... | @@ -185,8 +185,7 @@ pub fn flushModule(self: *C, comp: *Compilation) !void { |
| 185 | if (module.global_error_set.size == 0) break :render_errors; | 185 | if (module.global_error_set.size == 0) break :render_errors; |
| 186 | var it = module.global_error_set.iterator(); | 186 | var it = module.global_error_set.iterator(); |
| 187 | while (it.next()) |entry| { | 187 | while (it.next()) |entry| { |
| 188 | // + 1 because 0 represents no error | 188 | try err_typedef_writer.print("#define zig_error_{s} {d}\n", .{ entry.key, entry.value }); |
| 189 | try err_typedef_writer.print("#define zig_error_{s} {d}\n", .{ entry.key, entry.value + 1 }); | ||
| 190 | } | 189 | } |
| 191 | try err_typedef_writer.writeByte('\n'); | 190 | try err_typedef_writer.writeByte('\n'); |
| 192 | } | 191 | } |
src/zir.zig+8| ... | @@ -365,6 +365,10 @@ pub const Inst = struct { | ... | @@ -365,6 +365,10 @@ pub const Inst = struct { |
| 365 | /// Make an integer type out of signedness and bit count. | 365 | /// Make an integer type out of signedness and bit count. |
| 366 | /// Payload is `int_type` | 366 | /// Payload is `int_type` |
| 367 | int_type, | 367 | int_type, |
| 368 | /// Convert an error type to `u16` | ||
| 369 | error_to_int, | ||
| 370 | /// Convert a `u16` to `anyerror` | ||
| 371 | int_to_error, | ||
| 368 | /// Return a boolean false if an optional is null. `x != null` | 372 | /// Return a boolean false if an optional is null. `x != null` |
| 369 | /// Uses the `un_node` field. | 373 | /// Uses the `un_node` field. |
| 370 | is_non_null, | 374 | is_non_null, |
| ... | @@ -728,6 +732,8 @@ pub const Inst = struct { | ... | @@ -728,6 +732,8 @@ pub const Inst = struct { |
| 728 | .err_union_payload_unsafe_ptr, | 732 | .err_union_payload_unsafe_ptr, |
| 729 | .err_union_code, | 733 | .err_union_code, |
| 730 | .err_union_code_ptr, | 734 | .err_union_code_ptr, |
| 735 | .error_to_int, | ||
| 736 | .int_to_error, | ||
| 731 | .ptr_type, | 737 | .ptr_type, |
| 732 | .ptr_type_simple, | 738 | .ptr_type_simple, |
| 733 | .ensure_err_payload_void, | 739 | .ensure_err_payload_void, |
| ... | @@ -1414,6 +1420,8 @@ const Writer = struct { | ... | @@ -1414,6 +1420,8 @@ const Writer = struct { |
| 1414 | .err_union_payload_unsafe_ptr, | 1420 | .err_union_payload_unsafe_ptr, |
| 1415 | .err_union_code, | 1421 | .err_union_code, |
| 1416 | .err_union_code_ptr, | 1422 | .err_union_code_ptr, |
| 1423 | .int_to_error, | ||
| 1424 | .error_to_int, | ||
| 1417 | .is_non_null, | 1425 | .is_non_null, |
| 1418 | .is_null, | 1426 | .is_null, |
| 1419 | .is_non_null_ptr, | 1427 | .is_non_null_ptr, |
test/stage2/cbe.zig+36| ... | @@ -54,6 +54,42 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -54,6 +54,42 @@ pub fn addCases(ctx: *TestContext) !void { |
| 54 | , "Hello, world!" ++ std.cstr.line_sep); | 54 | , "Hello, world!" ++ std.cstr.line_sep); |
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | { | ||
| 58 | var case = ctx.exeFromCompiledC("@intToError", .{}); | ||
| 59 | |||
| 60 | case.addCompareOutput( | ||
| 61 | \\pub export fn main() c_int { | ||
| 62 | \\ // comptime checks | ||
| 63 | \\ const a = error.A; | ||
| 64 | \\ const b = error.B; | ||
| 65 | \\ const c = @intToError(2); | ||
| 66 | \\ const d = @intToError(1); | ||
| 67 | \\ if (!(c == b)) unreachable; | ||
| 68 | \\ if (!(a == d)) unreachable; | ||
| 69 | \\ // runtime checks | ||
| 70 | \\ var x = error.A; | ||
| 71 | \\ var y = error.B; | ||
| 72 | \\ var z = @intToError(2); | ||
| 73 | \\ var f = @intToError(1); | ||
| 74 | \\ if (!(y == z)) unreachable; | ||
| 75 | \\ if (!(x == f)) unreachable; | ||
| 76 | \\ return 0; | ||
| 77 | \\} | ||
| 78 | , ""); | ||
| 79 | case.addError( | ||
| 80 | \\pub export fn main() c_int { | ||
| 81 | \\ const c = @intToError(0); | ||
| 82 | \\ return 0; | ||
| 83 | \\} | ||
| 84 | , &.{":2:27: error: integer value 0 represents no error"}); | ||
| 85 | case.addError( | ||
| 86 | \\pub export fn main() c_int { | ||
| 87 | \\ const c = @intToError(3); | ||
| 88 | \\ return 0; | ||
| 89 | \\} | ||
| 90 | , &.{":2:27: error: integer value 3 represents no error"}); | ||
| 91 | } | ||
| 92 | |||
| 57 | { | 93 | { |
| 58 | var case = ctx.exeFromCompiledC("x86_64-linux inline assembly", linux_x64); | 94 | var case = ctx.exeFromCompiledC("x86_64-linux inline assembly", linux_x64); |
| 59 | 95 |