let compiler = self.compiler(self.top_stage, host);
cmd.env("RUSTC_STAGE", compiler.stage.to_string())
.env("RUSTC_SYSROOT", self.sysroot(compiler))
- .env(
- "RUSTDOC_LIBDIR",
- self.sysroot_libdir(compiler, self.config.build),
- )
+ // Note that this is *not* the sysroot_libdir because rustdoc must be linked
+ // equivalently to rustc.
+ .env("RUSTDOC_LIBDIR", self.rustc_libdir(compiler))
.env("CFG_RELEASE_CHANNEL", &self.config.channel)
.env("RUSTDOC_REAL", self.rustdoc(host))
.env("RUSTDOC_CRATE_VERSION", self.rust_version())
} else {
&maybe_sysroot
};
- let libdir = sysroot.join(libdir(&compiler.host));
+ let libdir = self.rustc_libdir(compiler);
// Customize the compiler we're running. Specify the compiler to cargo
// as our shim and then pass it some various options used to configure
cargo.env("RUSTC_ERROR_FORMAT", error_format);
}
if cmd != "build" && cmd != "check" && cmd != "rustc" && want_rustdoc {
- cargo.env("RUSTDOC_LIBDIR", self.sysroot_libdir(compiler, self.config.build));
+ cargo.env("RUSTDOC_LIBDIR", self.rustc_libdir(compiler));
}
if mode.is_tool() {
fn run(self, builder: &Builder) -> PathBuf {
let target_compiler = builder.compiler(builder.top_stage, self.host);
+ if target_compiler.stage == 0 {
+ if !target_compiler.is_snapshot(builder) {
+ panic!("rustdoc in stage 0 must be snapshot rustdoc");
+ }
+ return builder.initial_rustc.with_file_name(exe("rustdoc", &target_compiler.host));
+ }
let target = target_compiler.host;
- let build_compiler = if target_compiler.stage == 0 {
- builder.compiler(0, builder.config.build)
- } else if target_compiler.stage >= 2 {
- // Past stage 2, we consider the compiler to be ABI-compatible and hence capable of
- // building rustdoc itself.
- builder.compiler(target_compiler.stage, builder.config.build)
- } else {
- // Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise
- // we'd have stageN/bin/rustc and stageN/bin/rustdoc be effectively different stage
- // compilers, which isn't what we want.
- builder.compiler(target_compiler.stage - 1, builder.config.build)
- };
-
- builder.ensure(compile::Rustc { compiler: build_compiler, target });
- builder.ensure(compile::Rustc {
- compiler: build_compiler,
- target: builder.config.build,
- });
+ // Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise
+ // we'd have stageN/bin/rustc and stageN/bin/rustdoc be effectively different stage
+ // compilers, which isn't what we want. Rustdoc should be linked in the same way as the
+ // rustc compiler it's paired with, so it must be built with the previous stage compiler.
+ let build_compiler = builder.compiler(target_compiler.stage - 1, builder.config.build);
+
+ // The presence of `target_compiler` ensures that the necessary libraries (codegen backends,
+ // compiler libraries, ...) are built. Rustdoc does not require the presence of any
+ // libraries within sysroot_libdir (i.e., rustlib), though doctests may want it (since
+ // they'll be linked to those libraries). As such, don't explicitly `ensure` any additional
+ // libraries here. The intuition here is that If we've built a compiler, we should be able
+ // to build rustdoc.
let mut cargo = prepare_tool_cargo(
builder,
% 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).
% 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).
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.
% 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).
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;
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)
}
}
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
+++ /dev/null
-//! 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)
- }
- }
-}
/// - 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
/// [`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.
Ok(())
}
+/// Padding after the end of something. Returned by `Formatter::padding`.
+#[must_use = "don't forget to write the post padding"]
+struct PostPadding {
+ fill: char,
+ padding: usize,
+}
+
+impl PostPadding {
+ fn new(fill: char, padding: usize) -> PostPadding {
+ PostPadding { fill, padding }
+ }
+
+ /// Write this post padding.
+ fn write(self, buf: &mut dyn Write) -> Result {
+ for _ in 0..self.padding {
+ buf.write_char(self.fill)?;
+ }
+ Ok(())
+ }
+}
+
impl<'a> Formatter<'a> {
fn wrap_buf<'b, 'c, F>(&'b mut self, wrap: F) -> Formatter<'c>
where 'b: 'c, F: FnOnce(&'b mut (dyn Write+'b)) -> &'c mut (dyn Write+'c)
sign = Some('+'); width += 1;
}
- let prefixed = self.alternate();
- if prefixed {
+ let prefix = if self.alternate() {
width += prefix.chars().count();
- }
+ Some(prefix)
+ } else {
+ None
+ };
// Writes the sign if it exists, and then the prefix if it was requested
- let write_prefix = |f: &mut Formatter| {
+ #[inline(never)]
+ fn write_prefix(f: &mut Formatter, sign: Option<char>, prefix: Option<&str>) -> Result {
if let Some(c) = sign {
f.buf.write_char(c)?;
}
- if prefixed { f.buf.write_str(prefix) }
- else { Ok(()) }
- };
+ if let Some(prefix) = prefix {
+ f.buf.write_str(prefix)
+ } else {
+ Ok(())
+ }
+ }
// The `width` field is more of a `min-width` parameter at this point.
match self.width {
// If there's no minimum length requirements then we can just
// write the bytes.
None => {
- write_prefix(self)?; self.buf.write_str(buf)
+ write_prefix(self, sign, prefix)?;
+ self.buf.write_str(buf)
}
// Check if we're over the minimum width, if so then we can also
// just write the bytes.
Some(min) if width >= min => {
- write_prefix(self)?; self.buf.write_str(buf)
+ write_prefix(self, sign, prefix)?;
+ self.buf.write_str(buf)
}
// The sign and prefix goes before the padding if the fill character
// is zero
Some(min) if self.sign_aware_zero_pad() => {
self.fill = '0';
self.align = rt::v1::Alignment::Right;
- write_prefix(self)?;
- self.with_padding(min - width, rt::v1::Alignment::Right, |f| {
- f.buf.write_str(buf)
- })
+ write_prefix(self, sign, prefix)?;
+ let post_padding = self.padding(min - width, rt::v1::Alignment::Right)?;
+ self.buf.write_str(buf)?;
+ post_padding.write(self.buf)
}
// Otherwise, the sign and prefix goes after the padding
Some(min) => {
- self.with_padding(min - width, rt::v1::Alignment::Right, |f| {
- write_prefix(f)?; f.buf.write_str(buf)
- })
+ let post_padding = self.padding(min - width, rt::v1::Alignment::Right)?;
+ write_prefix(self, sign, prefix)?;
+ self.buf.write_str(buf)?;
+ post_padding.write(self.buf)
}
}
}
// up the minimum width with the specified string + some alignment.
Some(width) => {
let align = rt::v1::Alignment::Left;
- self.with_padding(width - s.chars().count(), align, |me| {
- me.buf.write_str(s)
- })
+ let post_padding = self.padding(width - s.chars().count(), align)?;
+ self.buf.write_str(s)?;
+ post_padding.write(self.buf)
}
}
}
- /// Runs a callback, emitting the correct padding either before or
- /// afterwards depending on whether right or left alignment is requested.
- fn with_padding<F>(&mut self, padding: usize, default: rt::v1::Alignment,
- f: F) -> Result
- where F: FnOnce(&mut Formatter) -> Result,
- {
+ /// Write the pre-padding and return the unwritten post-padding. Callers are
+ /// responsible for ensuring post-padding is written after the thing that is
+ /// being padded.
+ fn padding(
+ &mut self,
+ padding: usize,
+ default: rt::v1::Alignment
+ ) -> result::Result<PostPadding, Error> {
let align = match self.align {
rt::v1::Alignment::Unknown => default,
_ => self.align
rt::v1::Alignment::Center => (padding / 2, (padding + 1) / 2),
};
- let mut fill = [0; 4];
- let fill = self.fill.encode_utf8(&mut fill);
-
for _ in 0..pre_pad {
- self.buf.write_str(fill)?;
- }
-
- f(self)?;
-
- for _ in 0..post_pad {
- self.buf.write_str(fill)?;
+ self.buf.write_char(self.fill)?;
}
- Ok(())
+ Ok(PostPadding::new(self.fill, post_pad))
}
/// Takes the formatted parts and applies the padding.
let ret = if width <= len { // no padding
self.write_formatted_parts(&formatted)
} else {
- self.with_padding(width - len, align, |f| {
- f.write_formatted_parts(&formatted)
- })
+ let post_padding = self.padding(width - len, align)?;
+ self.write_formatted_parts(&formatted)?;
+ post_padding.write(self.buf)
};
self.fill = old_fill;
self.align = old_align;
integer! { i64, u64 }
integer! { i128, u128 }
-const DEC_DIGITS_LUT: &'static[u8] =
+
+static DEC_DIGITS_LUT: &[u8; 200] =
b"0001020304050607080910111213141516171819\
2021222324252627282930313233343536373839\
4041424344454647484950515253545556575859\
8081828384858687888990919293949596979899";
macro_rules! impl_Display {
- ($($t:ident),*: $conv_fn:ident) => ($(
- #[stable(feature = "rust1", since = "1.0.0")]
- impl fmt::Display for $t {
- #[allow(unused_comparisons)]
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- let is_nonnegative = *self >= 0;
- let mut n = if is_nonnegative {
- self.$conv_fn()
- } else {
- // convert the negative num to positive by summing 1 to it's 2 complement
- (!self.$conv_fn()).wrapping_add(1)
- };
+ ($($t:ident),* as $u:ident via $conv_fn:ident named $name:ident) => {
+ fn $name(mut n: $u, is_nonnegative: bool, f: &mut fmt::Formatter) -> fmt::Result {
let mut buf = uninitialized_array![u8; 39];
let mut curr = buf.len() as isize;
let buf_ptr = MaybeUninit::first_ptr_mut(&mut buf);
unsafe {
// need at least 16 bits for the 4-characters-at-a-time to work.
- if ::mem::size_of::<$t>() >= 2 {
- // eagerly decode 4 characters at a time
- while n >= 10000 {
- let rem = (n % 10000) as isize;
- n /= 10000;
-
- let d1 = (rem / 100) << 1;
- let d2 = (rem % 100) << 1;
- curr -= 4;
- ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
- ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(curr + 2), 2);
- }
+ assert!(::mem::size_of::<$u>() >= 2);
+
+ // eagerly decode 4 characters at a time
+ while n >= 10000 {
+ let rem = (n % 10000) as isize;
+ n /= 10000;
+
+ let d1 = (rem / 100) << 1;
+ let d2 = (rem % 100) << 1;
+ curr -= 4;
+ ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
+ ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(curr + 2), 2);
}
// if we reach here numbers are <= 9999, so at most 4 chars long
};
f.pad_integral(is_nonnegative, "", buf_slice)
}
- })*);
+
+ $(
+ #[stable(feature = "rust1", since = "1.0.0")]
+ impl fmt::Display for $t {
+ #[allow(unused_comparisons)]
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let is_nonnegative = *self >= 0;
+ let n = if is_nonnegative {
+ self.$conv_fn()
+ } else {
+ // convert the negative num to positive by summing 1 to it's 2 complement
+ (!self.$conv_fn()).wrapping_add(1)
+ };
+ $name(n, is_nonnegative, f)
+ }
+ })*
+ };
+}
+
+// Include wasm32 in here since it doesn't reflect the native pointer size, and
+// often cares strongly about getting a smaller code size.
+#[cfg(any(target_pointer_width = "64", target_arch = "wasm32"))]
+mod imp {
+ use super::*;
+ impl_Display!(
+ i8, u8, i16, u16, i32, u32, i64, u64, usize, isize
+ as u64 via to_u64 named fmt_u64
+ );
+}
+
+#[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))]
+mod imp {
+ use super::*;
+ impl_Display!(i8, u8, i16, u16, i32, u32, isize, usize as u32 via to_u32 named fmt_u32);
+ impl_Display!(i64, u64 as u64 via to_u64 named fmt_u64);
}
-impl_Display!(i8, u8, i16, u16, i32, u32: to_u32);
-impl_Display!(i64, u64: to_u64);
-impl_Display!(i128, u128: to_u128);
-#[cfg(target_pointer_width = "16")]
-impl_Display!(isize, usize: to_u16);
-#[cfg(target_pointer_width = "32")]
-impl_Display!(isize, usize: to_u32);
-#[cfg(target_pointer_width = "64")]
-impl_Display!(isize, usize: to_u64);
+impl_Display!(i128, u128 as u128 via to_u128 named fmt_u128);
use marker::Unpin;
use ops;
use pin::Pin;
-use task::{Poll, LocalWaker};
+use task::{Poll, Waker};
/// A future represents an asynchronous computation.
///
/// 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
/// 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
/// 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)
}
}
{
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)
}
}
/// // 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(
/// 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)]
/// 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
///
pub use self::poll::Poll;
mod wake;
-pub use self::wake::{Waker, LocalWaker, UnsafeWake};
+pub use self::wake::{Waker, RawWaker, RawWakerVTable};
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 {}
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 fmt::Debug for Waker {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.debug_struct("Waker")
- .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
+ // 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 LocalWaker {
+impl fmt::Debug for Waker {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.debug_struct("LocalWaker")
+ let vtable_ptr = self.waker.vtable as *const RawWakerVTable;
+ f.debug_struct("Waker")
+ .field("data", &self.waker.data)
+ .field("vtable", &vtable_ptr)
.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()
- }
-}
authors = ["The Rust Project Developers"]
name = "panic_unwind"
version = "0.0.0"
+edition = "2018"
[lib]
path = "lib.rs"
#![allow(non_upper_case_globals)]
#![allow(unused)]
-use dwarf::DwarfReader;
+use crate::dwarf::DwarfReader;
use core::mem;
pub const DW_EH_PE_omit: u8 = 0xFF;
pub const USING_SJLJ_EXCEPTIONS: bool = cfg!(all(target_os = "ios", target_arch = "arm"));
-pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext)
+pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext<'_>)
-> Result<EHAction, ()>
{
if lsda.is_null() {
}
unsafe fn read_encoded_pointer(reader: &mut DwarfReader,
- context: &EHContext,
+ context: &EHContext<'_>,
encoding: u8)
-> Result<usize, ()> {
if encoding == DW_EH_PE_omit {
use core::any::Any;
use core::ptr;
+use core::mem;
use alloc::boxed::Box;
use libc::{self, c_int};
use unwind as uw;
-use core::mem;
pub fn payload() -> *mut u8 {
ptr::null_mut()
use unwind as uw;
use libc::{c_int, uintptr_t};
-use dwarf::eh::{self, EHContext, EHAction};
+use crate::dwarf::eh::{self, EHContext, EHAction};
#[repr(C)]
struct Exception {
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/",
issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")]
+#![deny(rust_2018_idioms)]
+
#![feature(allocator_api)]
#![feature(alloc)]
#![feature(core_intrinsics)]
#![panic_runtime]
#![feature(panic_runtime)]
-extern crate alloc;
-extern crate libc;
-#[cfg(not(any(target_env = "msvc", all(windows, target_arch = "x86_64", target_env = "gnu"))))]
-extern crate unwind;
-
use alloc::boxed::Box;
use core::intrinsics;
use core::mem;
vtable_ptr: *mut usize)
-> u32 {
let mut payload = imp::payload();
- if intrinsics::try(f, data, &mut payload as *mut _ as *mut _) == 0 {
+ if intrinsics::r#try(f, data, &mut payload as *mut _ as *mut _) == 0 {
0
} else {
let obj = mem::transmute::<_, raw::TraitObject>(imp::cleanup(payload));
use core::mem;
use core::raw;
-use windows as c;
+use crate::windows as c;
use libc::{c_int, c_uint};
// First up, a whole bunch of type definitions. There's a few platform-specific
#[lang = "eh_personality"]
#[cfg(not(test))]
fn rust_eh_personality() {
- unsafe { ::core::intrinsics::abort() }
+ unsafe { core::intrinsics::abort() }
}
use core::any::Any;
use core::intrinsics;
use core::ptr;
-use dwarf::eh::{EHContext, EHAction, find_eh_action};
-use windows as c;
+use crate::dwarf::eh::{EHContext, EHAction, find_eh_action};
+use crate::windows as c;
// Define our exception codes:
// according to http://msdn.microsoft.com/en-us/library/het71c37(v=VS.80).aspx,
//! 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)]
+// ignore-tidy-linelength
#![allow(non_snake_case)]
// Error messages for EXXXX errors.
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
"##,
#![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##"
```
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##"
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,
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)
}
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(),
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))),
),
}
}
- fn is_body_owner(self, node_id: NodeId) -> bool {
+ fn is_body_owner(self, hir_id: HirId) -> bool {
match self.associated_body() {
- Some(b) => b.node_id == node_id,
+ Some(b) => b.hir_id == hir_id,
None => false,
}
}
}
pub fn body(&self, id: BodyId) -> &'hir Body {
- self.read(id.node_id);
+ self.read_by_hir_id(id.hir_id);
// N.B., intentionally bypass `self.forest.krate()` so that we
// do not trigger a read of the whole krate here
/// Returns the `NodeId` that corresponds to the definition of
/// which this is the body of, i.e., a `fn`, `const` or `static`
/// item (possibly associated), a closure, or a `hir::AnonConst`.
- pub fn body_owner(&self, BodyId { node_id }: BodyId) -> NodeId {
+ pub fn body_owner(&self, BodyId { hir_id }: BodyId) -> NodeId {
+ let node_id = self.hir_to_node_id(hir_id);
let parent = self.get_parent_node(node_id);
- assert!(self.map[parent.as_usize()].map_or(false, |e| e.is_body_owner(node_id)));
+ assert!(self.map[parent.as_usize()].map_or(false, |e| e.is_body_owner(hir_id)));
parent
}
}
}
+ // FIXME(@ljedrz): replace the NodeId variant
+ pub fn maybe_body_owned_by_by_hir_id(&self, id: HirId) -> Option<BodyId> {
+ let node_id = self.hir_to_node_id(id);
+ self.maybe_body_owned_by(node_id)
+ }
+
/// Given a body owner's id, returns the `BodyId` associated with it.
pub fn body_owned_by(&self, id: NodeId) -> BodyId {
self.maybe_body_owned_by(id).unwrap_or_else(|| {
}
}
+ // FIXME(@ljedrz): replace the NodeId variant
+ pub fn body_owner_kind_by_hir_id(&self, id: HirId) -> BodyOwnerKind {
+ let node_id = self.hir_to_node_id(id);
+ self.body_owner_kind(node_id)
+ }
+
pub fn ty_param_owner(&self, id: NodeId) -> NodeId {
match self.get(id) {
Node::Item(&Item { node: ItemKind::Trait(..), .. }) => id,
self.local_def_id(self.get_module_parent_node(id))
}
+ // FIXME(@ljedrz): replace the NodeId variant
+ pub fn get_module_parent_by_hir_id(&self, id: HirId) -> DefId {
+ let node_id = self.hir_to_node_id(id);
+ self.get_module_parent(node_id)
+ }
+
/// Returns the `NodeId` of `id`'s nearest module parent, or `id` itself if no
/// module parent is in this map.
pub fn get_module_parent_node(&self, id: NodeId) -> NodeId {
/// the `local_id` part of the `HirId` changing, which is a very useful property in
/// incremental compilation where we have to persist things through changes to
/// the code base.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
pub struct HirId {
pub owner: DefIndex,
pub local_id: ItemLocalId,
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct BodyId {
- pub node_id: NodeId,
+ pub hir_id: HirId,
}
/// The body of a function, closure, or constant value. In the case of
impl Body {
pub fn id(&self) -> BodyId {
BodyId {
- node_id: self.value.id
+ hir_id: self.value.hir_id,
}
}
}
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 {
/// 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`).
///
/// 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.
///
ItemKind::Union(..) => "union",
ItemKind::Trait(..) => "trait",
ItemKind::TraitAlias(..) => "trait alias",
- ItemKind::Impl(..) => "item",
+ ItemKind::Impl(..) => "impl",
}
}
fn to_stable_hash_key(&self,
hcx: &StableHashingContext<'a>)
-> (DefPathHash, hir::ItemLocalId) {
- let hir::BodyId { node_id } = *self;
- node_id.to_stable_hash_key(hcx)
+ let hir::BodyId { hir_id } = *self;
+ hir_id.to_stable_hash_key(hcx)
}
}
}
}
}
- 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,
+ ));
}
}
},
};
if let Some(body_id) = body_id {
- let expr = self.tcx.hir().expect_expr(body_id.node_id);
+ let expr = self.tcx.hir().expect_expr_by_hir_id(body_id.hir_id);
local_visitor.visit_expr(expr);
}
pub use self::ValuePairs::*;
pub use crate::ty::IntVarValue;
+use crate::hir;
use crate::hir::def_id::DefId;
use crate::infer::canonical::{Canonical, CanonicalVarValues};
use crate::middle::free_region::RegionRelations;
// for each body-id in this map, which will process the
// obligations within. This is expected to be done 'late enough'
// that all type inference variables have been bound and so forth.
- pub region_obligations: RefCell<Vec<(ast::NodeId, RegionObligation<'tcx>)>>,
+ pub region_obligations: RefCell<Vec<(hir::HirId, RegionObligation<'tcx>)>>,
/// What is the innermost universe we have created? Starts out as
/// `UniverseIndex::root()` but grows from there as we enter
pub fn partially_normalize_associated_types_in<T>(
&self,
span: Span,
- body_id: ast::NodeId,
+ body_id: hir::HirId,
param_env: ty::ParamEnv<'tcx>,
value: &T,
) -> InferOk<'tcx, T>
pub fn instantiate_opaque_types<T: TypeFoldable<'tcx>>(
&self,
parent_def_id: DefId,
- body_id: ast::NodeId,
+ body_id: hir::HirId,
param_env: ty::ParamEnv<'tcx>,
value: &T,
) -> InferOk<'tcx, (T, OpaqueTypeMap<'tcx>)> {
struct Instantiator<'a, 'gcx: 'tcx, 'tcx: 'a> {
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
parent_def_id: DefId,
- body_id: ast::NodeId,
+ body_id: hir::HirId,
param_env: ty::ParamEnv<'tcx>,
opaque_types: OpaqueTypeMap<'tcx>,
obligations: Vec<PredicateObligation<'tcx>>,
use crate::infer::outlives::free_region_map::FreeRegionMap;
use crate::infer::{GenericKind, InferCtxt};
+use crate::hir;
use rustc_data_structures::fx::FxHashMap;
-use syntax::ast;
use syntax_pos::Span;
use crate::traits::query::outlives_bounds::{self, OutlivesBound};
use crate::ty::{self, Ty};
// results when proving outlives obligations like `T: 'x` later
// (e.g., if `T: 'x` must be proven within the body B1, then we
// know it is true if either `'a: 'x` or `'b: 'x`).
- region_bound_pairs_map: FxHashMap<ast::NodeId, RegionBoundPairs<'tcx>>,
+ region_bound_pairs_map: FxHashMap<hir::HirId, RegionBoundPairs<'tcx>>,
// Used to compute `region_bound_pairs_map`: contains the set of
// in-scope region-bound pairs thus far.
}
/// Borrows current value of the `region_bound_pairs`.
- pub fn region_bound_pairs_map(&self) -> &FxHashMap<ast::NodeId, RegionBoundPairs<'tcx>> {
+ pub fn region_bound_pairs_map(&self) -> &FxHashMap<hir::HirId, RegionBoundPairs<'tcx>> {
&self.region_bound_pairs_map
}
&mut self,
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
fn_sig_tys: &[Ty<'tcx>],
- body_id: ast::NodeId,
+ body_id: hir::HirId,
span: Span,
) {
debug!("add_implied_bounds()");
}
/// Save the current set of region-bound pairs under the given `body_id`.
- pub fn save_implied_bounds(&mut self, body_id: ast::NodeId) {
+ pub fn save_implied_bounds(&mut self, body_id: hir::HirId) {
let old = self.region_bound_pairs_map.insert(
body_id,
self.region_bound_pairs_accum.clone(),
use crate::infer::outlives::verify::VerifyBoundCx;
use crate::infer::{self, GenericKind, InferCtxt, RegionObligation, SubregionOrigin, VerifyBound};
use rustc_data_structures::fx::FxHashMap;
-use syntax::ast;
+use crate::hir;
use crate::traits::ObligationCause;
use crate::ty::outlives::Component;
use crate::ty::{self, Region, Ty, TyCtxt, TypeFoldable};
/// information).
pub fn register_region_obligation(
&self,
- body_id: ast::NodeId,
+ body_id: hir::HirId,
obligation: RegionObligation<'tcx>,
) {
debug!(
}
/// Trait queries just want to pass back type obligations "as is"
- pub fn take_registered_region_obligations(&self) -> Vec<(ast::NodeId, RegionObligation<'tcx>)> {
+ pub fn take_registered_region_obligations(&self) -> Vec<(hir::HirId, RegionObligation<'tcx>)> {
::std::mem::replace(&mut *self.region_obligations.borrow_mut(), vec![])
}
/// processed.
pub fn process_registered_region_obligations(
&self,
- region_bound_pairs_map: &FxHashMap<ast::NodeId, RegionBoundPairs<'tcx>>,
+ region_bound_pairs_map: &FxHashMap<hir::HirId, RegionBoundPairs<'tcx>>,
implicit_region_bound: Option<ty::Region<'tcx>>,
param_env: ty::ParamEnv<'tcx>,
) {
}
BuiltinLintDiagnostics::UnusedImports(message, replaces) => {
if !replaces.is_empty() {
- db.multipart_suggestion(
+ db.tool_only_multipart_suggestion(
&message,
replaces,
Applicability::MachineApplicable,
}
impl<'a, 'tcx: 'a> MissingStabilityAnnotations<'a, 'tcx> {
- fn check_missing_stability(&self, id: NodeId, span: Span) {
+ fn check_missing_stability(&self, id: NodeId, span: Span, name: &str) {
let hir_id = self.tcx.hir().node_to_hir_id(id);
let stab = self.tcx.stability().local_stability(hir_id);
let is_error = !self.tcx.sess.opts.test &&
stab.is_none() &&
self.access_levels.is_reachable(id);
if is_error {
- self.tcx.sess.span_err(span, "This node does not have a stability attribute");
+ self.tcx.sess.span_err(
+ span,
+ &format!("{} has missing stability attribute", name),
+ );
}
}
}
// optional. They inherit stability from their parents when unannotated.
hir::ItemKind::Impl(.., None, _, _) | hir::ItemKind::ForeignMod(..) => {}
- _ => self.check_missing_stability(i.id, i.span)
+ _ => self.check_missing_stability(i.id, i.span, i.node.descriptive_variant())
}
intravisit::walk_item(self, i)
}
fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) {
- self.check_missing_stability(ti.id, ti.span);
+ self.check_missing_stability(ti.id, ti.span, "item");
intravisit::walk_trait_item(self, ti);
}
fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem) {
let impl_def_id = self.tcx.hir().local_def_id(self.tcx.hir().get_parent(ii.id));
if self.tcx.impl_trait_ref(impl_def_id).is_none() {
- self.check_missing_stability(ii.id, ii.span);
+ self.check_missing_stability(ii.id, ii.span, "item");
}
intravisit::walk_impl_item(self, ii);
}
fn visit_variant(&mut self, var: &'tcx Variant, g: &'tcx Generics, item_id: NodeId) {
- self.check_missing_stability(var.node.data.id(), var.span);
+ self.check_missing_stability(var.node.data.id(), var.span, "variant");
intravisit::walk_variant(self, var, g, item_id);
}
fn visit_struct_field(&mut self, s: &'tcx StructField) {
- self.check_missing_stability(s.id, s.span);
+ self.check_missing_stability(s.id, s.span, "field");
intravisit::walk_struct_field(self, s);
}
fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem) {
- self.check_missing_stability(i.id, i.span);
+ self.check_missing_stability(i.id, i.span, i.node.descriptive_variant());
intravisit::walk_foreign_item(self, i);
}
fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef) {
- self.check_missing_stability(md.id, md.span);
+ self.check_missing_stability(md.id, md.span, "macro");
}
}
// Deprecated attributes apply in-crate and cross-crate.
if let Some(id) = id {
if let Some(depr_entry) = self.lookup_deprecation_entry(def_id) {
- // If the deprecation is scheduled for a future Rust
- // version, then we should display no warning message.
- let deprecated_in_future_version = if let Some(sym) = depr_entry.attr.since {
- let since = sym.as_str();
- if !deprecation_in_effect(&since) {
- Some(since)
- } else {
- None
- }
- } else {
- None
- };
-
let parent_def_id = self.hir().local_def_id(self.hir().get_parent(id));
let skip = self.lookup_deprecation_entry(parent_def_id)
.map_or(false, |parent_depr| parent_depr.same_origin(&depr_entry));
- if let Some(since) = deprecated_in_future_version {
- let path = self.item_path_str(def_id);
- let message = format!("use of item '{}' \
- that will be deprecated in future version {}",
- path,
- since);
-
- lint_deprecated(def_id,
- id,
- depr_entry.attr.note,
- None,
- &message,
- lint::builtin::DEPRECATED_IN_FUTURE);
- } else if !skip {
+ if !skip {
let path = self.item_path_str(def_id);
let message = format!("use of deprecated item '{}'", path);
lint_deprecated(def_id,
tcx,
access_levels,
};
- missing.check_missing_stability(ast::CRATE_NODE_ID, krate.span);
+ missing.check_missing_stability(ast::CRATE_NODE_ID, krate.span, "crate");
intravisit::walk_crate(&mut missing, krate);
krate.visit_all_item_likes(&mut missing.as_deep_visitor());
}
full_env,
ty,
trait_did,
- ObligationCause::misc(DUMMY_SP, ast::DUMMY_NODE_ID),
+ ObligationCause::misc(DUMMY_SP, hir::DUMMY_HIR_ID),
);
fulfill.select_all_or_error(&infcx).unwrap_or_else(|e| {
panic!(
user_env.caller_bounds.iter().cloned().collect();
let mut new_env = param_env.clone();
- let dummy_cause = ObligationCause::misc(DUMMY_SP, ast::DUMMY_NODE_ID);
+ let dummy_cause = ObligationCause::misc(DUMMY_SP, hir::DUMMY_HIR_ID);
while let Some(pred) = predicates.pop_front() {
infcx.clear_caches();
select: &mut SelectionContext<'c, 'd, 'cx>,
only_projections: bool,
) -> bool {
- let dummy_cause = ObligationCause::misc(DUMMY_SP, ast::DUMMY_NODE_ID);
+ let dummy_cause = ObligationCause::misc(DUMMY_SP, hir::DUMMY_HIR_ID);
for (obligation, mut predicate) in nested
.map(|o| (o.clone(), o.predicate.clone()))
/// (in particular, closures can add new assumptions). See the
/// field `region_obligations` of the `FulfillmentContext` for more
/// information.
- pub body_id: ast::NodeId,
+ pub body_id: hir::HirId,
pub code: ObligationCauseCode<'tcx>
}
ObligationCauseCode::StartFunctionType => {
tcx.sess.source_map().def_span(self.span)
}
+ ObligationCauseCode::MatchExpressionArm { arm_span, .. } => arm_span,
_ => self.span,
}
}
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
};
let obligation = Obligation {
param_env,
- cause: ObligationCause::misc(span, ast::DUMMY_NODE_ID),
+ cause: ObligationCause::misc(span, hir::DUMMY_HIR_ID),
recursion_depth: 0,
predicate: trait_ref.to_predicate(),
};
// We can use a dummy node-id here because we won't pay any mind
// to region obligations that arise (there shouldn't really be any
// anyhow).
- let cause = ObligationCause::misc(span, ast::DUMMY_NODE_ID);
+ let cause = ObligationCause::misc(span, hir::DUMMY_HIR_ID);
fulfill_cx.register_bound(infcx, param_env, ty, def_id, cause);
}
pub fn misc(span: Span,
- body_id: ast::NodeId,
+ body_id: hir::HirId,
param_env: ty::ParamEnv<'tcx>,
trait_ref: O)
-> Obligation<'tcx, O> {
impl<'tcx> ObligationCause<'tcx> {
#[inline]
pub fn new(span: Span,
- body_id: ast::NodeId,
+ body_id: hir::HirId,
code: ObligationCauseCode<'tcx>)
-> ObligationCause<'tcx> {
- ObligationCause { span: span, body_id: body_id, code: code }
+ ObligationCause { span, body_id, code }
}
- pub fn misc(span: Span, body_id: ast::NodeId) -> ObligationCause<'tcx> {
- ObligationCause { span: span, body_id: body_id, code: MiscObligation }
+ pub fn misc(span: Span, body_id: hir::HirId) -> ObligationCause<'tcx> {
+ ObligationCause { span, body_id, code: MiscObligation }
}
pub fn dummy() -> ObligationCause<'tcx> {
- ObligationCause { span: DUMMY_SP, body_id: ast::CRATE_NODE_ID, code: MiscObligation }
+ ObligationCause { span: DUMMY_SP, body_id: hir::CRATE_HIR_ID, code: MiscObligation }
}
}
use crate::infer::InferCtxt;
use crate::infer::canonical::OriginalQueryValues;
-use syntax::ast;
+use crate::hir;
use syntax::source_map::Span;
use crate::traits::{FulfillmentContext, ObligationCause, TraitEngine, TraitEngineExt};
use crate::traits::query::NoSolution;
pub fn implied_outlives_bounds(
&self,
param_env: ty::ParamEnv<'tcx>,
- body_id: ast::NodeId,
+ body_id: hir::HirId,
ty: Ty<'tcx>,
span: Span,
) -> Vec<OutlivesBound<'tcx>> {
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 })
}
use rustc_data_structures::sync::{self, Lrc, ParallelIterator, par_iter};
use std::slice;
use std::{mem, ptr};
-use syntax::ast::{self, DUMMY_NODE_ID, Name, Ident, NodeId};
+use syntax::ast::{self, Name, Ident, NodeId};
use syntax::attr;
use syntax::ext::hygiene::Mark;
use syntax::symbol::{keywords, Symbol, LocalInternedString, InternedString};
pub fn find_field_index(self, ident: Ident, variant: &VariantDef) -> Option<usize> {
variant.fields.iter().position(|field| {
- self.adjust_ident(ident, variant.did, DUMMY_NODE_ID).0 == field.ident.modern()
+ self.adjust_ident(ident, variant.did, hir::DUMMY_HIR_ID).0 == field.ident.modern()
})
}
/// its supposed definition name (`def_name`). The method also needs `DefId` of the supposed
/// definition's parent/scope to perform comparison.
pub fn hygienic_eq(self, use_name: Ident, def_name: Ident, def_parent_def_id: DefId) -> bool {
- self.adjust_ident(use_name, def_parent_def_id, DUMMY_NODE_ID).0 == def_name.modern()
+ self.adjust_ident(use_name, def_parent_def_id, hir::DUMMY_HIR_ID).0 == def_name.modern()
}
- pub fn adjust_ident(self, mut ident: Ident, scope: DefId, block: NodeId) -> (Ident, DefId) {
+ pub fn adjust_ident(self, mut ident: Ident, scope: DefId, block: hir::HirId) -> (Ident, DefId) {
ident = ident.modern();
let target_expansion = match scope.krate {
LOCAL_CRATE => self.hir().definitions().expansion_that_defined(scope.index),
let scope = match ident.span.adjust(target_expansion) {
Some(actual_expansion) =>
self.hir().definitions().parent_module_of_macro_def(actual_expansion),
- None if block == DUMMY_NODE_ID => DefId::local(CRATE_DEF_INDEX), // Dummy DefId
- None => self.hir().get_module_parent(block),
+ None if block == hir::DUMMY_HIR_ID => DefId::local(CRATE_DEF_INDEX), // Dummy DefId
+ None => self.hir().get_module_parent_by_hir_id(block),
};
(ident, scope)
}
if tcx.sess.opts.debugging_opts.chalk { Some(def_id) } else { None }
);
- let body_id = tcx.hir().as_local_node_id(def_id).map_or(DUMMY_NODE_ID, |id| {
- tcx.hir().maybe_body_owned_by(id).map_or(id, |body| body.node_id)
+ let body_id = tcx.hir().as_local_hir_id(def_id).map_or(hir::DUMMY_HIR_ID, |id| {
+ tcx.hir().maybe_body_owned_by_by_hir_id(id).map_or(id, |body| body.hir_id)
});
let cause = traits::ObligationCause::misc(tcx.def_span(def_id), body_id);
traits::normalize_param_env_or_error(tcx, def_id, unnormalized_env, cause)
job.signal_complete();
}
-
- /// Executes a job by changing the ImplicitCtxt to point to the
- /// new query job while it executes. It returns the diagnostics
- /// captured during execution and the actual result.
- #[inline(always)]
- pub(super) fn start<'lcx, F, R>(
- &self,
- tcx: TyCtxt<'_, 'tcx, 'lcx>,
- diagnostics: Option<&Lock<ThinVec<Diagnostic>>>,
- compute: F)
- -> R
- where
- F: for<'b> FnOnce(TyCtxt<'b, 'tcx, 'lcx>) -> R
- {
- // The TyCtxt stored in TLS has the same global interner lifetime
- // as `tcx`, so we use `with_related_context` to relate the 'gcx lifetimes
- // when accessing the ImplicitCtxt
- tls::with_related_context(tcx, move |current_icx| {
- // Update the ImplicitCtxt to point to our new query job
- let new_icx = tls::ImplicitCtxt {
- tcx: tcx.global_tcx(),
- query: Some(self.job.clone()),
- diagnostics,
- layout_depth: current_icx.layout_depth,
- task_deps: current_icx.task_deps,
- };
-
- // Use the ImplicitCtxt while we execute the query
- tls::enter_context(&new_icx, |_| {
- compute(tcx)
- })
- })
- }
-
}
#[inline(always)]
}
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
+ /// Executes a job by changing the ImplicitCtxt to point to the
+ /// new query job while it executes. It returns the diagnostics
+ /// captured during execution and the actual result.
+ #[inline(always)]
+ pub(super) fn start_query<F, R>(
+ self,
+ job: Lrc<QueryJob<'gcx>>,
+ diagnostics: Option<&Lock<ThinVec<Diagnostic>>>,
+ compute: F)
+ -> R
+ where
+ F: for<'b, 'lcx> FnOnce(TyCtxt<'b, 'gcx, 'lcx>) -> R
+ {
+ // The TyCtxt stored in TLS has the same global interner lifetime
+ // as `self`, so we use `with_related_context` to relate the 'gcx lifetimes
+ // when accessing the ImplicitCtxt
+ tls::with_related_context(self, move |current_icx| {
+ // Update the ImplicitCtxt to point to our new query job
+ let new_icx = tls::ImplicitCtxt {
+ tcx: self.global_tcx(),
+ query: Some(job),
+ diagnostics,
+ layout_depth: current_icx.layout_depth,
+ task_deps: current_icx.task_deps,
+ };
+
+ // Use the ImplicitCtxt while we execute the query
+ tls::enter_context(&new_icx, |_| {
+ compute(self.global_tcx())
+ })
+ })
+ }
+
#[inline(never)]
#[cold]
pub(super) fn report_cycle(
self.sess.profiler(|p| p.start_query(Q::NAME, Q::CATEGORY));
let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| {
- job.start(self, diagnostics, |tcx| {
+ self.start_query(job.job.clone(), diagnostics, |tcx| {
tcx.dep_graph.with_anon_task(dep_node.kind, || {
Q::compute(tcx.global_tcx(), key)
})
}
if !dep_node.kind.is_input() {
- if let Some((prev_dep_node_index,
- dep_node_index)) = self.dep_graph.try_mark_green_and_read(self,
- &dep_node) {
- return Ok(self.load_from_disk_and_cache_in_memory::<Q>(
- key,
- job,
- prev_dep_node_index,
- dep_node_index,
- &dep_node
- ))
+ // The diagnostics for this query will be
+ // promoted to the current session during
+ // try_mark_green(), so we can ignore them here.
+ let loaded = self.start_query(job.job.clone(), None, |tcx| {
+ let marked = tcx.dep_graph.try_mark_green_and_read(tcx, &dep_node);
+ marked.map(|(prev_dep_node_index, dep_node_index)| {
+ (tcx.load_from_disk_and_cache_in_memory::<Q>(
+ key.clone(),
+ prev_dep_node_index,
+ dep_node_index,
+ &dep_node
+ ), dep_node_index)
+ })
+ });
+ if let Some((result, dep_node_index)) = loaded {
+ job.complete(&result, dep_node_index);
+ return Ok(result);
}
}
fn load_from_disk_and_cache_in_memory<Q: QueryDescription<'gcx>>(
self,
key: Q::Key,
- job: JobOwner<'a, 'gcx, Q>,
prev_dep_node_index: SerializedDepNodeIndex,
dep_node_index: DepNodeIndex,
dep_node: &DepNode
self.sess.profiler(|p| p.start_query(Q::NAME, Q::CATEGORY));
- // The diagnostics for this query have already been
- // promoted to the current session during
- // try_mark_green(), so we can ignore them here.
- let result = job.start(self, None, |tcx| {
- // The dep-graph for this computation is already in
- // place
- tcx.dep_graph.with_ignore(|| {
- Q::compute(tcx, key)
- })
+ // The dep-graph for this computation is already in
+ // place
+ let result = self.dep_graph.with_ignore(|| {
+ Q::compute(self, key)
});
self.sess.profiler(|p| p.end_query(Q::NAME, Q::CATEGORY));
self.dep_graph.mark_loaded_from_cache(dep_node_index, true);
}
- job.complete(&result, dep_node_index);
-
result
}
self.sess.profiler(|p| p.start_query(Q::NAME, Q::CATEGORY));
let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| {
- job.start(self, diagnostics, |tcx| {
+ self.start_query(job.job.clone(), diagnostics, |tcx| {
if dep_node.kind.is_eval_always() {
tcx.dep_graph.with_eval_always_task(dep_node,
tcx,
+use crate::hir;
use crate::hir::def_id::DefId;
use crate::infer::InferCtxt;
use crate::ty::subst::Substs;
use crate::traits;
use crate::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
use std::iter::once;
-use syntax::ast;
use syntax_pos::Span;
use crate::middle::lang_items;
/// say "$0 is WF if $0 is WF".
pub fn obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
- body_id: ast::NodeId,
+ body_id: hir::HirId,
ty: Ty<'tcx>,
span: Span)
-> Option<Vec<traits::PredicateObligation<'tcx>>>
/// if `Bar: Eq`.
pub fn trait_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
- body_id: ast::NodeId,
+ body_id: hir::HirId,
trait_ref: &ty::TraitRef<'tcx>,
span: Span)
-> Vec<traits::PredicateObligation<'tcx>>
pub fn predicate_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
- body_id: ast::NodeId,
+ body_id: hir::HirId,
predicate: &ty::Predicate<'tcx>,
span: Span)
-> Vec<traits::PredicateObligation<'tcx>>
struct WfPredicates<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
- body_id: ast::NodeId,
+ body_id: hir::HirId,
span: Span,
out: Vec<traits::PredicateObligation<'tcx>>,
}
match tcx.hir().get(closure_id) {
Node::Expr(expr) => match expr.node {
hir::ExprKind::Closure(.., body_id, _, _) => {
- body_id.node_id
+ tcx.hir().hir_to_node_id(body_id.hir_id)
}
_ => {
bug!("encountered non-closure id: {}", closure_id)
(control.after_analysis.callback)(&mut state);
});
+ // Plugins like clippy and rust-semverver stop the analysis early,
+ // but want to still return an error if errors during the analysis
+ // happened:
+ tcx.sess.compile_status()?;
+
if control.after_analysis.stop == Compilation::Stop {
return result.and_then(|_| Err(CompileIncomplete::Stopped));
}
use crate::CodeSuggestion;
+use crate::SuggestionStyle;
use crate::SubstitutionPart;
use crate::Substitution;
use crate::Applicability;
.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
}],
}],
msg: msg.to_owned(),
- show_code_when_inline: true,
+ style: SuggestionStyle::ShowCode,
applicability,
});
self
}],
}).collect(),
msg: msg.to_owned(),
- show_code_when_inline: true,
+ style: SuggestionStyle::ShowCode,
applicability,
});
self
}],
}],
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
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,
);
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);
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;
// 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)
}
}
- 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
}
- 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();
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);
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),
+ _ => ()
+ }
}
}
}
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
/// ```
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,
```
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##"
}
```
-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##"
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##"
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:
```
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##"
```
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##"
```
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##"
```
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##"
}
let def_id = src.def_id();
- let id = tcx.hir().as_local_node_id(def_id).unwrap();
+ let id = tcx.hir().as_local_hir_id(def_id).unwrap();
let mut const_promoted_temps = None;
- let mode = match tcx.hir().body_owner_kind(id) {
+ let mode = match tcx.hir().body_owner_kind_by_hir_id(id) {
hir::BodyOwnerKind::Closure => Mode::Fn,
hir::BodyOwnerKind::Fn => {
if tcx.is_const_fn(def_id) {
.chars()
.filter_map(|c| match c {
' ' => None,
- ':' => Some('_'),
+ ':' | '<' | '>' => Some('_'),
c => Some(c)
}));
s
match (descr, src.promoted) {
(_, Some(i)) => write!(w, "{:?} in ", i)?,
(Some(Def::StructCtor(..)), _) => write!(w, "struct ")?,
- (Some(Def::Const(_)), _) => write!(w, "const ")?,
+ (Some(Def::Const(_)), _)
+ | (Some(Def::AssociatedConst(_)), _) => write!(w, "const ")?,
(Some(Def::Static(_, /*is_mutbl*/false)), _) => write!(w, "static ")?,
(Some(Def::Static(_, /*is_mutbl*/true)), _) => write!(w, "static mut ")?,
(_, _) if is_function => write!(w, "fn ")?,
let node_id = tcx.hir().as_local_node_id(def_id)
.expect("rvalue_promotable_map invoked with non-local def-id");
let body_id = tcx.hir().body_owned_by(node_id);
- let body_hir_id = tcx.hir().node_to_hir_id(body_id.node_id);
- tcx.rvalue_promotable_map(def_id).contains(&body_hir_id.local_id)
+ tcx.rvalue_promotable_map(def_id).contains(&body_id.hir_id.local_id)
}
fn rvalue_promotable_map<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def: &'tcx ty::AdtDef, // definition of the struct or enum
field: &'tcx ty::FieldDef) { // definition of the field
let ident = Ident::new(keywords::Invalid.name(), use_ctxt);
- let def_id = self.tcx.adjust_ident(ident, def.did, self.current_item).1;
+ let current_hir = self.tcx.hir().node_to_hir_id(self.current_item);
+ let def_id = self.tcx.adjust_ident(ident, def.did, current_hir).1;
if !def.is_enum() && !field.vis.is_accessible_from(def_id, self.tcx) {
struct_span_err!(self.tcx.sess, span, E0451, "field `{}` of {} `{}` is private",
field.ident, def.variant_descr(), self.tcx.item_path_str(def.did))
// Try to lookup name in more relaxed fashion for better error reporting.
let ident = path.last().unwrap().ident;
- let candidates = self.lookup_import_candidates(ident, ns, is_expected);
+ let candidates = self.lookup_import_candidates(ident, ns, is_expected)
+ .drain(..)
+ .filter(|ImportSuggestion { did, .. }| {
+ match (did, def.and_then(|def| def.opt_def_id())) {
+ (Some(suggestion_did), Some(actual_did)) => *suggestion_did != actual_did,
+ _ => true,
+ }
+ })
+ .collect::<Vec<_>>();
if candidates.is_empty() && is_expected(Def::Enum(DefId::local(CRATE_DEF_INDEX))) {
let enum_candidates =
self.lookup_import_candidates(ident, ns, is_enum_variant);
use rustc::hir::def::Namespace::*;
use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, DefId};
use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap};
-use rustc::ty;
+use rustc::ty::{self, DefIdTree};
use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet, DefIdMap};
use rustc::{bug, span_bug};
/// A free importable items suggested in case of resolution failure.
struct ImportSuggestion {
+ did: Option<DefId>,
path: Path,
}
// collect results based on the filter function
if ident.name == lookup_ident.name && ns == namespace {
- if filter_fn(name_binding.def()) {
+ let def = name_binding.def();
+ if filter_fn(def) {
// create the path
let mut segms = path_segments.clone();
if lookup_ident.span.rust_2018() {
// declared as public (due to pruning, we don't explore
// outside crate private modules => no need to check this)
if !in_module_is_extern || name_binding.vis == ty::Visibility::Public {
- candidates.push(ImportSuggestion { path });
+ let did = match def {
+ Def::StructCtor(did, _) | Def::VariantCtor(did, _) =>
+ self.parent(did),
+ _ => def.opt_def_id(),
+ };
+ candidates.push(ImportSuggestion { did, path });
}
}
}
span: name_binding.span,
segments: path_segments,
};
- result = Some((module, ImportSuggestion { path }));
+ let did = module.def().and_then(|def| def.opt_def_id());
+ result = Some((module, ImportSuggestion { did, path }));
} else {
// add the module to the lookup
if seen_modules.insert(module.def_id().unwrap()) {
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),
..
// UEFI uses COFF/PE32+ format for binaries. All binaries must be statically linked. No dynamic
// linker is supported. As native to COFF, binaries are position-dependent, but will be relocated
// by the loader if the pre-chosen memory location is already in use.
-// UEFI forbids running code on anything but the boot-CPU. Not interrupts are allowed other than
+// UEFI forbids running code on anything but the boot-CPU. No interrupts are allowed other than
// the timer-interrupt. Device-drivers are required to use polling-based models. Furthermore, all
// code runs in the same environment, no process separation is supported.
"/NOLOGO".to_string(),
// UEFI is fully compatible to non-executable data pages. Tell the compiler that
- // non-code sections can be marked as non-executable, including stack pages.
+ // non-code sections can be marked as non-executable, including stack pages. In fact,
+ // firmware might enforce this, so we better let the linker know about this, so it
+ // will fail if the compiler ever tries placing code on the stack (e.g., trampoline
+ // constructs and alike).
"/NXCOMPAT".to_string(),
// There is no runtime for UEFI targets, prevent them from being linked. UEFI targets
base.cpu = "x86-64".to_string();
base.max_atomic_width = Some(64);
- // We disable MMX and SSE for now. UEFI does not prevent these from being used, but there have
- // been reports to GRUB that some firmware does not initialize the FP exception handlers
- // properly. Therefore, using FP coprocessors will end you up at random memory locations when
- // you throw FP exceptions.
- // To be safe, we disable them for now and force soft-float. This can be revisited when we
- // have more test coverage. Disabling FP served GRUB well so far, so it should be good for us
- // as well.
+ // We disable MMX and SSE for now, even though UEFI allows using them. Problem is, you have to
+ // enable these CPU features explicitly before their first use, otherwise their instructions
+ // will trigger an exception. Rust does not inject any code that enables AVX/MMX/SSE
+ // instruction sets, so this must be done by the firmware. However, existing firmware is known
+ // to leave these uninitialized, thus triggering exceptions if we make use of them. Which is
+ // why we avoid them and instead use soft-floats. This is also what GRUB and friends did so
+ // far.
+ // If you initialize FP units yourself, you can override these flags with custom linker
+ // arguments, thus giving you access to full MMX/SSE acceleration.
base.features = "-mmx,-sse,+soft-float".to_string();
// UEFI systems run without a host OS, hence we cannot assume any code locality. We must tell
// places no locality-restrictions, so it fits well here.
base.code_model = Some("large".to_string());
- // UEFI mostly mirrors the calling-conventions used on windows. In case of x86-64 this means
- // small structs will be returned as int. This shouldn't matter much, since the restrictions
- // placed by the UEFI specifications forbid any ABI to return structures.
+ // UEFI mirrors the calling-conventions used on windows. In case of x86-64 this means small
+ // structs will be returned as int. This shouldn't matter much, since the restrictions placed
+ // by the UEFI specifications forbid any ABI to return structures.
base.abi_return_struct_as_int = true;
Ok(Target {
//! Provider for the `implied_outlives_bounds` query.
//! Do not call this query directory. See [`rustc::traits::query::implied_outlives_bounds`].
+use rustc::hir;
use rustc::infer::InferCtxt;
use rustc::infer::canonical::{self, Canonical};
use rustc::traits::{TraitEngine, TraitEngineExt};
use rustc::ty::query::Providers;
use rustc::ty::wf;
use smallvec::{SmallVec, smallvec};
-use syntax::ast::DUMMY_NODE_ID;
use syntax::source_map::DUMMY_SP;
use rustc::traits::FulfillmentContext;
// unresolved inference variables here anyway, but there might be
// during typeck under some circumstances.)
let obligations =
- wf::obligations(infcx, param_env, DUMMY_NODE_ID, ty, DUMMY_SP).unwrap_or(vec![]);
+ wf::obligations(infcx, param_env, hir::DUMMY_HIR_ID, ty, DUMMY_SP).unwrap_or(vec![]);
// N.B., all of these predicates *ought* to be easily proven
// true. In fact, their correctness is (mostly) implied by
+use rustc::hir;
use rustc::infer::canonical::{Canonical, QueryResponse};
use rustc::traits::query::{normalize::NormalizationResult, CanonicalProjectionGoal, NoSolution};
use rustc::traits::{self, ObligationCause, SelectionContext, TraitEngineExt};
use rustc::ty::{ParamEnvAnd, TyCtxt};
use rustc_data_structures::sync::Lrc;
use std::sync::atomic::Ordering;
-use syntax::ast::DUMMY_NODE_ID;
use syntax_pos::DUMMY_SP;
crate fn provide(p: &mut Providers<'_>) {
value: goal,
}| {
let selcx = &mut SelectionContext::new(infcx);
- let cause = ObligationCause::misc(DUMMY_SP, DUMMY_NODE_ID);
+ let cause = ObligationCause::misc(DUMMY_SP, hir::DUMMY_HIR_ID);
let mut obligations = vec![];
let answer = traits::normalize_projection_type(
selcx,
use rustc::infer::at::ToTrace;
use rustc::infer::canonical::{Canonical, QueryResponse};
use rustc::infer::InferCtxt;
+use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::traits::query::type_op::ascribe_user_type::AscribeUserType;
use rustc::traits::query::type_op::eq::Eq;
};
use rustc_data_structures::sync::Lrc;
use std::fmt;
-use syntax::ast;
use syntax_pos::DUMMY_SP;
crate fn provide(p: &mut Providers<'_>) {
self.infcx
.partially_normalize_associated_types_in(
DUMMY_SP,
- ast::CRATE_NODE_ID,
+ hir::CRATE_HIR_ID,
self.param_env,
&value,
)
binding.item_name, binding.span)
}?;
+ let hir_ref_id = self.tcx().hir().node_to_hir_id(ref_id);
let (assoc_ident, def_scope) =
- tcx.adjust_ident(binding.item_name, candidate.def_id(), ref_id);
+ tcx.adjust_ident(binding.item_name, candidate.def_id(), hir_ref_id);
let assoc_ty = tcx.associated_items(candidate.def_id()).find(|i| {
i.kind == ty::AssociatedKind::Type && i.ident.modern() == assoc_ident
}).expect("missing associated type");
};
let trait_did = bound.def_id();
- let (assoc_ident, def_scope) = tcx.adjust_ident(assoc_ident, trait_did, ref_id);
+ let hir_ref_id = self.tcx().hir().node_to_hir_id(ref_id);
+ let (assoc_ident, def_scope) = tcx.adjust_ident(assoc_ident, trait_did, hir_ref_id);
let item = tcx.associated_items(trait_did).find(|i| {
Namespace::from(i.kind) == Namespace::Type &&
i.ident.modern() == assoc_ident
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);
_ => 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.
use super::{FnCtxt, PlaceOp, Needs};
use super::method::MethodCallee;
+use rustc::hir;
use rustc::infer::{InferCtxt, InferOk};
use rustc::session::DiagnosticMessageId;
use rustc::traits::{self, TraitEngine};
use rustc::ty::adjustment::{Adjustment, Adjust, OverloadedDeref};
use syntax_pos::Span;
-use syntax::ast::{self, Ident};
+use syntax::ast::Ident;
use std::iter;
pub struct Autoderef<'a, 'gcx: 'tcx, 'tcx: 'a> {
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
- body_id: ast::NodeId,
+ body_id: hir::HirId,
param_env: ty::ParamEnv<'tcx>,
steps: Vec<(Ty<'tcx>, AutoderefKind)>,
cur_ty: Ty<'tcx>,
impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
- body_id: ast::NodeId,
+ body_id: hir::HirId,
span: Span,
base_ty: Ty<'tcx>)
-> Autoderef<'a, 'gcx, 'tcx>
.liberate_late_bound_regions(expr_def_id, &bound_sig);
let liberated_sig = self.inh.normalize_associated_types_in(
body.value.span,
- body.value.id,
+ body.value.hir_id,
self.param_env,
&liberated_sig,
);
// `ObligationCause` (and the `FnCtxt`). This is what
// `regionck_item` expects.
let impl_m_node_id = tcx.hir().as_local_node_id(impl_m.def_id).unwrap();
+ let impl_m_hir_id = tcx.hir().node_to_hir_id(impl_m_node_id);
let cause = ObligationCause {
span: impl_m_span,
- body_id: impl_m_node_id,
+ body_id: impl_m_hir_id,
code: ObligationCauseCode::CompareImplMethodObligation {
item_name: impl_m.ident.name,
impl_item_def_id: impl_m.def_id,
// Construct trait parameter environment and then shift it into the placeholder viewpoint.
// The key step here is to update the caller_bounds's predicates to be
// the new hybrid bounds we computed.
- let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_node_id);
+ let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_hir_id);
let param_env = ty::ParamEnv::new(
tcx.intern_predicates(&hybrid_preds.predicates),
Reveal::UserFacing,
);
let impl_sig =
inh.normalize_associated_types_in(impl_m_span,
- impl_m_node_id,
+ impl_m_hir_id,
param_env,
&impl_sig);
let impl_fty = tcx.mk_fn_ptr(ty::Binder::bind(impl_sig));
trait_sig.subst(tcx, trait_to_skol_substs);
let trait_sig =
inh.normalize_associated_types_in(impl_m_span,
- impl_m_node_id,
+ impl_m_hir_id,
param_env,
&trait_sig);
let trait_fty = tcx.mk_fn_ptr(ty::Binder::bind(trait_sig));
// Finally, resolve all regions. This catches wily misuses of
// lifetime parameters.
- let fcx = FnCtxt::new(&inh, param_env, impl_m_node_id);
- fcx.regionck_item(impl_m_node_id, impl_m_span, &[]);
+ let fcx = FnCtxt::new(&inh, param_env, impl_m_hir_id);
+ fcx.regionck_item(impl_m_hir_id, impl_m_span, &[]);
Ok(())
})
// Create a parameter environment that represents the implementation's
// method.
let impl_c_node_id = tcx.hir().as_local_node_id(impl_c.def_id).unwrap();
+ let impl_c_hir_id = tcx.hir().node_to_hir_id(impl_c_node_id);
// Compute placeholder form of impl and trait const tys.
let impl_ty = tcx.type_of(impl_c.def_id);
let trait_ty = tcx.type_of(trait_c.def_id).subst(tcx, trait_to_impl_substs);
- let mut cause = ObligationCause::misc(impl_c_span, impl_c_node_id);
+ let mut cause = ObligationCause::misc(impl_c_span, impl_c_hir_id);
// There is no "body" here, so just pass dummy id.
let impl_ty = inh.normalize_associated_types_in(impl_c_span,
- impl_c_node_id,
+ impl_c_hir_id,
param_env,
&impl_ty);
debug!("compare_const_impl: impl_ty={:?}", impl_ty);
let trait_ty = inh.normalize_associated_types_in(impl_c_span,
- impl_c_node_id,
+ impl_c_hir_id,
param_env,
&trait_ty);
return;
}
- let fcx = FnCtxt::new(&inh, param_env, impl_c_node_id);
- fcx.regionck_item(impl_c_node_id, impl_c_span, &[]);
+ let fcx = FnCtxt::new(&inh, param_env, impl_c_hir_id);
+ fcx.regionck_item(impl_c_hir_id, impl_c_span, &[]);
});
}
/// ```
/// 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);
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)));
+ },
+ _ => ()
}
}
}
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);
use crate::check::regionck::RegionCtxt;
+use crate::hir;
use crate::hir::def_id::DefId;
use rustc::infer::outlives::env::OutlivesEnvironment;
use rustc::infer::{self, InferOk, SuppressRegionErrors};
use rustc::ty::{self, Ty, TyCtxt};
use crate::util::common::ErrorReported;
-use syntax::ast;
use syntax_pos::Span;
/// This function confirms that the `Drop` implementation identified by
drop_impl_ty: Ty<'tcx>,
self_type_did: DefId,
) -> Result<(), ErrorReported> {
- let drop_impl_node_id = tcx.hir().as_local_node_id(drop_impl_did).unwrap();
+ let drop_impl_hir_id = tcx.hir().as_local_hir_id(drop_impl_did).unwrap();
// check that the impl type can be made to match the trait type.
let fresh_impl_substs = infcx.fresh_substs_for_item(drop_impl_span, drop_impl_did);
let fresh_impl_self_ty = drop_impl_ty.subst(tcx, fresh_impl_substs);
- let cause = &ObligationCause::misc(drop_impl_span, drop_impl_node_id);
+ let cause = &ObligationCause::misc(drop_impl_span, drop_impl_hir_id);
match infcx
.at(cause, impl_param_env)
.eq(named_type, fresh_impl_self_ty)
rcx: &mut RegionCtxt<'a, 'gcx, 'tcx>,
ty: Ty<'tcx>,
span: Span,
- body_id: ast::NodeId,
+ body_id: hir::HirId,
scope: region::Scope,
) -> Result<(), ErrorReported> {
debug!("check_safety_of_destructor_if_necessary typ: {:?} scope: {:?}",
safety,
abi
)));
- let cause = ObligationCause::new(it.span, it.id, ObligationCauseCode::IntrinsicType);
+ let cause = ObligationCause::new(it.span, it.hir_id, ObligationCauseCode::IntrinsicType);
require_same_types(tcx, &cause, tcx.mk_fn_ptr(tcx.fn_sig(def_id)), fty);
}
tcx.infer_ctxt().enter_with_canonical(DUMMY_SP, &goal, |ref infcx, goal, inference_vars| {
let ParamEnvAnd { param_env, value: self_ty } = goal;
- let mut autoderef = Autoderef::new(infcx, param_env, ast::DUMMY_NODE_ID, DUMMY_SP, self_ty)
+ let mut autoderef = Autoderef::new(infcx, param_env, hir::DUMMY_HIR_ID, DUMMY_SP, self_ty)
.include_raw_pointers()
.silence_errors();
let mut reached_raw_pointer = false;
stable_pick: &Pick,
unstable_candidates: &[(&Candidate<'tcx>, Symbol)],
) {
- let mut diag = self.tcx.struct_span_lint_node(
+ let mut diag = self.tcx.struct_span_lint_hir(
lint::builtin::UNSTABLE_NAME_COLLISIONS,
self.fcx.body_id,
self.span,
};
let field_ty = field.ty(tcx, substs);
- let scope = self.tcx.hir().get_module_parent(self.body_id);
+ let scope = self.tcx.hir().get_module_parent_by_hir_id(
+ self.body_id);
if field.vis.is_accessible_from(scope, self.tcx) {
if self.is_fn_ty(&field_ty, span) {
err.help(&format!("use `({0}.{1})(...)` if you \
err: &mut DiagnosticBuilder,
mut msg: String,
candidates: Vec<DefId>) {
- let module_did = self.tcx.hir().get_module_parent(self.body_id);
+ let module_did = self.tcx.hir().get_module_parent_by_hir_id(self.body_id);
let module_id = self.tcx.hir().as_local_node_id(module_did).unwrap();
let krate = self.tcx.hir().krate();
let (span, found_use) = UsePlacementFinder::check(self.tcx, krate, module_id);
traits: &mut Vec<DefId>,
external_mods: &mut FxHashSet<DefId>,
def: Def) {
- let def_id = def.def_id();
match def {
- Def::Trait(..) => {
+ Def::Trait(def_id) => {
traits.push(def_id);
}
- Def::Mod(..) => {
+ Def::Mod(def_id) => {
if !external_mods.insert(def_id) {
return;
}
}
pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
- body_id: ast::NodeId,
+ body_id: hir::HirId,
/// The parameter environment used for proving trait obligations
/// in this function. This can change when we descend into
fn normalize_associated_types_in<T>(&self,
span: Span,
- body_id: ast::NodeId,
+ body_id: hir::HirId,
param_env: ty::ParamEnv<'tcx>,
value: &T) -> T
where T : TypeFoldable<'tcx>
tcx.liberate_late_bound_regions(def_id, &fn_sig);
let fn_sig =
inh.normalize_associated_types_in(body.value.span,
- body_id.node_id,
+ body_id.hir_id,
param_env,
&fn_sig);
let fcx = check_fn(&inh, param_env, fn_sig, decl, id, body, None).0;
fcx
} else {
- let fcx = FnCtxt::new(&inh, param_env, body.value.id);
+ let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
let expected_type = tcx.type_of(def_id);
let expected_type = fcx.normalize_associated_types_in(body.value.span, &expected_type);
fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
// Create the function context. This is either derived from scratch or,
// in the case of closures, based on the outer context.
- let mut fcx = FnCtxt::new(inherited, param_env, body.value.id);
+ let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id);
*fcx.ps.borrow_mut() = UnsafetyState::function(fn_sig.unsafety, fn_id);
let declared_ret_ty = fn_sig.output();
let substs = fcx.tcx.mk_substs_trait(declared_ret_ty, &[]);
let trait_ref = ty::TraitRef::new(term_id, substs);
let return_ty_span = decl.output.span();
+ let fn_hir_id = fcx.tcx.hir().node_to_hir_id(fn_id);
let cause = traits::ObligationCause::new(
- return_ty_span, fn_id, ObligationCauseCode::MainFunctionType);
+ return_ty_span, fn_hir_id, ObligationCauseCode::MainFunctionType);
inherited.register_predicate(
traits::Obligation::new(
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
pub fn new(inh: &'a Inherited<'a, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
- body_id: ast::NodeId)
+ body_id: hir::HirId)
-> FnCtxt<'a, 'gcx, 'tcx> {
FnCtxt {
body_id,
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
pub fn regionck_expr(&self, body: &'gcx hir::Body) {
let subject = self.tcx.hir().body_owner_def_id(body.id());
- let id = body.value.id;
+ let id = body.value.hir_id;
let mut rcx = RegionCtxt::new(
self,
RepeatingScope(id),
/// Region checking during the WF phase for items. `wf_tys` are the
/// types from which we should derive implied bounds, if any.
- pub fn regionck_item(&self, item_id: ast::NodeId, span: Span, wf_tys: &[Ty<'tcx>]) {
+ pub fn regionck_item(&self, item_id: hir::HirId, span: Span, wf_tys: &[Ty<'tcx>]) {
debug!("regionck_item(item.id={:?}, wf_tys={:?})", item_id, wf_tys);
- let subject = self.tcx.hir().local_def_id(item_id);
+ let subject = self.tcx.hir().local_def_id_from_hir_id(item_id);
let mut rcx = RegionCtxt::new(
self,
RepeatingScope(item_id),
pub fn regionck_fn(&self, fn_id: ast::NodeId, body: &'gcx hir::Body) {
debug!("regionck_fn(id={})", fn_id);
let subject = self.tcx.hir().body_owner_def_id(body.id());
- let node_id = body.value.id;
+ let hir_id = body.value.hir_id;
let mut rcx = RegionCtxt::new(
self,
- RepeatingScope(node_id),
- node_id,
+ RepeatingScope(hir_id),
+ hir_id,
Subject(subject),
self.param_env,
);
if self.err_count_since_creation() == 0 {
+ let fn_hir_id = self.tcx.hir().node_to_hir_id(fn_id);
// regionck assumes typeck succeeded
- rcx.visit_fn_body(fn_id, body, self.tcx.hir().span(fn_id));
+ rcx.visit_fn_body(fn_hir_id, body, self.tcx.hir().span_by_hir_id(fn_hir_id));
}
rcx.resolve_regions_and_report_errors(SuppressRegionErrors::when_nll_is_enabled(self.tcx));
outlives_environment: OutlivesEnvironment<'tcx>,
// id of innermost fn body id
- body_id: ast::NodeId,
+ body_id: hir::HirId,
// call_site scope of innermost fn
call_site_scope: Option<region::Scope>,
// id of innermost fn or loop
- repeating_scope: ast::NodeId,
+ repeating_scope: hir::HirId,
// id of AST node being analyzed (the subject of the analysis).
subject_def_id: DefId,
}
}
-pub struct RepeatingScope(ast::NodeId);
+pub struct RepeatingScope(hir::HirId);
pub struct Subject(DefId);
impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
pub fn new(
fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
RepeatingScope(initial_repeating_scope): RepeatingScope,
- initial_body_id: ast::NodeId,
+ initial_body_id: hir::HirId,
Subject(subject): Subject,
param_env: ty::ParamEnv<'tcx>,
) -> RegionCtxt<'a, 'gcx, 'tcx> {
}
}
- fn set_repeating_scope(&mut self, scope: ast::NodeId) -> ast::NodeId {
+ fn set_repeating_scope(&mut self, scope: hir::HirId) -> hir::HirId {
mem::replace(&mut self.repeating_scope, scope)
}
/// `intravisit::Visitor` impl below.)
fn visit_fn_body(
&mut self,
- id: ast::NodeId, // the id of the fn itself
+ id: hir::HirId, // the id of the fn itself
body: &'gcx hir::Body,
span: Span,
) {
// When we enter a function, we can derive
- debug!("visit_fn_body(id={})", id);
+ debug!("visit_fn_body(id={:?})", id);
let body_id = body.id();
- self.body_id = body_id.node_id;
+ self.body_id = body_id.hir_id;
let call_site = region::Scope {
id: body.value.hir_id.local_id,
self.call_site_scope = Some(call_site);
let fn_sig = {
- let fn_hir_id = self.tcx.hir().node_to_hir_id(id);
- match self.tables.borrow().liberated_fn_sigs().get(fn_hir_id) {
+ match self.tables.borrow().liberated_fn_sigs().get(id) {
Some(f) => f.clone(),
None => {
- bug!("No fn-sig entry for id={}", id);
+ bug!("No fn-sig entry for id={:?}", id);
}
}
};
self.outlives_environment.add_implied_bounds(
self.fcx,
&fn_sig_tys[..],
- body_id.node_id,
+ body_id.hir_id,
span,
);
self.outlives_environment
- .save_implied_bounds(body_id.node_id);
+ .save_implied_bounds(body_id.hir_id);
self.link_fn_args(
region::Scope {
id: body.value.hir_id.local_id,
&body.arguments,
);
self.visit_body(body);
- self.visit_region_obligations(body_id.node_id);
+ self.visit_region_obligations(body_id.hir_id);
let call_site_scope = self.call_site_scope.unwrap();
debug!(
);
let call_site_region = self.tcx.mk_region(ty::ReScope(call_site_scope));
- let body_hir_id = self.tcx.hir().node_to_hir_id(body_id.node_id);
- self.type_of_node_must_outlive(infer::CallReturn(span), body_hir_id, call_site_region);
+ self.type_of_node_must_outlive(infer::CallReturn(span), body_id.hir_id, call_site_region);
self.constrain_opaque_types(
&self.fcx.opaque_types.borrow(),
);
}
- fn visit_region_obligations(&mut self, node_id: ast::NodeId) {
- debug!("visit_region_obligations: node_id={}", node_id);
+ fn visit_region_obligations(&mut self, hir_id: hir::HirId) {
+ debug!("visit_region_obligations: hir_id={:?}", hir_id);
// region checking can introduce new pending obligations
// which, when processed, might generate new region
let env_snapshot = self.outlives_environment.push_snapshot_pre_closure();
let body = self.tcx.hir().body(body_id);
- self.visit_fn_body(id, body, span);
+ let hir_id = self.tcx.hir().node_to_hir_id(id);
+ self.visit_fn_body(hir_id, body, span);
// Restore state from previous function.
self.outlives_environment
fn visit_expr(&mut self, expr: &'gcx hir::Expr) {
debug!(
- "regionck::visit_expr(e={:?}, repeating_scope={})",
+ "regionck::visit_expr(e={:?}, repeating_scope={:?})",
expr, self.repeating_scope
);
}
debug!(
- "regionck::visit_expr(e={:?}, repeating_scope={}) - visiting subexprs",
+ "regionck::visit_expr(e={:?}, repeating_scope={:?}) - visiting subexprs",
expr, self.repeating_scope
);
match expr.node {
}
hir::ExprKind::Loop(ref body, _, _) => {
- let repeating_scope = self.set_repeating_scope(body.id);
+ let repeating_scope = self.set_repeating_scope(body.hir_id);
intravisit::walk_expr(self, expr);
self.set_repeating_scope(repeating_scope);
}
hir::ExprKind::While(ref cond, ref body, _) => {
- let repeating_scope = self.set_repeating_scope(cond.id);
+ let repeating_scope = self.set_repeating_scope(cond.hir_id);
self.visit_expr(&cond);
- self.set_repeating_scope(body.id);
+ self.set_repeating_scope(body.hir_id);
self.visit_block(&body);
self.set_repeating_scope(repeating_scope);
}
fn check_expr_fn_block(&mut self, expr: &'gcx hir::Expr, body_id: hir::BodyId) {
- let repeating_scope = self.set_repeating_scope(body_id.node_id);
+ let repeating_scope = self.set_repeating_scope(body_id.hir_id);
intravisit::walk_expr(self, expr);
self.set_repeating_scope(repeating_scope);
}
/// `F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(FnCtxt<'b, 'gcx, 'tcx>)`.
struct CheckWfFcxBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
inherited: super::InheritedBuilder<'a, 'gcx, 'tcx>,
- id: ast::NodeId,
+ id: hir::HirId,
span: Span,
param_env: ty::ParamEnv<'tcx>,
}
fn for_id<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, id: ast::NodeId, span: Span)
-> CheckWfFcxBuilder<'a, 'gcx, 'tcx> {
let def_id = tcx.hir().local_def_id(id);
+ let hir_id = tcx.hir().node_to_hir_id(id);
CheckWfFcxBuilder {
inherited: Inherited::build(tcx, def_id),
- id,
+ id: hir_id,
span,
param_env: tcx.param_env(def_id),
}
fn check_false_global_bounds<'a, 'gcx, 'tcx>(
fcx: &FnCtxt<'a, 'gcx, 'tcx>,
span: Span,
- id: ast::NodeId)
+ id: hir::HirId)
{
use rustc::ty::TypeFoldable;
let empty_env = ty::ParamEnv::empty();
- let def_id = fcx.tcx.hir().local_def_id(id);
+ let def_id = fcx.tcx.hir().local_def_id_from_hir_id(id);
let predicates = fcx.tcx.predicates_of(def_id).predicates
.iter()
.map(|(p, _)| *p)
body: &'gcx hir::Body,
rustc_dump_user_substs: bool,
) -> WritebackCx<'cx, 'gcx, 'tcx> {
- let owner = fcx.tcx.hir().definitions().node_to_hir_id(body.id().node_id);
+ let owner = body.id().hir_id;
WritebackCx {
fcx,
if impl_did.is_local() {
let dispatch_from_dyn_trait = tcx.lang_items().dispatch_from_dyn_trait().unwrap();
- let impl_node_id = tcx.hir().as_local_node_id(impl_did).unwrap();
- let span = tcx.hir().span(impl_node_id);
+ let impl_hir_id = tcx.hir().as_local_hir_id(impl_did).unwrap();
+ let span = tcx.hir().span_by_hir_id(impl_hir_id);
let source = tcx.type_of(impl_did);
assert!(!source.has_escaping_bound_vars());
};
tcx.infer_ctxt().enter(|infcx| {
- let cause = ObligationCause::misc(span, impl_node_id);
+ let cause = ObligationCause::misc(span, impl_hir_id);
use ty::TyKind::*;
match (&source.sty, &target.sty) {
});
// this provider should only get invoked for local def-ids
- let impl_node_id = gcx.hir().as_local_node_id(impl_did).unwrap_or_else(|| {
+ let impl_hir_id = gcx.hir().as_local_hir_id(impl_did).unwrap_or_else(|| {
bug!("coerce_unsized_info: invoked for non-local def-id {:?}", impl_did)
});
source,
target);
- let span = gcx.hir().span(impl_node_id);
+ let span = gcx.hir().span_by_hir_id(impl_hir_id);
let param_env = gcx.param_env(impl_did);
assert!(!source.has_escaping_bound_vars());
target);
gcx.infer_ctxt().enter(|infcx| {
- let cause = ObligationCause::misc(span, impl_node_id);
+ let cause = ObligationCause::misc(span, impl_hir_id);
let check_mutbl = |mt_a: ty::TypeAndMut<'gcx>,
mt_b: ty::TypeAndMut<'gcx>,
mk_ptr: &dyn Fn(Ty<'gcx>) -> Ty<'gcx>| {
being coerced, none found");
return err_info;
} else if diff_fields.len() > 1 {
- let item = gcx.hir().expect_item(impl_node_id);
+ let item = gcx.hir().expect_item_by_hir_id(impl_hir_id);
let span = if let ItemKind::Impl(.., Some(ref t), _, _) = item.node {
t.path.span
} else {
- gcx.hir().span(impl_node_id)
+ gcx.hir().span_by_hir_id(impl_hir_id)
};
let mut err = struct_span_err!(gcx.sess,
let mut fulfill_cx = TraitEngine::new(infcx.tcx);
// Register an obligation for `A: Trait<B>`.
- let cause = traits::ObligationCause::misc(span, impl_node_id);
+ let cause = traits::ObligationCause::misc(span, impl_hir_id);
let predicate = gcx.predicate_for_trait_def(param_env,
cause,
trait_def_id,
+// ignore-tidy-linelength
#![allow(non_snake_case)]
register_long_diagnostics! {
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 _:
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:
`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:
}
```
-[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##"
`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
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##"
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##"
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##"
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##"
```
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##"
}
fn check_main_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, main_def_id: DefId) {
- let main_id = tcx.hir().as_local_node_id(main_def_id).unwrap();
+ let main_id = tcx.hir().as_local_hir_id(main_def_id).unwrap();
let main_span = tcx.def_span(main_def_id);
let main_t = tcx.type_of(main_def_id);
match main_t.sty {
ty::FnDef(..) => {
- if let Some(Node::Item(it)) = tcx.hir().find(main_id) {
+ if let Some(Node::Item(it)) = tcx.hir().find_by_hir_id(main_id) {
if let hir::ItemKind::Fn(.., ref generics, _) = it.node {
let mut error = false;
if !generics.params.is_empty() {
}
fn check_start_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, start_def_id: DefId) {
- let start_id = tcx.hir().as_local_node_id(start_def_id).unwrap();
+ let start_id = tcx.hir().as_local_hir_id(start_def_id).unwrap();
let start_span = tcx.def_span(start_def_id);
let start_t = tcx.type_of(start_def_id);
match start_t.sty {
ty::FnDef(..) => {
- if let Some(Node::Item(it)) = tcx.hir().find(start_id) {
+ if let Some(Node::Item(it)) = tcx.hir().find_by_hir_id(start_id) {
if let hir::ItemKind::Fn(.., ref generics, _) = it.node {
let mut error = false;
if !generics.params.is_empty() {
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
}
}
}
fn print_const_expr(cx: &DocContext, body: hir::BodyId) -> String {
- cx.tcx.hir().node_to_pretty_string(body.node_id)
+ cx.tcx.hir().hir_to_pretty_string(body.hir_id)
}
/// Given a type Path, resolve it to a Type using the TyCtxt
// The trailing space after each tag is to space it properly against the rest of the docs.
if item.deprecation().is_some() {
- tags += &tag_html("deprecated", "Deprecated");
+ let mut message = "Deprecated";
+ if let Some(ref stab) = item.stability {
+ if let Some(ref depr) = stab.deprecation {
+ if let Some(ref since) = depr.since {
+ if !stability::deprecation_in_effect(&since) {
+ message = "Deprecation planned";
+ }
+ }
+ }
+ }
+ tags += &tag_html("deprecated", message);
}
if let Some(stab) = item
let mut stability = vec![];
let error_codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build());
- if let Some(Deprecation { since, note }) = &item.deprecation() {
+ if let Some(Deprecation { note, since }) = &item.deprecation() {
+ // We display deprecation messages for #[deprecated] and #[rustc_deprecated]
+ // but only display the future-deprecation messages for #[rustc_deprecated].
let mut message = if let Some(since) = since {
- if stability::deprecation_in_effect(since) {
- format!("Deprecated since {}", Escape(since))
- } else {
- format!("Deprecating in {}", Escape(since))
- }
+ format!("Deprecated since {}", Escape(since))
} else {
String::from("Deprecated")
};
+ if let Some(ref stab) = item.stability {
+ if let Some(ref depr) = stab.deprecation {
+ if let Some(ref since) = depr.since {
+ if !stability::deprecation_in_effect(&since) {
+ message = format!("Deprecating in {}", Escape(&since));
+ }
+ }
+ }
+ }
if let Some(note) = note {
let mut ids = cx.id_map.borrow_mut();
}
for item in self.cx.tcx.item_children(def_id).iter() {
- if self.cx.tcx.def_key(item.def.def_id()).parent.map_or(false, |d| d == def_id.index) ||
- item.vis == Visibility::Public {
- self.visit_item(item.def);
+ if let Some(def_id) = item.def.opt_def_id() {
+ if self.cx.tcx.def_key(def_id).parent.map_or(false, |d| d == def_id.index) ||
+ item.vis == Visibility::Public {
+ self.visit_item(item.def);
+ }
}
}
}
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)]
#[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),
})
}
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) {
#[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()
/// 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
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()) }
}
where
F: Future
{
- get_task_waker(|lw| F::poll(f, lw))
+ get_task_waker(|waker| F::poll(f, waker))
}
#[cfg(test)] extern crate std as realstd;
#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))]
-#[macro_use]
-#[allow(unused_imports)] // FIXME: without `#[macro_use]`, get error: “cannot
- // determine resolution for the macro `usercalls_asm`”
extern crate fortanix_sgx_abi;
// The standard macros that are not built-in to the compiler.
//! 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",
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")]
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)
}
}
//! [`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")]
.asciz "Re-entered aborted enclave!"
.Lreentry_panic_msg_end:
-.Lusercall_panic_msg:
- .asciz "Invalid usercall#!"
-.Lusercall_panic_msg_end:
-
.org .Lxsave_clear+512
.Lxsave_header:
.int 0, 0 /* XSTATE_BV */
orq $8,%rsp
jmp panic_msg
-.Lusercall_panic:
- lea .Lusercall_panic_msg(%rip),%rdi
- mov $.Lusercall_panic_msg_end-.Lusercall_panic_msg,%esi
- orq $8,%rsp
- jmp panic_msg
-
-.macro push_callee_saved_registers
+/* This *MUST* be called with 6 parameters, otherwise register information */
+/* might leak! */
+.global usercall
+usercall:
+ test %rcx,%rcx /* check `abort` function argument */
+ jnz .Lusercall_abort /* abort is set, jump to abort code (unlikely forward conditional) */
+ jmp .Lusercall_save_state /* non-aborting usercall */
+.Lusercall_abort:
+/* set aborted bit */
+ movb $1,.Laborted(%rip)
+/* save registers in DEBUG mode, so that debugger can reconstruct the stack */
+ testb $0xff,DEBUG(%rip)
+ jz .Lusercall_noreturn
+.Lusercall_save_state:
+/* save callee-saved state */
push %r15
push %r14
push %r13
sub $8, %rsp
fstcw 4(%rsp)
stmxcsr (%rsp)
-.endm
-
-.global usercall_exit
-usercall_exit:
-/* save registers in DEBUG mode, so that debugger can reconstruct the stack */
- testb $0xff,DEBUG(%rip)
- jz .Lskip_save_registers
- push_callee_saved_registers
- movq %rsp,%gs:tcsls_panic_last_rsp
-.Lskip_save_registers:
-/* set aborted bit */
- movb $1,.Laborted(%rip)
-/* call usercall exit(true) */
- /* NOP: mov %rsi,%rsi */ /* RSI = usercall() argument: panic */
- xor %rdx,%rdx /* RDX cleared */
- movq $usercall_nr_exit,%rdi /* RDI = usercall exit */
- jmp .Lexit
-
-/* This *MUST* be called with 6 parameters, otherwise register information */
-/* might leak! */
-.global usercall
-usercall:
- test %rdi,%rdi
- jle .Lusercall_panic
-/* save callee-saved state */
- push_callee_saved_registers
movq %rsp,%gs:tcsls_last_rsp
+.Lusercall_noreturn:
/* clear general purpose register state */
/* RAX overwritten by ENCLU */
/* RBX set by sgx_exit */
jmp .Lsgx_exit
.Lusercall_ret:
movq $0,%gs:tcsls_last_rsp
-/* restore callee-saved state, cf. push_callee_saved_registers */
+/* restore callee-saved state, cf. "save" above */
mov %r11,%rsp
ldmxcsr (%rsp)
fldcw 4(%rsp)
#[macro_use]
pub mod usercalls;
-global_asm!(concat!(usercalls_asm!(), include_str!("entry.S")));
+global_asm!(include_str!("entry.S"));
#[no_mangle]
unsafe extern "C" fn tcs_init(secondary: bool) {
-use super::usercalls::alloc::UserRef;
+use super::usercalls::{alloc::UserRef, self};
use cmp;
use io::{self, Write};
use mem;
#[no_mangle]
pub extern "C" fn panic_msg(msg: &str) -> ! {
let _ = SgxPanicOutput::new().map(|mut out| out.write(msg.as_bytes()));
- unsafe { usercall_exit(true); }
+ usercalls::exit(true)
}
-
-extern "C" { pub fn usercall_exit(panic: bool) -> !; }
/// Usercall `exit`. See the ABI documentation for more information.
#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn exit(panic: bool) -> ! {
- unsafe { super::panic::usercall_exit(panic) }
+ unsafe { raw::exit(panic) }
}
/// Usercall `wait`. See the ABI documentation for more information.
pub use fortanix_sgx_abi::*;
use ptr::NonNull;
+use num::NonZeroU64;
#[repr(C)]
struct UsercallReturn(u64, u64);
extern "C" {
- fn usercall(nr: u64, p1: u64, p2: u64, _ignore: u64, p3: u64, p4: u64) -> UsercallReturn;
+ fn usercall(nr: NonZeroU64, p1: u64, p2: u64, abort: u64, p3: u64, p4: u64) -> UsercallReturn;
}
/// Performs the raw usercall operation as defined in the ABI calling convention.
///
/// Panics if `nr` is `0`.
#[unstable(feature = "sgx_platform", issue = "56975")]
-pub unsafe fn do_usercall(nr: u64, p1: u64, p2: u64, p3: u64, p4: u64) -> (u64, u64) {
- if nr==0 { panic!("Invalid usercall number {}",nr) }
- let UsercallReturn(a, b) = usercall(nr,p1,p2,0,p3,p4);
+#[inline]
+pub unsafe fn do_usercall(nr: NonZeroU64, p1: u64, p2: u64, p3: u64, p4: u64, abort: bool)
+ -> (u64, u64)
+{
+ let UsercallReturn(a, b) = usercall(nr, p1, p2, abort as _, p3, p4);
(a, b)
}
}
macro_rules! define_usercalls {
- // Using `$r:tt` because `$r:ty` doesn't match ! in `clobber_diverging`
($(fn $f:ident($($n:ident: $t:ty),*) $(-> $r:tt)*; )*) => {
/// Usercall numbers as per the ABI.
#[repr(u64)]
};
}
-macro_rules! define_usercalls_asm {
- ($(fn $f:ident($($n:ident: $t:ty),*) $(-> $r:ty)*; )*) => {
- macro_rules! usercalls_asm {
- () => {
- concat!(
- ".equ usercall_nr_LAST, 0\n",
- $(
- ".equ usercall_nr_", stringify!($f), ", usercall_nr_LAST+1\n",
- ".equ usercall_nr_LAST, usercall_nr_", stringify!($f), "\n"
- ),*
- )
- }
- }
- };
-}
-
macro_rules! define_ra {
(< $i:ident > $t:ty) => {
impl<$i> RegisterArgument for $t {
}
}
+macro_rules! return_type_is_abort {
+ (!) => { true };
+ ($r:ty) => { false };
+}
+
+// In this macro: using `$r:tt` because `$r:ty` doesn't match ! in `return_type_is_abort`
macro_rules! enclave_usercalls_internal_define_usercalls {
(def fn $f:ident($n1:ident: $t1:ty, $n2:ident: $t2:ty,
- $n3:ident: $t3:ty, $n4:ident: $t4:ty) -> $r:ty) => (
+ $n3:ident: $t3:ty, $n4:ident: $t4:ty) -> $r:tt) => (
/// This is the raw function definition, see the ABI documentation for
/// more information.
#[unstable(feature = "sgx_platform", issue = "56975")]
#[inline(always)]
pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3, $n4: $t4) -> $r {
ReturnValue::from_registers(stringify!($f), do_usercall(
- Usercalls::$f as Register,
+ NonZeroU64::new(Usercalls::$f as Register)
+ .expect("Usercall number must be non-zero"),
RegisterArgument::into_register($n1),
RegisterArgument::into_register($n2),
RegisterArgument::into_register($n3),
RegisterArgument::into_register($n4),
+ return_type_is_abort!($r)
))
}
);
- (def fn $f:ident($n1:ident: $t1:ty, $n2:ident: $t2:ty, $n3:ident: $t3:ty) -> $r:ty) => (
+ (def fn $f:ident($n1:ident: $t1:ty, $n2:ident: $t2:ty, $n3:ident: $t3:ty) -> $r:tt) => (
/// This is the raw function definition, see the ABI documentation for
/// more information.
#[unstable(feature = "sgx_platform", issue = "56975")]
#[inline(always)]
pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3) -> $r {
ReturnValue::from_registers(stringify!($f), do_usercall(
- Usercalls::$f as Register,
+ NonZeroU64::new(Usercalls::$f as Register)
+ .expect("Usercall number must be non-zero"),
RegisterArgument::into_register($n1),
RegisterArgument::into_register($n2),
RegisterArgument::into_register($n3),
- 0
+ 0,
+ return_type_is_abort!($r)
))
}
);
- (def fn $f:ident($n1:ident: $t1:ty, $n2:ident: $t2:ty) -> $r:ty) => (
+ (def fn $f:ident($n1:ident: $t1:ty, $n2:ident: $t2:ty) -> $r:tt) => (
/// This is the raw function definition, see the ABI documentation for
/// more information.
#[unstable(feature = "sgx_platform", issue = "56975")]
#[inline(always)]
pub unsafe fn $f($n1: $t1, $n2: $t2) -> $r {
ReturnValue::from_registers(stringify!($f), do_usercall(
- Usercalls::$f as Register,
+ NonZeroU64::new(Usercalls::$f as Register)
+ .expect("Usercall number must be non-zero"),
RegisterArgument::into_register($n1),
RegisterArgument::into_register($n2),
- 0,0
+ 0,0,
+ return_type_is_abort!($r)
))
}
);
- (def fn $f:ident($n1:ident: $t1:ty) -> $r:ty) => (
+ (def fn $f:ident($n1:ident: $t1:ty) -> $r:tt) => (
/// This is the raw function definition, see the ABI documentation for
/// more information.
#[unstable(feature = "sgx_platform", issue = "56975")]
#[inline(always)]
pub unsafe fn $f($n1: $t1) -> $r {
ReturnValue::from_registers(stringify!($f), do_usercall(
- Usercalls::$f as Register,
+ NonZeroU64::new(Usercalls::$f as Register)
+ .expect("Usercall number must be non-zero"),
RegisterArgument::into_register($n1),
- 0,0,0
+ 0,0,0,
+ return_type_is_abort!($r)
))
}
);
- (def fn $f:ident() -> $r:ty) => (
+ (def fn $f:ident() -> $r:tt) => (
/// This is the raw function definition, see the ABI documentation for
/// more information.
#[unstable(feature = "sgx_platform", issue = "56975")]
#[inline(always)]
pub unsafe fn $f() -> $r {
ReturnValue::from_registers(stringify!($f), do_usercall(
- Usercalls::$f as Register,
- 0,0,0,0
+ NonZeroU64::new(Usercalls::$f as Register)
+ .expect("Usercall number must be non-zero"),
+ 0,0,0,0,
+ return_type_is_abort!($r)
))
}
);
}
invoke_with_usercalls!(define_usercalls);
-invoke_with_usercalls!(define_usercalls_asm);
}
pub unsafe fn abort_internal() -> ! {
- abi::panic::usercall_exit(true)
+ abi::usercalls::exit(true)
}
pub fn hashmap_random_keys() -> (u64, u64) {
//! 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
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;
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
}
}
--- /dev/null
+// revisions: rpass cfail
+
+trait Tr {
+ type Arr;
+
+ const C: usize = 0;
+}
+
+impl Tr for str {
+ #[cfg(rpass)]
+ type Arr = [u8; 8];
+ #[cfg(cfail)]
+ type Arr = [u8; Self::C];
+ //[cfail]~^ ERROR cycle detected when const-evaluating
+}
+
+fn main() {}
--- /dev/null
+// Test that we don't ICE when trying to dump MIR for unusual item types and
+// that we don't create filenames containing `<` and `>`
+
+struct A;
+
+impl A {
+ const ASSOCIATED_CONSTANT: i32 = 2;
+}
+
+enum E {
+ V = 5,
+}
+
+fn main() {
+ let v = Vec::<i32>::new();
+}
+
+// END RUST SOURCE
+
+// START rustc.{{impl}}-ASSOCIATED_CONSTANT.mir_map.0.mir
+// bb0: {
+// _0 = const 2i32;
+// return;
+// }
+// bb1: {
+// resume;
+// }
+// END rustc.{{impl}}-ASSOCIATED_CONSTANT.mir_map.0.mir
+
+// START rustc.E-V-{{constant}}.mir_map.0.mir
+// bb0: {
+// _0 = const 5isize;
+// return;
+// }
+// bb1: {
+// resume;
+// }
+// END rustc.E-V-{{constant}}.mir_map.0.mir
+
+// START rustc.ptr-real_drop_in_place.std__vec__Vec_i32_.AddMovesForPackedDrops.before.mir
+// bb0: {
+// goto -> bb7;
+// }
+// bb1: {
+// return;
+// }
+// bb2: {
+// resume;
+// }
+// bb3: {
+// goto -> bb1;
+// }
+// bb4: {
+// goto -> bb2;
+// }
+// bb5: {
+// drop(((*_1).0: alloc::raw_vec::RawVec<i32>)) -> bb4;
+// }
+// bb6: {
+// drop(((*_1).0: alloc::raw_vec::RawVec<i32>)) -> [return: bb3, unwind: bb4];
+// }
+// bb7: {
+// _2 = &mut (*_1);
+// _3 = const std::ops::Drop::drop(move _2) -> [return: bb6, unwind: bb5];
+// }
+// END rustc.ptr-real_drop_in_place.std__vec__Vec_i32_.AddMovesForPackedDrops.before.mir
--- /dev/null
+-include ../../run-make-fulldeps/tools.mk
+
+ifeq ($(TARGET),wasm32-unknown-unknown)
+all:
+ $(RUSTC) foo.rs -C lto -O --target wasm32-unknown-unknown
+ wc -c < $(TMPDIR)/foo.wasm
+ [ "`wc -c < $(TMPDIR)/foo.wasm`" -lt "20500" ]
+else
+all:
+endif
--- /dev/null
+#![crate_type = "cdylib"]
+
+extern "C" {
+ fn observe(ptr: *const u8, len: usize);
+}
+
+macro_rules! s {
+ ( $( $f:ident -> $t:ty );* $(;)* ) => {
+ $(
+ extern "C" {
+ fn $f() -> $t;
+ }
+ let s = $f().to_string();
+ observe(s.as_ptr(), s.len());
+ )*
+ };
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn foo() {
+ s! {
+ get_u8 -> u8;
+ get_i8 -> i8;
+ get_u16 -> u16;
+ get_i16 -> i16;
+ get_u32 -> u32;
+ get_i32 -> i32;
+ get_u64 -> u64;
+ get_i64 -> i64;
+ get_usize -> usize;
+ get_isize -> isize;
+ }
+}
// 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::{
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);
}
}
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
}
{
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));
--- /dev/null
+// 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);
+}
+// 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);
}
}
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();
}
+++ /dev/null
-// 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' },
- ],
-};
#![feature(deprecated)]
+// @has deprecated_future/index.html '//*[@class="stab deprecated"]' \
+// 'Deprecated'
// @has deprecated_future/struct.S.html '//*[@class="stab deprecated"]' \
-// 'Deprecating in 99.99.99: effectively never'
+// 'Deprecated since 99.99.99: effectively never'
#[deprecated(since = "99.99.99", note = "effectively never")]
pub struct S;
--- /dev/null
+#![feature(staged_api)]
+
+#![stable(feature = "rustc_deprecated-future-test", since = "1.0.0")]
+
+// @has rustc_deprecated_future/index.html '//*[@class="stab deprecated"]' \
+// 'Deprecation planned'
+// @has rustc_deprecated_future/struct.S.html '//*[@class="stab deprecated"]' \
+// 'Deprecating in 99.99.99: effectively never'
+#[rustc_deprecated(since = "99.99.99", reason = "effectively never")]
+#[stable(feature = "rustc_deprecated-future-test", since = "1.0.0")]
+pub struct S;
--> $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
--> $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
// ignore-tidy-linelength
+// run-pass
+
#![deny(deprecated_in_future)]
#[deprecated(since = "99.99.99", note = "text")]
pub fn deprecated_future() {}
fn test() {
- deprecated_future(); //~ ERROR use of item 'deprecated_future' that will be deprecated in future version 99.99.99: text
+ deprecated_future(); // ok; deprecated_in_future only applies to rustc_deprecated
}
fn main() {}
-error: use of item 'deprecated_future' that will be deprecated in future version 99.99.99: text
- --> $DIR/deprecation-in-future.rs:9:5
+warning: use of deprecated item 'deprecated_future': text
+ --> $DIR/deprecation-in-future.rs:11:5
|
-LL | deprecated_future(); //~ ERROR use of item 'deprecated_future' that will be deprecated in future version 99.99.99: text
+LL | deprecated_future(); // ok; deprecated_in_future only applies to rustc_deprecated
| ^^^^^^^^^^^^^^^^^
|
-note: lint level defined here
- --> $DIR/deprecation-in-future.rs:3:9
- |
-LL | #![deny(deprecated_in_future)]
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
+ = note: #[warn(deprecated)] on by default
<Foo>::trait_deprecated_text(&foo); //~ ERROR use of deprecated item 'this_crate::Trait::trait_deprecated_text': text
<Foo as Trait>::trait_deprecated_text(&foo); //~ ERROR use of deprecated item 'this_crate::Trait::trait_deprecated_text': text
- deprecated_future(); // Fine; no error.
- deprecated_future_text(); // Fine; no error.
+ // Future deprecations are only permitted for rustc_deprecated.
+ deprecated_future(); //~ ERROR use of deprecated item
+ deprecated_future_text(); //~ ERROR use of deprecated item
let _ = DeprecatedStruct {
//~^ ERROR use of deprecated item 'this_crate::DeprecatedStruct': text
LL | <Foo as Trait>::trait_deprecated_text(&foo); //~ ERROR use of deprecated item 'this_crate::Trait::trait_deprecated_text': text
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+error: use of deprecated item 'this_crate::deprecated_future': text
+ --> $DIR/deprecation-lint.rs:265:9
+ |
+LL | deprecated_future(); //~ ERROR use of deprecated item
+ | ^^^^^^^^^^^^^^^^^
+
+error: use of deprecated item 'this_crate::deprecated_future_text': text
+ --> $DIR/deprecation-lint.rs:266:9
+ |
+LL | deprecated_future_text(); //~ ERROR use of deprecated item
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
error: use of deprecated item 'this_crate::DeprecatedStruct': text
- --> $DIR/deprecation-lint.rs:267:17
+ --> $DIR/deprecation-lint.rs:268:17
|
LL | let _ = DeprecatedStruct {
| ^^^^^^^^^^^^^^^^
error: use of deprecated item 'this_crate::DeprecatedUnitStruct': text
- --> $DIR/deprecation-lint.rs:272:17
+ --> $DIR/deprecation-lint.rs:273:17
|
LL | let _ = DeprecatedUnitStruct; //~ ERROR use of deprecated item 'this_crate::DeprecatedUnitStruct': text
| ^^^^^^^^^^^^^^^^^^^^
error: use of deprecated item 'this_crate::Enum::DeprecatedVariant': text
- --> $DIR/deprecation-lint.rs:274:17
+ --> $DIR/deprecation-lint.rs:275:17
|
LL | let _ = Enum::DeprecatedVariant; //~ ERROR use of deprecated item 'this_crate::Enum::DeprecatedVariant': text
| ^^^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated item 'this_crate::DeprecatedTupleStruct': text
- --> $DIR/deprecation-lint.rs:276:17
+ --> $DIR/deprecation-lint.rs:277:17
|
LL | let _ = DeprecatedTupleStruct (1); //~ ERROR use of deprecated item 'this_crate::DeprecatedTupleStruct': text
| ^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated item 'this_crate::nested::DeprecatedStruct': text
- --> $DIR/deprecation-lint.rs:278:17
+ --> $DIR/deprecation-lint.rs:279:17
|
LL | let _ = nested::DeprecatedStruct {
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated item 'this_crate::nested::DeprecatedUnitStruct': text
- --> $DIR/deprecation-lint.rs:283:17
+ --> $DIR/deprecation-lint.rs:284:17
|
LL | let _ = nested::DeprecatedUnitStruct; //~ ERROR use of deprecated item 'this_crate::nested::DeprecatedUnitStruct': text
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated item 'this_crate::nested::Enum::DeprecatedVariant': text
- --> $DIR/deprecation-lint.rs:285:17
+ --> $DIR/deprecation-lint.rs:286:17
|
LL | let _ = nested::Enum::DeprecatedVariant; //~ ERROR use of deprecated item 'this_crate::nested::Enum::DeprecatedVariant': text
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated item 'this_crate::nested::DeprecatedTupleStruct': text
- --> $DIR/deprecation-lint.rs:287:17
+ --> $DIR/deprecation-lint.rs:288:17
|
LL | let _ = nested::DeprecatedTupleStruct (1); //~ ERROR use of deprecated item 'this_crate::nested::DeprecatedTupleStruct': text
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated item 'this_crate::Trait::trait_deprecated': text
- --> $DIR/deprecation-lint.rs:292:9
+ --> $DIR/deprecation-lint.rs:293:9
|
LL | Trait::trait_deprecated(&foo); //~ ERROR use of deprecated item 'this_crate::Trait::trait_deprecated'
| ^^^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated item 'this_crate::Trait::trait_deprecated': text
- --> $DIR/deprecation-lint.rs:294:9
+ --> $DIR/deprecation-lint.rs:295:9
|
LL | <Foo as Trait>::trait_deprecated(&foo); //~ ERROR use of deprecated item 'this_crate::Trait::trait_deprecated'
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text
- --> $DIR/deprecation-lint.rs:296:9
+ --> $DIR/deprecation-lint.rs:297:9
|
LL | Trait::trait_deprecated_text(&foo); //~ ERROR use of deprecated item 'this_crate::Trait::trait_deprecated_text': text
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text
- --> $DIR/deprecation-lint.rs:298:9
+ --> $DIR/deprecation-lint.rs:299:9
|
LL | <Foo as Trait>::trait_deprecated_text(&foo); //~ ERROR use of deprecated item 'this_crate::Trait::trait_deprecated_text': text
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated item 'this_crate::test_fn_closure_body::{{closure}}::bar'
- --> $DIR/deprecation-lint.rs:316:13
+ --> $DIR/deprecation-lint.rs:317:13
|
LL | bar(); //~ ERROR use of deprecated item 'this_crate::test_fn_closure_body::{{closure}}::bar'
| ^^^
error: use of deprecated item 'this_crate::DeprecatedTrait': text
- --> $DIR/deprecation-lint.rs:335:10
+ --> $DIR/deprecation-lint.rs:336:10
|
LL | impl DeprecatedTrait for S { } //~ ERROR use of deprecated item 'this_crate::DeprecatedTrait': text
| ^^^^^^^^^^^^^^^
error: use of deprecated item 'this_crate::DeprecatedTrait': text
- --> $DIR/deprecation-lint.rs:337:24
+ --> $DIR/deprecation-lint.rs:338:24
|
LL | trait LocalTrait : DeprecatedTrait { } //~ ERROR use of deprecated item 'this_crate::DeprecatedTrait': text
| ^^^^^^^^^^^^^^^
error: use of deprecated item 'this_crate2::Deprecated': text
- --> $DIR/deprecation-lint.rs:389:17
+ --> $DIR/deprecation-lint.rs:390:17
|
LL | let x = Deprecated {
| ^^^^^^^^^^
error: use of deprecated item 'this_crate2::Deprecated': text
- --> $DIR/deprecation-lint.rs:398:13
+ --> $DIR/deprecation-lint.rs:399:13
|
LL | let Deprecated {
| ^^^^^^^^^^
error: use of deprecated item 'this_crate2::Deprecated': text
- --> $DIR/deprecation-lint.rs:404:13
+ --> $DIR/deprecation-lint.rs:405:13
|
LL | let Deprecated
| ^^^^^^^^^^
error: use of deprecated item 'this_crate2::Deprecated2': text
- --> $DIR/deprecation-lint.rs:409:17
+ --> $DIR/deprecation-lint.rs:410:17
|
LL | let x = Deprecated2(1, 2, 3);
| ^^^^^^^^^^^
error: use of deprecated item 'this_crate2::Deprecated2': text
- --> $DIR/deprecation-lint.rs:419:13
+ --> $DIR/deprecation-lint.rs:420:13
|
LL | let Deprecated2
| ^^^^^^^^^^^
error: use of deprecated item 'this_crate2::Deprecated2': text
- --> $DIR/deprecation-lint.rs:428:13
+ --> $DIR/deprecation-lint.rs:429:13
|
LL | let Deprecated2
| ^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated item 'this_crate::DeprecatedStruct::i': text
- --> $DIR/deprecation-lint.rs:269:13
+ --> $DIR/deprecation-lint.rs:270:13
|
LL | i: 0 //~ ERROR use of deprecated item 'this_crate::DeprecatedStruct::i': text
| ^^^^
error: use of deprecated item 'this_crate::nested::DeprecatedStruct::i': text
- --> $DIR/deprecation-lint.rs:280:13
+ --> $DIR/deprecation-lint.rs:281:13
|
LL | i: 0 //~ ERROR use of deprecated item 'this_crate::nested::DeprecatedStruct::i': text
| ^^^^
error: use of deprecated item 'this_crate::Trait::trait_deprecated': text
- --> $DIR/deprecation-lint.rs:291:13
+ --> $DIR/deprecation-lint.rs:292:13
|
LL | foo.trait_deprecated(); //~ ERROR use of deprecated item 'this_crate::Trait::trait_deprecated'
| ^^^^^^^^^^^^^^^^
error: use of deprecated item 'this_crate::Trait::trait_deprecated': text
- --> $DIR/deprecation-lint.rs:293:9
+ --> $DIR/deprecation-lint.rs:294:9
|
LL | <Foo>::trait_deprecated(&foo); //~ ERROR use of deprecated item 'this_crate::Trait::trait_deprecated'
| ^^^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text
- --> $DIR/deprecation-lint.rs:295:13
+ --> $DIR/deprecation-lint.rs:296:13
|
LL | foo.trait_deprecated_text(); //~ ERROR use of deprecated item 'this_crate::Trait::trait_deprecated_text': text
| ^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text
- --> $DIR/deprecation-lint.rs:297:9
+ --> $DIR/deprecation-lint.rs:298:9
|
LL | <Foo>::trait_deprecated_text(&foo); //~ ERROR use of deprecated item 'this_crate::Trait::trait_deprecated_text': text
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated item 'this_crate::Trait::trait_deprecated': text
- --> $DIR/deprecation-lint.rs:302:13
+ --> $DIR/deprecation-lint.rs:303:13
|
LL | foo.trait_deprecated(); //~ ERROR use of deprecated item 'this_crate::Trait::trait_deprecated'
| ^^^^^^^^^^^^^^^^
error: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text
- --> $DIR/deprecation-lint.rs:303:13
+ --> $DIR/deprecation-lint.rs:304:13
|
LL | foo.trait_deprecated_text(); //~ ERROR use of deprecated item 'this_crate::Trait::trait_deprecated_text': text
| ^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated item 'this_crate2::Stable::override2': text
- --> $DIR/deprecation-lint.rs:362:13
+ --> $DIR/deprecation-lint.rs:363:13
|
LL | override2: 3,
| ^^^^^^^^^^^^
error: use of deprecated item 'this_crate2::Stable::override2': text
- --> $DIR/deprecation-lint.rs:366:17
+ --> $DIR/deprecation-lint.rs:367:17
|
LL | let _ = x.override2;
| ^^^^^^^^^^^
error: use of deprecated item 'this_crate2::Stable::override2': text
- --> $DIR/deprecation-lint.rs:370:13
+ --> $DIR/deprecation-lint.rs:371:13
|
LL | override2: _
| ^^^^^^^^^^^^
error: use of deprecated item 'this_crate2::Stable2::2': text
- --> $DIR/deprecation-lint.rs:378:17
+ --> $DIR/deprecation-lint.rs:379:17
|
LL | let _ = x.2;
| ^^^
error: use of deprecated item 'this_crate2::Stable2::2': text
- --> $DIR/deprecation-lint.rs:383:20
+ --> $DIR/deprecation-lint.rs:384:20
|
LL | _)
| ^
error: use of deprecated item 'this_crate2::Deprecated::inherit': text
- --> $DIR/deprecation-lint.rs:391:13
+ --> $DIR/deprecation-lint.rs:392:13
|
LL | inherit: 1,
| ^^^^^^^^^^
error: use of deprecated item 'this_crate2::Deprecated::inherit': text
- --> $DIR/deprecation-lint.rs:395:17
+ --> $DIR/deprecation-lint.rs:396:17
|
LL | let _ = x.inherit;
| ^^^^^^^^^
error: use of deprecated item 'this_crate2::Deprecated::inherit': text
- --> $DIR/deprecation-lint.rs:400:13
+ --> $DIR/deprecation-lint.rs:401:13
|
LL | inherit: _,
| ^^^^^^^^^^
error: use of deprecated item 'this_crate2::Deprecated2::0': text
- --> $DIR/deprecation-lint.rs:412:17
+ --> $DIR/deprecation-lint.rs:413:17
|
LL | let _ = x.0;
| ^^^
error: use of deprecated item 'this_crate2::Deprecated2::1': text
- --> $DIR/deprecation-lint.rs:414:17
+ --> $DIR/deprecation-lint.rs:415:17
|
LL | let _ = x.1;
| ^^^
error: use of deprecated item 'this_crate2::Deprecated2::2': text
- --> $DIR/deprecation-lint.rs:416:17
+ --> $DIR/deprecation-lint.rs:417:17
|
LL | let _ = x.2;
| ^^^
error: use of deprecated item 'this_crate2::Deprecated2::0': text
- --> $DIR/deprecation-lint.rs:421:14
+ --> $DIR/deprecation-lint.rs:422:14
|
LL | (_,
| ^
error: use of deprecated item 'this_crate2::Deprecated2::1': text
- --> $DIR/deprecation-lint.rs:423:14
+ --> $DIR/deprecation-lint.rs:424:14
|
LL | _,
| ^
error: use of deprecated item 'this_crate2::Deprecated2::2': text
- --> $DIR/deprecation-lint.rs:425:14
+ --> $DIR/deprecation-lint.rs:426:14
|
LL | _)
| ^
-error: aborting due to 120 previous errors
+error: aborting due to 122 previous errors
--- /dev/null
+// ignore-tidy-linelength
+
+#![deny(deprecated_in_future)]
+
+#![feature(staged_api)]
+
+#![stable(feature = "rustc_deprecation-in-future-test", since = "1.0.0")]
+
+#[rustc_deprecated(since = "99.99.99", reason = "effectively never")]
+#[stable(feature = "rustc_deprecation-in-future-test", since = "1.0.0")]
+pub struct S;
+
+fn main() {
+ let _ = S; //~ ERROR use of item 'S' that will be deprecated in future version 99.99.99: effectively never
+}
--- /dev/null
+error: use of item 'S' that will be deprecated in future version 99.99.99: effectively never
+ --> $DIR/rustc_deprecation-in-future.rs:14:13
+ |
+LL | let _ = S; //~ ERROR use of item 'S' that will be deprecated in future version 99.99.99: effectively never
+ | ^
+ |
+note: lint level defined here
+ --> $DIR/rustc_deprecation-in-future.rs:3:9
+ |
+LL | #![deny(deprecated_in_future)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
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 `()`
}
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
--> $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
--- /dev/null
+mod foo {
+ pub struct B(());
+}
+
+mod bar {
+ use foo::B;
+
+ fn foo() {
+ B(()); //~ ERROR expected function, found struct `B` [E0423]
+ }
+}
+
+mod baz {
+ fn foo() {
+ B(()); //~ ERROR cannot find function `B` in this scope [E0425]
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0423]: expected function, found struct `B`
+ --> $DIR/issue-42944.rs:9:9
+ |
+LL | B(()); //~ ERROR expected function, found struct `B` [E0423]
+ | ^ constructor is not visible here due to private fields
+
+error[E0425]: cannot find function `B` in this scope
+ --> $DIR/issue-42944.rs:15:9
+ |
+LL | B(()); //~ ERROR cannot find function `B` in this scope [E0425]
+ | ^ not found in this scope
+help: possible candidate is found in another module, you can import it into scope
+ |
+LL | use foo::B;
+ |
+
+error: aborting due to 2 previous errors
+
+Some errors occurred: E0423, E0425.
+For more information about an error, try `rustc --explain E0423`.
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
}
}
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 `()`
}
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,
"down" => RoomDirection::Down,
_ => None
}
+ //~^^ ERROR match arms have incompatible types
}
fn main() {
| ^^^^^^^^^ ...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<_>`
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() { }
= 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
--> $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
--> $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
--> $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
--> $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
--> $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
--> $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
--> $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
--- /dev/null
+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
+}
--- /dev/null
+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`.
#![stable(feature = "stable_test_feature", since = "1.0.0")]
pub fn unmarked() {
- //~^ ERROR This node does not have a stability attribute
+ //~^ ERROR function has missing stability attribute
()
}
pub mod bar {
// #[stable] is not inherited
pub fn unmarked() {}
- //~^ ERROR This node does not have a stability attribute
+ //~^ ERROR function has missing stability attribute
}
-error: This node does not have a stability attribute
+error: function has missing stability attribute
--> $DIR/missing-stability.rs:8:1
|
LL | / pub fn unmarked() {
-LL | | //~^ ERROR This node does not have a stability attribute
+LL | | //~^ ERROR function has missing stability attribute
LL | | ()
LL | | }
| |_^
-error: This node does not have a stability attribute
+error: function has missing stability attribute
--> $DIR/missing-stability.rs:22:5
|
LL | pub fn unmarked() {}
--> $DIR/privacy-struct-ctor.rs:20:9
|
LL | Z;
- | ^ constructor is not visible here due to private fields
-help: a tuple struct with a similar name exists
- |
-LL | S;
| ^
-help: possible better candidate is found in another module, you can import it into scope
- |
-LL | use m::n::Z;
- |
+ | |
+ | constructor is not visible here due to private fields
+ | help: a tuple struct with a similar name exists: `S`
error[E0423]: expected value, found struct `S`
--> $DIR/privacy-struct-ctor.rs:33:5
|
LL | S;
| ^ constructor is not visible here due to private fields
-help: possible better candidate is found in another module, you can import it into scope
- |
-LL | use m::S;
- |
error[E0423]: expected value, found struct `S2`
--> $DIR/privacy-struct-ctor.rs:38:5
--> $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
--> $DIR/basic.rs:27:9
|
LL | use S as _; //~ WARN unused import
- | ----^^^^^^- help: remove the whole `use` item
+ | ^^^^^^
--> $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
--> $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
LL | #![warn(unused)]
| ^^^^^^
= note: #[warn(unused_imports)] implied by #[warn(unused)]
-help: remove the unused imports
- |
-LL | use std::cmp::{min};
- | -- --
--- /dev/null
+#![feature(staged_api)]
+//~^ ERROR crate has missing stability attribute
+
+fn main() {}
--- /dev/null
+error: crate has missing stability attribute
+ --> $DIR/missing-stability-attr-at-top-level.rs:1:1
+ |
+LL | / #![feature(staged_api)]
+LL | | //~^ ERROR crate has missing stability attribute
+LL | |
+LL | | fn main() {}
+ | |____________^
+
+error: aborting due to previous error
+
#![stable(feature = "test", since = "0")]
#[stable(feature = "test", since = "0")]
-pub struct Reverse<T>(pub T); //~ ERROR This node does not have a stability attribute
+pub struct Reverse<T>(pub T); //~ ERROR field has missing stability attribute
fn main() {
// Make sure the field is used to fill the stability cache
-error: This node does not have a stability attribute
+error: field has missing stability attribute
--> $DIR/stability-attribute-issue-43027.rs:5:23
|
-LL | pub struct Reverse<T>(pub T); //~ ERROR This node does not have a stability attribute
+LL | pub struct Reverse<T>(pub T); //~ ERROR field has missing stability attribute
| ^^^^^
error: aborting due to previous error
#![stable(feature = "stable_test_feature", since = "1.0.0")]
#[macro_export]
-macro_rules! mac { //~ ERROR This node does not have a stability attribute
+macro_rules! mac { //~ ERROR macro has missing stability attribute
() => ()
}
-error: This node does not have a stability attribute
+error: macro has missing stability attribute
--> $DIR/stability-attribute-sanity-3.rs:8:1
|
-LL | / macro_rules! mac { //~ ERROR This node does not have a stability attribute
+LL | / macro_rules! mac { //~ ERROR macro has missing stability attribute
LL | | () => ()
LL | | }
| |_^
--> $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`
--> $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`
--> $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`
--> $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`
--> $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
--> $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
'rust-by-example': '@steveklabnik @marioidival @projektir',
}
+REPOS = {
+ 'miri': 'https://github.com/solson/miri',
+ 'clippy-driver': 'https://github.com/rust-lang/rust-clippy',
+ 'rls': 'https://github.com/rust-lang/rls',
+ 'rustfmt': 'https://github.com/rust-lang/rustfmt',
+ 'book': 'https://github.com/rust-lang/book',
+ 'nomicon': 'https://github.com/rust-lang-nursery/nomicon',
+ 'reference': 'https://github.com/rust-lang-nursery/reference',
+ 'rust-by-example': 'https://github.com/rust-lang/rust-by-example',
+}
+
def read_current_status(current_commit, path):
'''Reads build status of `current_commit` from content of `history/*.tsv`
return json.loads(status)
return {}
+def issue(
+ tool,
+ maintainers,
+ relevant_pr_number,
+ relevant_pr_user,
+ pr_reviewer,
+):
+ # Open an issue about the toolstate failure.
+ gh_url = 'https://api.github.com/repos/rust-lang/rust/issues'
+ assignees = [x.strip() for x in maintainers.split('@') if x != '']
+ assignees.append(relevant_pr_user)
+ response = urllib2.urlopen(urllib2.Request(
+ gh_url,
+ json.dumps({
+ 'body': textwrap.dedent('''\
+ Hello, this is your friendly neighborhood mergebot.
+ After merging PR {}, I observed that the tool {} no longer builds.
+ A follow-up PR to the repository {} is needed to fix the fallout.
+
+ cc @{}, do you think you would have time to do the follow-up work?
+ If so, that would be great!
+
+ cc @{}, the PR reviewer, and @rust-lang/compiler -- nominating for prioritization.
+
+ ''').format(relevant_pr_number, tool, REPOS[tool], relevant_pr_user, pr_reviewer),
+ 'title': '`{}` no longer builds after {}'.format(tool, relevant_pr_number),
+ 'assignees': assignees,
+ 'labels': ['T-compiler', 'I-nominated'],
+ }),
+ {
+ 'Authorization': 'token ' + github_token,
+ 'Content-Type': 'application/json',
+ }
+ ))
+ response.read()
def update_latest(
current_commit,
relevant_pr_number,
relevant_pr_url,
+ relevant_pr_user,
+ pr_reviewer,
current_datetime
):
'''Updates `_data/latest.json` to match build result of the given commit.
for status in latest:
tool = status['tool']
changed = False
+ build_failed = False
for os, s in current_status.items():
old = status[os]
new = s.get(tool, old)
status[os] = new
if new > old:
+ # things got fixed or at least the status quo improved
changed = True
message += '🎉 {} on {}: {} → {} (cc {}, @rust-lang/infra).\n' \
.format(tool, os, old, new, MAINTAINERS.get(tool))
elif new < old:
+ # tests or builds are failing and were not failing before
changed = True
- message += '💔 {} on {}: {} → {} (cc {}, @rust-lang/infra).\n' \
- .format(tool, os, old, new, MAINTAINERS.get(tool))
+ title = '💔 {} on {}: {} → {}' \
+ .format(tool, os, old, new)
+ message += '{} (cc {}, @rust-lang/infra).\n' \
+ .format(title, MAINTAINERS.get(tool))
+ # only create issues for build failures. Other failures can be spurious
+ if new == 'build-fail':
+ build_failed = True
+
+ if build_failed:
+ try:
+ issue(
+ tool, MAINTAINERS.get(tool),
+ relevant_pr_number, relevant_pr_user, pr_reviewer,
+ )
+ except IOError as (errno, strerror):
+ # network errors will simply end up not creating an issue, but that's better
+ # than failing the entire build job
+ print "I/O error({0}): {1}".format(errno, strerror)
+ except:
+ print "Unexpected error:", sys.exc_info()[0]
+ raise
if changed:
status['commit'] = current_commit
save_message_to_path = sys.argv[3]
github_token = sys.argv[4]
- relevant_pr_match = re.search('#([0-9]+)', cur_commit_msg)
+ # assume that PR authors are also owners of the repo where the branch lives
+ relevant_pr_match = re.search(
+ 'Auto merge of #([0-9]+) - ([^:]+):[^,]+ r=([^\s]+)',
+ cur_commit_msg,
+ )
if relevant_pr_match:
number = relevant_pr_match.group(1)
+ relevant_pr_user = relevant_pr_match.group(2)
relevant_pr_number = 'rust-lang/rust#' + number
relevant_pr_url = 'https://github.com/rust-lang/rust/pull/' + number
+ pr_reviewer = relevant_pr_match.group(3)
else:
number = '-1'
+ relevant_pr_user = '<unknown user>'
relevant_pr_number = '<unknown PR>'
relevant_pr_url = '<unknown>'
+ pr_reviewer = '<unknown reviewer>'
message = update_latest(
cur_commit,
relevant_pr_number,
relevant_pr_url,
+ relevant_pr_user,
+ pr_reviewer,
cur_datetime
)
if not message: