From 93e590a93bd2f28a3b8e885fa96e2dbb5b003afb Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 26 Sep 2014 17:42:38 +0200 Subject: [PATCH 1/7] Desugar `box () ` to `Placer` protocol. Note that this narrows desugaring to only be when actual placer is provided; `box ` and `box () ` both still fall through to the `mk_unary(UnUniq, _)` path. Many more compile-fail tests would need updating if we were not restricting desugaring to `box` with explicit placer. --- src/liballoc/boxed.rs | 81 +++++++++++- src/liballoc/lib.rs | 7 + src/libcore/ops.rs | 64 +++++++++ src/librustc/middle/cfg/construct.rs | 5 +- src/librustc/middle/expr_use_visitor.rs | 2 +- src/librustc/middle/liveness.rs | 3 +- src/librustc/middle/trans/debuginfo.rs | 2 +- src/librustc/middle/ty.rs | 3 +- src/librustc/middle/typeck/check/mod.rs | 8 +- src/libsyntax/ast.rs | 2 +- src/libsyntax/ext/expand.rs | 169 ++++++++++++++++++++++++ src/libsyntax/fold.rs | 2 +- src/libsyntax/parse/parser.rs | 6 +- src/libsyntax/print/pprust.rs | 2 +- src/libsyntax/visit.rs | 2 +- src/test/compile-fail/issue-14084.rs | 5 +- 16 files changed, 342 insertions(+), 21 deletions(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 168d0daeb3845..d4a716d8bb11e 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -10,13 +10,17 @@ //! A unique pointer type. +use heap; + use core::any::{Any, AnyRefExt}; use core::clone::Clone; use core::cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering}; use core::default::Default; use core::fmt; use core::intrinsics; +use core::kinds::Sized; use core::mem; +use core::ops::{Drop, Placer, PlacementAgent}; use core::option::Option; use core::raw::TraitObject; use core::result::{Ok, Err, Result}; @@ -36,22 +40,91 @@ use core::result::{Ok, Err, Result}; /// ``` #[lang = "exchange_heap"] #[experimental = "may be renamed; uncertain about custom allocator design"] -pub static HEAP: () = (); +pub static HEAP: ExchangeHeapSingleton = + ExchangeHeapSingleton { _force_singleton: () }; + +/// This the singleton type used solely for `boxed::HEAP`. +pub struct ExchangeHeapSingleton { _force_singleton: () } /// A type that represents a uniquely-owned value. #[lang = "owned_box"] #[unstable = "custom allocators will add an additional type parameter (with default)"] -pub struct Box(*mut T); +pub struct Box(*mut T); + +/// `IntermediateBox` represents uninitialized backing storage for `Box`. +/// +/// FIXME (pnkfelix): Ideally we would just reuse `Box` instead of +/// introducing a separate `IntermediateBox`; but then you hit +/// issues when you e.g. attempt to destructure an instance of `Box`, +/// since it is a lang item and so it gets special handling by the +/// compiler. Easier just to make this parallel type for now. +/// +/// FIXME (pnkfelix): Currently the `box` protocol only supports +/// creating instances of sized types. This IntermediateBox is +/// designed to be forward-compatible with a future protocol that +/// supports creating instances of unsized types; that is why the type +/// parameter has the `Sized?` generalization marker, and is also why +/// this carries an explicit size. However, it probably does not need +/// to carry the explicit alignment; that is just a work-around for +/// the fact that the `align_of` intrinsic currently requires the +/// input type to be Sized (which I do not think is strictly +/// necessary). +pub struct IntermediateBox{ + ptr: *mut u8, + size: uint, + align: uint, +} + +impl Placer, IntermediateBox> for ExchangeHeapSingleton { + fn make_place(&self) -> IntermediateBox { + let size = mem::size_of::(); + let align = mem::align_of::(); + + let p = if size == 0 { + heap::EMPTY as *mut u8 + } else { + unsafe { + heap::allocate(size, align) + } + }; + + IntermediateBox { ptr: p, size: size, align: align } + } +} + +impl PlacementAgent> for IntermediateBox { + unsafe fn pointer(&self) -> *mut T { + self.ptr as *mut T + } + unsafe fn finalize(self) -> Box { + let p = self.ptr as *mut T; + mem::forget(self); + mem::transmute(p) + } +} + +#[unsafe_destructor] +impl Drop for IntermediateBox { + fn drop(&mut self) { + if self.size > 0 { + unsafe { + heap::deallocate(self.ptr as *mut u8, self.size, self.align) + } + } + } +} impl Default for Box { - fn default() -> Box { box Default::default() } + fn default() -> Box { + box (HEAP) { let t : T = Default::default(); t } + } } #[unstable] impl Clone for Box { /// Returns a copy of the owned box. #[inline] - fn clone(&self) -> Box { box {(**self).clone()} } + fn clone(&self) -> Box { box (HEAP) {(**self).clone()} } /// Performs copy-assignment from `source` by reusing the existing allocation. #[inline] diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 2df9a585fec99..de2f606a0a059 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -94,8 +94,13 @@ pub mod libc_heap; // Primitive types using the heaps above +// Need to conditionally define the mod from `boxed.rs` to avoid +// duplicating the lang-items when building in test cfg; but also need +// to allow code to have `use boxed::HEAP;` declaration. #[cfg(not(test))] pub mod boxed; +#[cfg(test)] +mod boxed { pub use std::boxed::HEAP; } pub mod arc; pub mod rc; @@ -126,5 +131,7 @@ pub fn fixme_14344_be_sure_to_link_to_collections() {} #[doc(hidden)] mod std { pub use core::fmt; + pub use core::ops; pub use core::option; + pub use core::ptr; } diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index f6e3e7f61cf93..22ea7a76c336d 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -901,3 +901,67 @@ def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12) def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13) def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14) def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 A15) + +/// Interface to user-implementations of `box () `. +/// +/// `box (P) V` effectively expands into: +/// `{ let b = P.make_place(); let v = V; unsafe { b.pointer() = v; b.finalize() } }` +pub trait Placer> { + /// Allocates a place for the data to live, returning an + /// intermediate agent to negotiate ownership. + fn make_place(&self) -> Interim; +} + +/// Some free functions called by expansions of `box ` and +/// `box () `. +pub mod placer { + use kinds::Sized; + use ops::{Placer, PlacementAgent}; + + /// The first argument, `` in `box () `, must + /// implement `Placer`. + pub fn parenthesized_input_to_box_must_be_placer(p: P) -> P + where A:PlacementAgent, + P:Placer+Sized { + p + } + + /// Work-around for lack of UFCS: the `box () ` + /// syntax expands into calls to the three free functions below in + /// order to avoid requiring (or expanding into) declarations like + /// `use std::ops::Placer;` and `use std::ops::PlacementAgent;` + + /// Calls `p.make_place()` as work-around for lack of UFCS. + pub fn make_place(p: &P) -> A + where A:PlacementAgent, + P:Placer { + p.make_place() + } + + /// Calls `a.pointer()` as work-around for lack of UFCS. + pub unsafe fn pointer(a: &A) -> *mut Data + where A:PlacementAgent { + a.pointer() + } + + /// Calls `a.finalize()` as work-around for lack of UFCS. + pub unsafe fn finalize(a: A) -> Owner + where A:PlacementAgent { + a.finalize() + } +} + +/// Helper trait for expansion of `box (P) V`. +/// +/// We force all implementers to implement `Drop`, since in the majority of +/// cases, leaving out a user-defined drop is a bug for these values. +/// +/// See also `Placer`. +pub trait PlacementAgent : Drop { + /// Returns a pointer to the offset in the place where the data lives. + unsafe fn pointer(&self) -> *mut Data; + + /// Converts this intermediate agent into owning pointer for the data, + /// forgetting self in the process. + unsafe fn finalize(self) -> Owner; +} diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index 4b55a0b26098b..7ba295f92efa8 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -461,15 +461,14 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { self.straightline(expr, pred, [r, l].iter().map(|&e| &**e)) } + ast::ExprBox(Some(ref l), ref r) | ast::ExprIndex(ref l, ref r) | ast::ExprBinary(_, ref l, ref r) => { // NB: && and || handled earlier self.straightline(expr, pred, [l, r].iter().map(|&e| &**e)) } - ast::ExprBox(ref p, ref e) => { - self.straightline(expr, pred, [p, e].iter().map(|&e| &**e)) - } + ast::ExprBox(None, ref e) | ast::ExprAddrOf(_, ref e) | ast::ExprCast(ref e, _) | ast::ExprUnary(_, ref e) | diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index c413eb67a73ac..8d191fa127fd2 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -501,7 +501,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,TYPER> { } ast::ExprBox(ref place, ref base) => { - self.consume_expr(&**place); + place.as_ref().map(|e|self.consume_expr(&**e)); self.consume_expr(&**base); } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 63e9a80adc61a..6a76131731bb9 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -1186,7 +1186,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { ExprIndex(ref l, ref r) | ExprBinary(_, ref l, ref r) | - ExprBox(ref l, ref r) => { + ExprBox(Some(ref l), ref r) => { let r_succ = self.propagate_through_expr(&**r, succ); self.propagate_through_expr(&**l, r_succ) } @@ -1197,6 +1197,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.propagate_through_expr(&**e1, succ) } + ExprBox(None, ref e) | ExprAddrOf(_, ref e) | ExprCast(ref e, _) | ExprUnary(_, ref e) | diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index f2c965924cd19..9effbdc3af723 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -3420,7 +3420,7 @@ fn populate_scope_map(cx: &CrateContext, walk_expr(cx, &**sub_exp, scope_stack, scope_map), ast::ExprBox(ref place, ref sub_expr) => { - walk_expr(cx, &**place, scope_stack, scope_map); + place.as_ref().map(|e|walk_expr(cx, &**e, scope_stack, scope_map)); walk_expr(cx, &**sub_expr, scope_stack, scope_map); } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index a7ce93279bd83..a185e830c4c7e 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -3705,12 +3705,13 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind { ast::ExprLit(_) | // Note: LitStr is carved out above ast::ExprUnary(..) | + ast::ExprBox(None, _) | ast::ExprAddrOf(..) | ast::ExprBinary(..) => { RvalueDatumExpr } - ast::ExprBox(ref place, _) => { + ast::ExprBox(Some(ref place), _) => { // Special case `Box` for now: let definition = match tcx.def_map.borrow().find(&place.id) { Some(&def) => def, diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 5f7b31e573ade..8e25ecc8c1319 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -3723,15 +3723,15 @@ fn check_expr_with_unifier(fcx: &FnCtxt, let id = expr.id; match expr.node { ast::ExprBox(ref place, ref subexpr) => { - check_expr(fcx, &**place); + place.as_ref().map(|e|check_expr(fcx, &**e)); check_expr(fcx, &**subexpr); let mut checked = false; - match place.node { + place.as_ref().map(|e| match e.node { ast::ExprPath(ref path) => { // FIXME(pcwalton): For now we hardcode the two permissible // places: the exchange heap and the managed heap. - let definition = lookup_def(fcx, path.span, place.id); + let definition = lookup_def(fcx, path.span, e.id); let def_id = definition.def_id(); let referent_ty = fcx.expr_ty(&**subexpr); if tcx.lang_items.exchange_heap() == Some(def_id) { @@ -3740,7 +3740,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt, } } _ => {} - } + }); if !checked { span_err!(tcx.sess, expr.span, E0066, diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index df63d161eec35..5e2f9f591c5e3 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -510,7 +510,7 @@ pub struct Expr { #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum Expr_ { /// First expr is the place; second expr is the value. - ExprBox(P, P), + ExprBox(Option>, P), ExprVec(Vec>), ExprCall(P, Vec>), ExprMethodCall(SpannedIdent, Vec>, Vec>), diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 39b710e0d5725..5c9663012bce5 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -22,6 +22,7 @@ use codemap::{Span, Spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute}; use ext::base::*; use fold; use fold::*; +use owned_slice::OwnedSlice; use parse; use parse::token::{fresh_mark, fresh_name, intern}; use parse::token; @@ -61,6 +62,174 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { }) } + // FIXME (pnkfelix): The code below is designed to handle + // *both* `box ` and `box () `, but for + // now the desugaring will only apply to the latter. + // + // The motivation is mostly to make it easier to land without + // having to update many tests that are not expecting to deal + // with the desugared form in terms of (1.) error messages and + // (2.) the dependencies on `::std::ops::placer`. + // + // To re-enable the more general code paths, just change the + // `Some(place)` in this binding to `maybe_place`, and revise + // the `let maybe_place = ...` to call `fld.fold_expr(place)` + // directly. + + // Desugar ExprBox: `box () ` + ast::ExprBox(Some(place), value_expr) => { + let value_span = value_expr.span; + let place_span = place.span; + + let maybe_place : Option> = Some(fld.fold_expr(place)); + let value_expr = fld.fold_expr(value_expr); + + // Desugar `box () ` to something + // analogous to: + // + // { + // fn force_placer(p: P) -> P where P : Placer { p } + // let place = force_placer(); + // let agent = place.make_place(); + // let value = + // unsafe { + // ptr::write(agent.pointer(), value); + // agent.finalize() + // } + // } + // + // The intention of `fn force_placer` is to provide better + // error messages when the `` does not + // implement the Placer trait. Likewise, the actual + // expansion below actually calls free functions in + // `std::ops::placer`, in order to avoid the need for UFCS + // (and also to hopefully produce better error messags). + + let place_ident = token::gensym_ident("place1"); + let agent_ident = token::gensym_ident("agent"); + let value_ident = token::gensym_ident("value"); + + let place = fld.cx.expr_ident(span, place_ident); + let agent = fld.cx.expr_ident(span, agent_ident); + let value = fld.cx.expr_ident(span, value_ident); + + fn mk_path_for_idents(span: Span, + idents: &[&'static str]) -> ast::Path { + let segments : Vec = + idents.iter().map(|s| { + ast::PathSegment { + identifier: token::str_to_ident(*s), + lifetimes: vec![], + types: OwnedSlice::empty(), + } + }).collect(); + ast::Path { + span: span, global: true, segments: segments, + } + } + + // NOTE: clients using `box ` short-hand need to + // either use `libstd` or must make their own local + // + // ``` + // mod std { mod boxed { pub use ... as HEAP; } + // mod ops { mod placer { ... } } + // mod ptr { pub use ... as write; } } + // ``` + // + // as appropriate. + + let boxed_heap = || -> ast::Path { + let idents = ["std", "boxed", "HEAP"]; + mk_path_for_idents(place_span, idents) + }; + + let _force_placer = || -> ast::Path { + let idents = ["std", "ops", "placer", + "parenthesized_input_to_box_must_be_placer"]; + mk_path_for_idents(place_span, idents) + }; + + let placer_make_place = || -> ast::Path { + let idents = ["std", "ops", "placer", "make_place"]; + mk_path_for_idents(place_span, idents) + }; + + let placer_pointer = || -> ast::Path { + let idents = ["std", "ops", "placer", "pointer"]; + mk_path_for_idents(place_span, idents) + }; + + let placer_finalize = || -> ast::Path { + let idents = ["std", "ops", "placer", "finalize"]; + mk_path_for_idents(place_span, idents) + }; + + let ptr_write = || -> ast::Path { + let idents = ["std", "ptr", "write"]; + mk_path_for_idents(place_span, idents) + }; + + let make_call = |f: ast::Path, args: Vec>| -> P { + fld.cx.expr_call(span, fld.cx.expr_path(f), args) + }; + + let stmt_let = |span, bind, expr| fld.cx.stmt_let(span, false, bind, expr); + + // FIXME RE place2 (pnkfelix): This attempt to encode an + // assertion that the implements `Placer` is + // not working yet; gets type-inference failure with + // message "error: unable to infer enough type information + // to locate the impl of the trait `core::kinds::Sized` + // for the type ``; type annotations required" + // + // So for now pnkfelix is leaving out the `force_placer` + // invocation, which means we may get different type + // inference failures that are hard to diagnose, but at + // least we will be able to get something running. + + fld.cx.expr_block(fld.cx.block_all( + span, + vec![], + vec![ + // let place1 = ; // default of ::std::boxed::HEAP + stmt_let(place_span, place_ident, match maybe_place { + Some(place_expr) => place_expr, + None => fld.cx.expr_path(boxed_heap()), + }), + + // See "FIXME RE place2" above. + // + // // let place2 = force_placer(place1); + // stmt_let(place_span, place2_ident, make_call(force_placer(), vec![place])), + + // let agent = placer::make_place(&place1); + stmt_let(place_span, agent_ident, make_call(placer_make_place(), + vec![fld.cx.expr_addr_of(place_span, place)])), + + // let value = ; + stmt_let(value_span, value_ident, value_expr), + ], + + // unsafe { ptr::write(placer::pointer(&agent), value); + // placer::finalizer(agent) } + { + let call_agent_ptr = make_call(placer_pointer(), + vec![fld.cx.expr_addr_of(place_span, agent.clone())]); + let call_ptr_write = + StmtSemi(make_call(ptr_write(), vec![call_agent_ptr, value]), + ast::DUMMY_NODE_ID); + Some(fld.cx.expr_block(P(ast::Block { + view_items: vec![], + stmts: vec![P(codemap::respan(value_span, call_ptr_write))], + expr: Some(make_call(placer_finalize(), vec![agent])), + id: ast::DUMMY_NODE_ID, + rules: ast::UnsafeBlock(ast::CompilerGenerated), + span: span, + }))) + })) + } + ast::ExprWhile(cond, body, opt_ident) => { let cond = fld.fold_expr(cond); let (body, opt_ident) = expand_loop_block(body, opt_ident, fld); diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 5e29167bf1a29..4596675362b21 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1168,7 +1168,7 @@ pub fn noop_fold_expr(Expr {id, node, span}: Expr, folder: &mut T) -> id: folder.new_id(id), node: match node { ExprBox(p, e) => { - ExprBox(folder.fold_expr(p), folder.fold_expr(e)) + ExprBox(p.map(|e|folder.fold_expr(e)), folder.fold_expr(e)) } ExprVec(exprs) => { ExprVec(exprs.move_map(|x| folder.fold_expr(x))) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index ed806ad803ab1..45073f7469f7a 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2749,7 +2749,7 @@ impl<'a> Parser<'a> { self.expect(&token::RPAREN); let subexpression = self.parse_prefix_expr(); hi = subexpression.span.hi; - ex = ExprBox(place, subexpression); + ex = ExprBox(Some(place), subexpression); return self.mk_expr(lo, hi, ex); } } @@ -2757,6 +2757,10 @@ impl<'a> Parser<'a> { // Otherwise, we use the unique pointer default. let subexpression = self.parse_prefix_expr(); hi = subexpression.span.hi; + + // FIXME (pnkfelix): After working out kinks with box + // desugaring, should be `ExprBox(None, subexpression)` + // instead. ex = self.mk_unary(UnUniq, subexpression); } _ => return self.parse_dot_or_call_expr() diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index cdcbeedddb239..448d2902056ae 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1400,7 +1400,7 @@ impl<'a> State<'a> { ast::ExprBox(ref p, ref e) => { try!(word(&mut self.s, "box")); try!(word(&mut self.s, "(")); - try!(self.print_expr(&**p)); + try!(p.as_ref().map_or(Ok(()), |e|self.print_expr(&**e))); try!(self.word_space(")")); try!(self.print_expr(&**e)); } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 00377a324a768..588dedd8839b9 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -672,7 +672,7 @@ pub fn walk_mac<'v, V: Visitor<'v>>(_: &mut V, _: &'v Mac) { pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { match expression.node { ExprBox(ref place, ref subexpression) => { - visitor.visit_expr(&**place); + place.as_ref().map(|e|visitor.visit_expr(&**e)); visitor.visit_expr(&**subexpression) } ExprVec(ref subexpressions) => { diff --git a/src/test/compile-fail/issue-14084.rs b/src/test/compile-fail/issue-14084.rs index d247bf0913c3b..352b9f703ae00 100644 --- a/src/test/compile-fail/issue-14084.rs +++ b/src/test/compile-fail/issue-14084.rs @@ -10,5 +10,8 @@ fn main() { box ( () ) 0; - //~^ ERROR: only the managed heap and exchange heap are currently supported + //~^ ERROR: is not implemented for the type `()` + + // FIXME (pnkfelix): can we improve on the expected error (or + // better still, improve the actual error itself)? } From 53865bcdf80afcb7f3a032c7797ec7756f8e7400 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 22 Oct 2014 17:10:27 +0200 Subject: [PATCH 2/7] Add tests for user-defined use of `box () `. --- .../placement-box-user-defined-fail.rs | 120 +++++++++++ .../run-pass/placement-box-user-defined.rs | 196 ++++++++++++++++++ 2 files changed, 316 insertions(+) create mode 100644 src/test/run-fail/placement-box-user-defined-fail.rs create mode 100644 src/test/run-pass/placement-box-user-defined.rs diff --git a/src/test/run-fail/placement-box-user-defined-fail.rs b/src/test/run-fail/placement-box-user-defined-fail.rs new file mode 100644 index 0000000000000..7e63cfa6a2410 --- /dev/null +++ b/src/test/run-fail/placement-box-user-defined-fail.rs @@ -0,0 +1,120 @@ +// Copyright 2012-2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// error-pattern:the right fail + +#![feature(unsafe_destructor)] + +use std::cell::Cell; +use std::kinds::marker; +use std::mem; +use std::ops::{Placer,PlacementAgent}; + +#[deriving(PartialEq, Eq, Show)] +enum Entry { + DropInterim(uint), + FinalizeInterim(uint), + DropAtom(&'static str), +} + +type Record = Vec; + +struct Atom { + record: *mut Record, + name: &'static str, +} + +struct InterimAtom { + record: *mut Record, + name_todo: &'static str, + my_count: uint, +} + +struct AtomPool { + record: *mut Record, + total_count: Cell, +} + +struct ExpectDropRecord<'a> { + record: *mut Record, + expect: &'a [Entry], +} + +#[unsafe_destructor] +impl<'a> Drop for ExpectDropRecord<'a> { + fn drop(&mut self) { + unsafe { + assert_eq!((*self.record).as_slice(), self.expect); + } + } +} + +pub fn main() { + let mut record = vec![]; + let record = &mut record as *mut Record; + let pool = &AtomPool::new(record); + + let expect = [FinalizeInterim(0), + DropInterim(1), + DropAtom("hello")]; + let expect = ExpectDropRecord { record: record, expect: expect }; + inner(pool); +} + +fn inner(pool: &AtomPool) { + let a = box (pool) "hello"; + let b = box (pool) { fail!("the right fail"); "world" }; + let c = box (pool) { fail!("we never"); "get here " }; +} + +impl AtomPool { + fn new(record: *mut Record) -> AtomPool { + AtomPool { record: record, total_count: Cell::new(0) } + } +} + +impl<'a> Placer<&'static str, Atom, InterimAtom> for &'a AtomPool { + fn make_place(&self) -> InterimAtom { + let c = self.total_count.get(); + self.total_count.set(c + 1); + InterimAtom { + record: self.record, + name_todo: "", + my_count: c, + } + } +} + +impl PlacementAgent<&'static str, Atom> for InterimAtom { + unsafe fn pointer(&self) -> *mut &'static str { + mem::transmute(&self.name_todo) + } + unsafe fn finalize(self) -> Atom { + unsafe { (*self.record).push(FinalizeInterim(self.my_count)) } + let ret = Atom { + record: self.record, + name: self.name_todo, + }; + mem::forget(self); + ret + } +} + +impl Drop for InterimAtom { + fn drop(&mut self) { + unsafe { (*self.record).push(DropInterim(self.my_count)) } + } +} + +impl Drop for Atom { + fn drop(&mut self) { + unsafe { (*self.record).push(DropAtom(self.name)) } + } +} diff --git a/src/test/run-pass/placement-box-user-defined.rs b/src/test/run-pass/placement-box-user-defined.rs new file mode 100644 index 0000000000000..70acb8897e52f --- /dev/null +++ b/src/test/run-pass/placement-box-user-defined.rs @@ -0,0 +1,196 @@ +// Copyright 2012-2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This test illustrates use of `box () ` syntax to +// allocate and initialize user-defined smart-pointer types. +// +// (Note that the code itself is somewhat naive, especially since you +// wouldn't want to box f32*4 in this way in practice.) + +use std::cell::Cell; +use std::kinds::marker; +use std::mem; +use std::ops::{Placer,PlacementAgent}; + +pub fn main() { + let ref arena = PoolFloat4::new(); + inner(arena); + + let expecting = [true, true, true, true, true]; + assert_eq!(arena.avail_snapshot().as_slice(), expecting.as_slice()); +} + +fn inner(arena: &PoolFloat4) { + let avail = || -> Vec { arena.avail_snapshot() }; + + let expecting = [true, true, true, true, true]; + assert_eq!(avail().as_slice(), expecting.as_slice()); + + let a: BoxFloat4 = box (arena) [1.0, 2.0, 3.0, 4.0]; + + let expecting = [false, true, true, true, true]; + assert_eq!(avail().as_slice(), expecting.as_slice()); + assert_eq!(a.xyzw(), (1.0, 2.0, 3.0, 4.0)); + + let mut order = vec![]; + + let b: BoxFloat4 = box ({ order.push("arena"); arena }) [ + { order.push("10.0"); 10.0 }, + { order.push("20.0"); 20.0 }, + { order.push("30.0"); 30.0 }, + { order.push("40.0"); 40.0 }, + ]; + + let expecting = [false, false, true, true, true]; + assert_eq!(avail().as_slice(), expecting.as_slice()); + assert_eq!(a.xyzw(), (1.0, 2.0, 3.0, 4.0)); + assert_eq!(b.xyzw(), (10.0, 20.0, 30.0, 40.0)); + assert_eq!(order, vec!["arena", "10.0", "20.0", "30.0", "40.0"]); + + { + let c: BoxFloat4 = box (arena) [100.0, 200.0, 300.0, 400.0]; + let expecting = [false, false, false, true, true]; + assert_eq!(avail().as_slice(), expecting.as_slice()); + assert_eq!(a.xyzw(), (1.0, 2.0, 3.0, 4.0)); + assert_eq!(b.xyzw(), (10.0, 20.0, 30.0, 40.0)); + assert_eq!(c.xyzw(), (100.0, 200.0, 300.0, 400.0)); + } + + let expecting = [false, false, true, true, true]; + assert_eq!(avail().as_slice(), expecting.as_slice()); + assert_eq!(a.xyzw(), (1.0, 2.0, 3.0, 4.0)); + assert_eq!(b.xyzw(), (10.0, 20.0, 30.0, 40.0)); +} + +struct BoxFloat4 { + arena: *mut PoolFloat4, + f4: *mut f32, +} + +impl BoxFloat4 { + fn x(&self) -> f32 { unsafe { *self.f4.offset(0) } } + fn y(&self) -> f32 { unsafe { *self.f4.offset(1) } } + fn z(&self) -> f32 { unsafe { *self.f4.offset(2) } } + fn w(&self) -> f32 { unsafe { *self.f4.offset(3) } } + + fn xyzw(&self) -> (f32,f32,f32,f32) { + (self.x(), self.y(), self.z(), self.w()) + } +} + +struct InterimBoxFloat4 { + arena: *mut PoolFloat4, + f4: *mut f32, +} + +struct PoolFloat4 { + pool: [f32, ..20], + avail: [Cell, ..5], + no_copy: marker::NoCopy, +} + +impl PoolFloat4 { + fn new() -> PoolFloat4 { + let ret = PoolFloat4 { + pool: [0.0, ..20], + avail: [Cell::new(true), + Cell::new(true), + Cell::new(true), + Cell::new(true), + Cell::new(true), + ], + no_copy: marker::NoCopy, + }; + + ret + } + + fn avail_snapshot(&self) -> Vec { + self.avail.iter().map(|c|c.get()).collect() + } + + fn first_avail(&self) -> Option { + for i in range(0u, 5) { + if self.avail[i].get() { + return Some(i); + } + } + None + } + + fn find_entry(&self, p: *mut f32) -> Option { + for i in range(0u, 5) { + let ptr : &f32 = &self.pool[i*4]; + let cand: *mut f32 = unsafe { mem::transmute(ptr) }; + if p == cand { + return Some(i); + } + } + None + } + + unsafe fn mark_freed(&mut self, p: *mut f32) { + let i = match self.find_entry(p) { + Some(i) => i, + None => { + // (avoiding fail! in drop) + println!("interim internal consistency failure."); + return; + } + }; + self.avail[i].set(true); + assert_eq!(self.avail[i].get(), true); + } +} + +impl<'a> Placer<[f32, ..4], BoxFloat4, InterimBoxFloat4> + for &'a PoolFloat4 { + fn make_place(&self) -> InterimBoxFloat4 { + let i = self.first_avail() + .unwrap_or_else(|| fail!("exhausted all spots")); + + self.avail[i].set(false); + assert_eq!(self.avail[i].get(), false); + unsafe { + InterimBoxFloat4 { arena: mem::transmute(*self), + f4: mem::transmute(&self.pool[i*4]) } + } + } +} + +impl PlacementAgent<[f32, ..4], BoxFloat4> for InterimBoxFloat4 { + unsafe fn pointer(&self) -> *mut [f32, ..4] { + self.f4 as *mut [f32, ..4] + } + + unsafe fn finalize(self) -> BoxFloat4 { + let ret = BoxFloat4 { arena: self.arena, f4: self.f4 }; + mem::forget(self); + ret + } +} + +impl Drop for InterimBoxFloat4 { + fn drop(&mut self) { + unsafe { + let a : &mut PoolFloat4 = mem::transmute(self.arena); + a.mark_freed(self.f4); + } + } +} + +impl Drop for BoxFloat4 { + fn drop(&mut self) { + unsafe { + let a : &mut PoolFloat4 = mem::transmute(self.arena); + a.mark_freed(self.f4); + } + } +} From 040cf98262bd13d74cc48c5553959e5897be8f88 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 22 Oct 2014 17:43:14 +0200 Subject: [PATCH 3/7] placate `make tidy`. --- src/libsyntax/ext/expand.rs | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 5c9663012bce5..02ac733f4312e 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -204,8 +204,10 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { // stmt_let(place_span, place2_ident, make_call(force_placer(), vec![place])), // let agent = placer::make_place(&place1); - stmt_let(place_span, agent_ident, make_call(placer_make_place(), - vec![fld.cx.expr_addr_of(place_span, place)])), + stmt_let(place_span, agent_ident, + make_call(placer_make_place(), + vec![fld.cx.expr_addr_of(place_span, + place)])), // let value = ; stmt_let(value_span, value_ident, value_expr), @@ -214,14 +216,20 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { // unsafe { ptr::write(placer::pointer(&agent), value); // placer::finalizer(agent) } { - let call_agent_ptr = make_call(placer_pointer(), - vec![fld.cx.expr_addr_of(place_span, agent.clone())]); + let call_agent_ptr = + make_call(placer_pointer(), + vec![fld.cx.expr_addr_of(place_span, + agent.clone())]); let call_ptr_write = - StmtSemi(make_call(ptr_write(), vec![call_agent_ptr, value]), + StmtSemi(make_call(ptr_write(), + vec![call_agent_ptr, value]), ast::DUMMY_NODE_ID); + let call_ptr_write = + codemap::respan(value_span, call_ptr_write); + Some(fld.cx.expr_block(P(ast::Block { view_items: vec![], - stmts: vec![P(codemap::respan(value_span, call_ptr_write))], + stmts: vec![P(call_ptr_write)], expr: Some(make_call(placer_finalize(), vec![agent])), id: ast::DUMMY_NODE_ID, rules: ast::UnsafeBlock(ast::CompilerGenerated), From 452ecab4d80bd06f3e862a226109166c5dc8369a Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 23 Oct 2014 18:07:46 +0200 Subject: [PATCH 4/7] Revise the protocol to avoid inadvertantly moving the Placer. --- src/libcore/ops.rs | 2 +- src/libsyntax/ext/expand.rs | 23 +++++++++++------------ 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 22ea7a76c336d..679bb20e58ce4 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -920,7 +920,7 @@ pub mod placer { /// The first argument, `` in `box () `, must /// implement `Placer`. - pub fn parenthesized_input_to_box_must_be_placer(p: P) -> P + pub fn parenthesized_input_to_box_must_be_placer<'a, Sized? Data, Owner, A, P>(p: &'a P) -> &'a P where A:PlacementAgent, P:Placer+Sized { p diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 02ac733f4312e..29e80fa335921 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -88,8 +88,8 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { // analogous to: // // { - // fn force_placer(p: P) -> P where P : Placer { p } - // let place = force_placer(); + // fn force_placer<'a, D,T,I,P>(p: &'a P) -> &'a P where P : Placer { p } + // let place = force_placer(& ); // let agent = place.make_place(); // let value = // unsafe { @@ -192,22 +192,21 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { span, vec![], vec![ - // let place1 = ; // default of ::std::boxed::HEAP - stmt_let(place_span, place_ident, match maybe_place { - Some(place_expr) => place_expr, - None => fld.cx.expr_path(boxed_heap()), - }), + // let place1 = & ; // default of ::std::boxed::HEAP + stmt_let(place_span, + place_ident, + fld.cx.expr_addr_of(place_span, match maybe_place { + Some(place_expr) => place_expr, + None => fld.cx.expr_path(boxed_heap()), + })), // See "FIXME RE place2" above. // // // let place2 = force_placer(place1); // stmt_let(place_span, place2_ident, make_call(force_placer(), vec![place])), - // let agent = placer::make_place(&place1); - stmt_let(place_span, agent_ident, - make_call(placer_make_place(), - vec![fld.cx.expr_addr_of(place_span, - place)])), + // let agent = placer::make_place(place1); + stmt_let(place_span, agent_ident, make_call(placer_make_place(), vec![place])), // let value = ; stmt_let(value_span, value_ident, value_expr), From 731e9bac8b8f7688b2d698c4ccfeae82fb3c9a13 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 23 Oct 2014 18:08:26 +0200 Subject: [PATCH 5/7] A new test: illustrate use of box with emplacing into back of Vec. --- .../run-pass/placement-box-emplace-back.rs | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 src/test/run-pass/placement-box-emplace-back.rs diff --git a/src/test/run-pass/placement-box-emplace-back.rs b/src/test/run-pass/placement-box-emplace-back.rs new file mode 100644 index 0000000000000..d2ce863227db2 --- /dev/null +++ b/src/test/run-pass/placement-box-emplace-back.rs @@ -0,0 +1,86 @@ +// Copyright 2012-2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This test illustrates use of `box () ` syntax to +// initialize into the end of a Vec. + +#![feature(unsafe_destructor)] + +use std::cell::{UnsafeCell}; +use std::ops::{Placer,PlacementAgent}; + +struct EmplaceBack<'a, T:'a> { + vec: &'a mut Vec, +} + +pub fn main() { + let mut v : Vec<[f32, ..4]> = vec![]; + v.push([10., 20., 30., 40.]); + v.push([11., 21., 31., 41.]); + let mut pv = EmplaceBack { vec: &mut v }; + let () = box (pv) [12., 22., 32., 42.]; + let v = pv.vec; + assert!(same_contents( + v.as_slice(), + [[10., 20., 30., 40.], + [11., 21., 31., 41.], + [12., 22., 32., 42.], + ])); +} + +fn same_contents(a: &[[T, ..4]], b: &[[T, ..4]]) -> bool { + assert_eq!(a.len(), b.len()); + let len = a.len(); + for i in range(0, len) { + if a[i].as_slice() != b[i].as_slice() { + return false; + } + } + return true; +} + +struct EmplaceBackAgent { + vec_ptr: *mut Vec, + offset: uint, +} + +impl<'a, T> Placer> for EmplaceBack<'a, T> { + fn make_place(&self) -> EmplaceBackAgent { + let len = self.vec.len(); + let v = self.vec as *mut Vec; + unsafe { + (*v).reserve_additional(1); + } + EmplaceBackAgent { vec_ptr: v, offset: len } + } +} + +impl PlacementAgent for EmplaceBackAgent { + unsafe fn pointer(&self) -> *mut T { + assert_eq!((*self.vec_ptr).len(), self.offset); + assert!(self.offset < (*self.vec_ptr).capacity()); + (*self.vec_ptr).as_mut_ptr().offset(self.offset.to_int().unwrap()) + } + + unsafe fn finalize(self) -> () { + assert_eq!((*self.vec_ptr).len(), self.offset); + assert!(self.offset < (*self.vec_ptr).capacity()); + (*self.vec_ptr).set_len(self.offset + 1); + } +} + +#[unsafe_destructor] +impl Drop for EmplaceBackAgent { + fn drop(&mut self) { + // Do not need to do anything; all `make_place` did was ensure + // we had some space reserved, it did not touch the state of + // the vector itself. + } +} From b2939849a92ad8a76e5f630d08774c3f87cb4672 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 23 Oct 2014 18:24:32 +0200 Subject: [PATCH 6/7] Simplify example so that `emplace_back` is "just" an additional method on Vec. --- .../run-pass/placement-box-emplace-back.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/test/run-pass/placement-box-emplace-back.rs b/src/test/run-pass/placement-box-emplace-back.rs index d2ce863227db2..7cf96231b8678 100644 --- a/src/test/run-pass/placement-box-emplace-back.rs +++ b/src/test/run-pass/placement-box-emplace-back.rs @@ -16,17 +16,26 @@ use std::cell::{UnsafeCell}; use std::ops::{Placer,PlacementAgent}; -struct EmplaceBack<'a, T:'a> { +struct EmplaceBackPlacer<'a, T:'a> { vec: &'a mut Vec, } +trait EmplaceBack<'a, T> { + fn emplace_back(&'a mut self) -> EmplaceBackPlacer<'a, T>; +} + +impl<'a, T:'a> EmplaceBack<'a, T> for Vec { + fn emplace_back(&'a mut self) -> EmplaceBackPlacer<'a, T> { + EmplaceBackPlacer { vec: self } + } +} + pub fn main() { let mut v : Vec<[f32, ..4]> = vec![]; v.push([10., 20., 30., 40.]); v.push([11., 21., 31., 41.]); - let mut pv = EmplaceBack { vec: &mut v }; - let () = box (pv) [12., 22., 32., 42.]; - let v = pv.vec; + let () = // (Explicitly showing `box` returns `()` here.) + box (v.emplace_back()) [12., 22., 32., 42.]; assert!(same_contents( v.as_slice(), [[10., 20., 30., 40.], @@ -51,7 +60,7 @@ struct EmplaceBackAgent { offset: uint, } -impl<'a, T> Placer> for EmplaceBack<'a, T> { +impl<'a, T> Placer> for EmplaceBackPlacer<'a, T> { fn make_place(&self) -> EmplaceBackAgent { let len = self.vec.len(); let v = self.vec as *mut Vec; From 3b47ea4f3349fb4d1aed63b5045f17cf805dd0fe Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 24 Oct 2014 11:05:11 +0200 Subject: [PATCH 7/7] Switched Placer API to take `&mut self` rather than `&self`. This made some things cleaner (e.g. I got to get rid of the `Cell` in the `AtomPool` example). But it also highlights some weaknesses in my current expansion -- namely, my use of top-level functions rather than methods means that I am currently forced to make sure I have the right level of borrowing in the PLACER input in `box (PLACER) EXPR`. I will look into my options there -- it may be that the right thing is just to switch to method invocations. --- src/liballoc/boxed.rs | 4 +- src/libcore/ops.rs | 6 +-- src/libsyntax/ext/expand.rs | 8 +-- .../placement-box-user-defined-fail.rs | 16 +++--- .../run-pass/placement-box-emplace-back.rs | 2 +- .../run-pass/placement-box-user-defined.rs | 53 +++++++++---------- 6 files changed, 42 insertions(+), 47 deletions(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index d4a716d8bb11e..8ef004c3def23 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -40,7 +40,7 @@ use core::result::{Ok, Err, Result}; /// ``` #[lang = "exchange_heap"] #[experimental = "may be renamed; uncertain about custom allocator design"] -pub static HEAP: ExchangeHeapSingleton = +pub const HEAP: ExchangeHeapSingleton = ExchangeHeapSingleton { _force_singleton: () }; /// This the singleton type used solely for `boxed::HEAP`. @@ -76,7 +76,7 @@ pub struct IntermediateBox{ } impl Placer, IntermediateBox> for ExchangeHeapSingleton { - fn make_place(&self) -> IntermediateBox { + fn make_place(&mut self) -> IntermediateBox { let size = mem::size_of::(); let align = mem::align_of::(); diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 679bb20e58ce4..8bd55b57ea377 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -909,7 +909,7 @@ def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 A15) pub trait Placer> { /// Allocates a place for the data to live, returning an /// intermediate agent to negotiate ownership. - fn make_place(&self) -> Interim; + fn make_place(&mut self) -> Interim; } /// Some free functions called by expansions of `box ` and @@ -920,7 +920,7 @@ pub mod placer { /// The first argument, `` in `box () `, must /// implement `Placer`. - pub fn parenthesized_input_to_box_must_be_placer<'a, Sized? Data, Owner, A, P>(p: &'a P) -> &'a P + pub fn parenthesized_input_to_box_must_be_placer<'a, Sized? Data, Owner, A, P>(p: &'a mut P) -> &'a mut P where A:PlacementAgent, P:Placer+Sized { p @@ -932,7 +932,7 @@ pub mod placer { /// `use std::ops::Placer;` and `use std::ops::PlacementAgent;` /// Calls `p.make_place()` as work-around for lack of UFCS. - pub fn make_place(p: &P) -> A + pub fn make_place(p: &mut P) -> A where A:PlacementAgent, P:Placer { p.make_place() diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 29e80fa335921..78702e0b847b2 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -89,7 +89,7 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { // // { // fn force_placer<'a, D,T,I,P>(p: &'a P) -> &'a P where P : Placer { p } - // let place = force_placer(& ); + // let place = force_placer(&mut ); // let agent = place.make_place(); // let value = // unsafe { @@ -177,7 +177,7 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { let stmt_let = |span, bind, expr| fld.cx.stmt_let(span, false, bind, expr); // FIXME RE place2 (pnkfelix): This attempt to encode an - // assertion that the implements `Placer` is + // assertion that the implements `Placer` is // not working yet; gets type-inference failure with // message "error: unable to infer enough type information // to locate the impl of the trait `core::kinds::Sized` @@ -192,10 +192,10 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { span, vec![], vec![ - // let place1 = & ; // default of ::std::boxed::HEAP + // let place1 = &mut ; // default of ::std::boxed::HEAP stmt_let(place_span, place_ident, - fld.cx.expr_addr_of(place_span, match maybe_place { + fld.cx.expr_mut_addr_of(place_span, match maybe_place { Some(place_expr) => place_expr, None => fld.cx.expr_path(boxed_heap()), })), diff --git a/src/test/run-fail/placement-box-user-defined-fail.rs b/src/test/run-fail/placement-box-user-defined-fail.rs index 7e63cfa6a2410..3505eb4f57c3e 100644 --- a/src/test/run-fail/placement-box-user-defined-fail.rs +++ b/src/test/run-fail/placement-box-user-defined-fail.rs @@ -39,7 +39,7 @@ struct InterimAtom { struct AtomPool { record: *mut Record, - total_count: Cell, + total_count: uint, } struct ExpectDropRecord<'a> { @@ -59,7 +59,7 @@ impl<'a> Drop for ExpectDropRecord<'a> { pub fn main() { let mut record = vec![]; let record = &mut record as *mut Record; - let pool = &AtomPool::new(record); + let mut pool = &mut AtomPool::new(record); let expect = [FinalizeInterim(0), DropInterim(1), @@ -68,7 +68,7 @@ pub fn main() { inner(pool); } -fn inner(pool: &AtomPool) { +fn inner(mut pool: &mut AtomPool) { let a = box (pool) "hello"; let b = box (pool) { fail!("the right fail"); "world" }; let c = box (pool) { fail!("we never"); "get here " }; @@ -76,14 +76,14 @@ fn inner(pool: &AtomPool) { impl AtomPool { fn new(record: *mut Record) -> AtomPool { - AtomPool { record: record, total_count: Cell::new(0) } + AtomPool { record: record, total_count: 0 } } } -impl<'a> Placer<&'static str, Atom, InterimAtom> for &'a AtomPool { - fn make_place(&self) -> InterimAtom { - let c = self.total_count.get(); - self.total_count.set(c + 1); +impl<'a> Placer<&'static str, Atom, InterimAtom> for &'a mut AtomPool { + fn make_place(&mut self) -> InterimAtom { + let c = self.total_count; + self.total_count = c + 1; InterimAtom { record: self.record, name_todo: "", diff --git a/src/test/run-pass/placement-box-emplace-back.rs b/src/test/run-pass/placement-box-emplace-back.rs index 7cf96231b8678..bbd57dc029f66 100644 --- a/src/test/run-pass/placement-box-emplace-back.rs +++ b/src/test/run-pass/placement-box-emplace-back.rs @@ -61,7 +61,7 @@ struct EmplaceBackAgent { } impl<'a, T> Placer> for EmplaceBackPlacer<'a, T> { - fn make_place(&self) -> EmplaceBackAgent { + fn make_place(&mut self) -> EmplaceBackAgent { let len = self.vec.len(); let v = self.vec as *mut Vec; unsafe { diff --git a/src/test/run-pass/placement-box-user-defined.rs b/src/test/run-pass/placement-box-user-defined.rs index 70acb8897e52f..ee043724848f0 100644 --- a/src/test/run-pass/placement-box-user-defined.rs +++ b/src/test/run-pass/placement-box-user-defined.rs @@ -20,28 +20,28 @@ use std::mem; use std::ops::{Placer,PlacementAgent}; pub fn main() { - let ref arena = PoolFloat4::new(); + let ref mut arena = PoolFloat4::new(); inner(arena); let expecting = [true, true, true, true, true]; assert_eq!(arena.avail_snapshot().as_slice(), expecting.as_slice()); } -fn inner(arena: &PoolFloat4) { - let avail = || -> Vec { arena.avail_snapshot() }; +fn inner(arena: &mut PoolFloat4) { + fn avail<'a>(arena: &PoolFloat4) -> [bool, ..5] { arena.avail_snapshot() } let expecting = [true, true, true, true, true]; - assert_eq!(avail().as_slice(), expecting.as_slice()); + assert_eq!(avail(arena).as_slice(), expecting.as_slice()); - let a: BoxFloat4 = box (arena) [1.0, 2.0, 3.0, 4.0]; + let a: BoxFloat4 = box (*arena) [1.0, 2.0, 3.0, 4.0]; let expecting = [false, true, true, true, true]; - assert_eq!(avail().as_slice(), expecting.as_slice()); + assert_eq!(avail(arena).as_slice(), expecting.as_slice()); assert_eq!(a.xyzw(), (1.0, 2.0, 3.0, 4.0)); let mut order = vec![]; - let b: BoxFloat4 = box ({ order.push("arena"); arena }) [ + let b: BoxFloat4 = box (*{ order.push("arena"); &mut *arena }) [ { order.push("10.0"); 10.0 }, { order.push("20.0"); 20.0 }, { order.push("30.0"); 30.0 }, @@ -49,22 +49,22 @@ fn inner(arena: &PoolFloat4) { ]; let expecting = [false, false, true, true, true]; - assert_eq!(avail().as_slice(), expecting.as_slice()); + assert_eq!(avail(arena).as_slice(), expecting.as_slice()); assert_eq!(a.xyzw(), (1.0, 2.0, 3.0, 4.0)); assert_eq!(b.xyzw(), (10.0, 20.0, 30.0, 40.0)); assert_eq!(order, vec!["arena", "10.0", "20.0", "30.0", "40.0"]); { - let c: BoxFloat4 = box (arena) [100.0, 200.0, 300.0, 400.0]; + let c: BoxFloat4 = box (*arena) [100.0, 200.0, 300.0, 400.0]; let expecting = [false, false, false, true, true]; - assert_eq!(avail().as_slice(), expecting.as_slice()); + assert_eq!(avail(arena).as_slice(), expecting.as_slice()); assert_eq!(a.xyzw(), (1.0, 2.0, 3.0, 4.0)); assert_eq!(b.xyzw(), (10.0, 20.0, 30.0, 40.0)); assert_eq!(c.xyzw(), (100.0, 200.0, 300.0, 400.0)); } let expecting = [false, false, true, true, true]; - assert_eq!(avail().as_slice(), expecting.as_slice()); + assert_eq!(avail(arena).as_slice(), expecting.as_slice()); assert_eq!(a.xyzw(), (1.0, 2.0, 3.0, 4.0)); assert_eq!(b.xyzw(), (10.0, 20.0, 30.0, 40.0)); } @@ -92,7 +92,7 @@ struct InterimBoxFloat4 { struct PoolFloat4 { pool: [f32, ..20], - avail: [Cell, ..5], + avail: [bool, ..5], no_copy: marker::NoCopy, } @@ -100,25 +100,20 @@ impl PoolFloat4 { fn new() -> PoolFloat4 { let ret = PoolFloat4 { pool: [0.0, ..20], - avail: [Cell::new(true), - Cell::new(true), - Cell::new(true), - Cell::new(true), - Cell::new(true), - ], + avail: [true, ..5], no_copy: marker::NoCopy, }; ret } - fn avail_snapshot(&self) -> Vec { - self.avail.iter().map(|c|c.get()).collect() + fn avail_snapshot(&self) -> [bool, ..5] { + self.avail } fn first_avail(&self) -> Option { for i in range(0u, 5) { - if self.avail[i].get() { + if self.avail[i] { return Some(i); } } @@ -145,22 +140,22 @@ impl PoolFloat4 { return; } }; - self.avail[i].set(true); - assert_eq!(self.avail[i].get(), true); + self.avail[i] = true; + assert_eq!(self.avail[i], true); } } impl<'a> Placer<[f32, ..4], BoxFloat4, InterimBoxFloat4> - for &'a PoolFloat4 { - fn make_place(&self) -> InterimBoxFloat4 { + for PoolFloat4 { + fn make_place(&mut self) -> InterimBoxFloat4 { let i = self.first_avail() .unwrap_or_else(|| fail!("exhausted all spots")); - self.avail[i].set(false); - assert_eq!(self.avail[i].get(), false); + self.avail[i] = false; + assert_eq!(self.avail[i], false); unsafe { - InterimBoxFloat4 { arena: mem::transmute(*self), - f4: mem::transmute(&self.pool[i*4]) } + let f4 : *mut f32 = mem::transmute(&self.pool[i*4]); + InterimBoxFloat4 { arena: mem::transmute(self), f4: f4 } } } }