From 792181084244abc7ab361fd1db809c4217148304 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Fri, 1 Mar 2013 18:40:23 +0900 Subject: [PATCH] Allow constant c-like enum to integral/float cast --- src/librustc/middle/trans/consts.rs | 35 +++++++++++++++++++++++++++-- src/librustc/middle/ty.rs | 2 +- src/test/run-pass/enum-cast.rs | 31 +++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 src/test/run-pass/enum-cast.rs diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index 36cda3dfbe9..064dd2d0b06 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -10,7 +10,7 @@ use core::prelude::*; -use lib::llvm::{llvm, ValueRef, True, TypeRef, False}; +use lib::llvm::{llvm, ValueRef, TypeRef, Bool, True, False}; use middle::const_eval; use middle::trans::base; use middle::trans::base::get_insn_ctxt; @@ -304,7 +304,7 @@ pub fn const_expr(cx: @CrateContext, e: @ast::expr) -> ValueRef { expr::cast_type_kind(ety)) { (expr::cast_integral, expr::cast_integral) => { - let s = if ty::type_is_signed(basety) { True } else { False }; + let s = ty::type_is_signed(basety) as Bool; llvm::LLVMConstIntCast(v, llty, s) } (expr::cast_integral, expr::cast_float) => { @@ -321,6 +321,37 @@ pub fn const_expr(cx: @CrateContext, e: @ast::expr) -> ValueRef { if ty::type_is_signed(ety) { llvm::LLVMConstFPToSI(v, llty) } else { llvm::LLVMConstFPToUI(v, llty) } } + (expr::cast_enum, expr::cast_integral) | + (expr::cast_enum, expr::cast_float) => { + let def = ty::resolve_expr(cx.tcx, base); + let (enum_did, variant_did) = match def { + ast::def_variant(enum_did, variant_did) => { + (enum_did, variant_did) + } + _ => cx.sess.bug(~"enum cast source is not enum") + }; + // Note that we know this is a C-like (nullary) enum + // variant or we wouldn't have gotten here + let variants = ty::enum_variants(cx.tcx, enum_did); + let iv = if variants.len() == 1 { + // Univariants don't have a discriminant field, + // because there's only one value it could have: + C_integral(T_i64(), + variants[0].disr_val as u64, True) + } else { + base::get_discrim_val(cx, e.span, enum_did, variant_did) + }; + let ety_cast = expr::cast_type_kind(ety); + match ety_cast { + expr::cast_integral => { + let s = ty::type_is_signed(ety) as Bool; + llvm::LLVMConstIntCast(iv, llty, s) + } + expr::cast_float => llvm::LLVMConstUIToFP(iv, llty), + _ => cx.sess.bug(~"enum cast destination is not \ + integral or float") + } + } _ => { cx.sess.impossible_case(e.span, ~"bad combination of types for cast") diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 8bca7f42b48..868f885dfcd 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -3017,7 +3017,7 @@ pub fn method_call_bounds(tcx: ctxt, method_map: typeck::method_map, } } -fn resolve_expr(tcx: ctxt, expr: @ast::expr) -> ast::def { +pub fn resolve_expr(tcx: ctxt, expr: @ast::expr) -> ast::def { match tcx.def_map.find(&expr.id) { Some(def) => def, None => { diff --git a/src/test/run-pass/enum-cast.rs b/src/test/run-pass/enum-cast.rs new file mode 100644 index 00000000000..eed5645776b --- /dev/null +++ b/src/test/run-pass/enum-cast.rs @@ -0,0 +1,31 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum A { A1, A2 } +enum B { B1=0, B2=2 } + +fn main () { + const c1: int = A2 as int; + const c2: int = B2 as int; + const c3: float = A2 as float; + const c4: float = B2 as float; + let a1 = A2 as int; + let a2 = B2 as int; + let a3 = A2 as float; + let a4 = B2 as float; + assert(c1 == 1); + assert(c2 == 2); + assert(c3 == 1.0); + assert(c4 == 2.0); + assert(a1 == 1); + assert(a2 == 2); + assert(a3 == 1.0); + assert(a4 == 2.0); +}