about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/lint/context.rs4
-rw-r--r--src/librustc/metadata/common.rs3
-rw-r--r--src/librustc/metadata/encoder.rs31
-rw-r--r--src/librustc/metadata/loader.rs35
-rw-r--r--src/librustc/middle/astencode.rs43
-rw-r--r--src/librustc/middle/liveness.rs6
-rw-r--r--src/librustc/middle/subst.rs58
-rw-r--r--src/librustc/middle/trans/type_.rs15
-rw-r--r--src/librustc_llvm/lib.rs3
-rw-r--r--src/libsyntax/ast.rs2
-rw-r--r--src/libsyntax/ast_util.rs33
-rw-r--r--src/libsyntax/parse/token.rs4
-rw-r--r--src/libsyntax/print/pprust.rs13
13 files changed, 69 insertions, 181 deletions
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index a18d91196e0..6da74eee8a3 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -532,7 +532,7 @@ impl<'a, 'tcx> Context<'a, 'tcx> {
         }
     }
 
-    fn visit_ids(&self, f: |&mut ast_util::IdVisitor<Context>|) {
+    fn visit_ids(&mut self, f: |&mut ast_util::IdVisitor<Context>|) {
         let mut v = ast_util::IdVisitor {
             operation: self,
             pass_through_items: false,
@@ -749,7 +749,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> {
 
 // Output any lints that were previously added to the session.
 impl<'a, 'tcx> IdVisitingOperation for Context<'a, 'tcx> {
-    fn visit_id(&self, id: ast::NodeId) {
+    fn visit_id(&mut self, id: ast::NodeId) {
         match self.tcx.sess.lints.borrow_mut().pop(&id) {
             None => {}
             Some(lints) => {
diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs
index bc58097b860..a04f94c31bf 100644
--- a/src/librustc/metadata/common.rs
+++ b/src/librustc/metadata/common.rs
@@ -148,7 +148,7 @@ impl astencode_tag {
     pub fn from_uint(value : uint) -> Option<astencode_tag> {
         let is_a_tag = first_astencode_tag <= value && value <= last_astencode_tag;
         if !is_a_tag { None } else {
-            Some(unsafe { mem::transmute(value) })
+            Some(unsafe { mem::transmute::<uint, astencode_tag>(value) })
         }
     }
 }
@@ -247,4 +247,3 @@ pub const tag_type_param_def: uint = 0xa5;
 
 pub const tag_item_generics: uint = 0xa6;
 pub const tag_method_ty_generics: uint = 0xa7;
-
diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs
index a5d3cc1f12c..fd389c1f314 100644
--- a/src/librustc/metadata/encoder.rs
+++ b/src/librustc/metadata/encoder.rs
@@ -29,7 +29,6 @@ use serialize::Encodable;
 use std::cell::RefCell;
 use std::hash::Hash;
 use std::hash;
-use std::mem;
 use std::collections::HashMap;
 use syntax::abi;
 use syntax::ast::*;
@@ -1508,44 +1507,36 @@ fn my_visit_expr(_e: &Expr) { }
 
 fn my_visit_item(i: &Item,
                  rbml_w: &mut Encoder,
-                 ecx_ptr: *const int,
+                 ecx: &EncodeContext,
                  index: &mut Vec<entry<i64>>) {
-    let mut rbml_w = unsafe { rbml_w.unsafe_clone() };
-    // See above
-    let ecx: &EncodeContext = unsafe { mem::transmute(ecx_ptr) };
     ecx.tcx.map.with_path(i.id, |path| {
-        encode_info_for_item(ecx, &mut rbml_w, i, index, path, i.vis);
+        encode_info_for_item(ecx, rbml_w, i, index, path, i.vis);
     });
 }
 
 fn my_visit_foreign_item(ni: &ForeignItem,
                          rbml_w: &mut Encoder,
-                         ecx_ptr:*const int,
+                         ecx: &EncodeContext,
                          index: &mut Vec<entry<i64>>) {
-    // See above
-    let ecx: &EncodeContext = unsafe { mem::transmute(ecx_ptr) };
     debug!("writing foreign item {}::{}",
             ecx.tcx.map.path_to_string(ni.id),
             token::get_ident(ni.ident));
 
-    let mut rbml_w = unsafe {
-        rbml_w.unsafe_clone()
-    };
     let abi = ecx.tcx.map.get_foreign_abi(ni.id);
     ecx.tcx.map.with_path(ni.id, |path| {
-        encode_info_for_foreign_item(ecx, &mut rbml_w,
+        encode_info_for_foreign_item(ecx, rbml_w,
                                      ni, index,
                                      path, abi);
     });
 }
 
-struct EncodeVisitor<'a,'b:'a> {
+struct EncodeVisitor<'a, 'b:'a, 'c:'a, 'tcx:'c> {
     rbml_w_for_visit_item: &'a mut Encoder<'b>,
-    ecx_ptr:*const int,
+    ecx: &'a EncodeContext<'c,'tcx>,
     index: &'a mut Vec<entry<i64>>,
 }
 
-impl<'a, 'b, 'v> Visitor<'v> for EncodeVisitor<'a, 'b> {
+impl<'a, 'b, 'c, 'tcx, 'v> Visitor<'v> for EncodeVisitor<'a, 'b, 'c, 'tcx> {
     fn visit_expr(&mut self, ex: &Expr) {
         visit::walk_expr(self, ex);
         my_visit_expr(ex);
@@ -1554,14 +1545,14 @@ impl<'a, 'b, 'v> Visitor<'v> for EncodeVisitor<'a, 'b> {
         visit::walk_item(self, i);
         my_visit_item(i,
                       self.rbml_w_for_visit_item,
-                      self.ecx_ptr,
+                      self.ecx,
                       self.index);
     }
     fn visit_foreign_item(&mut self, ni: &ForeignItem) {
         visit::walk_foreign_item(self, ni);
         my_visit_foreign_item(ni,
                               self.rbml_w_for_visit_item,
-                              self.ecx_ptr,
+                              self.ecx,
                               self.index);
     }
 }
@@ -1585,11 +1576,9 @@ fn encode_info_for_items(ecx: &EncodeContext,
                         syntax::parse::token::special_idents::invalid,
                         Public);
 
-    // See comment in `encode_side_tables_for_ii` in astencode
-    let ecx_ptr: *const int = unsafe { mem::transmute(ecx) };
     visit::walk_crate(&mut EncodeVisitor {
         index: &mut index,
-        ecx_ptr: ecx_ptr,
+        ecx: ecx,
         rbml_w_for_visit_item: &mut *rbml_w,
     }, krate);
 
diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs
index 7b67def4051..738eeaae6a5 100644
--- a/src/librustc/metadata/loader.rs
+++ b/src/librustc/metadata/loader.rs
@@ -231,7 +231,6 @@ use std::c_str::ToCStr;
 use std::cmp;
 use std::io::fs::PathExtensions;
 use std::io;
-use std::mem;
 use std::ptr;
 use std::slice;
 use std::string;
@@ -287,8 +286,8 @@ pub struct Library {
 
 pub struct ArchiveMetadata {
     _archive: ArchiveRO,
-    // See comments in ArchiveMetadata::new for why this is static
-    data: &'static [u8],
+    // points into self._archive
+    data: *const [u8],
 }
 
 pub struct CratePaths {
@@ -709,33 +708,21 @@ pub fn note_crate_name(diag: &SpanHandler, name: &str) {
 
 impl ArchiveMetadata {
     fn new(ar: ArchiveRO) -> Option<ArchiveMetadata> {
-        let data: &'static [u8] = {
-            let data = match ar.read(METADATA_FILENAME) {
-                Some(data) => data,
-                None => {
-                    debug!("didn't find '{}' in the archive", METADATA_FILENAME);
-                    return None;
-                }
-            };
-            // This data is actually a pointer inside of the archive itself, but
-            // we essentially want to cache it because the lookup inside the
-            // archive is a fairly expensive operation (and it's queried for
-            // *very* frequently). For this reason, we transmute it to the
-            // static lifetime to put into the struct. Note that the buffer is
-            // never actually handed out with a static lifetime, but rather the
-            // buffer is loaned with the lifetime of this containing object.
-            // Hence, we're guaranteed that the buffer will never be used after
-            // this object is dead, so this is a safe operation to transmute and
-            // store the data as a static buffer.
-            unsafe { mem::transmute(data) }
+        let data = match ar.read(METADATA_FILENAME) {
+            Some(data) => data as *const [u8],
+            None => {
+                debug!("didn't find '{}' in the archive", METADATA_FILENAME);
+                return None;
+            }
         };
+
         Some(ArchiveMetadata {
             _archive: ar,
             data: data,
         })
     }
 
-    pub fn as_slice<'a>(&'a self) -> &'a [u8] { self.data }
+    pub fn as_slice<'a>(&'a self) -> &'a [u8] { unsafe { &*self.data } }
 }
 
 // Just a small wrapper to time how long reading metadata takes.
@@ -798,7 +785,7 @@ fn get_metadata_section_imp(os: abi::Os, filename: &Path) -> Result<MetadataBlob
                 let csz = llvm::LLVMGetSectionSize(si.llsi) as uint;
                 let mut found =
                     Err(format!("metadata not found: '{}'", filename.display()));
-                let cvbuf: *const u8 = mem::transmute(cbuf);
+                let cvbuf: *const u8 = cbuf as *const u8;
                 let vlen = encoder::metadata_encoding_version.len();
                 debug!("checking {} bytes of metadata-version stamp",
                        vlen);
diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs
index 988f7d46f5f..41ed7fcf01a 100644
--- a/src/librustc/middle/astencode.rs
+++ b/src/librustc/middle/astencode.rs
@@ -38,9 +38,7 @@ use syntax::parse::token;
 use syntax::ptr::P;
 use syntax;
 
-use libc;
 use std::io::Seek;
-use std::mem;
 use std::rc::Rc;
 
 use rbml::io::SeekableMemWriter;
@@ -1122,27 +1120,15 @@ impl<'a> write_tag_and_id for Encoder<'a> {
     }
 }
 
-struct SideTableEncodingIdVisitor<'a,'b:'a> {
-    ecx_ptr: *const libc::c_void,
-    new_rbml_w: &'a mut Encoder<'b>,
+struct SideTableEncodingIdVisitor<'a, 'b:'a, 'c:'a, 'tcx:'c> {
+    ecx: &'a e::EncodeContext<'c, 'tcx>,
+    rbml_w: &'a mut Encoder<'b>,
 }
 
-impl<'a,'b> ast_util::IdVisitingOperation for
-        SideTableEncodingIdVisitor<'a,'b> {
-    fn visit_id(&self, id: ast::NodeId) {
-        // Note: this will cause a copy of rbml_w, which is bad as
-        // it is mutable. But I believe it's harmless since we generate
-        // balanced EBML.
-        //
-        // FIXME(pcwalton): Don't copy this way.
-        let mut new_rbml_w = unsafe {
-            self.new_rbml_w.unsafe_clone()
-        };
-        // See above
-        let ecx: &e::EncodeContext = unsafe {
-            mem::transmute(self.ecx_ptr)
-        };
-        encode_side_tables_for_id(ecx, &mut new_rbml_w, id)
+impl<'a, 'b, 'c, 'tcx> ast_util::IdVisitingOperation for
+        SideTableEncodingIdVisitor<'a, 'b, 'c, 'tcx> {
+    fn visit_id(&mut self, id: ast::NodeId) {
+        encode_side_tables_for_id(self.ecx, self.rbml_w, id)
     }
 }
 
@@ -1150,18 +1136,9 @@ fn encode_side_tables_for_ii(ecx: &e::EncodeContext,
                              rbml_w: &mut Encoder,
                              ii: &ast::InlinedItem) {
     rbml_w.start_tag(c::tag_table as uint);
-    let mut new_rbml_w = unsafe {
-        rbml_w.unsafe_clone()
-    };
-
-    // Because the ast visitor uses @IdVisitingOperation, I can't pass in
-    // ecx directly, but /I/ know that it'll be fine since the lifetime is
-    // tied to the CrateContext that lives throughout this entire section.
-    ast_util::visit_ids_for_inlined_item(ii, &SideTableEncodingIdVisitor {
-        ecx_ptr: unsafe {
-            mem::transmute(ecx)
-        },
-        new_rbml_w: &mut new_rbml_w,
+    ast_util::visit_ids_for_inlined_item(ii, &mut SideTableEncodingIdVisitor {
+        ecx: ecx,
+        rbml_w: rbml_w
     });
     rbml_w.end_tag();
 }
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index a11d5f6604e..b5847a94b8d 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -118,7 +118,6 @@ use util::nodemap::NodeMap;
 
 use std::fmt;
 use std::io;
-use std::mem::transmute;
 use std::rc::Rc;
 use std::str;
 use std::uint;
@@ -380,10 +379,7 @@ fn visit_fn(ir: &mut IrMaps,
     // swap in a new set of IR maps for this function body:
     let mut fn_maps = IrMaps::new(ir.tcx);
 
-    unsafe {
-        debug!("creating fn_maps: {}",
-               transmute::<&IrMaps, *const IrMaps>(&fn_maps));
-    }
+    debug!("creating fn_maps: {}", &fn_maps as *const IrMaps);
 
     for arg in decl.inputs.iter() {
         pat_util::pat_bindings(&ir.tcx.def_map,
diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs
index b986d4dd591..bec02c736ad 100644
--- a/src/librustc/middle/subst.rs
+++ b/src/librustc/middle/subst.rs
@@ -16,67 +16,11 @@ use middle::ty_fold::{TypeFoldable, TypeFolder};
 use util::ppaux::Repr;
 
 use std::fmt;
-use std::mem;
-use std::raw;
-use std::slice::{Items, MutItems};
+use std::slice::Items;
 use std::vec::Vec;
 use syntax::codemap::{Span, DUMMY_SP};
 
 ///////////////////////////////////////////////////////////////////////////
-// HomogeneousTuple3 trait
-//
-// This could be moved into standard library at some point.
-
-trait HomogeneousTuple3<T> {
-    fn len(&self) -> uint;
-    fn as_slice<'a>(&'a self) -> &'a [T];
-    fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T];
-    fn iter<'a>(&'a self) -> Items<'a, T>;
-    fn iter_mut<'a>(&'a mut self) -> MutItems<'a, T>;
-    fn get<'a>(&'a self, index: uint) -> Option<&'a T>;
-    fn get_mut<'a>(&'a mut self, index: uint) -> Option<&'a mut T>;
-}
-
-impl<T> HomogeneousTuple3<T> for (T, T, T) {
-    fn len(&self) -> uint {
-        3
-    }
-
-    fn as_slice<'a>(&'a self) -> &'a [T] {
-        unsafe {
-            let ptr: *const T = mem::transmute(self);
-            let slice = raw::Slice { data: ptr, len: 3 };
-            mem::transmute(slice)
-        }
-    }
-
-    fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T] {
-        unsafe {
-            let ptr: *const T = mem::transmute(self);
-            let slice = raw::Slice { data: ptr, len: 3 };
-            mem::transmute(slice)
-        }
-    }
-
-    fn iter<'a>(&'a self) -> Items<'a, T> {
-        let slice: &'a [T] = self.as_slice();
-        slice.iter()
-    }
-
-    fn iter_mut<'a>(&'a mut self) -> MutItems<'a, T> {
-        self.as_mut_slice().iter_mut()
-    }
-
-    fn get<'a>(&'a self, index: uint) -> Option<&'a T> {
-        self.as_slice().get(index)
-    }
-
-    fn get_mut<'a>(&'a mut self, index: uint) -> Option<&'a mut T> {
-        Some(&mut self.as_mut_slice()[index]) // wrong: fallible
-    }
-}
-
-///////////////////////////////////////////////////////////////////////////
 
 /**
  * A substitution mapping type/region parameters to new values. We
diff --git a/src/librustc/middle/trans/type_.rs b/src/librustc/middle/trans/type_.rs
index d8424c9f316..1746f785311 100644
--- a/src/librustc/middle/trans/type_.rs
+++ b/src/librustc/middle/trans/type_.rs
@@ -27,6 +27,7 @@ use std::collections::HashMap;
 use libc::c_uint;
 
 #[deriving(Clone, PartialEq, Show)]
+#[repr(C)]
 pub struct Type {
     rf: TypeRef
 }
@@ -283,9 +284,10 @@ impl Type {
             if n_elts == 0 {
                 return Vec::new();
             }
-            let mut elts = Vec::from_elem(n_elts, 0 as TypeRef);
-            llvm::LLVMGetStructElementTypes(self.to_ref(), &mut elts[0]);
-            mem::transmute(elts)
+            let mut elts = Vec::from_elem(n_elts, Type { rf: 0 as TypeRef });
+            llvm::LLVMGetStructElementTypes(self.to_ref(),
+                                            elts.as_mut_ptr() as *mut TypeRef);
+            elts
         }
     }
 
@@ -296,9 +298,10 @@ impl Type {
     pub fn func_params(&self) -> Vec<Type> {
         unsafe {
             let n_args = llvm::LLVMCountParamTypes(self.to_ref()) as uint;
-            let args = Vec::from_elem(n_args, 0 as TypeRef);
-            llvm::LLVMGetParamTypes(self.to_ref(), args.as_ptr());
-            mem::transmute(args)
+            let mut args = Vec::from_elem(n_args, Type { rf: 0 as TypeRef });
+            llvm::LLVMGetParamTypes(self.to_ref(),
+                                    args.as_mut_ptr() as *mut TypeRef);
+            args
         }
     }
 
diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs
index 06456a91e03..48e1e590058 100644
--- a/src/librustc_llvm/lib.rs
+++ b/src/librustc_llvm/lib.rs
@@ -547,7 +547,7 @@ extern {
     pub fn LLVMIsFunctionVarArg(FunctionTy: TypeRef) -> Bool;
     pub fn LLVMGetReturnType(FunctionTy: TypeRef) -> TypeRef;
     pub fn LLVMCountParamTypes(FunctionTy: TypeRef) -> c_uint;
-    pub fn LLVMGetParamTypes(FunctionTy: TypeRef, Dest: *const TypeRef);
+    pub fn LLVMGetParamTypes(FunctionTy: TypeRef, Dest: *mut TypeRef);
 
     /* Operations on struct types */
     pub fn LLVMStructTypeInContext(C: ContextRef,
@@ -2195,4 +2195,3 @@ pub unsafe fn static_link_hack_this_sucks() {
 // Works to the above fix for #15460 to ensure LLVM dependencies that
 // are only used by rustllvm don't get stripped by the linker.
 mod llvmdeps;
-
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index a2c859cf9fd..1edcb35289a 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -119,7 +119,7 @@ impl Name {
     pub fn as_str<'a>(&'a self) -> &'a str {
         unsafe {
             // FIXME #12938: can't use copy_lifetime since &str isn't a &T
-            ::std::mem::transmute(token::get_name(*self).get())
+            ::std::mem::transmute::<&str,&str>(token::get_name(*self).get())
         }
     }
 
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs
index 8b0e1f32fd4..863f53be798 100644
--- a/src/libsyntax/ast_util.rs
+++ b/src/libsyntax/ast_util.rs
@@ -21,7 +21,6 @@ use ptr::P;
 use visit::Visitor;
 use visit;
 
-use std::cell::Cell;
 use std::cmp;
 use std::u32;
 
@@ -333,20 +332,20 @@ impl IdRange {
 }
 
 pub trait IdVisitingOperation {
-    fn visit_id(&self, node_id: NodeId);
+    fn visit_id(&mut self, node_id: NodeId);
 }
 
 /// A visitor that applies its operation to all of the node IDs
 /// in a visitable thing.
 
 pub struct IdVisitor<'a, O:'a> {
-    pub operation: &'a O,
+    pub operation: &'a mut O,
     pub pass_through_items: bool,
     pub visited_outermost: bool,
 }
 
 impl<'a, O: IdVisitingOperation> IdVisitor<'a, O> {
-    fn visit_generics_helper(&self, generics: &Generics) {
+    fn visit_generics_helper(&mut self, generics: &Generics) {
         for type_parameter in generics.ty_params.iter() {
             self.operation.visit_id(type_parameter.id)
         }
@@ -540,7 +539,7 @@ impl<'a, 'v, O: IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> {
 }
 
 pub fn visit_ids_for_inlined_item<O: IdVisitingOperation>(item: &InlinedItem,
-                                                          operation: &O) {
+                                                          operation: &mut O) {
     let mut id_visitor = IdVisitor {
         operation: operation,
         pass_through_items: true,
@@ -551,23 +550,21 @@ pub fn visit_ids_for_inlined_item<O: IdVisitingOperation>(item: &InlinedItem,
 }
 
 struct IdRangeComputingVisitor {
-    result: Cell<IdRange>,
+    result: IdRange,
 }
 
 impl IdVisitingOperation for IdRangeComputingVisitor {
-    fn visit_id(&self, id: NodeId) {
-        let mut id_range = self.result.get();
-        id_range.add(id);
-        self.result.set(id_range)
+    fn visit_id(&mut self, id: NodeId) {
+        self.result.add(id);
     }
 }
 
 pub fn compute_id_range_for_inlined_item(item: &InlinedItem) -> IdRange {
-    let visitor = IdRangeComputingVisitor {
-        result: Cell::new(IdRange::max())
+    let mut visitor = IdRangeComputingVisitor {
+        result: IdRange::max()
     };
-    visit_ids_for_inlined_item(item, &visitor);
-    visitor.result.get()
+    visit_ids_for_inlined_item(item, &mut visitor);
+    visitor.result
 }
 
 pub fn compute_id_range_for_fn_body(fk: visit::FnKind,
@@ -582,16 +579,16 @@ pub fn compute_id_range_for_fn_body(fk: visit::FnKind,
      * ignoring nested items.
      */
 
-    let visitor = IdRangeComputingVisitor {
-        result: Cell::new(IdRange::max())
+    let mut visitor = IdRangeComputingVisitor {
+        result: IdRange::max()
     };
     let mut id_visitor = IdVisitor {
-        operation: &visitor,
+        operation: &mut visitor,
         pass_through_items: false,
         visited_outermost: false,
     };
     id_visitor.visit_fn(fk, decl, body, sp, id);
-    visitor.result.get()
+    id_visitor.operation.result
 }
 
 pub fn walk_pat(pat: &Pat, it: |&Pat| -> bool) -> bool {
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index d56aa8da72a..615cd34ca14 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -668,12 +668,12 @@ impl InternedString {
 
 impl BytesContainer for InternedString {
     fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
-        // FIXME(pcwalton): This is a workaround for the incorrect signature
+        // FIXME #12938: This is a workaround for the incorrect signature
         // of `BytesContainer`, which is itself a workaround for the lack of
         // DST.
         unsafe {
             let this = self.get();
-            mem::transmute(this.container_as_bytes())
+            mem::transmute::<&[u8],&[u8]>(this.container_as_bytes())
         }
     }
 }
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 386fd8ae5a6..4cfc95d4c3f 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -169,17 +169,14 @@ pub fn to_string(f: |&mut State| -> IoResult<()>) -> String {
     let mut s = rust_printer(box MemWriter::new());
     f(&mut s).unwrap();
     eof(&mut s.s).unwrap();
-    unsafe {
+    let wr = unsafe {
         // FIXME(pcwalton): A nasty function to extract the string from an `io::Writer`
         // that we "know" to be a `MemWriter` that works around the lack of checked
         // downcasts.
-        let obj: TraitObject = mem::transmute_copy(&s.s.out);
-        let wr: Box<MemWriter> = mem::transmute(obj.data);
-        let result =
-            String::from_utf8(wr.get_ref().as_slice().to_vec()).unwrap();
-        mem::forget(wr);
-        result.to_string()
-    }
+        let obj: &TraitObject = mem::transmute(&s.s.out);
+        mem::transmute::<*mut (), &MemWriter>(obj.data)
+    };
+    String::from_utf8(wr.get_ref().to_vec()).unwrap()
 }
 
 pub fn binop_to_string(op: BinOpToken) -> &'static str {