1
Fork 0

rollup merge of #18318 : arielb1/transmute-cleanup

This commit is contained in:
Alex Crichton 2014-11-03 15:29:08 -08:00
commit 3aaee490d3
13 changed files with 69 additions and 181 deletions

View file

@ -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 { let mut v = ast_util::IdVisitor {
operation: self, operation: self,
pass_through_items: false, 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. // Output any lints that were previously added to the session.
impl<'a, 'tcx> IdVisitingOperation for Context<'a, 'tcx> { 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) { match self.tcx.sess.lints.borrow_mut().pop(&id) {
None => {} None => {}
Some(lints) => { Some(lints) => {

View file

@ -148,7 +148,7 @@ impl astencode_tag {
pub fn from_uint(value : uint) -> Option<astencode_tag> { pub fn from_uint(value : uint) -> Option<astencode_tag> {
let is_a_tag = first_astencode_tag <= value && value <= last_astencode_tag; let is_a_tag = first_astencode_tag <= value && value <= last_astencode_tag;
if !is_a_tag { None } else { 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_item_generics: uint = 0xa6;
pub const tag_method_ty_generics: uint = 0xa7; pub const tag_method_ty_generics: uint = 0xa7;

View file

@ -29,7 +29,6 @@ use serialize::Encodable;
use std::cell::RefCell; use std::cell::RefCell;
use std::hash::Hash; use std::hash::Hash;
use std::hash; use std::hash;
use std::mem;
use std::collections::HashMap; use std::collections::HashMap;
use syntax::abi; use syntax::abi;
use syntax::ast::*; use syntax::ast::*;
@ -1508,44 +1507,36 @@ fn my_visit_expr(_e: &Expr) { }
fn my_visit_item(i: &Item, fn my_visit_item(i: &Item,
rbml_w: &mut Encoder, rbml_w: &mut Encoder,
ecx_ptr: *const int, ecx: &EncodeContext,
index: &mut Vec<entry<i64>>) { 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| { 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, fn my_visit_foreign_item(ni: &ForeignItem,
rbml_w: &mut Encoder, rbml_w: &mut Encoder,
ecx_ptr:*const int, ecx: &EncodeContext,
index: &mut Vec<entry<i64>>) { index: &mut Vec<entry<i64>>) {
// See above
let ecx: &EncodeContext = unsafe { mem::transmute(ecx_ptr) };
debug!("writing foreign item {}::{}", debug!("writing foreign item {}::{}",
ecx.tcx.map.path_to_string(ni.id), ecx.tcx.map.path_to_string(ni.id),
token::get_ident(ni.ident)); token::get_ident(ni.ident));
let mut rbml_w = unsafe {
rbml_w.unsafe_clone()
};
let abi = ecx.tcx.map.get_foreign_abi(ni.id); let abi = ecx.tcx.map.get_foreign_abi(ni.id);
ecx.tcx.map.with_path(ni.id, |path| { 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, ni, index,
path, abi); 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>, rbml_w_for_visit_item: &'a mut Encoder<'b>,
ecx_ptr:*const int, ecx: &'a EncodeContext<'c,'tcx>,
index: &'a mut Vec<entry<i64>>, 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) { fn visit_expr(&mut self, ex: &Expr) {
visit::walk_expr(self, ex); visit::walk_expr(self, ex);
my_visit_expr(ex); my_visit_expr(ex);
@ -1554,14 +1545,14 @@ impl<'a, 'b, 'v> Visitor<'v> for EncodeVisitor<'a, 'b> {
visit::walk_item(self, i); visit::walk_item(self, i);
my_visit_item(i, my_visit_item(i,
self.rbml_w_for_visit_item, self.rbml_w_for_visit_item,
self.ecx_ptr, self.ecx,
self.index); self.index);
} }
fn visit_foreign_item(&mut self, ni: &ForeignItem) { fn visit_foreign_item(&mut self, ni: &ForeignItem) {
visit::walk_foreign_item(self, ni); visit::walk_foreign_item(self, ni);
my_visit_foreign_item(ni, my_visit_foreign_item(ni,
self.rbml_w_for_visit_item, self.rbml_w_for_visit_item,
self.ecx_ptr, self.ecx,
self.index); self.index);
} }
} }
@ -1585,11 +1576,9 @@ fn encode_info_for_items(ecx: &EncodeContext,
syntax::parse::token::special_idents::invalid, syntax::parse::token::special_idents::invalid,
Public); 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 { visit::walk_crate(&mut EncodeVisitor {
index: &mut index, index: &mut index,
ecx_ptr: ecx_ptr, ecx: ecx,
rbml_w_for_visit_item: &mut *rbml_w, rbml_w_for_visit_item: &mut *rbml_w,
}, krate); }, krate);

View file

@ -231,7 +231,6 @@ use std::c_str::ToCStr;
use std::cmp; use std::cmp;
use std::io::fs::PathExtensions; use std::io::fs::PathExtensions;
use std::io; use std::io;
use std::mem;
use std::ptr; use std::ptr;
use std::slice; use std::slice;
use std::string; use std::string;
@ -287,8 +286,8 @@ pub struct Library {
pub struct ArchiveMetadata { pub struct ArchiveMetadata {
_archive: ArchiveRO, _archive: ArchiveRO,
// See comments in ArchiveMetadata::new for why this is static // points into self._archive
data: &'static [u8], data: *const [u8],
} }
pub struct CratePaths { pub struct CratePaths {
@ -709,33 +708,21 @@ pub fn note_crate_name(diag: &SpanHandler, name: &str) {
impl ArchiveMetadata { impl ArchiveMetadata {
fn new(ar: ArchiveRO) -> Option<ArchiveMetadata> { fn new(ar: ArchiveRO) -> Option<ArchiveMetadata> {
let data: &'static [u8] = { let data = match ar.read(METADATA_FILENAME) {
let data = match ar.read(METADATA_FILENAME) { Some(data) => data as *const [u8],
Some(data) => data, None => {
None => { debug!("didn't find '{}' in the archive", METADATA_FILENAME);
debug!("didn't find '{}' in the archive", METADATA_FILENAME); return None;
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) }
}; };
Some(ArchiveMetadata { Some(ArchiveMetadata {
_archive: ar, _archive: ar,
data: data, 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. // 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 csz = llvm::LLVMGetSectionSize(si.llsi) as uint;
let mut found = let mut found =
Err(format!("metadata not found: '{}'", filename.display())); 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(); let vlen = encoder::metadata_encoding_version.len();
debug!("checking {} bytes of metadata-version stamp", debug!("checking {} bytes of metadata-version stamp",
vlen); vlen);

View file

@ -38,9 +38,7 @@ use syntax::parse::token;
use syntax::ptr::P; use syntax::ptr::P;
use syntax; use syntax;
use libc;
use std::io::Seek; use std::io::Seek;
use std::mem;
use std::rc::Rc; use std::rc::Rc;
use rbml::io::SeekableMemWriter; use rbml::io::SeekableMemWriter;
@ -1122,27 +1120,15 @@ impl<'a> write_tag_and_id for Encoder<'a> {
} }
} }
struct SideTableEncodingIdVisitor<'a,'b:'a> { struct SideTableEncodingIdVisitor<'a, 'b:'a, 'c:'a, 'tcx:'c> {
ecx_ptr: *const libc::c_void, ecx: &'a e::EncodeContext<'c, 'tcx>,
new_rbml_w: &'a mut Encoder<'b>, rbml_w: &'a mut Encoder<'b>,
} }
impl<'a,'b> ast_util::IdVisitingOperation for impl<'a, 'b, 'c, 'tcx> ast_util::IdVisitingOperation for
SideTableEncodingIdVisitor<'a,'b> { SideTableEncodingIdVisitor<'a, 'b, 'c, 'tcx> {
fn visit_id(&self, id: ast::NodeId) { fn visit_id(&mut self, id: ast::NodeId) {
// Note: this will cause a copy of rbml_w, which is bad as encode_side_tables_for_id(self.ecx, self.rbml_w, id)
// 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)
} }
} }
@ -1150,18 +1136,9 @@ fn encode_side_tables_for_ii(ecx: &e::EncodeContext,
rbml_w: &mut Encoder, rbml_w: &mut Encoder,
ii: &ast::InlinedItem) { ii: &ast::InlinedItem) {
rbml_w.start_tag(c::tag_table as uint); rbml_w.start_tag(c::tag_table as uint);
let mut new_rbml_w = unsafe { ast_util::visit_ids_for_inlined_item(ii, &mut SideTableEncodingIdVisitor {
rbml_w.unsafe_clone() ecx: ecx,
}; rbml_w: rbml_w
// 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,
}); });
rbml_w.end_tag(); rbml_w.end_tag();
} }

View file

@ -118,7 +118,6 @@ use util::nodemap::NodeMap;
use std::fmt; use std::fmt;
use std::io; use std::io;
use std::mem::transmute;
use std::rc::Rc; use std::rc::Rc;
use std::str; use std::str;
use std::uint; 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: // swap in a new set of IR maps for this function body:
let mut fn_maps = IrMaps::new(ir.tcx); let mut fn_maps = IrMaps::new(ir.tcx);
unsafe { debug!("creating fn_maps: {}", &fn_maps as *const IrMaps);
debug!("creating fn_maps: {}",
transmute::<&IrMaps, *const IrMaps>(&fn_maps));
}
for arg in decl.inputs.iter() { for arg in decl.inputs.iter() {
pat_util::pat_bindings(&ir.tcx.def_map, pat_util::pat_bindings(&ir.tcx.def_map,

View file

@ -16,66 +16,10 @@ use middle::ty_fold::{TypeFoldable, TypeFolder};
use util::ppaux::Repr; use util::ppaux::Repr;
use std::fmt; use std::fmt;
use std::mem; use std::slice::Items;
use std::raw;
use std::slice::{Items, MutItems};
use std::vec::Vec; use std::vec::Vec;
use syntax::codemap::{Span, DUMMY_SP}; 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
}
}
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
/** /**

View file

@ -27,6 +27,7 @@ use std::collections::HashMap;
use libc::c_uint; use libc::c_uint;
#[deriving(Clone, PartialEq, Show)] #[deriving(Clone, PartialEq, Show)]
#[repr(C)]
pub struct Type { pub struct Type {
rf: TypeRef rf: TypeRef
} }
@ -283,9 +284,10 @@ impl Type {
if n_elts == 0 { if n_elts == 0 {
return Vec::new(); return Vec::new();
} }
let mut elts = Vec::from_elem(n_elts, 0 as TypeRef); let mut elts = Vec::from_elem(n_elts, Type { rf: 0 as TypeRef });
llvm::LLVMGetStructElementTypes(self.to_ref(), &mut elts[0]); llvm::LLVMGetStructElementTypes(self.to_ref(),
mem::transmute(elts) elts.as_mut_ptr() as *mut TypeRef);
elts
} }
} }
@ -296,9 +298,10 @@ impl Type {
pub fn func_params(&self) -> Vec<Type> { pub fn func_params(&self) -> Vec<Type> {
unsafe { unsafe {
let n_args = llvm::LLVMCountParamTypes(self.to_ref()) as uint; let n_args = llvm::LLVMCountParamTypes(self.to_ref()) as uint;
let args = Vec::from_elem(n_args, 0 as TypeRef); let mut args = Vec::from_elem(n_args, Type { rf: 0 as TypeRef });
llvm::LLVMGetParamTypes(self.to_ref(), args.as_ptr()); llvm::LLVMGetParamTypes(self.to_ref(),
mem::transmute(args) args.as_mut_ptr() as *mut TypeRef);
args
} }
} }

View file

@ -547,7 +547,7 @@ extern {
pub fn LLVMIsFunctionVarArg(FunctionTy: TypeRef) -> Bool; pub fn LLVMIsFunctionVarArg(FunctionTy: TypeRef) -> Bool;
pub fn LLVMGetReturnType(FunctionTy: TypeRef) -> TypeRef; pub fn LLVMGetReturnType(FunctionTy: TypeRef) -> TypeRef;
pub fn LLVMCountParamTypes(FunctionTy: TypeRef) -> c_uint; 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 */ /* Operations on struct types */
pub fn LLVMStructTypeInContext(C: ContextRef, 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 // Works to the above fix for #15460 to ensure LLVM dependencies that
// are only used by rustllvm don't get stripped by the linker. // are only used by rustllvm don't get stripped by the linker.
mod llvmdeps; mod llvmdeps;

View file

@ -119,7 +119,7 @@ impl Name {
pub fn as_str<'a>(&'a self) -> &'a str { pub fn as_str<'a>(&'a self) -> &'a str {
unsafe { unsafe {
// FIXME #12938: can't use copy_lifetime since &str isn't a &T // 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())
} }
} }

View file

@ -21,7 +21,6 @@ use ptr::P;
use visit::Visitor; use visit::Visitor;
use visit; use visit;
use std::cell::Cell;
use std::cmp; use std::cmp;
use std::u32; use std::u32;
@ -333,20 +332,20 @@ impl IdRange {
} }
pub trait IdVisitingOperation { 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 /// A visitor that applies its operation to all of the node IDs
/// in a visitable thing. /// in a visitable thing.
pub struct IdVisitor<'a, O:'a> { pub struct IdVisitor<'a, O:'a> {
pub operation: &'a O, pub operation: &'a mut O,
pub pass_through_items: bool, pub pass_through_items: bool,
pub visited_outermost: bool, pub visited_outermost: bool,
} }
impl<'a, O: IdVisitingOperation> IdVisitor<'a, O> { 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() { for type_parameter in generics.ty_params.iter() {
self.operation.visit_id(type_parameter.id) 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, pub fn visit_ids_for_inlined_item<O: IdVisitingOperation>(item: &InlinedItem,
operation: &O) { operation: &mut O) {
let mut id_visitor = IdVisitor { let mut id_visitor = IdVisitor {
operation: operation, operation: operation,
pass_through_items: true, pass_through_items: true,
@ -551,23 +550,21 @@ pub fn visit_ids_for_inlined_item<O: IdVisitingOperation>(item: &InlinedItem,
} }
struct IdRangeComputingVisitor { struct IdRangeComputingVisitor {
result: Cell<IdRange>, result: IdRange,
} }
impl IdVisitingOperation for IdRangeComputingVisitor { impl IdVisitingOperation for IdRangeComputingVisitor {
fn visit_id(&self, id: NodeId) { fn visit_id(&mut self, id: NodeId) {
let mut id_range = self.result.get(); self.result.add(id);
id_range.add(id);
self.result.set(id_range)
} }
} }
pub fn compute_id_range_for_inlined_item(item: &InlinedItem) -> IdRange { pub fn compute_id_range_for_inlined_item(item: &InlinedItem) -> IdRange {
let visitor = IdRangeComputingVisitor { let mut visitor = IdRangeComputingVisitor {
result: Cell::new(IdRange::max()) result: IdRange::max()
}; };
visit_ids_for_inlined_item(item, &visitor); visit_ids_for_inlined_item(item, &mut visitor);
visitor.result.get() visitor.result
} }
pub fn compute_id_range_for_fn_body(fk: visit::FnKind, 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. * ignoring nested items.
*/ */
let visitor = IdRangeComputingVisitor { let mut visitor = IdRangeComputingVisitor {
result: Cell::new(IdRange::max()) result: IdRange::max()
}; };
let mut id_visitor = IdVisitor { let mut id_visitor = IdVisitor {
operation: &visitor, operation: &mut visitor,
pass_through_items: false, pass_through_items: false,
visited_outermost: false, visited_outermost: false,
}; };
id_visitor.visit_fn(fk, decl, body, sp, id); 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 { pub fn walk_pat(pat: &Pat, it: |&Pat| -> bool) -> bool {

View file

@ -668,12 +668,12 @@ impl InternedString {
impl BytesContainer for InternedString { impl BytesContainer for InternedString {
fn container_as_bytes<'a>(&'a self) -> &'a [u8] { 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 // of `BytesContainer`, which is itself a workaround for the lack of
// DST. // DST.
unsafe { unsafe {
let this = self.get(); let this = self.get();
mem::transmute(this.container_as_bytes()) mem::transmute::<&[u8],&[u8]>(this.container_as_bytes())
} }
} }
} }

View file

@ -169,17 +169,14 @@ pub fn to_string(f: |&mut State| -> IoResult<()>) -> String {
let mut s = rust_printer(box MemWriter::new()); let mut s = rust_printer(box MemWriter::new());
f(&mut s).unwrap(); f(&mut s).unwrap();
eof(&mut s.s).unwrap(); eof(&mut s.s).unwrap();
unsafe { let wr = unsafe {
// FIXME(pcwalton): A nasty function to extract the string from an `io::Writer` // 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 // that we "know" to be a `MemWriter` that works around the lack of checked
// downcasts. // downcasts.
let obj: TraitObject = mem::transmute_copy(&s.s.out); let obj: &TraitObject = mem::transmute(&s.s.out);
let wr: Box<MemWriter> = mem::transmute(obj.data); mem::transmute::<*mut (), &MemWriter>(obj.data)
let result = };
String::from_utf8(wr.get_ref().as_slice().to_vec()).unwrap(); String::from_utf8(wr.get_ref().to_vec()).unwrap()
mem::forget(wr);
result.to_string()
}
} }
pub fn binop_to_string(op: BinOpToken) -> &'static str { pub fn binop_to_string(op: BinOpToken) -> &'static str {