提交 199b7e21 编写于 作者: B bors

Auto merge of #48333 - aidanhs:aphs-no-place-for-placement, r=nikomatsakis

Remove all unstable placement features

Closes #22181, #27779. Effectively makes the assortment of placement RFCs (rust-lang/rfcs#470, rust-lang/rfcs#809, rust-lang/rfcs#1228) 'unaccepted'. It leaves `box_syntax` and keeps the `<-` token as recognised by libsyntax.

------------------------

I don't know the correct process for unaccepting an unstable feature that was accepted as an RFC so...here's a PR.

Let me preface this by saying I'm not particularly happy about doing this (I know it'll be unpopular), but I think it's the most honest expression of how things stand today. I've been motivated by a [post on reddit](https://www.reddit.com/r/rust/comments/7wrqk2/when_will_box_and_placementin_syntax_be_stable/) which asks when these features will be stable - the features have received little RFC-style design work since the end of 2015 (~2 years ago) and leaving them in limbo confuses people who want to know where they're up to. Without additional design work that needs to happen (see the collection of unresolved questions later in this post) they can't really get stabilised, and I think that design work would be most suited to an RFC rather than (currently mostly unused) experimental features in Rust nightly.

I have my own motivations - it's very simple to 'defeat' placement in debug mode today and I don't want a placement in Rust that a) has no guarantees to work and b) has no plan for in-place serde deserialisation.

There's a quote in [1]: "Ordinarily these uncertainties might lead to the RFC being postponed. [The RFC seems like a promising direction hence we will accept since it] will thus give us immediate experience with the design and help in determining the best final solution.". I propose that there have been enough additional uncertainties raised since then that the original direction is less promising and we should be think about the problem anew.

(a historical note: the first mention of placement (under that name - uninit pointers were earlier) in an RFC AFAIK is [0] in late 2014 (pre-1.0). RFCs since then have built on this base - [1] is a comment in Feb 2015 accepting a more conservative design of the Place* traits - this is back when serde still required aster and seemed to break every other nightly! A lot has changed since then, perhaps placement should too)

------------------------

Concrete unresolved questions include:

 - making placement work in debug mode [7]
 - making placement work for serde/with fallible creation [5], [irlo2], [8]
 - trait design:
   - opting into not consuming the placer in `Placer::make_place` - [2]
   - trait proliferation - [4] (+ others in that thread)
   - fallible allocation - [3], [4] (+ others in that thread)
 - support for DSTs/unsized structs (if at all) - [1], [6]

More speculative unresolved questions include:

 - better trait design with in the context of future language features [irlo1] (Q11), [irlo3]
 - interaction between custom allocators and placement [irlo3]

[0] https://github.com/rust-lang/rfcs/pull/470
[1] https://github.com/rust-lang/rfcs/pull/809#issuecomment-73910414
[2] https://github.com/rust-lang/rfcs/issues/1286
[3] https://github.com/rust-lang/rfcs/issues/1315
[4] https://github.com/rust-lang/rust/issues/27779#issuecomment-146711893
[5] https://github.com/rust-lang/rust/issues/27779#issuecomment-285562402
[6] https://github.com/rust-lang/rust/issues/27779#issuecomment-354464938
[7] https://github.com/rust-lang/rust/issues/27779#issuecomment-358025344
[8] https://github.com/rust-lang/rfcs/pull/1228#issuecomment-190825370
[irlo1] https://internals.rust-lang.org/t/placement-nwbi-faq-new-box-in-left-arrow/2789
[irlo2] https://internals.rust-lang.org/t/placement-nwbi-faq-new-box-in-left-arrow/2789/19
[irlo3] https://internals.rust-lang.org/t/lang-team-minutes-feature-status-report-placement-in-and-box/4646
......@@ -1400,7 +1400,6 @@ nonblock_expr
| BREAK lifetime { $$ = mk_node("ExprBreak", 1, $2); }
| YIELD { $$ = mk_node("ExprYield", 0); }
| YIELD expr { $$ = mk_node("ExprYield", 1, $2); }
| nonblock_expr LARROW expr { $$ = mk_node("ExprInPlace", 2, $1, $3); }
| nonblock_expr '=' expr { $$ = mk_node("ExprAssign", 2, $1, $3); }
| nonblock_expr SHLEQ expr { $$ = mk_node("ExprAssignShl", 2, $1, $3); }
| nonblock_expr SHREQ expr { $$ = mk_node("ExprAssignShr", 2, $1, $3); }
......@@ -1463,7 +1462,6 @@ expr
| BREAK ident { $$ = mk_node("ExprBreak", 1, $2); }
| YIELD { $$ = mk_node("ExprYield", 0); }
| YIELD expr { $$ = mk_node("ExprYield", 1, $2); }
| expr LARROW expr { $$ = mk_node("ExprInPlace", 2, $1, $3); }
| expr '=' expr { $$ = mk_node("ExprAssign", 2, $1, $3); }
| expr SHLEQ expr { $$ = mk_node("ExprAssignShl", 2, $1, $3); }
| expr SHREQ expr { $$ = mk_node("ExprAssignShr", 2, $1, $3); }
......@@ -1527,7 +1525,6 @@ expr_nostruct
| BREAK ident { $$ = mk_node("ExprBreak", 1, $2); }
| YIELD { $$ = mk_node("ExprYield", 0); }
| YIELD expr { $$ = mk_node("ExprYield", 1, $2); }
| expr_nostruct LARROW expr_nostruct { $$ = mk_node("ExprInPlace", 2, $1, $3); }
| expr_nostruct '=' expr_nostruct { $$ = mk_node("ExprAssign", 2, $1, $3); }
| expr_nostruct SHLEQ expr_nostruct { $$ = mk_node("ExprAssignShl", 2, $1, $3); }
| expr_nostruct SHREQ expr_nostruct { $$ = mk_node("ExprAssignShr", 2, $1, $3); }
......
......@@ -155,7 +155,7 @@
#![allow(missing_docs)]
#![stable(feature = "rust1", since = "1.0.0")]
use core::ops::{Deref, DerefMut, Place, Placer, InPlace};
use core::ops::{Deref, DerefMut};
use core::iter::{FromIterator, FusedIterator};
use core::mem::{swap, size_of};
use core::ptr;
......@@ -1195,67 +1195,3 @@ fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
self.extend(iter.into_iter().cloned());
}
}
#[unstable(feature = "collection_placement",
reason = "placement protocol is subject to change",
issue = "30172")]
pub struct BinaryHeapPlace<'a, T: 'a>
where T: Clone + Ord {
heap: *mut BinaryHeap<T>,
place: vec::PlaceBack<'a, T>,
}
#[unstable(feature = "collection_placement",
reason = "placement protocol is subject to change",
issue = "30172")]
impl<'a, T: Clone + Ord + fmt::Debug> fmt::Debug for BinaryHeapPlace<'a, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("BinaryHeapPlace")
.field(&self.place)
.finish()
}
}
#[unstable(feature = "collection_placement",
reason = "placement protocol is subject to change",
issue = "30172")]
impl<'a, T: 'a> Placer<T> for &'a mut BinaryHeap<T>
where T: Clone + Ord {
type Place = BinaryHeapPlace<'a, T>;
fn make_place(self) -> Self::Place {
let ptr = self as *mut BinaryHeap<T>;
let place = Placer::make_place(self.data.place_back());
BinaryHeapPlace {
heap: ptr,
place,
}
}
}
#[unstable(feature = "collection_placement",
reason = "placement protocol is subject to change",
issue = "30172")]
unsafe impl<'a, T> Place<T> for BinaryHeapPlace<'a, T>
where T: Clone + Ord {
fn pointer(&mut self) -> *mut T {
self.place.pointer()
}
}
#[unstable(feature = "collection_placement",
reason = "placement protocol is subject to change",
issue = "30172")]
impl<'a, T> InPlace<T> for BinaryHeapPlace<'a, T>
where T: Clone + Ord {
type Owner = &'a T;
unsafe fn finalize(self) -> &'a T {
self.place.finalize();
let heap: &mut BinaryHeap<T> = &mut *self.heap;
let len = heap.len();
let i = heap.sift_up(0, len - 1);
heap.data.get_unchecked(i)
}
}
......@@ -55,7 +55,6 @@
#![stable(feature = "rust1", since = "1.0.0")]
use heap::Heap;
use raw_vec::RawVec;
use core::any::Any;
......@@ -63,47 +62,14 @@
use core::cmp::Ordering;
use core::fmt;
use core::hash::{Hash, Hasher};
use core::heap::{Alloc, Layout};
use core::iter::FusedIterator;
use core::marker::{self, Unpin, Unsize};
use core::marker::{Unpin, Unsize};
use core::mem::{self, Pin};
use core::ops::{CoerceUnsized, Deref, DerefMut, Generator, GeneratorState};
use core::ops::{BoxPlace, Boxed, InPlace, Place, Placer};
use core::ptr::{self, NonNull, Unique};
use core::convert::From;
use str::from_boxed_utf8_unchecked;
/// A value that represents the heap. This is the default place that the `box`
/// keyword allocates into when no place is supplied.
///
/// The following two examples are equivalent:
///
/// ```
/// #![feature(box_heap)]
///
/// #![feature(box_syntax, placement_in_syntax)]
/// use std::boxed::HEAP;
///
/// fn main() {
/// let foo: Box<i32> = in HEAP { 5 };
/// let foo = box 5;
/// }
/// ```
#[unstable(feature = "box_heap",
reason = "may be renamed; uncertain about custom allocator design",
issue = "27779")]
pub const HEAP: ExchangeHeapSingleton = ExchangeHeapSingleton { _force_singleton: () };
/// This the singleton type used solely for `boxed::HEAP`.
#[unstable(feature = "box_heap",
reason = "may be renamed; uncertain about custom allocator design",
issue = "27779")]
#[allow(missing_debug_implementations)]
#[derive(Copy, Clone)]
pub struct ExchangeHeapSingleton {
_force_singleton: (),
}
/// A pointer type for heap allocation.
///
/// See the [module-level documentation](../../std/boxed/index.html) for more.
......@@ -112,121 +78,6 @@ pub struct ExchangeHeapSingleton {
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Box<T: ?Sized>(Unique<T>);
/// `IntermediateBox` represents uninitialized backing storage for `Box`.
///
/// FIXME (pnkfelix): Ideally we would just reuse `Box<T>` instead of
/// introducing a separate `IntermediateBox<T>`; 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.",
issue = "27779")]
#[allow(missing_debug_implementations)]
pub struct IntermediateBox<T: ?Sized> {
ptr: *mut u8,
layout: Layout,
marker: marker::PhantomData<*mut T>,
}
#[unstable(feature = "placement_in",
reason = "placement box design is still being worked out.",
issue = "27779")]
unsafe impl<T> Place<T> for IntermediateBox<T> {
fn pointer(&mut self) -> *mut T {
self.ptr as *mut T
}
}
unsafe fn finalize<T>(b: IntermediateBox<T>) -> Box<T> {
let p = b.ptr as *mut T;
mem::forget(b);
Box::from_raw(p)
}
fn make_place<T>() -> IntermediateBox<T> {
let layout = Layout::new::<T>();
let p = if layout.size() == 0 {
mem::align_of::<T>() as *mut u8
} else {
unsafe {
Heap.alloc(layout.clone()).unwrap_or_else(|err| {
Heap.oom(err)
})
}
};
IntermediateBox {
ptr: p,
layout,
marker: marker::PhantomData,
}
}
#[unstable(feature = "placement_in",
reason = "placement box design is still being worked out.",
issue = "27779")]
impl<T> BoxPlace<T> for IntermediateBox<T> {
fn make_place() -> IntermediateBox<T> {
make_place()
}
}
#[unstable(feature = "placement_in",
reason = "placement box design is still being worked out.",
issue = "27779")]
impl<T> InPlace<T> for IntermediateBox<T> {
type Owner = Box<T>;
unsafe fn finalize(self) -> Box<T> {
finalize(self)
}
}
#[unstable(feature = "placement_new_protocol", issue = "27779")]
impl<T> Boxed for Box<T> {
type Data = T;
type Place = IntermediateBox<T>;
unsafe fn finalize(b: IntermediateBox<T>) -> Box<T> {
finalize(b)
}
}
#[unstable(feature = "placement_in",
reason = "placement box design is still being worked out.",
issue = "27779")]
impl<T> Placer<T> for ExchangeHeapSingleton {
type Place = IntermediateBox<T>;
fn make_place(self) -> IntermediateBox<T> {
make_place()
}
}
#[unstable(feature = "placement_in",
reason = "placement box design is still being worked out.",
issue = "27779")]
impl<T: ?Sized> Drop for IntermediateBox<T> {
fn drop(&mut self) {
if self.layout.size() > 0 {
unsafe {
Heap.dealloc(self.ptr, self.layout.clone())
}
}
}
}
impl<T> Box<T> {
/// Allocates memory on the heap and then places `x` into it.
///
......
......@@ -76,7 +76,6 @@
#![deny(missing_debug_implementations)]
#![cfg_attr(test, allow(deprecated))] // rand
#![cfg_attr(test, feature(placement_in))]
#![cfg_attr(not(test), feature(core_float))]
#![cfg_attr(not(test), feature(exact_size_is_empty))]
#![cfg_attr(not(test), feature(generator_trait))]
......@@ -108,8 +107,6 @@
#![feature(optin_builtin_traits)]
#![feature(pattern)]
#![feature(pin)]
#![feature(placement_in_syntax)]
#![feature(placement_new_protocol)]
#![feature(ptr_internals)]
#![feature(rustc_attrs)]
#![feature(slice_get_slice)]
......@@ -128,8 +125,8 @@
#![feature(pointer_methods)]
#![feature(inclusive_range_fields)]
#![cfg_attr(not(test), feature(fn_traits, placement_new_protocol, swap_with_slice, i128))]
#![cfg_attr(test, feature(test, box_heap))]
#![cfg_attr(not(test), feature(fn_traits, swap_with_slice, i128))]
#![cfg_attr(test, feature(test))]
// Allow testing this library
......@@ -159,13 +156,12 @@
// 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;`
// and `use boxed::Box;` declarations.
// to allow code to have `use boxed::Box;` declarations.
#[cfg(not(test))]
pub mod boxed;
#[cfg(test)]
mod boxed {
pub use std::boxed::{Box, IntermediateBox, HEAP};
pub use std::boxed::Box;
}
#[cfg(test)]
mod boxed_test;
......
......@@ -28,10 +28,9 @@
use core::iter::{FromIterator, FusedIterator};
use core::marker::PhantomData;
use core::mem;
use core::ops::{BoxPlace, InPlace, Place, Placer};
use core::ptr::{self, NonNull};
use core::ptr::NonNull;
use boxed::{Box, IntermediateBox};
use boxed::Box;
use super::SpecExtend;
/// A doubly-linked list with owned nodes.
......@@ -786,62 +785,6 @@ pub fn drain_filter<F>(&mut self, filter: F) -> DrainFilter<T, F>
old_len: old_len,
}
}
/// Returns a place for insertion at the front of the list.
///
/// Using this method with placement syntax is equivalent to
/// [`push_front`](#method.push_front), but may be more efficient.
///
/// # Examples
///
/// ```
/// #![feature(collection_placement)]
/// #![feature(placement_in_syntax)]
///
/// use std::collections::LinkedList;
///
/// let mut list = LinkedList::new();
/// list.front_place() <- 2;
/// list.front_place() <- 4;
/// assert!(list.iter().eq(&[4, 2]));
/// ```
#[unstable(feature = "collection_placement",
reason = "method name and placement protocol are subject to change",
issue = "30172")]
pub fn front_place(&mut self) -> FrontPlace<T> {
FrontPlace {
list: self,
node: IntermediateBox::make_place(),
}
}
/// Returns a place for insertion at the back of the list.
///
/// Using this method with placement syntax is equivalent to [`push_back`](#method.push_back),
/// but may be more efficient.
///
/// # Examples
///
/// ```
/// #![feature(collection_placement)]
/// #![feature(placement_in_syntax)]
///
/// use std::collections::LinkedList;
///
/// let mut list = LinkedList::new();
/// list.back_place() <- 2;
/// list.back_place() <- 4;
/// assert!(list.iter().eq(&[2, 4]));
/// ```
#[unstable(feature = "collection_placement",
reason = "method name and placement protocol are subject to change",
issue = "30172")]
pub fn back_place(&mut self) -> BackPlace<T> {
BackPlace {
list: self,
node: IntermediateBox::make_place(),
}
}
}
#[stable(feature = "rust1", since = "1.0.0")]
......@@ -1242,123 +1185,6 @@ fn hash<H: Hasher>(&self, state: &mut H) {
}
}
unsafe fn finalize<T>(node: IntermediateBox<Node<T>>) -> Box<Node<T>> {
let mut node = node.finalize();
ptr::write(&mut node.next, None);
ptr::write(&mut node.prev, None);
node
}
/// A place for insertion at the front of a `LinkedList`.
///
/// See [`LinkedList::front_place`](struct.LinkedList.html#method.front_place) for details.
#[must_use = "places do nothing unless written to with `<-` syntax"]
#[unstable(feature = "collection_placement",
reason = "struct name and placement protocol are subject to change",
issue = "30172")]
pub struct FrontPlace<'a, T: 'a> {
list: &'a mut LinkedList<T>,
node: IntermediateBox<Node<T>>,
}
#[unstable(feature = "collection_placement",
reason = "struct name and placement protocol are subject to change",
issue = "30172")]
impl<'a, T: 'a + fmt::Debug> fmt::Debug for FrontPlace<'a, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("FrontPlace")
.field(&self.list)
.finish()
}
}
#[unstable(feature = "collection_placement",
reason = "placement protocol is subject to change",
issue = "30172")]
impl<'a, T> Placer<T> for FrontPlace<'a, T> {
type Place = Self;
fn make_place(self) -> Self {
self
}
}
#[unstable(feature = "collection_placement",
reason = "placement protocol is subject to change",
issue = "30172")]
unsafe impl<'a, T> Place<T> for FrontPlace<'a, T> {
fn pointer(&mut self) -> *mut T {
unsafe { &mut (*self.node.pointer()).element }
}
}
#[unstable(feature = "collection_placement",
reason = "placement protocol is subject to change",
issue = "30172")]
impl<'a, T> InPlace<T> for FrontPlace<'a, T> {
type Owner = ();
unsafe fn finalize(self) {
let FrontPlace { list, node } = self;
list.push_front_node(finalize(node));
}
}
/// A place for insertion at the back of a `LinkedList`.
///
/// See [`LinkedList::back_place`](struct.LinkedList.html#method.back_place) for details.
#[must_use = "places do nothing unless written to with `<-` syntax"]
#[unstable(feature = "collection_placement",
reason = "struct name and placement protocol are subject to change",
issue = "30172")]
pub struct BackPlace<'a, T: 'a> {
list: &'a mut LinkedList<T>,
node: IntermediateBox<Node<T>>,
}
#[unstable(feature = "collection_placement",
reason = "struct name and placement protocol are subject to change",
issue = "30172")]
impl<'a, T: 'a + fmt::Debug> fmt::Debug for BackPlace<'a, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("BackPlace")
.field(&self.list)
.finish()
}
}
#[unstable(feature = "collection_placement",
reason = "placement protocol is subject to change",
issue = "30172")]
impl<'a, T> Placer<T> for BackPlace<'a, T> {
type Place = Self;
fn make_place(self) -> Self {
self
}
}
#[unstable(feature = "collection_placement",
reason = "placement protocol is subject to change",
issue = "30172")]
unsafe impl<'a, T> Place<T> for BackPlace<'a, T> {
fn pointer(&mut self) -> *mut T {
unsafe { &mut (*self.node.pointer()).element }
}
}
#[unstable(feature = "collection_placement",
reason = "placement protocol is subject to change",
issue = "30172")]
impl<'a, T> InPlace<T> for BackPlace<'a, T> {
type Owner = ();
unsafe fn finalize(self) {
let BackPlace { list, node } = self;
list.push_back_node(finalize(node));
}
}
// Ensure that `LinkedList` and its read-only iterators are covariant in their type parameters.
#[allow(dead_code)]
fn assert_covariance() {
......
......@@ -278,26 +278,6 @@ fn test_extend_specialization() {
assert_eq!(a.into_sorted_vec(), [-20, -10, 1, 2, 3, 3, 5, 43]);
}
#[test]
fn test_placement() {
let mut a = BinaryHeap::new();
&mut a <- 2;
&mut a <- 4;
&mut a <- 3;
assert_eq!(a.peek(), Some(&4));
assert_eq!(a.len(), 3);
&mut a <- 1;
assert_eq!(a.into_sorted_vec(), vec![1, 2, 3, 4]);
}
#[test]
fn test_placement_panic() {
let mut heap = BinaryHeap::from(vec![1, 2, 3]);
fn mkpanic() -> usize { panic!() }
let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { &mut heap <- mkpanic(); }));
assert_eq!(heap.len(), 3);
}
#[allow(dead_code)]
fn assert_covariance() {
fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> {
......
......@@ -15,13 +15,11 @@
#![feature(attr_literals)]
#![feature(box_syntax)]
#![cfg_attr(stage0, feature(inclusive_range_syntax))]
#![feature(collection_placement)]
#![feature(const_fn)]
#![feature(drain_filter)]
#![feature(exact_size_is_empty)]
#![feature(iterator_step_by)]
#![feature(pattern)]
#![feature(placement_in_syntax)]
#![feature(rand)]
#![feature(slice_sort_by_cached_key)]
#![feature(splice)]
......
......@@ -10,7 +10,7 @@
use std::borrow::Cow;
use std::mem::size_of;
use std::{usize, isize, panic};
use std::{usize, isize};
use std::vec::{Drain, IntoIter};
use std::collections::CollectionAllocErr::*;
......@@ -753,24 +753,6 @@ fn into_iter<'new>(i: IntoIter<&'static str>) -> IntoIter<&'new str> {
}
}
#[test]
fn test_placement() {
let mut vec = vec![1];
assert_eq!(vec.place_back() <- 2, &2);
assert_eq!(vec.len(), 2);
assert_eq!(vec.place_back() <- 3, &3);
assert_eq!(vec.len(), 3);
assert_eq!(&vec, &[1, 2, 3]);
}
#[test]
fn test_placement_panic() {
let mut vec = vec![1, 2, 3];
fn mkpanic() -> usize { panic!() }
let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { vec.place_back() <- mkpanic(); }));
assert_eq!(vec.len(), 3);
}
#[test]
fn from_into_inner() {
let vec = vec![1, 2, 3];
......
......@@ -1004,28 +1004,6 @@ fn test_is_empty() {
assert!(v.into_iter().is_empty());
}
#[test]
fn test_placement_in() {
let mut buf: VecDeque<isize> = VecDeque::new();
buf.place_back() <- 1;
buf.place_back() <- 2;
assert_eq!(buf, [1,2]);
buf.place_front() <- 3;
buf.place_front() <- 4;
assert_eq!(buf, [4,3,1,2]);
{
let ptr_head = buf.place_front() <- 5;
assert_eq!(*ptr_head, 5);
}
{
let ptr_tail = buf.place_back() <- 6;
assert_eq!(*ptr_tail, 6);
}
assert_eq!(buf, [5,4,3,1,2,6]);
}
#[test]
fn test_reserve_exact_2() {
// This is all the same as test_reserve
......
......@@ -76,7 +76,7 @@
#[cfg(not(test))]
use core::num::Float;
use core::ops::Bound::{Excluded, Included, Unbounded};
use core::ops::{InPlace, Index, IndexMut, Place, Placer, RangeBounds};
use core::ops::{Index, IndexMut, RangeBounds};
use core::ops;
use core::ptr;
use core::ptr::NonNull;
......@@ -1065,29 +1065,6 @@ pub fn push(&mut self, value: T) {
}
}
/// Returns a place for insertion at the back of the `Vec`.
///
/// Using this method with placement syntax is equivalent to [`push`](#method.push),
/// but may be more efficient.
///
/// # Examples
///
/// ```
/// #![feature(collection_placement)]
/// #![feature(placement_in_syntax)]
///
/// let mut vec = vec![1, 2];
/// vec.place_back() <- 3;
/// vec.place_back() <- 4;
/// assert_eq!(&vec, &[1, 2, 3, 4]);
/// ```
#[unstable(feature = "collection_placement",
reason = "placement protocol is subject to change",
issue = "30172")]
pub fn place_back(&mut self) -> PlaceBack<T> {
PlaceBack { vec: self }
}
/// Removes the last element from a vector and returns it, or [`None`] if it
/// is empty.
///
......@@ -2492,57 +2469,6 @@ fn is_empty(&self) -> bool {
#[stable(feature = "fused", since = "1.26.0")]
impl<'a, T> FusedIterator for Drain<'a, T> {}
/// A place for insertion at the back of a `Vec`.
///
/// See [`Vec::place_back`](struct.Vec.html#method.place_back) for details.
#[must_use = "places do nothing unless written to with `<-` syntax"]
#[unstable(feature = "collection_placement",
reason = "struct name and placement protocol are subject to change",
issue = "30172")]
#[derive(Debug)]
pub struct PlaceBack<'a, T: 'a> {
vec: &'a mut Vec<T>,
}
#[unstable(feature = "collection_placement",
reason = "placement protocol is subject to change",
issue = "30172")]
impl<'a, T> Placer<T> for PlaceBack<'a, T> {
type Place = PlaceBack<'a, T>;
fn make_place(self) -> Self {
// This will panic or abort if we would allocate > isize::MAX bytes
// or if the length increment would overflow for zero-sized types.
if self.vec.len == self.vec.buf.cap() {
self.vec.buf.double();
}
self
}
}
#[unstable(feature = "collection_placement",
reason = "placement protocol is subject to change",
issue = "30172")]
unsafe impl<'a, T> Place<T> for PlaceBack<'a, T> {
fn pointer(&mut self) -> *mut T {
unsafe { self.vec.as_mut_ptr().offset(self.vec.len as isize) }
}
}
#[unstable(feature = "collection_placement",
reason = "placement protocol is subject to change",
issue = "30172")]
impl<'a, T> InPlace<T> for PlaceBack<'a, T> {
type Owner = &'a mut T;
unsafe fn finalize(mut self) -> &'a mut T {
let ptr = self.pointer();
self.vec.len += 1;
&mut *ptr
}
}
/// A splicing iterator for `Vec`.
///
/// This struct is created by the [`splice()`] method on [`Vec`]. See its
......
......@@ -22,7 +22,7 @@
use core::iter::{repeat, FromIterator, FusedIterator};
use core::mem;
use core::ops::Bound::{Excluded, Included, Unbounded};
use core::ops::{Index, IndexMut, Place, Placer, InPlace, RangeBounds};
use core::ops::{Index, IndexMut, RangeBounds};
use core::ptr;
use core::ptr::NonNull;
use core::slice;
......@@ -1885,56 +1885,6 @@ fn grow_if_necessary(&mut self) {
debug_assert!(!self.is_full());
}
}
/// Returns a place for insertion at the back of the `VecDeque`.
///
/// Using this method with placement syntax is equivalent to [`push_back`](#method.push_back),
/// but may be more efficient.
///
/// # Examples
///
/// ```
/// #![feature(collection_placement)]
/// #![feature(placement_in_syntax)]
///
/// use std::collections::VecDeque;
///
/// let mut buf = VecDeque::new();
/// buf.place_back() <- 3;
/// buf.place_back() <- 4;
/// assert_eq!(&buf, &[3, 4]);
/// ```
#[unstable(feature = "collection_placement",
reason = "placement protocol is subject to change",
issue = "30172")]
pub fn place_back(&mut self) -> PlaceBack<T> {
PlaceBack { vec_deque: self }
}
/// Returns a place for insertion at the front of the `VecDeque`.
///
/// Using this method with placement syntax is equivalent to [`push_front`](#method.push_front),
/// but may be more efficient.
///
/// # Examples
///
/// ```
/// #![feature(collection_placement)]
/// #![feature(placement_in_syntax)]
///
/// use std::collections::VecDeque;
///
/// let mut buf = VecDeque::new();
/// buf.place_front() <- 3;
/// buf.place_front() <- 4;
/// assert_eq!(&buf, &[4, 3]);
/// ```
#[unstable(feature = "collection_placement",
reason = "placement protocol is subject to change",
issue = "30172")]
pub fn place_front(&mut self) -> PlaceFront<T> {
PlaceFront { vec_deque: self }
}
}
impl<T: Clone> VecDeque<T> {
......@@ -2662,98 +2612,6 @@ fn from(other: VecDeque<T>) -> Self {
}
}
/// A place for insertion at the back of a `VecDeque`.
///
/// See [`VecDeque::place_back`](struct.VecDeque.html#method.place_back) for details.
#[must_use = "places do nothing unless written to with `<-` syntax"]
#[unstable(feature = "collection_placement",
reason = "struct name and placement protocol are subject to change",
issue = "30172")]
#[derive(Debug)]
pub struct PlaceBack<'a, T: 'a> {
vec_deque: &'a mut VecDeque<T>,
}
#[unstable(feature = "collection_placement",
reason = "placement protocol is subject to change",
issue = "30172")]
impl<'a, T> Placer<T> for PlaceBack<'a, T> {
type Place = PlaceBack<'a, T>;
fn make_place(self) -> Self {
self.vec_deque.grow_if_necessary();
self
}
}
#[unstable(feature = "collection_placement",
reason = "placement protocol is subject to change",
issue = "30172")]
unsafe impl<'a, T> Place<T> for PlaceBack<'a, T> {
fn pointer(&mut self) -> *mut T {
unsafe { self.vec_deque.ptr().offset(self.vec_deque.head as isize) }
}
}
#[unstable(feature = "collection_placement",
reason = "placement protocol is subject to change",
issue = "30172")]
impl<'a, T> InPlace<T> for PlaceBack<'a, T> {
type Owner = &'a mut T;
unsafe fn finalize(self) -> &'a mut T {
let head = self.vec_deque.head;
self.vec_deque.head = self.vec_deque.wrap_add(head, 1);
&mut *(self.vec_deque.ptr().offset(head as isize))
}
}
/// A place for insertion at the front of a `VecDeque`.
///
/// See [`VecDeque::place_front`](struct.VecDeque.html#method.place_front) for details.
#[must_use = "places do nothing unless written to with `<-` syntax"]
#[unstable(feature = "collection_placement",
reason = "struct name and placement protocol are subject to change",
issue = "30172")]
#[derive(Debug)]
pub struct PlaceFront<'a, T: 'a> {
vec_deque: &'a mut VecDeque<T>,
}
#[unstable(feature = "collection_placement",
reason = "placement protocol is subject to change",
issue = "30172")]
impl<'a, T> Placer<T> for PlaceFront<'a, T> {
type Place = PlaceFront<'a, T>;
fn make_place(self) -> Self {
self.vec_deque.grow_if_necessary();
self
}
}
#[unstable(feature = "collection_placement",
reason = "placement protocol is subject to change",
issue = "30172")]
unsafe impl<'a, T> Place<T> for PlaceFront<'a, T> {
fn pointer(&mut self) -> *mut T {
let tail = self.vec_deque.wrap_sub(self.vec_deque.tail, 1);
unsafe { self.vec_deque.ptr().offset(tail as isize) }
}
}
#[unstable(feature = "collection_placement",
reason = "placement protocol is subject to change",
issue = "30172")]
impl<'a, T> InPlace<T> for PlaceFront<'a, T> {
type Owner = &'a mut T;
unsafe fn finalize(self) -> &'a mut T {
self.vec_deque.tail = self.vec_deque.wrap_sub(self.vec_deque.tail, 1);
&mut *(self.vec_deque.ptr().offset(self.vec_deque.tail as isize))
}
}
#[cfg(test)]
mod tests {
use test;
......
......@@ -161,7 +161,6 @@
mod function;
mod generator;
mod index;
mod place;
mod range;
mod try;
mod unsize;
......@@ -200,8 +199,5 @@
#[unstable(feature = "generator_trait", issue = "43122")]
pub use self::generator::{Generator, GeneratorState};
#[unstable(feature = "placement_new_protocol", issue = "27779")]
pub use self::place::{Place, Placer, InPlace, Boxed, BoxPlace};
#[unstable(feature = "coerce_unsized", issue = "27732")]
pub use self::unsize::CoerceUnsized;
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
/// Both `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 it is up to 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", issue = "27779")]
pub unsafe trait Place<Data: ?Sized> {
/// 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.
///
/// This function must return a pointer through which a value
/// of type `Data` can be written.
fn pointer(&mut self) -> *mut Data;
}
/// Interface to implementations of `PLACE <- EXPR`.
///
/// `PLACE <- EXPR` effectively desugars into:
///
/// ```
/// # #![feature(placement_new_protocol, box_heap)]
/// # use std::ops::{Placer, Place, InPlace};
/// # #[allow(non_snake_case)]
/// # fn main() {
/// # let PLACE = std::boxed::HEAP;
/// # let EXPR = 1;
/// 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 `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", issue = "27779")]
pub trait Placer<Data: ?Sized> {
/// `Place` is the intermediate agent guarding the
/// uninitialized state for `Data`.
type Place: InPlace<Data>;
/// Creates a fresh place from `self`.
fn make_place(self) -> Self::Place;
}
/// Specialization of `Place` trait supporting `PLACE <- EXPR`.
#[unstable(feature = "placement_new_protocol", issue = "27779")]
pub trait InPlace<Data: ?Sized>: Place<Data> {
/// `Owner` is the type of the end value of `PLACE <- EXPR`
///
/// Note that when `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:
///
/// ```
/// # #![feature(placement_new_protocol)]
/// # use std::ops::{BoxPlace, Place, Boxed};
/// # #[allow(non_snake_case)]
/// # fn main() {
/// # let EXPR = 1;
/// let mut place = BoxPlace::make_place();
/// let raw_place = Place::pointer(&mut place);
/// let value = EXPR;
/// # let _: Box<_> =
/// 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
/// `<T as Boxed>` in turn dictates determines which
/// implementation of `BoxPlace` to use, namely:
/// `<<T as Boxed>::Place as BoxPlace>`.
#[unstable(feature = "placement_new_protocol", issue = "27779")]
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<Self::Data>;
/// 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", issue = "27779")]
pub trait BoxPlace<Data: ?Sized> : Place<Data> {
/// Creates a globally fresh place.
fn make_place() -> Self;
}
......@@ -2911,118 +2911,8 @@ fn lower_range_end(&mut self, e: &RangeEnd) -> hir::RangeEnd {
fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
let kind = match e.node {
// 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.
ExprKind::Box(ref inner) => hir::ExprBox(P(self.lower_expr(inner))),
// Desugar ExprBox: `in (PLACE) EXPR`
ExprKind::InPlace(ref placer, ref 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)
// })
let placer_expr = P(self.lower_expr(placer));
let value_expr = P(self.lower_expr(value_expr));
let placer_ident = self.str_to_ident("placer");
let place_ident = self.str_to_ident("place");
let p_ptr_ident = self.str_to_ident("p_ptr");
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 unstable_span =
self.allow_internal_unstable(CompilerDesugaringKind::BackArrow, e.span);
let make_call = |this: &mut LoweringContext, p, args| {
let path = P(this.expr_std_path(unstable_span, p, ThinVec::new()));
P(this.expr_call(e.span, path, args))
};
let mk_stmt_let = |this: &mut LoweringContext, bind, expr| {
this.stmt_let(e.span, false, bind, expr)
};
let mk_stmt_let_mut = |this: &mut LoweringContext, bind, expr| {
this.stmt_let(e.span, true, bind, expr)
};
// let placer = <placer_expr> ;
let (s1, placer_binding) = { mk_stmt_let(self, placer_ident, placer_expr) };
// let mut place = Placer::make_place(placer);
let (s2, place_binding) = {
let placer = self.expr_ident(e.span, placer_ident, placer_binding);
let call = make_call(self, &make_place, hir_vec![placer]);
mk_stmt_let_mut(self, place_ident, call)
};
// let p_ptr = Place::pointer(&mut place);
let (s3, p_ptr_binding) = {
let agent = P(self.expr_ident(e.span, place_ident, place_binding));
let args = hir_vec![self.expr_mut_addr_of(e.span, agent)];
let call = make_call(self, &place_pointer, args);
mk_stmt_let(self, p_ptr_ident, call)
};
// pop_unsafe!(EXPR));
let pop_unsafe_expr = {
self.signal_block_expr(
hir_vec![],
value_expr,
e.span,
hir::PopUnsafeBlock(hir::CompilerGenerated),
ThinVec::new(),
)
};
// push_unsafe!({
// std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR ));
// InPlace::finalize(place)
// })
let expr = {
let ptr = self.expr_ident(e.span, p_ptr_ident, p_ptr_binding);
let call_move_val_init = hir::StmtSemi(
make_call(self, &move_val_init, hir_vec![ptr, pop_unsafe_expr]),
self.next_id().node_id,
);
let call_move_val_init = respan(e.span, call_move_val_init);
let place = self.expr_ident(e.span, place_ident, place_binding);
let call = make_call(self, &inplace_finalize, hir_vec![place]);
P(self.signal_block_expr(
hir_vec![call_move_val_init],
call,
e.span,
hir::PushUnsafeBlock(hir::CompilerGenerated),
ThinVec::new(),
))
};
let block = self.block_all(e.span, hir_vec![s1, s2, s3], Some(expr));
hir::ExprBlock(P(block))
}
ExprKind::Array(ref exprs) => {
hir::ExprArray(exprs.iter().map(|x| self.lower_expr(x)).collect())
}
......@@ -4069,29 +3959,6 @@ fn std_path(&mut self, span: Span, components: &[&str], is_value: bool) -> hir::
.resolve_str_path(span, self.crate_root, components, is_value)
}
fn signal_block_expr(
&mut self,
stmts: hir::HirVec<hir::Stmt>,
expr: P<hir::Expr>,
span: Span,
rule: hir::BlockCheckMode,
attrs: ThinVec<Attribute>,
) -> hir::Expr {
let LoweredNodeId { node_id, hir_id } = self.next_id();
let block = P(hir::Block {
rules: rule,
span,
id: node_id,
hir_id,
stmts,
expr: Some(expr),
targeted_by_break: false,
recovered: false,
});
self.expr_block(block, attrs)
}
fn ty_path(&mut self, id: LoweredNodeId, span: Span, qpath: hir::QPath) -> P<hir::Ty> {
let mut id = id;
let node = match qpath {
......
......@@ -371,7 +371,6 @@ fn hash_token<'a, 'gcx, W: StableHasherResult>(
});
impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind {
BackArrow,
DotFill,
QuestionMark
});
......
......@@ -301,7 +301,6 @@ fn check_expr(&mut self, cx: &EarlyContext, e: &ast::Expr) {
Ret(Some(ref value)) => (value, "`return` value", false),
Assign(_, ref value) => (value, "assigned value", false),
AssignOp(.., ref value) => (value, "assigned value", false),
InPlace(_, ref value) => (value, "emplacement value", false),
// either function/method call, or something this lint doesn't care about
ref call_or_other => {
let args_to_check;
......
......@@ -196,15 +196,16 @@ pub fn perform_test(&mut self,
let mut values = Vec::with_capacity(used_variants);
let tcx = self.hir.tcx();
for (idx, discr) in adt_def.discriminants(tcx).enumerate() {
target_blocks.place_back() <- if variants.contains(idx) {
target_blocks.push(if variants.contains(idx) {
values.push(discr.val);
*(targets.place_back() <- self.cfg.start_new_block())
targets.push(self.cfg.start_new_block());
*targets.last().unwrap()
} else {
if otherwise_block.is_none() {
otherwise_block = Some(self.cfg.start_new_block());
}
otherwise_block.unwrap()
};
});
}
if let Some(otherwise_block) = otherwise_block {
targets.push(otherwise_block);
......
......@@ -34,8 +34,6 @@
#![feature(exhaustive_patterns)]
#![feature(range_contains)]
#![feature(rustc_diagnostic_macros)]
#![feature(placement_in_syntax)]
#![feature(collection_placement)]
#![feature(nonzero)]
#![cfg_attr(stage0, feature(underscore_lifetimes))]
#![cfg_attr(stage0, feature(never_type))]
......
......@@ -721,16 +721,6 @@ fn main() {
```
"##,
E0066: r##"
Box placement expressions (like C++'s "placement new") do not yet support any
place expression except the exchange heap (i.e. `std::boxed::HEAP`).
Furthermore, the syntax is changing to use `in` instead of `box`. See [RFC 470]
and [RFC 809] for more details.
[RFC 470]: https://github.com/rust-lang/rfcs/pull/470
[RFC 809]: https://github.com/rust-lang/rfcs/blob/master/text/0809-box-and-in-for-stdlib.md
"##,
E0067: r##"
The left-hand side of a compound assignment expression must be a place
expression. A place expression represents a memory location and includes
......
......@@ -22,8 +22,7 @@
use hash::{Hash, Hasher, BuildHasher, SipHasher13};
use iter::{FromIterator, FusedIterator};
use mem::{self, replace};
use ops::{Deref, Index, InPlace, Place, Placer};
use ptr;
use ops::{Deref, Index};
use sys;
use super::table::{self, Bucket, EmptyBucket, FullBucket, FullBucketMut, RawTable, SafeHash};
......@@ -2043,80 +2042,6 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
}
}
/// A place for insertion to a `Entry`.
///
/// See [`HashMap::entry`](struct.HashMap.html#method.entry) for details.
#[must_use = "places do nothing unless written to with `<-` syntax"]
#[unstable(feature = "collection_placement",
reason = "struct name and placement protocol is subject to change",
issue = "30172")]
pub struct EntryPlace<'a, K: 'a, V: 'a> {
bucket: FullBucketMut<'a, K, V>,
}
#[unstable(feature = "collection_placement",
reason = "struct name and placement protocol is subject to change",
issue = "30172")]
impl<'a, K: 'a + Debug, V: 'a + Debug> Debug for EntryPlace<'a, K, V> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("EntryPlace")
.field("key", self.bucket.read().0)
.field("value", self.bucket.read().1)
.finish()
}
}
#[unstable(feature = "collection_placement",
reason = "struct name and placement protocol is subject to change",
issue = "30172")]
impl<'a, K, V> Drop for EntryPlace<'a, K, V> {
fn drop(&mut self) {
// Inplacement insertion failed. Only key need to drop.
// The value is failed to insert into map.
unsafe { self.bucket.remove_key() };
}
}
#[unstable(feature = "collection_placement",
reason = "placement protocol is subject to change",
issue = "30172")]
impl<'a, K, V> Placer<V> for Entry<'a, K, V> {
type Place = EntryPlace<'a, K, V>;
fn make_place(self) -> EntryPlace<'a, K, V> {
let b = match self {
Occupied(mut o) => {
unsafe { ptr::drop_in_place(o.elem.read_mut().1); }
o.elem
}
Vacant(v) => {
unsafe { v.insert_key() }
}
};
EntryPlace { bucket: b }
}
}
#[unstable(feature = "collection_placement",
reason = "placement protocol is subject to change",
issue = "30172")]
unsafe impl<'a, K, V> Place<V> for EntryPlace<'a, K, V> {
fn pointer(&mut self) -> *mut V {
self.bucket.read_mut().1
}
}
#[unstable(feature = "collection_placement",
reason = "placement protocol is subject to change",
issue = "30172")]
impl<'a, K, V> InPlace<V> for EntryPlace<'a, K, V> {
type Owner = ();
unsafe fn finalize(self) {
mem::forget(self);
}
}
impl<'a, K, V> Entry<'a, K, V> {
#[stable(feature = "rust1", since = "1.0.0")]
/// Ensures a value is in the entry by inserting the default if empty, and returns
......@@ -2539,26 +2464,6 @@ pub fn insert(self, value: V) -> &'a mut V {
};
b.into_mut_refs().1
}
// Only used for InPlacement insert. Avoid unnecessary value copy.
// The value remains uninitialized.
unsafe fn insert_key(self) -> FullBucketMut<'a, K, V> {
match self.elem {
NeqElem(mut bucket, disp) => {
if disp >= DISPLACEMENT_THRESHOLD {
bucket.table_mut().set_tag(true);
}
let uninit = mem::uninitialized();
robin_hood(bucket, disp, self.hash, self.key, uninit)
},
NoElem(mut bucket, disp) => {
if disp >= DISPLACEMENT_THRESHOLD {
bucket.table_mut().set_tag(true);
}
bucket.put_key(self.hash, self.key)
},
}
}
}
#[stable(feature = "rust1", since = "1.0.0")]
......@@ -2823,7 +2728,6 @@ mod test_map {
use super::RandomState;
use cell::RefCell;
use rand::{thread_rng, Rng};
use panic;
use realstd::collections::CollectionAllocErr::*;
use realstd::mem::size_of;
use realstd::usize;
......@@ -3709,59 +3613,6 @@ fn test_adaptive() {
panic!("Adaptive early resize failed");
}
#[test]
fn test_placement_in() {
let mut map = HashMap::new();
map.extend((0..10).map(|i| (i, i)));
map.entry(100) <- 100;
assert_eq!(map[&100], 100);
map.entry(0) <- 10;
assert_eq!(map[&0], 10);
assert_eq!(map.len(), 11);
}
#[test]
fn test_placement_panic() {
let mut map = HashMap::new();
map.extend((0..10).map(|i| (i, i)));
fn mkpanic() -> usize { panic!() }
// modify existing key
// when panic happens, previous key is removed.
let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { map.entry(0) <- mkpanic(); }));
assert_eq!(map.len(), 9);
assert!(!map.contains_key(&0));
// add new key
let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { map.entry(100) <- mkpanic(); }));
assert_eq!(map.len(), 9);
assert!(!map.contains_key(&100));
}
#[test]
fn test_placement_drop() {
// correctly drop
struct TestV<'a>(&'a mut bool);
impl<'a> Drop for TestV<'a> {
fn drop(&mut self) {
if !*self.0 { panic!("value double drop!"); } // no double drop
*self.0 = false;
}
}
fn makepanic<'a>() -> TestV<'a> { panic!() }
let mut can_drop = true;
let mut hm = HashMap::new();
hm.insert(0, TestV(&mut can_drop));
let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { hm.entry(0) <- makepanic(); }));
assert_eq!(hm.len(), 0);
}
#[test]
fn test_try_reserve() {
......
......@@ -486,21 +486,6 @@ pub fn put(mut self, hash: SafeHash, key: K, value: V) -> FullBucket<K, V, M> {
table: self.table,
}
}
/// Puts given key, remain value uninitialized.
/// It is only used for inplacement insertion.
pub unsafe fn put_key(mut self, hash: SafeHash, key: K) -> FullBucket<K, V, M> {
*self.raw.hash() = hash.inspect();
let pair_ptr = self.raw.pair();
ptr::write(&mut (*pair_ptr).0, key);
self.table.borrow_table_mut().size += 1;
FullBucket {
raw: self.raw,
table: self.table,
}
}
}
impl<K, V, M: Deref<Target = RawTable<K, V>>> FullBucket<K, V, M> {
......@@ -576,17 +561,6 @@ pub fn take(self) -> (EmptyBucket<K, V, &'t mut RawTable<K, V>>, K, V) {
v)
}
}
/// Remove this bucket's `key` from the hashtable.
/// Only used for inplacement insertion.
/// NOTE: `Value` is uninitialized when this function is called, don't try to drop the `Value`.
pub unsafe fn remove_key(&mut self) {
self.table.size -= 1;
*self.raw.hash() = EMPTY_BUCKET;
let pair_ptr = self.raw.pair();
ptr::drop_in_place(&mut (*pair_ptr).0); // only drop key
}
}
// This use of `Put` is misleading and restrictive, but safe and sufficient for our use cases
......
......@@ -290,7 +290,6 @@
#![feature(panic_internals)]
#![feature(panic_unwind)]
#![feature(peek)]
#![feature(placement_in_syntax)]
#![feature(placement_new_protocol)]
#![feature(prelude_import)]
#![feature(ptr_internals)]
......
......@@ -1011,7 +1011,6 @@ pub(super) fn to_ty(&self) -> Option<P<Ty>> {
pub fn precedence(&self) -> ExprPrecedence {
match self.node {
ExprKind::Box(_) => ExprPrecedence::Box,
ExprKind::InPlace(..) => ExprPrecedence::InPlace,
ExprKind::Array(_) => ExprPrecedence::Array,
ExprKind::Call(..) => ExprPrecedence::Call,
ExprKind::MethodCall(..) => ExprPrecedence::MethodCall,
......@@ -1071,8 +1070,6 @@ pub enum RangeLimits {
pub enum ExprKind {
/// A `box x` expression.
Box(P<Expr>),
/// First expr is the place; second expr is the value.
InPlace(P<Expr>, P<Expr>),
/// An array (`[a, b, c, d]`)
Array(Vec<P<Expr>>),
/// A function call
......
......@@ -146,7 +146,6 @@ pub fn walk_feature_fields<F>(&self, mut f: F)
(active, rustc_diagnostic_macros, "1.0.0", None, None),
(active, rustc_const_unstable, "1.0.0", None, None),
(active, box_syntax, "1.0.0", Some(27779), None),
(active, placement_in_syntax, "1.0.0", Some(27779), None),
(active, unboxed_closures, "1.0.0", Some(29625), None),
(active, fundamental, "1.0.0", Some(29635), None),
......@@ -1287,9 +1286,6 @@ fn leveled_feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue
pub const EXPLAIN_LIFETIME_MATCHER: &'static str =
":lifetime fragment specifier is experimental and subject to change";
pub const EXPLAIN_PLACEMENT_IN: &'static str =
"placement-in expression syntax is experimental and subject to change.";
pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &'static str =
"Unsized tuple coercion is not stable enough for use and is subject to change";
......@@ -1636,9 +1632,6 @@ fn visit_expr(&mut self, e: &'a ast::Expr) {
gate_feature_post!(&self, type_ascription, e.span,
"type ascription is experimental");
}
ast::ExprKind::InPlace(..) => {
gate_feature_post!(&self, placement_in_syntax, e.span, EXPLAIN_PLACEMENT_IN);
}
ast::ExprKind::Yield(..) => {
gate_feature_post!(&self, generators,
e.span,
......
......@@ -1167,9 +1167,6 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
ExprKind::Box(e) => {
ExprKind::Box(folder.fold_expr(e))
}
ExprKind::InPlace(p, e) => {
ExprKind::InPlace(folder.fold_expr(p), folder.fold_expr(e))
}
ExprKind::Array(exprs) => {
ExprKind::Array(folder.fold_exprs(exprs))
}
......
......@@ -2850,17 +2850,6 @@ pub fn parse_prefix_expr(&mut self,
let (span, e) = self.interpolated_or_expr_span(e)?;
(lo.to(span), ExprKind::AddrOf(m, e))
}
token::Ident(..) if self.token.is_keyword(keywords::In) => {
self.bump();
let place = self.parse_expr_res(
Restrictions::NO_STRUCT_LITERAL,
None,
)?;
let blk = self.parse_block()?;
let span = blk.span;
let blk_expr = self.mk_expr(span, ExprKind::Block(blk), ThinVec::new());
(lo.to(span), ExprKind::InPlace(place, blk_expr))
}
token::Ident(..) if self.token.is_keyword(keywords::Box) => {
self.bump();
let e = self.parse_prefix_expr(None);
......@@ -3023,8 +3012,6 @@ pub fn parse_assoc_expr_with(&mut self,
}
AssocOp::Assign =>
self.mk_expr(span, ExprKind::Assign(lhs, rhs), ThinVec::new()),
AssocOp::Inplace =>
self.mk_expr(span, ExprKind::InPlace(lhs, rhs), ThinVec::new()),
AssocOp::AssignOp(k) => {
let aop = match k {
token::Plus => BinOpKind::Add,
......
......@@ -1877,16 +1877,6 @@ pub fn print_expr_as_cond(&mut self, expr: &ast::Expr) -> io::Result<()> {
Ok(())
}
fn print_expr_in_place(&mut self,
place: &ast::Expr,
expr: &ast::Expr) -> io::Result<()> {
let prec = AssocOp::Inplace.precedence() as i8;
self.print_expr_maybe_paren(place, prec + 1)?;
self.s.space()?;
self.word_space("<-")?;
self.print_expr_maybe_paren(expr, prec)
}
fn print_expr_vec(&mut self, exprs: &[P<ast::Expr>],
attrs: &[Attribute]) -> io::Result<()> {
self.ibox(INDENT_UNIT)?;
......@@ -2056,9 +2046,6 @@ fn print_expr_outer_attr_style(&mut self,
self.word_space("box")?;
self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)?;
}
ast::ExprKind::InPlace(ref place, ref expr) => {
self.print_expr_in_place(place, expr)?;
}
ast::ExprKind::Array(ref exprs) => {
self.print_expr_vec(&exprs[..], attrs)?;
}
......
......@@ -56,8 +56,6 @@ pub enum AssocOp {
GreaterEqual,
/// `=`
Assign,
/// `<-`
Inplace,
/// `?=` where ? is one of the BinOpToken
AssignOp(BinOpToken),
/// `as`
......@@ -86,7 +84,6 @@ pub fn from_token(t: &Token) -> Option<AssocOp> {
use self::AssocOp::*;
match *t {
Token::BinOpEq(k) => Some(AssignOp(k)),
Token::LArrow => Some(Inplace),
Token::Eq => Some(Assign),
Token::BinOp(BinOpToken::Star) => Some(Multiply),
Token::BinOp(BinOpToken::Slash) => Some(Divide),
......@@ -156,7 +153,6 @@ pub fn precedence(&self) -> usize {
LAnd => 6,
LOr => 5,
DotDot | DotDotEq => 4,
Inplace => 3,
Assign | AssignOp(_) => 2,
}
}
......@@ -166,7 +162,7 @@ pub fn fixity(&self) -> Fixity {
use self::AssocOp::*;
// NOTE: it is a bug to have an operators that has same precedence but different fixities!
match *self {
Inplace | Assign | AssignOp(_) => Fixity::Right,
Assign | AssignOp(_) => Fixity::Right,
As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd |
BitXor | BitOr | Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual |
LAnd | LOr | Colon => Fixity::Left,
......@@ -178,7 +174,7 @@ pub fn is_comparison(&self) -> bool {
use self::AssocOp::*;
match *self {
Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => true,
Inplace | Assign | AssignOp(_) | As | Multiply | Divide | Modulus | Add | Subtract |
Assign | AssignOp(_) | As | Multiply | Divide | Modulus | Add | Subtract |
ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr |
DotDot | DotDotEq | Colon => false
}
......@@ -187,7 +183,7 @@ pub fn is_comparison(&self) -> bool {
pub fn is_assign_like(&self) -> bool {
use self::AssocOp::*;
match *self {
Assign | AssignOp(_) | Inplace => true,
Assign | AssignOp(_) => true,
Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | As | Multiply | Divide |
Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd |
LOr | DotDot | DotDotEq | Colon => false
......@@ -215,7 +211,7 @@ pub fn to_ast_binop(&self) -> Option<BinOpKind> {
BitOr => Some(BinOpKind::BitOr),
LAnd => Some(BinOpKind::And),
LOr => Some(BinOpKind::Or),
Inplace | Assign | AssignOp(_) | As | DotDot | DotDotEq | Colon => None
Assign | AssignOp(_) | As | DotDot | DotDotEq | Colon => None
}
}
}
......@@ -242,7 +238,6 @@ pub enum ExprPrecedence {
Binary(BinOpKind),
InPlace,
Cast,
Type,
......@@ -310,7 +305,6 @@ pub fn order(self) -> i8 {
// Binop-like expr kinds, handled by `AssocOp`.
ExprPrecedence::Binary(op) => AssocOp::from_ast_binop(op).precedence() as i8,
ExprPrecedence::InPlace => AssocOp::Inplace.precedence() as i8,
ExprPrecedence::Cast => AssocOp::As.precedence() as i8,
ExprPrecedence::Type => AssocOp::Colon.precedence() as i8,
......
......@@ -654,10 +654,6 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
ExprKind::Box(ref subexpression) => {
visitor.visit_expr(subexpression)
}
ExprKind::InPlace(ref place, ref subexpression) => {
visitor.visit_expr(place);
visitor.visit_expr(subexpression)
}
ExprKind::Array(ref subexpressions) => {
walk_list!(visitor, visit_expr, subexpressions);
}
......
......@@ -430,7 +430,6 @@ pub enum ExpnFormat {
/// The kind of compiler desugaring.
#[derive(Clone, Hash, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
pub enum CompilerDesugaringKind {
BackArrow,
DotFill,
QuestionMark,
}
......@@ -439,7 +438,6 @@ impl CompilerDesugaringKind {
pub fn as_symbol(&self) -> Symbol {
use CompilerDesugaringKind::*;
let s = match *self {
BackArrow => "<-",
DotFill => "...",
QuestionMark => "?",
};
......
// Copyright 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(box_syntax)]
#![feature(placement_in_syntax)]
fn main() {
() <- 0;
//~^ ERROR: `(): std::ops::Placer<_>` is not satisfied
}
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Check that placement in respects unsafe code checks.
#![feature(box_heap)]
#![feature(placement_in_syntax)]
fn main() {
use std::boxed::HEAP;
let p: *const i32 = &42;
let _ = HEAP <- *p; //~ ERROR requires unsafe
let p: *const _ = &HEAP;
let _ = *p <- 42; //~ ERROR requires unsafe
}
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Check that placement in respects unstable code checks.
#![feature(placement_in_syntax)]
fn main() {
use std::boxed::HEAP; //~ ERROR use of unstable library feature
let _ = HEAP <- { //~ ERROR use of unstable library feature
HEAP //~ ERROR use of unstable library feature
};
}
......@@ -13,10 +13,9 @@
fn that_odd_parse() {
// following lines below parse and must not fail
x = if c { a } else { b }();
x <- if c { a } else { b }[n];
x = if true { 1 } else { 0 } as *mut _;
// however this does not parse and probably should fail to retain compat?
// NB: `..` here is arbitrary, failure happens/should happen ∀ops that aren’t `=` or `<-`
// NB: `..` here is arbitrary, failure happens/should happen ∀ops that aren’t `=`
// see assoc-oddities-2 and assoc-oddities-3
..if c { a } else { b }[n]; //~ ERROR expected one of
}
......@@ -12,7 +12,6 @@
#![feature(custom_attribute)]
#![feature(box_syntax)]
#![feature(placement_in_syntax)]
#![feature(stmt_expr_attributes)]
fn main() { }
......
......@@ -126,16 +126,6 @@ fn run() {
check_expr_attrs("#[attr] box 0", outer);
reject_expr_parse("box #![attr] 0");
check_expr_attrs("#[attr] 0 <- #[attr] 0", none);
check_expr_attrs("#[attr] (0 <- 0)", outer);
reject_expr_parse("0 #[attr] <- 0");
reject_expr_parse("0 <- #![attr] 0");
check_expr_attrs("in #[attr] 0 {#[attr] 0}", none);
check_expr_attrs("#[attr] (in 0 {0})", outer);
reject_expr_parse("in 0 #[attr] {0}");
reject_expr_parse("in 0 {#![attr] 0}");
check_expr_attrs("#[attr] [#![attr]]", both);
check_expr_attrs("#[attr] [#![attr] 0]", both);
check_expr_attrs("#[attr] [#![attr] 0; 0]", both);
......
......@@ -84,18 +84,11 @@ fn iter_exprs(depth: usize, f: &mut FnMut(P<Expr>)) {
let mut g = |e| f(expr(e));
for kind in 0 .. 17 {
for kind in 0 .. 16 {
match kind {
0 => iter_exprs(depth - 1, &mut |e| g(ExprKind::Box(e))),
1 => {
// Note that for binary expressions, we explore each side separately. The
// parenthesization decisions for the LHS and RHS should be independent, and this
// way produces `O(n)` results instead of `O(n^2)`.
iter_exprs(depth - 1, &mut |e| g(ExprKind::InPlace(e, make_x())));
iter_exprs(depth - 1, &mut |e| g(ExprKind::InPlace(make_x(), e)));
},
2 => iter_exprs(depth - 1, &mut |e| g(ExprKind::Call(e, vec![]))),
3 => {
1 => iter_exprs(depth - 1, &mut |e| g(ExprKind::Call(e, vec![]))),
2 => {
let seg = PathSegment {
identifier: Ident::from_str("x"),
span: DUMMY_SP,
......@@ -107,25 +100,25 @@ fn iter_exprs(depth: usize, f: &mut FnMut(P<Expr>)) {
iter_exprs(depth - 1, &mut |e| g(ExprKind::MethodCall(
seg.clone(), vec![make_x(), e])));
},
4 => {
3 => {
let op = Spanned { span: DUMMY_SP, node: BinOpKind::Add };
iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, e, make_x())));
iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, make_x(), e)));
},
5 => {
4 => {
let op = Spanned { span: DUMMY_SP, node: BinOpKind::Mul };
iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, e, make_x())));
iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, make_x(), e)));
},
6 => {
5 => {
let op = Spanned { span: DUMMY_SP, node: BinOpKind::Shl };
iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, e, make_x())));
iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, make_x(), e)));
},
7 => {
6 => {
iter_exprs(depth - 1, &mut |e| g(ExprKind::Unary(UnOp::Deref, e)));
},
8 => {
7 => {
let block = P(Block {
stmts: Vec::new(),
id: DUMMY_NODE_ID,
......@@ -135,7 +128,7 @@ fn iter_exprs(depth: usize, f: &mut FnMut(P<Expr>)) {
});
iter_exprs(depth - 1, &mut |e| g(ExprKind::If(e, block.clone(), None)));
},
9 => {
8 => {
let decl = P(FnDecl {
inputs: vec![],
output: FunctionRetTy::Default(DUMMY_SP),
......@@ -148,28 +141,28 @@ fn iter_exprs(depth: usize, f: &mut FnMut(P<Expr>)) {
e,
DUMMY_SP)));
},
10 => {
9 => {
iter_exprs(depth - 1, &mut |e| g(ExprKind::Assign(e, make_x())));
iter_exprs(depth - 1, &mut |e| g(ExprKind::Assign(make_x(), e)));
},
11 => {
10 => {
let ident = Spanned { span: DUMMY_SP, node: Ident::from_str("f") };
iter_exprs(depth - 1, &mut |e| g(ExprKind::Field(e, ident)));
},
12 => {
11 => {
iter_exprs(depth - 1, &mut |e| g(ExprKind::Range(
Some(e), Some(make_x()), RangeLimits::HalfOpen)));
iter_exprs(depth - 1, &mut |e| g(ExprKind::Range(
Some(make_x()), Some(e), RangeLimits::HalfOpen)));
},
13 => {
12 => {
iter_exprs(depth - 1, &mut |e| g(ExprKind::AddrOf(Mutability::Immutable, e)));
},
14 => {
13 => {
g(ExprKind::Ret(None));
iter_exprs(depth - 1, &mut |e| g(ExprKind::Ret(Some(e))));
},
15 => {
14 => {
let seg = PathSegment {
identifier: Ident::from_str("S"),
span: DUMMY_SP,
......@@ -181,7 +174,7 @@ fn iter_exprs(depth: usize, f: &mut FnMut(P<Expr>)) {
};
g(ExprKind::Struct(path, vec![], Some(make_x())));
},
16 => {
15 => {
iter_exprs(depth - 1, &mut |e| g(ExprKind::Try(e)));
},
_ => panic!("bad counter value in iter_exprs"),
......
......@@ -14,16 +14,11 @@
* http://creativecommons.org/publicdomain/zero/1.0/ */
#![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)]
#![feature(box_syntax)]
// Tests that the new `box` syntax works with unique pointers.
use std::boxed::{Box, HEAP};
use std::boxed::Box;
struct Structure {
x: isize,
......@@ -31,7 +26,6 @@ struct Structure {
}
pub fn main() {
let x: Box<isize> = in HEAP { 2 };
let y: Box<isize> = box 2;
let b: Box<isize> = box (1 + 2);
let c = box (3 + 4);
......
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<isize> = in HEAP { 2 };
let b: Box<isize> = in HEAP { 1 + 2 };
let c = in HEAP { 3 + 4 };
let s: Box<Structure> = in HEAP {
Structure {
x: 3,
y: 4,
}
};
}
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// gate-test-placement_in_syntax
// 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 = HEAP <- 'c'; //~ ERROR placement-in expression syntax is experimental
println!("x: {}", x);
}
error[E0658]: placement-in expression syntax is experimental and subject to change. (see issue #27779)
--> $DIR/feature-gate-placement-expr.rs:24:13
|
LL | let x = HEAP <- 'c'; //~ ERROR placement-in expression syntax is experimental
| ^^^^^^^^^^^
|
= help: add #![feature(placement_in_syntax)] to the crate attributes to enable
error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册