diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index d9653cecc73cf..acf2209423323 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -55,13 +55,16 @@ use core::prelude::*; +use heap; + use core::any::Any; use core::cmp::Ordering; use core::fmt; use core::hash::{self, Hash}; -use core::marker::Unsize; +use core::marker::{self, Unsize}; use core::mem; use core::ops::{CoerceUnsized, Deref, DerefMut}; +use core::ops::{Placer, Boxed, Place, InPlace, BoxPlace}; use core::ptr::Unique; use core::raw::{TraitObject}; @@ -72,7 +75,7 @@ use core::raw::{TraitObject}; /// /// ``` /// # #![feature(box_heap)] -/// #![feature(box_syntax)] +/// #![feature(box_syntax, placement_in_syntax)] /// use std::boxed::HEAP; /// /// fn main() { @@ -83,7 +86,12 @@ use core::raw::{TraitObject}; #[lang = "exchange_heap"] #[unstable(feature = "box_heap", reason = "may be renamed; uncertain about custom allocator design")] -pub const HEAP: () = (); +pub const HEAP: ExchangeHeapSingleton = + ExchangeHeapSingleton { _force_singleton: () }; + +/// This the singleton type used solely for `boxed::HEAP`. +#[derive(Copy, Clone)] +pub struct ExchangeHeapSingleton { _force_singleton: () } /// A pointer type for heap allocation. /// @@ -91,7 +99,97 @@ pub const HEAP: () = (); #[lang = "owned_box"] #[stable(feature = "rust1", since = "1.0.0")] #[fundamental] -pub struct Box(Unique); +pub struct Box(Unique); + +/// `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). +#[unstable(feature = "placement_in", reason = "placement box design is still being worked out.")] +pub struct IntermediateBox{ + ptr: *mut u8, + size: usize, + align: usize, + marker: marker::PhantomData<*mut T>, +} + +impl Place for IntermediateBox { + fn pointer(&mut self) -> *mut T { + unsafe { ::core::mem::transmute(self.ptr) } + } +} + +unsafe fn finalize(b: IntermediateBox) -> Box { + let p = b.ptr as *mut T; + mem::forget(b); + mem::transmute(p) +} + +fn make_place() -> IntermediateBox { + let size = mem::size_of::(); + let align = mem::align_of::(); + + let p = if size == 0 { + heap::EMPTY as *mut u8 + } else { + let p = unsafe { + heap::allocate(size, align) + }; + if p.is_null() { + panic!("Box make_place allocation failure."); + } + p + }; + + IntermediateBox { ptr: p, size: size, align: align, marker: marker::PhantomData } +} + +impl BoxPlace for IntermediateBox { + fn make_place() -> IntermediateBox { make_place() } +} + +impl InPlace for IntermediateBox { + type Owner = Box; + unsafe fn finalize(self) -> Box { finalize(self) } +} + +impl Boxed for Box { + type Data = T; + type Place = IntermediateBox; + unsafe fn finalize(b: IntermediateBox) -> Box { finalize(b) } +} + +impl Placer for ExchangeHeapSingleton { + type Place = IntermediateBox; + + fn make_place(self) -> IntermediateBox { + make_place() + } +} + +impl Drop for IntermediateBox { + fn drop(&mut self) { + if self.size > 0 { + unsafe { + heap::deallocate(self.ptr, self.size, self.align) + } + } + } +} impl Box { /// Allocates memory on the heap and then moves `x` into it. @@ -199,8 +297,7 @@ impl Clone for Box { /// let y = x.clone(); /// ``` #[inline] - fn clone(&self) -> Box { box {(**self).clone()} } - + fn clone(&self) -> Box { box (HEAP) {(**self).clone()} } /// Copies `source`'s contents into `self` without creating a new allocation. /// /// # Examples diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index ead0b4259a987..f66495c4057c4 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -70,6 +70,8 @@ test(no_crate_inject))] #![no_std] +// SNAP d4432b3 +#![allow(unused_features)] // until feature(placement_in_syntax) is in snap #![feature(allocator)] #![feature(box_syntax)] #![feature(coerce_unsized)] @@ -82,6 +84,8 @@ #![feature(no_std)] #![feature(nonzero)] #![feature(optin_builtin_traits)] +#![feature(placement_in_syntax)] +#![feature(placement_new_protocol)] #![feature(raw)] #![feature(staged_api)] #![feature(unboxed_closures)] diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index ef022179772c4..1d466895f2cfb 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -184,6 +184,14 @@ extern "rust-intrinsic" { /// elements. pub fn size_of() -> usize; + #[cfg(not(stage0))] + /// Moves a value to an uninitialized memory location. + /// + /// Drop glue is not run on the destination. + pub fn move_val_init(dst: *mut T, src: T); + + // SNAP d4432b3 + #[cfg(stage0)] /// Moves a value to an uninitialized memory location. /// /// Drop glue is not run on the destination. diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index c2a9b8c8308cd..2ea42011a5cf2 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -1266,3 +1266,120 @@ impl, U: ?Sized> CoerceUnsized<*const U> for *mut T {} // *const T -> *const U impl, U: ?Sized> CoerceUnsized<*const U> for *const T {} + +/// Both `in (PLACE) EXPR` and `box EXPR` desugar into expressions +/// that allocate an intermediate "place" that holds uninitialized +/// state. The desugaring evaluates EXPR, and writes the result at +/// the address returned by the `pointer` method of this trait. +/// +/// A `Place` can be thought of as a special representation for a +/// hypothetical `&uninit` reference (which Rust cannot currently +/// express directly). That is, it represents a pointer to +/// uninitialized storage. +/// +/// The client is responsible for two steps: First, initializing the +/// payload (it can access its address via `pointer`). Second, +/// converting the agent to an instance of the owning pointer, via the +/// appropriate `finalize` method (see the `InPlace`. +/// +/// If evaluating EXPR fails, then the destructor for the +/// implementation of Place to clean up any intermediate state +/// (e.g. deallocate box storage, pop a stack, etc). +#[unstable(feature = "placement_new_protocol")] +pub trait Place { + /// Returns the address where the input value will be written. + /// Note that the data at this address is generally uninitialized, + /// and thus one should use `ptr::write` for initializing it. + fn pointer(&mut self) -> *mut Data; +} + +/// Interface to implementations of `in (PLACE) EXPR`. +/// +/// `in (PLACE) EXPR` effectively desugars into: +/// +/// ```rust,ignore +/// let p = PLACE; +/// let mut place = Placer::make_place(p); +/// let raw_place = Place::pointer(&mut place); +/// let value = EXPR; +/// unsafe { +/// std::ptr::write(raw_place, value); +/// InPlace::finalize(place) +/// } +/// ``` +/// +/// The type of `in (PLACE) EXPR` is derived from the type of `PLACE`; +/// if the type of `PLACE` is `P`, then the final type of the whole +/// expression is `P::Place::Owner` (see the `InPlace` and `Boxed` +/// traits). +/// +/// Values for types implementing this trait usually are transient +/// intermediate values (e.g. the return value of `Vec::emplace_back`) +/// or `Copy`, since the `make_place` method takes `self` by value. +#[unstable(feature = "placement_new_protocol")] +pub trait Placer { + /// `Place` is the intermedate agent guarding the + /// uninitialized state for `Data`. + type Place: InPlace; + + /// Creates a fresh place from `self`. + fn make_place(self) -> Self::Place; +} + +/// Specialization of `Place` trait supporting `in (PLACE) EXPR`. +#[unstable(feature = "placement_new_protocol")] +pub trait InPlace: Place { + /// `Owner` is the type of the end value of `in (PLACE) EXPR` + /// + /// Note that when `in (PLACE) EXPR` is solely used for + /// side-effecting an existing data-structure, + /// e.g. `Vec::emplace_back`, then `Owner` need not carry any + /// information at all (e.g. it can be the unit type `()` in that + /// case). + type Owner; + + /// Converts self into the final value, shifting + /// deallocation/cleanup responsibilities (if any remain), over to + /// the returned instance of `Owner` and forgetting self. + unsafe fn finalize(self) -> Self::Owner; +} + +/// Core trait for the `box EXPR` form. +/// +/// `box EXPR` effectively desugars into: +/// +/// ```rust,ignore +/// let mut place = BoxPlace::make_place(); +/// let raw_place = Place::pointer(&mut place); +/// let value = EXPR; +/// unsafe { +/// ::std::ptr::write(raw_place, value); +/// Boxed::finalize(place) +/// } +/// ``` +/// +/// The type of `box EXPR` is supplied from its surrounding +/// context; in the above expansion, the result type `T` is used +/// to determine which implementation of `Boxed` to use, and that +/// `` in turn dictates determines which +/// implementation of `BoxPlace` to use, namely: +/// `<::Place as BoxPlace>`. +#[unstable(feature = "placement_new_protocol")] +pub trait Boxed { + /// The kind of data that is stored in this kind of box. + type Data; /* (`Data` unused b/c cannot yet express below bound.) */ + /// The place that will negotiate the storage of the data. + type Place: BoxPlace; + + /// Converts filled place into final owning value, shifting + /// deallocation/cleanup responsibilities (if any remain), over to + /// returned instance of `Self` and forgetting `filled`. + unsafe fn finalize(filled: Self::Place) -> Self; +} + +/// Specialization of `Place` trait supporting `box EXPR`. +#[unstable(feature = "placement_new_protocol")] +pub trait BoxPlace : Place { + /// Creates a globally fresh place. + fn make_place() -> Self; +} diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index b2a064bf86c6a..3fe1e2f5e8369 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -10,7 +10,7 @@ //! Enforces the Rust effect system. Currently there is just one effect, //! `unsafe`. -use self::UnsafeContext::*; +use self::RootUnsafeContext::*; use middle::def; use middle::ty::{self, Ty}; @@ -21,8 +21,20 @@ use syntax::codemap::Span; use syntax::visit; use syntax::visit::Visitor; +#[derive(Copy, Clone)] +struct UnsafeContext { + push_unsafe_count: usize, + root: RootUnsafeContext, +} + +impl UnsafeContext { + fn new(root: RootUnsafeContext) -> UnsafeContext { + UnsafeContext { root: root, push_unsafe_count: 0 } + } +} + #[derive(Copy, Clone, PartialEq)] -enum UnsafeContext { +enum RootUnsafeContext { SafeContext, UnsafeFn, UnsafeBlock(ast::NodeId), @@ -44,7 +56,8 @@ struct EffectCheckVisitor<'a, 'tcx: 'a> { impl<'a, 'tcx> EffectCheckVisitor<'a, 'tcx> { fn require_unsafe(&mut self, span: Span, description: &str) { - match self.unsafe_context { + if self.unsafe_context.push_unsafe_count > 0 { return; } + match self.unsafe_context.root { SafeContext => { // Report an error. span_err!(self.tcx.sess, span, E0133, @@ -75,9 +88,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { let old_unsafe_context = self.unsafe_context; if is_unsafe_fn { - self.unsafe_context = UnsafeFn + self.unsafe_context = UnsafeContext::new(UnsafeFn) } else if is_item_fn { - self.unsafe_context = SafeContext + self.unsafe_context = UnsafeContext::new(SafeContext) } visit::walk_fn(self, fn_kind, fn_decl, block, span); @@ -105,10 +118,18 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { // external blocks (e.g. `unsafe { println("") }`, // expands to `unsafe { ... unsafe { ... } }` where // the inner one is compiler generated). - if self.unsafe_context == SafeContext || source == ast::CompilerGenerated { - self.unsafe_context = UnsafeBlock(block.id) + if self.unsafe_context.root == SafeContext || source == ast::CompilerGenerated { + self.unsafe_context.root = UnsafeBlock(block.id) } } + ast::PushUnsafeBlock(..) => { + self.unsafe_context.push_unsafe_count = + self.unsafe_context.push_unsafe_count.checked_add(1).unwrap(); + } + ast::PopUnsafeBlock(..) => { + self.unsafe_context.push_unsafe_count = + self.unsafe_context.push_unsafe_count.checked_sub(1).unwrap(); + } } visit::walk_block(self, block); @@ -162,7 +183,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { pub fn check_crate(tcx: &ty::ctxt) { let mut visitor = EffectCheckVisitor { tcx: tcx, - unsafe_context: SafeContext, + unsafe_context: UnsafeContext::new(SafeContext), }; visit::walk_crate(&mut visitor, tcx.map.krate()); diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 54fc2daff2b8e..f27a96545ddfa 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -555,6 +555,11 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> { None => {} } self.consume_expr(&**base); + if place.is_some() { + self.tcx().sess.span_bug( + expr.span, + "box with explicit place remains after expansion"); + } } ast::ExprMac(..) => { diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 30553d62719bf..6d3bc7fb68c14 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -543,9 +543,19 @@ pub fn check_pat(tcx: &ty::ctxt, pat: &ast::Pat, fn maybe_do_stability_check(tcx: &ty::ctxt, id: ast::DefId, span: Span, cb: &mut FnMut(ast::DefId, Span, &Option<&Stability>)) { - if !is_staged_api(tcx, id) { return } - if is_internal(tcx, span) { return } + if !is_staged_api(tcx, id) { + debug!("maybe_do_stability_check: \ + skipping id={:?} since it is not staged_api", id); + return; + } + if is_internal(tcx, span) { + debug!("maybe_do_stability_check: \ + skipping span={:?} since it is internal", span); + return; + } let ref stability = lookup(tcx, id); + debug!("maybe_do_stability_check: \ + inspecting id={:?} span={:?} of stability={:?}", id, span, stability); cb(id, span, stability); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index d77d48eea48c2..9486e4953f851 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -232,12 +232,13 @@ impl<'tcx> Expectation<'tcx> { pub struct UnsafetyState { pub def: ast::NodeId, pub unsafety: ast::Unsafety, + pub unsafe_push_count: u32, from_fn: bool } impl UnsafetyState { pub fn function(unsafety: ast::Unsafety, def: ast::NodeId) -> UnsafetyState { - UnsafetyState { def: def, unsafety: unsafety, from_fn: true } + UnsafetyState { def: def, unsafety: unsafety, unsafe_push_count: 0, from_fn: true } } pub fn recurse(&mut self, blk: &ast::Block) -> UnsafetyState { @@ -249,13 +250,20 @@ impl UnsafetyState { ast::Unsafety::Unsafe if self.from_fn => *self, unsafety => { - let (unsafety, def) = match blk.rules { - ast::UnsafeBlock(..) => (ast::Unsafety::Unsafe, blk.id), - ast::DefaultBlock => (unsafety, self.def), + let (unsafety, def, count) = match blk.rules { + ast::PushUnsafeBlock(..) => + (unsafety, blk.id, self.unsafe_push_count.checked_add(1).unwrap()), + ast::PopUnsafeBlock(..) => + (unsafety, blk.id, self.unsafe_push_count.checked_sub(1).unwrap()), + ast::UnsafeBlock(..) => + (ast::Unsafety::Unsafe, blk.id, self.unsafe_push_count), + ast::DefaultBlock => + (unsafety, self.def, self.unsafe_push_count), }; UnsafetyState{ def: def, - unsafety: unsafety, - from_fn: false } + unsafety: unsafety, + unsafe_push_count: count, + from_fn: false } } } } @@ -4884,9 +4892,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { "move_val_init" => { (1, vec!( - tcx.mk_mut_ref(tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), - ty::BrAnon(0))), - param(ccx, 0)), + tcx.mk_mut_ptr(param(ccx, 0)), param(ccx, 0) ), tcx.mk_nil()) diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 82bc1314ad547..907eb3ed401ff 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -203,6 +203,7 @@ test(no_crate_inject, attr(deny(warnings))), test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))))] +#![cfg_attr(stage0, allow(unused_features))] #![feature(alloc)] #![feature(allow_internal_unstable)] #![feature(associated_consts)] @@ -234,6 +235,7 @@ #![feature(no_std)] #![feature(oom)] #![feature(optin_builtin_traits)] +#![feature(placement_in_syntax)] #![feature(rand)] #![feature(raw)] #![feature(reflect_marker)] diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index a0059d33bed84..fba9db401dbb1 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -810,6 +810,8 @@ pub type SpannedIdent = Spanned; pub enum BlockCheckMode { DefaultBlock, UnsafeBlock(UnsafeSource), + PushUnsafeBlock(UnsafeSource), + PopUnsafeBlock(UnsafeSource), } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index e6bc3218897d9..17e6b2c2e12df 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -980,6 +980,10 @@ impl CodeMap { mac_span.lo <= span.lo && span.hi <= mac_span.hi }); + debug!("span_allows_unstable: span: {:?} call_site: {:?} callee: {:?}", + (span.lo, span.hi), + (info.call_site.lo, info.call_site.hi), + info.callee.span.map(|x| (x.lo, x.hi))); debug!("span_allows_unstable: from this expansion? {}, allows unstable? {}", span_comes_from_this_expansion, info.callee.allow_internal_unstable); diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 499562edc0cc9..409ae86db35d4 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -591,6 +591,12 @@ fn initial_syntax_expander_table<'feat>(ecfg: &expand::ExpansionConfig<'feat>) syntax_expanders.insert(intern("cfg"), builtin_normal_expander( ext::cfg::expand_cfg)); + syntax_expanders.insert(intern("push_unsafe"), + builtin_normal_expander( + ext::pushpop_safe::expand_push_unsafe)); + syntax_expanders.insert(intern("pop_unsafe"), + builtin_normal_expander( + ext::pushpop_safe::expand_pop_unsafe)); syntax_expanders.insert(intern("trace_macros"), builtin_normal_expander( ext::trace_macros::expand_trace_macros)); diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 53befc092da88..faa1e5b2f515f 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -33,6 +33,16 @@ use visit; use visit::Visitor; use std_inject; +// Given suffix ["b","c","d"], returns path `::std::b::c::d` when +// `fld.cx.use_std`, and `::core::b::c::d` otherwise. +fn mk_core_path(fld: &mut MacroExpander, + span: Span, + suffix: &[&'static str]) -> ast::Path { + let mut idents = vec![fld.cx.ident_of_std("core")]; + for s in suffix.iter() { idents.push(fld.cx.ident_of(*s)); } + fld.cx.path_global(span, idents) +} + pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { fn push_compiler_expansion(fld: &mut MacroExpander, span: Span, expansion_desc: &str) { fld.cx.bt_push(ExpnInfo { @@ -40,13 +50,26 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { callee: NameAndSpan { name: expansion_desc.to_string(), format: CompilerExpansion, + + // This does *not* mean code generated after + // `push_compiler_expansion` is automatically exempt + // from stability lints; must also tag such code with + // an appropriate span from `fld.cx.backtrace()`. allow_internal_unstable: true, + span: None, }, }); } - e.and_then(|ast::Expr {id, node, span}| match node { + // Sets the expn_id so that we can use unstable methods. + fn allow_unstable(fld: &mut MacroExpander, span: Span) -> Span { + Span { expn_id: fld.cx.backtrace(), ..span } + } + + let expr_span = e.span; + return e.and_then(|ast::Expr {id, node, span}| match node { + // expr_mac should really be expr_ext or something; it's the // entry-point for all syntax extensions. ast::ExprMac(mac) => { @@ -71,6 +94,118 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { }) } + // Desugar ExprBox: `in (PLACE) EXPR` + ast::ExprBox(Some(placer), value_expr) => { + // to: + // + // let p = PLACE; + // let mut place = Placer::make_place(p); + // let raw_place = Place::pointer(&mut place); + // push_unsafe!({ + // std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR )); + // InPlace::finalize(place) + // }) + + // Ensure feature-gate is enabled + feature_gate::check_for_placement_in( + fld.cx.ecfg.features, + &fld.cx.parse_sess.span_diagnostic, + expr_span); + + push_compiler_expansion(fld, expr_span, "placement-in expansion"); + + let value_span = value_expr.span; + let placer_span = placer.span; + + let placer_expr = fld.fold_expr(placer); + let value_expr = fld.fold_expr(value_expr); + + let placer_ident = token::gensym_ident("placer"); + let agent_ident = token::gensym_ident("place"); + let p_ptr_ident = token::gensym_ident("p_ptr"); + + let placer = fld.cx.expr_ident(span, placer_ident); + let agent = fld.cx.expr_ident(span, agent_ident); + let p_ptr = fld.cx.expr_ident(span, p_ptr_ident); + + let make_place = ["ops", "Placer", "make_place"]; + let place_pointer = ["ops", "Place", "pointer"]; + let move_val_init = ["intrinsics", "move_val_init"]; + let inplace_finalize = ["ops", "InPlace", "finalize"]; + + let make_call = |fld: &mut MacroExpander, p, args| { + // We feed in the `expr_span` because codemap's span_allows_unstable + // allows the call_site span to inherit the `allow_internal_unstable` + // setting. + let span_unstable = allow_unstable(fld, expr_span); + let path = mk_core_path(fld, span_unstable, p); + let path = fld.cx.expr_path(path); + let expr_span_unstable = allow_unstable(fld, span); + fld.cx.expr_call(expr_span_unstable, path, args) + }; + + let stmt_let = |fld: &mut MacroExpander, bind, expr| { + fld.cx.stmt_let(placer_span, false, bind, expr) + }; + let stmt_let_mut = |fld: &mut MacroExpander, bind, expr| { + fld.cx.stmt_let(placer_span, true, bind, expr) + }; + + // let placer = ; + let s1 = stmt_let(fld, placer_ident, placer_expr); + + // let mut place = Placer::make_place(placer); + let s2 = { + let call = make_call(fld, &make_place, vec![placer]); + stmt_let_mut(fld, agent_ident, call) + }; + + // let p_ptr = Place::pointer(&mut place); + let s3 = { + let args = vec![fld.cx.expr_mut_addr_of(placer_span, agent.clone())]; + let call = make_call(fld, &place_pointer, args); + stmt_let(fld, p_ptr_ident, call) + }; + + // pop_unsafe!(EXPR)); + let pop_unsafe_expr = pop_unsafe_expr(fld.cx, value_expr, value_span); + + // push_unsafe!({ + // ptr::write(p_ptr, pop_unsafe!()); + // InPlace::finalize(place) + // }) + let expr = { + let call_move_val_init = StmtSemi(make_call( + fld, &move_val_init, vec![p_ptr, pop_unsafe_expr]), ast::DUMMY_NODE_ID); + let call_move_val_init = codemap::respan(value_span, call_move_val_init); + + let call = make_call(fld, &inplace_finalize, vec![agent]); + Some(push_unsafe_expr(fld.cx, vec![P(call_move_val_init)], call, span)) + }; + + let block = fld.cx.block_all(span, vec![s1, s2, s3], expr); + let result = fld.cx.expr_block(block); + fld.cx.bt_pop(); + result + } + + // Issue #22181: + // Eventually a desugaring for `box EXPR` + // (similar to the desugaring above for `in PLACE BLOCK`) + // should go here, desugaring + // + // to: + // + // let mut place = BoxPlace::make_place(); + // let raw_place = Place::pointer(&mut place); + // let value = $value; + // unsafe { + // ::std::ptr::write(raw_place, value); + // Boxed::finalize(place) + // } + // + // But for now there are type-inference issues doing that. + ast::ExprWhile(cond, body, opt_ident) => { let cond = fld.fold_expr(cond); let (body, opt_ident) = expand_loop_block(body, opt_ident, fld); @@ -360,7 +495,26 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { span: span }, fld)) } - }) + }); + + fn push_unsafe_expr(cx: &mut ExtCtxt, stmts: Vec>, + expr: P, span: Span) + -> P { + let rules = ast::PushUnsafeBlock(ast::CompilerGenerated); + cx.expr_block(P(ast::Block { + rules: rules, span: span, id: ast::DUMMY_NODE_ID, + stmts: stmts, expr: Some(expr), + })) + } + + fn pop_unsafe_expr(cx: &mut ExtCtxt, expr: P, span: Span) + -> P { + let rules = ast::PopUnsafeBlock(ast::CompilerGenerated); + cx.expr_block(P(ast::Block { + rules: rules, span: span, id: ast::DUMMY_NODE_ID, + stmts: vec![], expr: Some(expr), + })) + } } /// Expand a (not-ident-style) macro invocation. Returns the result @@ -1504,6 +1658,7 @@ impl<'feat> ExpansionConfig<'feat> { fn enable_trace_macros = allow_trace_macros, fn enable_allow_internal_unstable = allow_internal_unstable, fn enable_custom_derive = allow_custom_derive, + fn enable_pushpop_unsafe = allow_pushpop_unsafe, } } diff --git a/src/libsyntax/ext/pushpop_safe.rs b/src/libsyntax/ext/pushpop_safe.rs new file mode 100644 index 0000000000000..a67d550d3cd21 --- /dev/null +++ b/src/libsyntax/ext/pushpop_safe.rs @@ -0,0 +1,94 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/* + * The compiler code necessary to support the `push_unsafe!` and + * `pop_unsafe!` macros. + * + * This is a hack to allow a kind of "safety hygiene", where a macro + * can generate code with an interior expression that inherits the + * safety of some outer context. + * + * For example, in: + * + * ```rust + * fn foo() { push_unsafe!( { EXPR_1; pop_unsafe!( EXPR_2 ) } ) } + * ``` + * + * the `EXPR_1` is considered to be in an `unsafe` context, + * but `EXPR_2` is considered to be in a "safe" (i.e. checked) context. + * + * For comparison, in: + * + * ```rust + * fn foo() { unsafe { push_unsafe!( { EXPR_1; pop_unsafe!( EXPR_2 ) } ) } } + * ``` + * + * both `EXPR_1` and `EXPR_2` are considered to be in `unsafe` + * contexts. + * + */ + +use ast; +use codemap::Span; +use ext::base::*; +use ext::base; +use ext::build::AstBuilder; +use feature_gate; +use ptr::P; + +enum PushPop { Push, Pop } + +pub fn expand_push_unsafe<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) + -> Box { + expand_pushpop_unsafe(cx, sp, tts, PushPop::Push) +} + +pub fn expand_pop_unsafe<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) + -> Box { + expand_pushpop_unsafe(cx, sp, tts, PushPop::Pop) +} + +fn expand_pushpop_unsafe<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree], + pp: PushPop) -> Box { + feature_gate::check_for_pushpop_syntax( + cx.ecfg.features, &cx.parse_sess.span_diagnostic, sp); + + let mut exprs = match get_exprs_from_tts(cx, sp, tts) { + Some(exprs) => exprs.into_iter(), + None => return DummyResult::expr(sp), + }; + + let expr = match (exprs.next(), exprs.next()) { + (Some(expr), None) => expr, + _ => { + let msg = match pp { + PushPop::Push => "push_unsafe! takes 1 arguments", + PushPop::Pop => "pop_unsafe! takes 1 arguments", + }; + cx.span_err(sp, msg); + return DummyResult::expr(sp); + } + }; + + let source = ast::UnsafeSource::CompilerGenerated; + let check_mode = match pp { + PushPop::Push => ast::BlockCheckMode::PushUnsafeBlock(source), + PushPop::Pop => ast::BlockCheckMode::PopUnsafeBlock(source), + }; + + MacEager::expr(cx.expr_block(P(ast::Block { + stmts: vec![], + expr: Some(expr), + id: ast::DUMMY_NODE_ID, + rules: check_mode, + span: sp + }))) +} diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index ab8cf9ae6b64f..8c6855036f6e9 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -80,6 +80,8 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[ ("visible_private_types", "1.0.0", Active), ("slicing_syntax", "1.0.0", Accepted), ("box_syntax", "1.0.0", Active), + ("placement_in_syntax", "1.0.0", Active), + ("pushpop_unsafe", "1.2.0", Active), ("on_unimplemented", "1.0.0", Active), ("simd_ffi", "1.0.0", Active), ("allocator", "1.0.0", Active), @@ -325,6 +327,9 @@ pub struct Features { pub allow_trace_macros: bool, pub allow_internal_unstable: bool, pub allow_custom_derive: bool, + pub allow_placement_in: bool, + pub allow_box: bool, + pub allow_pushpop_unsafe: bool, pub simd_ffi: bool, pub unmarked_api: bool, pub negate_unsigned: bool, @@ -348,6 +353,9 @@ impl Features { allow_trace_macros: false, allow_internal_unstable: false, allow_custom_derive: false, + allow_placement_in: false, + allow_box: false, + allow_pushpop_unsafe: false, simd_ffi: false, unmarked_api: false, negate_unsigned: false, @@ -358,6 +366,36 @@ impl Features { } } +const EXPLAIN_BOX_SYNTAX: &'static str = + "box expression syntax is experimental; you can call `Box::new` instead."; + +const EXPLAIN_PLACEMENT_IN: &'static str = + "placement-in expression syntax is experimental and subject to change."; + +const EXPLAIN_PUSHPOP_UNSAFE: &'static str = + "push/pop_unsafe macros are experimental and subject to change."; + +pub fn check_for_box_syntax(f: Option<&Features>, diag: &SpanHandler, span: Span) { + if let Some(&Features { allow_box: true, .. }) = f { + return; + } + emit_feature_err(diag, "box_syntax", span, EXPLAIN_BOX_SYNTAX); +} + +pub fn check_for_placement_in(f: Option<&Features>, diag: &SpanHandler, span: Span) { + if let Some(&Features { allow_placement_in: true, .. }) = f { + return; + } + emit_feature_err(diag, "placement_in_syntax", span, EXPLAIN_PLACEMENT_IN); +} + +pub fn check_for_pushpop_syntax(f: Option<&Features>, diag: &SpanHandler, span: Span) { + if let Some(&Features { allow_pushpop_unsafe: true, .. }) = f { + return; + } + emit_feature_err(diag, "pushpop_unsafe", span, EXPLAIN_PUSHPOP_UNSAFE); +} + struct Context<'a> { features: Vec<&'static str>, span_handler: &'a SpanHandler, @@ -366,6 +404,11 @@ struct Context<'a> { } impl<'a> Context<'a> { + fn enable_feature(&mut self, feature: &'static str) { + debug!("enabling feature: {}", feature); + self.features.push(feature); + } + fn gate_feature(&self, feature: &str, span: Span, explain: &str) { let has_feature = self.has_feature(feature); debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", feature, span, has_feature); @@ -488,6 +531,26 @@ impl<'a, 'v> Visitor<'v> for MacroVisitor<'a> { fn visit_attribute(&mut self, attr: &'v ast::Attribute) { self.context.check_attribute(attr, true); } + + fn visit_expr(&mut self, e: &ast::Expr) { + // Issue 22181: overloaded-`box` and placement-`in` are + // implemented via a desugaring expansion, so their feature + // gates go into MacroVisitor since that works pre-expansion. + // + // Issue 22234: we also check during expansion as well. + // But we keep these checks as a pre-expansion check to catch + // uses in e.g. conditionalized code. + + if let ast::ExprBox(None, _) = e.node { + self.context.gate_feature("box_syntax", e.span, EXPLAIN_BOX_SYNTAX); + } + + if let ast::ExprBox(Some(_), _) = e.node { + self.context.gate_feature("placement_in_syntax", e.span, EXPLAIN_PLACEMENT_IN); + } + + visit::walk_expr(self, e); + } } struct PostExpansionVisitor<'a> { @@ -754,7 +817,7 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &SpanHandler, match KNOWN_FEATURES.iter() .find(|& &(n, _, _)| name == n) { Some(&(name, _, Active)) => { - cx.features.push(name); + cx.enable_feature(name); } Some(&(_, _, Removed)) => { span_handler.span_err(mi.span, "feature has been removed"); @@ -787,6 +850,9 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &SpanHandler, allow_trace_macros: cx.has_feature("trace_macros"), allow_internal_unstable: cx.has_feature("allow_internal_unstable"), allow_custom_derive: cx.has_feature("custom_derive"), + allow_placement_in: cx.has_feature("placement_in_syntax"), + allow_box: cx.has_feature("box_syntax"), + allow_pushpop_unsafe: cx.has_feature("pushpop_unsafe"), simd_ffi: cx.has_feature("simd_ffi"), unmarked_api: cx.has_feature("unmarked_api"), negate_unsigned: cx.has_feature("negate_unsigned"), diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index d93af5da13c1e..5424c0b214a4e 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -120,6 +120,7 @@ pub mod ext { pub mod log_syntax; pub mod mtwt; pub mod quote; + pub mod pushpop_safe; pub mod source_util; pub mod trace_macros; diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 4adfa3c311953..c2a2259a80adf 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2612,18 +2612,43 @@ impl<'a> Parser<'a> { ex = ExprAddrOf(m, e); } token::Ident(_, _) => { - if !self.check_keyword(keywords::Box) { + if !self.check_keyword(keywords::Box) && !self.check_keyword(keywords::In) { return self.parse_dot_or_call_expr(); } let lo = self.span.lo; - let box_hi = self.span.hi; + let keyword_hi = self.span.hi; + let is_in = self.token.is_keyword(keywords::In); try!(self.bump()); - // Check for a place: `box(PLACE) EXPR`. + if is_in { + let place = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL)); + let blk = try!(self.parse_block()); + hi = blk.span.hi; + let blk_expr = self.mk_expr(blk.span.lo, blk.span.hi, ExprBlock(blk)); + ex = ExprBox(Some(place), blk_expr); + return Ok(self.mk_expr(lo, hi, ex)); + } + + // FIXME (#22181) Remove `box (PLACE) EXPR` support + // entirely after next release (enabling `(box (EXPR))`), + // since it will be replaced by `in PLACE { EXPR }`, ... + // + // ... but for now: check for a place: `box(PLACE) EXPR`. + if try!(self.eat(&token::OpenDelim(token::Paren)) ){ - // Support `box() EXPR` as the default. + // SNAP d4432b3 + // Enable this warning after snapshot ... + // + // let box_span = mk_sp(lo, self.last_span.hi); + // self.span_warn( + // box_span, + // "deprecated syntax; use the `in` keyword now \ + // (e.g. change `box () ` to \ + // `in { }`)"); + + // Continue supporting `box () EXPR` (temporarily) if !try!(self.eat(&token::CloseDelim(token::Paren)) ){ let place = try!(self.parse_expr_nopanic()); try!(self.expect(&token::CloseDelim(token::Paren))); @@ -2634,10 +2659,15 @@ impl<'a> Parser<'a> { self.span_err(span, &format!("expected expression, found `{}`", this_token_to_string)); - let box_span = mk_sp(lo, box_hi); + + // Spanning just keyword avoids constructing + // printout of arg expression (which starts + // with parenthesis, as established above). + + let box_span = mk_sp(lo, keyword_hi); self.span_suggestion(box_span, - "try using `box()` instead:", - "box()".to_string()); + "try using `box ()` instead:", + format!("box ()")); self.abort_if_errors(); } let subexpression = try!(self.parse_prefix_expr()); @@ -2650,6 +2680,7 @@ impl<'a> Parser<'a> { // Otherwise, we use the unique pointer default. let subexpression = try!(self.parse_prefix_expr()); hi = subexpression.span.hi; + // FIXME (pnkfelix): After working out kinks with box // desugaring, should be `ExprBox(None, subexpression)` // instead. diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 6693eed6aced5..448857389da61 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1434,8 +1434,8 @@ impl<'a> State<'a> { attrs: &[ast::Attribute], close_box: bool) -> io::Result<()> { match blk.rules { - ast::UnsafeBlock(..) => try!(self.word_space("unsafe")), - ast::DefaultBlock => () + ast::UnsafeBlock(..) | ast::PushUnsafeBlock(..) => try!(self.word_space("unsafe")), + ast::DefaultBlock | ast::PopUnsafeBlock(..) => () } try!(self.maybe_print_comment(blk.span.lo)); try!(self.ann.pre(self, NodeBlock(blk))); diff --git a/src/test/compile-fail/feature-gate-box-expr.rs b/src/test/compile-fail/feature-gate-box-expr.rs index 8f8b035f4a96b..9640b2b475b6a 100644 --- a/src/test/compile-fail/feature-gate-box-expr.rs +++ b/src/test/compile-fail/feature-gate-box-expr.rs @@ -8,15 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn main() { - use std::boxed::HEAP; +// Check that `box EXPR` is feature-gated. +// +// See also feature-gate-placement-expr.rs +// +// (Note that the two tests are separated since the checks appear to +// be performed at distinct phases, with an abort_if_errors call +// separating them.) +fn main() { let x = box 'c'; //~ ERROR box expression syntax is experimental println!("x: {}", x); let x = box () 'c'; //~ ERROR box expression syntax is experimental println!("x: {}", x); - - let x = box (HEAP) 'c'; //~ ERROR box expression syntax is experimental - println!("x: {}", x); } diff --git a/src/test/compile-fail/feature-gate-placement-expr.rs b/src/test/compile-fail/feature-gate-placement-expr.rs new file mode 100644 index 0000000000000..64a1d49f9600c --- /dev/null +++ b/src/test/compile-fail/feature-gate-placement-expr.rs @@ -0,0 +1,27 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Check that `in PLACE { EXPR }` is feature-gated. +// +// See also feature-gate-box-expr.rs +// +// (Note that the two tests are separated since the checks appear to +// be performed at distinct phases, with an abort_if_errors call +// separating them.) + +fn main() { + use std::boxed::HEAP; + + let x = box (HEAP) 'c'; //~ ERROR placement-in expression syntax is experimental + println!("x: {}", x); + + let x = in HEAP { 'c' }; //~ ERROR placement-in expression syntax is experimental + println!("x: {}", x); +} diff --git a/src/test/compile-fail/feature-gate-pushpop-unsafe.rs b/src/test/compile-fail/feature-gate-pushpop-unsafe.rs new file mode 100644 index 0000000000000..e317b4c7d4d2a --- /dev/null +++ b/src/test/compile-fail/feature-gate-pushpop-unsafe.rs @@ -0,0 +1,14 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let c = push_unsafe!('c'); //~ ERROR push/pop_unsafe macros are experimental + let c = pop_unsafe!('c'); //~ ERROR push/pop_unsafe macros are experimental +} diff --git a/src/test/compile-fail/issue-14084.rs b/src/test/compile-fail/issue-14084.rs index 003c6644f7f02..8e566d7aafa68 100644 --- a/src/test/compile-fail/issue-14084.rs +++ b/src/test/compile-fail/issue-14084.rs @@ -9,8 +9,10 @@ // except according to those terms. #![feature(box_syntax)] +#![feature(placement_in_syntax)] fn main() { box ( () ) 0; - //~^ ERROR: only the exchange heap is currently supported + //~^ ERROR: the trait `core::ops::Placer<_>` is not implemented + //~| ERROR: the trait `core::ops::Placer<_>` is not implemented } diff --git a/src/test/compile-fail/pushpop-unsafe-rejects.rs b/src/test/compile-fail/pushpop-unsafe-rejects.rs new file mode 100644 index 0000000000000..72c065ae71417 --- /dev/null +++ b/src/test/compile-fail/pushpop-unsafe-rejects.rs @@ -0,0 +1,74 @@ +// Copyright 2012 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. + +// Basic sanity check for `push_unsafe!(EXPR)` and +// `pop_unsafe!(EXPR)`: we can call unsafe code when there are a +// positive number of pushes in the stack, or if we are within a +// normal `unsafe` block, but otherwise cannot. + +#![feature(pushpop_unsafe)] + +static mut X: i32 = 0; + +unsafe fn f() { X += 1; return; } +fn g() { unsafe { X += 1_000; } return; } + +fn main() { + push_unsafe!( { + f(); pop_unsafe!({ + f() //~ ERROR: call to unsafe function + }) + } ); + + push_unsafe!({ + f(); + pop_unsafe!({ + g(); + f(); //~ ERROR: call to unsafe function + }) + } ); + + push_unsafe!({ + g(); pop_unsafe!({ + unsafe { + f(); + } + f(); //~ ERROR: call to unsafe function + }) + }); + + + // Note: For implementation simplicity the compiler just + // ICE's if you underflow the push_unsafe stack. + // + // Thus all of the following cases cause an ICE. + // + // (The "ERROR" notes are from an earlier version + // that used saturated arithmetic rather than checked + // arithmetic.) + + // pop_unsafe!{ g() }; + // + // push_unsafe!({ + // pop_unsafe!(pop_unsafe!{ g() }) + // }); + // + // push_unsafe!({ + // g(); + // pop_unsafe!(pop_unsafe!({ + // f() // ERROR: call to unsafe function + // })) + // }); + // + // pop_unsafe!({ + // f(); // ERROR: call to unsafe function + // }) + +} diff --git a/src/test/parse-fail/parenthesized-box-expr-message.rs b/src/test/parse-fail/parenthesized-box-expr-message.rs index 09d32a71dea48..4c32d2f041e3c 100644 --- a/src/test/parse-fail/parenthesized-box-expr-message.rs +++ b/src/test/parse-fail/parenthesized-box-expr-message.rs @@ -12,7 +12,7 @@ fn main() { box (1 + 1) - //~^ HELP try using `box()` instead: - //~| SUGGESTION box() (1 + 1) + //~^ HELP try using `box ()` instead: + //~| SUGGESTION box () (1 + 1) ; //~ ERROR expected expression, found `;` } diff --git a/src/test/run-pass/intrinsic-move-val.rs b/src/test/run-pass/intrinsic-move-val.rs index 2e75f2dccd1ba..84af4fd0a08ea 100644 --- a/src/test/run-pass/intrinsic-move-val.rs +++ b/src/test/run-pass/intrinsic-move-val.rs @@ -20,7 +20,7 @@ use std::mem::{self, transmute}; mod rusti { extern "rust-intrinsic" { pub fn init() -> T; - pub fn move_val_init(dst: &mut T, src: T); + pub fn move_val_init(dst: *mut T, src: T); } } diff --git a/src/test/run-pass/new-box-syntax.rs b/src/test/run-pass/new-box-syntax.rs index b5a54a90ae758..da57e8682ca60 100644 --- a/src/test/run-pass/new-box-syntax.rs +++ b/src/test/run-pass/new-box-syntax.rs @@ -13,8 +13,13 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ -#![allow(warnings)] +#![allow(dead_code, unused_variables)] #![feature(box_syntax, box_heap)] +#![feature(placement_in_syntax)] + +// during check-pretty, the expanded code needs to opt into these +// features +#![feature(placement_new_protocol, core_intrinsics)] // Tests that the new `box` syntax works with unique pointers. @@ -30,4 +35,9 @@ pub fn main() { let y: Box = box 2; let b: Box = box()(1 + 2); let c = box()(3 + 4); + + let s: Box = box Structure { + x: 3, + y: 4, + }; } diff --git a/src/test/run-pass/placement-in-syntax.rs b/src/test/run-pass/placement-in-syntax.rs new file mode 100644 index 0000000000000..7bda9ae252439 --- /dev/null +++ b/src/test/run-pass/placement-in-syntax.rs @@ -0,0 +1,37 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(dead_code, unused_variables)] +#![feature(box_heap)] +#![feature(placement_in_syntax)] + +// Tests that the new `in` syntax works with unique pointers. +// +// Compare with new-box-syntax.rs + +use std::boxed::{Box, HEAP}; + +struct Structure { + x: isize, + y: isize, +} + +pub fn main() { + let x: Box = in HEAP { 2 }; + let b: Box = in HEAP { 1 + 2 }; + let c = in HEAP { 3 + 4 }; + + let s: Box = in HEAP { + Structure { + x: 3, + y: 4, + } + }; +} diff --git a/src/test/run-pass/pushpop-unsafe-okay.rs b/src/test/run-pass/pushpop-unsafe-okay.rs new file mode 100644 index 0000000000000..fc402d4136888 --- /dev/null +++ b/src/test/run-pass/pushpop-unsafe-okay.rs @@ -0,0 +1,56 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Basic sanity check for `push_unsafe!(EXPR)` and +// `pop_unsafe!(EXPR)`: we can call unsafe code when there are a +// positive number of pushes in the stack, or if we are within a +// normal `unsafe` block, but otherwise cannot. + +// ignore-pretty because the `push_unsafe!` and `pop_unsafe!` macros +// are not integrated with the pretty-printer. + +#![feature(pushpop_unsafe)] + +static mut X: i32 = 0; + +unsafe fn f() { X += 1; return; } +fn g() { unsafe { X += 1_000; } return; } + +fn check_reset_x(x: i32) -> bool { + #![allow(unused_parens)] // dont you judge my style choices! + unsafe { + let ret = (x == X); + X = 0; + ret + } +} + +fn main() { + // double-check test infrastructure + assert!(check_reset_x(0)); + unsafe { f(); } + assert!(check_reset_x(1)); + assert!(check_reset_x(0)); + { g(); } + assert!(check_reset_x(1000)); + assert!(check_reset_x(0)); + unsafe { f(); g(); g(); } + assert!(check_reset_x(2001)); + + push_unsafe!( { f(); pop_unsafe!( g() ) } ); + assert!(check_reset_x(1_001)); + push_unsafe!( { g(); pop_unsafe!( unsafe { f(); f(); } ) } ); + assert!(check_reset_x(1_002)); + + unsafe { push_unsafe!( { f(); pop_unsafe!( { f(); f(); } ) } ); } + assert!(check_reset_x(3)); + push_unsafe!( { f(); push_unsafe!( { pop_unsafe!( { f(); f(); f(); } ) } ); } ); + assert!(check_reset_x(4)); +}