support casting between floats
parent
e74a7264ad
commit
a4e19f94f1
|
@ -340,7 +340,7 @@ enum CastOp {
|
||||||
CastOpNoop, // fn call expr is a cast, but does nothing
|
CastOpNoop, // fn call expr is a cast, but does nothing
|
||||||
CastOpPtrToInt,
|
CastOpPtrToInt,
|
||||||
CastOpIntToPtr,
|
CastOpIntToPtr,
|
||||||
CastOpIntWidenOrShorten,
|
CastOpWidenOrShorten,
|
||||||
CastOpToUnknownSizeArray,
|
CastOpToUnknownSizeArray,
|
||||||
CastOpMaybeWrap,
|
CastOpMaybeWrap,
|
||||||
CastOpErrorWrap,
|
CastOpErrorWrap,
|
||||||
|
|
|
@ -1681,6 +1681,14 @@ static bool types_match_with_implicit_cast(CodeGen *g, TypeTableEntry *expected_
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// implicit float widening conversion
|
||||||
|
if (expected_type->id == TypeTableEntryIdFloat &&
|
||||||
|
actual_type->id == TypeTableEntryIdFloat &&
|
||||||
|
expected_type->size_in_bits >= actual_type->size_in_bits)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// implicit constant sized array to unknown size array conversion
|
// implicit constant sized array to unknown size array conversion
|
||||||
if (expected_type->id == TypeTableEntryIdStruct &&
|
if (expected_type->id == TypeTableEntryIdStruct &&
|
||||||
expected_type->data.structure.is_unknown_size_array &&
|
expected_type->data.structure.is_unknown_size_array &&
|
||||||
|
@ -3366,7 +3374,7 @@ static void eval_const_expr_implicit_cast(CodeGen *g, AstNode *node, AstNode *ex
|
||||||
case CastOpNoCast:
|
case CastOpNoCast:
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
case CastOpNoop:
|
case CastOpNoop:
|
||||||
case CastOpIntWidenOrShorten:
|
case CastOpWidenOrShorten:
|
||||||
case CastOpPointerReinterpret:
|
case CastOpPointerReinterpret:
|
||||||
*const_val = *other_val;
|
*const_val = *other_val;
|
||||||
break;
|
break;
|
||||||
|
@ -3477,11 +3485,13 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B
|
||||||
return wanted_type;
|
return wanted_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
// explicit cast from any int to any other int
|
// explicit widening or shortening cast
|
||||||
if (wanted_type->id == TypeTableEntryIdInt &&
|
if ((wanted_type->id == TypeTableEntryIdInt &&
|
||||||
actual_type->id == TypeTableEntryIdInt)
|
actual_type->id == TypeTableEntryIdInt) ||
|
||||||
|
(wanted_type->id == TypeTableEntryIdFloat &&
|
||||||
|
actual_type->id == TypeTableEntryIdFloat))
|
||||||
{
|
{
|
||||||
node->data.fn_call_expr.cast_op = CastOpIntWidenOrShorten;
|
node->data.fn_call_expr.cast_op = CastOpWidenOrShorten;
|
||||||
eval_const_expr_implicit_cast(g, node, expr_node);
|
eval_const_expr_implicit_cast(g, node, expr_node);
|
||||||
return wanted_type;
|
return wanted_type;
|
||||||
}
|
}
|
||||||
|
|
|
@ -349,9 +349,14 @@ static LLVMValueRef gen_enum_value_expr(CodeGen *g, AstNode *node, TypeTableEntr
|
||||||
static LLVMValueRef gen_widen_or_shorten(CodeGen *g, AstNode *source_node, TypeTableEntry *actual_type,
|
static LLVMValueRef gen_widen_or_shorten(CodeGen *g, AstNode *source_node, TypeTableEntry *actual_type,
|
||||||
TypeTableEntry *wanted_type, LLVMValueRef expr_val)
|
TypeTableEntry *wanted_type, LLVMValueRef expr_val)
|
||||||
{
|
{
|
||||||
|
assert(actual_type->id == wanted_type->id);
|
||||||
if (actual_type->size_in_bits == wanted_type->size_in_bits) {
|
if (actual_type->size_in_bits == wanted_type->size_in_bits) {
|
||||||
return expr_val;
|
return expr_val;
|
||||||
} else if (actual_type->size_in_bits < wanted_type->size_in_bits) {
|
} else if (actual_type->size_in_bits < wanted_type->size_in_bits) {
|
||||||
|
if (actual_type->id == TypeTableEntryIdFloat) {
|
||||||
|
add_debug_source_node(g, source_node);
|
||||||
|
return LLVMBuildFPExt(g->builder, expr_val, wanted_type->type_ref, "");
|
||||||
|
} else if (actual_type->id == TypeTableEntryIdInt) {
|
||||||
if (actual_type->data.integral.is_signed) {
|
if (actual_type->data.integral.is_signed) {
|
||||||
add_debug_source_node(g, source_node);
|
add_debug_source_node(g, source_node);
|
||||||
return LLVMBuildSExt(g->builder, expr_val, wanted_type->type_ref, "");
|
return LLVMBuildSExt(g->builder, expr_val, wanted_type->type_ref, "");
|
||||||
|
@ -360,9 +365,20 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, AstNode *source_node, TypeT
|
||||||
return LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, "");
|
return LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, "");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
assert(actual_type->size_in_bits > wanted_type->size_in_bits);
|
zig_unreachable();
|
||||||
|
}
|
||||||
|
} else if (actual_type->size_in_bits > wanted_type->size_in_bits) {
|
||||||
|
if (actual_type->id == TypeTableEntryIdFloat) {
|
||||||
|
add_debug_source_node(g, source_node);
|
||||||
|
return LLVMBuildFPTrunc(g->builder, expr_val, wanted_type->type_ref, "");
|
||||||
|
} else if (actual_type->id == TypeTableEntryIdInt) {
|
||||||
add_debug_source_node(g, source_node);
|
add_debug_source_node(g, source_node);
|
||||||
return LLVMBuildTrunc(g->builder, expr_val, wanted_type->type_ref, "");
|
return LLVMBuildTrunc(g->builder, expr_val, wanted_type->type_ref, "");
|
||||||
|
} else {
|
||||||
|
zig_unreachable();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
zig_unreachable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -455,7 +471,7 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
|
||||||
case CastOpPointerReinterpret:
|
case CastOpPointerReinterpret:
|
||||||
add_debug_source_node(g, node);
|
add_debug_source_node(g, node);
|
||||||
return LLVMBuildBitCast(g->builder, expr_val, wanted_type->type_ref, "");
|
return LLVMBuildBitCast(g->builder, expr_val, wanted_type->type_ref, "");
|
||||||
case CastOpIntWidenOrShorten:
|
case CastOpWidenOrShorten:
|
||||||
return gen_widen_or_shorten(g, node, actual_type, wanted_type, expr_val);
|
return gen_widen_or_shorten(g, node, actual_type, wanted_type, expr_val);
|
||||||
case CastOpToUnknownSizeArray:
|
case CastOpToUnknownSizeArray:
|
||||||
{
|
{
|
||||||
|
|
|
@ -1493,7 +1493,8 @@ c_import {
|
||||||
@c_include("stdio.h");
|
@c_include("stdio.h");
|
||||||
}
|
}
|
||||||
export fn main(argc: c_int, argv: &&u8) -> c_int {
|
export fn main(argc: c_int, argv: &&u8) -> c_int {
|
||||||
const x : f64 = 3.25;
|
const small: f32 = 3.25;
|
||||||
|
const x: f64 = small;
|
||||||
const y = i32(x);
|
const y = i32(x);
|
||||||
const z = f64(y);
|
const z = f64(y);
|
||||||
printf(c"%.2f\n%d\n%.2f\n", x, y, z);
|
printf(c"%.2f\n%d\n%.2f\n", x, y, z);
|
||||||
|
@ -1945,6 +1946,12 @@ pub fn a(x: i32) -> i32 {x + 0}
|
||||||
pub fn b(x: i32) -> i32 {x + 1}
|
pub fn b(x: i32) -> i32 {x + 1}
|
||||||
export fn c(x: i32) -> i32 {x + 2}
|
export fn c(x: i32) -> i32 {x + 2}
|
||||||
)SOURCE", 1, ".tmp_source.zig:2:37: error: expected type 'fn(i32) -> i32', got 'extern fn(i32) -> i32'");
|
)SOURCE", 1, ".tmp_source.zig:2:37: error: expected type 'fn(i32) -> i32', got 'extern fn(i32) -> i32'");
|
||||||
|
|
||||||
|
|
||||||
|
add_compile_fail_case("implicit cast from f64 to f32", R"SOURCE(
|
||||||
|
const x : f64 = 1.0;
|
||||||
|
const y : f32 = x;
|
||||||
|
)SOURCE", 1, ".tmp_source.zig:3:17: error: expected type 'f32', got 'f64'");
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
Loading…
Reference in New Issue