1
Fork 0

Replace many uses of mem::transmute with more specific functions

The replacements are functions that usually use a single `mem::transmute` in
their body and restrict input and output via more concrete types than `T` and
`U`. Worth noting are the `transmute` functions for slices and the `from_utf8*`
family for mutable slices. Additionally, `mem::transmute` was often used for
casting raw pointers, when you can already cast raw pointers just fine with
`as`.
This commit is contained in:
Tobias Bucher 2015-07-24 03:04:55 +02:00
parent febdc3b201
commit 22ec5f4af7
34 changed files with 187 additions and 103 deletions

View file

@ -193,7 +193,7 @@ impl<T> Arc<T> {
weak: atomic::AtomicUsize::new(1), weak: atomic::AtomicUsize::new(1),
data: data, data: data,
}; };
Arc { _ptr: unsafe { NonZero::new(mem::transmute(x)) } } Arc { _ptr: unsafe { NonZero::new(Box::into_raw(x)) } }
} }
} }

View file

@ -152,7 +152,7 @@ unsafe fn destroy_chunk(chunk: &Chunk) {
let fill = chunk.fill.get(); let fill = chunk.fill.get();
while idx < fill { while idx < fill {
let tydesc_data: *const usize = mem::transmute(buf.offset(idx as isize)); let tydesc_data = buf.offset(idx as isize) as *const usize;
let (tydesc, is_done) = un_bitpack_tydesc_ptr(*tydesc_data); let (tydesc, is_done) = un_bitpack_tydesc_ptr(*tydesc_data);
let (size, align) = ((*tydesc).size, (*tydesc).align); let (size, align) = ((*tydesc).size, (*tydesc).align);
@ -305,7 +305,7 @@ impl<'longer_than_self> Arena<'longer_than_self> {
let ptr = ptr as *mut T; let ptr = ptr as *mut T;
// Write in our tydesc along with a bit indicating that it // Write in our tydesc along with a bit indicating that it
// has *not* been initialized yet. // has *not* been initialized yet.
*ty_ptr = mem::transmute(tydesc); *ty_ptr = bitpack_tydesc_ptr(tydesc, false);
// Actually initialize it // Actually initialize it
ptr::write(&mut(*ptr), op()); ptr::write(&mut(*ptr), op());
// Now that we are done, update the tydesc to indicate that // Now that we are done, update the tydesc to indicate that
@ -443,8 +443,7 @@ impl<T> TypedArenaChunk<T> {
fn start(&self) -> *const u8 { fn start(&self) -> *const u8 {
let this: *const TypedArenaChunk<T> = self; let this: *const TypedArenaChunk<T> = self;
unsafe { unsafe {
mem::transmute(round_up(this.offset(1) as usize, round_up(this.offset(1) as usize, mem::align_of::<T>()) as *const u8
mem::align_of::<T>()))
} }
} }
@ -488,7 +487,7 @@ impl<T> TypedArena<T> {
} }
let ptr: &mut T = unsafe { let ptr: &mut T = unsafe {
let ptr: &mut T = mem::transmute(self.ptr.clone()); let ptr: &mut T = &mut *(self.ptr.get() as *mut T);
ptr::write(ptr, object); ptr::write(ptr, object);
self.ptr.set(self.ptr.get().offset(1)); self.ptr.set(self.ptr.get().offset(1));
ptr ptr

View file

@ -25,7 +25,7 @@ use core::iter::Zip;
use core::marker::PhantomData; use core::marker::PhantomData;
use core::ops::{Deref, DerefMut, Index, IndexMut}; use core::ops::{Deref, DerefMut, Index, IndexMut};
use core::ptr::Unique; use core::ptr::Unique;
use core::{slice, mem, ptr, cmp, raw}; use core::{slice, mem, ptr, cmp};
use alloc::heap::{self, EMPTY}; use alloc::heap::{self, EMPTY};
use borrow::Borrow; use borrow::Borrow;
@ -357,7 +357,10 @@ impl<K, V> Node<K, V> {
#[inline] #[inline]
pub fn as_slices_mut<'a>(&'a mut self) -> (&'a mut [K], &'a mut [V]) { pub fn as_slices_mut<'a>(&'a mut self) -> (&'a mut [K], &'a mut [V]) {
unsafe { mem::transmute(self.as_slices()) } unsafe {(
slice::from_raw_parts_mut(*self.keys, self.len()),
slice::from_raw_parts_mut(*self.vals, self.len()),
)}
} }
#[inline] #[inline]
@ -372,10 +375,7 @@ impl<K, V> Node<K, V> {
None => heap::EMPTY as *const Node<K,V>, None => heap::EMPTY as *const Node<K,V>,
Some(ref p) => **p as *const Node<K,V>, Some(ref p) => **p as *const Node<K,V>,
}; };
mem::transmute(raw::Slice { slice::from_raw_parts(data, self.len() + 1)
data: data,
len: self.len() + 1
})
} }
}; };
NodeSlice { NodeSlice {
@ -390,6 +390,7 @@ impl<K, V> Node<K, V> {
#[inline] #[inline]
pub fn as_slices_internal_mut<'b>(&'b mut self) -> MutNodeSlice<'b, K, V> { pub fn as_slices_internal_mut<'b>(&'b mut self) -> MutNodeSlice<'b, K, V> {
// TODO: Bad: This relies on structure layout!
unsafe { mem::transmute(self.as_slices_internal()) } unsafe { mem::transmute(self.as_slices_internal()) }
} }

View file

@ -47,7 +47,6 @@
#![feature(oom)] #![feature(oom)]
#![feature(pattern)] #![feature(pattern)]
#![feature(ptr_as_ref)] #![feature(ptr_as_ref)]
#![feature(raw)]
#![feature(slice_patterns)] #![feature(slice_patterns)]
#![feature(staged_api)] #![feature(staged_api)]
#![feature(step_by)] #![feature(step_by)]

View file

@ -109,6 +109,7 @@ pub use core::slice::{IntSliceExt, SplitMut, ChunksMut, Split};
pub use core::slice::{SplitN, RSplitN, SplitNMut, RSplitNMut}; pub use core::slice::{SplitN, RSplitN, SplitNMut, RSplitNMut};
pub use core::slice::{bytes, mut_ref_slice, ref_slice}; pub use core::slice::{bytes, mut_ref_slice, ref_slice};
pub use core::slice::{from_raw_parts, from_raw_parts_mut}; pub use core::slice::{from_raw_parts, from_raw_parts_mut};
pub use core::slice::{transmute, transmute_mut};
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Basic slice extension methods // Basic slice extension methods

View file

@ -479,6 +479,19 @@ impl str {
core_str::StrExt::as_bytes(self) core_str::StrExt::as_bytes(self)
} }
/// Converts `self` to a mutable byte slice.
///
/// # Unsafety
///
/// The `str` type guarantees that its contents are UTF-8 bytes, which can
/// be violated using this function, leading to memory-unsafeties in other
/// string functions.
#[unstable(feature = "str_as_bytes_mut")]
#[inline(always)]
pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
core_str::StrExt::as_bytes_mut(self)
}
/// Returns a raw pointer to the `&str`'s buffer. /// Returns a raw pointer to the `&str`'s buffer.
/// ///
/// The caller must ensure that the string outlives this pointer, and /// The caller must ensure that the string outlives this pointer, and
@ -504,8 +517,7 @@ impl str {
/// # Unsafety /// # Unsafety
/// ///
/// Caller must check both UTF-8 sequence boundaries and the boundaries /// Caller must check both UTF-8 sequence boundaries and the boundaries
/// of the entire slice as /// of the entire slice as well.
/// well.
/// ///
/// # Examples /// # Examples
/// ///

View file

@ -977,7 +977,7 @@ impl ops::Index<ops::RangeFull> for String {
#[inline] #[inline]
fn index(&self, _index: ops::RangeFull) -> &str { fn index(&self, _index: ops::RangeFull) -> &str {
unsafe { mem::transmute(&*self.vec) } unsafe { str::from_utf8_unchecked(&self.vec) }
} }
} }
@ -1016,7 +1016,7 @@ impl ops::Deref for String {
#[inline] #[inline]
fn deref(&self) -> &str { fn deref(&self) -> &str {
unsafe { mem::transmute(&self.vec[..]) } unsafe { str::from_utf8_unchecked(&self.vec) }
} }
} }
@ -1024,7 +1024,7 @@ impl ops::Deref for String {
impl ops::DerefMut for String { impl ops::DerefMut for String {
#[inline] #[inline]
fn deref_mut(&mut self) -> &mut str { fn deref_mut(&mut self) -> &mut str {
unsafe { mem::transmute(&mut self.vec[..]) } unsafe { mem::transmute(&mut *self.vec) }
} }
} }

View file

@ -1714,7 +1714,7 @@ impl<T> DoubleEndedIterator for IntoIter<T> {
} else { } else {
self.end = self.end.offset(-1); self.end = self.end.offset(-1);
Some(ptr::read(mem::transmute(self.end))) Some(ptr::read(self.end))
} }
} }
} }

View file

@ -146,7 +146,7 @@ impl Any {
let to: TraitObject = transmute(self); let to: TraitObject = transmute(self);
// Extract the data pointer // Extract the data pointer
Some(transmute(to.data)) Some(&*(to.data as *const T))
} }
} else { } else {
None None
@ -164,7 +164,7 @@ impl Any {
let to: TraitObject = transmute(self); let to: TraitObject = transmute(self);
// Extract the data pointer // Extract the data pointer
Some(transmute(to.data)) Some(&mut *(to.data as *const T as *mut T))
} }
} else { } else {
None None

View file

@ -19,6 +19,7 @@
use self::Ordering::*; use self::Ordering::*;
use mem;
use marker::Sized; use marker::Sized;
use option::Option::{self, Some, None}; use option::Option::{self, Some, None};
@ -114,6 +115,10 @@ pub enum Ordering {
} }
impl Ordering { impl Ordering {
unsafe fn from_i8_unchecked(v: i8) -> Ordering {
mem::transmute(v)
}
/// Reverse the `Ordering`. /// Reverse the `Ordering`.
/// ///
/// * `Less` becomes `Greater`. /// * `Less` becomes `Greater`.
@ -155,7 +160,7 @@ impl Ordering {
// //
// NB. it is safe because of the explicit discriminants // NB. it is safe because of the explicit discriminants
// given above. // given above.
::mem::transmute::<_, Ordering>(-(self as i8)) Ordering::from_i8_unchecked(-(self as i8))
} }
} }
} }

View file

@ -90,7 +90,7 @@ pub trait Write {
fn write_char(&mut self, c: char) -> Result { fn write_char(&mut self, c: char) -> Result {
let mut utf_8 = [0u8; 4]; let mut utf_8 = [0u8; 4];
let bytes_written = c.encode_utf8(&mut utf_8).unwrap_or(0); let bytes_written = c.encode_utf8(&mut utf_8).unwrap_or(0);
self.write_str(unsafe { mem::transmute(&utf_8[..bytes_written]) }) self.write_str(unsafe { str::from_utf8_unchecked(&utf_8[..bytes_written]) })
} }
/// Glue for usage of the `write!` macro with implementers of this trait. /// Glue for usage of the `write!` macro with implementers of this trait.
@ -1320,7 +1320,7 @@ impl Display for char {
} else { } else {
let mut utf8 = [0; 4]; let mut utf8 = [0; 4];
let amt = self.encode_utf8(&mut utf8).unwrap_or(0); let amt = self.encode_utf8(&mut utf8).unwrap_or(0);
let s: &str = unsafe { mem::transmute(&utf8[..amt]) }; let s: &str = unsafe { str::from_utf8_unchecked(&utf8[..amt]) };
f.pad(s) f.pad(s)
} }
} }

View file

@ -16,13 +16,13 @@
#![stable(feature = "rust1", since = "1.0.0")] #![stable(feature = "rust1", since = "1.0.0")]
use mem;
use clone::Clone; use clone::Clone;
use intrinsics; use intrinsics;
use ops::Deref; use ops::Deref;
use fmt; use fmt;
use option::Option::{self, Some, None}; use option::Option::{self, Some, None};
use marker::{PhantomData, Send, Sized, Sync}; use marker::{PhantomData, Send, Sized, Sync};
use mem;
use nonzero::NonZero; use nonzero::NonZero;
use cmp::{PartialEq, Eq, Ord, PartialOrd}; use cmp::{PartialEq, Eq, Ord, PartialOrd};
@ -100,7 +100,7 @@ pub unsafe fn swap<T>(x: *mut T, y: *mut T) {
#[inline] #[inline]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn replace<T>(dest: *mut T, mut src: T) -> T { pub unsafe fn replace<T>(dest: *mut T, mut src: T) -> T {
mem::swap(mem::transmute(dest), &mut src); // cannot overlap mem::swap(&mut *dest, &mut src); // cannot overlap
src src
} }
@ -327,15 +327,14 @@ impl<T: ?Sized> Clone for *mut T {
// Equality for extern "C" fn pointers // Equality for extern "C" fn pointers
mod externfnpointers { mod externfnpointers {
use mem;
use cmp::PartialEq; use cmp::PartialEq;
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<_R> PartialEq for extern "C" fn() -> _R { impl<_R> PartialEq for extern "C" fn() -> _R {
#[inline] #[inline]
fn eq(&self, other: &extern "C" fn() -> _R) -> bool { fn eq(&self, other: &extern "C" fn() -> _R) -> bool {
let self_: *const () = unsafe { mem::transmute(*self) }; let self_ = *self as usize;
let other_: *const () = unsafe { mem::transmute(*other) }; let other_ = *other as usize;
self_ == other_ self_ == other_
} }
} }
@ -345,9 +344,9 @@ mod externfnpointers {
impl<_R,$($p),*> PartialEq for extern "C" fn($($p),*) -> _R { impl<_R,$($p),*> PartialEq for extern "C" fn($($p),*) -> _R {
#[inline] #[inline]
fn eq(&self, other: &extern "C" fn($($p),*) -> _R) -> bool { fn eq(&self, other: &extern "C" fn($($p),*) -> _R) -> bool {
let self_: *const () = unsafe { mem::transmute(*self) }; let self_ = *self as usize;
let other_: *const () = unsafe { mem::transmute(*other) }; let other_ = *other as usize;
self_ == other_ self_ == other_
} }
} }

View file

@ -33,7 +33,6 @@
// * The `raw` and `bytes` submodules. // * The `raw` and `bytes` submodules.
// * Boilerplate trait implementations. // * Boilerplate trait implementations.
use mem::transmute;
use clone::Clone; use clone::Clone;
use cmp::{Ordering, PartialEq, PartialOrd, Eq, Ord}; use cmp::{Ordering, PartialEq, PartialOrd, Eq, Ord};
use cmp::Ordering::{Less, Equal, Greater}; use cmp::Ordering::{Less, Equal, Greater};
@ -148,7 +147,7 @@ macro_rules! slice_ref {
// Use a non-null pointer value // Use a non-null pointer value
&mut *(1 as *mut _) &mut *(1 as *mut _)
} else { } else {
transmute(ptr) mem::transmute(ptr)
} }
}}; }};
} }
@ -261,7 +260,7 @@ impl<T> SliceExt for [T] {
#[inline] #[inline]
unsafe fn get_unchecked(&self, index: usize) -> &T { unsafe fn get_unchecked(&self, index: usize) -> &T {
transmute(self.repr().data.offset(index as isize)) &*(self.repr().data.offset(index as isize))
} }
#[inline] #[inline]
@ -430,7 +429,7 @@ impl<T> SliceExt for [T] {
#[inline] #[inline]
unsafe fn get_unchecked_mut(&mut self, index: usize) -> &mut T { unsafe fn get_unchecked_mut(&mut self, index: usize) -> &mut T {
transmute((self.repr().data as *mut T).offset(index as isize)) &mut *(self.repr().data as *mut T).offset(index as isize)
} }
#[inline] #[inline]
@ -547,8 +546,7 @@ impl<T> ops::Index<usize> for [T] {
fn index(&self, index: usize) -> &T { fn index(&self, index: usize) -> &T {
assert!(index < self.len()); assert!(index < self.len());
unsafe { self.get_unchecked(index) }
unsafe { mem::transmute(self.repr().data.offset(index as isize)) }
} }
} }
@ -557,8 +555,7 @@ impl<T> ops::IndexMut<usize> for [T] {
#[inline] #[inline]
fn index_mut(&mut self, index: usize) -> &mut T { fn index_mut(&mut self, index: usize) -> &mut T {
assert!(index < self.len()); assert!(index < self.len());
unsafe { self.get_unchecked_mut(index) }
unsafe { mem::transmute(self.repr().data.offset(index as isize)) }
} }
} }
@ -1427,7 +1424,7 @@ pub fn mut_ref_slice<'a, A>(s: &'a mut A) -> &'a mut [A] {
#[inline] #[inline]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn from_raw_parts<'a, T>(p: *const T, len: usize) -> &'a [T] { pub unsafe fn from_raw_parts<'a, T>(p: *const T, len: usize) -> &'a [T] {
transmute(RawSlice { data: p, len: len }) mem::transmute(RawSlice { data: p, len: len })
} }
/// Performs the same functionality as `from_raw_parts`, except that a mutable /// Performs the same functionality as `from_raw_parts`, except that a mutable
@ -1439,7 +1436,40 @@ pub unsafe fn from_raw_parts<'a, T>(p: *const T, len: usize) -> &'a [T] {
#[inline] #[inline]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn from_raw_parts_mut<'a, T>(p: *mut T, len: usize) -> &'a mut [T] { pub unsafe fn from_raw_parts_mut<'a, T>(p: *mut T, len: usize) -> &'a mut [T] {
transmute(RawSlice { data: p, len: len }) mem::transmute(RawSlice { data: p, len: len })
}
#[inline]
fn check_types<T,U>() {
assert!(mem::size_of::<T>() == mem::size_of::<U>());
assert!(mem::align_of::<T>() % mem::align_of::<U>() == 0)
}
/// Reinterprets a slice of one type as a slice of another type.
///
/// Both types have to have the same size and the type that is converted to
/// must have equal or less restrictive alignment.
///
/// # Panics
///
/// This functions panics if the above preconditions about the types are not
/// met.
#[inline]
#[unstable(feature = "slice_transmute", reason = "recent API addition")]
pub unsafe fn transmute<T,U>(slice: &[T]) -> &[U] {
check_types::<T,U>();
from_raw_parts(slice.as_ptr() as *const U, slice.len())
}
/// Reinterprets a mutable slice of one type as a mutable slice of another
/// type.
///
/// Equivalent of `slice::transmute` for mutable slices.
#[inline]
#[unstable(feature = "slice_transmute", reason = "recent API addition")]
pub unsafe fn transmute_mut<T,U>(slice: &mut [T]) -> &mut [U] {
check_types::<T,U>();
from_raw_parts_mut(slice.as_mut_ptr() as *mut U, slice.len())
} }
// //
@ -1580,9 +1610,9 @@ macro_rules! impl_int_slice {
#[inline] #[inline]
fn as_signed(&self) -> &[$s] { unsafe { transmute(self) } } fn as_signed(&self) -> &[$s] { unsafe { transmute(self) } }
#[inline] #[inline]
fn as_unsigned_mut(&mut self) -> &mut [$u] { unsafe { transmute(self) } } fn as_unsigned_mut(&mut self) -> &mut [$u] { unsafe { transmute_mut(self) } }
#[inline] #[inline]
fn as_signed_mut(&mut self) -> &mut [$s] { unsafe { transmute(self) } } fn as_signed_mut(&mut self) -> &mut [$s] { unsafe { transmute_mut(self) } }
} }
} }
} }

View file

@ -17,7 +17,7 @@
use self::pattern::Pattern; use self::pattern::Pattern;
use self::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher}; use self::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher};
use char::CharExt; use char::{self, CharExt};
use clone::Clone; use clone::Clone;
use cmp::Eq; use cmp::Eq;
use convert::AsRef; use convert::AsRef;
@ -123,13 +123,13 @@ impl Utf8Error {
/// Converts a slice of bytes to a string slice without performing any /// Converts a slice of bytes to a string slice without performing any
/// allocations. /// allocations.
/// ///
/// Once the slice has been validated as utf-8, it is transmuted in-place and /// Once the slice has been validated as UTF-8, it is transmuted in-place and
/// returned as a '&str' instead of a '&[u8]' /// returned as a '&str' instead of a '&[u8]'
/// ///
/// # Failure /// # Failure
/// ///
/// Returns `Err` if the slice is not utf-8 with a description as to why the /// Returns `Err` if the slice is not UTF-8 with a description as to why the
/// provided slice is not utf-8. /// provided slice is not UTF-8.
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { pub fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> {
try!(run_utf8_validation_iterator(&mut v.iter())); try!(run_utf8_validation_iterator(&mut v.iter()));
@ -262,7 +262,7 @@ impl<'a> Iterator for Chars<'a> {
next_code_point(&mut self.iter).map(|ch| { next_code_point(&mut self.iter).map(|ch| {
// str invariant says `ch` is a valid Unicode Scalar Value // str invariant says `ch` is a valid Unicode Scalar Value
unsafe { unsafe {
mem::transmute(ch) char::from_u32_unchecked(ch)
} }
}) })
} }
@ -284,7 +284,7 @@ impl<'a> DoubleEndedIterator for Chars<'a> {
next_code_point_reverse(&mut self.iter).map(|ch| { next_code_point_reverse(&mut self.iter).map(|ch| {
// str invariant says `ch` is a valid Unicode Scalar Value // str invariant says `ch` is a valid Unicode Scalar Value
unsafe { unsafe {
mem::transmute(ch) char::from_u32_unchecked(ch)
} }
}) })
} }
@ -1264,6 +1264,7 @@ pub trait StrExt {
fn char_at(&self, i: usize) -> char; fn char_at(&self, i: usize) -> char;
fn char_at_reverse(&self, i: usize) -> char; fn char_at_reverse(&self, i: usize) -> char;
fn as_bytes<'a>(&'a self) -> &'a [u8]; fn as_bytes<'a>(&'a self) -> &'a [u8];
unsafe fn as_bytes_mut<'a>(&'a mut self) -> &'a mut [u8];
fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize>; fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize>;
fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize> fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize>
where P::Searcher: ReverseSearcher<'a>; where P::Searcher: ReverseSearcher<'a>;
@ -1507,7 +1508,7 @@ impl StrExt for str {
#[inline] #[inline]
fn char_range_at(&self, i: usize) -> CharRange { fn char_range_at(&self, i: usize) -> CharRange {
let (c, n) = char_range_at_raw(self.as_bytes(), i); let (c, n) = char_range_at_raw(self.as_bytes(), i);
CharRange { ch: unsafe { mem::transmute(c) }, next: n } CharRange { ch: unsafe { char::from_u32_unchecked(c) }, next: n }
} }
#[inline] #[inline]
@ -1535,7 +1536,7 @@ impl StrExt for str {
if w > 2 { val = utf8_acc_cont_byte(val, s.as_bytes()[i + 2]); } if w > 2 { val = utf8_acc_cont_byte(val, s.as_bytes()[i + 2]); }
if w > 3 { val = utf8_acc_cont_byte(val, s.as_bytes()[i + 3]); } if w > 3 { val = utf8_acc_cont_byte(val, s.as_bytes()[i + 3]); }
return CharRange {ch: unsafe { mem::transmute(val) }, next: i}; return CharRange {ch: unsafe { char::from_u32_unchecked(val) }, next: i};
} }
return multibyte_char_range_at_reverse(self, prev); return multibyte_char_range_at_reverse(self, prev);
@ -1556,6 +1557,11 @@ impl StrExt for str {
unsafe { mem::transmute(self) } unsafe { mem::transmute(self) }
} }
#[inline]
unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
mem::transmute(self)
}
fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize> { fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize> {
pat.into_searcher(self).next_match().map(|(i, _)| i) pat.into_searcher(self).next_match().map(|(i, _)| i)
} }

View file

@ -10,7 +10,6 @@
mod sip; mod sip;
use std::mem;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::default::Default; use std::default::Default;
@ -72,15 +71,11 @@ fn test_writer_hasher() {
// FIXME (#18248) Add tests for hashing Rc<str> and Rc<[T]> // FIXME (#18248) Add tests for hashing Rc<str> and Rc<[T]>
unsafe { let ptr = 5_usize as *const i32;
let ptr: *const i32 = mem::transmute(5_usize);
assert_eq!(hash(&ptr), 5); assert_eq!(hash(&ptr), 5);
}
unsafe { let ptr = 5_usize as *mut i32;
let ptr: *mut i32 = mem::transmute(5_usize);
assert_eq!(hash(&ptr), 5); assert_eq!(hash(&ptr), 5);
}
} }
struct Custom { hash: u64 } struct Custom { hash: u64 }

View file

@ -9,7 +9,6 @@
// except according to those terms. // except according to those terms.
use core::ptr::*; use core::ptr::*;
use core::mem;
#[test] #[test]
fn test() { fn test() {
@ -20,7 +19,7 @@ fn test() {
}; };
let mut p = Pair {fst: 10, snd: 20}; let mut p = Pair {fst: 10, snd: 20};
let pptr: *mut Pair = &mut p; let pptr: *mut Pair = &mut p;
let iptr: *mut isize = mem::transmute(pptr); let iptr: *mut isize = pptr as *mut isize;
assert_eq!(*iptr, 10); assert_eq!(*iptr, 10);
*iptr = 30; *iptr = 30;
assert_eq!(*iptr, 30); assert_eq!(*iptr, 30);

View file

@ -294,7 +294,7 @@ pub fn log(level: u32, loc: &'static LogLocation, args: fmt::Arguments) {
1 => panic!("cannot log after main thread has exited"), 1 => panic!("cannot log after main thread has exited"),
n => { n => {
let filter = mem::transmute::<_, &String>(n); let filter = mem::transmute::<_, &String>(n);
if !args.to_string().contains(&filter[..]) { if !args.to_string().contains(filter) {
return return
} }
} }

View file

@ -17,9 +17,9 @@ use distributions::{ziggurat, ziggurat_tables, Sample, IndependentSample};
/// A wrapper around an `f64` to generate Exp(1) random numbers. /// A wrapper around an `f64` to generate Exp(1) random numbers.
/// ///
/// See `Exp` for the general exponential distribution.Note that this /// See `Exp` for the general exponential distribution. Note that this has to
// has to be unwrapped before use as an `f64` (using either /// be unwrapped before use as an `f64` (using either `*` or `mem::transmute`
/// `*` or `mem::transmute` is safe). /// is safe).
/// ///
/// Implemented via the ZIGNOR variant[1] of the Ziggurat method. The /// Implemented via the ZIGNOR variant[1] of the Ziggurat method. The
/// exact description in the paper was adjusted to use tables for the /// exact description in the paper was adjusted to use tables for the

View file

@ -25,7 +25,6 @@ use syntax::diagnostic::{Emitter, Handler, Level};
use std::ffi::{CStr, CString}; use std::ffi::{CStr, CString};
use std::fs; use std::fs;
use std::mem;
use std::path::Path; use std::path::Path;
use std::ptr; use std::ptr;
use std::str; use std::str;
@ -375,8 +374,7 @@ unsafe extern "C" fn report_inline_asm<'a, 'b>(cgcx: &'a CodegenContext<'a>,
unsafe extern "C" fn inline_asm_handler(diag: SMDiagnosticRef, unsafe extern "C" fn inline_asm_handler(diag: SMDiagnosticRef,
user: *const c_void, user: *const c_void,
cookie: c_uint) { cookie: c_uint) {
let HandlerFreeVars { cgcx, .. } let HandlerFreeVars { cgcx, .. } = *(user as *const HandlerFreeVars);
= *mem::transmute::<_, *const HandlerFreeVars>(user);
let msg = llvm::build_string(|s| llvm::LLVMWriteSMDiagnosticToString(diag, s)) let msg = llvm::build_string(|s| llvm::LLVMWriteSMDiagnosticToString(diag, s))
.expect("non-UTF8 SMDiagnostic"); .expect("non-UTF8 SMDiagnostic");
@ -385,8 +383,7 @@ unsafe extern "C" fn inline_asm_handler(diag: SMDiagnosticRef,
} }
unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_void) { unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_void) {
let HandlerFreeVars { llcx, cgcx } let HandlerFreeVars { llcx, cgcx } = *(user as *const HandlerFreeVars);
= *mem::transmute::<_, *const HandlerFreeVars>(user);
match llvm::diagnostic::Diagnostic::unpack(info) { match llvm::diagnostic::Diagnostic::unpack(info) {
llvm::diagnostic::InlineAsm(inline) => { llvm::diagnostic::InlineAsm(inline) => {

View file

@ -25,6 +25,7 @@
html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/")] html_root_url = "http://doc.rust-lang.org/nightly/")]
#![cfg_attr(not(stage0), feature(slice_transmute))]
#![feature(box_patterns)] #![feature(box_patterns)]
#![feature(box_syntax)] #![feature(box_syntax)]
#![feature(const_fn)] #![feature(const_fn)]

View file

@ -20,8 +20,11 @@ use util::nodemap::FnvHashMap;
use syntax::ast; use syntax::ast;
use std::ffi::CString; use std::ffi::CString;
#[cfg(stage0)]
use std::mem; use std::mem;
use std::ptr; use std::ptr;
#[cfg(not(stage0))]
use std::slice;
use std::cell::RefCell; use std::cell::RefCell;
use libc::c_uint; use libc::c_uint;
@ -148,18 +151,35 @@ impl Type {
} }
} }
#[cfg(stage0)]
pub fn func(args: &[Type], ret: &Type) -> Type { pub fn func(args: &[Type], ret: &Type) -> Type {
let vec : &[TypeRef] = unsafe { mem::transmute(args) }; let vec : &[TypeRef] = unsafe { mem::transmute(args) };
ty!(llvm::LLVMFunctionType(ret.to_ref(), vec.as_ptr(), ty!(llvm::LLVMFunctionType(ret.to_ref(), vec.as_ptr(),
args.len() as c_uint, False)) args.len() as c_uint, False))
} }
#[cfg(not(stage0))]
pub fn func(args: &[Type], ret: &Type) -> Type {
let vec: &[TypeRef] = unsafe { slice::transmute(args) };
ty!(llvm::LLVMFunctionType(ret.to_ref(), vec.as_ptr(),
args.len() as c_uint, False))
}
#[cfg(stage0)]
pub fn variadic_func(args: &[Type], ret: &Type) -> Type { pub fn variadic_func(args: &[Type], ret: &Type) -> Type {
let vec : &[TypeRef] = unsafe { mem::transmute(args) }; let vec : &[TypeRef] = unsafe { mem::transmute(args) };
ty!(llvm::LLVMFunctionType(ret.to_ref(), vec.as_ptr(), ty!(llvm::LLVMFunctionType(ret.to_ref(), vec.as_ptr(),
args.len() as c_uint, True)) args.len() as c_uint, True))
} }
#[cfg(not(stage0))]
pub fn variadic_func(args: &[Type], ret: &Type) -> Type {
let vec: &[TypeRef] = unsafe { slice::transmute(args) };
ty!(llvm::LLVMFunctionType(ret.to_ref(), vec.as_ptr(),
args.len() as c_uint, True))
}
#[cfg(stage0)]
pub fn struct_(ccx: &CrateContext, els: &[Type], packed: bool) -> Type { pub fn struct_(ccx: &CrateContext, els: &[Type], packed: bool) -> Type {
let els : &[TypeRef] = unsafe { mem::transmute(els) }; let els : &[TypeRef] = unsafe { mem::transmute(els) };
ty!(llvm::LLVMStructTypeInContext(ccx.llcx(), els.as_ptr(), ty!(llvm::LLVMStructTypeInContext(ccx.llcx(), els.as_ptr(),
@ -167,6 +187,14 @@ impl Type {
packed as Bool)) packed as Bool))
} }
#[cfg(not(stage0))]
pub fn struct_(ccx: &CrateContext, els: &[Type], packed: bool) -> Type {
let els : &[TypeRef] = unsafe { slice::transmute(els) };
ty!(llvm::LLVMStructTypeInContext(ccx.llcx(), els.as_ptr(),
els.len() as c_uint,
packed as Bool))
}
pub fn named_struct(ccx: &CrateContext, name: &str) -> Type { pub fn named_struct(ccx: &CrateContext, name: &str) -> Type {
let name = CString::new(name).unwrap(); let name = CString::new(name).unwrap();
ty!(llvm::LLVMStructCreateNamed(ccx.llcx(), name.as_ptr())) ty!(llvm::LLVMStructCreateNamed(ccx.llcx(), name.as_ptr()))
@ -208,6 +236,7 @@ impl Type {
} }
} }
#[cfg(stage0)]
pub fn set_struct_body(&mut self, els: &[Type], packed: bool) { pub fn set_struct_body(&mut self, els: &[Type], packed: bool) {
unsafe { unsafe {
let vec : &[TypeRef] = mem::transmute(els); let vec : &[TypeRef] = mem::transmute(els);
@ -216,6 +245,15 @@ impl Type {
} }
} }
#[cfg(not(stage0))]
pub fn set_struct_body(&mut self, els: &[Type], packed: bool) {
unsafe {
let vec: &[TypeRef] = slice::transmute(els);
llvm::LLVMStructSetBody(self.to_ref(), vec.as_ptr(),
els.len() as c_uint, packed as Bool)
}
}
pub fn ptr_to(&self) -> Type { pub fn ptr_to(&self) -> Type {
ty!(llvm::LLVMPointerType(self.to_ref(), 0)) ty!(llvm::LLVMPointerType(self.to_ref(), 0))
} }

View file

@ -33,6 +33,7 @@
test(no_crate_inject))] test(no_crate_inject))]
#![no_std] #![no_std]
#![feature(char_from_unchecked)]
#![feature(core_char_ext)] #![feature(core_char_ext)]
#![feature(core_slice_ext)] #![feature(core_slice_ext)]
#![feature(core_str_ext)] #![feature(core_str_ext)]

View file

@ -126,20 +126,18 @@ const S_COUNT: u32 = (L_COUNT * N_COUNT);
// Decompose a precomposed Hangul syllable // Decompose a precomposed Hangul syllable
#[inline(always)] #[inline(always)]
fn decompose_hangul<F>(s: char, f: &mut F) where F: FnMut(char) { fn decompose_hangul<F>(s: char, f: &mut F) where F: FnMut(char) {
use core::mem::transmute; use core::char::from_u32_unchecked;
let si = s as u32 - S_BASE; let si = s as u32 - S_BASE;
let li = si / N_COUNT; let li = si / N_COUNT;
unsafe { unsafe {
(*f)(transmute(L_BASE + li)); (*f)(from_u32_unchecked(L_BASE + li));
let vi = (si % N_COUNT) / T_COUNT; let vi = (si % N_COUNT) / T_COUNT;
(*f)(transmute(V_BASE + vi)); (*f)(from_u32_unchecked(V_BASE + vi));
let ti = si % T_COUNT; let ti = si % T_COUNT;
if ti > 0 { if ti > 0 {
(*f)(transmute(T_BASE + ti)); (*f)(from_u32_unchecked(T_BASE + ti));
} }
} }
} }
@ -147,18 +145,18 @@ fn decompose_hangul<F>(s: char, f: &mut F) where F: FnMut(char) {
// Compose a pair of Hangul Jamo // Compose a pair of Hangul Jamo
#[inline(always)] #[inline(always)]
fn compose_hangul(a: char, b: char) -> Option<char> { fn compose_hangul(a: char, b: char) -> Option<char> {
use core::mem::transmute; use core::char::from_u32_unchecked;
let l = a as u32; let l = a as u32;
let v = b as u32; let v = b as u32;
// Compose an LPart and a VPart // Compose an LPart and a VPart
if L_BASE <= l && l < (L_BASE + L_COUNT) && V_BASE <= v && v < (V_BASE + V_COUNT) { if L_BASE <= l && l < (L_BASE + L_COUNT) && V_BASE <= v && v < (V_BASE + V_COUNT) {
let r = S_BASE + (l - L_BASE) * N_COUNT + (v - V_BASE) * T_COUNT; let r = S_BASE + (l - L_BASE) * N_COUNT + (v - V_BASE) * T_COUNT;
return unsafe { Some(transmute(r)) }; return unsafe { Some(from_u32_unchecked(r)) };
} }
// Compose an LVPart and a TPart // Compose an LVPart and a TPart
if S_BASE <= l && l <= (S_BASE+S_COUNT-T_COUNT) && T_BASE <= v && v < (T_BASE+T_COUNT) { if S_BASE <= l && l <= (S_BASE+S_COUNT-T_COUNT) && T_BASE <= v && v < (T_BASE+T_COUNT) {
let r = l + (v - T_BASE); let r = l + (v - T_BASE);
return unsafe { Some(transmute(r)) }; return unsafe { Some(from_u32_unchecked(r)) };
} }
None None
} }

View file

@ -20,7 +20,6 @@ use core::prelude::v1::*;
use core::char; use core::char;
use core::cmp; use core::cmp;
use core::iter::Filter; use core::iter::Filter;
use core::mem;
use core::slice; use core::slice;
use core::str::Split; use core::str::Split;
@ -454,7 +453,7 @@ impl<'a> Iterator for Utf16Items<'a> {
if u < 0xD800 || 0xDFFF < u { if u < 0xD800 || 0xDFFF < u {
// not a surrogate // not a surrogate
Some(Utf16Item::ScalarValue(unsafe {mem::transmute(u as u32)})) Some(Utf16Item::ScalarValue(unsafe { char::from_u32_unchecked(u as u32) }))
} else if u >= 0xDC00 { } else if u >= 0xDC00 {
// a trailing surrogate // a trailing surrogate
Some(Utf16Item::LoneSurrogate(u)) Some(Utf16Item::LoneSurrogate(u))
@ -476,7 +475,7 @@ impl<'a> Iterator for Utf16Items<'a> {
// all ok, so lets decode it. // all ok, so lets decode it.
let c = (((u - 0xD800) as u32) << 10 | (u2 - 0xDC00) as u32) + 0x1_0000; let c = (((u - 0xD800) as u32) << 10 | (u2 - 0xDC00) as u32) + 0x1_0000;
Some(Utf16Item::ScalarValue(unsafe {mem::transmute(c)})) Some(Utf16Item::ScalarValue(unsafe { char::from_u32_unchecked(c) }))
} }
} }

View file

@ -15,7 +15,6 @@
use prelude::v1::*; use prelude::v1::*;
use ops::Range; use ops::Range;
use mem;
/// Extension methods for ASCII-subset only operations on owned strings /// Extension methods for ASCII-subset only operations on owned strings
#[unstable(feature = "owned_ascii_ext", #[unstable(feature = "owned_ascii_ext",
@ -186,12 +185,12 @@ impl AsciiExt for str {
} }
fn make_ascii_uppercase(&mut self) { fn make_ascii_uppercase(&mut self) {
let me: &mut [u8] = unsafe { mem::transmute(self) }; let me: &mut [u8] = unsafe { self.as_bytes_mut() };
me.make_ascii_uppercase() me.make_ascii_uppercase()
} }
fn make_ascii_lowercase(&mut self) { fn make_ascii_lowercase(&mut self) {
let me: &mut [u8] = unsafe { mem::transmute(self) }; let me: &mut [u8] = unsafe { self.as_bytes_mut() };
me.make_ascii_lowercase() me.make_ascii_lowercase()
} }
} }

View file

@ -192,7 +192,7 @@ impl Error + 'static {
let to: TraitObject = transmute(self); let to: TraitObject = transmute(self);
// Extract the data pointer // Extract the data pointer
Some(transmute(to.data)) Some(&*(to.data as *const T))
} }
} else { } else {
None None
@ -210,7 +210,7 @@ impl Error + 'static {
let to: TraitObject = transmute(self); let to: TraitObject = transmute(self);
// Extract the data pointer // Extract the data pointer
Some(transmute(to.data)) Some(&mut *(to.data as *const T as *mut T))
} }
} else { } else {
None None

View file

@ -395,7 +395,7 @@ impl CStr {
/// > length calculation whenever this method is called. /// > length calculation whenever this method is called.
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub fn to_bytes_with_nul(&self) -> &[u8] { pub fn to_bytes_with_nul(&self) -> &[u8] {
unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.inner) } unsafe { slice::transmute(&self.inner) }
} }
/// Yields a `&str` slice if the `CStr` contains valid UTF-8. /// Yields a `&str` slice if the `CStr` contains valid UTF-8.

View file

@ -134,7 +134,7 @@ impl ops::Index<ops::RangeFull> for OsString {
#[inline] #[inline]
fn index(&self, _index: ops::RangeFull) -> &OsStr { fn index(&self, _index: ops::RangeFull) -> &OsStr {
unsafe { mem::transmute(self.inner.as_slice()) } OsStr::from_inner(self.inner.as_slice())
} }
} }
@ -226,6 +226,10 @@ impl OsStr {
s.as_ref() s.as_ref()
} }
fn from_inner(inner: &Slice) -> &OsStr {
unsafe { mem::transmute(inner) }
}
/// Yields a `&str` slice if the `OsStr` is valid unicode. /// Yields a `&str` slice if the `OsStr` is valid unicode.
/// ///
/// This conversion may entail doing a check for UTF-8 validity. /// This conversion may entail doing a check for UTF-8 validity.
@ -387,14 +391,14 @@ impl AsRef<OsStr> for OsString {
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl AsRef<OsStr> for str { impl AsRef<OsStr> for str {
fn as_ref(&self) -> &OsStr { fn as_ref(&self) -> &OsStr {
unsafe { mem::transmute(Slice::from_str(self)) } OsStr::from_inner(Slice::from_str(self))
} }
} }
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl AsRef<OsStr> for String { impl AsRef<OsStr> for String {
fn as_ref(&self) -> &OsStr { fn as_ref(&self) -> &OsStr {
unsafe { mem::transmute(Slice::from_str(self)) } (&**self).as_ref()
} }
} }

View file

@ -234,7 +234,9 @@
#![feature(reflect_marker)] #![feature(reflect_marker)]
#![feature(slice_bytes)] #![feature(slice_bytes)]
#![feature(slice_patterns)] #![feature(slice_patterns)]
#![feature(slice_transmute)]
#![feature(staged_api)] #![feature(staged_api)]
#![feature(str_as_bytes_mut)]
#![feature(str_char)] #![feature(str_char)]
#![feature(str_internals)] #![feature(str_internals)]
#![feature(unboxed_closures)] #![feature(unboxed_closures)]

View file

@ -942,7 +942,7 @@ pub struct PathBuf {
impl PathBuf { impl PathBuf {
fn as_mut_vec(&mut self) -> &mut Vec<u8> { fn as_mut_vec(&mut self) -> &mut Vec<u8> {
unsafe { mem::transmute(self) } unsafe { &mut *(self as *mut PathBuf as *mut Vec<u8>) }
} }
/// Allocates an empty `PathBuf`. /// Allocates an empty `PathBuf`.
@ -1126,7 +1126,7 @@ impl ops::Deref for PathBuf {
type Target = Path; type Target = Path;
fn deref(&self) -> &Path { fn deref(&self) -> &Path {
unsafe { mem::transmute(&self.inner[..]) } Path::new(&self.inner)
} }
} }
@ -1227,11 +1227,11 @@ impl Path {
// The following (private!) function allows construction of a path from a u8 // The following (private!) function allows construction of a path from a u8
// slice, which is only safe when it is known to follow the OsStr encoding. // slice, which is only safe when it is known to follow the OsStr encoding.
unsafe fn from_u8_slice(s: &[u8]) -> &Path { unsafe fn from_u8_slice(s: &[u8]) -> &Path {
mem::transmute(s) Path::new(u8_slice_as_os_str(s))
} }
// The following (private!) function reveals the byte encoding used for OsStr. // The following (private!) function reveals the byte encoding used for OsStr.
fn as_u8_slice(&self) -> &[u8] { fn as_u8_slice(&self) -> &[u8] {
unsafe { mem::transmute(self) } os_str_as_u8_slice(&self.inner)
} }
/// Directly wrap a string slice as a `Path` slice. /// Directly wrap a string slice as a `Path` slice.

View file

@ -73,7 +73,7 @@ mod tests {
fn test_reader_rng_u64() { fn test_reader_rng_u64() {
// transmute from the target to avoid endianness concerns. // transmute from the target to avoid endianness concerns.
let v = &[0, 0, 0, 0, 0, 0, 0, 1, let v = &[0, 0, 0, 0, 0, 0, 0, 1,
0 , 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2,
0, 0, 0, 0, 0, 0, 0, 3][..]; 0, 0, 0, 0, 0, 0, 0, 3][..];
let mut rng = ReaderRng::new(v); let mut rng = ReaderRng::new(v);

View file

@ -62,7 +62,6 @@ use core::prelude::v1::*;
use core::cell::{Cell, UnsafeCell}; use core::cell::{Cell, UnsafeCell};
use core::marker; use core::marker;
use core::mem;
use core::ptr; use core::ptr;
use core::usize; use core::usize;
@ -281,7 +280,7 @@ impl<'rx, T: Send> Handle<'rx, T> {
pub unsafe fn add(&mut self) { pub unsafe fn add(&mut self) {
if self.added { return } if self.added { return }
let selector = &mut *self.selector; let selector = &mut *self.selector;
let me: *mut Handle<'static, ()> = mem::transmute(&*self); let me = self as *mut Handle<'rx, T> as *mut Handle<'static, ()>;
if selector.head.is_null() { if selector.head.is_null() {
selector.head = me; selector.head = me;
@ -302,7 +301,7 @@ impl<'rx, T: Send> Handle<'rx, T> {
if !self.added { return } if !self.added { return }
let selector = &mut *self.selector; let selector = &mut *self.selector;
let me: *mut Handle<'static, ()> = mem::transmute(&*self); let me = self as *mut Handle<'rx, T> as *mut Handle<'static, ()>;
if self.prev.is_null() { if self.prev.is_null() {
assert_eq!(selector.head, me); assert_eq!(selector.head, me);

View file

@ -90,7 +90,6 @@ use io::prelude::*;
use ffi::CStr; use ffi::CStr;
use io; use io;
use libc; use libc;
use mem;
use str; use str;
use sync::StaticMutex; use sync::StaticMutex;
@ -168,7 +167,7 @@ pub fn write(w: &mut Write) -> io::Result<()> {
extern fn trace_fn(ctx: *mut uw::_Unwind_Context, extern fn trace_fn(ctx: *mut uw::_Unwind_Context,
arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code { arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code {
let cx: &mut Context = unsafe { mem::transmute(arg) }; let cx: &mut Context = unsafe { &mut *(arg as *mut Context) };
let mut ip_before_insn = 0; let mut ip_before_insn = 0;
let mut ip = unsafe { let mut ip = unsafe {
uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void

View file

@ -27,6 +27,7 @@
#![feature(associated_consts)] #![feature(associated_consts)]
#![feature(bitset)] #![feature(bitset)]
#![feature(copy_lifetime)]
#![feature(drain)] #![feature(drain)]
#![feature(filling_drop)] #![feature(filling_drop)]
#![feature(libc)] #![feature(libc)]