From 30772d94b1e86a09723af1f137149b45e8c12ed7 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 13 Jun 2014 11:14:04 -0700 Subject: [PATCH] librustc: Forbid enum-to-float casts. Closes #14794. If you're casting from an enum to a float, cast through an integer first. [breaking-change] --- src/librustc/middle/trans/consts.rs | 3 +-- src/librustc/middle/ty.rs | 8 ++++++++ src/librustc/middle/typeck/check/mod.rs | 19 ++++++++++++++++++- .../enum-to-float-cast.rs | 10 +++++----- src/test/run-pass/const-enum-cast.rs | 8 -------- src/test/run-pass/enum-disr-val-pretty.rs | 1 - src/test/run-pass/tag-variant-disr-val.rs | 1 - 7 files changed, 32 insertions(+), 18 deletions(-) rename src/test/{run-pass => compile-fail}/enum-to-float-cast.rs (74%) diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index ae476fb9741..7e4bcb8f684 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -503,9 +503,8 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, let s = ty::type_is_signed(ety) as Bool; llvm::LLVMConstIntCast(iv, llty.to_ref(), s) } - expr::cast_float => llvm::LLVMConstSIToFP(iv, llty.to_ref()), _ => cx.sess().bug("enum cast destination is not \ - integral or float") + integral") } } (expr::cast_pointer, expr::cast_pointer) => { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 2a0873e327b..0345dc3241e 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1658,6 +1658,14 @@ pub fn type_is_scalar(ty: t) -> bool { } } +/// Returns true if this type is a floating point type and false otherwise. +pub fn type_is_floating_point(ty: t) -> bool { + match get(ty).sty { + ty_float(_) => true, + _ => false, + } +} + pub fn type_needs_drop(cx: &ctxt, ty: t) -> bool { type_contents(cx, ty).needs_drop(cx) } diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index a6615d6bce9..a01df3dd7d2 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -3229,12 +3229,24 @@ fn check_expr_with_unifier(fcx: &FnCtxt, let t_1_is_scalar = type_is_scalar(fcx, expr.span, t_1); let t_1_is_char = type_is_char(fcx, expr.span, t_1); let t_1_is_bare_fn = type_is_bare_fn(fcx, expr.span, t_1); + let t_1_is_float = type_is_floating_point(fcx, + expr.span, + t_1); // casts to scalars other than `char` and `bare fn` are trivial let t_1_is_trivial = t_1_is_scalar && !t_1_is_char && !t_1_is_bare_fn; - if type_is_c_like_enum(fcx, expr.span, t_e) && t_1_is_trivial { + if type_is_c_like_enum(fcx, expr.span, t_e) && + t_1_is_trivial { + if t_1_is_float { + fcx.type_error_message(expr.span, |actual| { + format!("illegal cast; cast through an \ + integer first: `{}` as `{}`", + actual, + fcx.infcx().ty_to_str(t_1)) + }, t_e, None); + } // casts from C-like enums are allowed } else if t_1_is_char { let te = fcx.infcx().resolve_type_vars_if_possible(te); @@ -4205,6 +4217,11 @@ pub fn type_is_bare_fn(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool { return ty::type_is_bare_fn(typ_s); } +pub fn type_is_floating_point(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool { + let typ_s = structurally_resolved_type(fcx, sp, typ); + return ty::type_is_floating_point(typ_s); +} + pub fn type_is_unsafe_ptr(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool { let typ_s = structurally_resolved_type(fcx, sp, typ); return ty::type_is_unsafe_ptr(typ_s); diff --git a/src/test/run-pass/enum-to-float-cast.rs b/src/test/compile-fail/enum-to-float-cast.rs similarity index 74% rename from src/test/run-pass/enum-to-float-cast.rs rename to src/test/compile-fail/enum-to-float-cast.rs index eb6c078efcd..9c859cb0dde 100644 --- a/src/test/run-pass/enum-to-float-cast.rs +++ b/src/test/compile-fail/enum-to-float-cast.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Tests that enum-to-float-casts do *signed* integer-to-float conversion. +// Tests that enum-to-float casts are disallowed. enum E { L0 = -1, @@ -20,13 +20,13 @@ enum F { H1 = 0xFFFFFFFFFFFFFFFF } -static C0: f32 = L0 as f32; -static C1: f32 = H1 as f32; +static C0: f32 = L0 as f32; //~ ERROR illegal cast +static C1: f32 = H1 as f32; //~ ERROR illegal cast pub fn main() { - let a = L0 as f32; + let a = L0 as f32; //~ ERROR illegal cast let b = C0; - let c = H1 as f32; + let c = H1 as f32; //~ ERROR illegal cast let d = C1; assert_eq!(a, -1.0f32); assert_eq!(b, -1.0f32); diff --git a/src/test/run-pass/const-enum-cast.rs b/src/test/run-pass/const-enum-cast.rs index 75e942cb767..346d379aa14 100644 --- a/src/test/run-pass/const-enum-cast.rs +++ b/src/test/run-pass/const-enum-cast.rs @@ -14,18 +14,10 @@ enum B { B1=0, B2=2 } pub fn main () { static c1: int = A2 as int; static c2: int = B2 as int; - static c3: f64 = A2 as f64; - static c4: f64 = B2 as f64; let a1 = A2 as int; let a2 = B2 as int; - let a3 = A2 as f64; - let a4 = B2 as f64; assert_eq!(c1, 1); assert_eq!(c2, 2); - assert_eq!(c3, 1.0); - assert_eq!(c4, 2.0); assert_eq!(a1, 1); assert_eq!(a2, 2); - assert_eq!(a3, 1.0); - assert_eq!(a4, 2.0); } diff --git a/src/test/run-pass/enum-disr-val-pretty.rs b/src/test/run-pass/enum-disr-val-pretty.rs index 66b11aefd32..c34b2be6fb5 100644 --- a/src/test/run-pass/enum-disr-val-pretty.rs +++ b/src/test/run-pass/enum-disr-val-pretty.rs @@ -21,5 +21,4 @@ pub fn main() { fn test_color(color: color, val: int, _name: String) { assert!(color as int == val); - assert!(color as f64 == val as f64); } diff --git a/src/test/run-pass/tag-variant-disr-val.rs b/src/test/run-pass/tag-variant-disr-val.rs index 191a6a9c7e2..ac9af2b693d 100644 --- a/src/test/run-pass/tag-variant-disr-val.rs +++ b/src/test/run-pass/tag-variant-disr-val.rs @@ -40,7 +40,6 @@ pub fn main() { fn test_color(color: color, val: int, name: String) { //assert!(unsafe::transmute(color) == val); assert_eq!(color as int, val); - assert_eq!(color as f64, val as f64); assert!(get_color_alt(color) == name); assert!(get_color_if(color) == name); }