SRC=.
DEPLOY_ALT=1
RUSTC_RETRY_LINKER_ON_SEGFAULT=1
- SCCACHE_ERROR_LOG=/tmp/sccache.log
MACOSX_DEPLOYMENT_TARGET=10.7
NO_LLVM_ASSERTIONS=1
NO_DEBUG_ASSERTIONS=1
RUST_CONFIGURE_ARGS="--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler"
SRC=.
RUSTC_RETRY_LINKER_ON_SEGFAULT=1
- SCCACHE_ERROR_LOG=/tmp/sccache.log
MACOSX_DEPLOYMENT_TARGET=10.8
MACOSX_STD_DEPLOYMENT_TARGET=10.7
NO_LLVM_ASSERTIONS=1
RUST_CONFIGURE_ARGS=--build=i686-apple-darwin
SRC=.
RUSTC_RETRY_LINKER_ON_SEGFAULT=1
- SCCACHE_ERROR_LOG=/tmp/sccache.log
MACOSX_DEPLOYMENT_TARGET=10.8
MACOSX_STD_DEPLOYMENT_TARGET=10.7
NO_LLVM_ASSERTIONS=1
SRC=.
DEPLOY=1
RUSTC_RETRY_LINKER_ON_SEGFAULT=1
- SCCACHE_ERROR_LOG=/tmp/sccache.log
MACOSX_DEPLOYMENT_TARGET=10.7
NO_LLVM_ASSERTIONS=1
NO_DEBUG_ASSERTIONS=1
SRC=.
DEPLOY=1
RUSTC_RETRY_LINKER_ON_SEGFAULT=1
- SCCACHE_ERROR_LOG=/tmp/sccache.log
MACOSX_DEPLOYMENT_TARGET=10.7
NO_LLVM_ASSERTIONS=1
NO_DEBUG_ASSERTIONS=1
travis_retry brew update &&
travis_retry brew install xz;
fi &&
- travis_retry curl -fo /usr/local/bin/sccache https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/2017-05-12-sccache-x86_64-apple-darwin &&
+ travis_retry curl -fo /usr/local/bin/sccache https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/2018-04-02-sccache-x86_64-apple-darwin &&
chmod +x /usr/local/bin/sccache &&
travis_retry curl -fo /usr/local/bin/stamp https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/2017-03-17-stamp-x86_64-apple-darwin &&
chmod +x /usr/local/bin/stamp
df -h;
du . | sort -nr | head -n100
- # One of these is the linux sccache log, one is the OSX sccache log. Instead
- # of worrying about what system we are just cat both. One of these commands
- # will fail but that's ok, they'll both get executed.
- - cat obj/tmp/sccache.log
- - cat /tmp/sccache.log
-
# Random attempt at debugging currently. Just poking around in here to see if
# anything shows up.
- ls -lat $HOME/Library/Logs/DiagnosticReports/
- set PATH=C:\Python27;%PATH%
# Download and install sccache
- - appveyor-retry appveyor DownloadFile https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/2017-05-12-sccache-x86_64-pc-windows-msvc
- - mv 2017-05-12-sccache-x86_64-pc-windows-msvc sccache.exe
+ - appveyor-retry appveyor DownloadFile https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/2018-04-02-sccache-x86_64-pc-windows-msvc
+ - mv 2018-04-02-sccache-x86_64-pc-windows-msvc sccache.exe
- set PATH=%PATH%;%CD%
# Download and install ninja
- set PATH=%PATH%;%CD%\handle
- handle.exe -accepteula -help
- # Attempt to debug sccache failures
- - set SCCACHE_ERROR_LOG=%CD%/sccache.log
-
test_script:
- if not exist C:\cache\rustsrc\NUL mkdir C:\cache\rustsrc
- sh src/ci/init_repo.sh . /c/cache/rustsrc
- set NO_CCACHE=1
- sh src/ci/run.sh
-on_failure:
- - cat %CD%\sccache.log || exit 0
-
branches:
only:
- auto
bash musl.sh mipsel && \
rm -rf /build/*
+# FIXME(mozilla/sccache#235) this shouldn't be necessary but is currently
+# necessary to disambiguate the mips compiler with the mipsel compiler. We want
+# to give these two wrapper scripts (currently identical ones) different hashes
+# to ensure that sccache understands that they're different compilers.
+RUN \
+ echo "# a" >> /usr/local/mips-linux-musl/bin/mips-openwrt-linux-musl-wrapper.sh && \
+ echo "# b" >> /usr/local/mipsel-linux-musl/bin/mipsel-openwrt-linux-musl-wrapper.sh
+
ENV TARGETS=asmjs-unknown-emscripten
ENV TARGETS=$TARGETS,wasm32-unknown-emscripten
ENV TARGETS=$TARGETS,x86_64-rumprun-netbsd
args="$args --env SCCACHE_REGION"
args="$args --env AWS_ACCESS_KEY_ID"
args="$args --env AWS_SECRET_ACCESS_KEY"
- args="$args --env SCCACHE_ERROR_LOG=/tmp/sccache/sccache.log"
- args="$args --volume $objdir/tmp:/tmp/sccache"
else
mkdir -p $HOME/.cache/sccache
args="$args --env SCCACHE_DIR=/sccache --volume $HOME/.cache/sccache:/sccache"
set -ex
curl -fo /usr/local/bin/sccache \
- https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/2017-05-12-sccache-x86_64-unknown-linux-musl
+ https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/2018-04-02-sccache-x86_64-unknown-linux-musl
chmod +x /usr/local/bin/sccache
+++ /dev/null
-# `splice`
-
-The tracking issue for this feature is: [#44643]
-
-[#44643]: https://github.com/rust-lang/rust/issues/44643
-
-------------------------
-
-The `splice()` method on `String` allows you to replace a range
-of values in a string with another range of values.
-
-A simple example:
-
-```rust
-#![feature(splice)]
-let mut s = String::from("α is alpha, β is beta");
-let beta_offset = s.find('β').unwrap_or(s.len());
-
-// Replace the range up until the β from the string
-s.splice(..beta_offset, "Α is capital alpha; ");
-assert_eq!(s, "Α is capital alpha; β is beta");
-```
| 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); }
| 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); }
| 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); }
#![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;
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)
- }
-}
/// let vv: Vec<i32> = v.to_owned();
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use = "cloning is often expensive and is not expected to have side effects"]
fn to_owned(&self) -> Self::Owned;
/// Uses borrowed data to replace owned data, usually by cloning.
#![stable(feature = "rust1", since = "1.0.0")]
-use heap::Heap;
use raw_vec::RawVec;
use core::any::Any;
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.
#[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.
///
#![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))]
#![feature(fundamental)]
#![feature(generic_param_attrs)]
#![cfg_attr(stage0, feature(i128_type))]
-#![feature(iter_rfold)]
#![feature(lang_items)]
#![feature(needs_allocator)]
#![feature(nonzero)]
#![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)]
#![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
// 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;
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.
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")]
}
}
-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() {
}
}
- /// Creates a splicing iterator that removes the specified range in the string,
+ /// Removes the specified range in the string,
/// and replaces it with the given string.
/// The given string doesn't need to be the same length as the range.
///
/// Basic usage:
///
/// ```
- /// #![feature(splice)]
/// let mut s = String::from("α is alpha, β is beta");
/// let beta_offset = s.find('β').unwrap_or(s.len());
///
/// // Replace the range up until the β from the string
- /// s.splice(..beta_offset, "Α is capital alpha; ");
+ /// s.replace_range(..beta_offset, "Α is capital alpha; ");
/// assert_eq!(s, "Α is capital alpha; β is beta");
/// ```
- #[unstable(feature = "splice", reason = "recently added", issue = "44643")]
- pub fn splice<R>(&mut self, range: R, replace_with: &str)
+ #[stable(feature = "splice", since = "1.27.0")]
+ pub fn replace_range<R>(&mut self, range: R, replace_with: &str)
where R: RangeBounds<usize>
{
// Memory safety
//
- // The String version of Splice does not have the memory safety issues
+ // Replace_range does not have the memory safety issues of a vector Splice.
// of the vector version. The data is just plain bytes.
match range.start() {
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> {
#![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)]
}
#[test]
-fn test_splice() {
+fn test_replace_range() {
let mut s = "Hello, world!".to_owned();
- s.splice(7..12, "世界");
+ s.replace_range(7..12, "世界");
assert_eq!(s, "Hello, 世界!");
}
#[test]
#[should_panic]
-fn test_splice_char_boundary() {
+fn test_replace_range_char_boundary() {
let mut s = "Hello, 世界!".to_owned();
- s.splice(..8, "");
+ s.replace_range(..8, "");
}
#[test]
-fn test_splice_inclusive_range() {
+fn test_replace_range_inclusive_range() {
let mut v = String::from("12345");
- v.splice(2..=3, "789");
+ v.replace_range(2..=3, "789");
assert_eq!(v, "127895");
- v.splice(1..=2, "A");
+ v.replace_range(1..=2, "A");
assert_eq!(v, "1A895");
}
#[test]
#[should_panic]
-fn test_splice_out_of_bounds() {
+fn test_replace_range_out_of_bounds() {
let mut s = String::from("12345");
- s.splice(5..6, "789");
+ s.replace_range(5..6, "789");
}
#[test]
#[should_panic]
-fn test_splice_inclusive_out_of_bounds() {
+fn test_replace_range_inclusive_out_of_bounds() {
let mut s = String::from("12345");
- s.splice(5..=5, "789");
+ s.replace_range(5..=5, "789");
}
#[test]
-fn test_splice_empty() {
+fn test_replace_range_empty() {
let mut s = String::from("12345");
- s.splice(1..2, "");
+ s.replace_range(1..2, "");
assert_eq!(s, "1345");
}
#[test]
-fn test_splice_unbounded() {
+fn test_replace_range_unbounded() {
let mut s = String::from("12345");
- s.splice(.., "");
+ s.replace_range(.., "");
assert_eq!(s, "");
}
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::*;
}
}
-#[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];
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
#[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;
}
}
- /// 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.
///
}
other
}
+
+ /// Resizes the `Vec` in-place so that `len` is equal to `new_len`.
+ ///
+ /// If `new_len` is greater than `len`, the `Vec` is extended by the
+ /// difference, with each additional slot filled with the result of
+ /// calling the closure `f`. The return values from `f` will end up
+ /// in the `Vec` in the order they have been generated.
+ ///
+ /// If `new_len` is less than `len`, the `Vec` is simply truncated.
+ ///
+ /// This method uses a closure to create new values on every push. If
+ /// you'd rather [`Clone`] a given value, use [`resize`]. If you want
+ /// to use the [`Default`] trait to generate values, you can pass
+ /// [`Default::default()`] as the second argument..
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(vec_resize_with)]
+ ///
+ /// let mut vec = vec![1, 2, 3];
+ /// vec.resize_with(5, Default::default);
+ /// assert_eq!(vec, [1, 2, 3, 0, 0]);
+ ///
+ /// let mut vec = vec![];
+ /// let mut p = 1;
+ /// vec.resize_with(4, || { p *= 2; p });
+ /// assert_eq!(vec, [2, 4, 8, 16]);
+ /// ```
+ ///
+ /// [`resize`]: #method.resize
+ /// [`Clone`]: ../../std/clone/trait.Clone.html
+ #[unstable(feature = "vec_resize_with", issue = "41758")]
+ pub fn resize_with<F>(&mut self, new_len: usize, f: F)
+ where F: FnMut() -> T
+ {
+ let len = self.len();
+ if new_len > len {
+ self.extend_with(new_len - len, ExtendFunc(f));
+ } else {
+ self.truncate(new_len);
+ }
+ }
}
impl<T: Clone> Vec<T> {
/// If `new_len` is less than `len`, the `Vec` is simply truncated.
///
/// This method requires [`Clone`] to be able clone the passed value. If
- /// you'd rather create a value with [`Default`] instead, see
- /// [`resize_default`].
+ /// you need more flexibility (or want to rely on [`Default`] instead of
+ /// [`Clone`]), use [`resize_with`].
///
/// # Examples
///
///
/// [`Clone`]: ../../std/clone/trait.Clone.html
/// [`Default`]: ../../std/default/trait.Default.html
- /// [`resize_default`]: #method.resize_default
+ /// [`resize_with`]: #method.resize_with
#[stable(feature = "vec_resize", since = "1.5.0")]
pub fn resize(&mut self, new_len: usize, value: T) {
let len = self.len();
// This code generalises `extend_with_{element,default}`.
trait ExtendWith<T> {
- fn next(&self) -> T;
+ fn next(&mut self) -> T;
fn last(self) -> T;
}
struct ExtendElement<T>(T);
impl<T: Clone> ExtendWith<T> for ExtendElement<T> {
- fn next(&self) -> T { self.0.clone() }
+ fn next(&mut self) -> T { self.0.clone() }
fn last(self) -> T { self.0 }
}
struct ExtendDefault;
impl<T: Default> ExtendWith<T> for ExtendDefault {
- fn next(&self) -> T { Default::default() }
+ fn next(&mut self) -> T { Default::default() }
fn last(self) -> T { Default::default() }
}
+
+struct ExtendFunc<F>(F);
+impl<T, F: FnMut() -> T> ExtendWith<T> for ExtendFunc<F> {
+ fn next(&mut self) -> T { (self.0)() }
+ fn last(mut self) -> T { (self.0)() }
+}
+
impl<T> Vec<T> {
/// Extend the vector by `n` values, using the given generator.
- fn extend_with<E: ExtendWith<T>>(&mut self, n: usize, value: E) {
+ fn extend_with<E: ExtendWith<T>>(&mut self, n: usize, mut value: E) {
self.reserve(n);
unsafe {
#[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
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;
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> {
}
}
-/// 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;
let ptr = if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
libc::malloc(layout.size()) as *mut u8
} else {
+ #[cfg(target_os = "macos")]
+ {
+ if layout.align() > (1 << 31) {
+ return Err(AllocErr::Unsupported {
+ details: "requested alignment too large"
+ })
+ }
+ }
aligned_malloc(&layout)
};
if !ptr.is_null() {
/// assert_eq!("Hello", hello.clone());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use = "cloning is often expensive and is not expected to have side effects"]
fn clone(&self) -> Self;
/// Performs copy-assignment from `source`.
impl Layout {
/// Constructs a `Layout` from a given `size` and `align`,
- /// or returns `None` if any of the following conditions
+ /// or returns `None` if either of the following conditions
/// are not met:
///
/// * `align` must be a power of two,
///
- /// * `align` must not exceed 2<sup>31</sup> (i.e. `1 << 31`),
- ///
/// * `size`, when rounded up to the nearest multiple of `align`,
/// must not overflow (i.e. the rounded value must be less than
/// `usize::MAX`).
return None;
}
- if align > (1 << 31) {
- return None;
- }
-
// (power-of-two implies align != 0.)
// Rounded up size is:
/// # Safety
///
/// This function is unsafe as it does not verify that `align` is
- /// a power-of-two that is also less than or equal to 2<sup>31</sup>, nor
- /// that `size` aligned to `align` fits within the address space
- /// (i.e. the `Layout::from_size_align` preconditions).
+ /// a power-of-two nor `size` aligned to `align` fits within the
+ /// address space (i.e. the `Layout::from_size_align` preconditions).
#[inline]
pub unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Layout {
Layout { size: size, align: align }
let padded_size = self.size.checked_add(self.padding_needed_for(self.align))?;
let alloc_size = padded_size.checked_mul(n)?;
- // We can assume that `self.align` is a power-of-two that does
- // not exceed 2<sup>31</sup>. Furthermore, `alloc_size` has already been
- // rounded up to a multiple of `self.align`; therefore, the
- // call to `Layout::from_size_align` below should never panic.
+ // We can assume that `self.align` is a power-of-two.
+ // Furthermore, `alloc_size` has already been rounded up
+ // to a multiple of `self.align`; therefore, the call to
+ // `Layout::from_size_align` below should never panic.
Some((Layout::from_size_align(alloc_size, self.align).unwrap(), padded_size))
}
/// [`Result`]: ../../std/result/enum.Result.html
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use = "if you really need to exhaust the iterator, consider `.for_each(drop)` instead"]
fn collect<B: FromIterator<Self::Item>>(self) -> B where Self: Sized {
FromIterator::from_iter(self)
}
/// Basic usage:
///
/// ```
- /// #![feature(iterator_try_fold)]
/// let a = [1, 2, 3];
///
/// // the checked sum of all of the elements of the array
/// Short-circuiting:
///
/// ```
- /// #![feature(iterator_try_fold)]
/// let a = [10, 20, 30, 100, 40, 50];
/// let mut it = a.iter();
///
/// assert_eq!(it.next(), Some(&40));
/// ```
#[inline]
- #[unstable(feature = "iterator_try_fold", issue = "45594")]
+ #[stable(feature = "iterator_try_fold", since = "1.27.0")]
fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R where
Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try<Ok=B>
{
/// # Examples
///
/// ```
- /// #![feature(iterator_try_fold)]
/// use std::fs::rename;
/// use std::io::{stdout, Write};
/// use std::path::Path;
/// assert_eq!(it.next(), Some("stale_bread.json"));
/// ```
#[inline]
- #[unstable(feature = "iterator_try_fold", issue = "45594")]
+ #[stable(feature = "iterator_try_fold", since = "1.27.0")]
fn try_for_each<F, R>(&mut self, mut f: F) -> R where
Self: Sized, F: FnMut(Self::Item) -> R, R: Try<Ok=()>
{
}).break_value()
}
+ /// Applies function to the elements of iterator and returns
+ /// the first non-none result.
+ ///
+ /// `iter.find_map(f)` is equivalent to `iter.filter_map(f).next()`.
+ ///
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(iterator_find_map)]
+ /// let a = ["lol", "NaN", "2", "5"];
+ ///
+ /// let mut first_number = a.iter().find_map(|s| s.parse().ok());
+ ///
+ /// assert_eq!(first_number, Some(2));
+ /// ```
+ #[inline]
+ #[unstable(feature = "iterator_find_map",
+ reason = "unstable new API",
+ issue = "49602")]
+ fn find_map<B, F>(&mut self, mut f: F) -> Option<B> where
+ Self: Sized,
+ F: FnMut(Self::Item) -> Option<B>,
+ {
+ self.try_for_each(move |x| {
+ match f(x) {
+ Some(x) => LoopState::Break(x),
+ None => LoopState::Continue(()),
+ }
+ }).break_value()
+ }
+
/// Searches for an element in an iterator, returning its index.
///
/// `position()` takes a closure that returns `true` or `false`. It applies
/// Basic usage:
///
/// ```
- /// #![feature(iterator_try_fold)]
/// let a = ["1", "2", "3"];
/// let sum = a.iter()
/// .map(|&s| s.parse::<i32>())
/// Short-circuiting:
///
/// ```
- /// #![feature(iterator_try_fold)]
/// let a = ["1", "rust", "3"];
/// let mut it = a.iter();
/// let sum = it
/// assert_eq!(it.next_back(), Some(&"1"));
/// ```
#[inline]
- #[unstable(feature = "iterator_try_fold", issue = "45594")]
+ #[stable(feature = "iterator_try_fold", since = "1.27.0")]
fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R where
Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try<Ok=B>
{
/// Basic usage:
///
/// ```
- /// #![feature(iter_rfold)]
/// let a = [1, 2, 3];
///
/// // the sum of all of the elements of a
/// and continuing with each element from the back until the front:
///
/// ```
- /// #![feature(iter_rfold)]
/// let numbers = [1, 2, 3, 4, 5];
///
/// let zero = "0".to_string();
/// assert_eq!(result, "(1 + (2 + (3 + (4 + (5 + 0)))))");
/// ```
#[inline]
- #[unstable(feature = "iter_rfold", issue = "44705")]
+ #[stable(feature = "iter_rfold", since = "1.27.0")]
fn rfold<B, F>(mut self, accum: B, mut f: F) -> B where
Self: Sized, F: FnMut(B, Self::Item) -> B,
{
self.try_rfold(accum, move |acc, x| AlwaysOk(f(acc, x))).0
}
- /// Searches for an element of an iterator from the right that satisfies a predicate.
+ /// Searches for an element of an iterator from the back that satisfies a predicate.
///
/// `rfind()` takes a closure that returns `true` or `false`. It applies
/// this closure to each element of the iterator, starting at the end, and if any
/// Basic usage:
///
/// ```
- /// #![feature(iter_rfind)]
- ///
/// let a = [1, 2, 3];
///
/// assert_eq!(a.iter().rfind(|&&x| x == 2), Some(&2));
/// Stopping at the first `true`:
///
/// ```
- /// #![feature(iter_rfind)]
- ///
/// let a = [1, 2, 3];
///
/// let mut iter = a.iter();
/// assert_eq!(iter.next_back(), Some(&1));
/// ```
#[inline]
- #[unstable(feature = "iter_rfind", issue = "39480")]
+ #[stable(feature = "iter_rfind", since = "1.27.0")]
fn rfind<P>(&mut self, mut predicate: P) -> Option<Self::Item> where
Self: Sized,
P: FnMut(&Self::Item) -> bool
mod function;
mod generator;
mod index;
-mod place;
mod range;
mod try;
mod unsize;
#[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;
+++ /dev/null
-// 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;
-}
assert!(v.iter().find(|&&x| x % 12 == 0).is_none());
}
+#[test]
+fn test_find_map() {
+ let xs: &[isize] = &[];
+ assert_eq!(xs.iter().find_map(half_if_even), None);
+ let xs: &[isize] = &[3, 5];
+ assert_eq!(xs.iter().find_map(half_if_even), None);
+ let xs: &[isize] = &[4, 5];
+ assert_eq!(xs.iter().find_map(half_if_even), Some(2));
+ let xs: &[isize] = &[3, 6];
+ assert_eq!(xs.iter().find_map(half_if_even), Some(3));
+
+ let xs: &[isize] = &[1, 2, 3, 4, 5, 6, 7];
+ let mut iter = xs.iter();
+ assert_eq!(iter.find_map(half_if_even), Some(1));
+ assert_eq!(iter.find_map(half_if_even), Some(2));
+ assert_eq!(iter.find_map(half_if_even), Some(3));
+ assert_eq!(iter.next(), Some(&7));
+
+ fn half_if_even(x: &isize) -> Option<isize> {
+ if x % 2 == 0 {
+ Some(x / 2)
+ } else {
+ None
+ }
+ }
+}
+
#[test]
fn test_position() {
let v = &[1, 3, 9, 27, 103, 14, 11];
#![feature(iterator_step_by)]
#![cfg_attr(stage0, feature(i128_type))]
#![cfg_attr(stage0, feature(inclusive_range_syntax))]
-#![feature(iterator_try_fold)]
#![feature(iterator_flatten)]
#![cfg_attr(stage0, feature(conservative_impl_trait))]
-#![feature(iter_rfind)]
-#![feature(iter_rfold)]
#![feature(iterator_repeat_with)]
#![feature(nonzero)]
#![feature(pattern)]
#![feature(atomic_nand)]
#![feature(reverse_bits)]
#![feature(inclusive_range_fields)]
+#![feature(iterator_find_map)]
extern crate core;
extern crate test;
// Keep track of the previous guard expressions
let mut prev_guards = Vec::new();
- // Track if the previous pattern contained bindings or wildcards
- let mut prev_has_bindings = false;
for arm in arms {
// Add an exit node for when we've visited all the
// Visit the guard expression
let guard_exit = self.expr(&guard, guard_start);
- let this_has_bindings = pat.contains_bindings_or_wild();
-
- // If both this pattern and the previous pattern
- // were free of bindings, they must consist only
- // of "constant" patterns. Note we cannot match an
- // all-constant pattern, fail the guard, and then
- // match *another* all-constant pattern. This is
- // because if the previous pattern matches, then
- // we *cannot* match this one, unless all the
- // constants are the same (which is rejected by
- // `check_match`).
- //
- // We can use this to be smarter about the flow
- // along guards. If the previous pattern matched,
- // then we know we will not visit the guard in
- // this one (whether or not the guard succeeded),
- // if the previous pattern failed, then we know
- // the guard for that pattern will not have been
- // visited. Thus, it is not possible to visit both
- // the previous guard and the current one when
- // both patterns consist only of constant
- // sub-patterns.
- //
- // However, if the above does not hold, then all
- // previous guards need to be wired to visit the
- // current guard pattern.
- if prev_has_bindings || this_has_bindings {
- while let Some(prev) = prev_guards.pop() {
- self.add_contained_edge(prev, guard_start);
- }
+ // #47295: We used to have very special case code
+ // here for when a pair of arms are both formed
+ // solely from constants, and if so, not add these
+ // edges. But this was not actually sound without
+ // other constraints that we stopped enforcing at
+ // some point.
+ while let Some(prev) = prev_guards.pop() {
+ self.add_contained_edge(prev, guard_start);
}
- prev_has_bindings = this_has_bindings;
-
// Push the guard onto the list of previous guards
prev_guards.push(guard_exit);
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())
}
.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 {
});
impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind {
- BackArrow,
DotFill,
QuestionMark
});
impl_stable_hash_for!(struct ty::adjustment::Adjustment<'tcx> { kind, target });
impl_stable_hash_for!(struct ty::adjustment::OverloadedDeref<'tcx> { region, mutbl });
impl_stable_hash_for!(struct ty::UpvarBorrow<'tcx> { kind, region });
+impl_stable_hash_for!(enum ty::adjustment::AllowTwoPhase {
+ Yes,
+ No
+});
impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::adjustment::AutoBorrowMutability {
fn hash_stable<W: StableHasherResult>(&self,
tcx.hir.krate().visit_all_item_likes(&mut checker.as_deep_visitor());
}
+/// Check whether an item marked with `deprecated(since="X")` is currently
+/// deprecated (i.e. whether X is not greater than the current rustc version).
+pub fn deprecation_in_effect(since: &str) -> bool {
+ fn parse_version(ver: &str) -> Vec<u32> {
+ // We ignore non-integer components of the version (e.g. "nightly").
+ ver.split(|c| c == '.' || c == '-').flat_map(|s| s.parse()).collect()
+ }
+
+ if let Some(rustc) = option_env!("CFG_RELEASE") {
+ let since: Vec<u32> = parse_version(since);
+ let rustc: Vec<u32> = parse_version(rustc);
+ // We simply treat invalid `since` attributes as relating to a previous
+ // Rust version, thus always displaying the warning.
+ if since.len() != 3 {
+ return true;
+ }
+ since <= rustc
+ } else {
+ // By default, a deprecation warning applies to
+ // the current version of the compiler.
+ true
+ }
+}
+
struct Checker<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
// Deprecated attributes apply in-crate and cross-crate.
if let Some(id) = id {
if let Some(depr_entry) = self.lookup_deprecation_entry(def_id) {
+ // If the deprecation is scheduled for a future Rust
+ // version, then we should display no warning message.
+ let deprecated_in_future_version = if let Some(sym) = depr_entry.attr.since {
+ let since = sym.as_str();
+ !deprecation_in_effect(&since)
+ } else {
+ false
+ };
+
let parent_def_id = self.hir.local_def_id(self.hir.get_parent(id));
- let skip = self.lookup_deprecation_entry(parent_def_id)
- .map_or(false, |parent_depr| parent_depr.same_origin(&depr_entry));
+ let skip = deprecated_in_future_version ||
+ self.lookup_deprecation_entry(parent_def_id)
+ .map_or(false, |parent_depr| parent_depr.same_origin(&depr_entry));
if !skip {
lint_deprecated(def_id, id, depr_entry.attr.note);
}
}
}
+/// At least for initial deployment, we want to limit two-phase borrows to
+/// only a few specific cases. Right now, those mostly "things that desugar"
+/// into method calls
+/// - using x.some_method() syntax, where some_method takes &mut self
+/// - using Foo::some_method(&mut x, ...) syntax
+/// - binary assignment operators (+=, -=, *=, etc.)
+/// Anything else should be rejected until generalized two phase borrow support
+/// is implemented. Right now, dataflow can't handle the general case where there
+/// is more than one use of a mutable borrow, and we don't want to accept too much
+/// new code via two-phase borrows, so we try to limit where we create two-phase
+/// capable mutable borrows.
+/// See #49434 for tracking.
+#[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)]
+pub enum AllowTwoPhase {
+ Yes,
+ No
+}
+
#[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)]
pub enum AutoBorrowMutability {
- Mutable { allow_two_phase_borrow: bool },
+ Mutable { allow_two_phase_borrow: AllowTwoPhase },
Immutable,
}
/// Creates set holding every element whose index falls in range 0..universe_size.
pub fn new_filled(universe_size: usize) -> Self {
- Self::new(!0, universe_size)
+ let mut result = Self::new(!0, universe_size);
+ result.trim_to(universe_size);
+ result
}
/// Creates set holding no elements.
}
}
+ /// Sets all elements up to `universe_size`
+ pub fn set_up_to(&mut self, universe_size: usize) {
+ for b in &mut self.bits {
+ *b = !0;
+ }
+ self.trim_to(universe_size);
+ }
+
+ /// Clear all elements above `universe_size`.
+ fn trim_to(&mut self, universe_size: usize) {
+ let word_bits = mem::size_of::<Word>() * 8;
+
+ // `trim_block` is the first block where some bits have
+ // to be cleared.
+ let trim_block = universe_size / word_bits;
+
+ // all the blocks above it have to be completely cleared.
+ if trim_block < self.bits.len() {
+ for b in &mut self.bits[trim_block+1..] {
+ *b = 0;
+ }
+
+ // at that block, the `universe_size % word_bits` lsbs
+ // should remain.
+ let remaining_bits = universe_size % word_bits;
+ let mask = (1<<remaining_bits)-1;
+ self.bits[trim_block] &= mask;
+ }
+ }
+
/// Removes `elem` from the set `self`; returns true iff this changed `self`.
pub fn remove(&mut self, elem: &T) -> bool {
self.bits.clear_bit(elem.index())
}
}
}
+
+#[test]
+fn test_trim_to() {
+ use std::cmp;
+
+ for i in 0..256 {
+ let mut idx_buf: IdxSetBuf<usize> = IdxSetBuf::new_filled(128);
+ idx_buf.trim_to(i);
+
+ let elems: Vec<usize> = idx_buf.iter().collect();
+ let expected: Vec<usize> = (0..cmp::min(i, 128)).collect();
+ assert_eq!(elems, expected);
+ }
+}
+
+#[test]
+fn test_set_up_to() {
+ for i in 0..128 {
+ for mut idx_buf in
+ vec![IdxSetBuf::new_empty(128), IdxSetBuf::new_filled(128)]
+ .into_iter()
+ {
+ idx_buf.set_up_to(i);
+
+ let elems: Vec<usize> = idx_buf.iter().collect();
+ let expected: Vec<usize> = (0..i).collect();
+ assert_eq!(elems, expected);
+ }
+ }
+}
+
+#[test]
+fn test_new_filled() {
+ for i in 0..128 {
+ let mut idx_buf = IdxSetBuf::new_filled(i);
+ let elems: Vec<usize> = idx_buf.iter().collect();
+ let expected: Vec<usize> = (0..i).collect();
+ assert_eq!(elems, expected);
+ }
+}
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(set_stdio)]
+#![feature(rustc_stack_internals)]
extern crate arena;
extern crate getopts;
// Temporarily have stack size set to 16MB to deal with nom-using crates failing
const STACK_SIZE: usize = 16 * 1024 * 1024; // 16MB
- let mut cfg = thread::Builder::new().name("rustc".to_string());
+ #[cfg(unix)]
+ let spawn_thread = unsafe {
+ // Fetch the current resource limits
+ let mut rlim = libc::rlimit {
+ rlim_cur: 0,
+ rlim_max: 0,
+ };
+ if libc::getrlimit(libc::RLIMIT_STACK, &mut rlim) != 0 {
+ let err = io::Error::last_os_error();
+ error!("in_rustc_thread: error calling getrlimit: {}", err);
+ true
+ } else if rlim.rlim_max < STACK_SIZE as libc::rlim_t {
+ true
+ } else {
+ std::rt::deinit_stack_guard();
+ rlim.rlim_cur = STACK_SIZE as libc::rlim_t;
+ if libc::setrlimit(libc::RLIMIT_STACK, &mut rlim) != 0 {
+ let err = io::Error::last_os_error();
+ error!("in_rustc_thread: error calling setrlimit: {}", err);
+ std::rt::update_stack_guard();
+ true
+ } else {
+ std::rt::update_stack_guard();
+ false
+ }
+ }
+ };
- // FIXME: Hacks on hacks. If the env is trying to override the stack size
- // then *don't* set it explicitly.
- if env::var_os("RUST_MIN_STACK").is_none() {
- cfg = cfg.stack_size(STACK_SIZE);
- }
+ // We set the stack size at link time. See src/rustc/rustc.rs.
+ #[cfg(windows)]
+ let spawn_thread = false;
+
+ #[cfg(not(any(windows,unix)))]
+ let spawn_thread = true;
- let thread = cfg.spawn(f);
- thread.unwrap().join()
+ // The or condition is added from backward compatibility.
+ if spawn_thread || env::var_os("RUST_MIN_STACK").is_some() {
+ let mut cfg = thread::Builder::new().name("rustc".to_string());
+
+ // FIXME: Hacks on hacks. If the env is trying to override the stack size
+ // then *don't* set it explicitly.
+ if env::var_os("RUST_MIN_STACK").is_none() {
+ cfg = cfg.stack_size(STACK_SIZE);
+ }
+
+ let thread = cfg.spawn(f);
+ thread.unwrap().join()
+ } else {
+ Ok(f())
+ }
}
/// Get a list of extra command-line flags provided by the user, as strings.
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;
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);
/// macro (and methods below) makes working with `BlockAnd` much more
/// convenient.
-#[must_use] // if you don't use one of these results, you're leaving a dangling edge
+#[must_use = "if you don't use one of these results, you're leaving a dangling edge"]
struct BlockAnd<T>(BasicBlock, T);
trait BlockAndExtension {
// sets on_entry bits for Arg places
fn start_block_effect(&self, entry_set: &mut IdxSet<MovePathIndex>) {
// set all bits to 1 (uninit) before gathering counterevidence
- for e in entry_set.words_mut() { *e = !0; }
+ entry_set.set_up_to(self.bits_per_block());
drop_flag_effects_for_function_entry(
self.tcx, self.mir, self.mdpe,
// sets on_entry bits for Arg places
fn start_block_effect(&self, entry_set: &mut IdxSet<MovePathIndex>) {
- for e in entry_set.words_mut() { *e = 0; }
+ entry_set.clear();
drop_flag_effects_for_function_entry(
self.tcx, self.mir, self.mdpe,
impl ToBorrowKind for AutoBorrowMutability {
fn to_borrow_kind(&self) -> BorrowKind {
+ use rustc::ty::adjustment::AllowTwoPhase;
match *self {
AutoBorrowMutability::Mutable { allow_two_phase_borrow } =>
- BorrowKind::Mut { allow_two_phase_borrow },
+ BorrowKind::Mut { allow_two_phase_borrow: match allow_two_phase_borrow {
+ AllowTwoPhase::Yes => true,
+ AllowTwoPhase::No => false
+ }},
AutoBorrowMutability::Immutable =>
BorrowKind::Shared,
}
Discriminant(ref place) => {
let ty = self.place_ty(place);
+ let layout = self.layout_of(ty)?;
let place = self.eval_place(place)?;
let discr_val = self.read_discriminant_value(place, ty)?;
- if let ty::TyAdt(adt_def, _) = ty.sty {
- trace!("Read discriminant {}, valid discriminants {:?}", discr_val, adt_def.discriminants(*self.tcx).collect::<Vec<_>>());
- if adt_def.discriminants(*self.tcx).all(|v| {
- discr_val != v.val
- })
- {
- return err!(InvalidDiscriminant);
+ match layout.variants {
+ layout::Variants::Single { index } => {
+ assert_eq!(discr_val, index as u128);
+ }
+ layout::Variants::Tagged { .. } |
+ layout::Variants::NicheFilling { .. } => {
+ if let ty::TyAdt(adt_def, _) = ty.sty {
+ trace!("Read discriminant {}, valid discriminants {:?}", discr_val, adt_def.discriminants(*self.tcx).collect::<Vec<_>>());
+ if adt_def.discriminants(*self.tcx).all(|v| {
+ discr_val != v.val
+ })
+ {
+ return err!(InvalidDiscriminant);
+ }
+ } else {
+ bug!("rustc only generates Rvalue::Discriminant for enums");
+ }
}
- self.write_primval(dest, PrimVal::Bytes(discr_val), dest_ty)?;
- } else {
- bug!("rustc only generates Rvalue::Discriminant for enums");
}
+ self.write_primval(dest, PrimVal::Bytes(discr_val), dest_ty)?;
}
}
#![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))]
use hir::def_id::{DefId, LOCAL_CRATE};
use rustc::{infer, traits};
use rustc::ty::{self, TyCtxt, TypeFoldable, Ty};
-use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability};
+use rustc::ty::adjustment::{Adjustment, Adjust, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
use syntax::abi;
use syntax::symbol::Symbol;
use syntax_pos::Span;
// For initial two-phase borrow
// deployment, conservatively omit
// overloaded function call ops.
- allow_two_phase_borrow: false,
+ allow_two_phase_borrow: AllowTwoPhase::No,
}
};
autoref = Some(Adjustment {
use rustc::session::Session;
use rustc::traits;
use rustc::ty::{self, Ty, TypeFoldable};
+use rustc::ty::adjustment::AllowTwoPhase;
use rustc::ty::cast::{CastKind, CastTy};
use rustc::ty::subst::Substs;
use rustc::middle::lang_items;
let f = self.expr_ty.fn_sig(fcx.tcx);
let res = fcx.try_coerce(self.expr,
self.expr_ty,
- fcx.tcx.mk_fn_ptr(f));
+ fcx.tcx.mk_fn_ptr(f),
+ AllowTwoPhase::No);
if !res.is_ok() {
return Err(CastError::NonScalar);
}
}
fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> bool {
- fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty).is_ok()
+ fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty, AllowTwoPhase::No).is_ok()
}
}
use rustc::infer::{Coercion, InferResult, InferOk};
use rustc::infer::type_variable::TypeVariableOrigin;
use rustc::traits::{self, ObligationCause, ObligationCauseCode};
-use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability};
+use rustc::ty::adjustment::{Adjustment, Adjust, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
use rustc::ty::{self, TypeAndMut, Ty, ClosureSubsts};
use rustc::ty::fold::TypeFoldable;
use rustc::ty::error::TypeError;
fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
cause: ObligationCause<'tcx>,
use_lub: bool,
+ /// Determines whether or not allow_two_phase_borrow is set on any
+ /// autoref adjustments we create while coercing. We don't want to
+ /// allow deref coercions to create two-phase borrows, at least initially,
+ /// but we do need two-phase borrows for function argument reborrows.
+ /// See #47489 and #48598
+ /// See docs on the "AllowTwoPhase" type for a more detailed discussion
+ allow_two_phase: AllowTwoPhase,
}
impl<'a, 'gcx, 'tcx> Deref for Coerce<'a, 'gcx, 'tcx> {
}
impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
- fn new(fcx: &'f FnCtxt<'f, 'gcx, 'tcx>, cause: ObligationCause<'tcx>) -> Self {
+ fn new(fcx: &'f FnCtxt<'f, 'gcx, 'tcx>,
+ cause: ObligationCause<'tcx>,
+ allow_two_phase: AllowTwoPhase) -> Self {
Coerce {
fcx,
cause,
+ allow_two_phase,
use_lub: false,
}
}
let mutbl = match mt_b.mutbl {
hir::MutImmutable => AutoBorrowMutability::Immutable,
hir::MutMutable => AutoBorrowMutability::Mutable {
- // Deref-coercion is a case where we deliberately
- // disallow two-phase borrows in its initial
- // deployment; see discussion on PR #47489.
- allow_two_phase_borrow: false,
+ allow_two_phase_borrow: self.allow_two_phase,
}
};
adjustments.push(Adjustment {
let mutbl = match mt_b.mutbl {
hir::MutImmutable => AutoBorrowMutability::Immutable,
hir::MutMutable => AutoBorrowMutability::Mutable {
- allow_two_phase_borrow: false,
+ // We don't allow two-phase borrows here, at least for initial
+ // implementation. If it happens that this coercion is a function argument,
+ // the reborrow in coerce_borrowed_ptr will pick it up.
+ allow_two_phase_borrow: AllowTwoPhase::No,
}
};
Some((Adjustment {
pub fn try_coerce(&self,
expr: &hir::Expr,
expr_ty: Ty<'tcx>,
- target: Ty<'tcx>)
+ target: Ty<'tcx>,
+ allow_two_phase: AllowTwoPhase)
-> RelateResult<'tcx, Ty<'tcx>> {
let source = self.resolve_type_vars_with_obligations(expr_ty);
debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target);
let cause = self.cause(expr.span, ObligationCauseCode::ExprAssignable);
- let coerce = Coerce::new(self, cause);
+ let coerce = Coerce::new(self, cause, allow_two_phase);
let ok = self.commit_if_ok(|_| coerce.coerce(source, target))?;
let (adjustments, _) = self.register_infer_ok_obligations(ok);
debug!("coercion::can({:?} -> {:?})", source, target);
let cause = self.cause(syntax_pos::DUMMY_SP, ObligationCauseCode::ExprAssignable);
- let coerce = Coerce::new(self, cause);
+ // We don't ever need two-phase here since we throw out the result of the coercion
+ let coerce = Coerce::new(self, cause, AllowTwoPhase::No);
self.probe(|_| coerce.coerce(source, target)).is_ok()
}
return Ok(fn_ptr);
}
- let mut coerce = Coerce::new(self, cause.clone());
+ // Configure a Coerce instance to compute the LUB.
+ // We don't allow two-phase borrows on any autorefs this creates since we
+ // probably aren't processing function arguments here and even if we were,
+ // they're going to get autorefed again anyway and we can apply 2-phase borrows
+ // at that time.
+ let mut coerce = Coerce::new(self, cause.clone(), AllowTwoPhase::No);
coerce.use_lub = true;
// First try to coerce the new expression to the type of the previous ones,
if self.pushed == 0 {
// Special-case the first expression we are coercing.
// To be honest, I'm not entirely sure why we do this.
- fcx.try_coerce(expression, expression_ty, self.expected_ty)
+ // We don't allow two-phase borrows, see comment in try_find_coercion_lub for why
+ fcx.try_coerce(expression, expression_ty, self.expected_ty, AllowTwoPhase::No)
} else {
match self.expressions {
Expressions::Dynamic(ref exprs) =>
use rustc::hir::map::NodeItem;
use rustc::hir::{Item, ItemConst, print};
use rustc::ty::{self, Ty, AssociatedItem};
+use rustc::ty::adjustment::AllowTwoPhase;
use errors::{DiagnosticBuilder, CodeMapper};
use super::method::probe;
pub fn demand_coerce(&self,
expr: &hir::Expr,
checked_ty: Ty<'tcx>,
- expected: Ty<'tcx>)
+ expected: Ty<'tcx>,
+ allow_two_phase: AllowTwoPhase)
-> Ty<'tcx> {
- let (ty, err) = self.demand_coerce_diag(expr, checked_ty, expected);
+ let (ty, err) = self.demand_coerce_diag(expr, checked_ty, expected, allow_two_phase);
if let Some(mut err) = err {
err.emit();
}
pub fn demand_coerce_diag(&self,
expr: &hir::Expr,
checked_ty: Ty<'tcx>,
- expected: Ty<'tcx>)
+ expected: Ty<'tcx>,
+ allow_two_phase: AllowTwoPhase)
-> (Ty<'tcx>, Option<DiagnosticBuilder<'tcx>>) {
let expected = self.resolve_type_vars_with_obligations(expected);
- let e = match self.try_coerce(expr, checked_ty, expected) {
+ let e = match self.try_coerce(expr, checked_ty, expected, allow_two_phase) {
Ok(ty) => return (ty, None),
Err(e) => e
};
use rustc::traits;
use rustc::ty::{self, Ty};
use rustc::ty::subst::Subst;
-use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability, OverloadedDeref};
+use rustc::ty::adjustment::{Adjustment, Adjust, OverloadedDeref};
+use rustc::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
use rustc::ty::fold::TypeFoldable;
use rustc::infer::{self, InferOk};
use syntax_pos::Span;
hir::MutMutable => AutoBorrowMutability::Mutable {
// Method call receivers are the primary use case
// for two-phase borrows.
- allow_two_phase_borrow: true,
+ allow_two_phase_borrow: AllowTwoPhase::Yes,
}
};
adjustments.push(Adjustment {
// For initial two-phase borrow
// deployment, conservatively omit
// overloaded operators.
- allow_two_phase_borrow: false,
+ allow_two_phase_borrow: AllowTwoPhase::No,
}
};
adjustment.kind = Adjust::Borrow(AutoBorrow::Ref(region, mutbl));
use rustc::ty::subst::{Kind, Subst, Substs};
use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine};
use rustc::ty::{self, Ty, TyCtxt, Visibility, ToPredicate};
-use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
+use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
use rustc::ty::fold::TypeFoldable;
use rustc::ty::maps::Providers;
use rustc::ty::util::{Representability, IntTypeExt, Discr};
let mutbl = match mt.mutbl {
hir::MutImmutable => AutoBorrowMutability::Immutable,
hir::MutMutable => AutoBorrowMutability::Mutable {
- // FIXME (#46747): arguably indexing is
- // "just another kind of call"; perhaps it
- // would be more consistent to allow
- // two-phase borrows for .index()
- // receivers here.
- allow_two_phase_borrow: false,
+ // Indexing can be desugared to a method call,
+ // so maybe we could use two-phase here.
+ // See the documentation of AllowTwoPhase for why that's
+ // not the case today.
+ allow_two_phase_borrow: AllowTwoPhase::No,
}
};
adjustments.push(Adjustment {
// to, which is `expected_ty` if `rvalue_hint` returns an
// `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise.
let coerce_ty = expected.and_then(|e| e.only_has_type(self));
- self.demand_coerce(&arg, checked_ty, coerce_ty.unwrap_or(formal_ty));
+ // We're processing function arguments so we definitely want to use
+ // two-phase borrows.
+ self.demand_coerce(&arg,
+ checked_ty,
+ coerce_ty.unwrap_or(formal_ty),
+ AllowTwoPhase::Yes);
// 3. Relate the expected type and the formal one,
// if the expected type was used for the coercion.
expr,
ExpectHasType(expected),
needs);
- self.demand_coerce(expr, ty, expected)
+ // checks don't need two phase
+ self.demand_coerce(expr, ty, expected, AllowTwoPhase::No)
}
fn check_expr_with_hint(&self, expr: &'gcx hir::Expr,
// (It shouldn't actually matter for unary ops whether
// we enable two-phase borrows or not, since a unary
// op has no additional operands.)
- allow_two_phase_borrow: false,
+ allow_two_phase_borrow: AllowTwoPhase::No,
}
};
self.apply_adjustments(oprnd, vec![Adjustment {
let base_t = self.structurally_resolved_type(expr.span, base_t);
match self.lookup_indexing(expr, base, base_t, idx_t, needs) {
Some((index_ty, element_ty)) => {
- self.demand_coerce(idx, idx_t, index_ty);
+ // two-phase not needed because index_ty is never mutable
+ self.demand_coerce(idx, idx_t, index_ty, AllowTwoPhase::No);
element_ty
}
None => {
use super::method::MethodCallee;
use rustc::ty::{self, Ty, TypeFoldable, TypeVariants};
use rustc::ty::TypeVariants::{TyStr, TyRef, TyAdt};
-use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability};
+use rustc::ty::adjustment::{Adjustment, Adjust, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
use rustc::infer::type_variable::TypeVariableOrigin;
use errors;
use syntax_pos::Span;
hir::MutMutable => AutoBorrowMutability::Mutable {
// Allow two-phase borrows for binops in initial deployment
// since they desugar to methods
- allow_two_phase_borrow: true,
+ allow_two_phase_borrow: AllowTwoPhase::Yes,
}
};
let autoref = Adjustment {
hir::MutMutable => AutoBorrowMutability::Mutable {
// Allow two-phase borrows for binops in initial deployment
// since they desugar to methods
- allow_two_phase_borrow: true,
+ allow_two_phase_borrow: AllowTwoPhase::Yes,
}
};
let autoref = Adjustment {
```
"##,
-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
let ty = cx.resolver.borrow_mut()
.with_scope(*id,
|resolver| {
- resolver.resolve_str_path_error(DUMMY_SP,
- &path, false)
+ resolver.resolve_str_path_error(DUMMY_SP, &path, false)
})?;
match ty.def {
Def::Struct(did) | Def::Union(did) | Def::Enum(did) | Def::TyAlias(did) => {
};
Ok((ty.def, Some(format!("{}.{}", out, item_name))))
} else {
- Err(())
+ let is_enum = match ty.def {
+ Def::Enum(_) => true,
+ _ => false,
+ };
+ let elem = if is_enum {
+ cx.tcx.adt_def(did).all_fields().find(|item| item.name == item_name)
+ } else {
+ cx.tcx.adt_def(did)
+ .non_enum_variant()
+ .fields
+ .iter()
+ .find(|item| item.name == item_name)
+ };
+ if let Some(item) = elem {
+ Ok((ty.def,
+ Some(format!("{}.{}",
+ if is_enum { "variant" } else { "structfield" },
+ item.name))))
+ } else {
+ Err(())
+ }
}
}
Def::Trait(did) => {
let kind = match item.kind {
ty::AssociatedKind::Const if is_val => "associatedconstant",
ty::AssociatedKind::Type if !is_val => "associatedtype",
- ty::AssociatedKind::Method if is_val => "tymethod",
+ ty::AssociatedKind::Method if is_val => {
+ if item.defaultness.has_value() {
+ "method"
+ } else {
+ "tymethod"
+ }
+ }
_ => return Err(())
};
} else {
String::new()
};
- let text = format!("Deprecated{}{}",
- since,
- MarkdownHtml(&deprecated_reason));
+ let text = if stability::deprecation_in_effect(&stab.deprecated_since) {
+ format!("Deprecated{}{}",
+ since,
+ MarkdownHtml(&deprecated_reason))
+ } else {
+ format!("Deprecating in {}{}",
+ Escape(&stab.deprecated_since),
+ MarkdownHtml(&deprecated_reason))
+ };
stability.push(format!("<div class='stab deprecated'>{}</div>", text))
};
String::new()
};
- let text = format!("Deprecated{}{}", since, MarkdownHtml(¬e));
+ let text = if stability::deprecation_in_effect(&depr.since) {
+ format!("Deprecated{}{}",
+ since,
+ MarkdownHtml(¬e))
+ } else {
+ format!("Deprecating in {}{}",
+ Escape(&depr.since),
+ MarkdownHtml(¬e))
+ };
stability.push(format!("<div class='stab deprecated'>{}</div>", text))
}
write!(w, "<h2 id='fields' class='fields small-section-header'>
Fields<a href='#fields' class='anchor'></a></h2>")?;
for (field, ty) in fields {
- write!(w, "<span id='{shortty}.{name}' class=\"{shortty}\"><code>{name}: {ty}</code>
+ let name = field.name.as_ref().expect("union field name");
+ let id = format!("{}.{}", ItemType::StructField, name);
+ write!(w, "<span id=\"{id}\" class=\"{shortty} small-section-header\">\
+ <a href=\"#{id}\" class=\"anchor field\"></a>\
+ <span class='invisible'><code>{name}: {ty}</code></span>\
</span>",
+ id = id,
+ name = name,
shortty = ItemType::StructField,
- name = field.name.as_ref().unwrap(),
ty = ty)?;
if let Some(stability_class) = field.stability_class() {
write!(w, "<span class='stab {stab}'></span>",
}
:target > code {
- background: #FDFFD3;
+ background-color: #494a3d;
}
pre.compile_fail {
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};
}
}
-/// 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
};
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")]
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;
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() {
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> {
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
///
/// # Examples
///
- /// ```no_ru
+ /// ```no_run
/// # #![feature(bufreader_buffer)]
/// use std::io::{BufReader, BufRead};
/// use std::fs::File;
#![feature(panic_internals)]
#![feature(panic_unwind)]
#![feature(peek)]
-#![feature(placement_in_syntax)]
#![feature(placement_new_protocol)]
#![feature(prelude_import)]
#![feature(ptr_internals)]
/// ```
///
///
-#[stable(feature = "getpid", since = "1.27.0")]
+#[stable(feature = "getpid", since = "1.26.0")]
pub fn id() -> u32 {
::sys::os::getpid()
}
{
lang_start_internal(&move || main().report(), argc, argv)
}
+
+/// Function used for reverting changes to the main stack before setrlimit().
+/// This is POSIX (non-Linux) specific and unlikely to be directly stabilized.
+#[unstable(feature = "rustc_stack_internals", issue = "0")]
+pub unsafe fn deinit_stack_guard() {
+ ::sys::thread::guard::deinit();
+}
+
+/// Function used for resetting the main stack guard address after setrlimit().
+/// This is POSIX specific and unlikely to be directly stabilized.
+#[unstable(feature = "rustc_stack_internals", issue = "0")]
+pub unsafe fn update_stack_guard() {
+ let main_guard = ::sys::thread::guard::init();
+ ::sys_common::thread_info::reset_guard(main_guard);
+}
pub unsafe fn init() -> Option<Guard> {
None
}
+ pub unsafe fn deinit() {}
}
fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
pub type Guard = !;
pub unsafe fn current() -> Option<Guard> { None }
pub unsafe fn init() -> Option<Guard> { None }
+ pub unsafe fn deinit() {}
}
pub type Guard = Range<usize>;
pub unsafe fn current() -> Option<Guard> { None }
pub unsafe fn init() -> Option<Guard> { None }
+ pub unsafe fn deinit() {}
}
#[cfg_attr(test, allow(dead_code))]
pub mod guard {
use libc;
- use libc::mmap;
- use libc::{PROT_NONE, MAP_PRIVATE, MAP_ANON, MAP_FAILED, MAP_FIXED};
+ use libc::{mmap, mprotect};
+ use libc::{PROT_NONE, PROT_READ, PROT_WRITE, MAP_PRIVATE, MAP_ANON, MAP_FAILED, MAP_FIXED};
use ops::Range;
use sys::os;
ret
}
- pub unsafe fn init() -> Option<Guard> {
- PAGE_SIZE = os::page_size();
-
- let mut stackaddr = get_stack_start()?;
+ // Precondition: PAGE_SIZE is initialized.
+ unsafe fn get_stack_start_aligned() -> Option<*mut libc::c_void> {
+ assert!(PAGE_SIZE != 0);
+ let stackaddr = get_stack_start()?;
// Ensure stackaddr is page aligned! A parent process might
// have reset RLIMIT_STACK to be non-page aligned. The
// page-aligned, calculate the fix such that stackaddr <
// new_page_aligned_stackaddr < stackaddr + stacksize
let remainder = (stackaddr as usize) % PAGE_SIZE;
- if remainder != 0 {
- stackaddr = ((stackaddr as usize) + PAGE_SIZE - remainder)
- as *mut libc::c_void;
- }
+ Some(if remainder == 0 {
+ stackaddr
+ } else {
+ ((stackaddr as usize) + PAGE_SIZE - remainder) as *mut libc::c_void
+ })
+ }
+
+ pub unsafe fn init() -> Option<Guard> {
+ PAGE_SIZE = os::page_size();
+
+ let stackaddr = get_stack_start_aligned()?;
if cfg!(target_os = "linux") {
// Linux doesn't allocate the whole stack right away, and
}
}
+ pub unsafe fn deinit() {
+ if !cfg!(target_os = "linux") {
+ if let Some(stackaddr) = get_stack_start_aligned() {
+ // Remove the protection on the guard page.
+ // FIXME: we cannot unmap the page, because when we mmap()
+ // above it may be already mapped by the OS, which we can't
+ // detect from mmap()'s return value. If we unmap this page,
+ // it will lead to failure growing stack size on platforms like
+ // macOS. Instead, just restore the page to a writable state.
+ // This ain't Linux, so we probably don't need to care about
+ // execstack.
+ let result = mprotect(stackaddr, PAGE_SIZE, PROT_READ | PROT_WRITE);
+
+ if result != 0 {
+ panic!("unable to reset the guard page");
+ }
+ }
+ }
+ }
+
#[cfg(any(target_os = "macos",
target_os = "bitrig",
target_os = "openbsd",
pub type Guard = !;
pub unsafe fn current() -> Option<Guard> { None }
pub unsafe fn init() -> Option<Guard> { None }
+ pub unsafe fn deinit() {}
}
pub type Guard = !;
pub unsafe fn current() -> Option<Guard> { None }
pub unsafe fn init() -> Option<Guard> { None }
+ pub unsafe fn deinit() {}
}
thread,
}));
}
+
+pub fn reset_guard(stack_guard: Option<Guard>) {
+ THREAD_INFO.with(move |c| c.borrow_mut().as_mut().unwrap().stack_guard = stack_guard);
+}
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,
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
(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),
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";
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,
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))
}
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);
}
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,
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)?;
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)?;
}
GreaterEqual,
/// `=`
Assign,
- /// `<-`
- Inplace,
/// `?=` where ? is one of the BinOpToken
AssignOp(BinOpToken),
/// `as`
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),
LAnd => 6,
LOr => 5,
DotDot | DotDotEq => 4,
- Inplace => 3,
Assign | AssignOp(_) => 2,
}
}
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,
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
}
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
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
}
}
}
Binary(BinOpKind),
- InPlace,
Cast,
Type,
// 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,
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);
}
/// The kind of compiler desugaring.
#[derive(Clone, Hash, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
pub enum CompilerDesugaringKind {
- BackArrow,
DotFill,
QuestionMark,
}
pub fn as_symbol(&self) -> Symbol {
use CompilerDesugaringKind::*;
let s = match *self {
- BackArrow => "<-",
DotFill => "...",
QuestionMark => "?",
};
// except according to those terms.
#![feature(rustc_private)]
+#![feature(link_args)]
+
+// Set the stack size at link time on Windows. See rustc_driver::in_rustc_thread
+// for the rationale.
+#[cfg_attr(all(windows, target_env = "msvc"), link_args = "/STACK:16777216")]
+// We only build for msvc and gnu now, but we use a exhaustive condition here
+// so we can expect either the stack size to be set or the build fails.
+#[cfg_attr(all(windows, not(target_env = "msvc")), link_args = "-Wl,--stack,16777216")]
+// Also, don't forget to set this for rustdoc.
+extern {}
extern crate rustc_driver;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// revisions: lxl nll
+// revisions: ast lxl nll
+//[ast]compile-flags:
//[lxl]compile-flags: -Z borrowck=mir -Z two-phase-borrows
//[nll]compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z nll
use std::ops::{Index, IndexMut};
-// This is case outlined by Niko that we want to ensure we reject
-// (at least initially).
-
fn foo(x: &mut u32, y: u32) {
*x += y;
}
fn deref_coercion(x: &mut u32) {
foo(x, *x);
- //[lxl]~^ ERROR cannot use `*x` because it was mutably borrowed [E0503]
- //[nll]~^^ ERROR cannot use `*x` because it was mutably borrowed [E0503]
+ //[ast]~^ ERROR cannot use `*x` because it was mutably borrowed [E0503]
+ // Above error is a known limitation of AST borrowck
}
// While adding a flag to adjustments (indicating whether they
//[lxl]~^ ERROR cannot borrow `*f` as mutable more than once at a time
//[nll]~^^ ERROR cannot borrow `*f` as mutable more than once at a time
//[g2p]~^^^ ERROR cannot borrow `*f` as mutable more than once at a time
+ //[ast]~^^^^ ERROR cannot borrow `*f` as mutable more than once at a time
}
fn twice_ten_si<F: Fn(i32) -> i32>(f: &mut F) {
f(f(10));
}
fn twice_ten_so<F: FnOnce(i32) -> i32>(f: Box<F>) {
f(f(10));
- //[lxl]~^ ERROR use of moved value: `*f`
- //[nll]~^^ ERROR use of moved value: `*f`
- //[g2p]~^^^ ERROR use of moved value: `*f`
+ //[lxl]~^ ERROR use of moved value: `*f`
+ //[nll]~^^ ERROR use of moved value: `*f`
+ //[g2p]~^^^ ERROR use of moved value: `*f`
+ //[ast]~^^^^ ERROR use of moved value: `*f`
}
fn twice_ten_om(f: &mut FnMut(i32) -> i32) {
f(f(10));
- //[lxl]~^ ERROR cannot borrow `*f` as mutable more than once at a time
+ //[lxl]~^ ERROR cannot borrow `*f` as mutable more than once at a time
//[nll]~^^ ERROR cannot borrow `*f` as mutable more than once at a time
- //[g2p]~^^^ ERROR cannot borrow `*f` as mutable more than once at a time
+ //[g2p]~^^^ ERROR cannot borrow `*f` as mutable more than once at a time
+ //[ast]~^^^^ ERROR cannot borrow `*f` as mutable more than once at a time
}
fn twice_ten_oi(f: &mut Fn(i32) -> i32) {
f(f(10));
//[g2p]~^^^^^^^ ERROR cannot move a value of type
//[g2p]~^^^^^^^^ ERROR cannot move a value of type
//[g2p]~^^^^^^^^^ ERROR use of moved value: `*f`
+ //[ast]~^^^^^^^^^^ ERROR use of moved value: `*f`
}
twice_ten_sm(&mut |x| x + 1);
// This is not okay.
double_access(&mut a, &a);
- //[lxl]~^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable [E0502]
- //[nll]~^^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable [E0502]
- //[g2p]~^^^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable [E0502]
+ //[lxl]~^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable [E0502]
+ //[nll]~^^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable [E0502]
+ //[g2p]~^^^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable [E0502]
+ //[ast]~^^^^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable [E0502]
// But this is okay.
a.m(a.i(10));
+ //[ast]~^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable [E0502]
+ // Above error is an expected limitation of AST borrowck
}
struct I(i32);
fn coerce_index_op() {
let mut i = I(10);
i[i[3]] = 4;
- //[lxl]~^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
- //[nll]~^^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
+ //[lxl]~^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
+ //[nll]~^^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
+ //[ast]~^^^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
i[3] = i[4];
i[i[3]] = i[4];
- //[lxl]~^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
- //[nll]~^^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
+ //[lxl]~^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
+ //[nll]~^^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
+ //[ast]~^^^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
}
fn main() {
// As a reminder, this is the basic case we want to ensure we handle.
let mut v = vec![1, 2, 3];
v.push(v.len());
+ //[ast]~^ ERROR cannot borrow `v` as immutable because it is also borrowed as mutable [E0502]
+ // Error above is an expected limitation of AST borrowck
// (as a rule, pnkfelix does not like to write tests with dead code.)
let mut s = S;
s.m(s.i(10));
+ //[ast]~^ ERROR cannot borrow `s` as immutable because it is also borrowed as mutable [E0502]
+ // Error above is an expected limitation of AST borrowck
let mut t = T;
t.m(t.i(10));
+ //[ast]~^ ERROR cannot borrow `t` as immutable because it is also borrowed as mutable [E0502]
+ // Error above is an expected limitation of AST borrowck
coerce_unsized();
coerce_index_op();
#[deprecated(since = "1.0.0", note = "text")]
pub fn deprecated_text() {}
+ #[deprecated(since = "99.99.99", note = "text")]
+ pub fn deprecated_future() {}
+ #[deprecated(since = "99.99.99", note = "text")]
+ pub fn deprecated_future_text() {}
+
pub struct MethodTester;
impl MethodTester {
<Foo>::trait_deprecated_text(&foo); //~ ERROR use of deprecated item 'this_crate::Trait::trait_deprecated_text': text
<Foo as Trait>::trait_deprecated_text(&foo); //~ ERROR use of deprecated item 'this_crate::Trait::trait_deprecated_text': text
+ deprecated_future(); // Fine; no error.
+ deprecated_future_text(); // Fine; no error.
+
let _ = DeprecatedStruct {
//~^ ERROR use of deprecated item 'this_crate::DeprecatedStruct': text
i: 0 //~ ERROR use of deprecated item 'this_crate::DeprecatedStruct::i': text
+++ /dev/null
-// 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
-}
--- /dev/null
+// 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.
+
+// #47295: We used to have a hack of special-casing adjacent amtch
+// arms whose patterns were composed solely of constants to not have
+// them linked in the cfg.
+//
+// THis was broken for various reasons. In particular, that hack was
+// originally authored under the assunption that other checks
+// elsewhere would ensure that the two patterns did not overlap. But
+// that assumption did not hold, at least not in the long run (namely,
+// overlapping patterns were turned into warnings rather than errors).
+
+#![feature(box_syntax)]
+
+fn main() {
+ let x: Box<_> = box 1;
+
+ let v = (1, 2);
+
+ match v {
+ (1, 2) if take(x) => (),
+ (1, 2) if take(x) => (), //~ ERROR use of moved value: `x`
+ _ => (),
+ }
+}
+
+fn take<T>(_: T) -> bool { false }
+++ /dev/null
-// 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
-}
+++ /dev/null
-// 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
- };
-}
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
}
#![feature(custom_attribute)]
#![feature(box_syntax)]
-#![feature(placement_in_syntax)]
#![feature(stmt_expr_attributes)]
fn main() { }
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);
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,
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,
});
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),
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,
};
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"),
#![feature(proc_macro, stmt_expr_attributes)]
extern crate attr_stmt_expr;
-use attr_stmt_expr::{expect_let, expect_print_stmt, expect_expr, expect_print_expr};
+use attr_stmt_expr::{expect_let, expect_print_stmt, expect_expr, expect_print_expr,
+ no_output, noop};
fn print_str(string: &'static str) {
// macros are handled a bit differently
#[expect_print_stmt]
println!("{}", string);
+ let _: () = {
+ #[no_output]
+ "Hello, world!"
+ };
+
+ let _: &'static str = #[noop] "Hello, world!";
+
+ let _: &'static str = {
+ #[noop] "Hello, world!"
+ };
+
#[expect_expr]
print_str("string")
}
assert_eq!(item.to_string(), "println!(\"{}\" , string)");
item
}
+
+#[proc_macro_attribute]
+pub fn no_output(attr: TokenStream, item: TokenStream) -> TokenStream {
+ assert!(attr.to_string().is_empty());
+ assert!(!item.to_string().is_empty());
+ "".parse().unwrap()
+
+}
+
+#[proc_macro_attribute]
+pub fn noop(attr: TokenStream, item: TokenStream) -> TokenStream {
+ assert!(attr.to_string().is_empty());
+ assert!(!item.to_string().is_empty());
+ item
+}
+++ /dev/null
-// 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.
-
-// pretty-expanded FIXME #23616
-
-#![feature(box_syntax)]
-
-fn main() {
- let x: Box<_> = box 1;
-
- let v = (1, 2);
-
- match v {
- (2, 1) if take(x) => (),
- (1, 2) if take(x) => (),
- _ => (),
- }
-}
-
-fn take<T>(_: T) -> bool { false }
* 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,
}
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);
+++ /dev/null
-// 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,
- }
- };
-}
--- /dev/null
+// Copyright 2018 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.
+
+#![crate_name = "foo"]
+
+// @has foo/trait.Foo.html '//a[@href="../foo/trait.Foo.html#tymethod.req"]' 'req'
+// @has foo/trait.Foo.html '//a[@href="../foo/trait.Foo.html#method.prov"]' 'prov'
+
+/// Always make sure to implement [`req`], but you don't have to implement [`prov`].
+///
+/// [`req`]: Foo::req
+/// [`prov`]: Foo::prov
+pub trait Foo {
+ /// Required
+ fn req();
+ /// Provided
+ fn prov() {}
+}
--- /dev/null
+// Copyright 2018 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(deprecated)]
+
+// @has deprecated_future/struct.S.html '//*[@class="stab deprecated"]' \
+// 'Deprecating in 99.99.99: effectively never'
+#[deprecated(since = "99.99.99", note = "effectively never")]
+pub struct S;
--- /dev/null
+// Copyright 2018 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.
+
+/// Blah blah blah
+/// ```ignore (testing rustdoc's handling of ignore)
+/// bad_assert!();
+/// ```
+pub fn foo() {}
--- /dev/null
+// Copyright 2018 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.
+
+#![crate_name = "foo"]
+
+// ignore-tidy-linelength
+
+// @has foo/index.html '//*[@class="docblock"]/p/a[@href="../foo/struct.Foo.html#structfield.bar"]' 'Foo::bar'
+// @has foo/index.html '//*[@class="docblock"]/p/a[@href="../foo/union.Bar.html#structfield.foo"]' 'Bar::foo'
+// @has foo/index.html '//*[@class="docblock"]/p/a[@href="../foo/enum.Uniooon.html#X.v"]' 'Uniooon::X'
+
+//! Test with [Foo::bar], [Bar::foo], [Uniooon::X]
+
+pub struct Foo {
+ pub bar: usize,
+}
+
+pub union Bar {
+ pub foo: u32,
+}
+
+pub enum Uniooon {
+ F,
+ X,
+ Y,
+}
--- /dev/null
+// Copyright 2017 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.
+
+// revisions: lxl nll
+//[lxl]compile-flags: -Z borrowck=mir -Z two-phase-borrows
+//[nll]compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z nll
+
+// run-pass
+
+struct Foo<'a> {
+ x: &'a i32
+}
+
+impl<'a> Foo<'a> {
+ fn method(&mut self, _: &i32) {
+ }
+}
+
+fn main() {
+ let a = &mut Foo { x: &22 };
+ Foo::method(a, a.x);
+}
+++ /dev/null
-// 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);
-}
+++ /dev/null
-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`.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(link_args)]
+// Set the stack size at link time on Windows. See rustc_driver::in_rustc_thread
+// for the rationale.
+#[cfg_attr(all(windows, target_env = "msvc"), link_args = "/STACK:16777216")]
+// We only build for msvc and gnu now, but we use a exhaustive condition here
+// so we can expect either the stack size to be set or the build fails.
+#[cfg_attr(all(windows, not(target_env = "msvc")), link_args = "-Wl,--stack,16777216")]
+// See src/rustc/rustc.rs for the corresponding rustc settings.
+extern {}
+
extern crate rustdoc;
fn main() { rustdoc::main() }