Auto merge of #58446 - Centril:rollup, r=Centril
Rollup of 8 pull requests Successful merges: - #57451 (suggestion-diagnostics: as_ref improve snippet) - #57856 (Convert old first edition links to current edition one) - #57992 (Update the future/task API) - #58258 (Reduce the size of `hir::Expr`.) - #58267 (Tweak "incompatible match arms" error) - #58296 (Hidden suggestion support) - #58301 (Enable comparing fat pointers) - #58308 (Extract block to insert an intrinsic into its own function) Failed merges: r? @ghost
This commit is contained in:
commit
c67d4749a5
76 changed files with 962 additions and 819 deletions
|
@ -1,4 +1,4 @@
|
|||
% Error Handling in Rust
|
||||
|
||||
This content has moved into
|
||||
[the Rust Programming Language book](book/error-handling.html).
|
||||
[the Rust Programming Language book](book/ch09-00-error-handling.html).
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
% The (old) Rust Ownership Guide
|
||||
|
||||
This content has moved into
|
||||
[the Rust Programming Language book](book/ownership.html).
|
||||
[the Rust Programming Language book](book/ch04-00-understanding-ownership.html).
|
||||
|
|
|
@ -2,6 +2,6 @@
|
|||
|
||||
This content has been removed, with no direct replacement. Rust only
|
||||
has two built-in pointer types now,
|
||||
[references](book/references-and-borrowing.html) and [raw
|
||||
[references](book/ch04-02-references-and-borrowing.html) and [raw
|
||||
pointers](book/raw-pointers.html). Older Rusts had many more pointer
|
||||
types, they’re gone now.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
% The (old) Rust Testing Guide
|
||||
|
||||
This content has moved into
|
||||
[the Rust Programming Language book](book/testing.html).
|
||||
[the Rust Programming Language book](book/ch11-00-testing.html).
|
||||
|
|
|
@ -71,7 +71,7 @@ use core::ops::{
|
|||
CoerceUnsized, DispatchFromDyn, Deref, DerefMut, Receiver, Generator, GeneratorState
|
||||
};
|
||||
use core::ptr::{self, NonNull, Unique};
|
||||
use core::task::{LocalWaker, Poll};
|
||||
use core::task::{Waker, Poll};
|
||||
|
||||
use crate::vec::Vec;
|
||||
use crate::raw_vec::RawVec;
|
||||
|
@ -896,7 +896,7 @@ impl<G: ?Sized + Generator> Generator for Pin<Box<G>> {
|
|||
impl<F: ?Sized + Future + Unpin> Future for Box<F> {
|
||||
type Output = F::Output;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, lw: &LocalWaker) -> Poll<Self::Output> {
|
||||
F::poll(Pin::new(&mut *self), lw)
|
||||
fn poll(mut self: Pin<&mut Self>, waker: &Waker) -> Poll<Self::Output> {
|
||||
F::poll(Pin::new(&mut *self), waker)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -132,10 +132,6 @@ mod macros;
|
|||
|
||||
pub mod alloc;
|
||||
|
||||
#[unstable(feature = "futures_api",
|
||||
reason = "futures in libcore are unstable",
|
||||
issue = "50547")]
|
||||
pub mod task;
|
||||
// Primitive types using the heaps above
|
||||
|
||||
// Need to conditionally define the mod from `boxed.rs` to avoid
|
||||
|
|
|
@ -1,130 +0,0 @@
|
|||
//! Types and Traits for working with asynchronous tasks.
|
||||
|
||||
pub use core::task::*;
|
||||
|
||||
#[cfg(all(target_has_atomic = "ptr", target_has_atomic = "cas"))]
|
||||
pub use if_arc::*;
|
||||
|
||||
#[cfg(all(target_has_atomic = "ptr", target_has_atomic = "cas"))]
|
||||
mod if_arc {
|
||||
use super::*;
|
||||
use core::marker::PhantomData;
|
||||
use core::mem;
|
||||
use core::ptr::{self, NonNull};
|
||||
use crate::sync::Arc;
|
||||
|
||||
/// A way of waking up a specific task.
|
||||
///
|
||||
/// Any task executor must provide a way of signaling that a task it owns
|
||||
/// is ready to be `poll`ed again. Executors do so by implementing this trait.
|
||||
pub trait Wake: Send + Sync {
|
||||
/// Indicates that the associated task is ready to make progress and should
|
||||
/// be `poll`ed.
|
||||
///
|
||||
/// Executors generally maintain a queue of "ready" tasks; `wake` should place
|
||||
/// the associated task onto this queue.
|
||||
fn wake(arc_self: &Arc<Self>);
|
||||
|
||||
/// Indicates that the associated task is ready to make progress and should
|
||||
/// be `poll`ed. This function is like `wake`, but can only be called from the
|
||||
/// thread on which this `Wake` was created.
|
||||
///
|
||||
/// Executors generally maintain a queue of "ready" tasks; `wake_local` should place
|
||||
/// the associated task onto this queue.
|
||||
#[inline]
|
||||
unsafe fn wake_local(arc_self: &Arc<Self>) {
|
||||
Self::wake(arc_self);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(target_has_atomic = "ptr", target_has_atomic = "cas"))]
|
||||
struct ArcWrapped<T>(PhantomData<T>);
|
||||
|
||||
unsafe impl<T: Wake + 'static> UnsafeWake for ArcWrapped<T> {
|
||||
#[inline]
|
||||
unsafe fn clone_raw(&self) -> Waker {
|
||||
let me: *const ArcWrapped<T> = self;
|
||||
let arc = (*(&me as *const *const ArcWrapped<T> as *const Arc<T>)).clone();
|
||||
Waker::from(arc)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn drop_raw(&self) {
|
||||
let mut me: *const ArcWrapped<T> = self;
|
||||
let me = &mut me as *mut *const ArcWrapped<T> as *mut Arc<T>;
|
||||
ptr::drop_in_place(me);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn wake(&self) {
|
||||
let me: *const ArcWrapped<T> = self;
|
||||
T::wake(&*(&me as *const *const ArcWrapped<T> as *const Arc<T>))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn wake_local(&self) {
|
||||
let me: *const ArcWrapped<T> = self;
|
||||
T::wake_local(&*(&me as *const *const ArcWrapped<T> as *const Arc<T>))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Arc<T>> for Waker
|
||||
where T: Wake + 'static,
|
||||
{
|
||||
fn from(rc: Arc<T>) -> Self {
|
||||
unsafe {
|
||||
let ptr = mem::transmute::<Arc<T>, NonNull<ArcWrapped<T>>>(rc);
|
||||
Waker::new(ptr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a `LocalWaker` from a local `wake`.
|
||||
///
|
||||
/// This function requires that `wake` is "local" (created on the current thread).
|
||||
/// The resulting `LocalWaker` will call `wake.wake_local()` when awoken, and
|
||||
/// will call `wake.wake()` if awoken after being converted to a `Waker`.
|
||||
#[inline]
|
||||
pub unsafe fn local_waker<W: Wake + 'static>(wake: Arc<W>) -> LocalWaker {
|
||||
let ptr = mem::transmute::<Arc<W>, NonNull<ArcWrapped<W>>>(wake);
|
||||
LocalWaker::new(ptr)
|
||||
}
|
||||
|
||||
struct NonLocalAsLocal<T>(ArcWrapped<T>);
|
||||
|
||||
unsafe impl<T: Wake + 'static> UnsafeWake for NonLocalAsLocal<T> {
|
||||
#[inline]
|
||||
unsafe fn clone_raw(&self) -> Waker {
|
||||
self.0.clone_raw()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn drop_raw(&self) {
|
||||
self.0.drop_raw()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn wake(&self) {
|
||||
self.0.wake()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn wake_local(&self) {
|
||||
// Since we're nonlocal, we can't call wake_local
|
||||
self.0.wake()
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a `LocalWaker` from a non-local `wake`.
|
||||
///
|
||||
/// This function is similar to `local_waker`, but does not require that `wake`
|
||||
/// is local to the current thread. The resulting `LocalWaker` will call
|
||||
/// `wake.wake()` when awoken.
|
||||
#[inline]
|
||||
pub fn local_waker_from_nonlocal<W: Wake + 'static>(wake: Arc<W>) -> LocalWaker {
|
||||
unsafe {
|
||||
let ptr = mem::transmute::<Arc<W>, NonNull<NonLocalAsLocal<W>>>(wake);
|
||||
LocalWaker::new(ptr)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -116,9 +116,6 @@ pub const fn identity<T>(x: T) -> T { x }
|
|||
/// - Use `Borrow` when the goal is related to writing code that is agnostic to
|
||||
/// the type of borrow and whether it is a reference or value
|
||||
///
|
||||
/// See [the book][book] for a more detailed comparison.
|
||||
///
|
||||
/// [book]: ../../book/first-edition/borrow-and-asref.html
|
||||
/// [`Borrow`]: ../../std/borrow/trait.Borrow.html
|
||||
///
|
||||
/// **Note: this trait must not fail**. If the conversion can fail, use a
|
||||
|
@ -351,7 +348,7 @@ pub trait Into<T>: Sized {
|
|||
/// [`String`]: ../../std/string/struct.String.html
|
||||
/// [`Into<U>`]: trait.Into.html
|
||||
/// [`from`]: trait.From.html#tymethod.from
|
||||
/// [book]: ../../book/first-edition/error-handling.html
|
||||
/// [book]: ../../book/ch09-00-error-handling.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait From<T>: Sized {
|
||||
/// Performs the conversion.
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
use marker::Unpin;
|
||||
use ops;
|
||||
use pin::Pin;
|
||||
use task::{Poll, LocalWaker};
|
||||
use task::{Poll, Waker};
|
||||
|
||||
/// A future represents an asynchronous computation.
|
||||
///
|
||||
|
@ -19,13 +19,14 @@ use task::{Poll, LocalWaker};
|
|||
/// final value. This method does not block if the value is not ready. Instead,
|
||||
/// the current task is scheduled to be woken up when it's possible to make
|
||||
/// further progress by `poll`ing again. The wake up is performed using
|
||||
/// `cx.waker()`, a handle for waking up the current task.
|
||||
/// the `waker` argument of the `poll()` method, which is a handle for waking
|
||||
/// up the current task.
|
||||
///
|
||||
/// When using a future, you generally won't call `poll` directly, but instead
|
||||
/// `await!` the value.
|
||||
#[must_use = "futures do nothing unless polled"]
|
||||
pub trait Future {
|
||||
/// The result of the `Future`.
|
||||
/// The type of value produced on completion.
|
||||
type Output;
|
||||
|
||||
/// Attempt to resolve the future to a final value, registering
|
||||
|
@ -42,16 +43,16 @@ pub trait Future {
|
|||
/// Once a future has finished, clients should not `poll` it again.
|
||||
///
|
||||
/// When a future is not ready yet, `poll` returns `Poll::Pending` and
|
||||
/// stores a clone of the [`LocalWaker`] to be woken once the future can
|
||||
/// stores a clone of the [`Waker`] to be woken once the future can
|
||||
/// make progress. For example, a future waiting for a socket to become
|
||||
/// readable would call `.clone()` on the [`LocalWaker`] and store it.
|
||||
/// readable would call `.clone()` on the [`Waker`] and store it.
|
||||
/// When a signal arrives elsewhere indicating that the socket is readable,
|
||||
/// `[LocalWaker::wake]` is called and the socket future's task is awoken.
|
||||
/// `[Waker::wake]` is called and the socket future's task is awoken.
|
||||
/// Once a task has been woken up, it should attempt to `poll` the future
|
||||
/// again, which may or may not produce a final value.
|
||||
///
|
||||
/// Note that on multiple calls to `poll`, only the most recent
|
||||
/// [`LocalWaker`] passed to `poll` should be scheduled to receive a
|
||||
/// [`Waker`] passed to `poll` should be scheduled to receive a
|
||||
/// wakeup.
|
||||
///
|
||||
/// # Runtime characteristics
|
||||
|
@ -67,44 +68,35 @@ pub trait Future {
|
|||
/// typically do *not* suffer the same problems of "all wakeups must poll
|
||||
/// all events"; they are more like `epoll(4)`.
|
||||
///
|
||||
/// An implementation of `poll` should strive to return quickly, and must
|
||||
/// *never* block. Returning quickly prevents unnecessarily clogging up
|
||||
/// An implementation of `poll` should strive to return quickly, and should
|
||||
/// not block. Returning quickly prevents unnecessarily clogging up
|
||||
/// threads or event loops. If it is known ahead of time that a call to
|
||||
/// `poll` may end up taking awhile, the work should be offloaded to a
|
||||
/// thread pool (or something similar) to ensure that `poll` can return
|
||||
/// quickly.
|
||||
///
|
||||
/// # [`LocalWaker`], [`Waker`] and thread-safety
|
||||
///
|
||||
/// The `poll` function takes a [`LocalWaker`], an object which knows how to
|
||||
/// awaken the current task. [`LocalWaker`] is not `Send` nor `Sync`, so in
|
||||
/// order to make thread-safe futures the [`LocalWaker::into_waker`] method
|
||||
/// should be used to convert the [`LocalWaker`] into a thread-safe version.
|
||||
/// [`LocalWaker::wake`] implementations have the ability to be more
|
||||
/// efficient, however, so when thread safety is not necessary,
|
||||
/// [`LocalWaker`] should be preferred.
|
||||
/// An implementation of `poll` may also never cause memory unsafety.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Once a future has completed (returned `Ready` from `poll`),
|
||||
/// then any future calls to `poll` may panic, block forever, or otherwise
|
||||
/// cause bad behavior. The `Future` trait itself provides no guarantees
|
||||
/// about the behavior of `poll` after a future has completed.
|
||||
/// cause any kind of bad behavior expect causing memory unsafety.
|
||||
/// The `Future` trait itself provides no guarantees about the behavior
|
||||
/// of `poll` after a future has completed.
|
||||
///
|
||||
/// [`Poll::Pending`]: ../task/enum.Poll.html#variant.Pending
|
||||
/// [`Poll::Ready(val)`]: ../task/enum.Poll.html#variant.Ready
|
||||
/// [`LocalWaker`]: ../task/struct.LocalWaker.html
|
||||
/// [`LocalWaker::into_waker`]: ../task/struct.LocalWaker.html#method.into_waker
|
||||
/// [`LocalWaker::wake`]: ../task/struct.LocalWaker.html#method.wake
|
||||
/// [`Waker`]: ../task/struct.Waker.html
|
||||
fn poll(self: Pin<&mut Self>, lw: &LocalWaker) -> Poll<Self::Output>;
|
||||
/// [`Waker::wake`]: ../task/struct.Waker.html#method.wake
|
||||
fn poll(self: Pin<&mut Self>, waker: &Waker) -> Poll<Self::Output>;
|
||||
}
|
||||
|
||||
impl<'a, F: ?Sized + Future + Unpin> Future for &'a mut F {
|
||||
type Output = F::Output;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, lw: &LocalWaker) -> Poll<Self::Output> {
|
||||
F::poll(Pin::new(&mut **self), lw)
|
||||
fn poll(mut self: Pin<&mut Self>, waker: &Waker) -> Poll<Self::Output> {
|
||||
F::poll(Pin::new(&mut **self), waker)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -115,7 +107,7 @@ where
|
|||
{
|
||||
type Output = <<P as ops::Deref>::Target as Future>::Output;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, lw: &LocalWaker) -> Poll<Self::Output> {
|
||||
Pin::get_mut(self).as_mut().poll(lw)
|
||||
fn poll(self: Pin<&mut Self>, waker: &Waker) -> Poll<Self::Output> {
|
||||
Pin::get_mut(self).as_mut().poll(waker)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,7 +78,7 @@ impl<T: ?Sized> !Send for *mut T { }
|
|||
/// // be made into an object
|
||||
/// ```
|
||||
///
|
||||
/// [trait object]: ../../book/first-edition/trait-objects.html
|
||||
/// [trait object]: ../../book/ch17-02-trait-objects.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[lang = "sized"]
|
||||
#[rustc_on_unimplemented(
|
||||
|
@ -518,7 +518,7 @@ macro_rules! impls{
|
|||
/// types. We track the Rust type using a phantom type parameter on
|
||||
/// the struct `ExternalResource` which wraps a handle.
|
||||
///
|
||||
/// [FFI]: ../../book/first-edition/ffi.html
|
||||
/// [FFI]: ../../book/ch19-01-unsafe-rust.html#using-extern-functions-to-call-external-code
|
||||
///
|
||||
/// ```
|
||||
/// # #![allow(dead_code)]
|
||||
|
|
|
@ -299,7 +299,7 @@ pub const fn size_of<T>() -> usize {
|
|||
/// then `size_of_val` can be used to get the dynamically-known size.
|
||||
///
|
||||
/// [slice]: ../../std/primitive.slice.html
|
||||
/// [trait object]: ../../book/first-edition/trait-objects.html
|
||||
/// [trait object]: ../../book/ch17-02-trait-objects.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
|
@ -8,4 +8,4 @@ mod poll;
|
|||
pub use self::poll::Poll;
|
||||
|
||||
mod wake;
|
||||
pub use self::wake::{Waker, LocalWaker, UnsafeWake};
|
||||
pub use self::wake::{Waker, RawWaker, RawWakerVTable};
|
||||
|
|
|
@ -4,16 +4,92 @@
|
|||
|
||||
use fmt;
|
||||
use marker::Unpin;
|
||||
use ptr::NonNull;
|
||||
|
||||
/// A `RawWaker` allows the implementor of a task executor to create a [`Waker`]
|
||||
/// which provides customized wakeup behavior.
|
||||
///
|
||||
/// [vtable]: https://en.wikipedia.org/wiki/Virtual_method_table
|
||||
///
|
||||
/// It consists of a data pointer and a [virtual function pointer table (vtable)][vtable] that
|
||||
/// customizes the behavior of the `RawWaker`.
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub struct RawWaker {
|
||||
/// A data pointer, which can be used to store arbitrary data as required
|
||||
/// by the executor. This could be e.g. a type-erased pointer to an `Arc`
|
||||
/// that is associated with the task.
|
||||
/// The value of this field gets passed to all functions that are part of
|
||||
/// the vtable as the first parameter.
|
||||
data: *const (),
|
||||
/// Virtual function pointer table that customizes the behavior of this waker.
|
||||
vtable: &'static RawWakerVTable,
|
||||
}
|
||||
|
||||
impl RawWaker {
|
||||
/// Creates a new `RawWaker` from the provided `data` pointer and `vtable`.
|
||||
///
|
||||
/// The `data` pointer can be used to store arbitrary data as required
|
||||
/// by the executor. This could be e.g. a type-erased pointer to an `Arc`
|
||||
/// that is associated with the task.
|
||||
/// The value of this poiner will get passed to all functions that are part
|
||||
/// of the `vtable` as the first parameter.
|
||||
///
|
||||
/// The `vtable` customizes the behavior of a `Waker` which gets created
|
||||
/// from a `RawWaker`. For each operation on the `Waker`, the associated
|
||||
/// function in the `vtable` of the underlying `RawWaker` will be called.
|
||||
pub const fn new(data: *const (), vtable: &'static RawWakerVTable) -> RawWaker {
|
||||
RawWaker {
|
||||
data,
|
||||
vtable,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A virtual function pointer table (vtable) that specifies the behavior
|
||||
/// of a [`RawWaker`].
|
||||
///
|
||||
/// The pointer passed to all functions inside the vtable is the `data` pointer
|
||||
/// from the enclosing [`RawWaker`] object.
|
||||
///
|
||||
/// The functions inside this struct are only intended be called on the `data`
|
||||
/// pointer of a properly constructed [`RawWaker`] object from inside the
|
||||
/// [`RawWaker`] implementation. Calling one of the contained functions using
|
||||
/// any other `data` pointer will cause undefined behavior.
|
||||
#[derive(PartialEq, Copy, Clone, Debug)]
|
||||
pub struct RawWakerVTable {
|
||||
/// This function will be called when the [`RawWaker`] gets cloned, e.g. when
|
||||
/// the [`Waker`] in which the [`RawWaker`] is stored gets cloned.
|
||||
///
|
||||
/// The implementation of this function must retain all resources that are
|
||||
/// required for this additional instance of a [`RawWaker`] and associated
|
||||
/// task. Calling `wake` on the resulting [`RawWaker`] should result in a wakeup
|
||||
/// of the same task that would have been awoken by the original [`RawWaker`].
|
||||
pub clone: unsafe fn(*const ()) -> RawWaker,
|
||||
|
||||
/// This function will be called when `wake` is called on the [`Waker`].
|
||||
/// It must wake up the task associated with this [`RawWaker`].
|
||||
///
|
||||
/// The implemention of this function must not consume the provided data
|
||||
/// pointer.
|
||||
pub wake: unsafe fn(*const ()),
|
||||
|
||||
/// This function gets called when a [`RawWaker`] gets dropped.
|
||||
///
|
||||
/// The implementation of this function must make sure to release any
|
||||
/// resources that are associated with this instance of a [`RawWaker`] and
|
||||
/// associated task.
|
||||
pub drop: unsafe fn(*const ()),
|
||||
}
|
||||
|
||||
/// A `Waker` is a handle for waking up a task by notifying its executor that it
|
||||
/// is ready to be run.
|
||||
///
|
||||
/// This handle contains a trait object pointing to an instance of the `UnsafeWake`
|
||||
/// trait, allowing notifications to get routed through it.
|
||||
/// This handle encapsulates a [`RawWaker`] instance, which defines the
|
||||
/// executor-specific wakeup behavior.
|
||||
///
|
||||
/// Implements [`Clone`], [`Send`], and [`Sync`].
|
||||
#[repr(transparent)]
|
||||
pub struct Waker {
|
||||
inner: NonNull<dyn UnsafeWake>,
|
||||
waker: RawWaker,
|
||||
}
|
||||
|
||||
impl Unpin for Waker {}
|
||||
|
@ -21,264 +97,66 @@ unsafe impl Send for Waker {}
|
|||
unsafe impl Sync for Waker {}
|
||||
|
||||
impl Waker {
|
||||
/// Constructs a new `Waker` directly.
|
||||
///
|
||||
/// Note that most code will not need to call this. Implementers of the
|
||||
/// `UnsafeWake` trait will typically provide a wrapper that calls this
|
||||
/// but you otherwise shouldn't call it directly.
|
||||
///
|
||||
/// If you're working with the standard library then it's recommended to
|
||||
/// use the `Waker::from` function instead which works with the safe
|
||||
/// `Arc` type and the safe `Wake` trait.
|
||||
#[inline]
|
||||
pub unsafe fn new(inner: NonNull<dyn UnsafeWake>) -> Self {
|
||||
Waker { inner }
|
||||
}
|
||||
|
||||
/// Wake up the task associated with this `Waker`.
|
||||
#[inline]
|
||||
pub fn wake(&self) {
|
||||
unsafe { self.inner.as_ref().wake() }
|
||||
// The actual wakeup call is delegated through a virtual function call
|
||||
// to the implementation which is defined by the executor.
|
||||
|
||||
// SAFETY: This is safe because `Waker::new_unchecked` is the only way
|
||||
// to initialize `wake` and `data` requiring the user to acknowledge
|
||||
// that the contract of `RawWaker` is upheld.
|
||||
unsafe { (self.waker.vtable.wake)(self.waker.data) }
|
||||
}
|
||||
|
||||
/// Returns `true` if or not this `Waker` and `other` awaken the same task.
|
||||
/// Returns whether or not this `Waker` and other `Waker` have awaken the same task.
|
||||
///
|
||||
/// This function works on a best-effort basis, and may return false even
|
||||
/// when the `Waker`s would awaken the same task. However, if this function
|
||||
/// returns `true`, it is guaranteed that the `Waker`s will awaken the same
|
||||
/// task.
|
||||
/// returns `true`, it is guaranteed that the `Waker`s will awaken the same task.
|
||||
///
|
||||
/// This function is primarily used for optimization purposes.
|
||||
#[inline]
|
||||
pub fn will_wake(&self, other: &Waker) -> bool {
|
||||
self.inner == other.inner
|
||||
self.waker == other.waker
|
||||
}
|
||||
|
||||
/// Returns `true` if or not this `Waker` and `other` `LocalWaker` awaken
|
||||
/// the same task.
|
||||
/// Creates a new `Waker` from [`RawWaker`].
|
||||
///
|
||||
/// This function works on a best-effort basis, and may return false even
|
||||
/// when the `Waker`s would awaken the same task. However, if this function
|
||||
/// returns true, it is guaranteed that the `Waker`s will awaken the same
|
||||
/// task.
|
||||
///
|
||||
/// This function is primarily used for optimization purposes.
|
||||
#[inline]
|
||||
pub fn will_wake_local(&self, other: &LocalWaker) -> bool {
|
||||
self.will_wake(&other.0)
|
||||
/// The behavior of the returned `Waker` is undefined if the contract defined
|
||||
/// in [`RawWaker`]'s and [`RawWakerVTable`]'s documentation is not upheld.
|
||||
/// Therefore this method is unsafe.
|
||||
pub unsafe fn new_unchecked(waker: RawWaker) -> Waker {
|
||||
Waker {
|
||||
waker,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Waker {
|
||||
#[inline]
|
||||
fn clone(&self) -> Self {
|
||||
unsafe {
|
||||
self.inner.as_ref().clone_raw()
|
||||
Waker {
|
||||
// SAFETY: This is safe because `Waker::new_unchecked` is the only way
|
||||
// to initialize `clone` and `data` requiring the user to acknowledge
|
||||
// that the contract of [`RawWaker`] is upheld.
|
||||
waker: unsafe { (self.waker.vtable.clone)(self.waker.data) },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Waker {
|
||||
fn drop(&mut self) {
|
||||
// SAFETY: This is safe because `Waker::new_unchecked` is the only way
|
||||
// to initialize `drop` and `data` requiring the user to acknowledge
|
||||
// that the contract of `RawWaker` is upheld.
|
||||
unsafe { (self.waker.vtable.drop)(self.waker.data) }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Waker {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let vtable_ptr = self.waker.vtable as *const RawWakerVTable;
|
||||
f.debug_struct("Waker")
|
||||
.field("data", &self.waker.data)
|
||||
.field("vtable", &vtable_ptr)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Waker {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
self.inner.as_ref().drop_raw()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A `LocalWaker` is a handle for waking up a task by notifying its executor that it
|
||||
/// is ready to be run.
|
||||
///
|
||||
/// This is similar to the `Waker` type, but cannot be sent across threads.
|
||||
/// Task executors can use this type to implement more optimized single-threaded wakeup
|
||||
/// behavior.
|
||||
#[repr(transparent)]
|
||||
#[derive(Clone)]
|
||||
pub struct LocalWaker(Waker);
|
||||
|
||||
impl Unpin for LocalWaker {}
|
||||
impl !Send for LocalWaker {}
|
||||
impl !Sync for LocalWaker {}
|
||||
|
||||
impl LocalWaker {
|
||||
/// Constructs a new `LocalWaker` directly.
|
||||
///
|
||||
/// Note that most code will not need to call this. Implementers of the
|
||||
/// `UnsafeWake` trait will typically provide a wrapper that calls this
|
||||
/// but you otherwise shouldn't call it directly.
|
||||
///
|
||||
/// If you're working with the standard library then it's recommended to
|
||||
/// use the `local_waker_from_nonlocal` or `local_waker` to convert a `Waker`
|
||||
/// into a `LocalWaker`.
|
||||
///
|
||||
/// For this function to be used safely, it must be sound to call `inner.wake_local()`
|
||||
/// on the current thread.
|
||||
#[inline]
|
||||
pub unsafe fn new(inner: NonNull<dyn UnsafeWake>) -> Self {
|
||||
LocalWaker(Waker::new(inner))
|
||||
}
|
||||
|
||||
/// Borrows this `LocalWaker` as a `Waker`.
|
||||
///
|
||||
/// `Waker` is nearly identical to `LocalWaker`, but is threadsafe
|
||||
/// (implements `Send` and `Sync`).
|
||||
#[inline]
|
||||
pub fn as_waker(&self) -> &Waker {
|
||||
&self.0
|
||||
}
|
||||
|
||||
/// Converts this `LocalWaker` into a `Waker`.
|
||||
///
|
||||
/// `Waker` is nearly identical to `LocalWaker`, but is threadsafe
|
||||
/// (implements `Send` and `Sync`).
|
||||
#[inline]
|
||||
pub fn into_waker(self) -> Waker {
|
||||
self.0
|
||||
}
|
||||
|
||||
/// Wake up the task associated with this `LocalWaker`.
|
||||
#[inline]
|
||||
pub fn wake(&self) {
|
||||
unsafe { self.0.inner.as_ref().wake_local() }
|
||||
}
|
||||
|
||||
/// Returns `true` if or not this `LocalWaker` and `other` `LocalWaker` awaken the same task.
|
||||
///
|
||||
/// This function works on a best-effort basis, and may return false even
|
||||
/// when the `LocalWaker`s would awaken the same task. However, if this function
|
||||
/// returns true, it is guaranteed that the `LocalWaker`s will awaken the same
|
||||
/// task.
|
||||
///
|
||||
/// This function is primarily used for optimization purposes.
|
||||
#[inline]
|
||||
pub fn will_wake(&self, other: &LocalWaker) -> bool {
|
||||
self.0.will_wake(&other.0)
|
||||
}
|
||||
|
||||
/// Returns `true` if or not this `LocalWaker` and `other` `Waker` awaken the same task.
|
||||
///
|
||||
/// This function works on a best-effort basis, and may return false even
|
||||
/// when the `Waker`s would awaken the same task. However, if this function
|
||||
/// returns true, it is guaranteed that the `LocalWaker`s will awaken the same
|
||||
/// task.
|
||||
///
|
||||
/// This function is primarily used for optimization purposes.
|
||||
#[inline]
|
||||
pub fn will_wake_nonlocal(&self, other: &Waker) -> bool {
|
||||
self.0.will_wake(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<LocalWaker> for Waker {
|
||||
/// Converts a `LocalWaker` into a `Waker`.
|
||||
///
|
||||
/// This conversion turns a `!Sync` `LocalWaker` into a `Sync` `Waker`, allowing a wakeup
|
||||
/// object to be sent to another thread, but giving up its ability to do specialized
|
||||
/// thread-local wakeup behavior.
|
||||
#[inline]
|
||||
fn from(local_waker: LocalWaker) -> Self {
|
||||
local_waker.0
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for LocalWaker {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("LocalWaker")
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// An unsafe trait for implementing custom memory management for a `Waker` or `LocalWaker`.
|
||||
///
|
||||
/// A `Waker` conceptually is a cloneable trait object for `Wake`, and is
|
||||
/// most often essentially just `Arc<dyn Wake>`. However, in some contexts
|
||||
/// (particularly `no_std`), it's desirable to avoid `Arc` in favor of some
|
||||
/// custom memory management strategy. This trait is designed to allow for such
|
||||
/// customization.
|
||||
///
|
||||
/// When using `std`, a default implementation of the `UnsafeWake` trait is provided for
|
||||
/// `Arc<T>` where `T: Wake`.
|
||||
pub unsafe trait UnsafeWake: Send + Sync {
|
||||
/// Creates a clone of this `UnsafeWake` and stores it behind a `Waker`.
|
||||
///
|
||||
/// This function will create a new uniquely owned handle that under the
|
||||
/// hood references the same notification instance. In other words calls
|
||||
/// to `wake` on the returned handle should be equivalent to calls to
|
||||
/// `wake` on this handle.
|
||||
///
|
||||
/// # Unsafety
|
||||
///
|
||||
/// This function is unsafe to call because it's asserting the `UnsafeWake`
|
||||
/// value is in a consistent state, i.e., hasn't been dropped.
|
||||
unsafe fn clone_raw(&self) -> Waker;
|
||||
|
||||
/// Drops this instance of `UnsafeWake`, deallocating resources
|
||||
/// associated with it.
|
||||
///
|
||||
// FIXME(cramertj):
|
||||
/// This method is intended to have a signature such as:
|
||||
///
|
||||
/// ```ignore (not-a-doctest)
|
||||
/// fn drop_raw(self: *mut Self);
|
||||
/// ```
|
||||
///
|
||||
/// Unfortunately, in Rust today that signature is not object safe.
|
||||
/// Nevertheless it's recommended to implement this function *as if* that
|
||||
/// were its signature. As such it is not safe to call on an invalid
|
||||
/// pointer, nor is the validity of the pointer guaranteed after this
|
||||
/// function returns.
|
||||
///
|
||||
/// # Unsafety
|
||||
///
|
||||
/// This function is unsafe to call because it's asserting the `UnsafeWake`
|
||||
/// value is in a consistent state, i.e., hasn't been dropped.
|
||||
unsafe fn drop_raw(&self);
|
||||
|
||||
/// Indicates that the associated task is ready to make progress and should
|
||||
/// be `poll`ed.
|
||||
///
|
||||
/// Executors generally maintain a queue of "ready" tasks; `wake` should place
|
||||
/// the associated task onto this queue.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Implementations should avoid panicking, but clients should also be prepared
|
||||
/// for panics.
|
||||
///
|
||||
/// # Unsafety
|
||||
///
|
||||
/// This function is unsafe to call because it's asserting the `UnsafeWake`
|
||||
/// value is in a consistent state, i.e., hasn't been dropped.
|
||||
unsafe fn wake(&self);
|
||||
|
||||
/// Indicates that the associated task is ready to make progress and should
|
||||
/// be `poll`ed. This function is the same as `wake`, but can only be called
|
||||
/// from the thread that this `UnsafeWake` is "local" to. This allows for
|
||||
/// implementors to provide specialized wakeup behavior specific to the current
|
||||
/// thread. This function is called by `LocalWaker::wake`.
|
||||
///
|
||||
/// Executors generally maintain a queue of "ready" tasks; `wake_local` should place
|
||||
/// the associated task onto this queue.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Implementations should avoid panicking, but clients should also be prepared
|
||||
/// for panics.
|
||||
///
|
||||
/// # Unsafety
|
||||
///
|
||||
/// This function is unsafe to call because it's asserting the `UnsafeWake`
|
||||
/// value is in a consistent state, i.e., hasn't been dropped, and that the
|
||||
/// `UnsafeWake` hasn't moved from the thread on which it was created.
|
||||
unsafe fn wake_local(&self) {
|
||||
self.wake()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,9 @@
|
|||
//! function-like macros `#[proc_macro]`, macro attributes `#[proc_macro_attribute]` and
|
||||
//! custom derive attributes`#[proc_macro_derive]`.
|
||||
//!
|
||||
//! See [the book](../book/first-edition/procedural-macros.html) for more.
|
||||
//! See [the book] for more.
|
||||
//!
|
||||
//! [the book]: ../book/ch19-06-macros.html#procedural-macros-for-generating-code-from-attributes
|
||||
|
||||
#![stable(feature = "proc_macro_lib", since = "1.15.0")]
|
||||
#![deny(missing_docs)]
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// ignore-tidy-linelength
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
// Error messages for EXXXX errors.
|
||||
|
@ -410,7 +411,7 @@ fn baz<'a>(x: &'a str, y: &str) -> &str { }
|
|||
Lifetime elision in implementation headers was part of the lifetime elision
|
||||
RFC. It is, however, [currently unimplemented][iss15872].
|
||||
|
||||
[book-le]: https://doc.rust-lang.org/nightly/book/first-edition/lifetimes.html#lifetime-elision
|
||||
[book-le]: https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html#lifetime-elision
|
||||
[iss15872]: https://github.com/rust-lang/rust/issues/15872
|
||||
"##,
|
||||
|
||||
|
@ -646,7 +647,9 @@ attributes:
|
|||
#![no_std]
|
||||
```
|
||||
|
||||
See also https://doc.rust-lang.org/book/first-edition/no-stdlib.html
|
||||
See also the [unstable book][1].
|
||||
|
||||
[1]: https://doc.rust-lang.org/unstable-book/language-features/lang-items.html#writing-an-executable-without-stdlib
|
||||
"##,
|
||||
|
||||
E0214: r##"
|
||||
|
@ -1713,7 +1716,7 @@ fn main() {
|
|||
```
|
||||
|
||||
To understand better how closures work in Rust, read:
|
||||
https://doc.rust-lang.org/book/first-edition/closures.html
|
||||
https://doc.rust-lang.org/book/ch13-01-closures.html
|
||||
"##,
|
||||
|
||||
E0580: r##"
|
||||
|
|
|
@ -3859,7 +3859,7 @@ impl<'a> LoweringContext<'a> {
|
|||
hir::ExprKind::Call(f, args.iter().map(|x| self.lower_expr(x)).collect())
|
||||
}
|
||||
ExprKind::MethodCall(ref seg, ref args) => {
|
||||
let hir_seg = self.lower_path_segment(
|
||||
let hir_seg = P(self.lower_path_segment(
|
||||
e.span,
|
||||
seg,
|
||||
ParamMode::Optional,
|
||||
|
@ -3867,7 +3867,7 @@ impl<'a> LoweringContext<'a> {
|
|||
ParenthesizedGenericArgs::Err,
|
||||
ImplTraitContext::disallowed(),
|
||||
None,
|
||||
);
|
||||
));
|
||||
let args = args.iter().map(|x| self.lower_expr(x)).collect();
|
||||
hir::ExprKind::MethodCall(hir_seg, seg.ident.span, args)
|
||||
}
|
||||
|
@ -4148,7 +4148,7 @@ impl<'a> LoweringContext<'a> {
|
|||
node: if is_unit {
|
||||
hir::ExprKind::Path(struct_path)
|
||||
} else {
|
||||
hir::ExprKind::Struct(struct_path, fields, None)
|
||||
hir::ExprKind::Struct(P(struct_path), fields, None)
|
||||
},
|
||||
span: e.span,
|
||||
attrs: e.attrs.clone(),
|
||||
|
@ -4220,13 +4220,13 @@ impl<'a> LoweringContext<'a> {
|
|||
hir::ExprKind::InlineAsm(P(hir_asm), outputs, inputs)
|
||||
}
|
||||
ExprKind::Struct(ref path, ref fields, ref maybe_expr) => hir::ExprKind::Struct(
|
||||
self.lower_qpath(
|
||||
P(self.lower_qpath(
|
||||
e.id,
|
||||
&None,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
ImplTraitContext::disallowed(),
|
||||
),
|
||||
)),
|
||||
fields.iter().map(|x| self.lower_field(x)).collect(),
|
||||
maybe_expr.as_ref().map(|x| P(self.lower_expr(x))),
|
||||
),
|
||||
|
|
|
@ -1319,6 +1319,10 @@ pub struct Expr {
|
|||
pub hir_id: HirId,
|
||||
}
|
||||
|
||||
// `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
static_assert!(MEM_SIZE_OF_EXPR: std::mem::size_of::<Expr>() == 72);
|
||||
|
||||
impl Expr {
|
||||
pub fn precedence(&self) -> ExprPrecedence {
|
||||
match self.node {
|
||||
|
@ -1438,7 +1442,7 @@ pub enum ExprKind {
|
|||
/// and the remaining elements are the rest of the arguments.
|
||||
/// Thus, `x.foo::<Bar, Baz>(a, b, c, d)` is represented as
|
||||
/// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, [x, a, b, c, d])`.
|
||||
MethodCall(PathSegment, Span, HirVec<Expr>),
|
||||
MethodCall(P<PathSegment>, Span, HirVec<Expr>),
|
||||
/// A tuple (e.g., `(a, b, c ,d)`).
|
||||
Tup(HirVec<Expr>),
|
||||
/// A binary operation (e.g., `a + b`, `a * b`).
|
||||
|
@ -1506,7 +1510,7 @@ pub enum ExprKind {
|
|||
///
|
||||
/// For example, `Foo {x: 1, y: 2}`, or
|
||||
/// `Foo {x: 1, .. base}`, where `base` is the `Option<Expr>`.
|
||||
Struct(QPath, HirVec<Field>, Option<P<Expr>>),
|
||||
Struct(P<QPath>, HirVec<Field>, Option<P<Expr>>),
|
||||
|
||||
/// An array literal constructed from one repeated element.
|
||||
///
|
||||
|
|
|
@ -508,22 +508,31 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
ObligationCauseCode::MatchExpressionArm { arm_span, source } => match source {
|
||||
ObligationCauseCode::MatchExpressionArm {
|
||||
source,
|
||||
ref prior_arms,
|
||||
last_ty,
|
||||
..
|
||||
} => match source {
|
||||
hir::MatchSource::IfLetDesugar { .. } => {
|
||||
let msg = "`if let` arm with an incompatible type";
|
||||
if self.tcx.sess.source_map().is_multiline(arm_span) {
|
||||
err.span_note(arm_span, msg);
|
||||
} else {
|
||||
err.span_label(arm_span, msg);
|
||||
}
|
||||
let msg = "`if let` arms have incompatible types";
|
||||
err.span_label(cause.span, msg);
|
||||
}
|
||||
hir::MatchSource::TryDesugar => {}
|
||||
_ => {
|
||||
let msg = "match arm with an incompatible type";
|
||||
if self.tcx.sess.source_map().is_multiline(arm_span) {
|
||||
err.span_note(arm_span, msg);
|
||||
} else {
|
||||
err.span_label(arm_span, msg);
|
||||
let msg = "`match` arms have incompatible types";
|
||||
err.span_label(cause.span, msg);
|
||||
if prior_arms.len() <= 4 {
|
||||
for sp in prior_arms {
|
||||
err.span_label(*sp, format!(
|
||||
"this is found to be of type `{}`",
|
||||
last_ty,
|
||||
));
|
||||
}
|
||||
} else if let Some(sp) = prior_arms.last() {
|
||||
err.span_label(*sp, format!(
|
||||
"this and all prior arms are found to be of type `{}`", last_ty,
|
||||
));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -557,7 +557,7 @@ impl BuiltinLintDiagnostics {
|
|||
}
|
||||
BuiltinLintDiagnostics::UnusedImports(message, replaces) => {
|
||||
if !replaces.is_empty() {
|
||||
db.multipart_suggestion(
|
||||
db.tool_only_multipart_suggestion(
|
||||
&message,
|
||||
replaces,
|
||||
Applicability::MachineApplicable,
|
||||
|
|
|
@ -145,6 +145,7 @@ impl<'tcx> ObligationCause<'tcx> {
|
|||
ObligationCauseCode::StartFunctionType => {
|
||||
tcx.sess.source_map().def_span(self.span)
|
||||
}
|
||||
ObligationCauseCode::MatchExpressionArm { arm_span, .. } => arm_span,
|
||||
_ => self.span,
|
||||
}
|
||||
}
|
||||
|
@ -223,6 +224,8 @@ pub enum ObligationCauseCode<'tcx> {
|
|||
MatchExpressionArm {
|
||||
arm_span: Span,
|
||||
source: hir::MatchSource,
|
||||
prior_arms: Vec<Span>,
|
||||
last_ty: Ty<'tcx>,
|
||||
},
|
||||
|
||||
/// Computing common supertype in the pattern guard for the arms of a match expression
|
||||
|
|
|
@ -513,10 +513,21 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
|
|||
trait_item_def_id,
|
||||
}),
|
||||
super::ExprAssignable => Some(super::ExprAssignable),
|
||||
super::MatchExpressionArm { arm_span, source } => Some(super::MatchExpressionArm {
|
||||
super::MatchExpressionArm {
|
||||
arm_span,
|
||||
source: source,
|
||||
}),
|
||||
source,
|
||||
ref prior_arms,
|
||||
last_ty,
|
||||
} => {
|
||||
tcx.lift(&last_ty).map(|last_ty| {
|
||||
super::MatchExpressionArm {
|
||||
arm_span,
|
||||
source,
|
||||
prior_arms: prior_arms.clone(),
|
||||
last_ty,
|
||||
}
|
||||
})
|
||||
}
|
||||
super::MatchExpressionArmPattern { span, ty } => {
|
||||
tcx.lift(&ty).map(|ty| super::MatchExpressionArmPattern { span, ty })
|
||||
}
|
||||
|
|
|
@ -465,6 +465,20 @@ impl CodegenCx<'b, 'tcx> {
|
|||
self.declare_intrinsic(key).unwrap_or_else(|| bug!("unknown intrinsic '{}'", key))
|
||||
}
|
||||
|
||||
fn insert_intrinsic(
|
||||
&self, name: &'static str, args: Option<&[&'b llvm::Type]>, ret: &'b llvm::Type
|
||||
) -> &'b llvm::Value {
|
||||
let fn_ty = if let Some(args) = args {
|
||||
self.type_func(args, ret)
|
||||
} else {
|
||||
self.type_variadic_func(&[], ret)
|
||||
};
|
||||
let f = self.declare_cfn(name, fn_ty);
|
||||
llvm::SetUnnamedAddr(f, false);
|
||||
self.intrinsics.borrow_mut().insert(name, f.clone());
|
||||
f
|
||||
}
|
||||
|
||||
fn declare_intrinsic(
|
||||
&self,
|
||||
key: &str
|
||||
|
@ -472,26 +486,17 @@ impl CodegenCx<'b, 'tcx> {
|
|||
macro_rules! ifn {
|
||||
($name:expr, fn() -> $ret:expr) => (
|
||||
if key == $name {
|
||||
let f = self.declare_cfn($name, self.type_func(&[], $ret));
|
||||
llvm::SetUnnamedAddr(f, false);
|
||||
self.intrinsics.borrow_mut().insert($name, f.clone());
|
||||
return Some(f);
|
||||
return Some(self.insert_intrinsic($name, Some(&[]), $ret));
|
||||
}
|
||||
);
|
||||
($name:expr, fn(...) -> $ret:expr) => (
|
||||
if key == $name {
|
||||
let f = self.declare_cfn($name, self.type_variadic_func(&[], $ret));
|
||||
llvm::SetUnnamedAddr(f, false);
|
||||
self.intrinsics.borrow_mut().insert($name, f.clone());
|
||||
return Some(f);
|
||||
return Some(self.insert_intrinsic($name, None, $ret));
|
||||
}
|
||||
);
|
||||
($name:expr, fn($($arg:expr),*) -> $ret:expr) => (
|
||||
if key == $name {
|
||||
let f = self.declare_cfn($name, self.type_func(&[$($arg),*], $ret));
|
||||
llvm::SetUnnamedAddr(f, false);
|
||||
self.intrinsics.borrow_mut().insert($name, f.clone());
|
||||
return Some(f);
|
||||
return Some(self.insert_intrinsic($name, Some(&[$($arg),*]), $ret));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::CodeSuggestion;
|
||||
use crate::SuggestionStyle;
|
||||
use crate::SubstitutionPart;
|
||||
use crate::Substitution;
|
||||
use crate::Applicability;
|
||||
|
@ -243,7 +244,33 @@ impl Diagnostic {
|
|||
.collect(),
|
||||
}],
|
||||
msg: msg.to_owned(),
|
||||
show_code_when_inline: true,
|
||||
style: SuggestionStyle::ShowCode,
|
||||
applicability,
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
/// Prints out a message with for a multipart suggestion without showing the suggested code.
|
||||
///
|
||||
/// This is intended to be used for suggestions that are obvious in what the changes need to
|
||||
/// be from the message, showing the span label inline would be visually unpleasant
|
||||
/// (marginally overlapping spans or multiline spans) and showing the snippet window wouldn't
|
||||
/// improve understandability.
|
||||
pub fn tool_only_multipart_suggestion(
|
||||
&mut self,
|
||||
msg: &str,
|
||||
suggestion: Vec<(Span, String)>,
|
||||
applicability: Applicability,
|
||||
) -> &mut Self {
|
||||
self.suggestions.push(CodeSuggestion {
|
||||
substitutions: vec![Substitution {
|
||||
parts: suggestion
|
||||
.into_iter()
|
||||
.map(|(span, snippet)| SubstitutionPart { snippet, span })
|
||||
.collect(),
|
||||
}],
|
||||
msg: msg.to_owned(),
|
||||
style: SuggestionStyle::CompletelyHidden,
|
||||
applicability,
|
||||
});
|
||||
self
|
||||
|
@ -277,7 +304,7 @@ impl Diagnostic {
|
|||
}],
|
||||
}],
|
||||
msg: msg.to_owned(),
|
||||
show_code_when_inline: true,
|
||||
style: SuggestionStyle::ShowCode,
|
||||
applicability,
|
||||
});
|
||||
self
|
||||
|
@ -295,7 +322,7 @@ impl Diagnostic {
|
|||
}],
|
||||
}).collect(),
|
||||
msg: msg.to_owned(),
|
||||
show_code_when_inline: true,
|
||||
style: SuggestionStyle::ShowCode,
|
||||
applicability,
|
||||
});
|
||||
self
|
||||
|
@ -316,7 +343,51 @@ impl Diagnostic {
|
|||
}],
|
||||
}],
|
||||
msg: msg.to_owned(),
|
||||
show_code_when_inline: false,
|
||||
style: SuggestionStyle::HideCodeInline,
|
||||
applicability,
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
/// Prints out a message with for a suggestion without showing the suggested code.
|
||||
///
|
||||
/// This is intended to be used for suggestions that are obvious in what the changes need to
|
||||
/// be from the message, showing the span label inline would be visually unpleasant
|
||||
/// (marginally overlapping spans or multiline spans) and showing the snippet window wouldn't
|
||||
/// improve understandability.
|
||||
pub fn span_suggestion_hidden(
|
||||
&mut self, sp: Span, msg: &str, suggestion: String, applicability: Applicability
|
||||
) -> &mut Self {
|
||||
self.suggestions.push(CodeSuggestion {
|
||||
substitutions: vec![Substitution {
|
||||
parts: vec![SubstitutionPart {
|
||||
snippet: suggestion,
|
||||
span: sp,
|
||||
}],
|
||||
}],
|
||||
msg: msg.to_owned(),
|
||||
style: SuggestionStyle::HideCodeInline,
|
||||
applicability,
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
/// Adds a suggestion to the json output, but otherwise remains silent/undisplayed in the cli.
|
||||
///
|
||||
/// This is intended to be used for suggestions that are *very* obvious in what the changes
|
||||
/// need to be from the message, but we still want other tools to be able to apply them.
|
||||
pub fn tool_only_span_suggestion(
|
||||
&mut self, sp: Span, msg: &str, suggestion: String, applicability: Applicability
|
||||
) -> &mut Self {
|
||||
self.suggestions.push(CodeSuggestion {
|
||||
substitutions: vec![Substitution {
|
||||
parts: vec![SubstitutionPart {
|
||||
snippet: suggestion,
|
||||
span: sp,
|
||||
}],
|
||||
}],
|
||||
msg: msg.to_owned(),
|
||||
style: SuggestionStyle::CompletelyHidden,
|
||||
applicability: applicability,
|
||||
});
|
||||
self
|
||||
|
|
|
@ -205,6 +205,24 @@ impl<'a> DiagnosticBuilder<'a> {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn tool_only_multipart_suggestion(
|
||||
&mut self,
|
||||
msg: &str,
|
||||
suggestion: Vec<(Span, String)>,
|
||||
applicability: Applicability,
|
||||
) -> &mut Self {
|
||||
if !self.allow_suggestions {
|
||||
return self
|
||||
}
|
||||
self.diagnostic.tool_only_multipart_suggestion(
|
||||
msg,
|
||||
suggestion,
|
||||
applicability,
|
||||
);
|
||||
self
|
||||
}
|
||||
|
||||
|
||||
pub fn span_suggestion(
|
||||
&mut self,
|
||||
sp: Span,
|
||||
|
@ -261,6 +279,45 @@ impl<'a> DiagnosticBuilder<'a> {
|
|||
);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn span_suggestion_hidden(
|
||||
&mut self,
|
||||
sp: Span,
|
||||
msg: &str,
|
||||
suggestion: String,
|
||||
applicability: Applicability,
|
||||
) -> &mut Self {
|
||||
if !self.allow_suggestions {
|
||||
return self
|
||||
}
|
||||
self.diagnostic.span_suggestion_hidden(
|
||||
sp,
|
||||
msg,
|
||||
suggestion,
|
||||
applicability,
|
||||
);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn tool_only_span_suggestion(
|
||||
&mut self,
|
||||
sp: Span,
|
||||
msg: &str,
|
||||
suggestion: String,
|
||||
applicability: Applicability,
|
||||
) -> &mut Self {
|
||||
if !self.allow_suggestions {
|
||||
return self
|
||||
}
|
||||
self.diagnostic.tool_only_span_suggestion(
|
||||
sp,
|
||||
msg,
|
||||
suggestion,
|
||||
applicability,
|
||||
);
|
||||
self
|
||||
}
|
||||
|
||||
forward!(pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self);
|
||||
forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self);
|
||||
|
||||
|
|
|
@ -2,7 +2,10 @@ use Destination::*;
|
|||
|
||||
use syntax_pos::{SourceFile, Span, MultiSpan};
|
||||
|
||||
use crate::{Level, CodeSuggestion, DiagnosticBuilder, SubDiagnostic, SourceMapperDyn, DiagnosticId};
|
||||
use crate::{
|
||||
Level, CodeSuggestion, DiagnosticBuilder, SubDiagnostic,
|
||||
SuggestionStyle, SourceMapperDyn, DiagnosticId,
|
||||
};
|
||||
use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, StyledString, Style};
|
||||
use crate::styled_buffer::StyledBuffer;
|
||||
|
||||
|
@ -43,9 +46,14 @@ impl Emitter for EmitterWriter {
|
|||
// don't display long messages as labels
|
||||
sugg.msg.split_whitespace().count() < 10 &&
|
||||
// don't display multiline suggestions as labels
|
||||
!sugg.substitutions[0].parts[0].snippet.contains('\n') {
|
||||
!sugg.substitutions[0].parts[0].snippet.contains('\n') &&
|
||||
// when this style is set we want the suggestion to be a message, not inline
|
||||
sugg.style != SuggestionStyle::HideCodeAlways &&
|
||||
// trivial suggestion for tooling's sake, never shown
|
||||
sugg.style != SuggestionStyle::CompletelyHidden
|
||||
{
|
||||
let substitution = &sugg.substitutions[0].parts[0].snippet.trim();
|
||||
let msg = if substitution.len() == 0 || !sugg.show_code_when_inline {
|
||||
let msg = if substitution.len() == 0 || sugg.style.hide_inline() {
|
||||
// This substitution is only removal or we explicitly don't want to show the
|
||||
// code inline, don't show it
|
||||
format!("help: {}", sugg.msg)
|
||||
|
@ -942,14 +950,15 @@ impl EmitterWriter {
|
|||
}
|
||||
}
|
||||
|
||||
fn emit_message_default(&mut self,
|
||||
msp: &MultiSpan,
|
||||
msg: &[(String, Style)],
|
||||
code: &Option<DiagnosticId>,
|
||||
level: &Level,
|
||||
max_line_num_len: usize,
|
||||
is_secondary: bool)
|
||||
-> io::Result<()> {
|
||||
fn emit_message_default(
|
||||
&mut self,
|
||||
msp: &MultiSpan,
|
||||
msg: &[(String, Style)],
|
||||
code: &Option<DiagnosticId>,
|
||||
level: &Level,
|
||||
max_line_num_len: usize,
|
||||
is_secondary: bool,
|
||||
) -> io::Result<()> {
|
||||
let mut buffer = StyledBuffer::new();
|
||||
let header_style = if is_secondary {
|
||||
Style::HeaderMsg
|
||||
|
@ -1184,11 +1193,12 @@ impl EmitterWriter {
|
|||
|
||||
}
|
||||
|
||||
fn emit_suggestion_default(&mut self,
|
||||
suggestion: &CodeSuggestion,
|
||||
level: &Level,
|
||||
max_line_num_len: usize)
|
||||
-> io::Result<()> {
|
||||
fn emit_suggestion_default(
|
||||
&mut self,
|
||||
suggestion: &CodeSuggestion,
|
||||
level: &Level,
|
||||
max_line_num_len: usize,
|
||||
) -> io::Result<()> {
|
||||
if let Some(ref sm) = self.sm {
|
||||
let mut buffer = StyledBuffer::new();
|
||||
|
||||
|
@ -1198,11 +1208,13 @@ impl EmitterWriter {
|
|||
buffer.append(0, &level_str, Style::Level(level.clone()));
|
||||
buffer.append(0, ": ", Style::HeaderMsg);
|
||||
}
|
||||
self.msg_to_buffer(&mut buffer,
|
||||
&[(suggestion.msg.to_owned(), Style::NoStyle)],
|
||||
max_line_num_len,
|
||||
"suggestion",
|
||||
Some(Style::HeaderMsg));
|
||||
self.msg_to_buffer(
|
||||
&mut buffer,
|
||||
&[(suggestion.msg.to_owned(), Style::NoStyle)],
|
||||
max_line_num_len,
|
||||
"suggestion",
|
||||
Some(Style::HeaderMsg),
|
||||
);
|
||||
|
||||
// Render the replacements for each suggestion
|
||||
let suggestions = suggestion.splice_lines(&**sm);
|
||||
|
@ -1340,22 +1352,42 @@ impl EmitterWriter {
|
|||
if !self.short_message {
|
||||
for child in children {
|
||||
let span = child.render_span.as_ref().unwrap_or(&child.span);
|
||||
match self.emit_message_default(&span,
|
||||
&child.styled_message(),
|
||||
&None,
|
||||
&child.level,
|
||||
max_line_num_len,
|
||||
true) {
|
||||
match self.emit_message_default(
|
||||
&span,
|
||||
&child.styled_message(),
|
||||
&None,
|
||||
&child.level,
|
||||
max_line_num_len,
|
||||
true,
|
||||
) {
|
||||
Err(e) => panic!("failed to emit error: {}", e),
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
for sugg in suggestions {
|
||||
match self.emit_suggestion_default(sugg,
|
||||
&Level::Help,
|
||||
max_line_num_len) {
|
||||
Err(e) => panic!("failed to emit error: {}", e),
|
||||
_ => ()
|
||||
if sugg.style == SuggestionStyle::CompletelyHidden {
|
||||
// do not display this suggestion, it is meant only for tools
|
||||
} else if sugg.style == SuggestionStyle::HideCodeAlways {
|
||||
match self.emit_message_default(
|
||||
&MultiSpan::new(),
|
||||
&[(sugg.msg.to_owned(), Style::HeaderMsg)],
|
||||
&None,
|
||||
&Level::Help,
|
||||
max_line_num_len,
|
||||
true,
|
||||
) {
|
||||
Err(e) => panic!("failed to emit error: {}", e),
|
||||
_ => ()
|
||||
}
|
||||
} else {
|
||||
match self.emit_suggestion_default(
|
||||
sugg,
|
||||
&Level::Help,
|
||||
max_line_num_len,
|
||||
) {
|
||||
Err(e) => panic!("failed to emit error: {}", e),
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,6 +69,29 @@ pub enum Applicability {
|
|||
Unspecified,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, RustcEncodable, RustcDecodable)]
|
||||
pub enum SuggestionStyle {
|
||||
/// Hide the suggested code when displaying this suggestion inline.
|
||||
HideCodeInline,
|
||||
/// Always hide the suggested code but display the message.
|
||||
HideCodeAlways,
|
||||
/// Do not display this suggestion in the cli output, it is only meant for tools.
|
||||
CompletelyHidden,
|
||||
/// Always show the suggested code.
|
||||
/// This will *not* show the code if the suggestion is inline *and* the suggested code is
|
||||
/// empty.
|
||||
ShowCode,
|
||||
}
|
||||
|
||||
impl SuggestionStyle {
|
||||
fn hide_inline(&self) -> bool {
|
||||
match *self {
|
||||
SuggestionStyle::ShowCode => false,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
|
||||
pub struct CodeSuggestion {
|
||||
/// Each substitute can have multiple variants due to multiple
|
||||
|
@ -94,7 +117,8 @@ pub struct CodeSuggestion {
|
|||
/// ```
|
||||
pub substitutions: Vec<Substitution>,
|
||||
pub msg: String,
|
||||
pub show_code_when_inline: bool,
|
||||
/// Visual representation of this suggestion.
|
||||
pub style: SuggestionStyle,
|
||||
/// Whether or not the suggestion is approximate
|
||||
///
|
||||
/// Sometimes we may show suggestions with placeholders,
|
||||
|
|
|
@ -37,7 +37,7 @@ extern {}
|
|||
```
|
||||
|
||||
See more:
|
||||
https://doc.rust-lang.org/book/first-edition/conditional-compilation.html
|
||||
https://doc.rust-lang.org/reference/attributes.html#conditional-compilation
|
||||
"##,
|
||||
|
||||
E0458: r##"
|
||||
|
|
|
@ -11,7 +11,7 @@ use rustc::hir::def::Def;
|
|||
use rustc::mir::interpret::{ConstEvalErr, ErrorHandled};
|
||||
use rustc::mir;
|
||||
use rustc::ty::{self, TyCtxt, query::TyCtxtAt};
|
||||
use rustc::ty::layout::{self, LayoutOf, TyLayout, VariantIdx};
|
||||
use rustc::ty::layout::{self, LayoutOf, VariantIdx};
|
||||
use rustc::ty::subst::Subst;
|
||||
use rustc::traits::Reveal;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
|
@ -21,7 +21,8 @@ use syntax::ast::Mutability;
|
|||
use syntax::source_map::{Span, DUMMY_SP};
|
||||
|
||||
use crate::interpret::{self,
|
||||
PlaceTy, MPlaceTy, MemPlace, OpTy, Operand, Immediate, Scalar, RawConst, ConstValue, Pointer,
|
||||
PlaceTy, MPlaceTy, MemPlace, OpTy, ImmTy, Operand, Immediate, Scalar, Pointer,
|
||||
RawConst, ConstValue,
|
||||
EvalResult, EvalError, EvalErrorKind, GlobalId, EvalContext, StackPopCleanup,
|
||||
Allocation, AllocId, MemoryKind,
|
||||
snapshot, RefTracking,
|
||||
|
@ -77,7 +78,7 @@ pub fn op_to_const<'tcx>(
|
|||
let normalized_op = if normalize {
|
||||
ecx.try_read_immediate(op)?
|
||||
} else {
|
||||
match op.op {
|
||||
match *op {
|
||||
Operand::Indirect(mplace) => Err(mplace),
|
||||
Operand::Immediate(val) => Ok(val)
|
||||
}
|
||||
|
@ -105,15 +106,6 @@ pub fn op_to_const<'tcx>(
|
|||
Ok(ty::Const { val, ty: op.layout.ty })
|
||||
}
|
||||
|
||||
pub fn lazy_const_to_op<'tcx>(
|
||||
ecx: &CompileTimeEvalContext<'_, '_, 'tcx>,
|
||||
cnst: ty::LazyConst<'tcx>,
|
||||
ty: ty::Ty<'tcx>,
|
||||
) -> EvalResult<'tcx, OpTy<'tcx>> {
|
||||
let op = ecx.const_value_to_op(cnst)?;
|
||||
Ok(OpTy { op, layout: ecx.layout_of(ty)? })
|
||||
}
|
||||
|
||||
fn eval_body_and_ecx<'a, 'mir, 'tcx>(
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
cid: GlobalId<'tcx>,
|
||||
|
@ -388,10 +380,8 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx>
|
|||
fn ptr_op(
|
||||
_ecx: &EvalContext<'a, 'mir, 'tcx, Self>,
|
||||
_bin_op: mir::BinOp,
|
||||
_left: Scalar,
|
||||
_left_layout: TyLayout<'tcx>,
|
||||
_right: Scalar,
|
||||
_right_layout: TyLayout<'tcx>,
|
||||
_left: ImmTy<'tcx>,
|
||||
_right: ImmTy<'tcx>,
|
||||
) -> EvalResult<'tcx, (Scalar, bool)> {
|
||||
Err(
|
||||
ConstEvalError::NeedsRfc("pointer arithmetic or comparison".to_string()).into(),
|
||||
|
@ -486,7 +476,7 @@ pub fn const_field<'a, 'tcx>(
|
|||
let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env);
|
||||
let result = (|| {
|
||||
// get the operand again
|
||||
let op = lazy_const_to_op(&ecx, ty::LazyConst::Evaluated(value), value.ty)?;
|
||||
let op = ecx.lazy_const_to_op(ty::LazyConst::Evaluated(value), value.ty)?;
|
||||
// downcast
|
||||
let down = match variant {
|
||||
None => op,
|
||||
|
@ -512,7 +502,7 @@ pub fn const_variant_index<'a, 'tcx>(
|
|||
) -> EvalResult<'tcx, VariantIdx> {
|
||||
trace!("const_variant_index: {:?}", val);
|
||||
let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env);
|
||||
let op = lazy_const_to_op(&ecx, ty::LazyConst::Evaluated(val), val.ty)?;
|
||||
let op = ecx.lazy_const_to_op(ty::LazyConst::Evaluated(val), val.ty)?;
|
||||
Ok(ecx.read_discriminant(op)?.1)
|
||||
}
|
||||
|
||||
|
|
|
@ -690,7 +690,7 @@ fn main() {
|
|||
}
|
||||
```
|
||||
|
||||
See also https://doc.rust-lang.org/book/first-edition/unsafe.html
|
||||
See also https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html
|
||||
"##,
|
||||
|
||||
E0373: r##"
|
||||
|
@ -873,7 +873,7 @@ that at most one writer or multiple readers can access the data at any one time.
|
|||
If you wish to learn more about ownership in Rust, start with the chapter in the
|
||||
Book:
|
||||
|
||||
https://doc.rust-lang.org/book/first-edition/ownership.html
|
||||
https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html
|
||||
"##,
|
||||
|
||||
E0383: r##"
|
||||
|
@ -1207,7 +1207,7 @@ let mut a = &mut i;
|
|||
|
||||
Please note that in rust, you can either have many immutable references, or one
|
||||
mutable reference. Take a look at
|
||||
https://doc.rust-lang.org/stable/book/references-and-borrowing.html for more
|
||||
https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html for more
|
||||
information. Example:
|
||||
|
||||
|
||||
|
@ -1374,7 +1374,7 @@ fn foo(a: &mut i32) {
|
|||
```
|
||||
|
||||
For more information on the rust ownership system, take a look at
|
||||
https://doc.rust-lang.org/stable/book/references-and-borrowing.html.
|
||||
https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html.
|
||||
"##,
|
||||
|
||||
E0503: r##"
|
||||
|
@ -1430,7 +1430,7 @@ fn main() {
|
|||
```
|
||||
|
||||
You can find more information about borrowing in the rust-book:
|
||||
http://doc.rust-lang.org/stable/book/references-and-borrowing.html
|
||||
http://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html
|
||||
"##,
|
||||
|
||||
E0504: r##"
|
||||
|
@ -1614,7 +1614,7 @@ fn main() {
|
|||
```
|
||||
|
||||
You can find more information about borrowing in the rust-book:
|
||||
http://doc.rust-lang.org/stable/book/references-and-borrowing.html
|
||||
http://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html
|
||||
"##,
|
||||
|
||||
E0506: r##"
|
||||
|
@ -1825,7 +1825,7 @@ mem::replace(&mut borrowed.knight, TheDarkKnight).nothing_is_true(); // ok!
|
|||
```
|
||||
|
||||
You can find more information about borrowing in the rust-book:
|
||||
http://doc.rust-lang.org/book/first-edition/references-and-borrowing.html
|
||||
http://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html
|
||||
"##,
|
||||
|
||||
E0508: r##"
|
||||
|
|
|
@ -9,7 +9,7 @@ use rustc::mir::interpret::{
|
|||
use rustc::mir::CastKind;
|
||||
use rustc_apfloat::Float;
|
||||
|
||||
use super::{EvalContext, Machine, PlaceTy, OpTy, Immediate};
|
||||
use super::{EvalContext, Machine, PlaceTy, OpTy, ImmTy, Immediate};
|
||||
|
||||
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||
fn type_is_fat_ptr(&self, ty: Ty<'tcx>) -> bool {
|
||||
|
@ -372,7 +372,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
|
|||
assert_eq!(src.layout.fields.offset(i).bytes(), 0);
|
||||
assert_eq!(src_field_layout.size, src.layout.size);
|
||||
// just sawp out the layout
|
||||
OpTy { op: src.op, layout: src_field_layout }
|
||||
OpTy::from(ImmTy { imm: src.to_immediate(), layout: src_field_layout })
|
||||
}
|
||||
};
|
||||
if src_field.layout.ty == dst_field.layout.ty {
|
||||
|
|
|
@ -126,7 +126,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
|
|||
let l = self.read_immediate(args[0])?;
|
||||
let r = self.read_immediate(args[1])?;
|
||||
let is_add = intrinsic_name == "saturating_add";
|
||||
let (val, overflowed) = self.binary_op_imm(if is_add {
|
||||
let (val, overflowed) = self.binary_op(if is_add {
|
||||
BinOp::Add
|
||||
} else {
|
||||
BinOp::Sub
|
||||
|
@ -173,7 +173,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
|
|||
"unchecked_shr" => BinOp::Shr,
|
||||
_ => bug!("Already checked for int ops")
|
||||
};
|
||||
let (val, overflowed) = self.binary_op_imm(bin_op, l, r)?;
|
||||
let (val, overflowed) = self.binary_op(bin_op, l, r)?;
|
||||
if overflowed {
|
||||
let layout = self.layout_of(substs.type_at(0))?;
|
||||
let r_val = r.to_scalar()?.to_bits(layout.size)?;
|
||||
|
|
|
@ -7,11 +7,11 @@ use std::hash::Hash;
|
|||
|
||||
use rustc::hir::{self, def_id::DefId};
|
||||
use rustc::mir;
|
||||
use rustc::ty::{self, layout::TyLayout, query::TyCtxtAt};
|
||||
use rustc::ty::{self, query::TyCtxtAt};
|
||||
|
||||
use super::{
|
||||
Allocation, AllocId, EvalResult, Scalar, AllocationExtra,
|
||||
EvalContext, PlaceTy, MPlaceTy, OpTy, Pointer, MemoryKind,
|
||||
EvalContext, PlaceTy, MPlaceTy, OpTy, ImmTy, Pointer, MemoryKind,
|
||||
};
|
||||
|
||||
/// Whether this kind of memory is allowed to leak
|
||||
|
@ -158,10 +158,8 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized {
|
|||
fn ptr_op(
|
||||
ecx: &EvalContext<'a, 'mir, 'tcx, Self>,
|
||||
bin_op: mir::BinOp,
|
||||
left: Scalar<Self::PointerTag>,
|
||||
left_layout: TyLayout<'tcx>,
|
||||
right: Scalar<Self::PointerTag>,
|
||||
right_layout: TyLayout<'tcx>,
|
||||
left: ImmTy<'tcx, Self::PointerTag>,
|
||||
right: ImmTy<'tcx, Self::PointerTag>,
|
||||
) -> EvalResult<'tcx, (Scalar<Self::PointerTag>, bool)>;
|
||||
|
||||
/// Heap allocations via the `box` keyword.
|
||||
|
|
|
@ -11,7 +11,10 @@ use rustc::mir::interpret::{
|
|||
ConstValue, Pointer, Scalar,
|
||||
EvalResult, EvalErrorKind,
|
||||
};
|
||||
use super::{EvalContext, Machine, MemPlace, MPlaceTy, MemoryKind};
|
||||
use super::{
|
||||
EvalContext, Machine, AllocMap, Allocation, AllocationExtra,
|
||||
MemPlace, MPlaceTy, PlaceTy, Place, MemoryKind,
|
||||
};
|
||||
pub use rustc::mir::interpret::ScalarMaybeUndef;
|
||||
|
||||
/// A `Value` represents a single immediate self-contained Rust value.
|
||||
|
@ -41,6 +44,11 @@ impl Immediate {
|
|||
}
|
||||
|
||||
impl<'tcx, Tag> Immediate<Tag> {
|
||||
#[inline]
|
||||
pub fn from_scalar(val: Scalar<Tag>) -> Self {
|
||||
Immediate::Scalar(ScalarMaybeUndef::Scalar(val))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn erase_tag(self) -> Immediate
|
||||
{
|
||||
|
@ -112,7 +120,7 @@ impl<'tcx, Tag> Immediate<Tag> {
|
|||
// as input for binary and cast operations.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct ImmTy<'tcx, Tag=()> {
|
||||
immediate: Immediate<Tag>,
|
||||
pub imm: Immediate<Tag>,
|
||||
pub layout: TyLayout<'tcx>,
|
||||
}
|
||||
|
||||
|
@ -120,7 +128,7 @@ impl<'tcx, Tag> ::std::ops::Deref for ImmTy<'tcx, Tag> {
|
|||
type Target = Immediate<Tag>;
|
||||
#[inline(always)]
|
||||
fn deref(&self) -> &Immediate<Tag> {
|
||||
&self.immediate
|
||||
&self.imm
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -180,7 +188,7 @@ impl<Tag> Operand<Tag> {
|
|||
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||
pub struct OpTy<'tcx, Tag=()> {
|
||||
crate op: Operand<Tag>, // ideally we'd make this private, but const_prop needs this
|
||||
op: Operand<Tag>,
|
||||
pub layout: TyLayout<'tcx>,
|
||||
}
|
||||
|
||||
|
@ -206,12 +214,25 @@ impl<'tcx, Tag> From<ImmTy<'tcx, Tag>> for OpTy<'tcx, Tag> {
|
|||
#[inline(always)]
|
||||
fn from(val: ImmTy<'tcx, Tag>) -> Self {
|
||||
OpTy {
|
||||
op: Operand::Immediate(val.immediate),
|
||||
op: Operand::Immediate(val.imm),
|
||||
layout: val.layout
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, Tag: Copy> ImmTy<'tcx, Tag>
|
||||
{
|
||||
#[inline]
|
||||
pub fn from_scalar(val: Scalar<Tag>, layout: TyLayout<'tcx>) -> Self {
|
||||
ImmTy { imm: Immediate::from_scalar(val), layout }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_bits(self) -> EvalResult<'tcx, u128> {
|
||||
self.to_scalar()?.to_bits(self.layout.size)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, Tag> OpTy<'tcx, Tag>
|
||||
{
|
||||
#[inline]
|
||||
|
@ -324,8 +345,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
|
|||
&self,
|
||||
op: OpTy<'tcx, M::PointerTag>
|
||||
) -> EvalResult<'tcx, ImmTy<'tcx, M::PointerTag>> {
|
||||
if let Ok(immediate) = self.try_read_immediate(op)? {
|
||||
Ok(ImmTy { immediate, layout: op.layout })
|
||||
if let Ok(imm) = self.try_read_immediate(op)? {
|
||||
Ok(ImmTy { imm, layout: op.layout })
|
||||
} else {
|
||||
bug!("primitive read failed for type: {:?}", op.layout.ty);
|
||||
}
|
||||
|
@ -469,6 +490,22 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
|
|||
Ok(OpTy { op, layout })
|
||||
}
|
||||
|
||||
/// Every place can be read from, so we can turm them into an operand
|
||||
#[inline(always)]
|
||||
pub fn place_to_op(
|
||||
&self,
|
||||
place: PlaceTy<'tcx, M::PointerTag>
|
||||
) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
|
||||
let op = match *place {
|
||||
Place::Ptr(mplace) => {
|
||||
Operand::Indirect(mplace)
|
||||
}
|
||||
Place::Local { frame, local } =>
|
||||
*self.stack[frame].locals[local].access()?
|
||||
};
|
||||
Ok(OpTy { op, layout: place.layout })
|
||||
}
|
||||
|
||||
// Evaluate a place with the goal of reading from it. This lets us sometimes
|
||||
// avoid allocations.
|
||||
fn eval_place_to_op(
|
||||
|
@ -531,10 +568,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
|
|||
.collect()
|
||||
}
|
||||
|
||||
// Used when miri runs into a constant, and by CTFE.
|
||||
// FIXME: CTFE should use allocations, then we can make this private (embed it into
|
||||
// `eval_operand`, ideally).
|
||||
pub(crate) fn const_value_to_op(
|
||||
// Used when Miri runs into a constant, and (indirectly through lazy_const_to_op) by CTFE.
|
||||
fn const_value_to_op(
|
||||
&self,
|
||||
val: ty::LazyConst<'tcx>,
|
||||
) -> EvalResult<'tcx, Operand<M::PointerTag>> {
|
||||
|
@ -666,3 +701,21 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
impl<'a, 'mir, 'tcx, M> EvalContext<'a, 'mir, 'tcx, M>
|
||||
where
|
||||
M: Machine<'a, 'mir, 'tcx, PointerTag=()>,
|
||||
// FIXME: Working around https://github.com/rust-lang/rust/issues/24159
|
||||
M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKinds>, Allocation<(), M::AllocExtra>)>,
|
||||
M::AllocExtra: AllocationExtra<(), M::MemoryExtra>,
|
||||
{
|
||||
// FIXME: CTFE should use allocations, then we can remove this.
|
||||
pub(crate) fn lazy_const_to_op(
|
||||
&self,
|
||||
cnst: ty::LazyConst<'tcx>,
|
||||
ty: ty::Ty<'tcx>,
|
||||
) -> EvalResult<'tcx, OpTy<'tcx>> {
|
||||
let op = self.const_value_to_op(cnst)?;
|
||||
Ok(OpTy { op, layout: self.layout_of(ty)? })
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
|
|||
right: ImmTy<'tcx, M::PointerTag>,
|
||||
dest: PlaceTy<'tcx, M::PointerTag>,
|
||||
) -> EvalResult<'tcx> {
|
||||
let (val, overflowed) = self.binary_op_imm(op, left, right)?;
|
||||
let (val, overflowed) = self.binary_op(op, left, right)?;
|
||||
let val = Immediate::ScalarPair(val.into(), Scalar::from_bool(overflowed).into());
|
||||
self.write_immediate(val, dest)
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
|
|||
right: ImmTy<'tcx, M::PointerTag>,
|
||||
dest: PlaceTy<'tcx, M::PointerTag>,
|
||||
) -> EvalResult<'tcx> {
|
||||
let (val, _overflowed) = self.binary_op_imm(op, left, right)?;
|
||||
let (val, _overflowed) = self.binary_op(op, left, right)?;
|
||||
self.write_scalar(val, dest)
|
||||
}
|
||||
}
|
||||
|
@ -272,69 +272,55 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
|
|||
Ok((val, false))
|
||||
}
|
||||
|
||||
/// Convenience wrapper that's useful when keeping the layout together with the
|
||||
/// immediate value.
|
||||
/// Returns the result of the specified operation and whether it overflowed.
|
||||
#[inline]
|
||||
pub fn binary_op_imm(
|
||||
pub fn binary_op(
|
||||
&self,
|
||||
bin_op: mir::BinOp,
|
||||
left: ImmTy<'tcx, M::PointerTag>,
|
||||
right: ImmTy<'tcx, M::PointerTag>,
|
||||
) -> EvalResult<'tcx, (Scalar<M::PointerTag>, bool)> {
|
||||
self.binary_op(
|
||||
bin_op,
|
||||
left.to_scalar()?, left.layout,
|
||||
right.to_scalar()?, right.layout,
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns the result of the specified operation and whether it overflowed.
|
||||
pub fn binary_op(
|
||||
&self,
|
||||
bin_op: mir::BinOp,
|
||||
left: Scalar<M::PointerTag>,
|
||||
left_layout: TyLayout<'tcx>,
|
||||
right: Scalar<M::PointerTag>,
|
||||
right_layout: TyLayout<'tcx>,
|
||||
) -> EvalResult<'tcx, (Scalar<M::PointerTag>, bool)> {
|
||||
trace!("Running binary op {:?}: {:?} ({:?}), {:?} ({:?})",
|
||||
bin_op, left, left_layout.ty, right, right_layout.ty);
|
||||
bin_op, *left, left.layout.ty, *right, right.layout.ty);
|
||||
|
||||
match left_layout.ty.sty {
|
||||
match left.layout.ty.sty {
|
||||
ty::Char => {
|
||||
assert_eq!(left_layout.ty, right_layout.ty);
|
||||
let left = left.to_char()?;
|
||||
let right = right.to_char()?;
|
||||
assert_eq!(left.layout.ty, right.layout.ty);
|
||||
let left = left.to_scalar()?.to_char()?;
|
||||
let right = right.to_scalar()?.to_char()?;
|
||||
self.binary_char_op(bin_op, left, right)
|
||||
}
|
||||
ty::Bool => {
|
||||
assert_eq!(left_layout.ty, right_layout.ty);
|
||||
let left = left.to_bool()?;
|
||||
let right = right.to_bool()?;
|
||||
assert_eq!(left.layout.ty, right.layout.ty);
|
||||
let left = left.to_scalar()?.to_bool()?;
|
||||
let right = right.to_scalar()?.to_bool()?;
|
||||
self.binary_bool_op(bin_op, left, right)
|
||||
}
|
||||
ty::Float(fty) => {
|
||||
assert_eq!(left_layout.ty, right_layout.ty);
|
||||
let left = left.to_bits(left_layout.size)?;
|
||||
let right = right.to_bits(right_layout.size)?;
|
||||
assert_eq!(left.layout.ty, right.layout.ty);
|
||||
let left = left.to_bits()?;
|
||||
let right = right.to_bits()?;
|
||||
self.binary_float_op(bin_op, fty, left, right)
|
||||
}
|
||||
_ => {
|
||||
// Must be integer(-like) types. Don't forget about == on fn pointers.
|
||||
assert!(left_layout.ty.is_integral() || left_layout.ty.is_unsafe_ptr() ||
|
||||
left_layout.ty.is_fn());
|
||||
assert!(right_layout.ty.is_integral() || right_layout.ty.is_unsafe_ptr() ||
|
||||
right_layout.ty.is_fn());
|
||||
assert!(left.layout.ty.is_integral() || left.layout.ty.is_unsafe_ptr() ||
|
||||
left.layout.ty.is_fn());
|
||||
assert!(right.layout.ty.is_integral() || right.layout.ty.is_unsafe_ptr() ||
|
||||
right.layout.ty.is_fn());
|
||||
|
||||
// Handle operations that support pointer values
|
||||
if left.is_ptr() || right.is_ptr() || bin_op == mir::BinOp::Offset {
|
||||
return M::ptr_op(self, bin_op, left, left_layout, right, right_layout);
|
||||
if left.to_scalar_ptr()?.is_ptr() ||
|
||||
right.to_scalar_ptr()?.is_ptr() ||
|
||||
bin_op == mir::BinOp::Offset
|
||||
{
|
||||
return M::ptr_op(self, bin_op, left, right);
|
||||
}
|
||||
|
||||
// Everything else only works with "proper" bits
|
||||
let left = left.to_bits(left_layout.size).expect("we checked is_ptr");
|
||||
let right = right.to_bits(right_layout.size).expect("we checked is_ptr");
|
||||
self.binary_int_op(bin_op, left, left_layout, right, right_layout)
|
||||
let l = left.to_bits().expect("we checked is_ptr");
|
||||
let r = right.to_bits().expect("we checked is_ptr");
|
||||
self.binary_int_op(bin_op, l, left.layout, r, right.layout)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -342,13 +328,14 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
|
|||
pub fn unary_op(
|
||||
&self,
|
||||
un_op: mir::UnOp,
|
||||
val: Scalar<M::PointerTag>,
|
||||
layout: TyLayout<'tcx>,
|
||||
val: ImmTy<'tcx, M::PointerTag>,
|
||||
) -> EvalResult<'tcx, Scalar<M::PointerTag>> {
|
||||
use rustc::mir::UnOp::*;
|
||||
use rustc_apfloat::ieee::{Single, Double};
|
||||
use rustc_apfloat::Float;
|
||||
|
||||
let layout = val.layout;
|
||||
let val = val.to_scalar()?;
|
||||
trace!("Running unary op {:?}: {:?} ({:?})", un_op, val, layout.ty.sty);
|
||||
|
||||
match layout.ty.sty {
|
||||
|
|
|
@ -244,10 +244,10 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx, Tag: ::std::fmt::Debug> OpTy<'tcx, Tag> {
|
||||
impl<'tcx, Tag: ::std::fmt::Debug + Copy> OpTy<'tcx, Tag> {
|
||||
#[inline(always)]
|
||||
pub fn try_as_mplace(self) -> Result<MPlaceTy<'tcx, Tag>, Immediate<Tag>> {
|
||||
match self.op {
|
||||
match *self {
|
||||
Operand::Indirect(mplace) => Ok(MPlaceTy { mplace, layout: self.layout }),
|
||||
Operand::Immediate(imm) => Err(imm),
|
||||
}
|
||||
|
@ -487,9 +487,9 @@ where
|
|||
Deref => self.deref_operand(base.into())?,
|
||||
|
||||
Index(local) => {
|
||||
let n = *self.frame().locals[local].access()?;
|
||||
let n_layout = self.layout_of(self.tcx.types.usize)?;
|
||||
let n = self.read_scalar(OpTy { op: n, layout: n_layout })?;
|
||||
let layout = self.layout_of(self.tcx.types.usize)?;
|
||||
let n = self.access_local(self.frame(), local, Some(layout))?;
|
||||
let n = self.read_scalar(n)?;
|
||||
let n = n.to_bits(self.tcx.data_layout.pointer_size)?;
|
||||
self.mplace_field(base, u64::try_from(n).unwrap())?
|
||||
}
|
||||
|
@ -991,22 +991,6 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Every place can be read from, so we can turm them into an operand
|
||||
#[inline(always)]
|
||||
pub fn place_to_op(
|
||||
&self,
|
||||
place: PlaceTy<'tcx, M::PointerTag>
|
||||
) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
|
||||
let op = match place.place {
|
||||
Place::Ptr(mplace) => {
|
||||
Operand::Indirect(mplace)
|
||||
}
|
||||
Place::Local { frame, local } =>
|
||||
*self.stack[frame].locals[local].access()?
|
||||
};
|
||||
Ok(OpTy { op, layout: place.layout })
|
||||
}
|
||||
|
||||
pub fn raw_const_to_mplace(
|
||||
&self,
|
||||
raw: RawConst<'tcx>,
|
||||
|
|
|
@ -176,7 +176,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
|
|||
UnaryOp(un_op, ref operand) => {
|
||||
// The operand always has the same type as the result.
|
||||
let val = self.read_immediate(self.eval_operand(operand, Some(dest.layout))?)?;
|
||||
let val = self.unary_op(un_op, val.to_scalar()?, dest.layout)?;
|
||||
let val = self.unary_op(un_op, val)?;
|
||||
self.write_scalar(val, dest)?;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ use rustc_target::spec::abi::Abi;
|
|||
|
||||
use rustc::mir::interpret::{EvalResult, PointerArithmetic, EvalErrorKind, Scalar};
|
||||
use super::{
|
||||
EvalContext, Machine, Immediate, OpTy, PlaceTy, MPlaceTy, Operand, StackPopCleanup
|
||||
EvalContext, Machine, Immediate, OpTy, ImmTy, PlaceTy, MPlaceTy, StackPopCleanup
|
||||
};
|
||||
|
||||
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||
|
@ -51,8 +51,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
|
|||
// Compare using binary_op, to also support pointer values
|
||||
let const_int = Scalar::from_uint(const_int, discr.layout.size);
|
||||
let (res, _) = self.binary_op(mir::BinOp::Eq,
|
||||
discr.to_scalar()?, discr.layout,
|
||||
const_int, discr.layout,
|
||||
discr,
|
||||
ImmTy::from_scalar(const_int, discr.layout),
|
||||
)?;
|
||||
if res.to_bool()? {
|
||||
target_block = targets[index];
|
||||
|
@ -418,8 +418,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
|
|||
let mut args = args.to_vec();
|
||||
let pointee = args[0].layout.ty.builtin_deref(true).unwrap().ty;
|
||||
let fake_fat_ptr_ty = self.tcx.mk_mut_ptr(pointee);
|
||||
args[0].layout = self.layout_of(fake_fat_ptr_ty)?.field(self, 0)?;
|
||||
args[0].op = Operand::Immediate(Immediate::Scalar(ptr.ptr.into())); // strip vtable
|
||||
args[0] = OpTy::from(ImmTy { // strip vtable
|
||||
layout: self.layout_of(fake_fat_ptr_ty)?.field(self, 0)?,
|
||||
imm: Immediate::Scalar(ptr.ptr.into())
|
||||
});
|
||||
trace!("Patched self operand to {:#?}", args[0]);
|
||||
// recurse with concrete function
|
||||
self.eval_fn_call(instance, span, caller_abi, &args, dest, ret)
|
||||
|
@ -448,8 +450,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
|
|||
_ => (instance, place),
|
||||
};
|
||||
|
||||
let arg = OpTy {
|
||||
op: Operand::Immediate(place.to_ref()),
|
||||
let arg = ImmTy {
|
||||
imm: place.to_ref(),
|
||||
layout: self.layout_of(self.tcx.mk_mut_ptr(place.layout.ty))?,
|
||||
};
|
||||
|
||||
|
@ -460,7 +462,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
|
|||
instance,
|
||||
span,
|
||||
Abi::Rust,
|
||||
&[arg],
|
||||
&[arg.into()],
|
||||
Some(dest.into()),
|
||||
Some(target),
|
||||
)
|
||||
|
|
|
@ -22,6 +22,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
|
|||
let (ty, poly_trait_ref) = self.tcx.erase_regions(&(ty, poly_trait_ref));
|
||||
|
||||
if let Some(&vtable) = self.vtables.get(&(ty, poly_trait_ref)) {
|
||||
// This means we guarantee that there are no duplicate vtables, we will
|
||||
// always use the same vtable for the same (Type, Trait) combination.
|
||||
// That's not what happens in rustc, but emulating per-crate deduplication
|
||||
// does not sound like it actually makes anything any better.
|
||||
return Ok(Pointer::from(vtable).with_default_tag());
|
||||
}
|
||||
|
||||
|
|
|
@ -18,10 +18,9 @@ use rustc::ty::layout::{
|
|||
HasTyCtxt, TargetDataLayout, HasDataLayout,
|
||||
};
|
||||
|
||||
use crate::interpret::{self, EvalContext, ScalarMaybeUndef, Immediate, OpTy, MemoryKind};
|
||||
use crate::interpret::{EvalContext, ScalarMaybeUndef, Immediate, OpTy, ImmTy, MemoryKind};
|
||||
use crate::const_eval::{
|
||||
CompileTimeInterpreter, error_to_const_error, eval_promoted, mk_eval_cx,
|
||||
lazy_const_to_op,
|
||||
};
|
||||
use crate::transform::{MirPass, MirSource};
|
||||
|
||||
|
@ -254,7 +253,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
|
|||
source_info: SourceInfo,
|
||||
) -> Option<Const<'tcx>> {
|
||||
self.ecx.tcx.span = source_info.span;
|
||||
match lazy_const_to_op(&self.ecx, *c.literal, c.ty) {
|
||||
match self.ecx.lazy_const_to_op(*c.literal, c.ty) {
|
||||
Ok(op) => {
|
||||
Some((op, c.span))
|
||||
},
|
||||
|
@ -345,15 +344,15 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
|
|||
Rvalue::Len(_) => None,
|
||||
Rvalue::NullaryOp(NullOp::SizeOf, ty) => {
|
||||
type_size_of(self.tcx, self.param_env, ty).and_then(|n| Some((
|
||||
OpTy {
|
||||
op: interpret::Operand::Immediate(Immediate::Scalar(
|
||||
ImmTy {
|
||||
imm: Immediate::Scalar(
|
||||
Scalar::Bits {
|
||||
bits: n as u128,
|
||||
size: self.tcx.data_layout.pointer_size.bytes() as u8,
|
||||
}.into()
|
||||
)),
|
||||
),
|
||||
layout: self.tcx.layout_of(self.param_env.and(self.tcx.types.usize)).ok()?,
|
||||
},
|
||||
}.into(),
|
||||
span,
|
||||
)))
|
||||
}
|
||||
|
@ -371,13 +370,12 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
|
|||
|
||||
let (arg, _) = self.eval_operand(arg, source_info)?;
|
||||
let val = self.use_ecx(source_info, |this| {
|
||||
let prim = this.ecx.read_scalar(arg)?.not_undef()?;
|
||||
let prim = this.ecx.read_immediate(arg)?;
|
||||
match op {
|
||||
UnOp::Neg => {
|
||||
// Need to do overflow check here: For actual CTFE, MIR
|
||||
// generation emits code that does this before calling the op.
|
||||
let size = arg.layout.size;
|
||||
if prim.to_bits(size)? == (1 << (size.bits() - 1)) {
|
||||
if prim.to_bits()? == (1 << (prim.layout.size.bits() - 1)) {
|
||||
return err!(OverflowNeg);
|
||||
}
|
||||
}
|
||||
|
@ -386,13 +384,13 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
|
|||
}
|
||||
}
|
||||
// Now run the actual operation.
|
||||
this.ecx.unary_op(op, prim, arg.layout)
|
||||
this.ecx.unary_op(op, prim)
|
||||
})?;
|
||||
let res = OpTy {
|
||||
op: interpret::Operand::Immediate(Immediate::Scalar(val.into())),
|
||||
let res = ImmTy {
|
||||
imm: Immediate::Scalar(val.into()),
|
||||
layout: place_layout,
|
||||
};
|
||||
Some((res, span))
|
||||
Some((res.into(), span))
|
||||
}
|
||||
Rvalue::CheckedBinaryOp(op, ref left, ref right) |
|
||||
Rvalue::BinaryOp(op, ref left, ref right) => {
|
||||
|
@ -447,7 +445,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
|
|||
})?;
|
||||
trace!("const evaluating {:?} for {:?} and {:?}", op, left, right);
|
||||
let (val, overflow) = self.use_ecx(source_info, |this| {
|
||||
this.ecx.binary_op_imm(op, l, r)
|
||||
this.ecx.binary_op(op, l, r)
|
||||
})?;
|
||||
let val = if let Rvalue::CheckedBinaryOp(..) = *rvalue {
|
||||
Immediate::ScalarPair(
|
||||
|
@ -462,11 +460,11 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
|
|||
}
|
||||
Immediate::Scalar(val.into())
|
||||
};
|
||||
let res = OpTy {
|
||||
op: interpret::Operand::Immediate(val),
|
||||
let res = ImmTy {
|
||||
imm: val,
|
||||
layout: place_layout,
|
||||
};
|
||||
Some((res, span))
|
||||
Some((res.into(), span))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -614,11 +614,16 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
|
|||
Some(def) if def != HirDef::Err => def,
|
||||
_ => self.get_path_def(self.tcx.hir().get_parent_node(id)),
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
Node::Expr(&hir::Expr {
|
||||
node: hir::ExprKind::Struct(ref qpath, ..),
|
||||
..
|
||||
}) |
|
||||
}) => {
|
||||
let hir_id = self.tcx.hir().node_to_hir_id(id);
|
||||
self.tables.qpath_def(qpath, hir_id)
|
||||
}
|
||||
|
||||
Node::Expr(&hir::Expr {
|
||||
node: hir::ExprKind::Path(ref qpath),
|
||||
..
|
||||
|
|
|
@ -689,6 +689,8 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
|
|||
CoerceMany::with_coercion_sites(coerce_first, arms)
|
||||
};
|
||||
|
||||
let mut other_arms = vec![]; // used only for diagnostics
|
||||
let mut prior_arm_ty = None;
|
||||
for (i, (arm, pats_diverge)) in arms.iter().zip(all_arm_pats_diverge).enumerate() {
|
||||
if let Some(ref g) = arm.guard {
|
||||
self.diverges.set(pats_diverge);
|
||||
|
@ -709,17 +711,36 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
|
|||
_ => false
|
||||
};
|
||||
|
||||
let arm_span = if let hir::ExprKind::Block(ref blk, _) = arm.body.node {
|
||||
// Point at the block expr instead of the entire block
|
||||
blk.expr.as_ref().map(|e| e.span).unwrap_or(arm.body.span)
|
||||
} else {
|
||||
arm.body.span
|
||||
};
|
||||
if is_if_let_fallback {
|
||||
let cause = self.cause(expr.span, ObligationCauseCode::IfExpressionWithNoElse);
|
||||
assert!(arm_ty.is_unit());
|
||||
coercion.coerce_forced_unit(self, &cause, &mut |_| (), true);
|
||||
} else {
|
||||
let cause = self.cause(expr.span, ObligationCauseCode::MatchExpressionArm {
|
||||
arm_span: arm.body.span,
|
||||
source: match_src
|
||||
});
|
||||
let cause = if i == 0 {
|
||||
// The reason for the first arm to fail is not that the match arms diverge,
|
||||
// but rather that there's a prior obligation that doesn't hold.
|
||||
self.cause(arm_span, ObligationCauseCode::BlockTailExpression(arm.body.id))
|
||||
} else {
|
||||
self.cause(expr.span, ObligationCauseCode::MatchExpressionArm {
|
||||
arm_span,
|
||||
source: match_src,
|
||||
prior_arms: other_arms.clone(),
|
||||
last_ty: prior_arm_ty.unwrap(),
|
||||
})
|
||||
};
|
||||
coercion.coerce(self, &cause, &arm.body, arm_ty);
|
||||
}
|
||||
other_arms.push(arm_span);
|
||||
if other_arms.len() > 5 {
|
||||
other_arms.remove(0);
|
||||
}
|
||||
prior_arm_ty = Some(arm_ty);
|
||||
}
|
||||
|
||||
// We won't diverge unless the discriminant or all arms diverge.
|
||||
|
|
|
@ -210,7 +210,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
/// ```
|
||||
/// opt.map(|arg| { takes_ref(arg) });
|
||||
/// ```
|
||||
fn can_use_as_ref(&self, expr: &hir::Expr) -> Option<(Span, &'static str, String)> {
|
||||
fn can_use_as_ref(
|
||||
&self,
|
||||
expr: &hir::Expr,
|
||||
) -> Option<(Span, &'static str, String)> {
|
||||
if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = expr.node {
|
||||
if let hir::def::Def::Local(id) = path.def {
|
||||
let parent = self.tcx.hir().get_parent_node(id);
|
||||
|
@ -233,10 +236,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
self_ty.starts_with("std::option::Option") ||
|
||||
self_ty.starts_with("std::result::Result")
|
||||
) && (name == "map" || name == "and_then");
|
||||
if is_as_ref_able {
|
||||
return Some((span.shrink_to_lo(),
|
||||
"consider using `as_ref` instead",
|
||||
"as_ref().".into()));
|
||||
match (is_as_ref_able, self.sess().source_map().span_to_snippet(*span)) {
|
||||
(true, Ok(src)) => {
|
||||
return Some((*span, "consider using `as_ref` instead",
|
||||
format!("as_ref().{}", src)));
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -430,7 +435,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
|
||||
match expr.node {
|
||||
// All built-in range literals but `..=` and `..` desugar to Structs
|
||||
ExprKind::Struct(QPath::Resolved(None, ref path), _, _) |
|
||||
ExprKind::Struct(ref qpath, _, _) => {
|
||||
if let QPath::Resolved(None, ref path) = **qpath {
|
||||
return is_range_path(&path) && span_is_range_literal(&expr.span);
|
||||
}
|
||||
}
|
||||
// `..` desugars to its struct path
|
||||
ExprKind::Path(QPath::Resolved(None, ref path)) => {
|
||||
return is_range_path(&path) && span_is_range_literal(&expr.span);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// ignore-tidy-linelength
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
register_long_diagnostics! {
|
||||
|
@ -1544,7 +1545,9 @@ fn f<T>() {}
|
|||
|
||||
It is not possible to declare type parameters on a function that has the `start`
|
||||
attribute. Such a function must have the following type signature (for more
|
||||
information: http://doc.rust-lang.org/stable/book/first-edition/no-stdlib.html):
|
||||
information, view [the unstable book][1]):
|
||||
|
||||
[1]: https://doc.rust-lang.org/unstable-book/language-features/lang-items.html#writing-an-executable-without-stdlib
|
||||
|
||||
```
|
||||
# let _:
|
||||
|
@ -2918,10 +2921,11 @@ impl Baz for Bar { } // Note: This is OK
|
|||
|
||||
E0374: r##"
|
||||
A struct without a field containing an unsized type cannot implement
|
||||
`CoerceUnsized`. An
|
||||
[unsized type](https://doc.rust-lang.org/book/first-edition/unsized-types.html)
|
||||
is any type that the compiler doesn't know the length or alignment of at
|
||||
compile time. Any struct containing an unsized type is also unsized.
|
||||
`CoerceUnsized`. An [unsized type][1] is any type that the compiler
|
||||
doesn't know the length or alignment of at compile time. Any struct
|
||||
containing an unsized type is also unsized.
|
||||
|
||||
[1]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait
|
||||
|
||||
Example of erroneous code:
|
||||
|
||||
|
@ -2978,9 +2982,9 @@ A struct with more than one field containing an unsized type cannot implement
|
|||
`CoerceUnsized`. This only occurs when you are trying to coerce one of the
|
||||
types in your struct to another type in the struct. In this case we try to
|
||||
impl `CoerceUnsized` from `T` to `U` which are both types that the struct
|
||||
takes. An [unsized type] is any type that the compiler doesn't know the length
|
||||
or alignment of at compile time. Any struct containing an unsized type is also
|
||||
unsized.
|
||||
takes. An [unsized type][1] is any type that the compiler doesn't know the
|
||||
length or alignment of at compile time. Any struct containing an unsized type
|
||||
is also unsized.
|
||||
|
||||
Example of erroneous code:
|
||||
|
||||
|
@ -3025,7 +3029,7 @@ fn coerce_foo<T: CoerceUnsized<U>, U>(t: T) -> Foo<U> {
|
|||
}
|
||||
```
|
||||
|
||||
[unsized type]: https://doc.rust-lang.org/book/first-edition/unsized-types.html
|
||||
[1]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait
|
||||
"##,
|
||||
|
||||
E0376: r##"
|
||||
|
@ -3033,11 +3037,12 @@ The type you are trying to impl `CoerceUnsized` for is not a struct.
|
|||
`CoerceUnsized` can only be implemented for a struct. Unsized types are
|
||||
already able to be coerced without an implementation of `CoerceUnsized`
|
||||
whereas a struct containing an unsized type needs to know the unsized type
|
||||
field it's containing is able to be coerced. An
|
||||
[unsized type](https://doc.rust-lang.org/book/first-edition/unsized-types.html)
|
||||
field it's containing is able to be coerced. An [unsized type][1]
|
||||
is any type that the compiler doesn't know the length or alignment of at
|
||||
compile time. Any struct containing an unsized type is also unsized.
|
||||
|
||||
[1]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait
|
||||
|
||||
Example of erroneous code:
|
||||
|
||||
```compile_fail,E0376
|
||||
|
@ -3883,8 +3888,10 @@ let c = 86u8 as char; // ok!
|
|||
assert_eq!(c, 'V');
|
||||
```
|
||||
|
||||
For more information about casts, take a look at The Book:
|
||||
https://doc.rust-lang.org/book/first-edition/casting-between-types.html
|
||||
For more information about casts, take a look at the Type cast section in
|
||||
[The Reference Book][1].
|
||||
|
||||
[1]: https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions
|
||||
"##,
|
||||
|
||||
E0605: r##"
|
||||
|
@ -3912,8 +3919,10 @@ let v = 0 as *const u8;
|
|||
v as *const i8; // ok!
|
||||
```
|
||||
|
||||
For more information about casts, take a look at The Book:
|
||||
https://doc.rust-lang.org/book/first-edition/casting-between-types.html
|
||||
For more information about casts, take a look at the Type cast section in
|
||||
[The Reference Book][1].
|
||||
|
||||
[1]: https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions
|
||||
"##,
|
||||
|
||||
E0606: r##"
|
||||
|
@ -3934,8 +3943,10 @@ let x = &0u8;
|
|||
let y: u32 = *x as u32; // We dereference it first and then cast it.
|
||||
```
|
||||
|
||||
For more information about casts, take a look at The Book:
|
||||
https://doc.rust-lang.org/book/first-edition/casting-between-types.html
|
||||
For more information about casts, take a look at the Type cast section in
|
||||
[The Reference Book][1].
|
||||
|
||||
[1]: https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions
|
||||
"##,
|
||||
|
||||
E0607: r##"
|
||||
|
@ -3961,8 +3972,10 @@ pointer holds is their size.
|
|||
|
||||
To fix this error, don't try to cast directly between thin and fat pointers.
|
||||
|
||||
For more information about casts, take a look at The Book:
|
||||
https://doc.rust-lang.org/book/first-edition/casting-between-types.html
|
||||
For more information about casts, take a look at the Type cast section in
|
||||
[The Reference Book][1].
|
||||
|
||||
[1]: https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions
|
||||
"##,
|
||||
|
||||
E0609: r##"
|
||||
|
@ -4020,8 +4033,8 @@ println!("x: {}, y: {}", variable.x, variable.y);
|
|||
```
|
||||
|
||||
For more information about primitives and structs, take a look at The Book:
|
||||
https://doc.rust-lang.org/book/first-edition/primitive-types.html
|
||||
https://doc.rust-lang.org/book/first-edition/structs.html
|
||||
https://doc.rust-lang.org/book/ch03-02-data-types.html
|
||||
https://doc.rust-lang.org/book/ch05-00-structs.html
|
||||
"##,
|
||||
|
||||
E0614: r##"
|
||||
|
|
|
@ -137,7 +137,7 @@ To fix this error, don't try to cast directly between thin and fat
|
|||
pointers.
|
||||
|
||||
For more information about casts, take a look at The Book:
|
||||
https://doc.rust-lang.org/book/first-edition/casting-between-types.html");
|
||||
https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions");
|
||||
err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use core::marker::Unpin;
|
|||
use core::pin::Pin;
|
||||
use core::option::Option;
|
||||
use core::ptr::NonNull;
|
||||
use core::task::{LocalWaker, Poll};
|
||||
use core::task::{Waker, Poll};
|
||||
use core::ops::{Drop, Generator, GeneratorState};
|
||||
|
||||
#[doc(inline)]
|
||||
|
@ -32,10 +32,10 @@ impl<T: Generator<Yield = ()>> !Unpin for GenFuture<T> {}
|
|||
#[unstable(feature = "gen_future", issue = "50547")]
|
||||
impl<T: Generator<Yield = ()>> Future for GenFuture<T> {
|
||||
type Output = T::Return;
|
||||
fn poll(self: Pin<&mut Self>, lw: &LocalWaker) -> Poll<Self::Output> {
|
||||
fn poll(self: Pin<&mut Self>, waker: &Waker) -> Poll<Self::Output> {
|
||||
// Safe because we're !Unpin + !Drop mapping to a ?Unpin value
|
||||
let gen = unsafe { Pin::map_unchecked_mut(self, |s| &mut s.0) };
|
||||
set_task_waker(lw, || match gen.resume() {
|
||||
set_task_waker(waker, || match gen.resume() {
|
||||
GeneratorState::Yielded(()) => Poll::Pending,
|
||||
GeneratorState::Complete(x) => Poll::Ready(x),
|
||||
})
|
||||
|
@ -43,10 +43,10 @@ impl<T: Generator<Yield = ()>> Future for GenFuture<T> {
|
|||
}
|
||||
|
||||
thread_local! {
|
||||
static TLS_WAKER: Cell<Option<NonNull<LocalWaker>>> = Cell::new(None);
|
||||
static TLS_WAKER: Cell<Option<NonNull<Waker>>> = Cell::new(None);
|
||||
}
|
||||
|
||||
struct SetOnDrop(Option<NonNull<LocalWaker>>);
|
||||
struct SetOnDrop(Option<NonNull<Waker>>);
|
||||
|
||||
impl Drop for SetOnDrop {
|
||||
fn drop(&mut self) {
|
||||
|
@ -58,12 +58,12 @@ impl Drop for SetOnDrop {
|
|||
|
||||
#[unstable(feature = "gen_future", issue = "50547")]
|
||||
/// Sets the thread-local task context used by async/await futures.
|
||||
pub fn set_task_waker<F, R>(lw: &LocalWaker, f: F) -> R
|
||||
pub fn set_task_waker<F, R>(waker: &Waker, f: F) -> R
|
||||
where
|
||||
F: FnOnce() -> R
|
||||
{
|
||||
let old_waker = TLS_WAKER.with(|tls_waker| {
|
||||
tls_waker.replace(Some(NonNull::from(lw)))
|
||||
tls_waker.replace(Some(NonNull::from(waker)))
|
||||
});
|
||||
let _reset_waker = SetOnDrop(old_waker);
|
||||
f()
|
||||
|
@ -78,7 +78,7 @@ where
|
|||
/// retrieved by a surrounding call to get_task_waker.
|
||||
pub fn get_task_waker<F, R>(f: F) -> R
|
||||
where
|
||||
F: FnOnce(&LocalWaker) -> R
|
||||
F: FnOnce(&Waker) -> R
|
||||
{
|
||||
let waker_ptr = TLS_WAKER.with(|tls_waker| {
|
||||
// Clear the entry so that nested `get_task_waker` calls
|
||||
|
@ -88,7 +88,7 @@ where
|
|||
let _reset_waker = SetOnDrop(waker_ptr);
|
||||
|
||||
let waker_ptr = waker_ptr.expect(
|
||||
"TLS LocalWaker not set. This is a rustc bug. \
|
||||
"TLS Waker not set. This is a rustc bug. \
|
||||
Please file an issue on https://github.com/rust-lang/rust.");
|
||||
unsafe { f(waker_ptr.as_ref()) }
|
||||
}
|
||||
|
@ -99,5 +99,5 @@ pub fn poll_with_tls_waker<F>(f: Pin<&mut F>) -> Poll<F::Output>
|
|||
where
|
||||
F: Future
|
||||
{
|
||||
get_task_waker(|lw| F::poll(f, lw))
|
||||
get_task_waker(|waker| F::poll(f, waker))
|
||||
}
|
||||
|
|
|
@ -463,8 +463,6 @@ pub mod task {
|
|||
//! Types and Traits for working with asynchronous tasks.
|
||||
#[doc(inline)]
|
||||
pub use core::task::*;
|
||||
#[doc(inline)]
|
||||
pub use alloc_crate::task::*;
|
||||
}
|
||||
|
||||
#[unstable(feature = "futures_api",
|
||||
|
|
|
@ -12,7 +12,7 @@ use panicking;
|
|||
use ptr::{Unique, NonNull};
|
||||
use rc::Rc;
|
||||
use sync::{Arc, Mutex, RwLock, atomic};
|
||||
use task::{LocalWaker, Poll};
|
||||
use task::{Waker, Poll};
|
||||
use thread::Result;
|
||||
|
||||
#[stable(feature = "panic_hooks", since = "1.10.0")]
|
||||
|
@ -323,9 +323,9 @@ impl<T: fmt::Debug> fmt::Debug for AssertUnwindSafe<T> {
|
|||
impl<'a, F: Future> Future for AssertUnwindSafe<F> {
|
||||
type Output = F::Output;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, lw: &LocalWaker) -> Poll<Self::Output> {
|
||||
fn poll(self: Pin<&mut Self>, waker: &Waker) -> Poll<Self::Output> {
|
||||
let pinned_field = unsafe { Pin::map_unchecked_mut(self, |x| &mut x.0) };
|
||||
F::poll(pinned_field, lw)
|
||||
F::poll(pinned_field, waker)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -129,10 +129,10 @@
|
|||
//! [`std::string`]: ../string/index.html
|
||||
//! [`std::vec`]: ../vec/index.html
|
||||
//! [`to_owned`]: ../borrow/trait.ToOwned.html#tymethod.to_owned
|
||||
//! [book-closures]: ../../book/first-edition/closures.html
|
||||
//! [book-dtor]: ../../book/first-edition/drop.html
|
||||
//! [book-enums]: ../../book/first-edition/enums.html
|
||||
//! [book-iter]: ../../book/first-edition/iterators.html
|
||||
//! [book-closures]: ../../book/ch13-01-closures.html
|
||||
//! [book-dtor]: ../../book/ch15-03-drop.html
|
||||
//! [book-enums]: ../../book/ch06-01-defining-an-enum.html
|
||||
//! [book-iter]: ../../book/ch13-02-iterators.html
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
//! benchmarks themselves) should be done via the `#[test]` and
|
||||
//! `#[bench]` attributes.
|
||||
//!
|
||||
//! See the [Testing Chapter](../book/first-edition/testing.html) of the book for more details.
|
||||
//! See the [Testing Chapter](../book/ch11-00-testing.html) of the book for more details.
|
||||
|
||||
// Currently, not much of this is meant for users. It is intended to
|
||||
// support the simplest interface possible for representing and
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
use std::iter::Iterator;
|
||||
use std::future::Future;
|
||||
|
||||
use std::task::{Poll, LocalWaker};
|
||||
use std::task::{Poll, Waker};
|
||||
use std::pin::Pin;
|
||||
use std::unimplemented;
|
||||
|
||||
|
@ -13,7 +13,7 @@ struct MyFuture;
|
|||
impl Future for MyFuture {
|
||||
type Output = u32;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, lw: &LocalWaker) -> Poll<u32> {
|
||||
fn poll(self: Pin<&mut Self>, waker: &Waker) -> Poll<u32> {
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
// edition:2018
|
||||
// aux-build:arc_wake.rs
|
||||
|
||||
#![feature(arbitrary_self_types, async_await, await_macro, futures_api)]
|
||||
|
||||
extern crate arc_wake;
|
||||
|
||||
use std::pin::Pin;
|
||||
use std::future::Future;
|
||||
use std::sync::{
|
||||
|
@ -9,17 +12,17 @@ use std::sync::{
|
|||
atomic::{self, AtomicUsize},
|
||||
};
|
||||
use std::task::{
|
||||
LocalWaker, Poll, Wake,
|
||||
local_waker_from_nonlocal,
|
||||
Poll, Waker,
|
||||
};
|
||||
use arc_wake::ArcWake;
|
||||
|
||||
struct Counter {
|
||||
wakes: AtomicUsize,
|
||||
}
|
||||
|
||||
impl Wake for Counter {
|
||||
fn wake(this: &Arc<Self>) {
|
||||
this.wakes.fetch_add(1, atomic::Ordering::SeqCst);
|
||||
impl ArcWake for Counter {
|
||||
fn wake(arc_self: &Arc<Self>) {
|
||||
arc_self.wakes.fetch_add(1, atomic::Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,11 +32,11 @@ fn wake_and_yield_once() -> WakeOnceThenComplete { WakeOnceThenComplete(false) }
|
|||
|
||||
impl Future for WakeOnceThenComplete {
|
||||
type Output = ();
|
||||
fn poll(mut self: Pin<&mut Self>, lw: &LocalWaker) -> Poll<()> {
|
||||
fn poll(mut self: Pin<&mut Self>, waker: &Waker) -> Poll<()> {
|
||||
if self.0 {
|
||||
Poll::Ready(())
|
||||
} else {
|
||||
lw.wake();
|
||||
waker.wake();
|
||||
self.0 = true;
|
||||
Poll::Pending
|
||||
}
|
||||
|
@ -130,7 +133,7 @@ where
|
|||
{
|
||||
let mut fut = Box::pin(f(9));
|
||||
let counter = Arc::new(Counter { wakes: AtomicUsize::new(0) });
|
||||
let waker = local_waker_from_nonlocal(counter.clone());
|
||||
let waker = ArcWake::into_waker(counter.clone());
|
||||
assert_eq!(0, counter.wakes.load(atomic::Ordering::SeqCst));
|
||||
assert_eq!(Poll::Pending, fut.as_mut().poll(&waker));
|
||||
assert_eq!(1, counter.wakes.load(atomic::Ordering::SeqCst));
|
||||
|
|
56
src/test/run-pass/auxiliary/arc_wake.rs
Normal file
56
src/test/run-pass/auxiliary/arc_wake.rs
Normal file
|
@ -0,0 +1,56 @@
|
|||
// edition:2018
|
||||
|
||||
#![feature(arbitrary_self_types, futures_api)]
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::task::{
|
||||
Poll, Waker, RawWaker, RawWakerVTable,
|
||||
};
|
||||
|
||||
macro_rules! waker_vtable {
|
||||
($ty:ident) => {
|
||||
&RawWakerVTable {
|
||||
clone: clone_arc_raw::<$ty>,
|
||||
drop: drop_arc_raw::<$ty>,
|
||||
wake: wake_arc_raw::<$ty>,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub trait ArcWake {
|
||||
fn wake(arc_self: &Arc<Self>);
|
||||
|
||||
fn into_waker(wake: Arc<Self>) -> Waker where Self: Sized
|
||||
{
|
||||
let ptr = Arc::into_raw(wake) as *const();
|
||||
|
||||
unsafe {
|
||||
Waker::new_unchecked(RawWaker::new(ptr, waker_vtable!(Self)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn increase_refcount<T: ArcWake>(data: *const()) {
|
||||
// Retain Arc by creating a copy
|
||||
let arc: Arc<T> = Arc::from_raw(data as *const T);
|
||||
let arc_clone = arc.clone();
|
||||
// Forget the Arcs again, so that the refcount isn't decrased
|
||||
let _ = Arc::into_raw(arc);
|
||||
let _ = Arc::into_raw(arc_clone);
|
||||
}
|
||||
|
||||
unsafe fn clone_arc_raw<T: ArcWake>(data: *const()) -> RawWaker {
|
||||
increase_refcount::<T>(data);
|
||||
RawWaker::new(data, waker_vtable!(T))
|
||||
}
|
||||
|
||||
unsafe fn drop_arc_raw<T: ArcWake>(data: *const()) {
|
||||
// Drop Arc
|
||||
let _: Arc<T> = Arc::from_raw(data as *const T);
|
||||
}
|
||||
|
||||
unsafe fn wake_arc_raw<T: ArcWake>(data: *const()) {
|
||||
let arc: Arc<T> = Arc::from_raw(data as *const T);
|
||||
ArcWake::wake(&arc);
|
||||
let _ = Arc::into_raw(arc);
|
||||
}
|
|
@ -1,30 +1,28 @@
|
|||
// aux-build:arc_wake.rs
|
||||
|
||||
#![feature(arbitrary_self_types, futures_api)]
|
||||
#![allow(unused)]
|
||||
|
||||
extern crate arc_wake;
|
||||
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::rc::Rc;
|
||||
use std::sync::{
|
||||
Arc,
|
||||
atomic::{self, AtomicUsize},
|
||||
};
|
||||
use std::task::{
|
||||
Poll, Wake, Waker, LocalWaker,
|
||||
local_waker, local_waker_from_nonlocal,
|
||||
Poll, Waker,
|
||||
};
|
||||
use arc_wake::ArcWake;
|
||||
|
||||
struct Counter {
|
||||
local_wakes: AtomicUsize,
|
||||
nonlocal_wakes: AtomicUsize,
|
||||
wakes: AtomicUsize,
|
||||
}
|
||||
|
||||
impl Wake for Counter {
|
||||
fn wake(this: &Arc<Self>) {
|
||||
this.nonlocal_wakes.fetch_add(1, atomic::Ordering::SeqCst);
|
||||
}
|
||||
|
||||
unsafe fn wake_local(this: &Arc<Self>) {
|
||||
this.local_wakes.fetch_add(1, atomic::Ordering::SeqCst);
|
||||
impl ArcWake for Counter {
|
||||
fn wake(arc_self: &Arc<Self>) {
|
||||
arc_self.wakes.fetch_add(1, atomic::Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,40 +30,28 @@ struct MyFuture;
|
|||
|
||||
impl Future for MyFuture {
|
||||
type Output = ();
|
||||
fn poll(self: Pin<&mut Self>, lw: &LocalWaker) -> Poll<Self::Output> {
|
||||
// Wake once locally
|
||||
lw.wake();
|
||||
// Wake twice non-locally
|
||||
let waker = lw.clone().into_waker();
|
||||
fn poll(self: Pin<&mut Self>, waker: &Waker) -> Poll<Self::Output> {
|
||||
// Wake twice
|
||||
waker.wake();
|
||||
waker.wake();
|
||||
Poll::Ready(())
|
||||
}
|
||||
}
|
||||
|
||||
fn test_local_waker() {
|
||||
fn test_waker() {
|
||||
let counter = Arc::new(Counter {
|
||||
local_wakes: AtomicUsize::new(0),
|
||||
nonlocal_wakes: AtomicUsize::new(0),
|
||||
wakes: AtomicUsize::new(0),
|
||||
});
|
||||
let waker = unsafe { local_waker(counter.clone()) };
|
||||
assert_eq!(Poll::Ready(()), Pin::new(&mut MyFuture).poll(&waker));
|
||||
assert_eq!(1, counter.local_wakes.load(atomic::Ordering::SeqCst));
|
||||
assert_eq!(2, counter.nonlocal_wakes.load(atomic::Ordering::SeqCst));
|
||||
}
|
||||
let waker = ArcWake::into_waker(counter.clone());
|
||||
assert_eq!(2, Arc::strong_count(&counter));
|
||||
|
||||
fn test_local_as_nonlocal_waker() {
|
||||
let counter = Arc::new(Counter {
|
||||
local_wakes: AtomicUsize::new(0),
|
||||
nonlocal_wakes: AtomicUsize::new(0),
|
||||
});
|
||||
let waker: LocalWaker = local_waker_from_nonlocal(counter.clone());
|
||||
assert_eq!(Poll::Ready(()), Pin::new(&mut MyFuture).poll(&waker));
|
||||
assert_eq!(0, counter.local_wakes.load(atomic::Ordering::SeqCst));
|
||||
assert_eq!(3, counter.nonlocal_wakes.load(atomic::Ordering::SeqCst));
|
||||
assert_eq!(2, counter.wakes.load(atomic::Ordering::SeqCst));
|
||||
|
||||
drop(waker);
|
||||
assert_eq!(1, Arc::strong_count(&counter));
|
||||
}
|
||||
|
||||
fn main() {
|
||||
test_local_waker();
|
||||
test_local_as_nonlocal_waker();
|
||||
test_waker();
|
||||
}
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
// exact-check
|
||||
|
||||
const QUERY = 'waker_from';
|
||||
|
||||
const EXPECTED = {
|
||||
'others': [
|
||||
{ 'path': 'std::task', 'name': 'local_waker_from_nonlocal' },
|
||||
{ 'path': 'alloc::task', 'name': 'local_waker_from_nonlocal' },
|
||||
],
|
||||
};
|
|
@ -2,7 +2,7 @@ error: unused import: `std::option`
|
|||
--> $DIR/bad-lint-cap2.rs:6:5
|
||||
|
|
||||
LL | use std::option; //~ ERROR
|
||||
| ----^^^^^^^^^^^- help: remove the whole `use` item
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/bad-lint-cap2.rs:4:9
|
||||
|
|
|
@ -2,7 +2,7 @@ warning: unused import: `std::option`
|
|||
--> $DIR/bad-lint-cap3.rs:7:5
|
||||
|
|
||||
LL | use std::option; //~ WARN
|
||||
| ----^^^^^^^^^^^- help: remove the whole `use` item
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/bad-lint-cap3.rs:4:9
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
fn main() {
|
||||
if let Some(b) = None { //~ ERROR: `if let` arms have incompatible types
|
||||
//~^ expected (), found integer
|
||||
//~| expected type `()`
|
||||
//~| found type `{integer}`
|
||||
if let Some(b) = None {
|
||||
//~^ NOTE if let` arms have incompatible types
|
||||
()
|
||||
} else {
|
||||
1
|
||||
};
|
||||
//~^^ ERROR: `if let` arms have incompatible types
|
||||
//~| NOTE expected (), found integer
|
||||
//~| NOTE expected type `()`
|
||||
}
|
||||
|
|
|
@ -1,25 +1,17 @@
|
|||
error[E0308]: `if let` arms have incompatible types
|
||||
--> $DIR/if-let-arm-types.rs:2:5
|
||||
--> $DIR/if-let-arm-types.rs:6:9
|
||||
|
|
||||
LL | / if let Some(b) = None { //~ ERROR: `if let` arms have incompatible types
|
||||
LL | | //~^ expected (), found integer
|
||||
LL | | //~| expected type `()`
|
||||
LL | | //~| found type `{integer}`
|
||||
... |
|
||||
LL | / if let Some(b) = None {
|
||||
LL | | //~^ NOTE if let` arms have incompatible types
|
||||
LL | | ()
|
||||
LL | | } else {
|
||||
LL | | 1
|
||||
| | ^ expected (), found integer
|
||||
LL | | };
|
||||
| |_____^ expected (), found integer
|
||||
| |_____- `if let` arms have incompatible types
|
||||
|
|
||||
= note: expected type `()`
|
||||
found type `{integer}`
|
||||
note: `if let` arm with an incompatible type
|
||||
--> $DIR/if-let-arm-types.rs:7:12
|
||||
|
|
||||
LL | } else {
|
||||
| ____________^
|
||||
LL | | 1
|
||||
LL | | };
|
||||
| |_____^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ error: unused import: `super::f`
|
|||
--> $DIR/unused.rs:7:24
|
||||
|
|
||||
LL | pub(super) use super::f; //~ ERROR unused
|
||||
| ---------------^^^^^^^^- help: remove the whole `use` item
|
||||
| ^^^^^^^^
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/unused.rs:1:9
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
fn main() {
|
||||
match Some(10) {
|
||||
//~^ ERROR match arms have incompatible types
|
||||
//~| expected type `bool`
|
||||
//~| found type `()`
|
||||
//~| expected bool, found ()
|
||||
//~^ NOTE `match` arms have incompatible types
|
||||
Some(5) => false,
|
||||
//~^ NOTE this is found to be of type `bool`
|
||||
Some(2) => true,
|
||||
//~^ NOTE this is found to be of type `bool`
|
||||
None => (),
|
||||
//~^ ERROR match arms have incompatible types
|
||||
//~| NOTE expected bool, found ()
|
||||
//~| NOTE expected type `bool`
|
||||
_ => true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
error[E0308]: match arms have incompatible types
|
||||
--> $DIR/issue-11319.rs:2:5
|
||||
--> $DIR/issue-11319.rs:8:20
|
||||
|
|
||||
LL | / match Some(10) {
|
||||
LL | | //~^ ERROR match arms have incompatible types
|
||||
LL | | //~| expected type `bool`
|
||||
LL | | //~| found type `()`
|
||||
... |
|
||||
LL | | //~^ NOTE `match` arms have incompatible types
|
||||
LL | | Some(5) => false,
|
||||
| | ----- this is found to be of type `bool`
|
||||
LL | | //~^ NOTE this is found to be of type `bool`
|
||||
LL | | Some(2) => true,
|
||||
| | ---- this is found to be of type `bool`
|
||||
LL | | //~^ NOTE this is found to be of type `bool`
|
||||
LL | | None => (),
|
||||
| | -- match arm with an incompatible type
|
||||
| | ^^ expected bool, found ()
|
||||
... |
|
||||
LL | | _ => true
|
||||
LL | | }
|
||||
| |_____^ expected bool, found ()
|
||||
| |_____- `match` arms have incompatible types
|
||||
|
|
||||
= note: expected type `bool`
|
||||
found type `()`
|
||||
|
|
|
@ -97,7 +97,7 @@ impl Debug for Player {
|
|||
}
|
||||
|
||||
fn str_to_direction(to_parse: &str) -> RoomDirection {
|
||||
match to_parse { //~ ERROR match arms have incompatible types
|
||||
match to_parse {
|
||||
"w" | "west" => RoomDirection::West,
|
||||
"e" | "east" => RoomDirection::East,
|
||||
"n" | "north" => RoomDirection::North,
|
||||
|
@ -108,6 +108,7 @@ fn str_to_direction(to_parse: &str) -> RoomDirection {
|
|||
"down" => RoomDirection::Down,
|
||||
_ => None
|
||||
}
|
||||
//~^^ ERROR match arms have incompatible types
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -10,17 +10,19 @@ LL | Some(entry) => Ok(entry),
|
|||
| ^^^^^^^^^ ...but data from `room` is returned here
|
||||
|
||||
error[E0308]: match arms have incompatible types
|
||||
--> $DIR/issue-17728.rs:100:5
|
||||
--> $DIR/issue-17728.rs:109:14
|
||||
|
|
||||
LL | / match to_parse { //~ ERROR match arms have incompatible types
|
||||
LL | / match to_parse {
|
||||
LL | | "w" | "west" => RoomDirection::West,
|
||||
LL | | "e" | "east" => RoomDirection::East,
|
||||
LL | | "n" | "north" => RoomDirection::North,
|
||||
... |
|
||||
LL | | "down" => RoomDirection::Down,
|
||||
| | ------------------- this and all prior arms are found to be of type `RoomDirection`
|
||||
LL | | _ => None
|
||||
| | ---- match arm with an incompatible type
|
||||
| | ^^^^ expected enum `RoomDirection`, found enum `std::option::Option`
|
||||
LL | | }
|
||||
| |_____^ expected enum `RoomDirection`, found enum `std::option::Option`
|
||||
| |_____- `match` arms have incompatible types
|
||||
|
|
||||
= note: expected type `RoomDirection`
|
||||
found type `std::option::Option<_>`
|
||||
|
|
|
@ -6,11 +6,11 @@ fn closure_to_loc() {
|
|||
|
||||
fn closure_from_match() {
|
||||
let x = match 1usize {
|
||||
//~^ ERROR match arms have incompatible types
|
||||
1 => |c| c + 1,
|
||||
2 => |c| c - 1,
|
||||
_ => |c| c - 1
|
||||
};
|
||||
//~^^^ ERROR match arms have incompatible types
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
|
|
|
@ -10,20 +10,20 @@ LL | x = |c| c + 1;
|
|||
= help: consider boxing your closure and/or using it as a trait object
|
||||
|
||||
error[E0308]: match arms have incompatible types
|
||||
--> $DIR/issue-24036.rs:8:13
|
||||
--> $DIR/issue-24036.rs:10:14
|
||||
|
|
||||
LL | let x = match 1usize {
|
||||
| _____________^
|
||||
LL | | //~^ ERROR match arms have incompatible types
|
||||
| _____________-
|
||||
LL | | 1 => |c| c + 1,
|
||||
| | --------- this is found to be of type `[closure@$DIR/issue-24036.rs:9:14: 9:23]`
|
||||
LL | | 2 => |c| c - 1,
|
||||
| | --------- match arm with an incompatible type
|
||||
| | ^^^^^^^^^ expected closure, found a different closure
|
||||
LL | | _ => |c| c - 1
|
||||
LL | | };
|
||||
| |_____^ expected closure, found a different closure
|
||||
| |_____- `match` arms have incompatible types
|
||||
|
|
||||
= note: expected type `[closure@$DIR/issue-24036.rs:10:14: 10:23]`
|
||||
found type `[closure@$DIR/issue-24036.rs:11:14: 11:23]`
|
||||
= note: expected type `[closure@$DIR/issue-24036.rs:9:14: 9:23]`
|
||||
found type `[closure@$DIR/issue-24036.rs:10:14: 10:23]`
|
||||
= note: no two closures, even if identical, have the same type
|
||||
= help: consider boxing your closure and/or using it as a trait object
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ error: unused import: `std::thread`
|
|||
--> $DIR/issue-30730.rs:3:5
|
||||
|
|
||||
LL | use std::thread;
|
||||
| ----^^^^^^^^^^^- help: remove the whole `use` item
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/issue-30730.rs:2:9
|
||||
|
|
|
@ -2,7 +2,7 @@ error: unused import: `a::x`
|
|||
--> $DIR/lint-directives-on-use-items-issue-10534.rs:12:9
|
||||
|
|
||||
LL | use a::x; //~ ERROR: unused import
|
||||
| ----^^^^- help: remove the whole `use` item
|
||||
| ^^^^
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/lint-directives-on-use-items-issue-10534.rs:1:9
|
||||
|
@ -14,7 +14,7 @@ error: unused import: `a::y`
|
|||
--> $DIR/lint-directives-on-use-items-issue-10534.rs:21:9
|
||||
|
|
||||
LL | use a::y; //~ ERROR: unused import
|
||||
| ----^^^^- help: remove the whole `use` item
|
||||
| ^^^^
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/lint-directives-on-use-items-issue-10534.rs:20:12
|
||||
|
|
|
@ -2,7 +2,7 @@ error: unused import: `std::fmt::{}`
|
|||
--> $DIR/lint-unused-imports.rs:8:5
|
||||
|
|
||||
LL | use std::fmt::{};
|
||||
| ----^^^^^^^^^^^^- help: remove the whole `use` item
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/lint-unused-imports.rs:1:9
|
||||
|
@ -14,39 +14,37 @@ error: unused imports: `None`, `Some`
|
|||
--> $DIR/lint-unused-imports.rs:12:27
|
||||
|
|
||||
LL | use std::option::Option::{Some, None};
|
||||
| --------------------------^^^^--^^^^-- help: remove the whole `use` item
|
||||
| ^^^^ ^^^^
|
||||
|
||||
error: unused import: `test::A`
|
||||
--> $DIR/lint-unused-imports.rs:15:5
|
||||
|
|
||||
LL | use test::A; //~ ERROR unused import: `test::A`
|
||||
| ----^^^^^^^- help: remove the whole `use` item
|
||||
| ^^^^^^^
|
||||
|
||||
error: unused import: `bar`
|
||||
--> $DIR/lint-unused-imports.rs:24:18
|
||||
|
|
||||
LL | use test2::{foo, bar}; //~ ERROR unused import: `bar`
|
||||
| --^^^
|
||||
| |
|
||||
| help: remove the unused import
|
||||
| ^^^
|
||||
|
||||
error: unused import: `foo::Square`
|
||||
--> $DIR/lint-unused-imports.rs:52:13
|
||||
|
|
||||
LL | use foo::Square; //~ ERROR unused import: `foo::Square`
|
||||
| ----^^^^^^^^^^^- help: remove the whole `use` item
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: unused import: `self::g`
|
||||
--> $DIR/lint-unused-imports.rs:68:9
|
||||
|
|
||||
LL | use self::g; //~ ERROR unused import: `self::g`
|
||||
| ----^^^^^^^- help: remove the whole `use` item
|
||||
| ^^^^^^^
|
||||
|
||||
error: unused import: `test2::foo`
|
||||
--> $DIR/lint-unused-imports.rs:77:9
|
||||
|
|
||||
LL | use test2::foo; //~ ERROR unused import: `test2::foo`
|
||||
| ----^^^^^^^^^^- help: remove the whole `use` item
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: unused import: `test::B2`
|
||||
--> $DIR/lint-unused-imports.rs:20:5
|
||||
|
|
|
@ -2,7 +2,7 @@ warning: unused import: `std::string::ToString`
|
|||
--> $DIR/lints-in-foreign-macros.rs:11:16
|
||||
|
|
||||
LL | () => {use std::string::ToString;} //~ WARN: unused import
|
||||
| ----^^^^^^^^^^^^^^^^^^^^^- help: remove the whole `use` item
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
...
|
||||
LL | mod a { foo!(); }
|
||||
| ------- in this macro invocation
|
||||
|
@ -17,13 +17,13 @@ warning: unused import: `std::string::ToString`
|
|||
--> $DIR/lints-in-foreign-macros.rs:16:18
|
||||
|
|
||||
LL | mod c { baz!(use std::string::ToString;); } //~ WARN: unused import
|
||||
| ----^^^^^^^^^^^^^^^^^^^^^- help: remove the whole `use` item
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
warning: unused import: `std::string::ToString`
|
||||
--> $DIR/lints-in-foreign-macros.rs:17:19
|
||||
|
|
||||
LL | mod d { baz2!(use std::string::ToString;); } //~ WARN: unused import
|
||||
| ----^^^^^^^^^^^^^^^^^^^^^- help: remove the whole `use` item
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
warning: missing documentation for crate
|
||||
--> $DIR/lints-in-foreign-macros.rs:4:1
|
||||
|
|
45
src/test/ui/match/match-type-err-first-arm.rs
Normal file
45
src/test/ui/match/match-type-err-first-arm.rs
Normal file
|
@ -0,0 +1,45 @@
|
|||
fn main() {
|
||||
let _ = test_func1(1);
|
||||
let _ = test_func2(1);
|
||||
}
|
||||
|
||||
fn test_func1(n: i32) -> i32 {
|
||||
//~^ NOTE expected `i32` because of return type
|
||||
match n {
|
||||
12 => 'b',
|
||||
//~^ ERROR mismatched types
|
||||
//~| NOTE expected i32, found char
|
||||
_ => 42,
|
||||
}
|
||||
}
|
||||
|
||||
fn test_func2(n: i32) -> i32 {
|
||||
let x = match n {
|
||||
//~^ NOTE `match` arms have incompatible types
|
||||
12 => 'b',
|
||||
//~^ NOTE this is found to be of type `char`
|
||||
_ => 42,
|
||||
//~^ ERROR match arms have incompatible types
|
||||
//~| NOTE expected char, found integer
|
||||
//~| NOTE expected type `char`
|
||||
};
|
||||
x
|
||||
}
|
||||
|
||||
fn test_func3(n: i32) -> i32 {
|
||||
let x = match n {
|
||||
//~^ NOTE `match` arms have incompatible types
|
||||
1 => 'b',
|
||||
2 => 'b',
|
||||
3 => 'b',
|
||||
4 => 'b',
|
||||
5 => 'b',
|
||||
6 => 'b',
|
||||
//~^ NOTE this and all prior arms are found to be of type `char`
|
||||
_ => 42,
|
||||
//~^ ERROR match arms have incompatible types
|
||||
//~| NOTE expected char, found integer
|
||||
//~| NOTE expected type `char`
|
||||
};
|
||||
x
|
||||
}
|
53
src/test/ui/match/match-type-err-first-arm.stderr
Normal file
53
src/test/ui/match/match-type-err-first-arm.stderr
Normal file
|
@ -0,0 +1,53 @@
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/match-type-err-first-arm.rs:9:15
|
||||
|
|
||||
LL | fn test_func1(n: i32) -> i32 {
|
||||
| --- expected `i32` because of return type
|
||||
...
|
||||
LL | 12 => 'b',
|
||||
| ^^^ expected i32, found char
|
||||
|
||||
error[E0308]: match arms have incompatible types
|
||||
--> $DIR/match-type-err-first-arm.rs:21:14
|
||||
|
|
||||
LL | let x = match n {
|
||||
| _____________-
|
||||
LL | | //~^ NOTE `match` arms have incompatible types
|
||||
LL | | 12 => 'b',
|
||||
| | --- this is found to be of type `char`
|
||||
LL | | //~^ NOTE this is found to be of type `char`
|
||||
LL | | _ => 42,
|
||||
| | ^^ expected char, found integer
|
||||
... |
|
||||
LL | | //~| NOTE expected type `char`
|
||||
LL | | };
|
||||
| |_____- `match` arms have incompatible types
|
||||
|
|
||||
= note: expected type `char`
|
||||
found type `{integer}`
|
||||
|
||||
error[E0308]: match arms have incompatible types
|
||||
--> $DIR/match-type-err-first-arm.rs:39:14
|
||||
|
|
||||
LL | let x = match n {
|
||||
| _____________-
|
||||
LL | | //~^ NOTE `match` arms have incompatible types
|
||||
LL | | 1 => 'b',
|
||||
LL | | 2 => 'b',
|
||||
... |
|
||||
LL | | 6 => 'b',
|
||||
| | --- this and all prior arms are found to be of type `char`
|
||||
LL | | //~^ NOTE this and all prior arms are found to be of type `char`
|
||||
LL | | _ => 42,
|
||||
| | ^^ expected char, found integer
|
||||
... |
|
||||
LL | | //~| NOTE expected type `char`
|
||||
LL | | };
|
||||
| |_____- `match` arms have incompatible types
|
||||
|
|
||||
= note: expected type `char`
|
||||
found type `{integer}`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
|
@ -2,7 +2,7 @@ warning: unused import: `m::Tr1 as _`
|
|||
--> $DIR/basic.rs:26:9
|
||||
|
|
||||
LL | use m::Tr1 as _; //~ WARN unused import
|
||||
| ----^^^^^^^^^^^- help: remove the whole `use` item
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/basic.rs:4:9
|
||||
|
@ -14,5 +14,5 @@ warning: unused import: `S as _`
|
|||
--> $DIR/basic.rs:27:9
|
||||
|
|
||||
LL | use S as _; //~ WARN unused import
|
||||
| ----^^^^^^- help: remove the whole `use` item
|
||||
| ^^^^^^
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ error: unused import: `core::any`
|
|||
--> $DIR/unused-2018.rs:6:9
|
||||
|
|
||||
LL | use core::any; //~ ERROR unused import: `core::any`
|
||||
| ----^^^^^^^^^- help: remove the whole `use` item
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/unused-2018.rs:3:9
|
||||
|
@ -14,7 +14,7 @@ error: unused import: `core`
|
|||
--> $DIR/unused-2018.rs:10:9
|
||||
|
|
||||
LL | use core; //~ ERROR unused import: `core`
|
||||
| ----^^^^- help: remove the whole `use` item
|
||||
| ^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
@ -10,8 +10,4 @@ note: lint level defined here
|
|||
LL | #![warn(unused)]
|
||||
| ^^^^^^
|
||||
= note: #[warn(unused_imports)] implied by #[warn(unused)]
|
||||
help: remove the unused imports
|
||||
|
|
||||
LL | use std::cmp::{min};
|
||||
| -- --
|
||||
|
||||
|
|
|
@ -2,9 +2,9 @@ error[E0308]: mismatched types
|
|||
--> $DIR/as-ref.rs:6:27
|
||||
|
|
||||
LL | opt.map(|arg| takes_ref(arg));
|
||||
| - ^^^ expected &Foo, found struct `Foo`
|
||||
| --- ^^^ expected &Foo, found struct `Foo`
|
||||
| |
|
||||
| help: consider using `as_ref` instead: `as_ref().`
|
||||
| help: consider using `as_ref` instead: `as_ref().map`
|
||||
|
|
||||
= note: expected type `&Foo`
|
||||
found type `Foo`
|
||||
|
@ -13,9 +13,9 @@ error[E0308]: mismatched types
|
|||
--> $DIR/as-ref.rs:8:37
|
||||
|
|
||||
LL | opt.and_then(|arg| Some(takes_ref(arg)));
|
||||
| - ^^^ expected &Foo, found struct `Foo`
|
||||
| -------- ^^^ expected &Foo, found struct `Foo`
|
||||
| |
|
||||
| help: consider using `as_ref` instead: `as_ref().`
|
||||
| help: consider using `as_ref` instead: `as_ref().and_then`
|
||||
|
|
||||
= note: expected type `&Foo`
|
||||
found type `Foo`
|
||||
|
@ -24,9 +24,9 @@ error[E0308]: mismatched types
|
|||
--> $DIR/as-ref.rs:11:27
|
||||
|
|
||||
LL | opt.map(|arg| takes_ref(arg));
|
||||
| - ^^^ expected &Foo, found struct `Foo`
|
||||
| --- ^^^ expected &Foo, found struct `Foo`
|
||||
| |
|
||||
| help: consider using `as_ref` instead: `as_ref().`
|
||||
| help: consider using `as_ref` instead: `as_ref().map`
|
||||
|
|
||||
= note: expected type `&Foo`
|
||||
found type `Foo`
|
||||
|
@ -35,9 +35,9 @@ error[E0308]: mismatched types
|
|||
--> $DIR/as-ref.rs:13:35
|
||||
|
|
||||
LL | opt.and_then(|arg| Ok(takes_ref(arg)));
|
||||
| - ^^^ expected &Foo, found struct `Foo`
|
||||
| -------- ^^^ expected &Foo, found struct `Foo`
|
||||
| |
|
||||
| help: consider using `as_ref` instead: `as_ref().`
|
||||
| help: consider using `as_ref` instead: `as_ref().and_then`
|
||||
|
|
||||
= note: expected type `&Foo`
|
||||
found type `Foo`
|
||||
|
|
|
@ -2,7 +2,7 @@ error: unused imports: `*`, `Foo`, `baz::{}`, `foobar::*`
|
|||
--> $DIR/use-nested-groups-unused-imports.rs:16:11
|
||||
|
|
||||
LL | use foo::{Foo, bar::{baz::{}, foobar::*}, *};
|
||||
| ----------^^^--------^^^^^^^--^^^^^^^^^---^-- help: remove the whole `use` item
|
||||
| ^^^ ^^^^^^^ ^^^^^^^^^ ^
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/use-nested-groups-unused-imports.rs:3:9
|
||||
|
@ -14,15 +14,13 @@ error: unused import: `*`
|
|||
--> $DIR/use-nested-groups-unused-imports.rs:18:24
|
||||
|
|
||||
LL | use foo::bar::baz::{*, *};
|
||||
| --^
|
||||
| |
|
||||
| help: remove the unused import
|
||||
| ^
|
||||
|
||||
error: unused import: `foo::{}`
|
||||
--> $DIR/use-nested-groups-unused-imports.rs:20:5
|
||||
|
|
||||
LL | use foo::{};
|
||||
| ----^^^^^^^- help: remove the whole `use` item
|
||||
| ^^^^^^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue