Auto merge of #46312 - kennytm:rollup, r=kennytm
Rollup of 10 pull requests - Successful merges: #45506, #46174, #46231, #46240, #46249, #46258, #46262, #46275, #46282, #46285 - Failed merges:
This commit is contained in:
commit
b087a991fc
|
@ -1,41 +0,0 @@
|
|||
# `hint_core_should_pause`
|
||||
|
||||
The tracking issue for this feature is: [#41196]
|
||||
|
||||
[#41196]: https://github.com/rust-lang/rust/issues/41196
|
||||
|
||||
------------------------
|
||||
|
||||
Many programs have spin loops like the following:
|
||||
|
||||
```rust,no_run
|
||||
use std::sync::atomic::{AtomicBool,Ordering};
|
||||
|
||||
fn spin_loop(value: &AtomicBool) {
|
||||
loop {
|
||||
if value.load(Ordering::Acquire) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
These programs can be improved in performance like so:
|
||||
|
||||
```rust,no_run
|
||||
#![feature(hint_core_should_pause)]
|
||||
use std::sync::atomic;
|
||||
use std::sync::atomic::{AtomicBool,Ordering};
|
||||
|
||||
fn spin_loop(value: &AtomicBool) {
|
||||
loop {
|
||||
if value.load(Ordering::Acquire) {
|
||||
break;
|
||||
}
|
||||
atomic::hint_core_should_pause();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Further improvements could combine `hint_core_should_pause` with
|
||||
exponential backoff or `std::thread::yield_now`.
|
|
@ -220,6 +220,28 @@ impl<T> LinkedList<T> {
|
|||
node
|
||||
})
|
||||
}
|
||||
|
||||
/// Unlinks the specified node from the current list.
|
||||
///
|
||||
/// Warning: this will not check that the provided node belongs to the current list.
|
||||
#[inline]
|
||||
unsafe fn unlink_node(&mut self, mut node: Shared<Node<T>>) {
|
||||
let node = node.as_mut();
|
||||
|
||||
match node.prev {
|
||||
Some(mut prev) => prev.as_mut().next = node.next.clone(),
|
||||
// this node is the head node
|
||||
None => self.head = node.next.clone(),
|
||||
};
|
||||
|
||||
match node.next {
|
||||
Some(mut next) => next.as_mut().prev = node.prev.clone(),
|
||||
// this node is the tail node
|
||||
None => self.tail = node.prev.clone(),
|
||||
};
|
||||
|
||||
self.len -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
@ -722,6 +744,49 @@ impl<T> LinkedList<T> {
|
|||
second_part
|
||||
}
|
||||
|
||||
/// Creates an iterator which uses a closure to determine if an element should be removed.
|
||||
///
|
||||
/// If the closure returns true, then the element is removed and yielded.
|
||||
/// If the closure returns false, it will try again, and call the closure on the next element,
|
||||
/// seeing if it passes the test.
|
||||
///
|
||||
/// Note that `drain_filter` lets you mutate every element in the filter closure, regardless of
|
||||
/// whether you choose to keep or remove it.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Splitting a list into evens and odds, reusing the original list:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(drain_filter)]
|
||||
/// use std::collections::LinkedList;
|
||||
///
|
||||
/// let mut numbers: LinkedList<u32> = LinkedList::new();
|
||||
/// numbers.extend(&[1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15]);
|
||||
///
|
||||
/// let evens = numbers.drain_filter(|x| *x % 2 == 0).collect::<LinkedList<_>>();
|
||||
/// let odds = numbers;
|
||||
///
|
||||
/// assert_eq!(evens.into_iter().collect::<Vec<_>>(), vec![2, 4, 6, 8, 14]);
|
||||
/// assert_eq!(odds.into_iter().collect::<Vec<_>>(), vec![1, 3, 5, 9, 11, 13, 15]);
|
||||
/// ```
|
||||
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
|
||||
pub fn drain_filter<F>(&mut self, filter: F) -> DrainFilter<T, F>
|
||||
where F: FnMut(&mut T) -> bool
|
||||
{
|
||||
// avoid borrow issues.
|
||||
let it = self.head;
|
||||
let old_len = self.len;
|
||||
|
||||
DrainFilter {
|
||||
list: self,
|
||||
it: it,
|
||||
pred: filter,
|
||||
idx: 0,
|
||||
old_len: old_len,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a place for insertion at the front of the list.
|
||||
///
|
||||
/// Using this method with placement syntax is equivalent to
|
||||
|
@ -967,6 +1032,56 @@ impl<'a, T> IterMut<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// An iterator produced by calling `drain_filter` on LinkedList.
|
||||
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
|
||||
pub struct DrainFilter<'a, T: 'a, F: 'a>
|
||||
where F: FnMut(&mut T) -> bool,
|
||||
{
|
||||
list: &'a mut LinkedList<T>,
|
||||
it: Option<Shared<Node<T>>>,
|
||||
pred: F,
|
||||
idx: usize,
|
||||
old_len: usize,
|
||||
}
|
||||
|
||||
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
|
||||
impl<'a, T, F> Iterator for DrainFilter<'a, T, F>
|
||||
where F: FnMut(&mut T) -> bool,
|
||||
{
|
||||
type Item = T;
|
||||
|
||||
fn next(&mut self) -> Option<T> {
|
||||
while let Some(mut node) = self.it {
|
||||
unsafe {
|
||||
self.it = node.as_ref().next;
|
||||
self.idx += 1;
|
||||
|
||||
if (self.pred)(&mut node.as_mut().element) {
|
||||
self.list.unlink_node(node);
|
||||
return Some(Box::from_raw(node.as_ptr()).element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
(0, Some(self.old_len - self.idx))
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
|
||||
impl<'a, T: 'a + fmt::Debug, F> fmt::Debug for DrainFilter<'a, T, F>
|
||||
where F: FnMut(&mut T) -> bool
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_tuple("DrainFilter")
|
||||
.field(&self.list)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> Iterator for IntoIter<T> {
|
||||
type Item = T;
|
||||
|
@ -1509,4 +1624,28 @@ mod tests {
|
|||
}
|
||||
assert_eq!(i, v.len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drain_filter_test() {
|
||||
let mut m: LinkedList<u32> = LinkedList::new();
|
||||
m.extend(&[1, 2, 3, 4, 5, 6]);
|
||||
let deleted = m.drain_filter(|v| *v < 4).collect::<Vec<_>>();
|
||||
|
||||
check_links(&m);
|
||||
|
||||
assert_eq!(deleted, &[1, 2, 3]);
|
||||
assert_eq!(m.into_iter().collect::<Vec<_>>(), &[4, 5, 6]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drain_to_empty_test() {
|
||||
let mut m: LinkedList<u32> = LinkedList::new();
|
||||
m.extend(&[1, 2, 3, 4, 5, 6]);
|
||||
let deleted = m.drain_filter(|_| true).collect::<Vec<_>>();
|
||||
|
||||
check_links(&m);
|
||||
|
||||
assert_eq!(deleted, &[1, 2, 3, 4, 5, 6]);
|
||||
assert_eq!(m.into_iter().collect::<Vec<_>>(), &[]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -366,3 +366,191 @@ fn test_contains() {
|
|||
|
||||
assert!(!l.contains(&3));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drain_filter_empty() {
|
||||
let mut list: LinkedList<i32> = LinkedList::new();
|
||||
|
||||
{
|
||||
let mut iter = list.drain_filter(|_| true);
|
||||
assert_eq!(iter.size_hint(), (0, Some(0)));
|
||||
assert_eq!(iter.next(), None);
|
||||
assert_eq!(iter.size_hint(), (0, Some(0)));
|
||||
assert_eq!(iter.next(), None);
|
||||
assert_eq!(iter.size_hint(), (0, Some(0)));
|
||||
}
|
||||
|
||||
assert_eq!(list.len(), 0);
|
||||
assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drain_filter_zst() {
|
||||
let mut list: LinkedList<_> = vec![(), (), (), (), ()].into_iter().collect();
|
||||
let initial_len = list.len();
|
||||
let mut count = 0;
|
||||
|
||||
{
|
||||
let mut iter = list.drain_filter(|_| true);
|
||||
assert_eq!(iter.size_hint(), (0, Some(initial_len)));
|
||||
while let Some(_) = iter.next() {
|
||||
count += 1;
|
||||
assert_eq!(iter.size_hint(), (0, Some(initial_len - count)));
|
||||
}
|
||||
assert_eq!(iter.size_hint(), (0, Some(0)));
|
||||
assert_eq!(iter.next(), None);
|
||||
assert_eq!(iter.size_hint(), (0, Some(0)));
|
||||
}
|
||||
|
||||
assert_eq!(count, initial_len);
|
||||
assert_eq!(list.len(), 0);
|
||||
assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drain_filter_false() {
|
||||
let mut list: LinkedList<_> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
|
||||
|
||||
let initial_len = list.len();
|
||||
let mut count = 0;
|
||||
|
||||
{
|
||||
let mut iter = list.drain_filter(|_| false);
|
||||
assert_eq!(iter.size_hint(), (0, Some(initial_len)));
|
||||
for _ in iter.by_ref() {
|
||||
count += 1;
|
||||
}
|
||||
assert_eq!(iter.size_hint(), (0, Some(0)));
|
||||
assert_eq!(iter.next(), None);
|
||||
assert_eq!(iter.size_hint(), (0, Some(0)));
|
||||
}
|
||||
|
||||
assert_eq!(count, 0);
|
||||
assert_eq!(list.len(), initial_len);
|
||||
assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drain_filter_true() {
|
||||
let mut list: LinkedList<_> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
|
||||
|
||||
let initial_len = list.len();
|
||||
let mut count = 0;
|
||||
|
||||
{
|
||||
let mut iter = list.drain_filter(|_| true);
|
||||
assert_eq!(iter.size_hint(), (0, Some(initial_len)));
|
||||
while let Some(_) = iter.next() {
|
||||
count += 1;
|
||||
assert_eq!(iter.size_hint(), (0, Some(initial_len - count)));
|
||||
}
|
||||
assert_eq!(iter.size_hint(), (0, Some(0)));
|
||||
assert_eq!(iter.next(), None);
|
||||
assert_eq!(iter.size_hint(), (0, Some(0)));
|
||||
}
|
||||
|
||||
assert_eq!(count, initial_len);
|
||||
assert_eq!(list.len(), 0);
|
||||
assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drain_filter_complex() {
|
||||
|
||||
{ // [+xxx++++++xxxxx++++x+x++]
|
||||
let mut list = vec![
|
||||
1,
|
||||
2, 4, 6,
|
||||
7, 9, 11, 13, 15, 17,
|
||||
18, 20, 22, 24, 26,
|
||||
27, 29, 31, 33,
|
||||
34,
|
||||
35,
|
||||
36,
|
||||
37, 39
|
||||
].into_iter().collect::<LinkedList<_>>();
|
||||
|
||||
let removed = list.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
|
||||
assert_eq!(removed.len(), 10);
|
||||
assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]);
|
||||
|
||||
assert_eq!(list.len(), 14);
|
||||
assert_eq!(
|
||||
list.into_iter().collect::<Vec<_>>(),
|
||||
vec![1, 7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35, 37, 39]
|
||||
);
|
||||
}
|
||||
|
||||
{ // [xxx++++++xxxxx++++x+x++]
|
||||
let mut list = vec![
|
||||
2, 4, 6,
|
||||
7, 9, 11, 13, 15, 17,
|
||||
18, 20, 22, 24, 26,
|
||||
27, 29, 31, 33,
|
||||
34,
|
||||
35,
|
||||
36,
|
||||
37, 39
|
||||
].into_iter().collect::<LinkedList<_>>();
|
||||
|
||||
let removed = list.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
|
||||
assert_eq!(removed.len(), 10);
|
||||
assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]);
|
||||
|
||||
assert_eq!(list.len(), 13);
|
||||
assert_eq!(
|
||||
list.into_iter().collect::<Vec<_>>(),
|
||||
vec![7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35, 37, 39]
|
||||
);
|
||||
}
|
||||
|
||||
{ // [xxx++++++xxxxx++++x+x]
|
||||
let mut list = vec![
|
||||
2, 4, 6,
|
||||
7, 9, 11, 13, 15, 17,
|
||||
18, 20, 22, 24, 26,
|
||||
27, 29, 31, 33,
|
||||
34,
|
||||
35,
|
||||
36
|
||||
].into_iter().collect::<LinkedList<_>>();
|
||||
|
||||
let removed = list.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
|
||||
assert_eq!(removed.len(), 10);
|
||||
assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]);
|
||||
|
||||
assert_eq!(list.len(), 11);
|
||||
assert_eq!(
|
||||
list.into_iter().collect::<Vec<_>>(),
|
||||
vec![7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35]
|
||||
);
|
||||
}
|
||||
|
||||
{ // [xxxxxxxxxx+++++++++++]
|
||||
let mut list = vec![
|
||||
2, 4, 6, 8, 10, 12, 14, 16, 18, 20,
|
||||
1, 3, 5, 7, 9, 11, 13, 15, 17, 19
|
||||
].into_iter().collect::<LinkedList<_>>();
|
||||
|
||||
let removed = list.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
|
||||
assert_eq!(removed.len(), 10);
|
||||
assert_eq!(removed, vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20]);
|
||||
|
||||
assert_eq!(list.len(), 10);
|
||||
assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19]);
|
||||
}
|
||||
|
||||
{ // [+++++++++++xxxxxxxxxx]
|
||||
let mut list = vec![
|
||||
1, 3, 5, 7, 9, 11, 13, 15, 17, 19,
|
||||
2, 4, 6, 8, 10, 12, 14, 16, 18, 20
|
||||
].into_iter().collect::<LinkedList<_>>();
|
||||
|
||||
let removed = list.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
|
||||
assert_eq!(removed.len(), 10);
|
||||
assert_eq!(removed, vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20]);
|
||||
|
||||
assert_eq!(list.len(), 10);
|
||||
assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -624,6 +624,9 @@ pub trait Display {
|
|||
///
|
||||
/// The `Octal` trait should format its output as a number in base-8.
|
||||
///
|
||||
/// For primitive signed integers (`i8` to `i128`, and `isize`),
|
||||
/// negative values are formatted as the two’s complement representation.
|
||||
///
|
||||
/// The alternate flag, `#`, adds a `0o` in front of the output.
|
||||
///
|
||||
/// For more information on formatters, see [the module-level documentation][module].
|
||||
|
@ -639,6 +642,8 @@ pub trait Display {
|
|||
///
|
||||
/// assert_eq!(format!("{:o}", x), "52");
|
||||
/// assert_eq!(format!("{:#o}", x), "0o52");
|
||||
///
|
||||
/// assert_eq!(format!("{:o}", -16), "37777777760");
|
||||
/// ```
|
||||
///
|
||||
/// Implementing `Octal` on a type:
|
||||
|
@ -671,6 +676,9 @@ pub trait Octal {
|
|||
///
|
||||
/// The `Binary` trait should format its output as a number in binary.
|
||||
///
|
||||
/// For primitive signed integers (`i8` to `i128`, and `isize`),
|
||||
/// negative values are formatted as the two’s complement representation.
|
||||
///
|
||||
/// The alternate flag, `#`, adds a `0b` in front of the output.
|
||||
///
|
||||
/// For more information on formatters, see [the module-level documentation][module].
|
||||
|
@ -686,6 +694,8 @@ pub trait Octal {
|
|||
///
|
||||
/// assert_eq!(format!("{:b}", x), "101010");
|
||||
/// assert_eq!(format!("{:#b}", x), "0b101010");
|
||||
///
|
||||
/// assert_eq!(format!("{:b}", -16), "11111111111111111111111111110000");
|
||||
/// ```
|
||||
///
|
||||
/// Implementing `Binary` on a type:
|
||||
|
@ -719,6 +729,9 @@ pub trait Binary {
|
|||
/// The `LowerHex` trait should format its output as a number in hexadecimal, with `a` through `f`
|
||||
/// in lower case.
|
||||
///
|
||||
/// For primitive signed integers (`i8` to `i128`, and `isize`),
|
||||
/// negative values are formatted as the two’s complement representation.
|
||||
///
|
||||
/// The alternate flag, `#`, adds a `0x` in front of the output.
|
||||
///
|
||||
/// For more information on formatters, see [the module-level documentation][module].
|
||||
|
@ -734,6 +747,8 @@ pub trait Binary {
|
|||
///
|
||||
/// assert_eq!(format!("{:x}", x), "2a");
|
||||
/// assert_eq!(format!("{:#x}", x), "0x2a");
|
||||
///
|
||||
/// assert_eq!(format!("{:x}", -16), "fffffff0");
|
||||
/// ```
|
||||
///
|
||||
/// Implementing `LowerHex` on a type:
|
||||
|
@ -767,6 +782,9 @@ pub trait LowerHex {
|
|||
/// The `UpperHex` trait should format its output as a number in hexadecimal, with `A` through `F`
|
||||
/// in upper case.
|
||||
///
|
||||
/// For primitive signed integers (`i8` to `i128`, and `isize`),
|
||||
/// negative values are formatted as the two’s complement representation.
|
||||
///
|
||||
/// The alternate flag, `#`, adds a `0x` in front of the output.
|
||||
///
|
||||
/// For more information on formatters, see [the module-level documentation][module].
|
||||
|
@ -782,6 +800,8 @@ pub trait LowerHex {
|
|||
///
|
||||
/// assert_eq!(format!("{:X}", x), "2A");
|
||||
/// assert_eq!(format!("{:#X}", x), "0x2A");
|
||||
///
|
||||
/// assert_eq!(format!("{:X}", -16), "FFFFFFF0");
|
||||
/// ```
|
||||
///
|
||||
/// Implementing `UpperHex` on a type:
|
||||
|
|
|
@ -132,7 +132,14 @@ macro_rules! int_impl {
|
|||
|
||||
/// Converts a string slice in a given base to an integer.
|
||||
///
|
||||
/// The string is expected to be an optional `+` or `-` sign
|
||||
/// followed by digits.
|
||||
/// Leading and trailing whitespace represent an error.
|
||||
/// Digits are a subset of these characters, depending on `radix`:
|
||||
///
|
||||
/// * `0-9`
|
||||
/// * `a-z`
|
||||
/// * `A-Z`
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
|
@ -1301,7 +1308,18 @@ macro_rules! uint_impl {
|
|||
|
||||
/// Converts a string slice in a given base to an integer.
|
||||
///
|
||||
/// The string is expected to be an optional `+` sign
|
||||
/// followed by digits.
|
||||
/// Leading and trailing whitespace represent an error.
|
||||
/// Digits are a subset of these characters, depending on `radix`:
|
||||
///
|
||||
/// * `0-9`
|
||||
/// * `a-z`
|
||||
/// * `A-Z`
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function panics if `radix` is not in the range from 2 to 36.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
|
@ -103,9 +103,8 @@ use fmt;
|
|||
///
|
||||
/// On some platforms this function may not do anything at all.
|
||||
#[inline]
|
||||
#[unstable(feature = "hint_core_should_pause", issue = "41196")]
|
||||
pub fn hint_core_should_pause()
|
||||
{
|
||||
#[stable(feature = "spin_loop_hint", since = "1.24.0")]
|
||||
pub fn spin_loop_hint() {
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
unsafe {
|
||||
asm!("pause" ::: "memory" : "volatile");
|
||||
|
|
|
@ -581,6 +581,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
trait_ref.self_ty()));
|
||||
}
|
||||
|
||||
self.suggest_borrow_on_unsized_slice(&obligation.cause.code, &mut err);
|
||||
|
||||
// Try to report a help message
|
||||
if !trait_ref.has_infer_types() &&
|
||||
self.predicate_can_apply(obligation.param_env, trait_ref) {
|
||||
|
@ -821,6 +823,27 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
err.emit();
|
||||
}
|
||||
|
||||
/// When encountering an assignment of an unsized trait, like `let x = ""[..];`, provide a
|
||||
/// suggestion to borrow the initializer in order to use have a slice instead.
|
||||
fn suggest_borrow_on_unsized_slice(&self,
|
||||
code: &ObligationCauseCode<'tcx>,
|
||||
err: &mut DiagnosticBuilder<'tcx>) {
|
||||
if let &ObligationCauseCode::VariableType(node_id) = code {
|
||||
let parent_node = self.tcx.hir.get_parent_node(node_id);
|
||||
if let Some(hir::map::NodeLocal(ref local)) = self.tcx.hir.find(parent_node) {
|
||||
if let Some(ref expr) = local.init {
|
||||
if let hir::ExprIndex(_, _) = expr.node {
|
||||
if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(expr.span) {
|
||||
err.span_suggestion(expr.span,
|
||||
"consider borrowing here",
|
||||
format!("&{}", snippet));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn report_arg_count_mismatch(
|
||||
&self,
|
||||
span: Span,
|
||||
|
|
|
@ -81,17 +81,18 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
// (And cycle errors around impls tend to occur during the
|
||||
// collect/coherence phases anyhow.)
|
||||
item_path::with_forced_impl_filename_line(|| {
|
||||
let span = self.sess.codemap().def_span(span);
|
||||
let mut err =
|
||||
struct_span_err!(self.sess, span, E0391,
|
||||
"unsupported cyclic reference between types/traits detected");
|
||||
err.span_label(span, "cyclic reference");
|
||||
|
||||
err.span_note(stack[0].0, &format!("the cycle begins when {}...",
|
||||
stack[0].1.describe(self)));
|
||||
err.span_note(self.sess.codemap().def_span(stack[0].0),
|
||||
&format!("the cycle begins when {}...", stack[0].1.describe(self)));
|
||||
|
||||
for &(span, ref query) in &stack[1..] {
|
||||
err.span_note(span, &format!("...which then requires {}...",
|
||||
query.describe(self)));
|
||||
err.span_note(self.sess.codemap().def_span(span),
|
||||
&format!("...which then requires {}...", query.describe(self)));
|
||||
}
|
||||
|
||||
err.note(&format!("...which then again requires {}, completing the cycle.",
|
||||
|
|
|
@ -484,6 +484,34 @@ enum WriteKind {
|
|||
Move,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum InitializationRequiringAction {
|
||||
Update,
|
||||
Borrow,
|
||||
Use,
|
||||
Assignment,
|
||||
}
|
||||
|
||||
impl InitializationRequiringAction {
|
||||
fn as_noun(self) -> &'static str {
|
||||
match self {
|
||||
InitializationRequiringAction::Update => "update",
|
||||
InitializationRequiringAction::Borrow => "borrow",
|
||||
InitializationRequiringAction::Use => "use",
|
||||
InitializationRequiringAction::Assignment => "assign"
|
||||
}
|
||||
}
|
||||
|
||||
fn as_verb_in_past_tense(self) -> &'static str {
|
||||
match self {
|
||||
InitializationRequiringAction::Update => "updated",
|
||||
InitializationRequiringAction::Borrow => "borrowed",
|
||||
InitializationRequiringAction::Use => "used",
|
||||
InitializationRequiringAction::Assignment => "assigned"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
/// Checks an access to the given lvalue to see if it is allowed. Examines the set of borrows
|
||||
/// that are in scope, as well as which paths have been initialized, to ensure that (a) the
|
||||
|
@ -574,7 +602,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
// Write of P[i] or *P, or WriteAndRead of any P, requires P init'd.
|
||||
match mode {
|
||||
MutateMode::WriteAndRead => {
|
||||
self.check_if_path_is_moved(context, "update", lvalue_span, flow_state);
|
||||
self.check_if_path_is_moved(context, InitializationRequiringAction::Update,
|
||||
lvalue_span, flow_state);
|
||||
}
|
||||
MutateMode::JustWrite => {
|
||||
self.check_if_assigned_path_is_moved(context, lvalue_span, flow_state);
|
||||
|
@ -600,7 +629,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
BorrowKind::Mut => (Deep, Write(WriteKind::MutableBorrow(bk))),
|
||||
};
|
||||
self.access_lvalue(context, (lvalue, span), access_kind, flow_state);
|
||||
self.check_if_path_is_moved(context, "borrow", (lvalue, span), flow_state);
|
||||
self.check_if_path_is_moved(context, InitializationRequiringAction::Borrow,
|
||||
(lvalue, span), flow_state);
|
||||
}
|
||||
|
||||
Rvalue::Use(ref operand) |
|
||||
|
@ -619,7 +649,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
};
|
||||
self.access_lvalue(
|
||||
context, (lvalue, span), (Shallow(Some(af)), Read(ReadKind::Copy)), flow_state);
|
||||
self.check_if_path_is_moved(context, "use", (lvalue, span), flow_state);
|
||||
self.check_if_path_is_moved(context, InitializationRequiringAction::Use,
|
||||
(lvalue, span), flow_state);
|
||||
}
|
||||
|
||||
Rvalue::BinaryOp(_bin_op, ref operand1, ref operand2) |
|
||||
|
@ -720,7 +751,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
// skip this check in that case).
|
||||
}
|
||||
ConsumeKind::Consume => {
|
||||
self.check_if_path_is_moved(context, "use", lvalue_span, flow_state);
|
||||
self.check_if_path_is_moved(context, InitializationRequiringAction::Use,
|
||||
lvalue_span, flow_state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -772,7 +804,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
|
||||
fn check_if_path_is_moved(&mut self,
|
||||
context: Context,
|
||||
desired_action: &str,
|
||||
desired_action: InitializationRequiringAction,
|
||||
lvalue_span: (&Lvalue<'tcx>, Span),
|
||||
flow_state: &InProgress<'cx, 'gcx, 'tcx>) {
|
||||
// FIXME: analogous code in check_loans first maps `lvalue` to
|
||||
|
@ -943,7 +975,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
// `base` to its base_path.
|
||||
|
||||
self.check_if_path_is_moved(
|
||||
context, "assignment", (base, span), flow_state);
|
||||
context, InitializationRequiringAction::Assignment,
|
||||
(base, span), flow_state);
|
||||
|
||||
// (base initialized; no need to
|
||||
// recur further)
|
||||
|
@ -1347,7 +1380,7 @@ mod prefixes {
|
|||
impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
fn report_use_of_moved_or_uninitialized(&mut self,
|
||||
_context: Context,
|
||||
desired_action: &str,
|
||||
desired_action: InitializationRequiringAction,
|
||||
(lvalue, span): (&Lvalue<'tcx>, Span),
|
||||
mpi: MovePathIndex,
|
||||
curr_move_out: &IdxSetBuf<MoveOutIndex>) {
|
||||
|
@ -1357,7 +1390,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
|
||||
if mois.is_empty() {
|
||||
self.tcx.cannot_act_on_uninitialized_variable(span,
|
||||
desired_action,
|
||||
desired_action.as_noun(),
|
||||
&self.describe_lvalue(lvalue),
|
||||
Origin::Mir)
|
||||
.span_label(span, format!("use of possibly uninitialized `{}`",
|
||||
|
@ -1367,11 +1400,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
let msg = ""; //FIXME: add "partially " or "collaterally "
|
||||
|
||||
let mut err = self.tcx.cannot_act_on_moved_value(span,
|
||||
desired_action,
|
||||
desired_action.as_noun(),
|
||||
msg,
|
||||
&self.describe_lvalue(lvalue),
|
||||
Origin::Mir);
|
||||
err.span_label(span, format!("value {} here after move", desired_action));
|
||||
|
||||
err.span_label(span, format!("value {} here after move",
|
||||
desired_action.as_verb_in_past_tense()));
|
||||
for moi in mois {
|
||||
let move_msg = ""; //FIXME: add " (into closure)"
|
||||
let move_span = self.mir.source_info(self.move_data.moves[*moi].source).span;
|
||||
|
|
|
@ -1625,6 +1625,15 @@ impl<T: Send> error::Error for TrySendError<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "mpsc_error_conversions", since = "1.23.0")]
|
||||
impl<T> From<SendError<T>> for TrySendError<T> {
|
||||
fn from(err: SendError<T>) -> TrySendError<T> {
|
||||
match err {
|
||||
SendError(t) => TrySendError::Disconnected(t),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl fmt::Display for RecvError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
|
@ -1677,6 +1686,15 @@ impl error::Error for TryRecvError {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "mpsc_error_conversions", since = "1.23.0")]
|
||||
impl From<RecvError> for TryRecvError {
|
||||
fn from(err: RecvError) -> TryRecvError {
|
||||
match err {
|
||||
RecvError => TryRecvError::Disconnected,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "mpsc_recv_timeout_error", since = "1.15.0")]
|
||||
impl fmt::Display for RecvTimeoutError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
|
@ -1709,6 +1727,15 @@ impl error::Error for RecvTimeoutError {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "mpsc_error_conversions", since = "1.23.0")]
|
||||
impl From<RecvError> for RecvTimeoutError {
|
||||
fn from(err: RecvError) -> RecvTimeoutError {
|
||||
match err {
|
||||
RecvError => RecvTimeoutError::Disconnected,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(test, not(target_os = "emscripten")))]
|
||||
mod tests {
|
||||
use env;
|
||||
|
|
|
@ -5486,7 +5486,12 @@ impl<'a> Parser<'a> {
|
|||
|
||||
if !self.eat(term) {
|
||||
let token_str = self.this_token_to_string();
|
||||
return Err(self.fatal(&format!("expected item, found `{}`", token_str)));
|
||||
let mut err = self.fatal(&format!("expected item, found `{}`", token_str));
|
||||
let msg = "consider removing this semicolon";
|
||||
if token_str == ";" {
|
||||
err.span_suggestion_short(self.span, msg, "".to_string());
|
||||
}
|
||||
return Err(err);
|
||||
}
|
||||
|
||||
let hi = if self.span == syntax_pos::DUMMY_SP {
|
||||
|
|
|
@ -14,7 +14,7 @@ error[E0382]: use of moved value: `x` (Mir)
|
|||
17 | drop(x);
|
||||
| - value moved here
|
||||
18 | let _ = (1,x); //~ ERROR use of moved value: `x` (Ast)
|
||||
| ^ value use here after move
|
||||
| ^ value used here after move
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
error[E0277]: the trait bound `std::rc::Rc<std::cell::Cell<i32>>: std::marker::Send` is not satisfied in `impl std::ops::Fn<(i32,)>`
|
||||
--> $DIR/auto-trait-leak.rs:27:5
|
||||
|
|
||||
27 | send(before());
|
||||
| ^^^^ `std::rc::Rc<std::cell::Cell<i32>>` cannot be sent between threads safely
|
||||
|
|
||||
= help: within `impl std::ops::Fn<(i32,)>`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<std::cell::Cell<i32>>`
|
||||
= note: required because it appears within the type `[closure@$DIR/auto-trait-leak.rs:21:5: 21:22 p:std::rc::Rc<std::cell::Cell<i32>>]`
|
||||
= note: required because it appears within the type `impl std::ops::Fn<(i32,)>`
|
||||
= note: required by `send`
|
||||
|
||||
error[E0277]: the trait bound `std::rc::Rc<std::cell::Cell<i32>>: std::marker::Send` is not satisfied in `impl std::ops::Fn<(i32,)>`
|
||||
--> $DIR/auto-trait-leak.rs:34:5
|
||||
|
|
||||
34 | send(after());
|
||||
| ^^^^ `std::rc::Rc<std::cell::Cell<i32>>` cannot be sent between threads safely
|
||||
|
|
||||
= help: within `impl std::ops::Fn<(i32,)>`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<std::cell::Cell<i32>>`
|
||||
= note: required because it appears within the type `[closure@$DIR/auto-trait-leak.rs:46:5: 46:22 p:std::rc::Rc<std::cell::Cell<i32>>]`
|
||||
= note: required because it appears within the type `impl std::ops::Fn<(i32,)>`
|
||||
= note: required by `send`
|
||||
|
||||
error[E0391]: unsupported cyclic reference between types/traits detected
|
||||
--> $DIR/auto-trait-leak.rs:52:1
|
||||
|
|
||||
52 | fn cycle1() -> impl Clone {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ cyclic reference
|
||||
|
|
||||
note: the cycle begins when processing `cycle1`...
|
||||
--> $DIR/auto-trait-leak.rs:52:1
|
||||
|
|
||||
52 | fn cycle1() -> impl Clone {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
note: ...which then requires processing `cycle2::{{impl-Trait}}`...
|
||||
--> $DIR/auto-trait-leak.rs:63:16
|
||||
|
|
||||
63 | fn cycle2() -> impl Clone {
|
||||
| ^^^^^^^^^^
|
||||
note: ...which then requires processing `cycle2`...
|
||||
--> $DIR/auto-trait-leak.rs:63:1
|
||||
|
|
||||
63 | fn cycle2() -> impl Clone {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
note: ...which then requires processing `cycle1::{{impl-Trait}}`...
|
||||
--> $DIR/auto-trait-leak.rs:52:16
|
||||
|
|
||||
52 | fn cycle1() -> impl Clone {
|
||||
| ^^^^^^^^^^
|
||||
= note: ...which then again requires processing `cycle1`, completing the cycle.
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
struct Struct {
|
||||
a: usize,
|
||||
}; //~ ERROR expected item, found `;`
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,8 @@
|
|||
error: expected item, found `;`
|
||||
--> $DIR/issue-46186.rs:13:2
|
||||
|
|
||||
13 | }; //~ ERROR expected item, found `;`
|
||||
| ^ help: consider removing this semicolon
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
@ -8,7 +8,7 @@ note: the cycle begins when processing `<impl at $DIR/issue-23305.rs:15:1: 15:20
|
|||
--> $DIR/issue-23305.rs:15:1
|
||||
|
|
||||
15 | impl ToNbt<Self> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
= note: ...which then again requires processing `<impl at $DIR/issue-23305.rs:15:1: 15:20>`, completing the cycle.
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
fn main() { //~ NOTE expected `()` because of default return type
|
||||
let s = "abc";
|
||||
let t = if true { s[..2] } else { s };
|
||||
//~^ ERROR if and else have incompatible types
|
||||
//~| NOTE expected str, found &str
|
||||
//~| NOTE expected type
|
||||
let u: &str = if true { s[..2] } else { s };
|
||||
//~^ ERROR mismatched types
|
||||
//~| NOTE expected &str, found str
|
||||
//~| NOTE expected type
|
||||
let v = s[..2];
|
||||
//~^ ERROR the trait bound `str: std::marker::Sized` is not satisfied
|
||||
//~| HELP consider borrowing here
|
||||
//~| NOTE `str` does not have a constant size known at compile-time
|
||||
//~| HELP the trait `std::marker::Sized` is not implemented for `str`
|
||||
//~| NOTE all local variables must have a statically known size
|
||||
let w: &str = s[..2];
|
||||
//~^ ERROR mismatched types
|
||||
//~| NOTE expected &str, found str
|
||||
//~| NOTE expected type
|
||||
//~| HELP try with `&s[..2]`
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
error[E0308]: if and else have incompatible types
|
||||
--> $DIR/str-array-assignment.rs:13:11
|
||||
|
|
||||
13 | let t = if true { s[..2] } else { s };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected str, found &str
|
||||
|
|
||||
= note: expected type `str`
|
||||
found type `&str`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/str-array-assignment.rs:17:27
|
||||
|
|
||||
11 | fn main() { //~ NOTE expected `()` because of default return type
|
||||
| - expected `()` because of default return type
|
||||
...
|
||||
17 | let u: &str = if true { s[..2] } else { s };
|
||||
| ^^^^^^ expected &str, found str
|
||||
|
|
||||
= note: expected type `&str`
|
||||
found type `str`
|
||||
|
||||
error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied
|
||||
--> $DIR/str-array-assignment.rs:21:7
|
||||
|
|
||||
21 | let v = s[..2];
|
||||
| ^ ------ help: consider borrowing here: `&s[..2]`
|
||||
| |
|
||||
| `str` does not have a constant size known at compile-time
|
||||
|
|
||||
= help: the trait `std::marker::Sized` is not implemented for `str`
|
||||
= note: all local variables must have a statically known size
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/str-array-assignment.rs:27:17
|
||||
|
|
||||
27 | let w: &str = s[..2];
|
||||
| ^^^^^^ expected &str, found str
|
||||
|
|
||||
= note: expected type `&str`
|
||||
found type `str`
|
||||
= help: try with `&s[..2]`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
|
@ -10,6 +10,8 @@ filetime = "0.1"
|
|||
getopts = "0.2"
|
||||
log = "0.3"
|
||||
rustc-serialize = "0.3"
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
libc = "0.2"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
|
|
Loading…
Reference in New Issue