aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Kelley <superjoe30@gmail.com>2017-08-07 15:57:41 -0400
committerAndrew Kelley <superjoe30@gmail.com>2017-08-07 15:57:41 -0400
commit2234788fa80dfaf1e58df51ff576701f8161b0df (patch)
treec544704e7d4981e2cae1c54abb4e6b17bc872268 /src
parent38b47d8aca57efbb10b8000cb726eb24b1f37ccb (diff)
downloadzig-2234788fa80dfaf1e58df51ff576701f8161b0df.tar.gz
zig-2234788fa80dfaf1e58df51ff576701f8161b0df.zip
add ability to explicitly cast float to integer
closes #414
Diffstat (limited to 'src')
-rw-r--r--src/bigfloat.cpp4
-rw-r--r--src/bigfloat.hpp1
-rw-r--r--src/ir.cpp46
3 files changed, 42 insertions, 9 deletions
diff --git a/src/bigfloat.cpp b/src/bigfloat.cpp
index 3986efc19d..22ff9c29a3 100644
--- a/src/bigfloat.cpp
+++ b/src/bigfloat.cpp
@@ -150,3 +150,7 @@ Cmp bigfloat_cmp_zero(const BigFloat *bigfloat) {
return CmpEQ;
}
}
+
+bool bigfloat_has_fraction(const BigFloat *bigfloat) {
+ return floorl(bigfloat->value) != bigfloat->value;
+}
diff --git a/src/bigfloat.hpp b/src/bigfloat.hpp
index 2f32f37110..30aa754ce6 100644
--- a/src/bigfloat.hpp
+++ b/src/bigfloat.hpp
@@ -43,5 +43,6 @@ void bigfloat_read_ieee597(BigFloat *dest, const uint8_t *buf, size_t bit_count,
// convenience functions
Cmp bigfloat_cmp_zero(const BigFloat *bigfloat);
+bool bigfloat_has_fraction(const BigFloat *bigfloat);
#endif
diff --git a/src/ir.cpp b/src/ir.cpp
index 686c247117..5c21f06f40 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -6206,7 +6206,9 @@ static bool const_val_fits_in_num_lit(ConstExprValue *const_val, TypeTableEntry
(const_val->type->id == TypeTableEntryIdInt || const_val->type->id == TypeTableEntryIdNumLitInt)));
}
-static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruction, TypeTableEntry *other_type) {
+static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruction, TypeTableEntry *other_type,
+ bool explicit_cast)
+{
if (type_is_invalid(other_type)) {
return false;
}
@@ -6243,6 +6245,32 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc
return true;
}
}
+ if (explicit_cast && (other_type->id == TypeTableEntryIdInt || other_type->id == TypeTableEntryIdNumLitInt) &&
+ const_val_is_float)
+ {
+ if (bigfloat_has_fraction(&const_val->data.x_bigfloat)) {
+ Buf *val_buf = buf_alloc();
+ bigfloat_write_buf(val_buf, &const_val->data.x_bigfloat);
+
+ ir_add_error(ira, instruction,
+ buf_sprintf("fractional component prevents float value %s from being casted to type '%s'",
+ buf_ptr(val_buf),
+ buf_ptr(&other_type->name)));
+ return false;
+ } else {
+ BigInt bigint;
+ bigint_init_bigfloat(&bigint, &const_val->data.x_bigfloat);
+ if (other_type->id == TypeTableEntryIdNumLitInt) {
+ return true;
+ } else {
+ if (bigint_fits_in_bits(&bigint, other_type->data.integral.bit_count,
+ other_type->data.integral.is_signed))
+ {
+ return true;
+ }
+ }
+ }
+ }
const char *num_lit_str;
Buf *val_buf = buf_alloc();
@@ -6425,12 +6453,12 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
if (expected_type->id == TypeTableEntryIdPointer &&
expected_type->data.pointer.is_const)
{
- if (ir_num_lit_fits_in_other_type(ira, value, expected_type->data.pointer.child_type)) {
+ if (ir_num_lit_fits_in_other_type(ira, value, expected_type->data.pointer.child_type, false)) {
return ImplicitCastMatchResultYes;
} else {
return ImplicitCastMatchResultReportedError;
}
- } else if (ir_num_lit_fits_in_other_type(ira, value, expected_type)) {
+ } else if (ir_num_lit_fits_in_other_type(ira, value, expected_type, false)) {
return ImplicitCastMatchResultYes;
} else {
return ImplicitCastMatchResultReportedError;
@@ -6542,7 +6570,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
} else if (prev_type->id == TypeTableEntryIdNumLitInt ||
prev_type->id == TypeTableEntryIdNumLitFloat)
{
- if (ir_num_lit_fits_in_other_type(ira, prev_inst, cur_type)) {
+ if (ir_num_lit_fits_in_other_type(ira, prev_inst, cur_type, false)) {
prev_inst = cur_inst;
continue;
} else {
@@ -6551,7 +6579,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
} else if (cur_type->id == TypeTableEntryIdNumLitInt ||
cur_type->id == TypeTableEntryIdNumLitFloat)
{
- if (ir_num_lit_fits_in_other_type(ira, cur_inst, prev_type)) {
+ if (ir_num_lit_fits_in_other_type(ira, cur_inst, prev_type, false)) {
continue;
} else {
return ira->codegen->builtin_types.entry_invalid;
@@ -7636,7 +7664,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
} else if (actual_type->id == TypeTableEntryIdNumLitInt ||
actual_type->id == TypeTableEntryIdNumLitFloat)
{
- if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.maybe.child_type)) {
+ if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.maybe.child_type, true)) {
return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type);
} else {
return ira->codegen->invalid_instruction;
@@ -7658,7 +7686,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
} else if (actual_type->id == TypeTableEntryIdNumLitInt ||
actual_type->id == TypeTableEntryIdNumLitFloat)
{
- if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.error.child_type)) {
+ if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.error.child_type, true)) {
return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type);
} else {
return ira->codegen->invalid_instruction;
@@ -7736,7 +7764,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
return ira->codegen->invalid_instruction;
return cast2;
- } else if (ir_num_lit_fits_in_other_type(ira, value, wanted_type)) {
+ } else if (ir_num_lit_fits_in_other_type(ira, value, wanted_type, true)) {
CastOp op;
if ((actual_type->id == TypeTableEntryIdNumLitFloat &&
wanted_type->id == TypeTableEntryIdFloat) ||
@@ -8630,7 +8658,7 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
return ira->codegen->builtin_types.entry_invalid;
}
- ir_num_lit_fits_in_other_type(ira, &bin_op_instruction->base, resolved_type);
+ ir_num_lit_fits_in_other_type(ira, &bin_op_instruction->base, resolved_type, false);
return resolved_type;
}