| author | |
| committer | |
| log | f46d7304b176cdc77053225943a7d5030dd0d4ee |
| tree | 483f0aa5303fe5a1ab4fbe9140d6dabf916d88b1 |
| parent | 19d5ffc710faa23cd07a6dff23d4afc43c0c7f63 |
15 files changed, 131 insertions(+), 7 deletions(-)
src/Air.zig+5| ... | @@ -660,6 +660,10 @@ pub const Inst = struct { | ... | @@ -660,6 +660,10 @@ pub const Inst = struct { |
| 660 | /// Uses the `pl_op` field with payload `AtomicRmw`. Operand is `ptr`. | 660 | /// Uses the `pl_op` field with payload `AtomicRmw`. Operand is `ptr`. |
| 661 | atomic_rmw, | 661 | atomic_rmw, |
| 662 | 662 | ||
| 663 | /// Returns true if enum tag value has a name. | ||
| 664 | /// Uses the `un_op` field. | ||
| 665 | is_named_enum_value, | ||
| 666 | |||
| 663 | /// Given an enum tag value, returns the tag name. The enum type may be non-exhaustive. | 667 | /// Given an enum tag value, returns the tag name. The enum type may be non-exhaustive. |
| 664 | /// Result type is always `[:0]const u8`. | 668 | /// Result type is always `[:0]const u8`. |
| 665 | /// Uses the `un_op` field. | 669 | /// Uses the `un_op` field. |
| ... | @@ -1057,6 +1061,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { | ... | @@ -1057,6 +1061,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 1057 | .is_non_err, | 1061 | .is_non_err, |
| 1058 | .is_err_ptr, | 1062 | .is_err_ptr, |
| 1059 | .is_non_err_ptr, | 1063 | .is_non_err_ptr, |
| 1064 | .is_named_enum_value, | ||
| 1060 | => return Type.bool, | 1065 | => return Type.bool, |
| 1061 | 1066 | ||
| 1062 | .const_ty => return Type.type, | 1067 | .const_ty => return Type.type, |
src/Liveness.zig+2| ... | @@ -291,6 +291,7 @@ pub fn categorizeOperand( | ... | @@ -291,6 +291,7 @@ pub fn categorizeOperand( |
| 291 | .is_non_err_ptr, | 291 | .is_non_err_ptr, |
| 292 | .ptrtoint, | 292 | .ptrtoint, |
| 293 | .bool_to_int, | 293 | .bool_to_int, |
| 294 | .is_named_enum_value, | ||
| 294 | .tag_name, | 295 | .tag_name, |
| 295 | .error_name, | 296 | .error_name, |
| 296 | .sqrt, | 297 | .sqrt, |
| ... | @@ -858,6 +859,7 @@ fn analyzeInst( | ... | @@ -858,6 +859,7 @@ fn analyzeInst( |
| 858 | .bool_to_int, | 859 | .bool_to_int, |
| 859 | .ret, | 860 | .ret, |
| 860 | .ret_load, | 861 | .ret_load, |
| 862 | .is_named_enum_value, | ||
| 861 | .tag_name, | 863 | .tag_name, |
| 862 | .error_name, | 864 | .error_name, |
| 863 | .sqrt, | 865 | .sqrt, |
src/Sema.zig+13-2| ... | @@ -6933,8 +6933,12 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -6933,8 +6933,12 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 6933 | } | 6933 | } |
| 6934 | 6934 | ||
| 6935 | try sema.requireRuntimeBlock(block, src, operand_src); | 6935 | try sema.requireRuntimeBlock(block, src, operand_src); |
| 6936 | // TODO insert safety check to make sure the value matches an enum value | 6936 | const result = try block.addTyOp(.intcast, dest_ty, operand); |
| 6937 | return block.addTyOp(.intcast, dest_ty, operand); | 6937 | if (block.wantSafety() and !dest_ty.isNonexhaustiveEnum() and sema.mod.comp.bin_file.options.use_llvm) { |
| 6938 | const ok = try block.addUnOp(.is_named_enum_value, result); | ||
| 6939 | try sema.addSafetyCheck(block, ok, .invalid_enum_value); | ||
| 6940 | } | ||
| 6941 | return result; | ||
| 6938 | } | 6942 | } |
| 6939 | 6943 | ||
| 6940 | /// Pointer in, pointer out. | 6944 | /// Pointer in, pointer out. |
| ... | @@ -15887,6 +15891,11 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -15887,6 +15891,11 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 15887 | const field_name = enum_ty.enumFieldName(field_index); | 15891 | const field_name = enum_ty.enumFieldName(field_index); |
| 15888 | return sema.addStrLit(block, field_name); | 15892 | return sema.addStrLit(block, field_name); |
| 15889 | } | 15893 | } |
| 15894 | try sema.requireRuntimeBlock(block, src, operand_src); | ||
| 15895 | if (block.wantSafety() and sema.mod.comp.bin_file.options.use_llvm) { | ||
| 15896 | const ok = try block.addUnOp(.is_named_enum_value, casted_operand); | ||
| 15897 | try sema.addSafetyCheck(block, ok, .invalid_enum_value); | ||
| 15898 | } | ||
| 15890 | // In case the value is runtime-known, we have an AIR instruction for this instead | 15899 | // In case the value is runtime-known, we have an AIR instruction for this instead |
| 15891 | // of trying to lower it in Sema because an optimization pass may result in the operand | 15900 | // of trying to lower it in Sema because an optimization pass may result in the operand |
| 15892 | // being comptime-known, which would let us elide the `tag_name` AIR instruction. | 15901 | // being comptime-known, which would let us elide the `tag_name` AIR instruction. |
| ... | @@ -20019,6 +20028,7 @@ pub const PanicId = enum { | ... | @@ -20019,6 +20028,7 @@ pub const PanicId = enum { |
| 20019 | integer_part_out_of_bounds, | 20028 | integer_part_out_of_bounds, |
| 20020 | corrupt_switch, | 20029 | corrupt_switch, |
| 20021 | shift_rhs_too_big, | 20030 | shift_rhs_too_big, |
| 20031 | invalid_enum_value, | ||
| 20022 | }; | 20032 | }; |
| 20023 | 20033 | ||
| 20024 | fn addSafetyCheck( | 20034 | fn addSafetyCheck( |
| ... | @@ -20316,6 +20326,7 @@ fn safetyPanic( | ... | @@ -20316,6 +20326,7 @@ fn safetyPanic( |
| 20316 | .integer_part_out_of_bounds => "integer part of floating point value out of bounds", | 20326 | .integer_part_out_of_bounds => "integer part of floating point value out of bounds", |
| 20317 | .corrupt_switch => "switch on corrupt value", | 20327 | .corrupt_switch => "switch on corrupt value", |
| 20318 | .shift_rhs_too_big => "shift amount is greater than the type size", | 20328 | .shift_rhs_too_big => "shift amount is greater than the type size", |
| 20329 | .invalid_enum_value => "invalid enum value", | ||
| 20319 | }; | 20330 | }; |
| 20320 | 20331 | ||
| 20321 | const msg_inst = msg_inst: { | 20332 | const msg_inst = msg_inst: { |
src/arch/aarch64/CodeGen.zig+2| ... | @@ -753,6 +753,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -753,6 +753,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 753 | .float_to_int_optimized, | 753 | .float_to_int_optimized, |
| 754 | => return self.fail("TODO implement optimized float mode", .{}), | 754 | => return self.fail("TODO implement optimized float mode", .{}), |
| 755 | 755 | ||
| 756 | .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}), | ||
| 757 | |||
| 756 | .wasm_memory_size => unreachable, | 758 | .wasm_memory_size => unreachable, |
| 757 | .wasm_memory_grow => unreachable, | 759 | .wasm_memory_grow => unreachable, |
| 758 | // zig fmt: on | 760 | // zig fmt: on |
src/arch/arm/CodeGen.zig+2| ... | @@ -768,6 +768,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -768,6 +768,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 768 | .float_to_int_optimized, | 768 | .float_to_int_optimized, |
| 769 | => return self.fail("TODO implement optimized float mode", .{}), | 769 | => return self.fail("TODO implement optimized float mode", .{}), |
| 770 | 770 | ||
| 771 | .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}), | ||
| 772 | |||
| 771 | .wasm_memory_size => unreachable, | 773 | .wasm_memory_size => unreachable, |
| 772 | .wasm_memory_grow => unreachable, | 774 | .wasm_memory_grow => unreachable, |
| 773 | // zig fmt: on | 775 | // zig fmt: on |
src/arch/riscv64/CodeGen.zig+2| ... | @@ -693,6 +693,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -693,6 +693,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 693 | .float_to_int_optimized, | 693 | .float_to_int_optimized, |
| 694 | => return self.fail("TODO implement optimized float mode", .{}), | 694 | => return self.fail("TODO implement optimized float mode", .{}), |
| 695 | 695 | ||
| 696 | .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}), | ||
| 697 | |||
| 696 | .wasm_memory_size => unreachable, | 698 | .wasm_memory_size => unreachable, |
| 697 | .wasm_memory_grow => unreachable, | 699 | .wasm_memory_grow => unreachable, |
| 698 | // zig fmt: on | 700 | // zig fmt: on |
src/arch/sparc64/CodeGen.zig+2| ... | @@ -705,6 +705,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -705,6 +705,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 705 | .float_to_int_optimized, | 705 | .float_to_int_optimized, |
| 706 | => @panic("TODO implement optimized float mode"), | 706 | => @panic("TODO implement optimized float mode"), |
| 707 | 707 | ||
| 708 | .is_named_enum_value => @panic("TODO implement is_named_enum_value"), | ||
| 709 | |||
| 708 | .wasm_memory_size => unreachable, | 710 | .wasm_memory_size => unreachable, |
| 709 | .wasm_memory_grow => unreachable, | 711 | .wasm_memory_grow => unreachable, |
| 710 | // zig fmt: on | 712 | // zig fmt: on |
src/arch/wasm/CodeGen.zig+1| ... | @@ -1621,6 +1621,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { | ... | @@ -1621,6 +1621,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { |
| 1621 | .tag_name, | 1621 | .tag_name, |
| 1622 | .err_return_trace, | 1622 | .err_return_trace, |
| 1623 | .set_err_return_trace, | 1623 | .set_err_return_trace, |
| 1624 | .is_named_enum_value, | ||
| 1624 | => |tag| return self.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}), | 1625 | => |tag| return self.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}), |
| 1625 | 1626 | ||
| 1626 | .add_optimized, | 1627 | .add_optimized, |
src/arch/x86_64/CodeGen.zig+2| ... | @@ -775,6 +775,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -775,6 +775,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 775 | .float_to_int_optimized, | 775 | .float_to_int_optimized, |
| 776 | => return self.fail("TODO implement optimized float mode", .{}), | 776 | => return self.fail("TODO implement optimized float mode", .{}), |
| 777 | 777 | ||
| 778 | .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}), | ||
| 779 | |||
| 778 | .wasm_memory_size => unreachable, | 780 | .wasm_memory_size => unreachable, |
| 779 | .wasm_memory_grow => unreachable, | 781 | .wasm_memory_grow => unreachable, |
| 780 | // zig fmt: on | 782 | // zig fmt: on |
src/codegen/c.zig+2| ... | @@ -1952,6 +1952,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO | ... | @@ -1952,6 +1952,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO |
| 1952 | .reduce_optimized, | 1952 | .reduce_optimized, |
| 1953 | .float_to_int_optimized, | 1953 | .float_to_int_optimized, |
| 1954 | => return f.fail("TODO implement optimized float mode", .{}), | 1954 | => return f.fail("TODO implement optimized float mode", .{}), |
| 1955 | |||
| 1956 | .is_named_enum_value => return f.fail("TODO: C backend: implement is_named_enum_value", .{}), | ||
| 1955 | // zig fmt: on | 1957 | // zig fmt: on |
| 1956 | }; | 1958 | }; |
| 1957 | switch (result_value) { | 1959 | switch (result_value) { |
src/codegen/llvm.zig+87| ... | @@ -201,6 +201,8 @@ pub const Object = struct { | ... | @@ -201,6 +201,8 @@ pub const Object = struct { |
| 201 | /// * it works for functions not all globals. | 201 | /// * it works for functions not all globals. |
| 202 | /// Therefore, this table keeps track of the mapping. | 202 | /// Therefore, this table keeps track of the mapping. |
| 203 | decl_map: std.AutoHashMapUnmanaged(Module.Decl.Index, *const llvm.Value), | 203 | decl_map: std.AutoHashMapUnmanaged(Module.Decl.Index, *const llvm.Value), |
| 204 | /// Serves the same purpose as `decl_map` but only used for the `is_named_enum_value` instruction. | ||
| 205 | named_enum_map: std.AutoHashMapUnmanaged(Module.Decl.Index, *const llvm.Value), | ||
| 204 | /// Maps Zig types to LLVM types. The table memory itself is backed by the GPA of | 206 | /// Maps Zig types to LLVM types. The table memory itself is backed by the GPA of |
| 205 | /// the compiler, but the Type/Value memory here is backed by `type_map_arena`. | 207 | /// the compiler, but the Type/Value memory here is backed by `type_map_arena`. |
| 206 | /// TODO we need to remove entries from this map in response to incremental compilation | 208 | /// TODO we need to remove entries from this map in response to incremental compilation |
| ... | @@ -377,6 +379,7 @@ pub const Object = struct { | ... | @@ -377,6 +379,7 @@ pub const Object = struct { |
| 377 | .target_data = target_data, | 379 | .target_data = target_data, |
| 378 | .target = options.target, | 380 | .target = options.target, |
| 379 | .decl_map = .{}, | 381 | .decl_map = .{}, |
| 382 | .named_enum_map = .{}, | ||
| 380 | .type_map = .{}, | 383 | .type_map = .{}, |
| 381 | .type_map_arena = std.heap.ArenaAllocator.init(gpa), | 384 | .type_map_arena = std.heap.ArenaAllocator.init(gpa), |
| 382 | .di_type_map = .{}, | 385 | .di_type_map = .{}, |
| ... | @@ -396,6 +399,7 @@ pub const Object = struct { | ... | @@ -396,6 +399,7 @@ pub const Object = struct { |
| 396 | self.llvm_module.dispose(); | 399 | self.llvm_module.dispose(); |
| 397 | self.context.dispose(); | 400 | self.context.dispose(); |
| 398 | self.decl_map.deinit(gpa); | 401 | self.decl_map.deinit(gpa); |
| 402 | self.named_enum_map.deinit(gpa); | ||
| 399 | self.type_map.deinit(gpa); | 403 | self.type_map.deinit(gpa); |
| 400 | self.type_map_arena.deinit(); | 404 | self.type_map_arena.deinit(); |
| 401 | self.extern_collisions.deinit(gpa); | 405 | self.extern_collisions.deinit(gpa); |
| ... | @@ -4180,6 +4184,8 @@ pub const FuncGen = struct { | ... | @@ -4180,6 +4184,8 @@ pub const FuncGen = struct { |
| 4180 | .union_init => try self.airUnionInit(inst), | 4184 | .union_init => try self.airUnionInit(inst), |
| 4181 | .prefetch => try self.airPrefetch(inst), | 4185 | .prefetch => try self.airPrefetch(inst), |
| 4182 | 4186 | ||
| 4187 | .is_named_enum_value => try self.airIsNamedEnumValue(inst), | ||
| 4188 | |||
| 4183 | .reduce => try self.airReduce(inst, false), | 4189 | .reduce => try self.airReduce(inst, false), |
| 4184 | .reduce_optimized => try self.airReduce(inst, true), | 4190 | .reduce_optimized => try self.airReduce(inst, true), |
| 4185 | 4191 | ||
| ... | @@ -7882,6 +7888,87 @@ pub const FuncGen = struct { | ... | @@ -7882,6 +7888,87 @@ pub const FuncGen = struct { |
| 7882 | } | 7888 | } |
| 7883 | } | 7889 | } |
| 7884 | 7890 | ||
| 7891 | fn airIsNamedEnumValue(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { | ||
| 7892 | if (self.liveness.isUnused(inst)) return null; | ||
| 7893 | |||
| 7894 | const un_op = self.air.instructions.items(.data)[inst].un_op; | ||
| 7895 | const operand = try self.resolveInst(un_op); | ||
| 7896 | const enum_ty = self.air.typeOf(un_op); | ||
| 7897 | |||
| 7898 | const llvm_fn = try self.getIsNamedEnumValueFunction(enum_ty); | ||
| 7899 | const params = [_]*const llvm.Value{operand}; | ||
| 7900 | return self.builder.buildCall(llvm_fn, &params, params.len, .Fast, .Auto, ""); | ||
| 7901 | } | ||
| 7902 | |||
| 7903 | fn getIsNamedEnumValueFunction(self: *FuncGen, enum_ty: Type) !*const llvm.Value { | ||
| 7904 | const enum_decl = enum_ty.getOwnerDecl(); | ||
| 7905 | |||
| 7906 | // TODO: detect when the type changes and re-emit this function. | ||
| 7907 | const gop = try self.dg.object.named_enum_map.getOrPut(self.dg.gpa, enum_decl); | ||
| 7908 | if (gop.found_existing) return gop.value_ptr.*; | ||
| 7909 | errdefer assert(self.dg.object.named_enum_map.remove(enum_decl)); | ||
| 7910 | |||
| 7911 | var arena_allocator = std.heap.ArenaAllocator.init(self.gpa); | ||
| 7912 | defer arena_allocator.deinit(); | ||
| 7913 | const arena = arena_allocator.allocator(); | ||
| 7914 | |||
| 7915 | const mod = self.dg.module; | ||
| 7916 | const llvm_fn_name = try std.fmt.allocPrintZ(arena, "__zig_is_named_enum_value_{s}", .{ | ||
| 7917 | try mod.declPtr(enum_decl).getFullyQualifiedName(mod), | ||
| 7918 | }); | ||
| 7919 | |||
| 7920 | var int_tag_type_buffer: Type.Payload.Bits = undefined; | ||
| 7921 | const int_tag_ty = enum_ty.intTagType(&int_tag_type_buffer); | ||
| 7922 | const param_types = [_]*const llvm.Type{try self.dg.lowerType(int_tag_ty)}; | ||
| 7923 | |||
| 7924 | const llvm_ret_ty = try self.dg.lowerType(Type.bool); | ||
| 7925 | const fn_type = llvm.functionType(llvm_ret_ty, &param_types, param_types.len, .False); | ||
| 7926 | const fn_val = self.dg.object.llvm_module.addFunction(llvm_fn_name, fn_type); | ||
| 7927 | fn_val.setLinkage(.Internal); | ||
| 7928 | fn_val.setFunctionCallConv(.Fast); | ||
| 7929 | self.dg.addCommonFnAttributes(fn_val); | ||
| 7930 | gop.value_ptr.* = fn_val; | ||
| 7931 | |||
| 7932 | const prev_block = self.builder.getInsertBlock(); | ||
| 7933 | const prev_debug_location = self.builder.getCurrentDebugLocation2(); | ||
| 7934 | defer { | ||
| 7935 | self.builder.positionBuilderAtEnd(prev_block); | ||
| 7936 | if (self.di_scope != null) { | ||
| 7937 | self.builder.setCurrentDebugLocation2(prev_debug_location); | ||
| 7938 | } | ||
| 7939 | } | ||
| 7940 | |||
| 7941 | const entry_block = self.dg.context.appendBasicBlock(fn_val, "Entry"); | ||
| 7942 | self.builder.positionBuilderAtEnd(entry_block); | ||
| 7943 | self.builder.clearCurrentDebugLocation(); | ||
| 7944 | |||
| 7945 | const fields = enum_ty.enumFields(); | ||
| 7946 | const named_block = self.dg.context.appendBasicBlock(fn_val, "Named"); | ||
| 7947 | const unnamed_block = self.dg.context.appendBasicBlock(fn_val, "Unnamed"); | ||
| 7948 | const tag_int_value = fn_val.getParam(0); | ||
| 7949 | const switch_instr = self.builder.buildSwitch(tag_int_value, unnamed_block, @intCast(c_uint, fields.count())); | ||
| 7950 | |||
| 7951 | for (fields.keys()) |_, field_index| { | ||
| 7952 | const this_tag_int_value = int: { | ||
| 7953 | var tag_val_payload: Value.Payload.U32 = .{ | ||
| 7954 | .base = .{ .tag = .enum_field_index }, | ||
| 7955 | .data = @intCast(u32, field_index), | ||
| 7956 | }; | ||
| 7957 | break :int try self.dg.lowerValue(.{ | ||
| 7958 | .ty = enum_ty, | ||
| 7959 | .val = Value.initPayload(&tag_val_payload.base), | ||
| 7960 | }); | ||
| 7961 | }; | ||
| 7962 | switch_instr.addCase(this_tag_int_value, named_block); | ||
| 7963 | } | ||
| 7964 | self.builder.positionBuilderAtEnd(named_block); | ||
| 7965 | _ = self.builder.buildRet(self.dg.context.intType(1).constInt(1, .False)); | ||
| 7966 | |||
| 7967 | self.builder.positionBuilderAtEnd(unnamed_block); | ||
| 7968 | _ = self.builder.buildRet(self.dg.context.intType(1).constInt(0, .False)); | ||
| 7969 | return fn_val; | ||
| 7970 | } | ||
| 7971 | |||
| 7885 | fn airTagName(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { | 7972 | fn airTagName(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| 7886 | if (self.liveness.isUnused(inst)) return null; | 7973 | if (self.liveness.isUnused(inst)) return null; |
| 7887 | 7974 |
src/print_air.zig+1| ... | @@ -170,6 +170,7 @@ const Writer = struct { | ... | @@ -170,6 +170,7 @@ const Writer = struct { |
| 170 | .bool_to_int, | 170 | .bool_to_int, |
| 171 | .ret, | 171 | .ret, |
| 172 | .ret_load, | 172 | .ret_load, |
| 173 | .is_named_enum_value, | ||
| 173 | .tag_name, | 174 | .tag_name, |
| 174 | .error_name, | 175 | .error_name, |
| 175 | .sqrt, | 176 | .sqrt, |
test/cases/safety/@intToEnum - no matching tag value.zig	+6-3| ... | @@ -1,9 +1,11 @@ | ... | @@ -1,9 +1,11 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | 2 | ||
| 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | ||
| 5 | _ = stack_trace; | 4 | _ = stack_trace; |
| 6 | std.process.exit(0); | 5 | if (std.mem.eql(u8, message, "invalid enum value")) { |
| 6 | std.process.exit(0); | ||
| 7 | } | ||
| 8 | std.process.exit(1); | ||
| 7 | } | 9 | } |
| 8 | const Foo = enum { | 10 | const Foo = enum { |
| 9 | A, | 11 | A, |
| ... | @@ -18,6 +20,7 @@ fn bar(a: u2) Foo { | ... | @@ -18,6 +20,7 @@ fn bar(a: u2) Foo { |
| 18 | return @intToEnum(Foo, a); | 20 | return @intToEnum(Foo, a); |
| 19 | } | 21 | } |
| 20 | fn baz(_: Foo) void {} | 22 | fn baz(_: Foo) void {} |
| 23 | |||
| 21 | // run | 24 | // run |
| 22 | // backend=stage1 | 25 | // backend=llvm |
| 23 | // target=native | 26 | // target=native |
test/cases/safety/@tagName on corrupted enum value.zig	+2-1| ... | @@ -10,6 +10,7 @@ pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noretur | ... | @@ -10,6 +10,7 @@ pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noretur |
| 10 | 10 | ||
| 11 | const E = enum(u32) { | 11 | const E = enum(u32) { |
| 12 | X = 1, | 12 | X = 1, |
| 13 | Y = 2, | ||
| 13 | }; | 14 | }; |
| 14 | 15 | ||
| 15 | pub fn main() !void { | 16 | pub fn main() !void { |
| ... | @@ -21,5 +22,5 @@ pub fn main() !void { | ... | @@ -21,5 +22,5 @@ pub fn main() !void { |
| 21 | } | 22 | } |
| 22 | 23 | ||
| 23 | // run | 24 | // run |
| 24 | // backend=stage1 | 25 | // backend=llvm |
| 25 | // target=native | 26 | // target=native |
test/cases/safety/@tagName on corrupted union value.zig	+2-1| ... | @@ -10,6 +10,7 @@ pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noretur | ... | @@ -10,6 +10,7 @@ pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noretur |
| 10 | 10 | ||
| 11 | const U = union(enum(u32)) { | 11 | const U = union(enum(u32)) { |
| 12 | X: u8, | 12 | X: u8, |
| 13 | Y: i8, | ||
| 13 | }; | 14 | }; |
| 14 | 15 | ||
| 15 | pub fn main() !void { | 16 | pub fn main() !void { |
| ... | @@ -22,5 +23,5 @@ pub fn main() !void { | ... | @@ -22,5 +23,5 @@ pub fn main() !void { |
| 22 | } | 23 | } |
| 23 | 24 | ||
| 24 | // run | 25 | // run |
| 25 | // backend=stage1 | 26 | // backend=llvm |
| 26 | // target=native | 27 | // target=native |