Commit bfcfaaf5bd
Changed files (3)
src
test
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;
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);
}
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);