authorgravatar for jacoblevgw@gmail.comJacob G-W <jacoblevgw@gmail.com> 2021-03-26 17:54:41-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-03-28 18:22:01-07:00
log0005b346375f1fbe7bc42c22d658e3218bbd599d
treed88211b36f2be7689a138bf0d5f1a2e62f695323
parentf80f8a7a7835db5f8b13aab23b4ee79e88c25e63

stage2: implement sema for @errorToInt and @intToError


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 };
942942
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.
81global_error_set: std.StringHashMapUnmanaged(u16) = .{},81global_error_set: std.StringHashMapUnmanaged(u16) = .{},
8282
83/// error u16 -> []const u8 for fast lookups for @intToError at comptime
84error_name_list: ArrayListUnmanaged([]const u8) = .{},
85
83/// Keys are fully qualified paths86/// Keys are fully qualified paths
84import_table: std.StringArrayHashMapUnmanaged(*Scope.File) = .{},87import_table: std.StringArrayHashMapUnmanaged(*Scope.File) = .{},
8588
...@@ -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);
18951913
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);
33503369
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}
33553377
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}
14621464
1465fn 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
1491fn 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
1463fn zirMergeErrorSets(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {1524fn 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};
32463308
3247fn addSafetyCheck(sema: *Sema, parent_block: *Scope.Block, ok: *Inst, panic_id: PanicId) !void {3309fn 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 }
25592561
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}
10741076
1077fn genIntToError(o: *Object, inst: *Inst.UnOp) !CValue {
1078 return o.resolveInst(inst.operand);
1079}
1080
1081fn genErrorToInt(o: *Object, inst: *Inst.UnOp) !CValue {
1082 return o.resolveInst(inst.operand);
1083}
1084
1075fn IndentWriter(comptime UnderlyingWriter: type) type {1085fn 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 => bool93 /// *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 error188 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 }
5656
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);
5995