authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2022-01-08 02:02:01+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-01-08 14:30:11-05:00
log4931b8dc93ee4a99a415dffab03d400e95d1a90a
tree8586196d647638d70dd7c3c3e657f9adeabdb39c
parent3f586781b6c8d698468cc58ab64797097323c253

stage2: @errorName sema+llvm


13 files changed, 197 insertions(+), 23 deletions(-)

src/Air.zig+5-1
...@@ -501,6 +501,10 @@ pub const Inst = struct {...@@ -501,6 +501,10 @@ pub const Inst = struct {
501 /// Uses the `un_op` field.501 /// Uses the `un_op` field.
502 tag_name,502 tag_name,
503503
504 /// Given an error value, return the error name. Result type is always `[:0] const u8`.
505 /// Uses the `un_op` field.
506 error_name,
507
504 pub fn fromCmpOp(op: std.math.CompareOperator) Tag {508 pub fn fromCmpOp(op: std.math.CompareOperator) Tag {
505 return switch (op) {509 return switch (op) {
506 .lt => .cmp_lt,510 .lt => .cmp_lt,
...@@ -816,7 +820,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -816,7 +820,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
816820
817 .bool_to_int => return Type.initTag(.u1),821 .bool_to_int => return Type.initTag(.u1),
818822
819 .tag_name => return Type.initTag(.const_slice_u8_sentinel_0),823 .tag_name, .error_name => return Type.initTag(.const_slice_u8_sentinel_0),
820824
821 .call => {825 .call => {
822 const callee_ty = air.typeOf(datas[inst].pl_op.operand);826 const callee_ty = air.typeOf(datas[inst].pl_op.operand);
src/Liveness.zig+1
...@@ -334,6 +334,7 @@ fn analyzeInst(...@@ -334,6 +334,7 @@ fn analyzeInst(
334 .ret,334 .ret,
335 .ret_load,335 .ret_load,
336 .tag_name,336 .tag_name,
337 .error_name,
337 => {338 => {
338 const operand = inst_datas[inst].un_op;339 const operand = inst_datas[inst].un_op;
339 return trackOperands(a, new_set, inst, main_tomb, .{ operand, .none, .none });340 return trackOperands(a, new_set, inst, main_tomb, .{ operand, .none, .none });
src/Sema.zig+12-1
...@@ -10478,7 +10478,18 @@ fn zirBoolToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -10478,7 +10478,18 @@ fn zirBoolToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
10478fn zirErrorName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {10478fn zirErrorName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
10479 const inst_data = sema.code.instructions.items(.data)[inst].un_node;10479 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
10480 const src = inst_data.src();10480 const src = inst_data.src();
10481 return sema.fail(block, src, "TODO: Sema.zirErrorName", .{});10481 _ = src;
10482 const operand = sema.resolveInst(inst_data.operand);
10483 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
10484
10485 if (try sema.resolveDefinedValue(block, operand_src, operand)) |val| {
10486 const bytes = val.castTag(.@"error").?.data.name;
10487 return sema.addStrLit(block, bytes);
10488 }
10489
10490 // Similar to zirTagName, we have special AIR instruction for the error name in case an optimimzation pass
10491 // might be able to resolve the result at compile time.
10492 return block.addUnOp(.error_name, operand);
10482}10493}
1048310494
10484fn zirUnaryMath(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {10495fn zirUnaryMath(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
src/arch/aarch64/CodeGen.zig+11
...@@ -592,6 +592,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -592,6 +592,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
592 .ctz => try self.airCtz(inst),592 .ctz => try self.airCtz(inst),
593 .popcount => try self.airPopcount(inst),593 .popcount => try self.airPopcount(inst),
594 .tag_name => try self.airTagName(inst),594 .tag_name => try self.airTagName(inst),
595 .error_name => try self.airErrorName(inst),
595596
596 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),597 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
597 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),598 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
...@@ -2557,6 +2558,16 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void {...@@ -2557,6 +2558,16 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
2557 return self.finishAir(inst, result, .{ un_op, .none, .none });2558 return self.finishAir(inst, result, .{ un_op, .none, .none });
2558}2559}
25592560
2561fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
2562 const un_op = self.air.instructions.items(.data)[inst].un_op;
2563 const operand = try self.resolveInst(un_op);
2564 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else {
2565 _ = operand;
2566 return self.fail("TODO implement airErrorName for aarch64", .{});
2567 };
2568 return self.finishAir(inst, result, .{ un_op, .none, .none });
2569}
2570
2560fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {2571fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
2561 // First section of indexes correspond to a set number of constant values.2572 // First section of indexes correspond to a set number of constant values.
2562 const ref_int = @enumToInt(inst);2573 const ref_int = @enumToInt(inst);
src/arch/arm/CodeGen.zig+11
...@@ -590,6 +590,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -590,6 +590,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
590 .ctz => try self.airCtz(inst),590 .ctz => try self.airCtz(inst),
591 .popcount => try self.airPopcount(inst),591 .popcount => try self.airPopcount(inst),
592 .tag_name => try self.airTagName(inst),592 .tag_name => try self.airTagName(inst),
593 .error_name => try self.airErrorName(inst),
593594
594 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),595 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
595 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),596 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
...@@ -3682,6 +3683,16 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void {...@@ -3682,6 +3683,16 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
3682 return self.finishAir(inst, result, .{ un_op, .none, .none });3683 return self.finishAir(inst, result, .{ un_op, .none, .none });
3683}3684}
36843685
3686fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
3687 const un_op = self.air.instructions.items(.data)[inst].un_op;
3688 const operand = try self.resolveInst(un_op);
3689 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else {
3690 _ = operand;
3691 return self.fail("TODO implement airErrorName for arm", .{});
3692 };
3693 return self.finishAir(inst, result, .{ un_op, .none, .none });
3694}
3695
3685fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {3696fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
3686 // First section of indexes correspond to a set number of constant values.3697 // First section of indexes correspond to a set number of constant values.
3687 const ref_int = @enumToInt(inst);3698 const ref_int = @enumToInt(inst);
src/arch/riscv64/CodeGen.zig+11
...@@ -571,6 +571,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -571,6 +571,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
571 .ctz => try self.airCtz(inst),571 .ctz => try self.airCtz(inst),
572 .popcount => try self.airPopcount(inst),572 .popcount => try self.airPopcount(inst),
573 .tag_name => try self.airTagName(inst),573 .tag_name => try self.airTagName(inst),
574 .error_name => try self.airErrorName(inst),
574575
575 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),576 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
576 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),577 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
...@@ -2056,6 +2057,16 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void {...@@ -2056,6 +2057,16 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
2056 return self.finishAir(inst, result, .{ un_op, .none, .none });2057 return self.finishAir(inst, result, .{ un_op, .none, .none });
2057}2058}
20582059
2060fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
2061 const un_op = self.air.instructions.items(.data)[inst].un_op;
2062 const operand = try self.resolveInst(un_op);
2063 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else {
2064 _ = operand;
2065 return self.fail("TODO implement airErrorName for riscv64", .{});
2066 };
2067 return self.finishAir(inst, result, .{ un_op, .none, .none });
2068}
2069
2059fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {2070fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
2060 // First section of indexes correspond to a set number of constant values.2071 // First section of indexes correspond to a set number of constant values.
2061 const ref_int = @enumToInt(inst);2072 const ref_int = @enumToInt(inst);
src/arch/x86_64/CodeGen.zig+11
...@@ -635,6 +635,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -635,6 +635,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
635 .ctz => try self.airCtz(inst),635 .ctz => try self.airCtz(inst),
636 .popcount => try self.airPopcount(inst),636 .popcount => try self.airPopcount(inst),
637 .tag_name => try self.airTagName(inst),637 .tag_name => try self.airTagName(inst),
638 .error_name, => try self.airErrorName(inst),
638639
639 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),640 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
640 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),641 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
...@@ -3649,6 +3650,16 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void {...@@ -3649,6 +3650,16 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
3649 return self.finishAir(inst, result, .{ un_op, .none, .none });3650 return self.finishAir(inst, result, .{ un_op, .none, .none });
3650}3651}
36513652
3653fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
3654 const un_op = self.air.instructions.items(.data)[inst].un_op;
3655 const operand = try self.resolveInst(un_op);
3656 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else {
3657 _ = operand;
3658 return self.fail("TODO implement airErrorName for x86_64", .{});
3659 };
3660 return self.finishAir(inst, result, .{ un_op, .none, .none });
3661}
3662
3652fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {3663fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
3653 // First section of indexes correspond to a set number of constant values.3664 // First section of indexes correspond to a set number of constant values.
3654 const ref_int = @enumToInt(inst);3665 const ref_int = @enumToInt(inst);
src/codegen/c.zig+17
...@@ -1244,6 +1244,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO...@@ -1244,6 +1244,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
1244 .ctz => try airBuiltinCall(f, inst, "ctz"),1244 .ctz => try airBuiltinCall(f, inst, "ctz"),
1245 .popcount => try airBuiltinCall(f, inst, "popcount"),1245 .popcount => try airBuiltinCall(f, inst, "popcount"),
1246 .tag_name => try airTagName(f, inst),1246 .tag_name => try airTagName(f, inst),
1247 .error_name => try airErrorName(f, inst),
12471248
1248 .int_to_float,1249 .int_to_float,
1249 .float_to_int,1250 .float_to_int,
...@@ -2998,6 +2999,22 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -2998,6 +2999,22 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {
2998 //return local;2999 //return local;
2999}3000}
30003001
3002fn airErrorName(f: *Function, inst: Air.Inst.Index) !CValue {
3003 if (f.liveness.isUnused(inst)) return CValue.none;
3004
3005 const un_op = f.air.instructions.items(.data)[inst].un_op;
3006 const writer = f.object.writer();
3007 const inst_ty = f.air.typeOfIndex(inst);
3008 const operand = try f.resolveInst(un_op);
3009 const local = try f.allocLocal(inst_ty, .Const);
3010
3011 try writer.writeAll(" = ");
3012
3013 _ = operand;
3014 _ = local;
3015 return f.fail("TODO: C backend: implement airErrorName", .{});
3016}
3017
3001fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 {3018fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 {
3002 return switch (order) {3019 return switch (order) {
3003 .Unordered => "memory_order_relaxed",3020 .Unordered => "memory_order_relaxed",
src/codegen/llvm.zig+92
...@@ -181,6 +181,9 @@ pub const Object = struct {...@@ -181,6 +181,9 @@ pub const Object = struct {
181 /// The backing memory for `type_map`. Periodically garbage collected after flush().181 /// The backing memory for `type_map`. Periodically garbage collected after flush().
182 /// The code for doing the periodical GC is not yet implemented.182 /// The code for doing the periodical GC is not yet implemented.
183 type_map_arena: std.heap.ArenaAllocator,183 type_map_arena: std.heap.ArenaAllocator,
184 /// The LLVM global table which holds the names corresponding to Zig errors. Note that the values
185 /// are not added until flushModule, when all errors in the compilation are known.
186 error_name_table: ?*const llvm.Value,
184187
185 pub const TypeMap = std.HashMapUnmanaged(188 pub const TypeMap = std.HashMapUnmanaged(
186 Type,189 Type,
...@@ -269,6 +272,7 @@ pub const Object = struct {...@@ -269,6 +272,7 @@ pub const Object = struct {
269 .decl_map = .{},272 .decl_map = .{},
270 .type_map = .{},273 .type_map = .{},
271 .type_map_arena = std.heap.ArenaAllocator.init(gpa),274 .type_map_arena = std.heap.ArenaAllocator.init(gpa),
275 .error_name_table = null,
272 };276 };
273 }277 }
274278
...@@ -298,7 +302,60 @@ pub const Object = struct {...@@ -298,7 +302,60 @@ pub const Object = struct {
298 return slice.ptr;302 return slice.ptr;
299 }303 }
300304
305 fn genErrorNameTable(self: *Object, comp: *Compilation) !void {
306 // If self.error_name_table is null, there was no instruction that actually referenced the error table.
307 const error_name_table_ptr_global = self.error_name_table orelse return;
308
309 const mod = comp.bin_file.options.module.?;
310 const target = mod.getTarget();
311
312 const llvm_ptr_ty = self.context.intType(8).pointerType(0); // TODO: Address space
313 const llvm_usize_ty = self.context.intType(target.cpu.arch.ptrBitWidth());
314 const type_fields = [_]*const llvm.Type{
315 llvm_ptr_ty,
316 llvm_usize_ty,
317 };
318 const llvm_slice_ty = self.context.structType(&type_fields, type_fields.len, .False);
319 const slice_ty = Type.initTag(.const_slice_u8_sentinel_0);
320 const slice_alignment = slice_ty.abiAlignment(target);
321
322 const error_name_list = mod.error_name_list.items;
323 const llvm_errors = try comp.gpa.alloc(*const llvm.Value, error_name_list.len);
324 defer comp.gpa.free(llvm_errors);
325
326 llvm_errors[0] = llvm_slice_ty.getUndef();
327 for (llvm_errors[1..]) |*llvm_error, i| {
328 const name = error_name_list[1..][i];
329 const str_init = self.context.constString(name.ptr, @intCast(c_uint, name.len), .False);
330 const str_global = self.llvm_module.addGlobal(str_init.typeOf(), "");
331 str_global.setInitializer(str_init);
332 str_global.setLinkage(.Private);
333 str_global.setGlobalConstant(.True);
334 str_global.setUnnamedAddr(.True);
335 str_global.setAlignment(1);
336
337 const slice_fields = [_]*const llvm.Value{
338 str_global.constBitCast(llvm_ptr_ty),
339 llvm_usize_ty.constInt(name.len, .False),
340 };
341 llvm_error.* = llvm_slice_ty.constNamedStruct(&slice_fields, slice_fields.len);
342 }
343
344 const error_name_table_init = llvm_slice_ty.constArray(llvm_errors.ptr, @intCast(c_uint, error_name_list.len));
345
346 const error_name_table_global = self.llvm_module.addGlobal(error_name_table_init.typeOf(), "");
347 error_name_table_global.setInitializer(error_name_table_init);
348 error_name_table_global.setLinkage(.Private);
349 error_name_table_global.setGlobalConstant(.True);
350 error_name_table_global.setUnnamedAddr(.True);
351 error_name_table_global.setAlignment(slice_alignment); // TODO: Dont hardcode
352
353 const error_name_table_ptr = error_name_table_global.constBitCast(llvm_slice_ty.pointerType(0)); // TODO: Address space
354 error_name_table_ptr_global.setInitializer(error_name_table_ptr);
355 }
356
301 pub fn flushModule(self: *Object, comp: *Compilation) !void {357 pub fn flushModule(self: *Object, comp: *Compilation) !void {
358 try self.genErrorNameTable(comp);
302 if (comp.verbose_llvm_ir) {359 if (comp.verbose_llvm_ir) {
303 self.llvm_module.dump();360 self.llvm_module.dump();
304 }361 }
...@@ -2031,6 +2088,7 @@ pub const FuncGen = struct {...@@ -2031,6 +2088,7 @@ pub const FuncGen = struct {
2031 .ctz => try self.airClzCtz(inst, "cttz"),2088 .ctz => try self.airClzCtz(inst, "cttz"),
2032 .popcount => try self.airPopCount(inst, "ctpop"),2089 .popcount => try self.airPopCount(inst, "ctpop"),
2033 .tag_name => try self.airTagName(inst),2090 .tag_name => try self.airTagName(inst),
2091 .error_name => try self.airErrorName(inst),
20342092
2035 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),2093 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
2036 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),2094 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
...@@ -4279,6 +4337,40 @@ pub const FuncGen = struct {...@@ -4279,6 +4337,40 @@ pub const FuncGen = struct {
4279 return fn_val;4337 return fn_val;
4280 }4338 }
42814339
4340 fn airErrorName(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
4341 if (self.liveness.isUnused(inst)) return null;
4342
4343 const un_op = self.air.instructions.items(.data)[inst].un_op;
4344 const operand = try self.resolveInst(un_op);
4345
4346 const error_name_table_ptr = try self.getErrorNameTable();
4347 const error_name_table = self.builder.buildLoad(error_name_table_ptr, "");
4348 const indices = [_]*const llvm.Value{operand};
4349 const error_name_ptr = self.builder.buildInBoundsGEP(error_name_table, &indices, indices.len, "");
4350 return self.builder.buildLoad(error_name_ptr, "");
4351 }
4352
4353 fn getErrorNameTable(self: *FuncGen) !*const llvm.Value {
4354 if (self.dg.object.error_name_table) |table| {
4355 return table;
4356 }
4357
4358 const slice_ty = Type.initTag(.const_slice_u8_sentinel_0);
4359 const slice_alignment = slice_ty.abiAlignment(self.dg.module.getTarget());
4360 const llvm_slice_ty = try self.dg.llvmType(slice_ty);
4361 const llvm_slice_ptr_ty = llvm_slice_ty.pointerType(0); // TODO: Address space
4362
4363 const error_name_table_global = self.dg.object.llvm_module.addGlobal(llvm_slice_ptr_ty, "__zig_err_name_table");
4364 error_name_table_global.setInitializer(llvm_slice_ptr_ty.getUndef());
4365 error_name_table_global.setLinkage(.Private);
4366 error_name_table_global.setGlobalConstant(.True);
4367 error_name_table_global.setUnnamedAddr(.True);
4368 error_name_table_global.setAlignment(slice_alignment);
4369
4370 self.dg.object.error_name_table = error_name_table_global;
4371 return error_name_table_global;
4372 }
4373
4282 /// Assumes the optional is not pointer-like and payload has bits.4374 /// Assumes the optional is not pointer-like and payload has bits.
4283 fn optIsNonNull(self: *FuncGen, opt_handle: *const llvm.Value, is_by_ref: bool) *const llvm.Value {4375 fn optIsNonNull(self: *FuncGen, opt_handle: *const llvm.Value, is_by_ref: bool) *const llvm.Value {
4284 if (is_by_ref) {4376 if (is_by_ref) {
src/print_air.zig+1
...@@ -156,6 +156,7 @@ const Writer = struct {...@@ -156,6 +156,7 @@ const Writer = struct {
156 .ret,156 .ret,
157 .ret_load,157 .ret_load,
158 .tag_name,158 .tag_name,
159 .error_name,
159 => try w.writeUnOp(s, inst),160 => try w.writeUnOp(s, inst),
160161
161 .breakpoint,162 .breakpoint,
test/behavior.zig+1
...@@ -90,6 +90,7 @@ test {...@@ -90,6 +90,7 @@ test {
90 _ = @import("behavior/bugs/9584.zig");90 _ = @import("behavior/bugs/9584.zig");
91 _ = @import("behavior/cast_llvm.zig");91 _ = @import("behavior/cast_llvm.zig");
92 _ = @import("behavior/enum_llvm.zig");92 _ = @import("behavior/enum_llvm.zig");
93 _ = @import("behavior/error_llvm.zig");
93 _ = @import("behavior/eval.zig");94 _ = @import("behavior/eval.zig");
94 _ = @import("behavior/floatop.zig");95 _ = @import("behavior/floatop.zig");
95 _ = @import("behavior/fn.zig");96 _ = @import("behavior/fn.zig");
test/behavior/error_llvm.zig created+24
...@@ -0,0 +1,24 @@
1const std = @import("std");
2const expect = std.testing.expect;
3const mem = std.mem;
4
5fn gimmeItBroke() anyerror {
6 return error.ItBroke;
7}
8
9test "@errorName" {
10 try expect(mem.eql(u8, @errorName(error.AnError), "AnError"));
11 try expect(mem.eql(u8, @errorName(error.ALongerErrorName), "ALongerErrorName"));
12 try expect(mem.eql(u8, @errorName(gimmeItBroke()), "ItBroke"));
13}
14
15test "@errorName sentinel length matches slice length" {
16 const name = testBuiltinErrorName(error.FooBar);
17 const length: usize = 6;
18 try expect(length == std.mem.indexOfSentinel(u8, 0, name.ptr));
19 try expect(length == name.len);
20}
21
22pub fn testBuiltinErrorName(err: anyerror) [:0]const u8 {
23 return @errorName(err);
24}
test/behavior/error_stage1.zig-21
...@@ -4,27 +4,6 @@ const expectError = std.testing.expectError;...@@ -4,27 +4,6 @@ const expectError = std.testing.expectError;
4const expectEqual = std.testing.expectEqual;4const expectEqual = std.testing.expectEqual;
5const mem = std.mem;5const mem = std.mem;
66
7fn gimmeItBroke() anyerror {
8 return error.ItBroke;
9}
10
11test "@errorName" {
12 try expect(mem.eql(u8, @errorName(error.AnError), "AnError"));
13 try expect(mem.eql(u8, @errorName(error.ALongerErrorName), "ALongerErrorName"));
14 try expect(mem.eql(u8, @errorName(gimmeItBroke()), "ItBroke"));
15}
16
17test "@errorName sentinel length matches slice length" {
18 const name = testBuiltinErrorName(error.FooBar);
19 const length: usize = 6;
20 try expectEqual(length, std.mem.indexOfSentinel(u8, 0, name.ptr));
21 try expectEqual(length, name.len);
22}
23
24pub fn testBuiltinErrorName(err: anyerror) [:0]const u8 {
25 return @errorName(err);
26}
27
28test "error union type " {7test "error union type " {
29 try testErrorUnionType();8 try testErrorUnionType();
30 comptime try testErrorUnionType();9 comptime try testErrorUnionType();