librustc: Implement reinterpret_cast in terms of transmute.

This commit is contained in:
Patrick Walton 2013-04-22 16:22:36 -07:00
parent b0522a497c
commit b6277f8140
4 changed files with 84 additions and 1 deletions

View file

@ -10,21 +10,48 @@
//! Unsafe casting functions
use sys;
use unstable;
pub mod rusti {
#[abi = "rust-intrinsic"]
#[link_name = "rusti"]
pub extern "rust-intrinsic" {
fn forget<T>(+x: T);
#[cfg(stage0)]
fn reinterpret_cast<T, U>(&&e: T) -> U;
#[cfg(stage1)]
#[cfg(stage2)]
#[cfg(stage3)]
fn transmute<T,U>(e: T) -> U;
}
}
/// Casts the value at `src` to U. The two types must have the same length.
#[inline(always)]
#[cfg(stage0)]
pub unsafe fn reinterpret_cast<T, U>(src: &T) -> U {
rusti::reinterpret_cast(*src)
}
#[inline(always)]
#[cfg(stage1)]
#[cfg(stage2)]
#[cfg(stage3)]
pub unsafe fn reinterpret_cast<T, U>(src: &T) -> U {
let mut dest: U = unstable::intrinsics::init();
{
let dest_ptr: *mut u8 = rusti::transmute(&mut dest);
let src_ptr: *u8 = rusti::transmute(src);
unstable::intrinsics::memmove64(dest_ptr,
src_ptr,
sys::size_of::<U>() as u64);
}
dest
}
/**
* Move a thing into the void
*
@ -53,12 +80,21 @@ pub unsafe fn bump_box_refcount<T>(t: @T) { forget(t); }
* assert!(transmute("L") == ~[76u8, 0u8]);
*/
#[inline(always)]
#[cfg(stage0)]
pub unsafe fn transmute<L, G>(thing: L) -> G {
let newthing: G = reinterpret_cast(&thing);
forget(thing);
newthing
}
#[inline(always)]
#[cfg(stage1)]
#[cfg(stage2)]
#[cfg(stage3)]
pub unsafe fn transmute<L, G>(thing: L) -> G {
rusti::transmute(thing)
}
/// Coerce an immutable reference to be mutable.
#[inline(always)]
pub unsafe fn transmute_mut<'a,T>(ptr: &'a T) -> &'a mut T { transmute(ptr) }

View file

@ -745,6 +745,52 @@ pub fn trans_intrinsic(ccx: @CrateContext,
call_memcpy(bcx, llretptr, llcast, llsize_of(ccx, lltp_ty));
}
}
~"transmute" => {
let (in_type, out_type) = (substs.tys[0], substs.tys[1]);
let llintype = type_of::type_of(ccx, in_type);
let llouttype = type_of::type_of(ccx, out_type);
let in_type_size = machine::llbitsize_of_real(ccx, llintype);
let out_type_size = machine::llbitsize_of_real(ccx, llouttype);
if in_type_size != out_type_size {
let sp = match *ccx.tcx.items.get(&ref_id.get()) {
ast_map::node_expr(e) => e.span,
_ => fail!(~"transmute has non-expr arg"),
};
let pluralize = |n| if 1u == n { "" } else { "s" };
ccx.sess.span_err(sp,
fmt!("transmute called on types with \
different sizes: %s (%u bit%s) to \
%s (%u bit%s)",
ty_to_str(ccx.tcx, in_type),
in_type_size,
pluralize(in_type_size),
ty_to_str(ccx.tcx, out_type),
out_type_size,
pluralize(out_type_size)));
}
if !ty::type_is_nil(out_type) {
// NB: Do not use a Load and Store here. This causes massive
// code bloat when `transmute` is used on large structural
// types.
let lldestptr = fcx.llretptr.get();
let lldestptr = PointerCast(bcx, lldestptr, T_ptr(T_i8()));
let llsrcval = get_param(decl, first_real_arg);
let llsrcptr = if ty::type_is_immediate(in_type) {
let llsrcptr = alloca(bcx, llintype);
Store(bcx, llsrcval, llsrcptr);
llsrcptr
} else {
llsrcval
};
let llsrcptr = PointerCast(bcx, llsrcptr, T_ptr(T_i8()));
let llsize = llsize_of(ccx, llintype);
call_memcpy(bcx, lldestptr, llsrcptr, llsize);
}
}
~"needs_drop" => {
let tp_ty = substs.tys[0];
Store(bcx,

View file

@ -123,7 +123,7 @@ pub fn type_uses_for(ccx: @CrateContext, fn_id: def_id, n_tps: uint)
if abi.is_intrinsic() {
let flags = match *cx.ccx.sess.str_of(i.ident) {
~"size_of" | ~"pref_align_of" | ~"min_align_of" |
~"init" | ~"reinterpret_cast" |
~"init" | ~"reinterpret_cast" | ~"transmute" |
~"move_val" | ~"move_val_init" => use_repr,
~"get_tydesc" | ~"needs_drop" => use_tydesc,

View file

@ -3441,6 +3441,7 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) {
ty::mk_nil()),
~"reinterpret_cast" => (2u, ~[arg(ast::by_ref, param(ccx, 0u))],
param(ccx, 1u)),
~"transmute" => (2, ~[arg(ast::by_copy, param(ccx, 0))], param(ccx, 1)),
~"move_val" | ~"move_val_init" => {
(1u, ~[arg(ast::by_copy,
ty::mk_mut_rptr(tcx, ty::re_bound(ty::br_anon(0)),