librustc: Implement reinterpret_cast
in terms of transmute
.
This commit is contained in:
parent
b0522a497c
commit
b6277f8140
4 changed files with 84 additions and 1 deletions
|
@ -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) }
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)),
|
||||
|
|
Loading…
Reference in a new issue