From e3b9bf5e828556aa798e100c832bd217eb9e4716 Mon Sep 17 00:00:00 2001 From: Stefan Plantikow Date: Wed, 30 Nov 2011 12:30:22 +0100 Subject: [PATCH 1/5] ty: added type comparison that subs prim types with targ_cfg machine types --- src/comp/middle/ty.rs | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 5a290f7efc6d8..481507c53d969 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -102,6 +102,7 @@ export substitute_type_params; export t; export tag_variants; export tag_variant_with_id; +export triv_eq_ty; export ty_param_substs_opt_and_ty; export ty_param_kinds_and_ty; export ty_native_fn; @@ -128,6 +129,7 @@ export ty_param; export ty_ptr; export ty_rec; export ty_tag; +export ty_to_machine_ty; export ty_tup; export ty_type; export ty_uint; @@ -1481,6 +1483,41 @@ fn eq_raw_ty(&&a: @raw_t, &&b: @raw_t) -> bool { fn eq_ty(&&a: t, &&b: t) -> bool { ret a == b; } +// Convert type to machine type +// (i.e. replace uint, int, float with target architecture machine types) +// +// Somewhat expensive but casts that need this should be rare +fn ty_to_machine_ty(cx: ctxt, ty: t) -> t { + fn sub_fn(cx: ctxt, uint_ty: t, int_ty: t, float_ty: t, in: t) -> t { + alt struct(cx, in) { + ty_uint. { ret uint_ty; } + ty_int. { ret int_ty; } + ty_float. { ret float_ty; } + _ { ret in; } + } + } + + let cfg = cx.sess.get_targ_cfg(); + let uint_ty = mk_mach(cx, cfg.uint_type); + let int_ty = mk_mach(cx, cfg.int_type); + let float_ty = mk_mach(cx, cfg.float_type); + let fold_m = fm_general(bind sub_fn(cx, uint_ty, int_ty, float_ty, _)); + + ret fold_ty(cx, fold_m, ty); +} + +// Two types are trivially equal if they are either +// equal or if they are equal after substituting all occurences of +// machine independent primitive types by their machine type equivalents +// for the current target architecture +// +// Somewhat expensive but casts that need this should be rare +fn triv_eq_ty(cx: ctxt, &&a: t, &&b: t) -> bool { + let mach_a = ty_to_machine_ty(cx, a); + let mach_b = ty_to_machine_ty(cx, b ); + ret eq_ty(a, b) || eq_ty(mach_a, mach_b); +} + // Type lookups fn node_id_to_ty_param_substs_opt_and_ty(cx: ctxt, id: ast::node_id) -> ty_param_substs_opt_and_ty { From f724512689676c50c0b9f8cfad3490d62404425b Mon Sep 17 00:00:00 2001 From: Stefan Plantikow Date: Wed, 30 Nov 2011 17:58:08 +0100 Subject: [PATCH 2/5] ty: trans: added support for dropping trivial casts --- src/comp/middle/trans.rs | 9 ++++++++- src/comp/middle/ty.rs | 10 ++++++++++ src/comp/middle/typeck.rs | 10 +++++++--- src/comp/syntax/ast_util.rs | 9 ++++++++- 4 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 237b00899536f..52eae92111ff2 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -4086,7 +4086,14 @@ fn trans_expr(bcx: @block_ctxt, e: @ast::expr, dest: dest) -> @block_ctxt { if !ty::expr_is_lval(tcx, a) { ret trans_expr(bcx, a, dest); } else { ret lval_to_dps(bcx, a, dest); } } - ast::expr_cast(val, _) { ret trans_cast(bcx, val, e.id, dest); } + ast::expr_cast(val, _) { + alt tcx.cast_map.find(e.id) { + option::none. { ret trans_cast(bcx, val, e.id, dest); } + some { alt option::get(some) { + ty::triv_cast. { ret trans_expr(bcx, val, dest); } + } } + } + } ast::expr_anon_obj(anon_obj) { ret trans_anon_obj(bcx, e.span, anon_obj, e.id, dest); } diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 481507c53d969..9dbe3f7c1de63 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -32,6 +32,7 @@ export ast_constr_to_constr; export bind_params_in_type; export block_ty; export constr; +export cast_type; export constr_general; export constr_table; export count_ty_params; @@ -102,6 +103,7 @@ export substitute_type_params; export t; export tag_variants; export tag_variant_with_id; +export triv_cast; export triv_eq_ty; export ty_param_substs_opt_and_ty; export ty_param_kinds_and_ty; @@ -200,6 +202,12 @@ type mt = {ty: t, mut: ast::mutability}; // the types of AST nodes. type creader_cache = hashmap<{cnum: int, pos: uint, len: uint}, ty::t>; +tag cast_type { + /* cast may be ignored after substituting primitive with machine types + since expr already has the right type */ + triv_cast; +} + type ctxt = // constr_table fn_constrs, // We need the ext_map just for printing the types of tags defined in @@ -208,6 +216,7 @@ type ctxt = sess: session::session, def_map: resolve::def_map, ext_map: resolve::ext_map, + cast_map: hashmap, node_types: node_type_table, items: ast_map::map, freevars: freevars::freevar_map, @@ -395,6 +404,7 @@ fn mk_ctxt(s: session::session, dm: resolve::def_map, sess: s, def_map: dm, ext_map: em, + cast_map: ast_util::new_node_hash(), node_types: ntt, items: amap, freevars: freevars, diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index fc0a4de5245da..3b6c70d4f237f 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -2103,15 +2103,19 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, ast::expr_cast(e, t) { bot = check_expr(fcx, e); let t_1 = ast_ty_to_ty_crate(fcx.ccx, t); - // FIXME: there are more forms of cast to support, eventually. + let t_e = expr_ty(tcx, e); - if !(type_is_scalar(fcx, expr.span, expr_ty(tcx, e)) && - type_is_scalar(fcx, expr.span, t_1)) { + // FIXME there are more forms of cast to support, eventually. + if !( type_is_scalar(fcx, expr.span, t_e) + && type_is_scalar(fcx, expr.span, t_1)) { tcx.sess.span_err(expr.span, "non-scalar cast: " + ty_to_str(tcx, expr_ty(tcx, e)) + " as " + ty_to_str(tcx, t_1)); } + + if ty::triv_eq_ty(tcx, t_1, t_e) + { tcx.cast_map.insert(expr.id, ty::triv_cast); } write::ty_only_fixup(fcx, id, t_1); } ast::expr_vec(args, mut) { diff --git a/src/comp/syntax/ast_util.rs b/src/comp/syntax/ast_util.rs index da7b5a449534e..53c3892195853 100644 --- a/src/comp/syntax/ast_util.rs +++ b/src/comp/syntax/ast_util.rs @@ -1,4 +1,4 @@ -import std::{str, option}; +import std::{str, option, int, map}; import codemap::span; import ast::*; @@ -6,6 +6,13 @@ fn respan(sp: span, t: T) -> spanned { ret {node: t, span: sp}; } +fn new_node_hash() -> map::hashmap { + fn node_id_hash(&&i: node_id) -> uint { ret int::hash(i as int); } + fn node_id_eq(&&a: node_id, &&b: node_id) -> bool + { ret int::eq(a as int, b as int); } + ret map::mk_hashmap(node_id_hash, node_id_eq); +} + /* assuming that we're not in macro expansion */ fn mk_sp(lo: uint, hi: uint) -> span { ret {lo: lo, hi: hi, expanded_from: codemap::os_none}; From f2677eb759d2f8e22ca6ed6f3deacebeef649146 Mon Sep 17 00:00:00 2001 From: Stefan Plantikow Date: Wed, 30 Nov 2011 19:55:41 +0100 Subject: [PATCH 3/5] parse: typeck: enabling trivial casts of tail-call return values introduces ctypes::m_* machine type aliases for int, uint, float depending on cfg(target_arch) that are used in tests --- src/comp/middle/trans.rs | 11 ++-- src/comp/middle/ty.rs | 9 ++-- src/comp/middle/typeck.rs | 17 ++++++- src/comp/syntax/ast_util.rs | 8 +++ src/comp/syntax/parse/parser.rs | 2 +- src/lib/ctypes.rs | 17 ++++++- src/lib/math.rs | 62 +++++++++++------------ src/test/compile-fail/non-triv-cast-be.rs | 19 +++++++ src/test/run-pass/triv-cast-be.rs | 26 ++++++++++ 9 files changed, 124 insertions(+), 47 deletions(-) create mode 100644 src/test/compile-fail/non-triv-cast-be.rs create mode 100644 src/test/run-pass/triv-cast-be.rs diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 52eae92111ff2..ae09250b2e5f9 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -4088,10 +4088,8 @@ fn trans_expr(bcx: @block_ctxt, e: @ast::expr, dest: dest) -> @block_ctxt { } ast::expr_cast(val, _) { alt tcx.cast_map.find(e.id) { - option::none. { ret trans_cast(bcx, val, e.id, dest); } - some { alt option::get(some) { - ty::triv_cast. { ret trans_expr(bcx, val, dest); } - } } + some(ty::triv_cast.) { ret trans_expr(bcx, val, dest); } + _ { ret trans_cast(bcx, val, e.id, dest); } } } ast::expr_anon_obj(anon_obj) { @@ -4122,7 +4120,7 @@ fn trans_expr(bcx: @block_ctxt, e: @ast::expr, dest: dest) -> @block_ctxt { // that is_call_expr(ex) -- but we don't support that // yet // FIXME - check (ast_util::is_call_expr(ex)); + check (ast_util::is_tail_call_expr(ex)); ret trans_be(bcx, ex); } ast::expr_fail(expr) { @@ -4455,7 +4453,8 @@ fn trans_ret(bcx: @block_ctxt, e: option::t<@ast::expr>) -> @block_ctxt { fn build_return(bcx: @block_ctxt) { Br(bcx, bcx_fcx(bcx).llreturn); } // fn trans_be(cx: &@block_ctxt, e: &@ast::expr) -> result { -fn trans_be(cx: @block_ctxt, e: @ast::expr) : ast_util::is_call_expr(e) -> +fn trans_be(cx: @block_ctxt, e: @ast::expr) : +ast_util::is_tail_call_expr(e) -> @block_ctxt { // FIXME: Turn this into a real tail call once // calling convention issues are settled diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 9dbe3f7c1de63..100154ae6856d 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -1496,7 +1496,7 @@ fn eq_ty(&&a: t, &&b: t) -> bool { ret a == b; } // Convert type to machine type // (i.e. replace uint, int, float with target architecture machine types) // -// Somewhat expensive but casts that need this should be rare +// FIXME somewhat expensive but this should only be called rarely fn ty_to_machine_ty(cx: ctxt, ty: t) -> t { fn sub_fn(cx: ctxt, uint_ty: t, int_ty: t, float_ty: t, in: t) -> t { alt struct(cx, in) { @@ -1520,12 +1520,9 @@ fn ty_to_machine_ty(cx: ctxt, ty: t) -> t { // equal or if they are equal after substituting all occurences of // machine independent primitive types by their machine type equivalents // for the current target architecture -// -// Somewhat expensive but casts that need this should be rare fn triv_eq_ty(cx: ctxt, &&a: t, &&b: t) -> bool { - let mach_a = ty_to_machine_ty(cx, a); - let mach_b = ty_to_machine_ty(cx, b ); - ret eq_ty(a, b) || eq_ty(mach_a, mach_b); + ret eq_ty(a, b) + || eq_ty(ty_to_machine_ty(cx, a), ty_to_machine_ty(cx, b)); } // Type lookups diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index 3b6c70d4f237f..c76f1318a75ce 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -1848,8 +1848,21 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, } ast::expr_be(e) { // FIXME: prove instead of assert - assert (ast_util::is_call_expr(e)); + assert (ast_util::is_tail_call_expr(e)); check_expr_with(fcx, e, fcx.ret_ty); + + alt e.node { + ast::expr_cast(_, _) { + alt tcx.cast_map.find(e.id) { + option::some(ty::triv_cast.) { } + _ { tcx.sess.span_err(expr.span, + "non-trivial cast of tail-call return value"); + } + } + } + _ { /* regular tail call */ } + } + bot = true; write::nil_ty(tcx, id); } @@ -2114,8 +2127,10 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, ty_to_str(tcx, t_1)); } + // mark as triv_cast for later dropping in trans if ty::triv_eq_ty(tcx, t_1, t_e) { tcx.cast_map.insert(expr.id, ty::triv_cast); } + write::ty_only_fixup(fcx, id, t_1); } ast::expr_vec(args, mut) { diff --git a/src/comp/syntax/ast_util.rs b/src/comp/syntax/ast_util.rs index 53c3892195853..e190a77b50510 100644 --- a/src/comp/syntax/ast_util.rs +++ b/src/comp/syntax/ast_util.rs @@ -175,6 +175,14 @@ pure fn is_call_expr(e: @expr) -> bool { alt e.node { expr_call(_, _, _) { true } _ { false } } } +pure fn is_tail_call_expr(e: @expr) -> bool { + alt e.node { + expr_call(_, _, _) { true } + expr_cast(inner_e, _) { is_call_expr(inner_e) } + _ { false } + } +} + fn is_constraint_arg(e: @expr) -> bool { alt e.node { expr_lit(_) { ret true; } diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs index 6d751dff64550..95aa3ffc434c0 100644 --- a/src/comp/syntax/parse/parser.rs +++ b/src/comp/syntax/parse/parser.rs @@ -962,7 +962,7 @@ fn parse_bottom_expr(p: parser) -> @ast::expr { let e = parse_expr(p); // FIXME: Is this the right place for this check? - if /*check*/ast_util::is_call_expr(e) { + if /*check*/ ast_util::is_tail_call_expr(e) { hi = e.span.hi; ex = ast::expr_be(e); } else { p.fatal("Non-call expression in tail call"); } diff --git a/src/lib/ctypes.rs b/src/lib/ctypes.rs index 48c4a85fcbcdb..82e414a864ce5 100644 --- a/src/lib/ctypes.rs +++ b/src/lib/ctypes.rs @@ -5,6 +5,7 @@ Definitions useful for C interop */ type c_int = i32; +type c_uint = u32; type void = int; // Not really the same as C type long = int; @@ -15,8 +16,20 @@ type intptr_t = uint; type uintptr_t = uint; type uint32_t = u32; -// This *must* match with "import c_float = fXX" in std::math per arch -type c_float = f64; +// machine type equivalents of rust int, uint, float + +#[cfg(target_arch="x86")] +type m_int = i32; +#[cfg(target_arch="x86_64")] +type m_int = i64; + +#[cfg(target_arch="x86")] +type m_uint = u32; +#[cfg(target_arch="x86_64")] +type m_uint = u64; + +// This *must* match with "import m_float = fXX" in std::math per arch +type m_float = f64; type size_t = uint; type ssize_t = int; diff --git a/src/lib/math.rs b/src/lib/math.rs index 7b4308668b48a..72056548ca578 100644 --- a/src/lib/math.rs +++ b/src/lib/math.rs @@ -18,11 +18,11 @@ export // These two must match in width according to architecture -import ctypes::c_float; +import ctypes::m_float; import ctypes::c_int; -import c_float = math_f64; +import m_float = math_f64; -// FIXME replace with redirect to c_float::consts::FOO as soon as it works +// FIXME replace with redirect to m_float::consts::FOO as soon as it works mod consts { /* Const: pi @@ -140,7 +140,7 @@ Function: acos Returns the arccosine of an angle (measured in rad) */ pure fn acos(x: float) -> float - { c_float::acos(x as c_float) as float } + { m_float::acos(x as m_float) as float } /* Function: asin @@ -148,7 +148,7 @@ Function: asin Returns the arcsine of an angle (measured in rad) */ pure fn asin(x: float) -> float - { c_float::asin(x as c_float) as float } + { m_float::asin(x as m_float) as float } /* Function: atan @@ -156,7 +156,7 @@ Function: atan Returns the arctangents of an angle (measured in rad) */ pure fn atan(x: float) -> float - { c_float::atan(x as c_float) as float } + { m_float::atan(x as m_float) as float } /* @@ -165,7 +165,7 @@ Function: atan2 Returns the arctangent of an angle (measured in rad) */ pure fn atan2(y: float, x: float) -> float - { c_float::atan2(y as c_float, x as c_float) as float } + { m_float::atan2(y as m_float, x as m_float) as float } /* Function: ceil @@ -173,7 +173,7 @@ Function: ceil Returns the smallest integral value less than or equal to `n` */ pure fn ceil(n: float) -> float - { c_float::ceil(n as c_float) as float } + { m_float::ceil(n as m_float) as float } /* Function: cos @@ -181,7 +181,7 @@ Function: cos Returns the cosine of an angle `x` (measured in rad) */ pure fn cos(x: float) -> float - { c_float::cos(x as c_float) as float } + { m_float::cos(x as m_float) as float } /* Function: cosh @@ -190,7 +190,7 @@ Returns the hyperbolic cosine of `x` */ pure fn cosh(x: float) -> float - { c_float::cosh(x as c_float) as float } + { m_float::cosh(x as m_float) as float } /* @@ -199,7 +199,7 @@ Function: exp Returns `consts::e` to the power of `n* */ pure fn exp(n: float) -> float - { c_float::exp(n as c_float) as float } + { m_float::exp(n as m_float) as float } /* Function: abs @@ -207,7 +207,7 @@ Function: abs Returns the absolute value of `n` */ pure fn abs(n: float) -> float - { c_float::abs(n as c_float) as float } + { m_float::abs(n as m_float) as float } /* Function: floor @@ -215,7 +215,7 @@ Function: floor Returns the largest integral value less than or equal to `n` */ pure fn floor(n: float) -> float - { c_float::floor(n as c_float) as float } + { m_float::floor(n as m_float) as float } /* Function: fmod @@ -223,7 +223,7 @@ Function: fmod Returns the floating-point remainder of `x/y` */ pure fn fmod(x: float, y: float) -> float - { c_float::fmod(x as c_float, y as c_float) as float } + { m_float::fmod(x as m_float, y as m_float) as float } /* Function: ln @@ -231,7 +231,7 @@ Function: ln Returns the natural logaritm of `n` */ pure fn ln(n: float) -> float - { c_float::ln(n as c_float) as float } + { m_float::ln(n as m_float) as float } /* Function: ldexp @@ -239,7 +239,7 @@ Function: ldexp Returns `x` multiplied by 2 to the power of `n` */ pure fn ldexp(n: float, i: int) -> float - { c_float::ldexp(n as c_float, i as c_int) as float } + { m_float::ldexp(n as m_float, i as c_int) as float } /* Function: ln1p @@ -248,7 +248,7 @@ Returns the natural logarithm of `1+n` accurately, even for very small values of `n` */ pure fn ln1p(n: float) -> float - { c_float::ln1p(n as c_float) as float } + { m_float::ln1p(n as m_float) as float } /* Function: log10 @@ -256,7 +256,7 @@ Function: log10 Returns the logarithm to base 10 of `n` */ pure fn log10(n: float) -> float - { c_float::log10(n as c_float) as float } + { m_float::log10(n as m_float) as float } /* Function: log2 @@ -264,7 +264,7 @@ Function: log2 Returns the logarithm to base 2 of `n` */ pure fn log2(n: float) -> float - { c_float::log2(n as c_float) as float } + { m_float::log2(n as m_float) as float } /* @@ -281,8 +281,8 @@ The fractional part of `n` */ pure fn modf(n: float, &iptr: float) -> float { unchecked { - let f = iptr as c_float; - let r = c_float::modf(n as c_float, f) as float; + let f = iptr as m_float; + let r = m_float::modf(n as m_float, f) as float; iptr = f as float; ret r; } @@ -303,13 +303,13 @@ Returns: The fractional part of `n` */ pure fn frexp(n: float, &exp: c_int) -> float - { c_float::frexp(n as c_float, exp) as float } + { m_float::frexp(n as m_float, exp) as float } /* Function: pow */ pure fn pow(v: float, e: float) -> float - { c_float::pow(v as c_float, e as c_float) as float } + { m_float::pow(v as m_float, e as m_float) as float } /* @@ -319,7 +319,7 @@ Returns the integral value nearest to `x` (according to the prevailing rounding mode) in floating-point format */ pure fn rint(x: float) -> float - { c_float::rint(x as c_float) as float } + { m_float::rint(x as m_float) as float } /* Function: round @@ -329,7 +329,7 @@ Return the integral value nearest to `x` rounding half-way cases away from zero, regardless of the current rounding direction. */ pure fn round(x: float) -> float - { c_float::round(x as c_float) as float } + { m_float::round(x as m_float) as float } /* Function: sin @@ -337,7 +337,7 @@ Function: sin Returns the sine of an angle `x` (measured in rad) */ pure fn sin(x: float) -> float - { c_float::sin(x as c_float) as float } + { m_float::sin(x as m_float) as float } /* Function: sinh @@ -345,7 +345,7 @@ Function: sinh Returns the hyperbolic sine of an angle `x` (measured in rad) */ pure fn sinh(x: float) -> float - { c_float::sinh(x as c_float) as float } + { m_float::sinh(x as m_float) as float } /* Function: sqrt @@ -353,7 +353,7 @@ Function: sqrt Returns the square root of `x` */ pure fn sqrt(x: float) -> float - { c_float::sqrt(x as c_float) as float } + { m_float::sqrt(x as m_float) as float } /* Function: tan @@ -362,7 +362,7 @@ Returns the tangent of an angle `x` (measured in rad) */ pure fn tan(x: float) -> float - { c_float::tan(x as c_float) as float } + { m_float::tan(x as m_float) as float } /* Function: tanh @@ -371,7 +371,7 @@ Returns the hyperbolic tangent of an angle `x` (measured in rad) */ pure fn tanh(x: float) -> float - { c_float::tanh(x as c_float) as float } + { m_float::tanh(x as m_float) as float } /* Function: trunc @@ -380,7 +380,7 @@ Returns the integral value nearest to but no larger in magnitude than `x` */ pure fn trunc(x: float) -> float - { c_float::trunc(x as c_float) as float } + { m_float::trunc(x as m_float) as float } diff --git a/src/test/compile-fail/non-triv-cast-be.rs b/src/test/compile-fail/non-triv-cast-be.rs new file mode 100644 index 0000000000000..14f2c0bfdcd69 --- /dev/null +++ b/src/test/compile-fail/non-triv-cast-be.rs @@ -0,0 +1,19 @@ +// error-pattern: non-trivial cast of tail-call return value +use std; + +import std::ctypes::*; + +fn foo_float() -> m_float { ret 0.0 as m_float; } +fn bar_float() -> bool { be foo_float() as bool; } + +fn foo_int() -> m_int { ret 0 as m_int; } +fn bar_int() -> bool { be foo_int() as bool; } + +fn foo_uint() -> m_uint { ret 0u as m_uint; } +fn bar_uint() -> bool { be foo_uint() as bool; } + +fn main() { + assert bar_float() == 0.0; + assert bar_int() == 0.0; + assert bar_uint() == 0.0; +} \ No newline at end of file diff --git a/src/test/run-pass/triv-cast-be.rs b/src/test/run-pass/triv-cast-be.rs new file mode 100644 index 0000000000000..de78341a199c5 --- /dev/null +++ b/src/test/run-pass/triv-cast-be.rs @@ -0,0 +1,26 @@ +use std; + +import std::ctypes::*; + +fn foo_float() -> m_float { ret 0.0 as m_float; } +fn bar_float() -> float { be foo_float() as float; } + +fn foo_int() -> m_int { ret 0 as m_int; } +fn bar_int() -> int { be foo_int() as int; } + +fn foo_uint() -> m_uint { ret 0u as m_uint; } +fn bar_uint() -> uint { be foo_uint() as uint; } + +fn foo_long() -> long { ret 0 as long; } +fn bar_long() -> int { be foo_long() as int; } + +fn foo_ulong() -> ulong { ret 0u as ulong; } +fn bar_ulong() -> uint { be foo_uint() as uint; } + +fn main() { + assert bar_float() == 0.0; + assert bar_int() == 0; + assert bar_uint() == 0u; + assert bar_long() == 0; + assert bar_ulong() == 0u; +} \ No newline at end of file From 543b78c0d44a5a1cdb6e4cc3711670f2c6968f8b Mon Sep 17 00:00:00 2001 From: Stefan Plantikow Date: Fri, 2 Dec 2011 02:15:49 +0100 Subject: [PATCH 4/5] doc: added definition of trivial casts to spec (cf @ignored Expr.Be and #1215 for intended use) --- doc/rust.texi | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/doc/rust.texi b/doc/rust.texi index 09524a8055de1..540b209c0745c 100644 --- a/doc/rust.texi +++ b/doc/rust.texi @@ -2954,9 +2954,8 @@ analogous to a @code{become} expression in Newsqueak or Alef.} destroys the current function activation frame and replaces it with an activation frame for the called function. In other words, @code{be} executes a tail-call. The syntactic form of a @code{be} expression is therefore limited to @emph{tail -position}: its argument must be a @emph{call expression}, and it must be the -last expression in a block. - +position}: its argument must be a @emph{call expression} or a @{trivial cast} +of a @emph{call expression}, and it must be the last expression in a block. An example of a @code{be} expression: @example fn print_loop(n: int) @{ @@ -2971,6 +2970,7 @@ fn print_loop(n: int) @{ The above example executes in constant space, replacing each frame with a new copy of itself. + @end ignore @@ -3001,6 +3001,7 @@ execution and destroying the iterator frame. @cindex As expression @cindex Cast @cindex Typecast +@cindex Trivial cast Executing an @code{as} expression casts the value on the left-hand side to the type on the right-hand side. @@ -3018,6 +3019,10 @@ fn avg(v: [float]) -> float @{ @} @end example +A cast is a @emph{trivial cast} iff the type of the casted expression and the +target type are identical after replacing all occurences of @code{int}, +@code{uint}, @code{float} with their machine type equivalents of the +target architecture in both types. @node Ref.Expr.Fail @subsection Ref.Expr.Fail From 331ca40fefbf046357ebfd3f888708e4301a2485 Mon Sep 17 00:00:00 2001 From: Stefan Plantikow Date: Fri, 2 Dec 2011 13:57:34 +0100 Subject: [PATCH 5/5] const_check: trans: added support for trivial casts Part of #1215 --- src/comp/middle/check_const.rs | 1 + src/comp/middle/trans.rs | 10 ++++++++++ src/test/run-pass/triv-cast-const.rs | 15 +++++++++++++++ 3 files changed, 26 insertions(+) create mode 100644 src/test/run-pass/triv-cast-const.rs diff --git a/src/comp/middle/check_const.rs b/src/comp/middle/check_const.rs index d9e96b0cb7366..a7b3c388d59e9 100644 --- a/src/comp/middle/check_const.rs +++ b/src/comp/middle/check_const.rs @@ -25,6 +25,7 @@ fn check_item(tcx: ty::ctxt, it: @item, &&s: (), v: visit::vt<()>) { fn check_const_expr(tcx: ty::ctxt, ex: @expr, &&s: (), v: visit::vt<()>) { visit::visit_expr(ex, s, v); alt ex.node { + expr_cast(_, _) { } expr_lit(_) { } expr_binary(_, _, _) { /* subexps covered by visit */ } expr_unary(u, _) { diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index ae09250b2e5f9..6a70d9e109deb 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -5184,6 +5184,16 @@ fn trans_tag_variant(cx: @local_ctxt, tag_id: ast::node_id, // that does so later on? fn trans_const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef { alt e.node { + ast::expr_cast(e1, _) { + alt ccx_tcx(cx).cast_map.find(e.id) { + some(ty::triv_cast.) { trans_const_expr(cx, e1) } + _ { + cx.sess.span_err(e.span, + "non-trivial cast in constant expression"); + fail; + } + } + } ast::expr_lit(lit) { ret trans_crate_lit(cx, *lit); } ast::expr_binary(b, e1, e2) { let te1 = trans_const_expr(cx, e1); diff --git a/src/test/run-pass/triv-cast-const.rs b/src/test/run-pass/triv-cast-const.rs new file mode 100644 index 0000000000000..59d7d618d2313 --- /dev/null +++ b/src/test/run-pass/triv-cast-const.rs @@ -0,0 +1,15 @@ +use std; + +import std::ctypes::*; + +// This will be more interesting once there is support +// for consts that refer to other consts, i.e. math_f64::consts::pi as m_float +#[cfg(target_arch="x86")] +const foo: m_int = 0i32 as m_int; + +#[cfg(target_arch="x86_64")] +const foo: m_int = 0i64 as m_int; + +fn main() { + assert foo == 0 as m_int; +} \ No newline at end of file