mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 14:23:09 +00:00
stage2: @errorName sema+llvm
This commit is contained in:
parent
3f586781b6
commit
4931b8dc93
@ -501,6 +501,10 @@ pub const Inst = struct {
|
|||||||
/// Uses the `un_op` field.
|
/// Uses the `un_op` field.
|
||||||
tag_name,
|
tag_name,
|
||||||
|
|
||||||
|
/// Given an error value, return the error name. Result type is always `[:0] const u8`.
|
||||||
|
/// Uses the `un_op` field.
|
||||||
|
error_name,
|
||||||
|
|
||||||
pub fn fromCmpOp(op: std.math.CompareOperator) Tag {
|
pub fn fromCmpOp(op: std.math.CompareOperator) Tag {
|
||||||
return switch (op) {
|
return switch (op) {
|
||||||
.lt => .cmp_lt,
|
.lt => .cmp_lt,
|
||||||
@ -816,7 +820,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
|
|||||||
|
|
||||||
.bool_to_int => return Type.initTag(.u1),
|
.bool_to_int => return Type.initTag(.u1),
|
||||||
|
|
||||||
.tag_name => return Type.initTag(.const_slice_u8_sentinel_0),
|
.tag_name, .error_name => return Type.initTag(.const_slice_u8_sentinel_0),
|
||||||
|
|
||||||
.call => {
|
.call => {
|
||||||
const callee_ty = air.typeOf(datas[inst].pl_op.operand);
|
const callee_ty = air.typeOf(datas[inst].pl_op.operand);
|
||||||
|
|||||||
@ -334,6 +334,7 @@ fn analyzeInst(
|
|||||||
.ret,
|
.ret,
|
||||||
.ret_load,
|
.ret_load,
|
||||||
.tag_name,
|
.tag_name,
|
||||||
|
.error_name,
|
||||||
=> {
|
=> {
|
||||||
const operand = inst_datas[inst].un_op;
|
const operand = inst_datas[inst].un_op;
|
||||||
return trackOperands(a, new_set, inst, main_tomb, .{ operand, .none, .none });
|
return trackOperands(a, new_set, inst, main_tomb, .{ operand, .none, .none });
|
||||||
|
|||||||
13
src/Sema.zig
13
src/Sema.zig
@ -10478,7 +10478,18 @@ fn zirBoolToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
|
|||||||
fn zirErrorName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
fn zirErrorName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
||||||
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
|
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
|
||||||
const src = inst_data.src();
|
const src = inst_data.src();
|
||||||
return sema.fail(block, src, "TODO: Sema.zirErrorName", .{});
|
_ = src;
|
||||||
|
const operand = sema.resolveInst(inst_data.operand);
|
||||||
|
const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
|
||||||
|
|
||||||
|
if (try sema.resolveDefinedValue(block, operand_src, operand)) |val| {
|
||||||
|
const bytes = val.castTag(.@"error").?.data.name;
|
||||||
|
return sema.addStrLit(block, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Similar to zirTagName, we have special AIR instruction for the error name in case an optimimzation pass
|
||||||
|
// might be able to resolve the result at compile time.
|
||||||
|
return block.addUnOp(.error_name, operand);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn zirUnaryMath(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
fn zirUnaryMath(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
||||||
|
|||||||
@ -592,6 +592,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
|||||||
.ctz => try self.airCtz(inst),
|
.ctz => try self.airCtz(inst),
|
||||||
.popcount => try self.airPopcount(inst),
|
.popcount => try self.airPopcount(inst),
|
||||||
.tag_name => try self.airTagName(inst),
|
.tag_name => try self.airTagName(inst),
|
||||||
|
.error_name => try self.airErrorName(inst),
|
||||||
|
|
||||||
.atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
|
.atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
|
||||||
.atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
|
.atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
|
||||||
@ -2557,6 +2558,16 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
|
|||||||
return self.finishAir(inst, result, .{ un_op, .none, .none });
|
return self.finishAir(inst, result, .{ un_op, .none, .none });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
|
||||||
|
const un_op = self.air.instructions.items(.data)[inst].un_op;
|
||||||
|
const operand = try self.resolveInst(un_op);
|
||||||
|
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else {
|
||||||
|
_ = operand;
|
||||||
|
return self.fail("TODO implement airErrorName for aarch64", .{});
|
||||||
|
};
|
||||||
|
return self.finishAir(inst, result, .{ un_op, .none, .none });
|
||||||
|
}
|
||||||
|
|
||||||
fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
|
fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
|
||||||
// First section of indexes correspond to a set number of constant values.
|
// First section of indexes correspond to a set number of constant values.
|
||||||
const ref_int = @enumToInt(inst);
|
const ref_int = @enumToInt(inst);
|
||||||
|
|||||||
@ -590,6 +590,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
|||||||
.ctz => try self.airCtz(inst),
|
.ctz => try self.airCtz(inst),
|
||||||
.popcount => try self.airPopcount(inst),
|
.popcount => try self.airPopcount(inst),
|
||||||
.tag_name => try self.airTagName(inst),
|
.tag_name => try self.airTagName(inst),
|
||||||
|
.error_name => try self.airErrorName(inst),
|
||||||
|
|
||||||
.atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
|
.atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
|
||||||
.atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
|
.atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
|
||||||
@ -3682,6 +3683,16 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
|
|||||||
return self.finishAir(inst, result, .{ un_op, .none, .none });
|
return self.finishAir(inst, result, .{ un_op, .none, .none });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
|
||||||
|
const un_op = self.air.instructions.items(.data)[inst].un_op;
|
||||||
|
const operand = try self.resolveInst(un_op);
|
||||||
|
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else {
|
||||||
|
_ = operand;
|
||||||
|
return self.fail("TODO implement airErrorName for arm", .{});
|
||||||
|
};
|
||||||
|
return self.finishAir(inst, result, .{ un_op, .none, .none });
|
||||||
|
}
|
||||||
|
|
||||||
fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
|
fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
|
||||||
// First section of indexes correspond to a set number of constant values.
|
// First section of indexes correspond to a set number of constant values.
|
||||||
const ref_int = @enumToInt(inst);
|
const ref_int = @enumToInt(inst);
|
||||||
|
|||||||
@ -571,6 +571,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
|||||||
.ctz => try self.airCtz(inst),
|
.ctz => try self.airCtz(inst),
|
||||||
.popcount => try self.airPopcount(inst),
|
.popcount => try self.airPopcount(inst),
|
||||||
.tag_name => try self.airTagName(inst),
|
.tag_name => try self.airTagName(inst),
|
||||||
|
.error_name => try self.airErrorName(inst),
|
||||||
|
|
||||||
.atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
|
.atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
|
||||||
.atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
|
.atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
|
||||||
@ -2056,6 +2057,16 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
|
|||||||
return self.finishAir(inst, result, .{ un_op, .none, .none });
|
return self.finishAir(inst, result, .{ un_op, .none, .none });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
|
||||||
|
const un_op = self.air.instructions.items(.data)[inst].un_op;
|
||||||
|
const operand = try self.resolveInst(un_op);
|
||||||
|
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else {
|
||||||
|
_ = operand;
|
||||||
|
return self.fail("TODO implement airErrorName for riscv64", .{});
|
||||||
|
};
|
||||||
|
return self.finishAir(inst, result, .{ un_op, .none, .none });
|
||||||
|
}
|
||||||
|
|
||||||
fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
|
fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
|
||||||
// First section of indexes correspond to a set number of constant values.
|
// First section of indexes correspond to a set number of constant values.
|
||||||
const ref_int = @enumToInt(inst);
|
const ref_int = @enumToInt(inst);
|
||||||
|
|||||||
@ -635,6 +635,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
|||||||
.ctz => try self.airCtz(inst),
|
.ctz => try self.airCtz(inst),
|
||||||
.popcount => try self.airPopcount(inst),
|
.popcount => try self.airPopcount(inst),
|
||||||
.tag_name => try self.airTagName(inst),
|
.tag_name => try self.airTagName(inst),
|
||||||
|
.error_name, => try self.airErrorName(inst),
|
||||||
|
|
||||||
.atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
|
.atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
|
||||||
.atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
|
.atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
|
||||||
@ -3649,6 +3650,16 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
|
|||||||
return self.finishAir(inst, result, .{ un_op, .none, .none });
|
return self.finishAir(inst, result, .{ un_op, .none, .none });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
|
||||||
|
const un_op = self.air.instructions.items(.data)[inst].un_op;
|
||||||
|
const operand = try self.resolveInst(un_op);
|
||||||
|
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else {
|
||||||
|
_ = operand;
|
||||||
|
return self.fail("TODO implement airErrorName for x86_64", .{});
|
||||||
|
};
|
||||||
|
return self.finishAir(inst, result, .{ un_op, .none, .none });
|
||||||
|
}
|
||||||
|
|
||||||
fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
|
fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
|
||||||
// First section of indexes correspond to a set number of constant values.
|
// First section of indexes correspond to a set number of constant values.
|
||||||
const ref_int = @enumToInt(inst);
|
const ref_int = @enumToInt(inst);
|
||||||
|
|||||||
@ -1244,6 +1244,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
|
|||||||
.ctz => try airBuiltinCall(f, inst, "ctz"),
|
.ctz => try airBuiltinCall(f, inst, "ctz"),
|
||||||
.popcount => try airBuiltinCall(f, inst, "popcount"),
|
.popcount => try airBuiltinCall(f, inst, "popcount"),
|
||||||
.tag_name => try airTagName(f, inst),
|
.tag_name => try airTagName(f, inst),
|
||||||
|
.error_name => try airErrorName(f, inst),
|
||||||
|
|
||||||
.int_to_float,
|
.int_to_float,
|
||||||
.float_to_int,
|
.float_to_int,
|
||||||
@ -2998,6 +2999,22 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {
|
|||||||
//return local;
|
//return local;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn airErrorName(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||||
|
if (f.liveness.isUnused(inst)) return CValue.none;
|
||||||
|
|
||||||
|
const un_op = f.air.instructions.items(.data)[inst].un_op;
|
||||||
|
const writer = f.object.writer();
|
||||||
|
const inst_ty = f.air.typeOfIndex(inst);
|
||||||
|
const operand = try f.resolveInst(un_op);
|
||||||
|
const local = try f.allocLocal(inst_ty, .Const);
|
||||||
|
|
||||||
|
try writer.writeAll(" = ");
|
||||||
|
|
||||||
|
_ = operand;
|
||||||
|
_ = local;
|
||||||
|
return f.fail("TODO: C backend: implement airErrorName", .{});
|
||||||
|
}
|
||||||
|
|
||||||
fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 {
|
fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 {
|
||||||
return switch (order) {
|
return switch (order) {
|
||||||
.Unordered => "memory_order_relaxed",
|
.Unordered => "memory_order_relaxed",
|
||||||
|
|||||||
@ -181,6 +181,9 @@ pub const Object = struct {
|
|||||||
/// The backing memory for `type_map`. Periodically garbage collected after flush().
|
/// The backing memory for `type_map`. Periodically garbage collected after flush().
|
||||||
/// The code for doing the periodical GC is not yet implemented.
|
/// The code for doing the periodical GC is not yet implemented.
|
||||||
type_map_arena: std.heap.ArenaAllocator,
|
type_map_arena: std.heap.ArenaAllocator,
|
||||||
|
/// The LLVM global table which holds the names corresponding to Zig errors. Note that the values
|
||||||
|
/// are not added until flushModule, when all errors in the compilation are known.
|
||||||
|
error_name_table: ?*const llvm.Value,
|
||||||
|
|
||||||
pub const TypeMap = std.HashMapUnmanaged(
|
pub const TypeMap = std.HashMapUnmanaged(
|
||||||
Type,
|
Type,
|
||||||
@ -269,6 +272,7 @@ pub const Object = struct {
|
|||||||
.decl_map = .{},
|
.decl_map = .{},
|
||||||
.type_map = .{},
|
.type_map = .{},
|
||||||
.type_map_arena = std.heap.ArenaAllocator.init(gpa),
|
.type_map_arena = std.heap.ArenaAllocator.init(gpa),
|
||||||
|
.error_name_table = null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,7 +302,60 @@ pub const Object = struct {
|
|||||||
return slice.ptr;
|
return slice.ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn genErrorNameTable(self: *Object, comp: *Compilation) !void {
|
||||||
|
// If self.error_name_table is null, there was no instruction that actually referenced the error table.
|
||||||
|
const error_name_table_ptr_global = self.error_name_table orelse return;
|
||||||
|
|
||||||
|
const mod = comp.bin_file.options.module.?;
|
||||||
|
const target = mod.getTarget();
|
||||||
|
|
||||||
|
const llvm_ptr_ty = self.context.intType(8).pointerType(0); // TODO: Address space
|
||||||
|
const llvm_usize_ty = self.context.intType(target.cpu.arch.ptrBitWidth());
|
||||||
|
const type_fields = [_]*const llvm.Type{
|
||||||
|
llvm_ptr_ty,
|
||||||
|
llvm_usize_ty,
|
||||||
|
};
|
||||||
|
const llvm_slice_ty = self.context.structType(&type_fields, type_fields.len, .False);
|
||||||
|
const slice_ty = Type.initTag(.const_slice_u8_sentinel_0);
|
||||||
|
const slice_alignment = slice_ty.abiAlignment(target);
|
||||||
|
|
||||||
|
const error_name_list = mod.error_name_list.items;
|
||||||
|
const llvm_errors = try comp.gpa.alloc(*const llvm.Value, error_name_list.len);
|
||||||
|
defer comp.gpa.free(llvm_errors);
|
||||||
|
|
||||||
|
llvm_errors[0] = llvm_slice_ty.getUndef();
|
||||||
|
for (llvm_errors[1..]) |*llvm_error, i| {
|
||||||
|
const name = error_name_list[1..][i];
|
||||||
|
const str_init = self.context.constString(name.ptr, @intCast(c_uint, name.len), .False);
|
||||||
|
const str_global = self.llvm_module.addGlobal(str_init.typeOf(), "");
|
||||||
|
str_global.setInitializer(str_init);
|
||||||
|
str_global.setLinkage(.Private);
|
||||||
|
str_global.setGlobalConstant(.True);
|
||||||
|
str_global.setUnnamedAddr(.True);
|
||||||
|
str_global.setAlignment(1);
|
||||||
|
|
||||||
|
const slice_fields = [_]*const llvm.Value{
|
||||||
|
str_global.constBitCast(llvm_ptr_ty),
|
||||||
|
llvm_usize_ty.constInt(name.len, .False),
|
||||||
|
};
|
||||||
|
llvm_error.* = llvm_slice_ty.constNamedStruct(&slice_fields, slice_fields.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
const error_name_table_init = llvm_slice_ty.constArray(llvm_errors.ptr, @intCast(c_uint, error_name_list.len));
|
||||||
|
|
||||||
|
const error_name_table_global = self.llvm_module.addGlobal(error_name_table_init.typeOf(), "");
|
||||||
|
error_name_table_global.setInitializer(error_name_table_init);
|
||||||
|
error_name_table_global.setLinkage(.Private);
|
||||||
|
error_name_table_global.setGlobalConstant(.True);
|
||||||
|
error_name_table_global.setUnnamedAddr(.True);
|
||||||
|
error_name_table_global.setAlignment(slice_alignment); // TODO: Dont hardcode
|
||||||
|
|
||||||
|
const error_name_table_ptr = error_name_table_global.constBitCast(llvm_slice_ty.pointerType(0)); // TODO: Address space
|
||||||
|
error_name_table_ptr_global.setInitializer(error_name_table_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn flushModule(self: *Object, comp: *Compilation) !void {
|
pub fn flushModule(self: *Object, comp: *Compilation) !void {
|
||||||
|
try self.genErrorNameTable(comp);
|
||||||
if (comp.verbose_llvm_ir) {
|
if (comp.verbose_llvm_ir) {
|
||||||
self.llvm_module.dump();
|
self.llvm_module.dump();
|
||||||
}
|
}
|
||||||
@ -2031,6 +2088,7 @@ pub const FuncGen = struct {
|
|||||||
.ctz => try self.airClzCtz(inst, "cttz"),
|
.ctz => try self.airClzCtz(inst, "cttz"),
|
||||||
.popcount => try self.airPopCount(inst, "ctpop"),
|
.popcount => try self.airPopCount(inst, "ctpop"),
|
||||||
.tag_name => try self.airTagName(inst),
|
.tag_name => try self.airTagName(inst),
|
||||||
|
.error_name => try self.airErrorName(inst),
|
||||||
|
|
||||||
.atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
|
.atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
|
||||||
.atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
|
.atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
|
||||||
@ -4279,6 +4337,40 @@ pub const FuncGen = struct {
|
|||||||
return fn_val;
|
return fn_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn airErrorName(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
|
||||||
|
if (self.liveness.isUnused(inst)) return null;
|
||||||
|
|
||||||
|
const un_op = self.air.instructions.items(.data)[inst].un_op;
|
||||||
|
const operand = try self.resolveInst(un_op);
|
||||||
|
|
||||||
|
const error_name_table_ptr = try self.getErrorNameTable();
|
||||||
|
const error_name_table = self.builder.buildLoad(error_name_table_ptr, "");
|
||||||
|
const indices = [_]*const llvm.Value{operand};
|
||||||
|
const error_name_ptr = self.builder.buildInBoundsGEP(error_name_table, &indices, indices.len, "");
|
||||||
|
return self.builder.buildLoad(error_name_ptr, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getErrorNameTable(self: *FuncGen) !*const llvm.Value {
|
||||||
|
if (self.dg.object.error_name_table) |table| {
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
const slice_ty = Type.initTag(.const_slice_u8_sentinel_0);
|
||||||
|
const slice_alignment = slice_ty.abiAlignment(self.dg.module.getTarget());
|
||||||
|
const llvm_slice_ty = try self.dg.llvmType(slice_ty);
|
||||||
|
const llvm_slice_ptr_ty = llvm_slice_ty.pointerType(0); // TODO: Address space
|
||||||
|
|
||||||
|
const error_name_table_global = self.dg.object.llvm_module.addGlobal(llvm_slice_ptr_ty, "__zig_err_name_table");
|
||||||
|
error_name_table_global.setInitializer(llvm_slice_ptr_ty.getUndef());
|
||||||
|
error_name_table_global.setLinkage(.Private);
|
||||||
|
error_name_table_global.setGlobalConstant(.True);
|
||||||
|
error_name_table_global.setUnnamedAddr(.True);
|
||||||
|
error_name_table_global.setAlignment(slice_alignment);
|
||||||
|
|
||||||
|
self.dg.object.error_name_table = error_name_table_global;
|
||||||
|
return error_name_table_global;
|
||||||
|
}
|
||||||
|
|
||||||
/// Assumes the optional is not pointer-like and payload has bits.
|
/// Assumes the optional is not pointer-like and payload has bits.
|
||||||
fn optIsNonNull(self: *FuncGen, opt_handle: *const llvm.Value, is_by_ref: bool) *const llvm.Value {
|
fn optIsNonNull(self: *FuncGen, opt_handle: *const llvm.Value, is_by_ref: bool) *const llvm.Value {
|
||||||
if (is_by_ref) {
|
if (is_by_ref) {
|
||||||
|
|||||||
@ -156,6 +156,7 @@ const Writer = struct {
|
|||||||
.ret,
|
.ret,
|
||||||
.ret_load,
|
.ret_load,
|
||||||
.tag_name,
|
.tag_name,
|
||||||
|
.error_name,
|
||||||
=> try w.writeUnOp(s, inst),
|
=> try w.writeUnOp(s, inst),
|
||||||
|
|
||||||
.breakpoint,
|
.breakpoint,
|
||||||
|
|||||||
@ -90,6 +90,7 @@ test {
|
|||||||
_ = @import("behavior/bugs/9584.zig");
|
_ = @import("behavior/bugs/9584.zig");
|
||||||
_ = @import("behavior/cast_llvm.zig");
|
_ = @import("behavior/cast_llvm.zig");
|
||||||
_ = @import("behavior/enum_llvm.zig");
|
_ = @import("behavior/enum_llvm.zig");
|
||||||
|
_ = @import("behavior/error_llvm.zig");
|
||||||
_ = @import("behavior/eval.zig");
|
_ = @import("behavior/eval.zig");
|
||||||
_ = @import("behavior/floatop.zig");
|
_ = @import("behavior/floatop.zig");
|
||||||
_ = @import("behavior/fn.zig");
|
_ = @import("behavior/fn.zig");
|
||||||
|
|||||||
24
test/behavior/error_llvm.zig
Normal file
24
test/behavior/error_llvm.zig
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const expect = std.testing.expect;
|
||||||
|
const mem = std.mem;
|
||||||
|
|
||||||
|
fn gimmeItBroke() anyerror {
|
||||||
|
return error.ItBroke;
|
||||||
|
}
|
||||||
|
|
||||||
|
test "@errorName" {
|
||||||
|
try expect(mem.eql(u8, @errorName(error.AnError), "AnError"));
|
||||||
|
try expect(mem.eql(u8, @errorName(error.ALongerErrorName), "ALongerErrorName"));
|
||||||
|
try expect(mem.eql(u8, @errorName(gimmeItBroke()), "ItBroke"));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "@errorName sentinel length matches slice length" {
|
||||||
|
const name = testBuiltinErrorName(error.FooBar);
|
||||||
|
const length: usize = 6;
|
||||||
|
try expect(length == std.mem.indexOfSentinel(u8, 0, name.ptr));
|
||||||
|
try expect(length == name.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn testBuiltinErrorName(err: anyerror) [:0]const u8 {
|
||||||
|
return @errorName(err);
|
||||||
|
}
|
||||||
@ -4,27 +4,6 @@ const expectError = std.testing.expectError;
|
|||||||
const expectEqual = std.testing.expectEqual;
|
const expectEqual = std.testing.expectEqual;
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
|
|
||||||
fn gimmeItBroke() anyerror {
|
|
||||||
return error.ItBroke;
|
|
||||||
}
|
|
||||||
|
|
||||||
test "@errorName" {
|
|
||||||
try expect(mem.eql(u8, @errorName(error.AnError), "AnError"));
|
|
||||||
try expect(mem.eql(u8, @errorName(error.ALongerErrorName), "ALongerErrorName"));
|
|
||||||
try expect(mem.eql(u8, @errorName(gimmeItBroke()), "ItBroke"));
|
|
||||||
}
|
|
||||||
|
|
||||||
test "@errorName sentinel length matches slice length" {
|
|
||||||
const name = testBuiltinErrorName(error.FooBar);
|
|
||||||
const length: usize = 6;
|
|
||||||
try expectEqual(length, std.mem.indexOfSentinel(u8, 0, name.ptr));
|
|
||||||
try expectEqual(length, name.len);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn testBuiltinErrorName(err: anyerror) [:0]const u8 {
|
|
||||||
return @errorName(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
test "error union type " {
|
test "error union type " {
|
||||||
try testErrorUnionType();
|
try testErrorUnionType();
|
||||||
comptime try testErrorUnionType();
|
comptime try testErrorUnionType();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user