diff --git a/src/codegen.cpp b/src/codegen.cpp index 090812bbb9844a47bb9369eb090ee4024605983e..b1915ae45a5174bbcd5d4aabca629a737756eabc 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 104fa8f58cd5b2ea11050259d2eb44ec9ced31bf..5f456364a53b5ea1d80bcf23ad5ba91314de0533 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 3d58dfe7487199c2946e28d369a753e926824a4b..ece6c2283aad29ded1f2091bf3ebddecb7ab6815 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);