Commit 503b85a1b0

Matthew Borkowski <matthew.h.borkowski@gmail.com>
2021-05-29 05:32:19
stage1: make `@truncate` to an integer type of different sign an error at comptime too
1 parent 0c25ff8
Changed files (3)
src
stage1
test
src/stage1/ir.cpp
@@ -19563,6 +19563,18 @@ static IrInstGen *ir_analyze_instruction_truncate(IrAnalyze *ira, IrInstSrcTrunc
         return ir_implicit_cast2(ira, &instruction->target->base, target, dest_type);
     }
 
+    if (src_type->id != ZigTypeIdComptimeInt) {
+        if (src_type->data.integral.is_signed != dest_type->data.integral.is_signed) {
+            const char *sign_str = dest_type->data.integral.is_signed ? "signed" : "unsigned";
+            ir_add_error(ira, &target->base, buf_sprintf("expected %s integer type, found '%s'", sign_str, buf_ptr(&src_type->name)));
+            return ira->codegen->invalid_inst_gen;
+        } else if (src_type->data.integral.bit_count > 0 && src_type->data.integral.bit_count < dest_type->data.integral.bit_count) {
+            ir_add_error(ira, &target->base, buf_sprintf("type '%s' has fewer bits than destination type '%s'",
+                        buf_ptr(&src_type->name), buf_ptr(&dest_type->name)));
+            return ira->codegen->invalid_inst_gen;
+        }
+    }
+
     if (instr_is_comptime(target)) {
         ZigValue *val = ir_resolve_const(ira, target, UndefBad);
         if (val == nullptr)
@@ -19580,16 +19592,6 @@ static IrInstGen *ir_analyze_instruction_truncate(IrAnalyze *ira, IrInstSrcTrunc
         return result;
     }
 
-    if (src_type->data.integral.is_signed != dest_type->data.integral.is_signed) {
-        const char *sign_str = dest_type->data.integral.is_signed ? "signed" : "unsigned";
-        ir_add_error(ira, &target->base, buf_sprintf("expected %s integer type, found '%s'", sign_str, buf_ptr(&src_type->name)));
-        return ira->codegen->invalid_inst_gen;
-    } else if (src_type->data.integral.bit_count < dest_type->data.integral.bit_count) {
-        ir_add_error(ira, &target->base, buf_sprintf("type '%s' has fewer bits than destination type '%s'",
-                    buf_ptr(&src_type->name), buf_ptr(&dest_type->name)));
-        return ira->codegen->invalid_inst_gen;
-    }
-
     return ir_build_truncate_gen(ira, &instruction->base.base, dest_type, target);
 }
 
test/behavior/truncate.zig
@@ -24,13 +24,34 @@ test "truncate.u0.var" {
     try expect(z == 0);
 }
 
-test "truncate sign mismatch but comptime known so it works anyway" {
-    const x: u32 = 10;
-    var result = @truncate(i8, x);
-    try expect(result == 10);
+test "truncate i0 to larger integer allowed and has comptime known result" {
+    var x: i0 = 0;
+    const y = @truncate(i8, x);
+    comptime try expect(y == 0);
+}
+
+test "truncate.i0.literal" {
+    var z = @truncate(i0, 0);
+    try expect(z == 0);
+}
+
+test "truncate.i0.const" {
+    const c0: isize = 0;
+    var z = @truncate(i0, c0);
+    try expect(z == 0);
+}
+
+test "truncate.i0.var" {
+    var d: i8 = 2;
+    var z = @truncate(i0, d);
+    try expect(z == 0);
 }
 
 test "truncate on comptime integer" {
     var x = @truncate(u16, 9999);
     try expect(x == 9999);
+    var y = @truncate(u16, -21555);
+    try expect(y == 0xabcd);
+    var z = @truncate(i16, -65537);
+    try expect(z == -1);
 }
test/compile_errors.zig
@@ -6031,14 +6031,27 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
     });
 
     cases.add("truncate sign mismatch",
-        \\fn f() i8 {
+        \\export fn entry1() i8 {
         \\    var x: u32 = 10;
         \\    return @truncate(i8, x);
         \\}
-        \\
-        \\export fn entry() usize { return @sizeOf(@TypeOf(f)); }
+        \\export fn entry2() u8 {
+        \\    var x: i32 = -10;
+        \\    return @truncate(u8, x);
+        \\}
+        \\export fn entry3() i8 {
+        \\    comptime var x: u32 = 10;
+        \\    return @truncate(i8, x);
+        \\}
+        \\export fn entry4() u8 {
+        \\    comptime var x: i32 = -10;
+        \\    return @truncate(u8, x);
+        \\}
     , &[_][]const u8{
         "tmp.zig:3:26: error: expected signed integer type, found 'u32'",
+        "tmp.zig:7:26: error: expected unsigned integer type, found 'i32'",
+        "tmp.zig:11:26: error: expected signed integer type, found 'u32'",
+        "tmp.zig:15:26: error: expected unsigned integer type, found 'i32'",
     });
 
     cases.add("try in function with non error return type",