language: generic
sudo: required
-dist: trusty
+services:
+ - docker
# LLVM takes awhile to check out and otherwise we'll manage the submodules in
# our configure script, so disable auto submodule management.
submodules: false
before_install:
- - echo 0 | sudo tee /proc/sys/net/ipv6/conf/lo/disable_ipv6
- - echo 'deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.7 main' | sudo tee -a /etc/apt/sources.list
- - echo 'deb-src http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.7 main' | sudo tee -a /etc/apt/sources.list
- - sudo apt-get update
- - sudo apt-get --force-yes install curl make g++ python2.7 git zlib1g-dev libedit-dev llvm-3.7-tools
+ - docker build -t rust -f src/etc/Dockerfile src/etc
script:
- - ./configure --llvm-root=/usr/lib/llvm-3.7
- - make tidy && make check-notidy -j4
+ - docker run -v `pwd`:/build rust
+ sh -c "
+ ./configure --llvm-root=/usr/lib/llvm-3.7 &&
+ make tidy &&
+ make check-notidy -j4
+ "
# Real testing happens on http://buildbot.rust-lang.org/
#
At runtime each borrow causes a modification/check of the refcount.
-[cell-mod]: ../std/cell/
+[cell-mod]: ../std/cell/index.html
[cell]: ../std/cell/struct.Cell.html
[refcell]: ../std/cell/struct.RefCell.html
correct; documentation comments apply to the thing after them, and there's
nothing after that last comment.
-[rc-new]: https://doc.rust-lang.org/nightly/std/rc/struct.Rc.html#method.new
+[rc-new]: ../std/rc/struct.Rc.html#method.new
### Writing documentation comments
[3]: ../std/option/enum.Option.html#method.unwrap_or
[4]: ../std/option/enum.Option.html#method.unwrap_or_else
[5]: ../std/option/enum.Option.html
-[6]: ../std/result/
+[6]: ../std/result/index.html
[7]: ../std/result/enum.Result.html#method.unwrap
[8]: ../std/fmt/trait.Debug.html
[9]: ../std/primitive.str.html#method.parse
```
Much of the functionality that’s exposed in the standard library is also
-available via the [`core` crate](../core/). When we’re using the standard
-library, Rust automatically brings `std` into scope, allowing you to use
-its features without an explicit import. By the same token, when using
+available via the [`core` crate](../core/index.html). When we’re using the
+standard library, Rust automatically brings `std` into scope, allowing you to
+use its features without an explicit import. By the same token, when using
`#![no_std]`, Rust will bring `core` into scope for you, as well as [its
-prelude](../core/prelude/v1/). This means that a lot of code will Just Work:
+prelude](../core/prelude/v1/index.html). This means that a lot of code will Just
+Work:
```rust
#![no_std]
[box]: ../std/boxed/index.html
[generic]: generics.html
[panic]: concurrency.html#panics
-[get]: http://doc.rust-lang.org/std/vec/struct.Vec.html#method.get
-[get_mut]: http://doc.rust-lang.org/std/vec/struct.Vec.html#method.get_mut
+[get]: ../std/vec/struct.Vec.html#method.get
+[get_mut]: ../std/vec/struct.Vec.html#method.get_mut
We will also be spending a lot of time talking about the different kinds
of safety and guarantees.
-[trpl]: ../book/
+[trpl]: ../book/index.html
--- /dev/null
+FROM ubuntu:xenial
+
+# curl
+# Download stage0, see src/bootstrap/bootstrap.py
+# g++
+# Compile LLVM binding in src/rustllvm
+# git
+# Get commit hash and commit date in version string
+# make
+# Run build scripts in mk
+# libedit-dev zlib1g-dev
+# LLVM dependencies as packaged in Ubuntu
+# (They are optional, but Ubuntu package enables them)
+# llvm-3.7-dev (installed by llvm-3.7-tools)
+# LLVM
+# llvm-3.7-tools
+# FileCheck is used to run tests in src/test/codegen
+
+RUN apt-get update && apt-get -y install \
+ curl g++ git make \
+ libedit-dev zlib1g-dev \
+ llvm-3.7-tools
+
+RUN mkdir /build
+WORKDIR /build
// Check if right-most child is underfull.
let mut last_edge = internal.last_edge();
let right_child_len = last_edge.reborrow().descend().len();
- if right_child_len < node::CAPACITY / 2 {
+ if right_child_len < node::MIN_LEN {
// We need to steal.
let mut last_kv = match last_edge.left_kv() {
Ok(left) => left,
Err(_) => unreachable!(),
};
- last_kv.bulk_steal_left(node::CAPACITY/2 - right_child_len);
+ last_kv.bulk_steal_left(node::MIN_LEN - right_child_len);
last_edge = last_kv.right_edge();
}
cur_node = last_edge.descend();
}
}
+
+ /// Splits the collection into two at the given key. Returns everything after the given key,
+ /// including the key.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(btree_split_off)]
+ /// use std::collections::BTreeMap;
+ ///
+ /// let mut a = BTreeMap::new();
+ /// a.insert(1, "a");
+ /// a.insert(2, "b");
+ /// a.insert(3, "c");
+ /// a.insert(17, "d");
+ /// a.insert(41, "e");
+ ///
+ /// let b = a.split_off(&3);
+ ///
+ /// assert_eq!(a.len(), 2);
+ /// assert_eq!(b.len(), 3);
+ ///
+ /// assert_eq!(a[&1], "a");
+ /// assert_eq!(a[&2], "b");
+ ///
+ /// assert_eq!(b[&3], "c");
+ /// assert_eq!(b[&17], "d");
+ /// assert_eq!(b[&41], "e");
+ /// ```
+ #[unstable(feature = "btree_split_off",
+ reason = "recently added as part of collections reform 2",
+ issue = "19986")]
+ pub fn split_off<Q: ?Sized + Ord>(&mut self, key: &Q) -> Self where K: Borrow<Q> {
+ if self.is_empty() {
+ return Self::new();
+ }
+
+ let total_num = self.len();
+
+ let mut right = Self::new();
+ for _ in 0..(self.root.as_ref().height()) {
+ right.root.push_level();
+ }
+
+ {
+ let mut left_node = self.root.as_mut();
+ let mut right_node = right.root.as_mut();
+
+ loop {
+ let mut split_edge = match search::search_node(left_node, key) {
+ // key is going to the right tree
+ Found(handle) => handle.left_edge(),
+ GoDown(handle) => handle
+ };
+
+ split_edge.move_suffix(&mut right_node);
+
+ match (split_edge.force(), right_node.force()) {
+ (Internal(edge), Internal(node)) => {
+ left_node = edge.descend();
+ right_node = node.first_edge().descend();
+ }
+ (Leaf(_), Leaf(_)) => { break; },
+ _ => { unreachable!(); }
+ }
+ }
+ }
+
+ self.fix_right_border();
+ right.fix_left_border();
+
+ if self.root.as_ref().height() < right.root.as_ref().height() {
+ self.recalc_length();
+ right.length = total_num - self.len();
+ } else {
+ right.recalc_length();
+ self.length = total_num - right.len();
+ }
+
+ right
+ }
+
+ /// Calculates the number of elements if it is incorrect.
+ fn recalc_length(&mut self) {
+ fn dfs<K, V>(node: NodeRef<marker::Immut, K, V, marker::LeafOrInternal>) -> usize {
+ let mut res = node.len();
+
+ if let Internal(node) = node.force() {
+ let mut edge = node.first_edge();
+ loop {
+ res += dfs(edge.reborrow().descend());
+ match edge.right_kv() {
+ Ok(right_kv) => { edge = right_kv.right_edge(); },
+ Err(_) => { break; }
+ }
+ }
+ }
+
+ res
+ }
+
+ self.length = dfs(self.root.as_ref());
+ }
+
+ /// Removes empty levels on the top.
+ fn fix_top(&mut self) {
+ loop {
+ {
+ let node = self.root.as_ref();
+ if node.height() == 0 || node.len() > 0 {
+ break;
+ }
+ }
+ self.root.pop_level();
+ }
+ }
+
+ fn fix_right_border(&mut self) {
+ self.fix_top();
+
+ {
+ let mut cur_node = self.root.as_mut();
+
+ while let Internal(node) = cur_node.force() {
+ let mut last_kv = node.last_kv();
+
+ if last_kv.can_merge() {
+ cur_node = last_kv.merge().descend();
+ } else {
+ let right_len = last_kv.reborrow().right_edge().descend().len();
+ // `MINLEN + 1` to avoid readjust if merge happens on the next level.
+ if right_len < node::MIN_LEN + 1 {
+ last_kv.bulk_steal_left(node::MIN_LEN + 1 - right_len);
+ }
+ cur_node = last_kv.right_edge().descend();
+ }
+ }
+ }
+
+ self.fix_top();
+ }
+
+ /// The symmetric clone of `fix_right_border`.
+ fn fix_left_border(&mut self) {
+ self.fix_top();
+
+ {
+ let mut cur_node = self.root.as_mut();
+
+ while let Internal(node) = cur_node.force() {
+ let mut first_kv = node.first_kv();
+
+ if first_kv.can_merge() {
+ cur_node = first_kv.merge().descend();
+ } else {
+ let left_len = first_kv.reborrow().left_edge().descend().len();
+ if left_len < node::MIN_LEN + 1 {
+ first_kv.bulk_steal_right(node::MIN_LEN + 1 - left_len);
+ }
+ cur_node = first_kv.left_edge().descend();
+ }
+ }
+ }
+
+ self.fix_top();
+ }
}
impl<'a, K: 'a, V: 'a> IntoIterator for &'a BTreeMap<K, V> {
use boxed::Box;
const B: usize = 6;
+pub const MIN_LEN: usize = B - 1;
pub const CAPACITY: usize = 2 * B - 1;
/// The underlying representation of leaf nodes. Note that it is often unsafe to actually store
let len = self.len();
Handle::new_edge(self, len)
}
+
+ /// Note that `self` must be nonempty.
+ pub fn first_kv(self) -> Handle<Self, marker::KV> {
+ debug_assert!(self.len() > 0);
+ Handle::new_kv(self, 0)
+ }
+
+ /// Note that `self` must be nonempty.
+ pub fn last_kv(self) -> Handle<Self, marker::KV> {
+ let len = self.len();
+ debug_assert!(len > 0);
+ Handle::new_kv(self, len - 1)
+ }
}
impl<K, V> NodeRef<marker::Owned, K, V, marker::Leaf> {
}
}
+ fn correct_childrens_parent_links(&mut self, first: usize, after_last: usize) {
+ for i in first..after_last {
+ Handle::new_edge(unsafe { self.reborrow_mut() }, i).correct_parent_link();
+ }
+ }
+
+ fn correct_all_childrens_parent_links(&mut self) {
+ let len = self.len();
+ self.correct_childrens_parent_links(0, len + 1);
+ }
+
/// Adds a key/value pair and an edge to go to the left of that pair to
/// the beginning of the node.
pub fn push_front(&mut self, key: K, val: V, edge: Root<K, V>) {
self.as_leaf_mut().len += 1;
- for i in 0..self.len()+1 {
- Handle::new_edge(self.reborrow_mut(), i).correct_parent_link();
- }
+ self.correct_all_childrens_parent_links();
}
-
}
}
(key, val, edge)
}
}
+
+ fn into_kv_pointers_mut(mut self) -> (*mut K, *mut V) {
+ (
+ self.keys_mut().as_mut_ptr(),
+ self.vals_mut().as_mut_ptr()
+ )
+ }
}
impl<BorrowType, K, V> NodeRef<BorrowType, K, V, marker::LeafOrInternal> {
}
/// This does stealing similar to `steal_left` but steals multiple elements at once.
- pub fn bulk_steal_left(&mut self, n: usize) {
+ pub fn bulk_steal_left(&mut self, count: usize) {
unsafe {
- // Get raw pointers to left child's keys, values and edges.
- let (left_len, left_k, left_v, left_e) = {
- let mut left = self.reborrow_mut().left_edge().descend();
-
- (left.len(),
- left.keys_mut().as_mut_ptr(),
- left.vals_mut().as_mut_ptr(),
- match left.force() {
- ForceResult::Leaf(_) => None,
- ForceResult::Internal(mut i) => Some(i.as_internal_mut().edges.as_mut_ptr()),
- })
- };
-
- // Get raw pointers to right child's keys, values and edges.
- let (right_len, right_k, right_v, right_e) = {
- let mut right = self.reborrow_mut().right_edge().descend();
-
- (right.len(),
- right.keys_mut().as_mut_ptr(),
- right.vals_mut().as_mut_ptr(),
- match right.force() {
- ForceResult::Leaf(_) => None,
- ForceResult::Internal(mut i) => Some(i.as_internal_mut().edges.as_mut_ptr()),
- })
- };
-
- // Get raw pointers to parent's key and value.
- let (parent_k, parent_v) = {
- let kv = self.reborrow_mut().into_kv_mut();
- (kv.0 as *mut K, kv.1 as *mut V)
- };
+ let mut left_node = ptr::read(self).left_edge().descend();
+ let left_len = left_node.len();
+ let mut right_node = ptr::read(self).right_edge().descend();
+ let right_len = right_node.len();
// Make sure that we may steal safely.
- debug_assert!(right_len + n <= CAPACITY);
- debug_assert!(left_len >= n);
-
- // Make room for stolen elements in right child.
- ptr::copy(right_k,
- right_k.offset(n as isize),
- right_len);
- ptr::copy(right_v,
- right_v.offset(n as isize),
- right_len);
- if let Some(edges) = right_e {
- ptr::copy(edges,
- edges.offset(n as isize),
- right_len+1);
+ debug_assert!(right_len + count <= CAPACITY);
+ debug_assert!(left_len >= count);
+
+ let new_left_len = left_len - count;
+
+ // Move data.
+ {
+ let left_kv = left_node.reborrow_mut().into_kv_pointers_mut();
+ let right_kv = right_node.reborrow_mut().into_kv_pointers_mut();
+ let parent_kv = {
+ let kv = self.reborrow_mut().into_kv_mut();
+ (kv.0 as *mut K, kv.1 as *mut V)
+ };
+
+ // Make room for stolen elements in the right child.
+ ptr::copy(right_kv.0,
+ right_kv.0.offset(count as isize),
+ right_len);
+ ptr::copy(right_kv.1,
+ right_kv.1.offset(count as isize),
+ right_len);
+
+ // Move elements from the left child to the right one.
+ move_kv(left_kv, new_left_len + 1, right_kv, 0, count - 1);
+
+ // Move parent's key/value pair to the right child.
+ move_kv(parent_kv, 0, right_kv, count - 1, 1);
+
+ // Move the left-most stolen pair to the parent.
+ move_kv(left_kv, new_left_len, parent_kv, 0, 1);
}
- // Move elements from the left child to the right one.
- let left_ind = (left_len - n) as isize;
- ptr::copy_nonoverlapping(left_k.offset(left_ind + 1),
- right_k,
- n - 1);
- ptr::copy_nonoverlapping(left_v.offset(left_ind + 1),
- right_v,
- n - 1);
- match (left_e, right_e) {
- (Some(left), Some(right)) => {
- ptr::copy_nonoverlapping(left.offset(left_ind + 1),
- right,
- n);
+ left_node.reborrow_mut().as_leaf_mut().len -= count as u16;
+ right_node.reborrow_mut().as_leaf_mut().len += count as u16;
+
+ match (left_node.force(), right_node.force()) {
+ (ForceResult::Internal(left), ForceResult::Internal(mut right)) => {
+ // Make room for stolen edges.
+ let right_edges = right.reborrow_mut().as_internal_mut().edges.as_mut_ptr();
+ ptr::copy(right_edges,
+ right_edges.offset(count as isize),
+ right_len + 1);
+ right.correct_childrens_parent_links(count, count + right_len + 1);
+
+ move_edges(left, new_left_len + 1, right, 0, count);
},
- (Some(_), None) => unreachable!(),
- (None, Some(_)) => unreachable!(),
- (None, None) => {},
+ (ForceResult::Leaf(_), ForceResult::Leaf(_)) => { }
+ _ => { unreachable!(); }
}
+ }
+ }
- // Copy parent key/value pair to right child.
- ptr::copy_nonoverlapping(parent_k,
- right_k.offset(n as isize - 1),
- 1);
- ptr::copy_nonoverlapping(parent_v,
- right_v.offset(n as isize - 1),
- 1);
- // Copy left-most stolen pair to parent.
- ptr::copy_nonoverlapping(left_k.offset(left_ind),
- parent_k,
- 1);
- ptr::copy_nonoverlapping(left_v.offset(left_ind),
- parent_v,
- 1);
-
- // Fix lengths of left and right child and parent pointers in children of the right
- // child.
- self.reborrow_mut().left_edge().descend().as_leaf_mut().len -= n as u16;
- let mut right = self.reborrow_mut().right_edge().descend();
- right.as_leaf_mut().len += n as u16;
- if let ForceResult::Internal(mut node) = right.force() {
- for i in 0..(right_len+n+1) {
- Handle::new_edge(node.reborrow_mut(), i as usize).correct_parent_link();
- }
+ /// The symmetric clone of `bulk_steal_left`.
+ pub fn bulk_steal_right(&mut self, count: usize) {
+ unsafe {
+ let mut left_node = ptr::read(self).left_edge().descend();
+ let left_len = left_node.len();
+ let mut right_node = ptr::read(self).right_edge().descend();
+ let right_len = right_node.len();
+
+ // Make sure that we may steal safely.
+ debug_assert!(left_len + count <= CAPACITY);
+ debug_assert!(right_len >= count);
+
+ let new_right_len = right_len - count;
+
+ // Move data.
+ {
+ let left_kv = left_node.reborrow_mut().into_kv_pointers_mut();
+ let right_kv = right_node.reborrow_mut().into_kv_pointers_mut();
+ let parent_kv = {
+ let kv = self.reborrow_mut().into_kv_mut();
+ (kv.0 as *mut K, kv.1 as *mut V)
+ };
+
+ // Move parent's key/value pair to the left child.
+ move_kv(parent_kv, 0, left_kv, left_len, 1);
+
+ // Move elements from the right child to the left one.
+ move_kv(right_kv, 0, left_kv, left_len + 1, count - 1);
+
+ // Move the right-most stolen pair to the parent.
+ move_kv(right_kv, count - 1, parent_kv, 0, 1);
+
+ // Fix right indexing
+ ptr::copy(right_kv.0.offset(count as isize),
+ right_kv.0,
+ new_right_len);
+ ptr::copy(right_kv.1.offset(count as isize),
+ right_kv.1,
+ new_right_len);
+ }
+
+ left_node.reborrow_mut().as_leaf_mut().len += count as u16;
+ right_node.reborrow_mut().as_leaf_mut().len -= count as u16;
+
+ match (left_node.force(), right_node.force()) {
+ (ForceResult::Internal(left), ForceResult::Internal(mut right)) => {
+ move_edges(right.reborrow_mut(), 0, left, left_len + 1, count);
+
+ // Fix right indexing.
+ let right_edges = right.reborrow_mut().as_internal_mut().edges.as_mut_ptr();
+ ptr::copy(right_edges.offset(count as isize),
+ right_edges,
+ new_right_len + 1);
+ right.correct_childrens_parent_links(0, new_right_len + 1);
+ },
+ (ForceResult::Leaf(_), ForceResult::Leaf(_)) => { }
+ _ => { unreachable!(); }
}
}
}
}
+unsafe fn move_kv<K, V>(
+ source: (*mut K, *mut V), source_offset: usize,
+ dest: (*mut K, *mut V), dest_offset: usize,
+ count: usize)
+{
+ ptr::copy_nonoverlapping(source.0.offset(source_offset as isize),
+ dest.0.offset(dest_offset as isize),
+ count);
+ ptr::copy_nonoverlapping(source.1.offset(source_offset as isize),
+ dest.1.offset(dest_offset as isize),
+ count);
+}
+
+// Source and destination must have the same height.
+unsafe fn move_edges<K, V>(
+ mut source: NodeRef<marker::Mut, K, V, marker::Internal>, source_offset: usize,
+ mut dest: NodeRef<marker::Mut, K, V, marker::Internal>, dest_offset: usize,
+ count: usize)
+{
+ let source_ptr = source.as_internal_mut().edges.as_mut_ptr();
+ let dest_ptr = dest.as_internal_mut().edges.as_mut_ptr();
+ ptr::copy_nonoverlapping(source_ptr.offset(source_offset as isize),
+ dest_ptr.offset(dest_offset as isize),
+ count);
+ dest.correct_childrens_parent_links(dest_offset, dest_offset + count);
+}
+
impl<BorrowType, K, V, HandleType>
Handle<NodeRef<BorrowType, K, V, marker::LeafOrInternal>, HandleType> {
}
}
+impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, marker::Edge> {
+ /// Move the suffix after `self` from one node to another one. `right` must be empty.
+ /// The first edge of `right` remains unchanged.
+ pub fn move_suffix(&mut self,
+ right: &mut NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>) {
+ unsafe {
+ let left_new_len = self.idx;
+ let mut left_node = self.reborrow_mut().into_node();
+
+ let right_new_len = left_node.len() - left_new_len;
+ let mut right_node = right.reborrow_mut();
+
+ debug_assert!(right_node.len() == 0);
+ debug_assert!(left_node.height == right_node.height);
+
+ let left_kv = left_node.reborrow_mut().into_kv_pointers_mut();
+ let right_kv = right_node.reborrow_mut().into_kv_pointers_mut();
+
+
+ move_kv(left_kv, left_new_len, right_kv, 0, right_new_len);
+
+ left_node.reborrow_mut().as_leaf_mut().len = left_new_len as u16;
+ right_node.reborrow_mut().as_leaf_mut().len = right_new_len as u16;
+
+ match (left_node.force(), right_node.force()) {
+ (ForceResult::Internal(left), ForceResult::Internal(right)) => {
+ move_edges(left, left_new_len + 1, right, 1, right_new_len);
+ },
+ (ForceResult::Leaf(_), ForceResult::Leaf(_)) => { }
+ _ => { unreachable!(); }
+ }
+ }
+ }
+}
+
pub enum ForceResult<Leaf, Internal> {
Leaf(Leaf),
Internal(Internal)
pub fn append(&mut self, other: &mut Self) {
self.map.append(&mut other.map);
}
+
+ /// Splits the collection into two at the given key. Returns everything after the given key,
+ /// including the key.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(btree_split_off)]
+ /// use std::collections::BTreeMap;
+ ///
+ /// let mut a = BTreeMap::new();
+ /// a.insert(1, "a");
+ /// a.insert(2, "b");
+ /// a.insert(3, "c");
+ /// a.insert(17, "d");
+ /// a.insert(41, "e");
+ ///
+ /// let b = a.split_off(&3);
+ ///
+ /// assert_eq!(a.len(), 2);
+ /// assert_eq!(b.len(), 3);
+ ///
+ /// assert_eq!(a[&1], "a");
+ /// assert_eq!(a[&2], "b");
+ ///
+ /// assert_eq!(b[&3], "c");
+ /// assert_eq!(b[&17], "d");
+ /// assert_eq!(b[&41], "e");
+ /// ```
+ #[unstable(feature = "btree_split_off",
+ reason = "recently added as part of collections reform 2",
+ issue = "19986")]
+ pub fn split_off<Q: ?Sized + Ord>(&mut self, key: &Q) -> Self where T: Borrow<Q> {
+ BTreeSet { map: self.map.split_off(key) }
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
}
}
-/// Deprecated, renamed to EncodeUtf16
-#[unstable(feature = "str_utf16", issue = "27714")]
-#[rustc_deprecated(since = "1.8.0", reason = "renamed to EncodeUtf16")]
-pub type Utf16Units<'a> = EncodeUtf16<'a>;
-
/// External iterator for a string's UTF-16 code units.
///
/// For use with the `std::iter` module.
core_str::StrExt::slice_mut_unchecked(self, begin, end)
}
- /// Given a byte position, returns the next `char` and its index.
- ///
- /// # Panics
- ///
- /// If `i` is greater than or equal to the length of the string.
- /// If `i` is not the index of the beginning of a valid UTF-8 sequence.
- ///
- /// # Examples
- ///
- /// This example manually iterates through the code points of a string;
- /// this should normally be
- /// done by `.chars()` or `.char_indices()`.
- ///
- /// ```
- /// #![feature(str_char)]
- /// #![allow(deprecated)]
- ///
- /// use std::str::CharRange;
- ///
- /// let s = "中华Việt Nam";
- /// let mut i = 0;
- /// while i < s.len() {
- /// let CharRange {ch, next} = s.char_range_at(i);
- /// println!("{}: {}", i, ch);
- /// i = next;
- /// }
- /// ```
- ///
- /// This outputs:
- ///
- /// ```text
- /// 0: 中
- /// 3: 华
- /// 6: V
- /// 7: i
- /// 8: e
- /// 9:
- /// 11:
- /// 13: t
- /// 14:
- /// 15: N
- /// 16: a
- /// 17: m
- /// ```
- #[unstable(feature = "str_char",
- reason = "often replaced by char_indices, this method may \
- be removed in favor of just char_at() or eventually \
- removed altogether",
- issue = "27754")]
- #[inline]
- #[rustc_deprecated(reason = "use slicing plus chars() plus len_utf8",
- since = "1.9.0")]
- #[allow(deprecated)]
- pub fn char_range_at(&self, start: usize) -> CharRange {
- core_str::StrExt::char_range_at(self, start)
- }
-
- /// Given a byte position, returns the previous `char` and its position.
- ///
- /// Note that Unicode has many features, such as combining marks, ligatures,
- /// and direction marks, that need to be taken into account to correctly reverse a string.
- ///
- /// Returns 0 for next index if called on start index 0.
- ///
- /// # Panics
- ///
- /// If `i` is greater than the length of the string.
- /// If `i` is not an index following a valid UTF-8 sequence.
- ///
- /// # Examples
- ///
- /// This example manually iterates through the code points of a string;
- /// this should normally be
- /// done by `.chars().rev()` or `.char_indices()`.
- ///
- /// ```
- /// #![feature(str_char)]
- /// #![allow(deprecated)]
- ///
- /// use std::str::CharRange;
- ///
- /// let s = "中华Việt Nam";
- /// let mut i = s.len();
- /// while i > 0 {
- /// let CharRange {ch, next} = s.char_range_at_reverse(i);
- /// println!("{}: {}", i, ch);
- /// i = next;
- /// }
- /// ```
- ///
- /// This outputs:
- ///
- /// ```text
- /// 18: m
- /// 17: a
- /// 16: N
- /// 15:
- /// 14: t
- /// 13:
- /// 11:
- /// 9: e
- /// 8: i
- /// 7: V
- /// 6: 华
- /// 3: 中
- /// ```
- #[unstable(feature = "str_char",
- reason = "often replaced by char_indices, this method may \
- be removed in favor of just char_at_reverse() or \
- eventually removed altogether",
- issue = "27754")]
- #[inline]
- #[rustc_deprecated(reason = "use slicing plus chars().rev() plus len_utf8",
- since = "1.9.0")]
- #[allow(deprecated)]
- pub fn char_range_at_reverse(&self, start: usize) -> CharRange {
- core_str::StrExt::char_range_at_reverse(self, start)
- }
-
- /// Given a byte position, returns the `char` at that position.
- ///
- /// # Panics
- ///
- /// If `i` is greater than or equal to the length of the string.
- /// If `i` is not the index of the beginning of a valid UTF-8 sequence.
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(str_char)]
- /// #![allow(deprecated)]
- ///
- /// let s = "abπc";
- /// assert_eq!(s.char_at(1), 'b');
- /// assert_eq!(s.char_at(2), 'π');
- /// assert_eq!(s.char_at(4), 'c');
- /// ```
- #[unstable(feature = "str_char",
- reason = "frequently replaced by the chars() iterator, this \
- method may be removed or possibly renamed in the \
- future; it is normally replaced by chars/char_indices \
- iterators or by getting the first char from a \
- subslice",
- issue = "27754")]
- #[inline]
- #[allow(deprecated)]
- #[rustc_deprecated(reason = "use slicing plus chars()",
- since = "1.9.0")]
- pub fn char_at(&self, i: usize) -> char {
- core_str::StrExt::char_at(self, i)
- }
-
- /// Given a byte position, returns the `char` at that position, counting
- /// from the end.
- ///
- /// # Panics
- ///
- /// If `i` is greater than the length of the string.
- /// If `i` is not an index following a valid UTF-8 sequence.
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(str_char)]
- /// #![allow(deprecated)]
- ///
- /// let s = "abπc";
- /// assert_eq!(s.char_at_reverse(1), 'a');
- /// assert_eq!(s.char_at_reverse(2), 'b');
- /// assert_eq!(s.char_at_reverse(3), 'π');
- /// ```
- #[unstable(feature = "str_char",
- reason = "see char_at for more details, but reverse semantics \
- are also somewhat unclear, especially with which \
- cases generate panics",
- issue = "27754")]
- #[inline]
- #[rustc_deprecated(reason = "use slicing plus chars().rev()",
- since = "1.9.0")]
- #[allow(deprecated)]
- pub fn char_at_reverse(&self, i: usize) -> char {
- core_str::StrExt::char_at_reverse(self, i)
- }
-
- /// Retrieves the first `char` from a `&str` and returns it.
- ///
- /// Note that a single Unicode character (grapheme cluster)
- /// can be composed of multiple `char`s.
- ///
- /// This does not allocate a new string; instead, it returns a slice that
- /// points one code point beyond the code point that was shifted.
- ///
- /// `None` is returned if the slice is empty.
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(str_char)]
- /// #![allow(deprecated)]
- ///
- /// let s = "Łódź"; // \u{141}o\u{301}dz\u{301}
- /// let (c, s1) = s.slice_shift_char().unwrap();
- ///
- /// assert_eq!(c, 'Ł');
- /// assert_eq!(s1, "ódź");
- ///
- /// let (c, s2) = s1.slice_shift_char().unwrap();
- ///
- /// assert_eq!(c, 'o');
- /// assert_eq!(s2, "\u{301}dz\u{301}");
- /// ```
- #[unstable(feature = "str_char",
- reason = "awaiting conventions about shifting and slices and \
- may not be warranted with the existence of the chars \
- and/or char_indices iterators",
- issue = "27754")]
- #[inline]
- #[rustc_deprecated(reason = "use chars() plus Chars::as_str",
- since = "1.9.0")]
- #[allow(deprecated)]
- pub fn slice_shift_char(&self) -> Option<(char, &str)> {
- core_str::StrExt::slice_shift_char(self)
- }
-
/// Divide one string slice into two at an index.
///
/// The argument, `mid`, should be a byte offset from the start of the
core_str::StrExt::lines_any(self)
}
- /// Returns an iterator of `u16` over the string encoded as UTF-16.
- #[unstable(feature = "str_utf16",
- reason = "this functionality may only be provided by libunicode",
- issue = "27714")]
- #[rustc_deprecated(since = "1.8.0", reason = "renamed to encode_utf16")]
- #[allow(deprecated)]
- pub fn utf16_units(&self) -> Utf16Units {
- Utf16Units { encoder: Utf16Encoder::new(self[..].chars()) }
- }
-
/// Returns an iterator of `u16` over the string encoded as UTF-16.
#[stable(feature = "encode_utf16", since = "1.8.0")]
pub fn encode_utf16(&self) -> EncodeUtf16 {
use std::collections::btree_map::Entry::{Occupied, Vacant};
use std::rc::Rc;
+use std::iter::FromIterator;
+use super::DeterministicRng;
+
#[test]
fn test_basic_large() {
let mut map = BTreeMap::new();
create_append_test!(test_append_239, 239);
create_append_test!(test_append_1700, 1700);
+fn rand_data(len: usize) -> Vec<(u32, u32)> {
+ let mut rng = DeterministicRng::new();
+ Vec::from_iter(
+ (0..len).map(|_| (rng.next(), rng.next()))
+ )
+}
+
+#[test]
+fn test_split_off_empty_right() {
+ let mut data = rand_data(173);
+
+ let mut map = BTreeMap::from_iter(data.clone());
+ let right = map.split_off(&(data.iter().max().unwrap().0 + 1));
+
+ data.sort();
+ assert!(map.into_iter().eq(data));
+ assert!(right.into_iter().eq(None));
+}
+
+#[test]
+fn test_split_off_empty_left() {
+ let mut data = rand_data(314);
+
+ let mut map = BTreeMap::from_iter(data.clone());
+ let right = map.split_off(&data.iter().min().unwrap().0);
+
+ data.sort();
+ assert!(map.into_iter().eq(None));
+ assert!(right.into_iter().eq(data));
+}
+
+#[test]
+fn test_split_off_large_random_sorted() {
+ let mut data = rand_data(1529);
+ // special case with maximum height.
+ data.sort();
+
+ let mut map = BTreeMap::from_iter(data.clone());
+ let key = data[data.len() / 2].0;
+ let right = map.split_off(&key);
+
+ assert!(map.into_iter().eq(data.clone().into_iter().filter(|x| x.0 < key)));
+ assert!(right.into_iter().eq(data.into_iter().filter(|x| x.0 >= key)));
+}
+
mod bench {
use std::collections::BTreeMap;
use std::__rand::{Rng, thread_rng};
mod map;
mod set;
+
+/// XorShiftRng
+struct DeterministicRng {
+ x: u32,
+ y: u32,
+ z: u32,
+ w: u32,
+}
+
+impl DeterministicRng {
+ fn new() -> Self {
+ DeterministicRng {
+ x: 0x193a6754,
+ y: 0xa8a7d469,
+ z: 0x97830e05,
+ w: 0x113ba7bb
+ }
+ }
+
+ fn next(&mut self) -> u32 {
+ let x = self.x;
+ let t = x ^ (x << 11);
+ self.x = self.y;
+ self.y = self.z;
+ self.z = self.w;
+ let w_ = self.w;
+ self.w = w_ ^ (w_ >> 19) ^ (t ^ (t >> 8));
+ self.w
+ }
+}
use std::collections::BTreeSet;
+use std::iter::FromIterator;
+use super::DeterministicRng;
+
#[test]
fn test_clone_eq() {
let mut m = BTreeSet::new();
assert_eq!(a.contains(&4), true);
assert_eq!(a.contains(&5), true);
}
+
+fn rand_data(len: usize) -> Vec<u32> {
+ let mut rng = DeterministicRng::new();
+ Vec::from_iter(
+ (0..len).map(|_| rng.next())
+ )
+}
+
+#[test]
+fn test_split_off_empty_right() {
+ let mut data = rand_data(173);
+
+ let mut set = BTreeSet::from_iter(data.clone());
+ let right = set.split_off(&(data.iter().max().unwrap() + 1));
+
+ data.sort();
+ assert!(set.into_iter().eq(data));
+ assert!(right.into_iter().eq(None));
+}
+
+#[test]
+fn test_split_off_empty_left() {
+ let mut data = rand_data(314);
+
+ let mut set = BTreeSet::from_iter(data.clone());
+ let right = set.split_off(data.iter().min().unwrap());
+
+ data.sort();
+ assert!(set.into_iter().eq(None));
+ assert!(right.into_iter().eq(data));
+}
+
+#[test]
+fn test_split_off_large_random_sorted() {
+ let mut data = rand_data(1529);
+ // special case with maximum height.
+ data.sort();
+
+ let mut set = BTreeSet::from_iter(data.clone());
+ let key = data[data.len() / 2];
+ let right = set.split_off(&key);
+
+ assert!(set.into_iter().eq(data.clone().into_iter().filter(|x| *x < key)));
+ assert!(right.into_iter().eq(data.into_iter().filter(|x| *x >= key)));
+}
#![feature(binary_heap_append)]
#![feature(box_syntax)]
#![feature(btree_append)]
+#![feature(btree_split_off)]
#![feature(btree_range)]
#![feature(collections)]
#![feature(collections_bound)]
#![feature(pattern)]
#![feature(rand)]
#![feature(step_by)]
-#![feature(str_char)]
#![feature(str_escape)]
#![feature(test)]
#![feature(unboxed_closures)]
assert!(!" _ ".chars().all(|c| c.is_whitespace()));
}
-#[test]
-#[allow(deprecated)]
-fn test_slice_shift_char() {
- let data = "ประเทศไทย中";
- assert_eq!(data.slice_shift_char(), Some(('ป', "ระเทศไทย中")));
-}
-
-#[test]
-#[allow(deprecated)]
-fn test_slice_shift_char_2() {
- let empty = "";
- assert_eq!(empty.slice_shift_char(), None);
-}
-
#[test]
fn test_is_utf8() {
// deny overlong encodings
assert!(!"".contains('a'));
}
-#[test]
-#[allow(deprecated)]
-fn test_char_at() {
- let s = "ศไทย中华Việt Nam";
- let v = vec!['ศ','ไ','ท','ย','中','华','V','i','ệ','t',' ','N','a','m'];
- let mut pos = 0;
- for ch in &v {
- assert!(s.char_at(pos) == *ch);
- pos += ch.to_string().len();
- }
-}
-
-#[test]
-#[allow(deprecated)]
-fn test_char_at_reverse() {
- let s = "ศไทย中华Việt Nam";
- let v = vec!['ศ','ไ','ท','ย','中','华','V','i','ệ','t',' ','N','a','m'];
- let mut pos = s.len();
- for ch in v.iter().rev() {
- assert!(s.char_at_reverse(pos) == *ch);
- pos -= ch.to_string().len();
- }
-}
-
#[test]
fn test_split_at() {
let s = "ศไทย中华Việt Nam";
assert_eq!("22".cmp("1234"), Greater);
}
-#[test]
-#[allow(deprecated)]
-fn test_char_range_at() {
- let data = "b¢€𤭢𤭢€¢b";
- assert_eq!('b', data.char_range_at(0).ch);
- assert_eq!('¢', data.char_range_at(1).ch);
- assert_eq!('€', data.char_range_at(3).ch);
- assert_eq!('𤭢', data.char_range_at(6).ch);
- assert_eq!('𤭢', data.char_range_at(10).ch);
- assert_eq!('€', data.char_range_at(14).ch);
- assert_eq!('¢', data.char_range_at(17).ch);
- assert_eq!('b', data.char_range_at(19).ch);
-}
-
-#[test]
-#[allow(deprecated)]
-fn test_char_range_at_reverse_underflow() {
- assert_eq!("abc".char_range_at_reverse(0).next, 0);
-}
-
#[test]
fn test_iterator() {
let s = "ศไทย中华Việt Nam";
borrow: orig.borrow,
}
}
-
- /// Make a new `Ref` for an optional component of the borrowed data, e.g. an
- /// enum variant.
- ///
- /// The `RefCell` is already immutably borrowed, so this cannot fail.
- ///
- /// This is an associated function that needs to be used as
- /// `Ref::filter_map(...)`. A method would interfere with methods of the
- /// same name on the contents of a `RefCell` used through `Deref`.
- ///
- /// # Example
- ///
- /// ```
- /// # #![feature(cell_extras)]
- /// use std::cell::{RefCell, Ref};
- ///
- /// let c = RefCell::new(Ok(5));
- /// let b1: Ref<Result<u32, ()>> = c.borrow();
- /// let b2: Ref<u32> = Ref::filter_map(b1, |o| o.as_ref().ok()).unwrap();
- /// assert_eq!(*b2, 5)
- /// ```
- #[unstable(feature = "cell_extras", reason = "recently added",
- issue = "27746")]
- #[rustc_deprecated(since = "1.8.0", reason = "can be built on `Ref::map`: \
- https://crates.io/crates/ref_filter_map")]
- #[inline]
- pub fn filter_map<U: ?Sized, F>(orig: Ref<'b, T>, f: F) -> Option<Ref<'b, U>>
- where F: FnOnce(&T) -> Option<&U>
- {
- f(orig.value).map(move |new| Ref {
- value: new,
- borrow: orig.borrow,
- })
- }
}
#[unstable(feature = "coerce_unsized", issue = "27732")]
borrow: orig.borrow,
}
}
-
- /// Make a new `RefMut` for an optional component of the borrowed data, e.g.
- /// an enum variant.
- ///
- /// The `RefCell` is already mutably borrowed, so this cannot fail.
- ///
- /// This is an associated function that needs to be used as
- /// `RefMut::filter_map(...)`. A method would interfere with methods of the
- /// same name on the contents of a `RefCell` used through `Deref`.
- ///
- /// # Example
- ///
- /// ```
- /// # #![feature(cell_extras)]
- /// use std::cell::{RefCell, RefMut};
- ///
- /// let c = RefCell::new(Ok(5));
- /// {
- /// let b1: RefMut<Result<u32, ()>> = c.borrow_mut();
- /// let mut b2: RefMut<u32> = RefMut::filter_map(b1, |o| {
- /// o.as_mut().ok()
- /// }).unwrap();
- /// assert_eq!(*b2, 5);
- /// *b2 = 42;
- /// }
- /// assert_eq!(*c.borrow(), Ok(42));
- /// ```
- #[unstable(feature = "cell_extras", reason = "recently added",
- issue = "27746")]
- #[rustc_deprecated(since = "1.8.0", reason = "can be built on `RefMut::map`: \
- https://crates.io/crates/ref_filter_map")]
- #[inline]
- pub fn filter_map<U: ?Sized, F>(orig: RefMut<'b, T>, f: F) -> Option<RefMut<'b, U>>
- where F: FnOnce(&mut T) -> Option<&mut U>
- {
- let RefMut { value, borrow } = orig;
- f(value).map(move |new| RefMut {
- value: new,
- borrow: borrow,
- })
- }
}
struct BorrowRefMut<'b> {
//!
//! Their definition should always match the ABI defined in `rustc::back::abi`.
-use clone::Clone;
-use marker::Copy;
-use mem;
-
-/// The representation of a slice like `&[T]`.
-///
-/// This struct is guaranteed to have the layout of types like `&[T]`,
-/// `&str`, and `Box<[T]>`, but is not the type of such slices
-/// (e.g. the fields are not directly accessible on a `&[T]`) nor does
-/// it control that layout (changing the definition will not change
-/// the layout of a `&[T]`). It is only designed to be used by unsafe
-/// code that needs to manipulate the low-level details.
-///
-/// However, it is not recommended to use this type for such code,
-/// since there are alternatives which may be safer:
-///
-/// - Creating a slice from a data pointer and length can be done with
-/// `std::slice::from_raw_parts` or `std::slice::from_raw_parts_mut`
-/// instead of `std::mem::transmute`ing a value of type `Slice`.
-/// - Extracting the data pointer and length from a slice can be
-/// performed with the `as_ptr` (or `as_mut_ptr`) and `len`
-/// methods.
-///
-/// If one does decide to convert a slice value to a `Slice`, the
-/// `Repr` trait in this module provides a method for a safe
-/// conversion from `&[T]` (and `&str`) to a `Slice`, more type-safe
-/// than a call to `transmute`.
-///
-/// # Examples
-///
-/// ```
-/// #![feature(raw)]
-///
-/// use std::raw::{self, Repr};
-///
-/// let slice: &[u16] = &[1, 2, 3, 4];
-///
-/// let repr: raw::Slice<u16> = slice.repr();
-/// println!("data pointer = {:?}, length = {}", repr.data, repr.len);
-/// ```
-#[repr(C)]
-#[allow(missing_debug_implementations)]
-#[rustc_deprecated(reason = "use raw accessors/constructors in `slice` module",
- since = "1.9.0")]
-#[unstable(feature = "raw", issue = "27751")]
-pub struct Slice<T> {
- pub data: *const T,
- pub len: usize,
-}
-
-#[allow(deprecated)]
-impl<T> Copy for Slice<T> {}
-#[allow(deprecated)]
-impl<T> Clone for Slice<T> {
- fn clone(&self) -> Slice<T> { *self }
-}
-
/// The representation of a trait object like `&SomeTrait`.
///
/// This struct has the same layout as types like `&SomeTrait` and
pub data: *mut (),
pub vtable: *mut (),
}
-
-/// This trait is meant to map equivalences between raw structs and their
-/// corresponding rust values.
-#[rustc_deprecated(reason = "use raw accessors/constructors in `slice` module",
- since = "1.9.0")]
-#[unstable(feature = "raw", issue = "27751")]
-pub unsafe trait Repr<T> {
- /// This function "unwraps" a rust value (without consuming it) into its raw
- /// struct representation. This can be used to read/write different values
- /// for the struct. This is a safe method because by default it does not
- /// enable write-access to the fields of the return value in safe code.
- #[inline]
- fn repr(&self) -> T { unsafe { mem::transmute_copy(&self) } }
-}
-
-#[allow(deprecated)]
-unsafe impl<T> Repr<Slice<T>> for [T] {}
-#[allow(deprecated)]
-unsafe impl Repr<Slice<u8>> for str {}
use self::pattern::Pattern;
use self::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher};
-use char::{self, CharExt};
+use char;
use clone::Clone;
use convert::AsRef;
use default::Default;
where P::Searcher: ReverseSearcher<'a>;
#[stable(feature = "is_char_boundary", since = "1.9.0")]
fn is_char_boundary(&self, index: usize) -> bool;
- #[unstable(feature = "str_char",
- reason = "often replaced by char_indices, this method may \
- be removed in favor of just char_at() or eventually \
- removed altogether",
- issue = "27754")]
- #[rustc_deprecated(reason = "use slicing plus chars() plus len_utf8",
- since = "1.9.0")]
- fn char_range_at(&self, start: usize) -> CharRange;
- #[unstable(feature = "str_char",
- reason = "often replaced by char_indices, this method may \
- be removed in favor of just char_at_reverse() or \
- eventually removed altogether",
- issue = "27754")]
- #[rustc_deprecated(reason = "use slicing plus chars().rev() plus len_utf8",
- since = "1.9.0")]
- fn char_range_at_reverse(&self, start: usize) -> CharRange;
- #[unstable(feature = "str_char",
- reason = "frequently replaced by the chars() iterator, this \
- method may be removed or possibly renamed in the \
- future; it is normally replaced by chars/char_indices \
- iterators or by getting the first char from a \
- subslice",
- issue = "27754")]
- #[rustc_deprecated(reason = "use slicing plus chars()",
- since = "1.9.0")]
- fn char_at(&self, i: usize) -> char;
- #[unstable(feature = "str_char",
- reason = "see char_at for more details, but reverse semantics \
- are also somewhat unclear, especially with which \
- cases generate panics",
- issue = "27754")]
- #[rustc_deprecated(reason = "use slicing plus chars().rev()",
- since = "1.9.0")]
- fn char_at_reverse(&self, i: usize) -> char;
#[stable(feature = "core", since = "1.6.0")]
fn as_bytes(&self) -> &[u8];
#[stable(feature = "core", since = "1.6.0")]
fn split_at(&self, mid: usize) -> (&str, &str);
#[stable(feature = "core", since = "1.6.0")]
fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str);
- #[unstable(feature = "str_char",
- reason = "awaiting conventions about shifting and slices and \
- may not be warranted with the existence of the chars \
- and/or char_indices iterators",
- issue = "27754")]
- #[rustc_deprecated(reason = "use chars() plus Chars::as_str",
- since = "1.9.0")]
- fn slice_shift_char(&self) -> Option<(char, &str)>;
#[stable(feature = "core", since = "1.6.0")]
fn as_ptr(&self) -> *const u8;
#[stable(feature = "core", since = "1.6.0")]
}
}
- #[inline]
- fn char_range_at(&self, i: usize) -> CharRange {
- let (c, n) = char_range_at_raw(self.as_bytes(), i);
- CharRange { ch: unsafe { char::from_u32_unchecked(c) }, next: n }
- }
-
- #[inline]
- fn char_range_at_reverse(&self, start: usize) -> CharRange {
- let mut prev = start;
-
- prev = prev.saturating_sub(1);
- if self.as_bytes()[prev] < 128 {
- return CharRange{ch: self.as_bytes()[prev] as char, next: prev}
- }
-
- // Multibyte case is a fn to allow char_range_at_reverse to inline cleanly
- fn multibyte_char_range_at_reverse(s: &str, mut i: usize) -> CharRange {
- // while there is a previous byte == 10......
- while i > 0 && s.as_bytes()[i] & !CONT_MASK == TAG_CONT_U8 {
- i -= 1;
- }
-
- let first= s.as_bytes()[i];
- let w = UTF8_CHAR_WIDTH[first as usize];
- assert!(w != 0);
-
- let mut val = utf8_first_byte(first, w as u32);
- val = utf8_acc_cont_byte(val, s.as_bytes()[i + 1]);
- if w > 2 { val = utf8_acc_cont_byte(val, s.as_bytes()[i + 2]); }
- if w > 3 { val = utf8_acc_cont_byte(val, s.as_bytes()[i + 3]); }
-
- CharRange {ch: unsafe { char::from_u32_unchecked(val) }, next: i}
- }
-
- multibyte_char_range_at_reverse(self, prev)
- }
-
- #[inline]
- #[allow(deprecated)]
- fn char_at(&self, i: usize) -> char {
- self.char_range_at(i).ch
- }
-
- #[inline]
- #[allow(deprecated)]
- fn char_at_reverse(&self, i: usize) -> char {
- self.char_range_at_reverse(i).ch
- }
-
#[inline]
fn as_bytes(&self) -> &[u8] {
unsafe { mem::transmute(self) }
}
}
- #[inline]
- #[allow(deprecated)]
- fn slice_shift_char(&self) -> Option<(char, &str)> {
- if self.is_empty() {
- None
- } else {
- let ch = self.char_at(0);
- let next_s = unsafe { self.slice_unchecked(ch.len_utf8(), self.len()) };
- Some((ch, next_s))
- }
- }
-
#[inline]
fn as_ptr(&self) -> *const u8 {
self as *const str as *const u8
}
}
-/// Pluck a code point out of a UTF-8-like byte slice and return the
-/// index of the next code point.
-#[inline]
-fn char_range_at_raw(bytes: &[u8], i: usize) -> (u32, usize) {
- if bytes[i] < 128 {
- return (bytes[i] as u32, i + 1);
- }
-
- // Multibyte case is a fn to allow char_range_at to inline cleanly
- fn multibyte_char_range_at(bytes: &[u8], i: usize) -> (u32, usize) {
- let first = bytes[i];
- let w = UTF8_CHAR_WIDTH[first as usize];
- assert!(w != 0);
-
- let mut val = utf8_first_byte(first, w as u32);
- val = utf8_acc_cont_byte(val, bytes[i + 1]);
- if w > 2 { val = utf8_acc_cont_byte(val, bytes[i + 2]); }
- if w > 3 { val = utf8_acc_cont_byte(val, bytes[i + 3]); }
-
- (val, i + w as usize)
- }
-
- multibyte_char_range_at(bytes, i)
-}
-
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> Default for &'a str {
fn default() -> &'a str { "" }
assert_eq!(*d, 7);
}
-#[test]
-#[allow(deprecated)]
-fn ref_filter_map_accessor() {
- struct X(RefCell<Result<u32, ()>>);
- impl X {
- fn accessor(&self) -> Option<Ref<u32>> {
- Ref::filter_map(self.0.borrow(), |r| r.as_ref().ok())
- }
- }
- let x = X(RefCell::new(Ok(7)));
- let d: Ref<u32> = x.accessor().unwrap();
- assert_eq!(*d, 7);
-}
-
#[test]
fn ref_mut_map_accessor() {
struct X(RefCell<(u32, char)>);
assert_eq!(*x.0.borrow(), (8, 'z'));
}
-#[test]
-#[allow(deprecated)]
-fn ref_mut_filter_map_accessor() {
- struct X(RefCell<Result<u32, ()>>);
- impl X {
- fn accessor(&self) -> Option<RefMut<u32>> {
- RefMut::filter_map(self.0.borrow_mut(), |r| r.as_mut().ok())
- }
- }
- let x = X(RefCell::new(Ok(7)));
- {
- let mut d: RefMut<u32> = x.accessor().unwrap();
- assert_eq!(*d, 7);
- *d += 1;
- }
- assert_eq!(*x.0.borrow(), Ok(8));
-}
-
#[test]
fn as_unsafe_cell() {
let c1: Cell<usize> = Cell::new(0);
-Subproject commit b19b5465a1235be3323363cdc11838739b593029
+Subproject commit 45d85899e99d33e291b2bf3259881b46cc5365d7
// This fails to compile because the match is irrefutable.
while let Irrefutable(x) = irr {
- ...
+ // ...
}
+```
Try this instead:
-```
+```no_run
struct Irrefutable(i32);
let irr = Irrefutable(0);
loop {
let Irrefutable(x) = irr;
- ...
+ // ...
}
```
"##,
}
TestKind::SwitchInt { switch_ty, ref options, indices: _ } => {
- let otherwise = self.cfg.start_new_block();
- let targets: Vec<_> =
- options.iter()
- .map(|_| self.cfg.start_new_block())
- .chain(Some(otherwise))
- .collect();
+ let (targets, term) = match switch_ty.sty {
+ // If we're matching on boolean we can
+ // use the If TerminatorKind instead
+ ty::TyBool => {
+ assert!(options.len() > 0 && options.len() <= 2);
+
+ let (true_bb, else_bb) =
+ (self.cfg.start_new_block(),
+ self.cfg.start_new_block());
+
+ let targets = match &options[0] {
+ &ConstVal::Bool(true) => vec![true_bb, else_bb],
+ &ConstVal::Bool(false) => vec![else_bb, true_bb],
+ v => span_bug!(test.span, "expected boolean value but got {:?}", v)
+ };
+
+ (targets,
+ TerminatorKind::If {
+ cond: Operand::Consume(lvalue.clone()),
+ targets: (true_bb, else_bb)
+ })
+
+ }
+ _ => {
+ // The switch may be inexhaustive so we
+ // add a catch all block
+ let otherwise = self.cfg.start_new_block();
+ let targets: Vec<_> =
+ options.iter()
+ .map(|_| self.cfg.start_new_block())
+ .chain(Some(otherwise))
+ .collect();
+
+ (targets.clone(),
+ TerminatorKind::SwitchInt {
+ discr: lvalue.clone(),
+ switch_ty: switch_ty,
+ values: options.clone(),
+ targets: targets
+ })
+ }
+ };
+
self.cfg.terminate(block,
scope_id,
test.span,
- TerminatorKind::SwitchInt {
- discr: lvalue.clone(),
- switch_ty: switch_ty,
- values: options.clone(),
- targets: targets.clone(),
- });
+ term);
targets
}
message: &'a str,
context: UnresolvedNameContext<'a>,
is_static_method: bool,
- is_field: bool
+ is_field: bool,
+ def: Def,
},
/// error E0426: use of undeclared label
UndeclaredLabel(&'a str),
argument is missing?")
}
ResolutionError::UnresolvedName { path, message: msg, context, is_static_method,
- is_field } => {
+ is_field, def } => {
let mut err = struct_span_err!(resolver.session,
span,
E0425,
UnresolvedNameContext::PathIsMod(parent) => {
err.help(&match parent.map(|parent| &parent.node) {
Some(&ExprKind::Field(_, ident)) => {
- format!("To reference an item from the `{module}` module, \
+ format!("to reference an item from the `{module}` module, \
use `{module}::{ident}`",
module = path,
ident = ident.node)
}
Some(&ExprKind::MethodCall(ident, _, _)) => {
- format!("To call a function from the `{module}` module, \
+ format!("to call a function from the `{module}` module, \
use `{module}::{ident}(..)`",
module = path,
ident = ident.node)
}
_ => {
- format!("Module `{module}` cannot be used as an expression",
+ format!("{def} `{module}` cannot be used as an expression",
+ def = def.kind_name(),
module = path)
}
});
message: "",
context: UnresolvedNameContext::Other,
is_static_method: false,
- is_field: false
+ is_field: false,
+ def: Def::Err,
};
resolve_error(self, path.span, error);
Def::Err
};
let mut context = UnresolvedNameContext::Other;
+ let mut def = Def::Err;
if !msg.is_empty() {
msg = format!(". Did you mean {}?", msg);
} else {
match self.resolve_module_path(&name_path[..],
UseLexicalScope,
expr.span) {
- Success(_) => {
+ Success(e) => {
+ if let Some(def_type) = e.def {
+ def = def_type;
+ }
context = UnresolvedNameContext::PathIsMod(parent);
},
_ => {},
context: context,
is_static_method: method_scope && is_static,
is_field: is_field,
+ def: def,
});
}
}
// the trait
fn foo(&self) {}
}
+```
"##,
E0186: r##"
/// it was opened with. Files also implement `Seek` to alter the logical cursor
/// that the file contains internally.
///
+/// Files are automatically closed when they go out of scope.
+///
/// # Examples
///
/// ```no_run
/// if dir.is_dir() {
/// for entry in try!(fs::read_dir(dir)) {
/// let entry = try!(entry);
-/// if try!(entry.file_type()).is_dir() {
-/// try!(visit_dirs(&entry.path(), cb));
+/// let path = entry.path();
+/// if path.is_dir() {
+/// try!(visit_dirs(&path, cb));
/// } else {
/// cb(&entry);
/// }
#[stable(feature = "panic_hooks", since = "1.10.0")]
pub use panicking::{take_hook, set_hook, PanicInfo, Location};
-///
-#[rustc_deprecated(since = "1.9.0", reason = "renamed to set_hook")]
-#[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")]
-pub fn set_handler<F>(handler: F) where F: Fn(&PanicInfo) + 'static + Sync + Send {
- set_hook(Box::new(handler))
-}
-
-///
-#[rustc_deprecated(since = "1.9.0", reason = "renamed to take_hook")]
-#[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")]
-pub fn take_handler() -> Box<Fn(&PanicInfo) + 'static + Sync + Send> {
- take_hook()
-}
-
-/// A marker trait which represents "unwind safe" types in Rust.
+/// A marker trait which represents "panic safe" types in Rust.
///
/// This trait is implemented by default for many types and behaves similarly in
/// terms of inference of implementation to the `Send` and `Sync` traits. The
across an unwind boundary"]
pub trait UnwindSafe {}
-/// Deprecated, renamed to UnwindSafe
-#[unstable(feature = "recover", reason = "awaiting feedback", issue = "27719")]
-#[rustc_deprecated(reason = "renamed to `UnwindSafe`", since = "1.9.0")]
-pub trait RecoverSafe {}
-#[unstable(feature = "recover", reason = "awaiting feedback", issue = "27719")]
-#[allow(deprecated)]
-impl<T: UnwindSafe> RecoverSafe for T {}
-
/// A marker trait representing types where a shared reference is considered
/// unwind safe.
///
pub T
);
-/// Deprecated, renamed to `AssertUnwindSafe`
-#[unstable(feature = "recover", issue = "27719")]
-#[rustc_deprecated(reason = "renamed to `AssertUnwindSafe`", since = "1.9.0")]
-pub struct AssertRecoverSafe<T>(pub T);
-
// Implementations of the `UnwindSafe` trait:
//
// * By default everything is unwind safe
impl<T: ?Sized> UnwindSafe for RwLock<T> {}
#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<T> UnwindSafe for AssertUnwindSafe<T> {}
-#[unstable(feature = "recover", issue = "27719")]
-#[allow(deprecated)]
-impl<T> UnwindSafe for AssertRecoverSafe<T> {}
// not covered via the Shared impl above b/c the inner contents use
// Cell/AtomicUsize, but the usage here is unwind safe so we can lift the
impl<T: ?Sized> !RefUnwindSafe for UnsafeCell<T> {}
#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<T> RefUnwindSafe for AssertUnwindSafe<T> {}
-#[unstable(feature = "recover", issue = "27719")]
-#[allow(deprecated)]
-impl<T> RefUnwindSafe for AssertRecoverSafe<T> {}
#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<T> Deref for AssertUnwindSafe<T> {
}
}
-#[allow(deprecated)]
-impl<T> AssertRecoverSafe<T> {
- /// Creates a new `AssertRecoverSafe` wrapper around the provided type.
- #[unstable(feature = "recover", reason = "awaiting feedback", issue = "27719")]
- #[rustc_deprecated(reason = "the type's field is now public, construct it directly",
- since = "1.9.0")]
- pub fn new(t: T) -> AssertRecoverSafe<T> {
- AssertRecoverSafe(t)
- }
-
- /// Consumes the `AssertRecoverSafe`, returning the wrapped value.
- #[unstable(feature = "recover", reason = "awaiting feedback", issue = "27719")]
- #[rustc_deprecated(reason = "the type's field is now public, access it directly",
- since = "1.9.0")]
- pub fn into_inner(self) -> T {
- self.0
- }
-}
-
-#[unstable(feature = "recover", issue = "27719")]
-#[allow(deprecated)]
-impl<T> Deref for AssertRecoverSafe<T> {
- type Target = T;
-
- fn deref(&self) -> &T {
- &self.0
- }
-}
-
-#[unstable(feature = "recover", issue = "27719")]
-#[allow(deprecated)]
-impl<T> DerefMut for AssertRecoverSafe<T> {
- fn deref_mut(&mut self) -> &mut T {
- &mut self.0
- }
-}
-
-#[unstable(feature = "recover", issue = "27719")]
-#[allow(deprecated)]
-impl<R, F: FnOnce() -> R> FnOnce<()> for AssertRecoverSafe<F> {
- type Output = R;
-
- extern "rust-call" fn call_once(self, _args: ()) -> R {
- (self.0)()
- }
-}
-
/// Invokes a closure, capturing the cause of an unwinding panic if one occurs.
///
/// This function will return `Ok` with the closure's result if the closure
}
}
-/// Deprecated, renamed to `catch_unwind`
-#[unstable(feature = "recover", reason = "awaiting feedback", issue = "27719")]
-#[rustc_deprecated(reason = "renamed to `catch_unwind`", since = "1.9.0")]
-pub fn recover<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
- catch_unwind(f)
-}
-
/// Triggers a panic without invoking the panic hook.
///
/// This is designed to be used in conjunction with `catch_unwind` to, for
pub fn resume_unwind(payload: Box<Any + Send>) -> ! {
panicking::rust_panic(payload)
}
-
-/// Deprecated, use resume_unwind instead
-#[unstable(feature = "panic_propagate", reason = "awaiting feedback", issue = "30752")]
-#[rustc_deprecated(reason = "renamed to `resume_unwind`", since = "1.9.0")]
-pub fn propagate(payload: Box<Any + Send>) -> ! {
- resume_unwind(payload)
-}
/// ```
///
/// [`assert!`]: macro.assert!.html
-/// [`if` conditionals]: ../book/if.html
+/// [`if`]: ../book/if.html
/// [`BitAnd`]: ops/trait.BitAnd.html
/// [`BitOr`]: ops/trait.BitOr.html
/// [`Not`]: ops/trait.Not.html
/// .arg("-c")
/// .arg("echo hello")
/// .output()
-/// .expect("failed to execute proces");
+/// .expect("failed to execute process");
///
/// let hello = output.stdout;
/// ```
/// Creates a new mutex in an unlocked state ready for use.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new(t: T) -> Mutex<T> {
- Mutex {
+ let mut m = Mutex {
inner: box StaticMutex::new(),
data: UnsafeCell::new(t),
+ };
+ unsafe {
+ m.inner.lock.init();
}
+ m
}
}
}
})
}
-
- /// Transform this guard to hold a sub-borrow of the original data.
- ///
- /// Applies the supplied closure to the data, returning a new lock
- /// guard referencing the borrow returned by the closure.
- ///
- /// # Examples
- ///
- /// ```rust
- /// # #![feature(guard_map)]
- /// # use std::sync::{RwLockReadGuard, RwLock};
- /// let x = RwLock::new(vec![1, 2]);
- ///
- /// let y = RwLockReadGuard::map(x.read().unwrap(), |v| &v[0]);
- /// assert_eq!(*y, 1);
- /// ```
- #[unstable(feature = "guard_map",
- reason = "recently added, needs RFC for stabilization,
- questionable interaction with Condvar",
- issue = "27746")]
- #[rustc_deprecated(since = "1.8.0",
- reason = "unsound on Mutex because of Condvar and \
- RwLock may also with to be used with Condvar \
- one day")]
- pub fn map<U: ?Sized, F>(this: Self, cb: F) -> RwLockReadGuard<'rwlock, U>
- where F: FnOnce(&T) -> &U
- {
- let new = RwLockReadGuard {
- __lock: this.__lock,
- __data: cb(this.__data)
- };
-
- mem::forget(this);
-
- new
- }
}
#[allow(deprecated)]
}
})
}
-
- /// Transform this guard to hold a sub-borrow of the original data.
- ///
- /// Applies the supplied closure to the data, returning a new lock
- /// guard referencing the borrow returned by the closure.
- ///
- /// # Examples
- ///
- /// ```rust
- /// # #![feature(guard_map)]
- /// # use std::sync::{RwLockWriteGuard, RwLock};
- /// let x = RwLock::new(vec![1, 2]);
- ///
- /// {
- /// let mut y = RwLockWriteGuard::map(x.write().unwrap(), |v| &mut v[0]);
- /// assert_eq!(*y, 1);
- ///
- /// *y = 10;
- /// }
- ///
- /// assert_eq!(&**x.read().unwrap(), &[10, 2]);
- /// ```
- #[unstable(feature = "guard_map",
- reason = "recently added, needs RFC for stabilization,
- questionable interaction with Condvar",
- issue = "27746")]
- #[rustc_deprecated(since = "1.8.0",
- reason = "unsound on Mutex because of Condvar and \
- RwLock may also with to be used with Condvar \
- one day")]
- pub fn map<U: ?Sized, F>(this: Self, cb: F) -> RwLockWriteGuard<'rwlock, U>
- where F: FnOnce(&mut T) -> &mut U
- {
- // Compute the new data while still owning the original lock
- // in order to correctly poison if the callback panics.
- let data = unsafe { ptr::read(&this.__data) };
- let new_data = cb(data);
-
- // We don't want to unlock the lock by running the destructor of the
- // original lock, so just read the fields we need and forget it.
- let (poison, lock) = unsafe {
- (ptr::read(&this.__poison), ptr::read(&this.__lock))
- };
- mem::forget(this);
-
- RwLockWriteGuard {
- __lock: lock,
- __data: new_data,
- __poison: poison
- }
- }
}
#[stable(feature = "rust1", since = "1.0.0")]
use rand::{self, Rng};
use sync::mpsc::channel;
use thread;
- use sync::{Arc, RwLock, StaticRwLock, TryLockError, RwLockWriteGuard};
+ use sync::{Arc, RwLock, StaticRwLock, TryLockError};
use sync::atomic::{AtomicUsize, Ordering};
#[derive(Eq, PartialEq, Debug)]
Ok(x) => panic!("get_mut of poisoned RwLock is Ok: {:?}", x),
}
}
-
- #[test]
- fn test_rwlock_write_map_poison() {
- let rwlock = Arc::new(RwLock::new(vec![1, 2]));
- let rwlock2 = rwlock.clone();
-
- thread::spawn(move || {
- let _ = RwLockWriteGuard::map::<usize, _>(rwlock2.write().unwrap(), |_| panic!());
- }).join().unwrap_err();
-
- match rwlock.read() {
- Ok(r) => panic!("Read lock on poisioned RwLock is Ok: {:?}", &*r),
- Err(_) => {}
- };
- }
}
-
/// first used with any of the functions below.
pub const fn new() -> Mutex { Mutex(imp::Mutex::new()) }
+ /// Prepare the mutex for use.
+ ///
+ /// This should be called once the mutex is at a stable memory address.
+ #[inline]
+ pub unsafe fn init(&mut self) { self.0.init() }
+
/// Locks the mutex blocking the current thread until it is available.
///
/// Behavior is undefined if the mutex has been moved between this and any
// implemented as an illegal instruction.
#[cfg(unix)]
unsafe fn abort_internal() -> ! {
- use libc;
- libc::abort()
+ ::libc::abort()
}
-// On Windows, we want to avoid using libc, and there isn't a direct
-// equivalent of libc::abort. The __failfast intrinsic may be a reasonable
-// substitute, but desireability of using it over the abort instrinsic is
-// debateable; see https://github.com/rust-lang/rust/pull/31519 for details.
-#[cfg(not(unix))]
+// On Windows, use the processor-specific __fastfail mechanism. In Windows 8
+// and later, this will terminate the process immediately without running any
+// in-process exception handlers. In earlier versions of Windows, this
+// sequence of instructions will be treated as an access violation,
+// terminating the process but without necessarily bypassing all exception
+// handlers.
+//
+// https://msdn.microsoft.com/en-us/library/dn774154.aspx
+#[cfg(all(windows, any(target_arch = "x86", target_arch = "x86_64")))]
unsafe fn abort_internal() -> ! {
- use intrinsics;
- intrinsics::abort()
+ asm!("int $$0x29" :: "{ecx}"(7) ::: volatile); // 7 is FAST_FAIL_FATAL_APP_EXIT
+ ::intrinsics::unreachable();
}
+// Other platforms should use the appropriate platform-specific mechanism for
+// aborting the process. If no platform-specific mechanism is available,
+// ::intrinsics::abort() may be used instead. The above implementations cover
+// all targets currently supported by libstd.
+
pub fn abort(args: fmt::Arguments) -> ! {
dumb_print(format_args!("fatal runtime error: {}\n", args));
unsafe { abort_internal(); }
#[stable(feature = "rust1", since = "1.0.0")]
fn gid(&mut self, id: u32) -> &mut process::Command;
- /// Create a new session (cf. `setsid(2)`) for the child process. This means
- /// that the child is the leader of a new process group. The parent process
- /// remains the child reaper of the new process.
- ///
- /// This is not enough to create a daemon process. The *init* process should
- /// be the child reaper of a daemon. This can be achieved if the parent
- /// process exit. Moreover, a daemon should not have a controlling terminal.
- /// To achieve this, a session leader (the child) must spawn another process
- /// (the daemon) in the same session.
- #[unstable(feature = "process_session_leader", reason = "recently added",
- issue = "27811")]
- #[rustc_deprecated(reason = "use `before_exec` instead",
- since = "1.9.0")]
- fn session_leader(&mut self, on: bool) -> &mut process::Command;
-
/// Schedules a closure to be run just before the `exec` function is
/// invoked.
///
self
}
- fn session_leader(&mut self, on: bool) -> &mut process::Command {
- self.as_inner_mut().session_leader(on);
- self
- }
-
fn before_exec<F>(&mut self, f: F) -> &mut process::Command
where F: FnMut() -> io::Result<()> + Send + Sync + 'static
{
Mutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) }
}
#[inline]
+ pub unsafe fn init(&mut self) {
+ // Issue #33770
+ //
+ // A pthread mutex initialized with PTHREAD_MUTEX_INITIALIZER will have
+ // a type of PTHREAD_MUTEX_DEFAULT, which has undefined behavior if you
+ // try to re-lock it from the same thread when you already hold a lock.
+ //
+ // In practice, glibc takes advantage of this undefined behavior to
+ // implement hardware lock elision, which uses hardware transactional
+ // memory to avoid acquiring the lock. While a transaction is in
+ // progress, the lock appears to be unlocked. This isn't a problem for
+ // other threads since the transactional memory will abort if a conflict
+ // is detected, however no abort is generated if re-locking from the
+ // same thread.
+ //
+ // Since locking the same mutex twice will result in two aliasing &mut
+ // references, we instead create the mutex with type
+ // PTHREAD_MUTEX_NORMAL which is guaranteed to deadlock if we try to
+ // re-lock it from the same thread, thus avoiding undefined behavior.
+ //
+ // We can't do anything for StaticMutex, but that type is deprecated
+ // anyways.
+ let mut attr: libc::pthread_mutexattr_t = mem::uninitialized();
+ let r = libc::pthread_mutexattr_init(&mut attr);
+ debug_assert_eq!(r, 0);
+ let r = libc::pthread_mutexattr_settype(&mut attr, libc::PTHREAD_MUTEX_NORMAL);
+ debug_assert_eq!(r, 0);
+ let r = libc::pthread_mutex_init(self.inner.get(), &attr);
+ debug_assert_eq!(r, 0);
+ let r = libc::pthread_mutexattr_destroy(&mut attr);
+ debug_assert_eq!(r, 0);
+ }
+ #[inline]
pub unsafe fn lock(&self) {
let r = libc::pthread_mutex_lock(self.inner.get());
debug_assert_eq!(r, 0);
cwd: Option<CString>,
uid: Option<uid_t>,
gid: Option<gid_t>,
- session_leader: bool,
saw_nul: bool,
closures: Vec<Box<FnMut() -> io::Result<()> + Send + Sync>>,
stdin: Option<Stdio>,
cwd: None,
uid: None,
gid: None,
- session_leader: false,
saw_nul: saw_nul,
closures: Vec::new(),
stdin: None,
pub fn gid(&mut self, id: gid_t) {
self.gid = Some(id);
}
- pub fn session_leader(&mut self, session_leader: bool) {
- self.session_leader = session_leader;
- }
pub fn before_exec(&mut self,
f: Box<FnMut() -> io::Result<()> + Send + Sync>) {
t!(cvt(libc::setuid(u as uid_t)));
}
- if self.session_leader {
- // Don't check the error of setsid because it fails if we're the
- // process leader already. We just forked so it shouldn't return
- // error, but ignore it anyway.
- let _ = libc::setsid();
- }
if let Some(ref cwd) = self.cwd {
t!(cvt(libc::chdir(cwd.as_ptr())));
}
use libc;
use cell::UnsafeCell;
+use sync::atomic::{AtomicUsize, Ordering};
-pub struct RWLock { inner: UnsafeCell<libc::pthread_rwlock_t> }
+pub struct RWLock {
+ inner: UnsafeCell<libc::pthread_rwlock_t>,
+ write_locked: UnsafeCell<bool>,
+ num_readers: AtomicUsize,
+}
unsafe impl Send for RWLock {}
unsafe impl Sync for RWLock {}
impl RWLock {
pub const fn new() -> RWLock {
- RWLock { inner: UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER) }
+ RWLock {
+ inner: UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER),
+ write_locked: UnsafeCell::new(false),
+ num_readers: AtomicUsize::new(0),
+ }
}
#[inline]
pub unsafe fn read(&self) {
//
// We roughly maintain the deadlocking behavior by panicking to ensure
// that this lock acquisition does not succeed.
- if r == libc::EDEADLK {
+ //
+ // We also check whether there this lock is already write locked. This
+ // is only possible if it was write locked by the current thread and
+ // the implementation allows recursive locking. The POSIX standard
+ // doesn't require recursivly locking a rwlock to deadlock, but we can't
+ // allow that because it could lead to aliasing issues.
+ if r == libc::EDEADLK || *self.write_locked.get() {
+ if r == 0 {
+ self.raw_unlock();
+ }
panic!("rwlock read lock would result in deadlock");
} else {
debug_assert_eq!(r, 0);
+ self.num_readers.fetch_add(1, Ordering::Relaxed);
}
}
#[inline]
pub unsafe fn try_read(&self) -> bool {
- libc::pthread_rwlock_tryrdlock(self.inner.get()) == 0
+ let r = libc::pthread_rwlock_tryrdlock(self.inner.get());
+ if r == 0 {
+ if *self.write_locked.get() {
+ self.raw_unlock();
+ false
+ } else {
+ self.num_readers.fetch_add(1, Ordering::Relaxed);
+ true
+ }
+ } else {
+ false
+ }
}
#[inline]
pub unsafe fn write(&self) {
let r = libc::pthread_rwlock_wrlock(self.inner.get());
- // see comments above for why we check for EDEADLK
- if r == libc::EDEADLK {
+ // See comments above for why we check for EDEADLK and write_locked. We
+ // also need to check that num_readers is 0.
+ if r == libc::EDEADLK || *self.write_locked.get() ||
+ self.num_readers.load(Ordering::Relaxed) != 0 {
+ if r == 0 {
+ self.raw_unlock();
+ }
panic!("rwlock write lock would result in deadlock");
} else {
debug_assert_eq!(r, 0);
}
+ *self.write_locked.get() = true;
}
#[inline]
pub unsafe fn try_write(&self) -> bool {
- libc::pthread_rwlock_trywrlock(self.inner.get()) == 0
+ let r = libc::pthread_rwlock_trywrlock(self.inner.get());
+ if r == 0 {
+ if *self.write_locked.get() || self.num_readers.load(Ordering::Relaxed) != 0 {
+ self.raw_unlock();
+ false
+ } else {
+ *self.write_locked.get() = true;
+ true
+ }
+ } else {
+ false
+ }
}
#[inline]
- pub unsafe fn read_unlock(&self) {
+ unsafe fn raw_unlock(&self) {
let r = libc::pthread_rwlock_unlock(self.inner.get());
debug_assert_eq!(r, 0);
}
#[inline]
- pub unsafe fn write_unlock(&self) { self.read_unlock() }
+ pub unsafe fn read_unlock(&self) {
+ debug_assert!(!*self.write_locked.get());
+ self.num_readers.fetch_sub(1, Ordering::Relaxed);
+ self.raw_unlock();
+ }
+ #[inline]
+ pub unsafe fn write_unlock(&self) {
+ debug_assert_eq!(self.num_readers.load(Ordering::Relaxed), 0);
+ debug_assert!(*self.write_locked.get());
+ *self.write_locked.get() = false;
+ self.raw_unlock();
+ }
#[inline]
pub unsafe fn destroy(&self) {
let r = libc::pthread_rwlock_destroy(self.inner.get());
held: UnsafeCell::new(false),
}
}
+ #[inline]
+ pub unsafe fn init(&mut self) {}
pub unsafe fn lock(&self) {
match kind() {
Kind::SRWLock => c::AcquireSRWLockExclusive(raw(self)),
////////////////////////////////////////////////////////////////////////////////
#[macro_use] mod local;
-#[macro_use] mod scoped_tls;
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::local::{LocalKey, LocalKeyState};
-#[unstable(feature = "scoped_tls",
- reason = "scoped TLS has yet to have wide enough use to fully \
- consider stabilizing its interface",
- issue = "27715")]
-#[allow(deprecated)]
-pub use self::scoped_tls::ScopedKey;
-
#[unstable(feature = "libstd_thread_internals", issue = "0")]
#[cfg(target_thread_local)]
#[doc(hidden)] pub use self::local::elf::Key as __ElfLocalKeyInner;
#[unstable(feature = "libstd_thread_internals", issue = "0")]
#[doc(hidden)] pub use self::local::os::Key as __OsLocalKeyInner;
-#[unstable(feature = "libstd_thread_internals", issue = "0")]
-#[doc(hidden)] pub use self::scoped_tls::__KeyInner as __ScopedKeyInner;
////////////////////////////////////////////////////////////////////////////////
// Builder
+++ /dev/null
-// Copyright 2014-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.
-
-//! Scoped thread-local storage
-//!
-//! This module provides the ability to generate *scoped* thread-local
-//! variables. In this sense, scoped indicates that thread local storage
-//! actually stores a reference to a value, and this reference is only placed
-//! in storage for a scoped amount of time.
-//!
-//! There are no restrictions on what types can be placed into a scoped
-//! variable, but all scoped variables are initialized to the equivalent of
-//! null. Scoped thread local storage is useful when a value is present for a known
-//! period of time and it is not required to relinquish ownership of the
-//! contents.
-//!
-//! # Examples
-//!
-//! ```
-//! #![feature(scoped_tls)]
-//!
-//! scoped_thread_local!(static FOO: u32);
-//!
-//! // Initially each scoped slot is empty.
-//! assert!(!FOO.is_set());
-//!
-//! // When inserting a value, the value is only in place for the duration
-//! // of the closure specified.
-//! FOO.set(&1, || {
-//! FOO.with(|slot| {
-//! assert_eq!(*slot, 1);
-//! });
-//! });
-//! ```
-
-#![unstable(feature = "thread_local_internals", issue = "0")]
-#![allow(deprecated)]
-
-#[doc(hidden)]
-pub use self::imp::KeyInner as __KeyInner;
-
-/// Type representing a thread local storage key corresponding to a reference
-/// to the type parameter `T`.
-///
-/// Keys are statically allocated and can contain a reference to an instance of
-/// type `T` scoped to a particular lifetime. Keys provides two methods, `set`
-/// and `with`, both of which currently use closures to control the scope of
-/// their contents.
-#[unstable(feature = "scoped_tls",
- reason = "scoped TLS has yet to have wide enough use to fully consider \
- stabilizing its interface",
- issue = "27715")]
-#[rustc_deprecated(since = "1.8.0",
- reason = "hasn't proven itself over LocalKey")]
-pub struct ScopedKey<T:'static> { inner: fn() -> &'static imp::KeyInner<T> }
-
-/// Declare a new scoped thread local storage key.
-///
-/// This macro declares a `static` item on which methods are used to get and
-/// set the value stored within.
-///
-/// See [ScopedKey documentation](thread/struct.ScopedKey.html) for more
-/// information.
-#[unstable(feature = "thread_local_internals",
- reason = "should not be necessary",
- issue = "0")]
-#[rustc_deprecated(since = "1.8.0",
- reason = "hasn't proven itself over LocalKey")]
-#[macro_export]
-#[allow_internal_unstable]
-macro_rules! scoped_thread_local {
- (static $name:ident: $t:ty) => (
- static $name: $crate::thread::ScopedKey<$t> =
- __scoped_thread_local_inner!($t);
- );
- (pub static $name:ident: $t:ty) => (
- pub static $name: $crate::thread::ScopedKey<$t> =
- __scoped_thread_local_inner!($t);
- );
-}
-
-#[doc(hidden)]
-#[unstable(feature = "thread_local_internals",
- reason = "should not be necessary",
- issue = "0")]
-#[rustc_deprecated(since = "1.8.0",
- reason = "hasn't proven itself over LocalKey")]
-#[macro_export]
-#[allow_internal_unstable]
-macro_rules! __scoped_thread_local_inner {
- ($t:ty) => {{
- #[cfg_attr(target_thread_local, thread_local)]
- static _KEY: $crate::thread::__ScopedKeyInner<$t> =
- $crate::thread::__ScopedKeyInner::new();
- fn _getit() -> &'static $crate::thread::__ScopedKeyInner<$t> { &_KEY }
- $crate::thread::ScopedKey::new(_getit)
- }}
-}
-
-#[unstable(feature = "scoped_tls",
- reason = "scoped TLS has yet to have wide enough use to fully consider \
- stabilizing its interface",
- issue = "27715")]
-#[rustc_deprecated(since = "1.8.0",
- reason = "hasn't proven itself over LocalKey")]
-impl<T> ScopedKey<T> {
- #[doc(hidden)]
- pub const fn new(inner: fn() -> &'static imp::KeyInner<T>) -> ScopedKey<T> {
- ScopedKey { inner: inner }
- }
-
- /// Inserts a value into this scoped thread local storage slot for a
- /// duration of a closure.
- ///
- /// While `cb` is running, the value `t` will be returned by `get` unless
- /// this function is called recursively inside of `cb`.
- ///
- /// Upon return, this function will restore the previous value, if any
- /// was available.
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(scoped_tls)]
- ///
- /// scoped_thread_local!(static FOO: u32);
- ///
- /// FOO.set(&100, || {
- /// let val = FOO.with(|v| *v);
- /// assert_eq!(val, 100);
- ///
- /// // set can be called recursively
- /// FOO.set(&101, || {
- /// // ...
- /// });
- ///
- /// // Recursive calls restore the previous value.
- /// let val = FOO.with(|v| *v);
- /// assert_eq!(val, 100);
- /// });
- /// ```
- pub fn set<R, F>(&'static self, t: &T, cb: F) -> R where
- F: FnOnce() -> R,
- {
- struct Reset<'a, T: 'a> {
- key: &'a imp::KeyInner<T>,
- val: *mut T,
- }
- impl<'a, T> Drop for Reset<'a, T> {
- fn drop(&mut self) {
- unsafe { self.key.set(self.val) }
- }
- }
-
- let inner = (self.inner)();
- let prev = unsafe {
- let prev = inner.get();
- inner.set(t as *const T as *mut T);
- prev
- };
-
- let _reset = Reset { key: inner, val: prev };
- cb()
- }
-
- /// Gets a value out of this scoped variable.
- ///
- /// This function takes a closure which receives the value of this
- /// variable.
- ///
- /// # Panics
- ///
- /// This function will panic if `set` has not previously been called.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// #![feature(scoped_tls)]
- ///
- /// scoped_thread_local!(static FOO: u32);
- ///
- /// FOO.with(|slot| {
- /// // work with `slot`
- /// });
- /// ```
- pub fn with<R, F>(&'static self, cb: F) -> R where
- F: FnOnce(&T) -> R
- {
- unsafe {
- let ptr = (self.inner)().get();
- assert!(!ptr.is_null(), "cannot access a scoped thread local \
- variable without calling `set` first");
- cb(&*ptr)
- }
- }
-
- /// Test whether this TLS key has been `set` for the current thread.
- pub fn is_set(&'static self) -> bool {
- unsafe { !(self.inner)().get().is_null() }
- }
-}
-
-#[cfg(target_thread_local)]
-#[doc(hidden)]
-mod imp {
- use cell::Cell;
- use ptr;
-
- pub struct KeyInner<T> { inner: Cell<*mut T> }
-
- unsafe impl<T> ::marker::Sync for KeyInner<T> { }
-
- impl<T> KeyInner<T> {
- pub const fn new() -> KeyInner<T> {
- KeyInner { inner: Cell::new(ptr::null_mut()) }
- }
- pub unsafe fn set(&self, ptr: *mut T) { self.inner.set(ptr); }
- pub unsafe fn get(&self) -> *mut T { self.inner.get() }
- }
-}
-
-#[cfg(not(target_thread_local))]
-#[doc(hidden)]
-mod imp {
- use cell::Cell;
- use marker;
- use sys_common::thread_local::StaticKey as OsStaticKey;
-
- pub struct KeyInner<T> {
- pub inner: OsStaticKey,
- pub marker: marker::PhantomData<Cell<T>>,
- }
-
- unsafe impl<T> marker::Sync for KeyInner<T> { }
-
- impl<T> KeyInner<T> {
- pub const fn new() -> KeyInner<T> {
- KeyInner {
- inner: OsStaticKey::new(None),
- marker: marker::PhantomData
- }
- }
- pub unsafe fn set(&self, ptr: *mut T) { self.inner.set(ptr as *mut _) }
- pub unsafe fn get(&self) -> *mut T { self.inner.get() as *mut _ }
- }
-}
-
-
-#[cfg(test)]
-mod tests {
- use cell::Cell;
-
- scoped_thread_local!(static FOO: u32);
-
- #[test]
- fn smoke() {
- scoped_thread_local!(static BAR: u32);
-
- assert!(!BAR.is_set());
- BAR.set(&1, || {
- assert!(BAR.is_set());
- BAR.with(|slot| {
- assert_eq!(*slot, 1);
- });
- });
- assert!(!BAR.is_set());
- }
-
- #[test]
- fn cell_allowed() {
- scoped_thread_local!(static BAR: Cell<u32>);
-
- BAR.set(&Cell::new(1), || {
- BAR.with(|slot| {
- assert_eq!(slot.get(), 1);
- });
- });
- }
-
- #[test]
- fn scope_item_allowed() {
- assert!(!FOO.is_set());
- FOO.set(&1, || {
- assert!(FOO.is_set());
- FOO.with(|slot| {
- assert_eq!(*slot, 1);
- });
- });
- assert!(!FOO.is_set());
- }
-}
self.0.sub_instant(&earlier.0)
}
- /// Deprecated, renamed to `duration_since`
- #[unstable(feature = "time2_old", issue = "29866")]
- #[rustc_deprecated(since = "1.8.0", reason = "renamed to duration_since")]
- pub fn duration_from_earlier(&self, earlier: Instant) -> Duration {
- self.0.sub_instant(&earlier.0)
- }
-
/// Returns the amount of time elapsed since this instant was created.
///
/// # Panics
self.0.sub_time(&earlier.0).map_err(SystemTimeError)
}
- /// Deprecated, renamed to `duration_since`
- #[unstable(feature = "time2_old", issue = "29866")]
- #[rustc_deprecated(since = "1.8.0", reason = "renamed to duration_since")]
- pub fn duration_from_earlier(&self, earlier: SystemTime)
- -> Result<Duration, SystemTimeError> {
- self.0.sub_time(&earlier.0).map_err(SystemTimeError)
- }
-
/// Returns the amount of time elapsed since this system time was created.
///
/// This function may fail as the underlying system clock is susceptible to
-Subproject commit 4638c60dedfa581fd5fa7c6420d8f32274c9ca0b
+Subproject commit a3736a0a1907cbc8bf619708738815a5fd789c80
--- /dev/null
+// Copyright 2016 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.
+
+struct Irrefutable(i32);
+
+fn main() {
+ let irr = Irrefutable(0);
+ if let Irrefutable(x) = irr { //~ ERROR E0162
+ println!("{}", x);
+ }
+}
--- /dev/null
+// Copyright 2016 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.
+
+enum Foo { B(u32) }
+
+fn bar(foo: Foo) -> u32 {
+ match foo {
+ Foo::B { i } => i, //~ ERROR E0163
+ }
+}
+
+fn main() {
+}
--- /dev/null
+// Copyright 2016 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.
+
+enum Foo { B { i: u32 } }
+
+fn bar(foo: Foo) -> u32 {
+ match foo {
+ Foo::B(i) => i, //~ ERROR E0164
+ }
+}
+
+fn main() {
+}
--- /dev/null
+// Copyright 2016 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.
+
+struct Irrefutable(i32);
+
+fn main() {
+ let irr = Irrefutable(0);
+ while let Irrefutable(x) = irr { //~ ERROR E0165
+ // ...
+ }
+}
--- /dev/null
+// Copyright 2016 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.
+
+fn foo() -> ! { return; } //~ ERROR E0166
+
+fn main() {
+}
--- /dev/null
+// Copyright 2016 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.
+
+fn foo(bar: i32+std::fmt::Display) {} //~ ERROR E0172
+
+fn main() {
+}
--- /dev/null
+// Copyright 2016 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.
+
+trait Foo {}
+
+struct Bar<'a> {
+ w: &'a Foo + Copy, //~ ERROR E0178
+ x: &'a Foo + 'a, //~ ERROR E0178
+ y: &'a mut Foo + 'a, //~ ERROR E0178
+ z: fn() -> Foo + 'a, //~ ERROR E0178
+}
+
+fn main() {
+}
--- /dev/null
+// Copyright 2016 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.
+
+#[derive(Copy)] //~ ERROR E0184
+struct Foo;
+
+impl Drop for Foo {
+ fn drop(&mut self) {
+ }
+}
+
+fn main() {
+}
--- /dev/null
+// Copyright 2016 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.
+
+trait Foo {
+ fn foo();
+}
+
+struct Bar;
+
+impl Foo for Bar {
+ fn foo(&self) {} //~ ERROR E0185
+}
+
+fn main() {
+}
--- /dev/null
+// Copyright 2016 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.
+
+trait Foo {
+ fn foo(&self);
+}
+
+struct Bar;
+
+impl Foo for Bar {
+ fn foo() {} //~ ERROR E0186
+}
+
+fn main() {
+}
--- /dev/null
+// Copyright 2016 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.
+
+trait Trait {
+ type Bar;
+}
+
+type Foo = Trait; //~ ERROR E0191
+
+fn main() {
+}
--- /dev/null
+// Copyright 2016 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(optin_builtin_traits)]
+
+trait Trait {
+ type Bar;
+}
+
+struct Foo;
+
+impl !Trait for Foo { } //~ ERROR E0192
+
+fn main() {
+}
--- /dev/null
+// Copyright 2016 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.
+
+trait Foo<T> {
+ fn do_something(&self) -> T;
+ fn do_something_else<T: Clone>(&self, bar: T); //~ ERROR E0194
+}
+
+fn main() {
+}
--- /dev/null
+// Copyright 2016 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.
+
+trait Trait {
+ fn bar<'a,'b:'a>(x: &'a str, y: &'b str);
+}
+
+struct Foo;
+
+impl Trait for Foo {
+ fn bar<'a,'b>(x: &'a str, y: &'b str) { //~ ERROR E0195
+ }
+}
+
+fn main() {
+}
--- /dev/null
+// Copyright 2016 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.
+
+struct Foo;
+
+unsafe impl Foo { } //~ ERROR E0197
+
+fn main() {
+}
--- /dev/null
+// Copyright 2016 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(optin_builtin_traits)]
+
+struct Foo;
+
+unsafe impl !Clone for Foo { } //~ ERROR E0199
+
+fn main() {
+}
--- /dev/null
+// Copyright 2016 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.
+
+struct Foo;
+
+unsafe trait Bar { }
+
+impl Bar for Foo { } //~ ERROR E0200
+
+fn main() {
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::raw::Slice;
+struct Slice<T> {
+ data: *const T,
+ len: usize,
+}
fn main() {
let Slice { data: data, len: len } = "foo";
//~^ ERROR mismatched types
//~| expected type `&str`
- //~| found type `std::raw::Slice<_>`
- //~| expected &-ptr, found struct `std::raw::Slice`
+ //~| found type `Slice<_>`
+ //~| expected &-ptr, found struct `Slice`
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::raw::Slice;
+struct Slice<T> {
+ data: *const T,
+ len: usize,
+}
fn main() {
match () {
Slice { data: data, len: len } => (),
//~^ ERROR mismatched types
//~| expected type `()`
- //~| found type `std::raw::Slice<_>`
- //~| expected (), found struct `std::raw::Slice`
+ //~| found type `Slice<_>`
+ //~| expected (), found struct `Slice`
_ => unreachable!()
}
}
fn main() {
self += 1;
//~^ ERROR: unresolved name `self`
- //~| HELP: Module
+ //~| HELP: module `self`
// it's a bug if this suggests a missing `self` as we're not in a method
}
--- /dev/null
+// Copyright 2016 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(reflect_marker)]
+
+use std::marker::Reflect;
+use std::any::Any;
+
+struct Foo;
+
+trait Bar {}
+
+impl Bar for Foo {}
+
+fn main() {
+ let any: &Any = &Bar; //~ ERROR E0425
+ //~| HELP trait `Bar`
+ if any.is::<u32>() { println!("u32"); }
+}
// except according to those terms.
#![allow(dead_code)]
-#![feature(recover)]
-use std::panic::RecoverSafe;
+use std::panic::UnwindSafe;
use std::rc::Rc;
use std::cell::RefCell;
-fn assert<T: RecoverSafe + ?Sized>() {}
+fn assert<T: UnwindSafe + ?Sized>() {}
fn main() {
assert::<Rc<RefCell<i32>>>();
// except according to those terms.
#![allow(dead_code)]
-#![feature(recover)]
-use std::panic::RecoverSafe;
+use std::panic::UnwindSafe;
use std::sync::Arc;
use std::cell::RefCell;
-fn assert<T: RecoverSafe + ?Sized>() {}
+fn assert<T: UnwindSafe + ?Sized>() {}
fn main() {
assert::<Arc<RefCell<i32>>>();
// except according to those terms.
#![allow(dead_code)]
-#![feature(recover)]
-use std::panic::RecoverSafe;
+use std::panic::UnwindSafe;
use std::cell::RefCell;
-fn assert<T: RecoverSafe + ?Sized>() {}
+fn assert<T: UnwindSafe + ?Sized>() {}
fn main() {
assert::<&RefCell<i32>>();
// except according to those terms.
#![allow(dead_code)]
-#![feature(recover)]
-use std::panic::RecoverSafe;
+use std::panic::UnwindSafe;
use std::cell::UnsafeCell;
-fn assert<T: RecoverSafe + ?Sized>() {}
+fn assert<T: UnwindSafe + ?Sized>() {}
fn main() {
assert::<*const UnsafeCell<i32>>(); //~ ERROR E0277
// except according to those terms.
#![allow(dead_code)]
-#![feature(recover)]
-use std::panic::RecoverSafe;
+use std::panic::UnwindSafe;
use std::cell::RefCell;
-fn assert<T: RecoverSafe + ?Sized>() {}
+fn assert<T: UnwindSafe + ?Sized>() {}
fn main() {
assert::<*mut RefCell<i32>>();
fn h1() -> i32 {
a.I
//~^ ERROR E0425
- //~| HELP To reference an item from the `a` module, use `a::I`
+ //~| HELP to reference an item from the `a` module, use `a::I`
}
fn h2() -> i32 {
a.g()
//~^ ERROR E0425
- //~| HELP To call a function from the `a` module, use `a::g(..)`
+ //~| HELP to call a function from the `a` module, use `a::g(..)`
}
fn h3() -> i32 {
a.b.J
//~^ ERROR E0425
- //~| HELP To reference an item from the `a` module, use `a::b`
+ //~| HELP to reference an item from the `a` module, use `a::b`
}
fn h4() -> i32 {
a::b.J
//~^ ERROR E0425
- //~| HELP To reference an item from the `a::b` module, use `a::b::J`
+ //~| HELP to reference an item from the `a::b` module, use `a::b::J`
}
fn h5() {
a.b.f();
//~^ ERROR E0425
- //~| HELP To reference an item from the `a` module, use `a::b`
+ //~| HELP to reference an item from the `a` module, use `a::b`
let v = Vec::new();
v.push(a::b);
//~^ ERROR E0425
- //~| HELP Module `a::b` cannot be used as an expression
+ //~| HELP module `a::b` cannot be used as an expression
}
fn h6() -> i32 {
a::b.f()
//~^ ERROR E0425
- //~| HELP To call a function from the `a::b` module, use `a::b::f(..)`
+ //~| HELP to call a function from the `a::b` module, use `a::b::f(..)`
}
fn h7() {
a::b
//~^ ERROR E0425
- //~| HELP Module `a::b` cannot be used as an expression
+ //~| HELP module `a::b` cannot be used as an expression
}
fn h8() -> i32 {
a::b()
//~^ ERROR E0425
- //~| HELP Module `a::b` cannot be used as an expression
+ //~| HELP module `a::b` cannot be used as an expression
}
// error-pattern:greetings from the panic handler
-#![feature(std_panic, panic_handler)]
+#![feature(panic_handler)]
+
use std::panic;
use std::io::{self, Write};
fn main() {
- panic::set_handler(|i| {
+ panic::set_hook(Box::new(|i| {
write!(io::stderr(), "greetings from the panic handler");
- });
+ }));
panic!("foobar");
}
// error-pattern:thread '<main>' panicked at 'foobar'
-#![feature(std_panic, panic_handler)]
+#![feature(panic_handler)]
+
use std::panic;
use std::io::{self, Write};
fn main() {
- panic::set_handler(|i| {
+ panic::set_hook(Box::new(|i| {
write!(io::stderr(), "greetings from the panic handler");
- });
- panic::take_handler();
+ }));
+ panic::take_hook();
panic!("foobar");
}
// error-pattern:thread '<main>' panicked at 'foobar'
-#![feature(std_panic, panic_handler)]
+#![feature(panic_handler)]
+
use std::panic;
fn main() {
- panic::take_handler();
+ panic::take_hook();
panic!("foobar");
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(recover, rand, std_panic)]
+#![feature(rand, std_panic)]
use std::__rand::{thread_rng, Rng};
-use std::panic::{self, AssertRecoverSafe};
+use std::panic::{self, AssertUnwindSafe};
use std::collections::BinaryHeap;
use std::cmp;
{
// push the panicking item to the heap and catch the panic
let thread_result = {
- let mut heap_ref = AssertRecoverSafe(&mut heap);
- panic::recover(move || {
+ let mut heap_ref = AssertUnwindSafe(&mut heap);
+ panic::catch_unwind(move || {
heap_ref.push(panic_item);
})
};
--- /dev/null
+// Copyright 2016 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.
+
+// Issue #33540
+// We previously used to generate a 3-armed boolean `SwitchInt` in the
+// MIR of the function `foo` below. #33583 changed rustc to
+// generate an `If` terminator instead. This test is to just ensure
+// sanity in that we generate an if-else chain giving the correct
+// results.
+
+#![feature(rustc_attrs)]
+
+#[rustc_mir]
+fn foo(x: bool, y: bool) -> u32 {
+ match (x, y) {
+ (false, _) => 0,
+ (_, false) => 1,
+ (true, true) => 2
+ }
+}
+
+fn main() {
+ assert_eq!(foo(false, true), 0);
+ assert_eq!(foo(false, false), 0);
+ assert_eq!(foo(true, false), 1);
+ assert_eq!(foo(true, true), 2);
+}
--- /dev/null
+// Copyright 2016 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.
+
+use std::process::{Command, Stdio};
+use std::env;
+use std::sync::{Mutex, RwLock};
+use std::time::Duration;
+use std::thread;
+
+fn test_mutex() {
+ let m = Mutex::new(0);
+ let _g = m.lock().unwrap();
+ let _g2 = m.lock().unwrap();
+}
+
+fn test_try_mutex() {
+ let m = Mutex::new(0);
+ let _g = m.lock().unwrap();
+ let _g2 = m.try_lock().unwrap();
+}
+
+fn test_rwlock_ww() {
+ let m = RwLock::new(0);
+ let _g = m.write().unwrap();
+ let _g2 = m.write().unwrap();
+}
+
+fn test_try_rwlock_ww() {
+ let m = RwLock::new(0);
+ let _g = m.write().unwrap();
+ let _g2 = m.try_write().unwrap();
+}
+
+fn test_rwlock_rw() {
+ let m = RwLock::new(0);
+ let _g = m.read().unwrap();
+ let _g2 = m.write().unwrap();
+}
+
+fn test_try_rwlock_rw() {
+ let m = RwLock::new(0);
+ let _g = m.read().unwrap();
+ let _g2 = m.try_write().unwrap();
+}
+
+fn test_rwlock_wr() {
+ let m = RwLock::new(0);
+ let _g = m.write().unwrap();
+ let _g2 = m.read().unwrap();
+}
+
+fn test_try_rwlock_wr() {
+ let m = RwLock::new(0);
+ let _g = m.write().unwrap();
+ let _g2 = m.try_read().unwrap();
+}
+
+fn main() {
+ let args: Vec<String> = env::args().collect();
+ if args.len() > 1 {
+ match &*args[1] {
+ "mutex" => test_mutex(),
+ "try_mutex" => test_try_mutex(),
+ "rwlock_ww" => test_rwlock_ww(),
+ "try_rwlock_ww" => test_try_rwlock_ww(),
+ "rwlock_rw" => test_rwlock_rw(),
+ "try_rwlock_rw" => test_try_rwlock_rw(),
+ "rwlock_wr" => test_rwlock_wr(),
+ "try_rwlock_wr" => test_try_rwlock_wr(),
+ _ => unreachable!(),
+ }
+ // If we reach this point then the test failed
+ println!("TEST FAILED: {}", args[1]);
+ } else {
+ let mut v = vec![];
+ v.push(Command::new(&args[0]).arg("mutex").stderr(Stdio::null()).spawn().unwrap());
+ v.push(Command::new(&args[0]).arg("try_mutex").stderr(Stdio::null()).spawn().unwrap());
+ v.push(Command::new(&args[0]).arg("rwlock_ww").stderr(Stdio::null()).spawn().unwrap());
+ v.push(Command::new(&args[0]).arg("try_rwlock_ww").stderr(Stdio::null()).spawn().unwrap());
+ v.push(Command::new(&args[0]).arg("rwlock_rw").stderr(Stdio::null()).spawn().unwrap());
+ v.push(Command::new(&args[0]).arg("try_rwlock_rw").stderr(Stdio::null()).spawn().unwrap());
+ v.push(Command::new(&args[0]).arg("rwlock_wr").stderr(Stdio::null()).spawn().unwrap());
+ v.push(Command::new(&args[0]).arg("try_rwlock_wr").stderr(Stdio::null()).spawn().unwrap());
+
+ thread::sleep(Duration::new(1, 0));
+
+ // Make sure all subprocesses either panicked or were killed because they deadlocked
+ for mut c in v {
+ c.kill().ok();
+ assert!(!c.wait().unwrap().success());
+ }
+ }
+}
// ignore-emscripten no threads support
-#![feature(std_panic, recover, panic_propagate, panic_handler, const_fn)]
+#![feature(panic_handler)]
-use std::sync::atomic::{AtomicUsize, Ordering};
+use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
use std::panic;
use std::thread;
-static A: AtomicUsize = AtomicUsize::new(0);
+static A: AtomicUsize = ATOMIC_USIZE_INIT;
fn main() {
- panic::set_handler(|_| {
+ panic::set_hook(Box::new(|_| {
A.fetch_add(1, Ordering::SeqCst);
- });
+ }));
let result = thread::spawn(|| {
- let result = panic::recover(|| {
+ let result = panic::catch_unwind(|| {
panic!("hi there");
});
- panic::propagate(result.unwrap_err());
+ panic::resume_unwind(result.unwrap_err());
}).join();
let msg = *result.unwrap_err().downcast::<&'static str>().unwrap();
// aux-build:reachable-unnameable-items.rs
-#![feature(recover)]
-
extern crate reachable_unnameable_items;
use reachable_unnameable_items::*;
let none = None;
function_accepting_unnameable_type(none);
- let _guard = std::panic::recover(|| none.unwrap().method_of_unnameable_type3());
+ let _guard = std::panic::catch_unwind(|| none.unwrap().method_of_unnameable_type3());
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(std_panic, recover, start)]
+#![feature(start)]
use std::ffi::CStr;
use std::process::{Command, Output};
match **argv.offset(1) as char {
'1' => {}
'2' => println!("foo"),
- '3' => assert!(panic::recover(|| {}).is_ok()),
- '4' => assert!(panic::recover(|| panic!()).is_err()),
+ '3' => assert!(panic::catch_unwind(|| {}).is_ok()),
+ '4' => assert!(panic::catch_unwind(|| panic!()).is_err()),
'5' => assert!(Command::new("test").spawn().is_err()),
_ => panic!()
}
assert_eq!(s.chars().count(), 4);
assert_eq!(schs.len(), 4);
assert_eq!(schs.iter().cloned().collect::<String>(), s);
- assert_eq!(s.char_at(0), 'e');
- assert_eq!(s.char_at(1), 'é');
assert!((str::from_utf8(s.as_bytes()).is_ok()));
// invalid prefix
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-msvc -- sprintf isn't a symbol in msvcrt? maybe a #define?
-
-#![feature(libc, std_misc)]
-
-extern crate libc;
-
-use std::ffi::{CStr, CString};
-use libc::{c_char, c_int};
-
-
+#[link(name = "rust_test_helpers")]
extern {
- fn sprintf(s: *mut c_char, format: *const c_char, ...) -> c_int;
-}
-
-unsafe fn check<T, F>(expected: &str, f: F) where F: FnOnce(*mut c_char) -> T {
- let mut x = [0 as c_char; 50];
- f(&mut x[0] as *mut c_char);
- assert_eq!(expected.as_bytes(), CStr::from_ptr(x.as_ptr()).to_bytes());
+ fn rust_interesting_average(_: u64, ...) -> f64;
}
pub fn main() {
-
+ // Call without variadic arguments
unsafe {
- // Call with just the named parameter
- let c = CString::new(&b"Hello World\n"[..]).unwrap();
- check("Hello World\n", |s| sprintf(s, c.as_ptr()));
-
- // Call with variable number of arguments
- let c = CString::new(&b"%d %f %c %s\n"[..]).unwrap();
- check("42 42.500000 a %d %f %c %s\n\n", |s| {
- sprintf(s, c.as_ptr(), 42, 42.5f64, 'a' as c_int, c.as_ptr());
- });
+ assert!(rust_interesting_average(0).is_nan());
+ }
- // Make a function pointer
- let x: unsafe extern fn(*mut c_char, *const c_char, ...) -> c_int = sprintf;
+ // Call with direct arguments
+ unsafe {
+ assert_eq!(rust_interesting_average(1, 10i64, 10.0f64) as i64, 20);
+ }
- // A function that takes a function pointer
- unsafe fn call(fp: unsafe extern fn(*mut c_char, *const c_char, ...) -> c_int) {
- // Call with just the named parameter
- let c = CString::new(&b"Hello World\n"[..]).unwrap();
- check("Hello World\n", |s| fp(s, c.as_ptr()));
+ // Call with named arguments, variable number of them
+ let (x1, x2, x3, x4) = (10i64, 10.0f64, 20i64, 20.0f64);
+ unsafe {
+ assert_eq!(rust_interesting_average(2, x1, x2, x3, x4) as i64, 30);
+ }
- // Call with variable number of arguments
- let c = CString::new(&b"%d %f %c %s\n"[..]).unwrap();
- check("42 42.500000 a %d %f %c %s\n\n", |s| {
- fp(s, c.as_ptr(), 42, 42.5f64, 'a' as c_int, c.as_ptr());
- });
- }
+ // A function that takes a function pointer
+ unsafe fn call(fp: unsafe extern fn(u64, ...) -> f64) {
+ let (x1, x2, x3, x4) = (10i64, 10.0f64, 20i64, 20.0f64);
+ assert_eq!(fp(2, x1, x2, x3, x4) as i64, 30);
+ }
- // Pass sprintf directly
- call(sprintf);
+ unsafe {
+ call(rust_interesting_average);
- // Pass sprintf indirectly
+ // Make a function pointer, pass indirectly
+ let x: unsafe extern fn(u64, ...) -> f64 = rust_interesting_average;
call(x);
}
-
}