Commit 9851a943ed

Andrew Kelley <superjoe30@gmail.com>
2017-05-16 23:04:35
add compile error for compile-time integer cast truncating bits
closes #371
1 parent f375063
Changed files (3)
src/ir.cpp
@@ -7053,12 +7053,20 @@ static IrInstruction *ir_analyze_widen_or_shorten(IrAnalyze *ira, IrInstruction
         ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
         if (!val)
             return ira->codegen->invalid_instruction;
-        if (val->data.x_bignum.is_negative && wanted_type->id == TypeTableEntryIdInt &&
-            !wanted_type->data.integral.is_signed)
-        {
-            ir_add_error(ira, source_instr,
-                buf_sprintf("attempt to cast negative value to unsigned integer"));
-            return ira->codegen->invalid_instruction;
+        if (wanted_type->id == TypeTableEntryIdInt) {
+            if (val->data.x_bignum.is_negative && !wanted_type->data.integral.is_signed) {
+                ir_add_error(ira, source_instr,
+                    buf_sprintf("attempt to cast negative value to unsigned integer"));
+                return ira->codegen->invalid_instruction;
+            }
+            if (!bignum_fits_in_bits(&val->data.x_bignum, wanted_type->data.integral.bit_count,
+                    wanted_type->data.integral.is_signed))
+            {
+                ir_add_error(ira, source_instr,
+                    buf_sprintf("cast from '%s' to '%s' truncates bits",
+                        buf_ptr(&target->value.type->name), buf_ptr(&wanted_type->name)));
+                return ira->codegen->invalid_instruction;
+            }
         }
         IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
                 source_instr->source_node, wanted_type);
test/cases/eval.zig
@@ -314,3 +314,11 @@ const global_array = {
     }
     result
 };
+
+test "compile-time downcast when the bits fit" {
+    comptime {
+        const spartan_count: u16 = 255;
+        const byte = u8(spartan_count);
+        assert(byte == 255);
+    }
+}
test/compile_errors.zig
@@ -1827,4 +1827,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
         \\}
     ,
         ".tmp_source.zig:4:17: error: division by zero is undefined");
+
+    cases.add("compile-time integer cast truncates bits",
+        \\comptime {
+        \\    const spartan_count: u16 = 300;
+        \\    const byte = u8(spartan_count);
+        \\}
+    ,
+        ".tmp_source.zig:3:20: error: cast from 'u16' to 'u8' truncates bits");
 }