Skip to content

Commit 4c148a5

Browse files
committed
librustc: Implement reinterpret_cast in terms of transmute.
1 parent 71a2ee0 commit 4c148a5

File tree

4 files changed

+84
-1
lines changed

4 files changed

+84
-1
lines changed

src/libcore/cast.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,48 @@
1010

1111
//! Unsafe casting functions
1212
13+
use sys;
14+
use unstable;
15+
1316
pub mod rusti {
1417
#[abi = "rust-intrinsic"]
1518
#[link_name = "rusti"]
1619
pub extern "rust-intrinsic" {
1720
fn forget<T>(+x: T);
21+
22+
#[cfg(stage0)]
1823
fn reinterpret_cast<T, U>(&&e: T) -> U;
24+
25+
#[cfg(stage1)]
26+
#[cfg(stage2)]
27+
#[cfg(stage3)]
28+
fn transmute<T,U>(e: T) -> U;
1929
}
2030
}
2131

2232
/// Casts the value at `src` to U. The two types must have the same length.
2333
#[inline(always)]
34+
#[cfg(stage0)]
2435
pub unsafe fn reinterpret_cast<T, U>(src: &T) -> U {
2536
rusti::reinterpret_cast(*src)
2637
}
2738

39+
#[inline(always)]
40+
#[cfg(stage1)]
41+
#[cfg(stage2)]
42+
#[cfg(stage3)]
43+
pub unsafe fn reinterpret_cast<T, U>(src: &T) -> U {
44+
let mut dest: U = unstable::intrinsics::init();
45+
{
46+
let dest_ptr: *mut u8 = rusti::transmute(&mut dest);
47+
let src_ptr: *u8 = rusti::transmute(src);
48+
unstable::intrinsics::memmove64(dest_ptr,
49+
src_ptr,
50+
sys::size_of::<U>() as u64);
51+
}
52+
dest
53+
}
54+
2855
/**
2956
* Move a thing into the void
3057
*
@@ -53,12 +80,21 @@ pub unsafe fn bump_box_refcount<T>(t: @T) { forget(t); }
5380
* assert!(transmute("L") == ~[76u8, 0u8]);
5481
*/
5582
#[inline(always)]
83+
#[cfg(stage0)]
5684
pub unsafe fn transmute<L, G>(thing: L) -> G {
5785
let newthing: G = reinterpret_cast(&thing);
5886
forget(thing);
5987
newthing
6088
}
6189

90+
#[inline(always)]
91+
#[cfg(stage1)]
92+
#[cfg(stage2)]
93+
#[cfg(stage3)]
94+
pub unsafe fn transmute<L, G>(thing: L) -> G {
95+
rusti::transmute(thing)
96+
}
97+
6298
/// Coerce an immutable reference to be mutable.
6399
#[inline(always)]
64100
pub unsafe fn transmute_mut<'a,T>(ptr: &'a T) -> &'a mut T { transmute(ptr) }

src/librustc/middle/trans/foreign.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -747,6 +747,52 @@ pub fn trans_intrinsic(ccx: @CrateContext,
747747
call_memcpy(bcx, llretptr, llcast, llsize_of(ccx, lltp_ty));
748748
}
749749
}
750+
~"transmute" => {
751+
let (in_type, out_type) = (substs.tys[0], substs.tys[1]);
752+
let llintype = type_of::type_of(ccx, in_type);
753+
let llouttype = type_of::type_of(ccx, out_type);
754+
755+
let in_type_size = machine::llbitsize_of_real(ccx, llintype);
756+
let out_type_size = machine::llbitsize_of_real(ccx, llouttype);
757+
if in_type_size != out_type_size {
758+
let sp = match *ccx.tcx.items.get(&ref_id.get()) {
759+
ast_map::node_expr(e) => e.span,
760+
_ => fail!(~"transmute has non-expr arg"),
761+
};
762+
let pluralize = |n| if 1u == n { "" } else { "s" };
763+
ccx.sess.span_err(sp,
764+
fmt!("transmute called on types with \
765+
different sizes: %s (%u bit%s) to \
766+
%s (%u bit%s)",
767+
ty_to_str(ccx.tcx, in_type),
768+
in_type_size,
769+
pluralize(in_type_size),
770+
ty_to_str(ccx.tcx, out_type),
771+
out_type_size,
772+
pluralize(out_type_size)));
773+
}
774+
775+
if !ty::type_is_nil(out_type) {
776+
// NB: Do not use a Load and Store here. This causes massive
777+
// code bloat when `transmute` is used on large structural
778+
// types.
779+
let lldestptr = fcx.llretptr.get();
780+
let lldestptr = PointerCast(bcx, lldestptr, T_ptr(T_i8()));
781+
782+
let llsrcval = get_param(decl, first_real_arg);
783+
let llsrcptr = if ty::type_is_immediate(in_type) {
784+
let llsrcptr = alloca(bcx, llintype);
785+
Store(bcx, llsrcval, llsrcptr);
786+
llsrcptr
787+
} else {
788+
llsrcval
789+
};
790+
let llsrcptr = PointerCast(bcx, llsrcptr, T_ptr(T_i8()));
791+
792+
let llsize = llsize_of(ccx, llintype);
793+
call_memcpy(bcx, lldestptr, llsrcptr, llsize);
794+
}
795+
}
750796
~"needs_drop" => {
751797
let tp_ty = substs.tys[0];
752798
Store(bcx,

src/librustc/middle/trans/type_use.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ pub fn type_uses_for(ccx: @CrateContext, fn_id: def_id, n_tps: uint)
125125
if abi.is_intrinsic() {
126126
let flags = match *cx.ccx.sess.str_of(i.ident) {
127127
~"size_of" | ~"pref_align_of" | ~"min_align_of" |
128-
~"init" | ~"reinterpret_cast" |
128+
~"init" | ~"reinterpret_cast" | ~"transmute" |
129129
~"move_val" | ~"move_val_init" => use_repr,
130130

131131
~"get_tydesc" | ~"needs_drop" => use_tydesc,

src/librustc/middle/typeck/check/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3447,6 +3447,7 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) {
34473447
ty::mk_nil()),
34483448
~"reinterpret_cast" => (2u, ~[arg(ast::by_ref, param(ccx, 0u))],
34493449
param(ccx, 1u)),
3450+
~"transmute" => (2, ~[arg(ast::by_copy, param(ccx, 0))], param(ccx, 1)),
34503451
~"move_val" | ~"move_val_init" => {
34513452
(1u, ~[arg(ast::by_copy,
34523453
ty::mk_mut_rptr(tcx, ty::re_bound(ty::br_anon(0)),

0 commit comments

Comments
 (0)