authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-05-16 17:04:35-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-05-16 17:04:35-04:00
log9851a943ed0360433c9612449ed065a6800adc51
treedcf15bcb1dd31da8ba975dd2594d7a89f5ca46ae
parentf37506391795353bbb87f49b73cf0f82ad9e2c17

add compile error for compile-time integer cast truncating bits

closes #371

3 files changed, 30 insertions(+), 6 deletions(-)

src/ir.cpp+14-6
...@@ -7053,12 +7053,20 @@ static IrInstruction *ir_analyze_widen_or_shorten(IrAnalyze *ira, IrInstruction...@@ -7053,12 +7053,20 @@ static IrInstruction *ir_analyze_widen_or_shorten(IrAnalyze *ira, IrInstruction
7053 ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);7053 ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
7054 if (!val)7054 if (!val)
7055 return ira->codegen->invalid_instruction;7055 return ira->codegen->invalid_instruction;
7056 if (val->data.x_bignum.is_negative && wanted_type->id == TypeTableEntryIdInt &&7056 if (wanted_type->id == TypeTableEntryIdInt) {
7057 !wanted_type->data.integral.is_signed)7057 if (val->data.x_bignum.is_negative && !wanted_type->data.integral.is_signed) {
7058 {7058 ir_add_error(ira, source_instr,
7059 ir_add_error(ira, source_instr,7059 buf_sprintf("attempt to cast negative value to unsigned integer"));
7060 buf_sprintf("attempt to cast negative value to unsigned integer"));7060 return ira->codegen->invalid_instruction;
7061 return ira->codegen->invalid_instruction;7061 }
7062 if (!bignum_fits_in_bits(&val->data.x_bignum, wanted_type->data.integral.bit_count,
7063 wanted_type->data.integral.is_signed))
7064 {
7065 ir_add_error(ira, source_instr,
7066 buf_sprintf("cast from '%s' to '%s' truncates bits",
7067 buf_ptr(&target->value.type->name), buf_ptr(&wanted_type->name)));
7068 return ira->codegen->invalid_instruction;
7069 }
7062 }7070 }
7063 IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,7071 IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
7064 source_instr->source_node, wanted_type);7072 source_instr->source_node, wanted_type);
test/cases/eval.zig+8
...@@ -314,3 +314,11 @@ const global_array = {...@@ -314,3 +314,11 @@ const global_array = {
314 }314 }
315 result315 result
316};316};
317
318test "compile-time downcast when the bits fit" {
319 comptime {
320 const spartan_count: u16 = 255;
321 const byte = u8(spartan_count);
322 assert(byte == 255);
323 }
324}
test/compile_errors.zig+8
...@@ -1827,4 +1827,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) {...@@ -1827,4 +1827,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
1827 \\}1827 \\}
1828 ,1828 ,
1829 ".tmp_source.zig:4:17: error: division by zero is undefined");1829 ".tmp_source.zig:4:17: error: division by zero is undefined");
1830
1831 cases.add("compile-time integer cast truncates bits",
1832 \\comptime {
1833 \\ const spartan_count: u16 = 300;
1834 \\ const byte = u8(spartan_count);
1835 \\}
1836 ,
1837 ".tmp_source.zig:3:20: error: cast from 'u16' to 'u8' truncates bits");
1830}1838}