diff --git a/src/all_types.hpp b/src/all_types.hpp index 9d00980c2a..68a9b080ed 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -340,7 +340,7 @@ enum CastOp { CastOpNoop, // fn call expr is a cast, but does nothing CastOpPtrToInt, CastOpIntToPtr, - CastOpIntWidenOrShorten, + CastOpWidenOrShorten, CastOpToUnknownSizeArray, CastOpMaybeWrap, CastOpErrorWrap, diff --git a/src/analyze.cpp b/src/analyze.cpp index 785bad9ff2..8942746e2d 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1681,6 +1681,14 @@ static bool types_match_with_implicit_cast(CodeGen *g, TypeTableEntry *expected_ 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 if (expected_type->id == TypeTableEntryIdStruct && 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: zig_unreachable(); case CastOpNoop: - case CastOpIntWidenOrShorten: + case CastOpWidenOrShorten: case CastOpPointerReinterpret: *const_val = *other_val; break; @@ -3477,11 +3485,13 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B return wanted_type; } - // explicit cast from any int to any other int - if (wanted_type->id == TypeTableEntryIdInt && - actual_type->id == TypeTableEntryIdInt) + // explicit widening or shortening cast + if ((wanted_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); return wanted_type; } diff --git a/src/codegen.cpp b/src/codegen.cpp index 24608bc553..9af8555d49 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -349,20 +349,36 @@ 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, TypeTableEntry *wanted_type, LLVMValueRef expr_val) { + assert(actual_type->id == wanted_type->id); if (actual_type->size_in_bits == wanted_type->size_in_bits) { return expr_val; } else if (actual_type->size_in_bits < wanted_type->size_in_bits) { - if (actual_type->data.integral.is_signed) { + if (actual_type->id == TypeTableEntryIdFloat) { add_debug_source_node(g, source_node); - return LLVMBuildSExt(g->builder, expr_val, wanted_type->type_ref, ""); + return LLVMBuildFPExt(g->builder, expr_val, wanted_type->type_ref, ""); + } else if (actual_type->id == TypeTableEntryIdInt) { + if (actual_type->data.integral.is_signed) { + add_debug_source_node(g, source_node); + return LLVMBuildSExt(g->builder, expr_val, wanted_type->type_ref, ""); + } else { + add_debug_source_node(g, source_node); + return LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, ""); + } } else { + 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 LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, ""); + return LLVMBuildFPTrunc(g->builder, expr_val, wanted_type->type_ref, ""); + } else if (actual_type->id == TypeTableEntryIdInt) { + add_debug_source_node(g, source_node); + return LLVMBuildTrunc(g->builder, expr_val, wanted_type->type_ref, ""); + } else { + zig_unreachable(); } } else { - assert(actual_type->size_in_bits > wanted_type->size_in_bits); - add_debug_source_node(g, source_node); - return LLVMBuildTrunc(g->builder, expr_val, wanted_type->type_ref, ""); + zig_unreachable(); } } @@ -455,7 +471,7 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) { case CastOpPointerReinterpret: add_debug_source_node(g, node); 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); case CastOpToUnknownSizeArray: { diff --git a/test/run_tests.cpp b/test/run_tests.cpp index e93145d4d0..39cecb72d5 100644 --- a/test/run_tests.cpp +++ b/test/run_tests.cpp @@ -1493,7 +1493,8 @@ c_import { @c_include("stdio.h"); } 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 z = f64(y); 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} 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'"); + + + 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'"); } //////////////////////////////////////////////////////////////////////////////