Fix a bunch of bugs
* segfault due to not copying drop flag when coercing * fat pointer casts * segfault due to not checking drop flag properly * debuginfo for DST smart pointers * unreachable code in drop glue
This commit is contained in:
parent
7d953538d1
commit
03d4d5f80e
10 changed files with 114 additions and 54 deletions
|
@ -544,7 +544,8 @@ impl<T: ?Sized> Drop for Rc<T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr = *self._ptr;
|
let ptr = *self._ptr;
|
||||||
if !(*(&ptr as *const _ as *const *const ())).is_null() {
|
if !(*(&ptr as *const _ as *const *const ())).is_null() &&
|
||||||
|
ptr as usize != mem::POST_DROP_USIZE {
|
||||||
self.dec_strong();
|
self.dec_strong();
|
||||||
if self.strong() == 0 {
|
if self.strong() == 0 {
|
||||||
// destroy the contained object
|
// destroy the contained object
|
||||||
|
@ -1010,7 +1011,8 @@ impl<T: ?Sized> Drop for Weak<T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr = *self._ptr;
|
let ptr = *self._ptr;
|
||||||
if !(*(&ptr as *const _ as *const *const ())).is_null() {
|
if !(*(&ptr as *const _ as *const *const ())).is_null() &&
|
||||||
|
ptr as usize != mem::POST_DROP_USIZE {
|
||||||
self.dec_weak();
|
self.dec_weak();
|
||||||
// the weak count starts at 1, and will only go to zero if all
|
// the weak count starts at 1, and will only go to zero if all
|
||||||
// the strong pointers have disappeared.
|
// the strong pointers have disappeared.
|
||||||
|
|
|
@ -5606,8 +5606,7 @@ impl DtorKind {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If struct_id names a struct with a dtor, return Some(the dtor's id).
|
/* If struct_id names a struct with a dtor. */
|
||||||
Otherwise return none. */
|
|
||||||
pub fn ty_dtor(cx: &ctxt, struct_id: DefId) -> DtorKind {
|
pub fn ty_dtor(cx: &ctxt, struct_id: DefId) -> DtorKind {
|
||||||
match cx.destructor_for_type.borrow().get(&struct_id) {
|
match cx.destructor_for_type.borrow().get(&struct_id) {
|
||||||
Some(&method_def_id) => {
|
Some(&method_def_id) => {
|
||||||
|
|
|
@ -141,7 +141,8 @@ pub fn represent_node<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||||
|
|
||||||
/// Decides how to represent a given type.
|
/// Decides how to represent a given type.
|
||||||
pub fn represent_type<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
pub fn represent_type<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||||
t: Ty<'tcx>) -> Rc<Repr<'tcx>> {
|
t: Ty<'tcx>)
|
||||||
|
-> Rc<Repr<'tcx>> {
|
||||||
debug!("Representing: {}", ty_to_string(cx.tcx(), t));
|
debug!("Representing: {}", ty_to_string(cx.tcx(), t));
|
||||||
match cx.adt_reprs().borrow().get(&t) {
|
match cx.adt_reprs().borrow().get(&t) {
|
||||||
Some(repr) => return repr.clone(),
|
Some(repr) => return repr.clone(),
|
||||||
|
@ -216,7 +217,9 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||||
}).collect::<Vec<_>>();
|
}).collect::<Vec<_>>();
|
||||||
let packed = ty::lookup_packed(cx.tcx(), def_id);
|
let packed = ty::lookup_packed(cx.tcx(), def_id);
|
||||||
let dtor = ty::ty_dtor(cx.tcx(), def_id).has_drop_flag();
|
let dtor = ty::ty_dtor(cx.tcx(), def_id).has_drop_flag();
|
||||||
if dtor { ftys.push(cx.tcx().dtor_type()); }
|
if dtor {
|
||||||
|
ftys.push(cx.tcx().dtor_type());
|
||||||
|
}
|
||||||
|
|
||||||
Univariant(mk_struct(cx, &ftys[..], packed, t), dtor_to_init_u8(dtor))
|
Univariant(mk_struct(cx, &ftys[..], packed, t), dtor_to_init_u8(dtor))
|
||||||
}
|
}
|
||||||
|
@ -517,8 +520,7 @@ fn mk_struct<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||||
-> Struct<'tcx> {
|
-> Struct<'tcx> {
|
||||||
let sized = tys.iter().all(|&ty| type_is_sized(cx.tcx(), ty));
|
let sized = tys.iter().all(|&ty| type_is_sized(cx.tcx(), ty));
|
||||||
let lltys : Vec<Type> = if sized {
|
let lltys : Vec<Type> = if sized {
|
||||||
tys.iter()
|
tys.iter().map(|&ty| type_of::sizing_type_of(cx, ty)).collect()
|
||||||
.map(|&ty| type_of::sizing_type_of(cx, ty)).collect()
|
|
||||||
} else {
|
} else {
|
||||||
tys.iter().filter(|&ty| type_is_sized(cx.tcx(), *ty))
|
tys.iter().filter(|&ty| type_is_sized(cx.tcx(), *ty))
|
||||||
.map(|&ty| type_of::sizing_type_of(cx, ty)).collect()
|
.map(|&ty| type_of::sizing_type_of(cx, ty)).collect()
|
||||||
|
@ -1060,7 +1062,9 @@ pub fn fold_variants<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access the struct drop flag, if present.
|
/// Access the struct drop flag, if present.
|
||||||
pub fn trans_drop_flag_ptr<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>, val: ValueRef)
|
pub fn trans_drop_flag_ptr<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
||||||
|
r: &Repr<'tcx>,
|
||||||
|
val: ValueRef)
|
||||||
-> datum::DatumBlock<'blk, 'tcx, datum::Expr>
|
-> datum::DatumBlock<'blk, 'tcx, datum::Expr>
|
||||||
{
|
{
|
||||||
let tcx = bcx.tcx();
|
let tcx = bcx.tcx();
|
||||||
|
|
|
@ -58,7 +58,7 @@ use middle::check_const;
|
||||||
use middle::def;
|
use middle::def;
|
||||||
use middle::lang_items::CoerceUnsizedTraitLangItem;
|
use middle::lang_items::CoerceUnsizedTraitLangItem;
|
||||||
use middle::mem_categorization::Typer;
|
use middle::mem_categorization::Typer;
|
||||||
use middle::subst::{Subst, Substs, VecPerParamSpace};
|
use middle::subst::{Substs, VecPerParamSpace};
|
||||||
use middle::traits;
|
use middle::traits;
|
||||||
use trans::{_match, adt, asm, base, callee, closure, consts, controlflow};
|
use trans::{_match, adt, asm, base, callee, closure, consts, controlflow};
|
||||||
use trans::base::*;
|
use trans::base::*;
|
||||||
|
@ -476,8 +476,8 @@ fn coerce_unsized<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// This can be extended to enums and tuples in the future.
|
// This can be extended to enums and tuples in the future.
|
||||||
// (&ty::ty_enum(def_id_a, substs_a), &ty::ty_enum(def_id_b, substs_b)) |
|
// (&ty::ty_enum(def_id_a, _), &ty::ty_enum(def_id_b, _)) |
|
||||||
(&ty::ty_struct(def_id_a, substs_a), &ty::ty_struct(def_id_b, substs_b)) => {
|
(&ty::ty_struct(def_id_a, _), &ty::ty_struct(def_id_b, _)) => {
|
||||||
assert_eq!(def_id_a, def_id_b);
|
assert_eq!(def_id_a, def_id_b);
|
||||||
|
|
||||||
// The target is already by-ref because it's to be written to.
|
// The target is already by-ref because it's to be written to.
|
||||||
|
@ -504,35 +504,41 @@ fn coerce_unsized<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||||
};
|
};
|
||||||
|
|
||||||
let repr_source = adt::represent_type(bcx.ccx(), source.ty);
|
let repr_source = adt::represent_type(bcx.ccx(), source.ty);
|
||||||
|
let src_fields = match &*repr_source {
|
||||||
|
&adt::Repr::Univariant(ref s, _) => &s.fields,
|
||||||
|
_ => bcx.sess().span_bug(span,
|
||||||
|
&format!("Non univariant struct? (repr_source: {:?})",
|
||||||
|
repr_source)),
|
||||||
|
};
|
||||||
let repr_target = adt::represent_type(bcx.ccx(), target.ty);
|
let repr_target = adt::represent_type(bcx.ccx(), target.ty);
|
||||||
let fields = ty::lookup_struct_fields(bcx.tcx(), def_id_a);
|
let target_fields = match &*repr_target {
|
||||||
|
&adt::Repr::Univariant(ref s, _) => &s.fields,
|
||||||
|
_ => bcx.sess().span_bug(span,
|
||||||
|
&format!("Non univariant struct? (repr_target: {:?})",
|
||||||
|
repr_target)),
|
||||||
|
};
|
||||||
|
|
||||||
let coerce_index = match kind {
|
let coerce_index = match kind {
|
||||||
ty::CustomCoerceUnsized::Struct(i) => i
|
ty::CustomCoerceUnsized::Struct(i) => i
|
||||||
};
|
};
|
||||||
assert!(coerce_index < fields.len());
|
assert!(coerce_index < src_fields.len() && src_fields.len() == target_fields.len());
|
||||||
|
|
||||||
for (i, field) in fields.iter().enumerate() {
|
let iter = src_fields.iter().zip(target_fields.iter()).enumerate();
|
||||||
|
for (i, (src_ty, target_ty)) in iter {
|
||||||
let ll_source = adt::trans_field_ptr(bcx, &repr_source, source.val, 0, i);
|
let ll_source = adt::trans_field_ptr(bcx, &repr_source, source.val, 0, i);
|
||||||
let ll_target = adt::trans_field_ptr(bcx, &repr_target, target.val, 0, i);
|
let ll_target = adt::trans_field_ptr(bcx, &repr_target, target.val, 0, i);
|
||||||
|
|
||||||
let ty = ty::lookup_field_type_unsubstituted(bcx.tcx(),
|
|
||||||
def_id_a,
|
|
||||||
field.id);
|
|
||||||
let field_source = ty.subst(bcx.tcx(), substs_a);
|
|
||||||
let field_target = ty.subst(bcx.tcx(), substs_b);
|
|
||||||
|
|
||||||
// If this is the field we need to coerce, recurse on it.
|
// If this is the field we need to coerce, recurse on it.
|
||||||
if i == coerce_index {
|
if i == coerce_index {
|
||||||
coerce_unsized(bcx, span,
|
coerce_unsized(bcx, span,
|
||||||
Datum::new(ll_source, field_source,
|
Datum::new(ll_source, src_ty,
|
||||||
Rvalue::new(ByRef)),
|
Rvalue::new(ByRef)),
|
||||||
Datum::new(ll_target, field_target,
|
Datum::new(ll_target, target_ty,
|
||||||
Rvalue::new(ByRef)));
|
Rvalue::new(ByRef)));
|
||||||
} else {
|
} else {
|
||||||
// Otherwise, simply copy the data from the source.
|
// Otherwise, simply copy the data from the source.
|
||||||
assert_eq!(field_source, field_target);
|
assert_eq!(src_ty, target_ty);
|
||||||
memcpy_ty(bcx, ll_target, ll_source, field_source);
|
memcpy_ty(bcx, ll_target, ll_source, src_ty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2013,6 +2019,7 @@ fn float_cast(bcx: Block,
|
||||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||||
pub enum cast_kind {
|
pub enum cast_kind {
|
||||||
cast_pointer,
|
cast_pointer,
|
||||||
|
cast_fat_ptr,
|
||||||
cast_integral,
|
cast_integral,
|
||||||
cast_float,
|
cast_float,
|
||||||
cast_enum,
|
cast_enum,
|
||||||
|
@ -2027,7 +2034,7 @@ pub fn cast_type_kind<'tcx>(tcx: &ty::ctxt<'tcx>, t: Ty<'tcx>) -> cast_kind {
|
||||||
if type_is_sized(tcx, mt.ty) {
|
if type_is_sized(tcx, mt.ty) {
|
||||||
cast_pointer
|
cast_pointer
|
||||||
} else {
|
} else {
|
||||||
cast_other
|
cast_fat_ptr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::ty_bare_fn(..) => cast_pointer,
|
ty::ty_bare_fn(..) => cast_pointer,
|
||||||
|
@ -2103,10 +2110,18 @@ fn trans_imm_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||||
let llexpr = datum.to_llscalarish(bcx);
|
let llexpr = datum.to_llscalarish(bcx);
|
||||||
PtrToInt(bcx, llexpr, ll_t_out)
|
PtrToInt(bcx, llexpr, ll_t_out)
|
||||||
}
|
}
|
||||||
|
(cast_fat_ptr, cast_integral) => {
|
||||||
|
let data_ptr = Load(bcx, get_dataptr(bcx, datum.val));
|
||||||
|
PtrToInt(bcx, data_ptr, ll_t_out)
|
||||||
|
}
|
||||||
(cast_pointer, cast_pointer) => {
|
(cast_pointer, cast_pointer) => {
|
||||||
let llexpr = datum.to_llscalarish(bcx);
|
let llexpr = datum.to_llscalarish(bcx);
|
||||||
PointerCast(bcx, llexpr, ll_t_out)
|
PointerCast(bcx, llexpr, ll_t_out)
|
||||||
}
|
}
|
||||||
|
(cast_fat_ptr, cast_pointer) => {
|
||||||
|
let data_ptr = Load(bcx, get_dataptr(bcx, datum.val));
|
||||||
|
PointerCast(bcx, data_ptr, ll_t_out)
|
||||||
|
}
|
||||||
(cast_enum, cast_integral) |
|
(cast_enum, cast_integral) |
|
||||||
(cast_enum, cast_float) => {
|
(cast_enum, cast_float) => {
|
||||||
let mut bcx = bcx;
|
let mut bcx = bcx;
|
||||||
|
|
|
@ -278,18 +278,14 @@ fn get_drop_glue_core<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||||
|
|
||||||
fn trans_struct_drop_flag<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
fn trans_struct_drop_flag<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
||||||
t: Ty<'tcx>,
|
t: Ty<'tcx>,
|
||||||
v0: ValueRef,
|
struct_data: ValueRef,
|
||||||
dtor_did: ast::DefId,
|
dtor_did: ast::DefId,
|
||||||
class_did: ast::DefId,
|
class_did: ast::DefId,
|
||||||
substs: &subst::Substs<'tcx>)
|
substs: &subst::Substs<'tcx>)
|
||||||
-> Block<'blk, 'tcx> {
|
-> Block<'blk, 'tcx> {
|
||||||
|
assert!(type_is_sized(bcx.tcx(), t), "Precondition: caller must ensure t is sized");
|
||||||
|
|
||||||
let repr = adt::represent_type(bcx.ccx(), t);
|
let repr = adt::represent_type(bcx.ccx(), t);
|
||||||
let struct_data = if type_is_sized(bcx.tcx(), t) {
|
|
||||||
v0
|
|
||||||
} else {
|
|
||||||
let llval = GEPi(bcx, v0, &[0, abi::FAT_PTR_ADDR]);
|
|
||||||
Load(bcx, llval)
|
|
||||||
};
|
|
||||||
let drop_flag = unpack_datum!(bcx, adt::trans_drop_flag_ptr(bcx, &*repr, struct_data));
|
let drop_flag = unpack_datum!(bcx, adt::trans_drop_flag_ptr(bcx, &*repr, struct_data));
|
||||||
let loaded = load_ty(bcx, drop_flag.val, bcx.tcx().dtor_type());
|
let loaded = load_ty(bcx, drop_flag.val, bcx.tcx().dtor_type());
|
||||||
let drop_flag_llty = type_of(bcx.fcx.ccx, bcx.tcx().dtor_type());
|
let drop_flag_llty = type_of(bcx.fcx.ccx, bcx.tcx().dtor_type());
|
||||||
|
@ -313,9 +309,8 @@ fn trans_struct_drop_flag<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
||||||
|
|
||||||
let drop_flag_dtor_needed = ICmp(bcx, llvm::IntEQ, loaded, init_val, DebugLoc::None);
|
let drop_flag_dtor_needed = ICmp(bcx, llvm::IntEQ, loaded, init_val, DebugLoc::None);
|
||||||
with_cond(bcx, drop_flag_dtor_needed, |cx| {
|
with_cond(bcx, drop_flag_dtor_needed, |cx| {
|
||||||
trans_struct_drop(cx, t, v0, dtor_did, class_did, substs)
|
trans_struct_drop(cx, t, struct_data, dtor_did, class_did, substs)
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_res_dtor<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
pub fn get_res_dtor<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||||
|
|
|
@ -101,7 +101,8 @@ pub fn llalign_of_min(cx: &CrateContext, ty: Type) -> llalign {
|
||||||
|
|
||||||
pub fn llelement_offset(cx: &CrateContext, struct_ty: Type, element: usize) -> u64 {
|
pub fn llelement_offset(cx: &CrateContext, struct_ty: Type, element: usize) -> u64 {
|
||||||
unsafe {
|
unsafe {
|
||||||
return llvm::LLVMOffsetOfElement(cx.td().lltd, struct_ty.to_ref(),
|
return llvm::LLVMOffsetOfElement(cx.td().lltd,
|
||||||
|
struct_ty.to_ref(),
|
||||||
element as u32);
|
element as u32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,6 +99,7 @@ pub fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) {
|
||||||
let t_1_is_bare_fn = ty::type_is_bare_fn(t_1);
|
let t_1_is_bare_fn = ty::type_is_bare_fn(t_1);
|
||||||
let t_1_is_float = ty::type_is_floating_point(t_1);
|
let t_1_is_float = ty::type_is_floating_point(t_1);
|
||||||
let t_1_is_c_enum = ty::type_is_c_like_enum(fcx.tcx(), t_1);
|
let t_1_is_c_enum = ty::type_is_c_like_enum(fcx.tcx(), t_1);
|
||||||
|
let t1_is_fat_ptr = fcx.type_is_fat_ptr(t_1, span);
|
||||||
|
|
||||||
// casts to scalars other than `char` and `bare fn` are trivial
|
// casts to scalars other than `char` and `bare fn` are trivial
|
||||||
let t_1_is_trivial = t_1_is_scalar && !t_1_is_char && !t_1_is_bare_fn;
|
let t_1_is_trivial = t_1_is_scalar && !t_1_is_char && !t_1_is_bare_fn;
|
||||||
|
@ -170,18 +171,16 @@ pub fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) {
|
||||||
demand::coerce(fcx, e.span, t_1, &e);
|
demand::coerce(fcx, e.span, t_1, &e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if fcx.type_is_fat_ptr(t_e, span) != fcx.type_is_fat_ptr(t_1, span) {
|
} else if t1_is_fat_ptr {
|
||||||
|
// FIXME This should be allowed where the lefthandside is also a fat
|
||||||
|
// pointer and is the same kind of fat pointer, i.e., array to array,
|
||||||
|
// trait object to trait object.
|
||||||
fcx.type_error_message(span, |actual| {
|
fcx.type_error_message(span, |actual| {
|
||||||
format!("illegal cast; cast to or from fat pointer: `{}` as `{}` \
|
format!("cast to fat pointer: `{}` as `{}`",
|
||||||
involving incompatible type.",
|
actual,
|
||||||
actual, fcx.infcx().ty_to_string(t_1))
|
fcx.infcx().ty_to_string(t_1))
|
||||||
}, t_e, None);
|
}, t_e, None);
|
||||||
} else if !(t_e_is_scalar && t_1_is_trivial) {
|
} else if !(t_e_is_scalar && t_1_is_trivial) {
|
||||||
/*
|
|
||||||
If more type combinations should be supported than are
|
|
||||||
supported here, then file an enhancement issue and
|
|
||||||
record the issue number in this comment.
|
|
||||||
*/
|
|
||||||
fcx.type_error_message(span, |actual| {
|
fcx.type_error_message(span, |actual| {
|
||||||
format!("non-scalar cast: `{}` as `{}`",
|
format!("non-scalar cast: `{}` as `{}`",
|
||||||
actual,
|
actual,
|
||||||
|
|
|
@ -15,17 +15,13 @@ pub trait Trait {}
|
||||||
fn main() {
|
fn main() {
|
||||||
let a: &[i32] = &[1, 2, 3];
|
let a: &[i32] = &[1, 2, 3];
|
||||||
let b: Box<[i32]> = Box::new([1, 2, 3]);
|
let b: Box<[i32]> = Box::new([1, 2, 3]);
|
||||||
let p = a as *const [i32];
|
|
||||||
let q = a.as_ptr();
|
|
||||||
|
|
||||||
a as usize; //~ ERROR illegal cast
|
a as usize; //~ ERROR illegal cast
|
||||||
b as usize; //~ ERROR illegal cast
|
b as usize; //~ ERROR illegal cast
|
||||||
p as usize; //~ ERROR illegal cast
|
|
||||||
|
|
||||||
// #22955
|
let a: usize = 42;
|
||||||
q as *const [i32]; //~ ERROR illegal cast
|
a as *const [i32]; //~ ERROR cast to fat pointer: `usize` as `*const [i32]`
|
||||||
|
|
||||||
// #21397
|
let a: *const u8 = &42;
|
||||||
let t: *mut (Trait + 'static) = 0 as *mut _; //~ ERROR illegal cast
|
a as *const [u8]; //~ ERROR cast to fat pointer: `*const u8` as `*const [u8]`
|
||||||
let mut fail: *const str = 0 as *const str; //~ ERROR illegal cast
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,5 +9,5 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
0 as &std::any::Any; //~ ERROR illegal cast
|
0 as &std::any::Any; //~ ERROR cast to fat pointer: `i32` as `&core::any::Any`
|
||||||
}
|
}
|
||||||
|
|
49
src/test/run-pass/fat-ptr-cast.rs
Normal file
49
src/test/run-pass/fat-ptr-cast.rs
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
// Copyright 2015 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 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![feature(core)]
|
||||||
|
|
||||||
|
use std::mem;
|
||||||
|
use std::raw;
|
||||||
|
|
||||||
|
trait Foo {
|
||||||
|
fn foo(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Bar;
|
||||||
|
|
||||||
|
impl Foo for Bar {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Test we can turn a fat pointer to array back into a thin pointer.
|
||||||
|
let a: *const [i32] = &[1, 2, 3];
|
||||||
|
let b = a as *const [i32; 2];
|
||||||
|
unsafe {
|
||||||
|
assert!(*b == [1, 2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test conversion to an address (usize).
|
||||||
|
let a: *const [i32; 3] = &[1, 2, 3];
|
||||||
|
let b: *const [i32] = a;
|
||||||
|
assert!(a as usize == b as usize);
|
||||||
|
|
||||||
|
// And conversion to a void pointer/address for trait objects too.
|
||||||
|
let a: *mut Foo = &mut Bar;
|
||||||
|
let b = a as *mut ();
|
||||||
|
let c = a as usize;
|
||||||
|
|
||||||
|
let d = unsafe {
|
||||||
|
let r: raw::TraitObject = mem::transmute(a);
|
||||||
|
r.data
|
||||||
|
};
|
||||||
|
|
||||||
|
assert!(b == d);
|
||||||
|
assert!(c == d as usize);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue