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:
bors 2017-11-27 23:40:16 +00:00
commit b087a991fc
20 changed files with 628 additions and 61 deletions

View File

@ -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`.

View File

@ -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<_>>(), &[]);
}
}

View File

@ -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]);
}
}

View File

@ -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 twos 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 twos 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 twos 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 twos 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:

View File

@ -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
///

View File

@ -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");

View File

@ -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,

View File

@ -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.",

View File

@ -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;

View File

@ -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;

View File

@ -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 {

View File

@ -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

View File

@ -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

View File

@ -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() {}

View File

@ -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

View File

@ -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

View File

@ -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]`
}

View File

@ -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

View File

@ -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]