diff --git a/src/codegen.cpp b/src/codegen.cpp index 090812bbb9..b1915ae45a 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1689,6 +1689,22 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, Z if (actual_type->id == ZigTypeIdFloat) { return LLVMBuildFPTrunc(g->builder, expr_val, wanted_type->type_ref, ""); } else if (actual_type->id == ZigTypeIdInt) { + if (wanted_bits == 0) { + if (!want_runtime_safety) + return nullptr; + + LLVMValueRef zero = LLVMConstNull(actual_type->type_ref); + LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, expr_val, zero, ""); + LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenOk"); + LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenFail"); + LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); + + LLVMPositionBuilderAtEnd(g->builder, fail_block); + gen_safety_crash(g, PanicMsgIdCastTruncatedData); + + LLVMPositionBuilderAtEnd(g->builder, ok_block); + return nullptr; + } LLVMValueRef trunc_val = LLVMBuildTrunc(g->builder, expr_val, wanted_type->type_ref, ""); if (!want_runtime_safety) { return trunc_val; diff --git a/test/cases/eval.zig b/test/cases/eval.zig index 104fa8f58c..5f456364a5 100644 --- a/test/cases/eval.zig +++ b/test/cases/eval.zig @@ -692,4 +692,11 @@ test "zero extend from u0 to u1" { test "bit shift a u1" { var x: u1 = 1; var y = x << 0; + assert(y == 1); +} + +test "@intCast to a u0" { + var x: u8 = 0; + var y: u0 = @intCast(u0, x); + assert(y == 0); } diff --git a/test/runtime_safety.zig b/test/runtime_safety.zig index 3d58dfe748..ece6c2283a 100644 --- a/test/runtime_safety.zig +++ b/test/runtime_safety.zig @@ -249,6 +249,19 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { \\} ); + cases.addRuntimeSafety("value does not fit in shortening cast - u0", + \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { + \\ @import("std").os.exit(126); + \\} + \\pub fn main() !void { + \\ const x = shorten_cast(1); + \\ if (x == 0) return error.Whatever; + \\} + \\fn shorten_cast(x: u8) u0 { + \\ return @intCast(u0, x); + \\} + ); + cases.addRuntimeSafety("signed integer not fitting in cast to unsigned integer", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126);