Rollup merge of #64532 - ecstatic-morse:dataflow-cursor-get, r=tmandry
Replace `state_for_location` with `DataflowResultsCursor`
These are two different ways of getting the same data from the result of a dataflow analysis. However, `state_for_location` goes quadratic if you try to call it for every statement in the body.
diff --git a/Cargo.lock b/Cargo.lock
index 77e2ce0..326f3b1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -201,9 +201,7 @@
name = "build-manifest"
version = "0.1.0"
dependencies = [
- "reqwest",
"serde",
- "serde_json",
"toml",
]
@@ -234,9 +232,9 @@
[[package]]
name = "byteorder"
-version = "1.2.7"
+version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d"
+checksum = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
[[package]]
name = "bytes"
@@ -2067,7 +2065,7 @@
"hex",
"log",
"num-traits",
- "rand 0.6.1",
+ "rand 0.7.0",
"rustc-workspace-hack",
"rustc_version",
"shell-escape",
@@ -2182,9 +2180,9 @@
[[package]]
name = "openssl-src"
-version = "111.3.0+1.1.1c"
+version = "111.6.0+1.1.1d"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53ed5f31d294bdf5f7a4ba0a206c2754b0f60e9a63b7e3076babc5317873c797"
+checksum = "b9c2da1de8a7a3f860919c01540b03a6db16de042405a8a07a5e9d0b4b825d9c"
dependencies = [
"cc",
]
@@ -3255,7 +3253,6 @@
name = "rustc-workspace-hack"
version = "1.0.0"
dependencies = [
- "byteorder",
"crossbeam-utils 0.6.5",
"serde",
"serde_json",
diff --git a/RELEASES.md b/RELEASES.md
index f26f6e6..d634feb 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,3 +1,108 @@
+Version 1.38.0 (2019-09-26)
+==========================
+
+Language
+--------
+- [The `#[global_allocator]` attribute can now be used in submodules.][62735]
+- [The `#[deprecated]` attribute can now be used on macros.][62042]
+
+Compiler
+--------
+- [Added pipelined compilation support to `rustc`.][62766] This will
+ improve compilation times in some cases. For further information please refer
+ to the [_"Evaluating pipelined rustc compilation"_][pipeline-internals] thread.
+- [Added tier 3\* support for the `aarch64-uwp-windows-msvc`, `i686-uwp-windows-gnu`,
+ `i686-uwp-windows-msvc`, `x86_64-uwp-windows-gnu`, and
+ `x86_64-uwp-windows-msvc` targets.][60260]
+- [Added tier 3 support for the `armv7-unknown-linux-gnueabi` and
+ `armv7-unknown-linux-musleabi` targets.][63107]
+- [Added tier 3 support for the `hexagon-unknown-linux-musl` target.][62814]
+- [Added tier 3 support for the `riscv32i-unknown-none-elf` target.][62784]
+
+\* Refer to Rust's [platform support page][forge-platform-support] for more
+information on Rust's tiered platform support.
+
+Libraries
+---------
+- [`ascii::EscapeDefault` now implements `Clone` and `Display`.][63421]
+- [Derive macros for prelude traits (e.g. `Clone`, `Debug`, `Hash`) are now
+ available at the same path as the trait.][63056] (e.g. The `Clone` derive macro
+ is available at `std::clone::Clone`). This also makes all built-in macros
+ available in `std`/`core` root. e.g. `std::include_bytes!`.
+- [`str::Chars` now implements `Debug`.][63000]
+- [`slice::{concat, connect, join}` now accepts `&[T]` in addition to `&T`.][62528]
+- [`*const T` and `*mut T` now implement `marker::Unpin`.][62583]
+- [`Arc<[T]>` and `Rc<[T]>` now implement `FromIterator<T>`.][61953]
+- [Added euclidean remainder and division operations (`div_euclid`,
+ `rem_euclid`) to all numeric primitives.][61884] Additionally `checked`,
+ `overflowing`, and `wrapping` versions are available for all
+ integer primitives.
+- [`thread::AccessError` now implements `Clone`, `Copy`, `Eq`, `Error`, and
+ `PartialEq`.][61491]
+- [`iter::{StepBy, Peekable, Take}` now implement `DoubleEndedIterator`.][61457]
+
+Stabilized APIs
+---------------
+- [`<*const T>::cast`]
+- [`<*mut T>::cast`]
+- [`Duration::as_secs_f32`]
+- [`Duration::as_secs_f64`]
+- [`Duration::div_duration_f32`]
+- [`Duration::div_duration_f64`]
+- [`Duration::div_f32`]
+- [`Duration::div_f64`]
+- [`Duration::from_secs_f32`]
+- [`Duration::from_secs_f64`]
+- [`Duration::mul_f32`]
+- [`Duration::mul_f64`]
+- [`any::type_name`]
+
+Cargo
+-----
+- [Added pipelined compilation support to `cargo`.][cargo/7143]
+- [You can now pass the `--features` option multiple times to enable
+ multiple features.][cargo/7084]
+
+Misc
+----
+- [`rustc` will now warn about some incorrect uses of
+ `mem::{uninitialized, zeroed}` that are known to cause undefined behaviour.][63346]
+
+[60260]: https://github.com/rust-lang/rust/pull/60260/
+[61457]: https://github.com/rust-lang/rust/pull/61457/
+[61491]: https://github.com/rust-lang/rust/pull/61491/
+[61884]: https://github.com/rust-lang/rust/pull/61884/
+[61953]: https://github.com/rust-lang/rust/pull/61953/
+[62042]: https://github.com/rust-lang/rust/pull/62042/
+[62528]: https://github.com/rust-lang/rust/pull/62528/
+[62583]: https://github.com/rust-lang/rust/pull/62583/
+[62735]: https://github.com/rust-lang/rust/pull/62735/
+[62766]: https://github.com/rust-lang/rust/pull/62766/
+[62784]: https://github.com/rust-lang/rust/pull/62784/
+[62814]: https://github.com/rust-lang/rust/pull/62814/
+[63000]: https://github.com/rust-lang/rust/pull/63000/
+[63056]: https://github.com/rust-lang/rust/pull/63056/
+[63107]: https://github.com/rust-lang/rust/pull/63107/
+[63346]: https://github.com/rust-lang/rust/pull/63346/
+[63421]: https://github.com/rust-lang/rust/pull/63421/
+[cargo/7084]: https://github.com/rust-lang/cargo/pull/7084/
+[cargo/7143]: https://github.com/rust-lang/cargo/pull/7143/
+[`<*const T>::cast`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.cast
+[`<*mut T>::cast`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.cast
+[`Duration::as_secs_f32`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.as_secs_f32
+[`Duration::as_secs_f64`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.as_secs_f64
+[`Duration::div_duration_f32`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.div_duration_f32
+[`Duration::div_duration_f64`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.div_duration_f64
+[`Duration::div_f32`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.div_f32
+[`Duration::div_f64`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.div_f64
+[`Duration::from_secs_f32`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.from_secs_f32
+[`Duration::from_secs_f64`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.from_secs_f64
+[`Duration::mul_f32`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.mul_f32
+[`Duration::mul_f64`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.mul_f64
+[`any::type_name`]: https://doc.rust-lang.org/std/any/fn.type_name.html
+[forge-platform-support]: https://forge.rust-lang.org/platform-support.html
+[pipeline-internals]: https://internals.rust-lang.org/t/evaluating-pipelined-rustc-compilation/10199
+
Version 1.37.0 (2019-08-15)
==========================
diff --git a/src/ci/azure-pipelines/auto.yml b/src/ci/azure-pipelines/auto.yml
index 77c9cda..1656066 100644
--- a/src/ci/azure-pipelines/auto.yml
+++ b/src/ci/azure-pipelines/auto.yml
@@ -236,10 +236,16 @@
MSYS_BITS: 32
RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc
SCRIPT: make ci-subset-1
+ # FIXME(#59637)
+ NO_DEBUG_ASSERTIONS: 1
+ NO_LLVM_ASSERTIONS: 1
i686-msvc-2:
MSYS_BITS: 32
RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc
SCRIPT: make ci-subset-2
+ # FIXME(#59637)
+ NO_DEBUG_ASSERTIONS: 1
+ NO_LLVM_ASSERTIONS: 1
# MSVC aux tests
x86_64-msvc-aux:
MSYS_BITS: 64
@@ -250,6 +256,9 @@
SCRIPT: python x.py test src/tools/cargotest src/tools/cargo
RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc
VCVARS_BAT: vcvars64.bat
+ # FIXME(#59637)
+ NO_DEBUG_ASSERTIONS: 1
+ NO_LLVM_ASSERTIONS: 1
# MSVC tools tests
x86_64-msvc-tools:
MSYS_BITS: 64
diff --git a/src/ci/docker/i686-gnu-nopt/Dockerfile b/src/ci/docker/i686-gnu-nopt/Dockerfile
index 2041ba5..517b59c 100644
--- a/src/ci/docker/i686-gnu-nopt/Dockerfile
+++ b/src/ci/docker/i686-gnu-nopt/Dockerfile
@@ -19,3 +19,6 @@
ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu --disable-optimize-tests
ENV SCRIPT python2.7 ../x.py test
+
+# FIXME(#59637) takes too long on CI right now
+ENV NO_LLVM_ASSERTIONS=1 NO_DEBUG_ASSERTIONS=1
diff --git a/src/ci/docker/i686-gnu/Dockerfile b/src/ci/docker/i686-gnu/Dockerfile
index 17441dd..03db3ba 100644
--- a/src/ci/docker/i686-gnu/Dockerfile
+++ b/src/ci/docker/i686-gnu/Dockerfile
@@ -25,3 +25,6 @@
--exclude src/test/rustdoc-js \
--exclude src/tools/error_index_generator \
--exclude src/tools/linkchecker
+
+# FIXME(#59637) takes too long on CI right now
+ENV NO_LLVM_ASSERTIONS=1 NO_DEBUG_ASSERTIONS=1
diff --git a/src/doc/nomicon b/src/doc/nomicon
index 38b9a76..4374786 160000
--- a/src/doc/nomicon
+++ b/src/doc/nomicon
@@ -1 +1 @@
-Subproject commit 38b9a76bc8b59ac862663807fc51c9b757337fd6
+Subproject commit 4374786f0b4bf0606b35d5c30a9681f342e5707b
diff --git a/src/doc/reference b/src/doc/reference
index 1944efe..fa5dfb8 160000
--- a/src/doc/reference
+++ b/src/doc/reference
@@ -1 +1 @@
-Subproject commit 1944efed35989ba57fa397c0724c4921310311fc
+Subproject commit fa5dfb832ef8a7568e17dabf612f486d641ff4ac
diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs
index 402a7b2..06f2b7b 100644
--- a/src/libcore/convert.rs
+++ b/src/libcore/convert.rs
@@ -42,11 +42,11 @@
use crate::fmt;
-/// An identity function.
+/// The identity function.
///
/// Two things are important to note about this function:
///
-/// - It is not always equivalent to a closure like `|x| x` since the
+/// - It is not always equivalent to a closure like `|x| x`, since the
/// closure may coerce `x` into a different type.
///
/// - It moves the input `x` passed to the function.
@@ -56,31 +56,32 @@
///
/// # Examples
///
-/// Using `identity` to do nothing among other interesting functions:
+/// Using `identity` to do nothing in a sequence of other, interesting,
+/// functions:
///
/// ```rust
/// use std::convert::identity;
///
/// fn manipulation(x: u32) -> u32 {
-/// // Let's assume that this function does something interesting.
+/// // Let's pretend that adding one is an interesting function.
/// x + 1
/// }
///
/// let _arr = &[identity, manipulation];
/// ```
///
-/// Using `identity` to get a function that changes nothing in a conditional:
+/// Using `identity` as a "do nothing" base case in a conditional:
///
/// ```rust
/// use std::convert::identity;
///
/// # let condition = true;
-///
+/// #
/// # fn manipulation(x: u32) -> u32 { x + 1 }
-///
+/// #
/// let do_stuff = if condition { manipulation } else { identity };
///
-/// // do more interesting stuff..
+/// // Do more interesting stuff...
///
/// let _results = do_stuff(42);
/// ```
diff --git a/src/libcore/hint.rs b/src/libcore/hint.rs
index 6439fa0..ee4be6c 100644
--- a/src/libcore/hint.rs
+++ b/src/libcore/hint.rs
@@ -49,28 +49,16 @@
intrinsics::unreachable()
}
-/// Signals the processor that it is entering a busy-wait spin-loop.
+/// Emits a machine instruction hinting to the processor that it is running in busy-wait
+/// spin-loop ("spin lock").
///
-/// Upon receiving spin-loop signal the processor can optimize its behavior by, for example, saving
-/// power or switching hyper-threads.
-///
-/// This function is different than [`std::thread::yield_now`] which directly yields to the
-/// system's scheduler, whereas `spin_loop` only signals the processor that it is entering a
-/// busy-wait spin-loop without yielding control to the system's scheduler.
-///
-/// Using a busy-wait spin-loop with `spin_loop` is ideally used in situations where a
-/// contended lock is held by another thread executed on a different CPU and where the waiting
-/// times are relatively small. Because entering busy-wait spin-loop does not trigger the system's
-/// scheduler, no overhead for switching threads occurs. However, if the thread holding the
-/// contended lock is running on the same CPU, the spin-loop is likely to occupy an entire CPU slice
-/// before switching to the thread that holds the lock. If the contending lock is held by a thread
-/// on the same CPU or if the waiting times for acquiring the lock are longer, it is often better to
-/// use [`std::thread::yield_now`].
+/// For a discussion of different locking strategies and their trade-offs, see
+/// [`core::sync::atomic::spin_loop_hint`].
///
/// **Note**: On platforms that do not support receiving spin-loop hints this function does not
/// do anything at all.
///
-/// [`std::thread::yield_now`]: ../../std/thread/fn.yield_now.html
+/// [`core::sync::atomic::spin_loop_hint`]: ../sync/atomic/fn.spin_loop_hint.html
#[inline]
#[unstable(feature = "renamed_spin_loop", issue = "55002")]
pub fn spin_loop() {
diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs
index d145f22..ecff40a 100644
--- a/src/libcore/intrinsics.rs
+++ b/src/libcore/intrinsics.rs
@@ -845,21 +845,26 @@
///
/// ```
/// let store = [0, 1, 2, 3];
- /// let mut v_orig = store.iter().collect::<Vec<&i32>>();
+ /// let v_orig = store.iter().collect::<Vec<&i32>>();
+ ///
+ /// // clone the vector as we will reuse them later
+ /// let v_clone = v_orig.clone();
///
/// // Using transmute: this is Undefined Behavior, and a bad idea.
/// // However, it is no-copy.
/// let v_transmuted = unsafe {
- /// std::mem::transmute::<Vec<&i32>, Vec<Option<&i32>>>(
- /// v_orig.clone())
+ /// std::mem::transmute::<Vec<&i32>, Vec<Option<&i32>>>(v_clone)
/// };
///
+ /// let v_clone = v_orig.clone();
+ ///
/// // This is the suggested, safe way.
/// // It does copy the entire vector, though, into a new array.
- /// let v_collected = v_orig.clone()
- /// .into_iter()
- /// .map(|r| Some(r))
- /// .collect::<Vec<Option<&i32>>>();
+ /// let v_collected = v_clone.into_iter()
+ /// .map(Some)
+ /// .collect::<Vec<Option<&i32>>>();
+ ///
+ /// let v_clone = v_orig.clone();
///
/// // The no-copy, unsafe way, still using transmute, but not UB.
/// // This is equivalent to the original, but safer, and reuses the
@@ -869,11 +874,12 @@
/// // the original inner type (`&i32`) to the converted inner type
/// // (`Option<&i32>`), so read the nomicon pages linked above.
/// let v_from_raw = unsafe {
- /// Vec::from_raw_parts(v_orig.as_mut_ptr() as *mut Option<&i32>,
- /// v_orig.len(),
- /// v_orig.capacity())
+ /// // Ensure the original vector is not dropped.
+ /// let mut v_clone = std::mem::ManuallyDrop::new(v_clone);
+ /// Vec::from_raw_parts(v_clone.as_mut_ptr() as *mut Option<&i32>,
+ /// v_clone.len(),
+ /// v_clone.capacity())
/// };
- /// std::mem::forget(v_orig);
/// ```
///
/// Implementing `split_at_mut`:
diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs
index df1c00c..0cf2ebb 100644
--- a/src/libcore/num/mod.rs
+++ b/src/libcore/num/mod.rs
@@ -2092,11 +2092,14 @@
```
let bytes = ", $swap_op, stringify!($SelfT), ".to_ne_bytes();
-assert_eq!(bytes, if cfg!(target_endian = \"big\") {
+assert_eq!(
+ bytes,
+ if cfg!(target_endian = \"big\") {
", $be_bytes, "
} else {
", $le_bytes, "
- });
+ }
+);
```"),
#[stable(feature = "int_to_from_bytes", since = "1.32.0")]
#[rustc_const_unstable(feature = "const_int_conversion")]
@@ -2188,10 +2191,10 @@
```
let value = ", stringify!($SelfT), "::from_ne_bytes(if cfg!(target_endian = \"big\") {
- ", $be_bytes, "
- } else {
- ", $le_bytes, "
- });
+ ", $be_bytes, "
+} else {
+ ", $le_bytes, "
+});
assert_eq!(value, ", $swap_op, ");
```
@@ -3911,11 +3914,14 @@
```
let bytes = ", $swap_op, stringify!($SelfT), ".to_ne_bytes();
-assert_eq!(bytes, if cfg!(target_endian = \"big\") {
+assert_eq!(
+ bytes,
+ if cfg!(target_endian = \"big\") {
", $be_bytes, "
} else {
", $le_bytes, "
- });
+ }
+);
```"),
#[stable(feature = "int_to_from_bytes", since = "1.32.0")]
#[rustc_const_unstable(feature = "const_int_conversion")]
@@ -4007,10 +4013,10 @@
```
let value = ", stringify!($SelfT), "::from_ne_bytes(if cfg!(target_endian = \"big\") {
- ", $be_bytes, "
- } else {
- ", $le_bytes, "
- });
+ ", $be_bytes, "
+} else {
+ ", $le_bytes, "
+});
assert_eq!(value, ", $swap_op, ");
```
diff --git a/src/libcore/option.rs b/src/libcore/option.rs
index 79bd04b..5569d99 100644
--- a/src/libcore/option.rs
+++ b/src/libcore/option.rs
@@ -295,7 +295,7 @@
/// [`Pin`]: ../pin/struct.Pin.html
#[inline]
#[stable(feature = "pin", since = "1.33.0")]
- pub fn as_pin_ref<'a>(self: Pin<&'a Option<T>>) -> Option<Pin<&'a T>> {
+ pub fn as_pin_ref(self: Pin<&Self>) -> Option<Pin<&T>> {
unsafe {
Pin::get_ref(self).as_ref().map(|x| Pin::new_unchecked(x))
}
@@ -306,7 +306,7 @@
/// [`Pin`]: ../pin/struct.Pin.html
#[inline]
#[stable(feature = "pin", since = "1.33.0")]
- pub fn as_pin_mut<'a>(self: Pin<&'a mut Option<T>>) -> Option<Pin<&'a mut T>> {
+ pub fn as_pin_mut(self: Pin<&mut Self>) -> Option<Pin<&mut T>> {
unsafe {
Pin::get_unchecked_mut(self).as_mut().map(|x| Pin::new_unchecked(x))
}
diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs
index 1080fd3..1dc6d54 100644
--- a/src/libcore/pin.rs
+++ b/src/libcore/pin.rs
@@ -233,7 +233,7 @@
//! # type Field = i32;
//! # struct Struct { field: Field }
//! impl Struct {
-//! fn pin_get_field<'a>(self: Pin<&'a mut Self>) -> &'a mut Field {
+//! fn pin_get_field(self: Pin<&mut Self>) -> &mut Field {
//! // This is okay because `field` is never considered pinned.
//! unsafe { &mut self.get_unchecked_mut().field }
//! }
@@ -257,7 +257,7 @@
//! # type Field = i32;
//! # struct Struct { field: Field }
//! impl Struct {
-//! fn pin_get_field<'a>(self: Pin<&'a mut Self>) -> Pin<&'a mut Field> {
+//! fn pin_get_field(self: Pin<&mut Self>) -> Pin<&mut Field> {
//! // This is okay because `field` is pinned when `self` is.
//! unsafe { self.map_unchecked_mut(|s| &mut s.field) }
//! }
@@ -549,7 +549,7 @@
/// ruled out by the contract of `Pin::new_unchecked`.
#[stable(feature = "pin", since = "1.33.0")]
#[inline(always)]
- pub fn as_ref(self: &Pin<P>) -> Pin<&P::Target> {
+ pub fn as_ref(&self) -> Pin<&P::Target> {
unsafe { Pin::new_unchecked(&*self.pointer) }
}
@@ -584,9 +584,30 @@
/// the pointee cannot move after `Pin<Pointer<T>>` got created.
/// "Malicious" implementations of `Pointer::DerefMut` are likewise
/// ruled out by the contract of `Pin::new_unchecked`.
+ ///
+ /// This method is useful when doing multiple calls to functions that consume the pinned type.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use std::pin::Pin;
+ ///
+ /// # struct Type {}
+ /// impl Type {
+ /// fn method(self: Pin<&mut Self>) {
+ /// // do something
+ /// }
+ ///
+ /// fn call_method_twice(mut self: Pin<&mut Self>) {
+ /// // `method` consumes `self`, so reborrow the `Pin<&mut Self>` via `as_mut`.
+ /// self.as_mut().method();
+ /// self.as_mut().method();
+ /// }
+ /// }
+ /// ```
#[stable(feature = "pin", since = "1.33.0")]
#[inline(always)]
- pub fn as_mut(self: &mut Pin<P>) -> Pin<&mut P::Target> {
+ pub fn as_mut(&mut self) -> Pin<&mut P::Target> {
unsafe { Pin::new_unchecked(&mut *self.pointer) }
}
@@ -596,7 +617,7 @@
/// run before being overwritten, so no pinning guarantee is violated.
#[stable(feature = "pin", since = "1.33.0")]
#[inline(always)]
- pub fn set(self: &mut Pin<P>, value: P::Target)
+ pub fn set(&mut self, value: P::Target)
where
P::Target: Sized,
{
@@ -621,7 +642,7 @@
///
/// [`pin` module]: ../../std/pin/index.html#projections-and-structural-pinning
#[stable(feature = "pin", since = "1.33.0")]
- pub unsafe fn map_unchecked<U, F>(self: Pin<&'a T>, func: F) -> Pin<&'a U> where
+ pub unsafe fn map_unchecked<U, F>(self, func: F) -> Pin<&'a U> where
F: FnOnce(&T) -> &U,
{
let pointer = &*self.pointer;
@@ -648,7 +669,7 @@
/// ["pinning projections"]: ../../std/pin/index.html#projections-and-structural-pinning
#[stable(feature = "pin", since = "1.33.0")]
#[inline(always)]
- pub fn get_ref(self: Pin<&'a T>) -> &'a T {
+ pub fn get_ref(self) -> &'a T {
self.pointer
}
}
@@ -657,7 +678,7 @@
/// Converts this `Pin<&mut T>` into a `Pin<&T>` with the same lifetime.
#[stable(feature = "pin", since = "1.33.0")]
#[inline(always)]
- pub fn into_ref(self: Pin<&'a mut T>) -> Pin<&'a T> {
+ pub fn into_ref(self) -> Pin<&'a T> {
Pin { pointer: self.pointer }
}
@@ -672,7 +693,7 @@
/// with the same lifetime as the original `Pin`.
#[stable(feature = "pin", since = "1.33.0")]
#[inline(always)]
- pub fn get_mut(self: Pin<&'a mut T>) -> &'a mut T
+ pub fn get_mut(self) -> &'a mut T
where T: Unpin,
{
self.pointer
@@ -690,7 +711,7 @@
/// instead.
#[stable(feature = "pin", since = "1.33.0")]
#[inline(always)]
- pub unsafe fn get_unchecked_mut(self: Pin<&'a mut T>) -> &'a mut T {
+ pub unsafe fn get_unchecked_mut(self) -> &'a mut T {
self.pointer
}
@@ -710,7 +731,7 @@
///
/// [`pin` module]: ../../std/pin/index.html#projections-and-structural-pinning
#[stable(feature = "pin", since = "1.33.0")]
- pub unsafe fn map_unchecked_mut<U, F>(self: Pin<&'a mut T>, func: F) -> Pin<&'a mut U> where
+ pub unsafe fn map_unchecked_mut<U, F>(self, func: F) -> Pin<&'a mut U> where
F: FnOnce(&mut T) -> &mut U,
{
let pointer = Pin::get_unchecked_mut(self);
diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs
index a731115..c9ccef9 100644
--- a/src/libcore/sync/atomic.rs
+++ b/src/libcore/sync/atomic.rs
@@ -124,28 +124,31 @@
use crate::hint::spin_loop;
-/// Signals the processor that it is entering a busy-wait spin-loop.
+/// Signals the processor that it is inside a busy-wait spin-loop ("spin lock").
///
/// Upon receiving spin-loop signal the processor can optimize its behavior by, for example, saving
/// power or switching hyper-threads.
///
-/// This function is different than [`std::thread::yield_now`] which directly yields to the
-/// system's scheduler, whereas `spin_loop_hint` only signals the processor that it is entering a
-/// busy-wait spin-loop without yielding control to the system's scheduler.
+/// This function is different from [`std::thread::yield_now`] which directly yields to the
+/// system's scheduler, whereas `spin_loop_hint` does not interact with the operating system.
///
-/// Using a busy-wait spin-loop with `spin_loop_hint` is ideally used in situations where a
-/// contended lock is held by another thread executed on a different CPU and where the waiting
-/// times are relatively small. Because entering busy-wait spin-loop does not trigger the system's
-/// scheduler, no overhead for switching threads occurs. However, if the thread holding the
-/// contended lock is running on the same CPU, the spin-loop is likely to occupy an entire CPU slice
-/// before switching to the thread that holds the lock. If the contending lock is held by a thread
-/// on the same CPU or if the waiting times for acquiring the lock are longer, it is often better to
-/// use [`std::thread::yield_now`].
+/// Spin locks can be very efficient for short lock durations because they do not involve context
+/// switches or interaction with the operating system. For long lock durations they become wasteful
+/// however because they use CPU cycles for the entire lock duration, and using a
+/// [`std::sync::Mutex`] is likely the better approach. If actively spinning for a long time is
+/// required, e.g. because code polls a non-blocking API, calling [`std::thread::yield_now`]
+/// or [`std::thread::sleep`] may be the best option.
+///
+/// **Note**: Spin locks are based on the underlying assumption that another thread will release
+/// the lock 'soon'. In order for this to work, that other thread must run on a different CPU or
+/// core (at least potentially). Spin locks do not work efficiently on single CPU / core platforms.
///
/// **Note**: On platforms that do not support receiving spin-loop hints this function does not
/// do anything at all.
///
/// [`std::thread::yield_now`]: ../../../std/thread/fn.yield_now.html
+/// [`std::thread::sleep`]: ../../../std/thread/fn.sleep.html
+/// [`std::sync::Mutex`]: ../../../std/sync/struct.Mutex.html
#[inline]
#[stable(feature = "spin_loop_hint", since = "1.24.0")]
pub fn spin_loop_hint() {
diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml
index d569573..0834faf 100644
--- a/src/librustc/Cargo.toml
+++ b/src/librustc/Cargo.toml
@@ -31,7 +31,7 @@
syntax_pos = { path = "../libsyntax_pos" }
backtrace = "0.3.3"
parking_lot = "0.9"
-byteorder = { version = "1.1", features = ["i128"]}
+byteorder = { version = "1.3" }
chalk-engine = { version = "0.9.0", default-features=false }
rustc_fs_util = { path = "../librustc_fs_util" }
smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 58789a1..48f7fc4 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -2682,12 +2682,8 @@
bounds.iter().map(|bound| self.lower_param_bound(bound, itctx.reborrow())).collect()
}
- fn lower_block_with_stmts(
- &mut self,
- b: &Block,
- targeted_by_break: bool,
- mut stmts: Vec<hir::Stmt>,
- ) -> P<hir::Block> {
+ fn lower_block(&mut self, b: &Block, targeted_by_break: bool) -> P<hir::Block> {
+ let mut stmts = vec![];
let mut expr = None;
for (index, stmt) in b.stmts.iter().enumerate() {
@@ -2712,8 +2708,11 @@
})
}
- fn lower_block(&mut self, b: &Block, targeted_by_break: bool) -> P<hir::Block> {
- self.lower_block_with_stmts(b, targeted_by_break, vec![])
+ /// Lowers a block directly to an expression, presuming that it
+ /// has no attributes and is not targeted by a `break`.
+ fn lower_block_expr(&mut self, b: &Block) -> hir::Expr {
+ let block = self.lower_block(b, false);
+ self.expr_block(block, ThinVec::new())
}
fn lower_pat(&mut self, p: &Pat) -> P<hir::Pat> {
diff --git a/src/librustc/hir/lowering/expr.rs b/src/librustc/hir/lowering/expr.rs
index a46cdab..990728f 100644
--- a/src/librustc/hir/lowering/expr.rs
+++ b/src/librustc/hir/lowering/expr.rs
@@ -90,10 +90,7 @@
),
ExprKind::Async(capture_clause, closure_node_id, ref block) => {
self.make_async_expr(capture_clause, closure_node_id, None, block.span, |this| {
- this.with_new_scopes(|this| {
- let block = this.lower_block(block, false);
- this.expr_block(block, ThinVec::new())
- })
+ this.with_new_scopes(|this| this.lower_block_expr(block))
})
}
ExprKind::Await(ref expr) => self.lower_expr_await(e.span, expr),
@@ -284,8 +281,7 @@
let else_arm = self.arm(hir_vec![else_pat], P(else_expr));
// Handle then + scrutinee:
- let then_blk = self.lower_block(then, false);
- let then_expr = self.expr_block(then_blk, ThinVec::new());
+ let then_expr = self.lower_block_expr(then);
let (then_pat, scrutinee, desugar) = match cond.node {
// `<pat> => <then>`:
ExprKind::Let(ref pat, ref scrutinee) => {
@@ -335,8 +331,7 @@
};
// Handle then + scrutinee:
- let then_blk = self.lower_block(body, false);
- let then_expr = self.expr_block(then_blk, ThinVec::new());
+ let then_expr = self.lower_block_expr(body);
let (then_pat, scrutinee, desugar, source) = match cond.node {
ExprKind::Let(ref pat, ref scrutinee) => {
// to:
@@ -356,7 +351,7 @@
//
// ```
// 'label: loop {
- // match DropTemps($cond) {
+ // match drop-temps { $cond } {
// true => $body,
// _ => break,
// }
@@ -1310,7 +1305,7 @@
/// `{ let _t = $expr; _t }` but should provide better compile-time performance.
///
/// The drop order can be important in e.g. `if expr { .. }`.
- fn expr_drop_temps(
+ pub(super) fn expr_drop_temps(
&mut self,
span: Span,
expr: P<hir::Expr>,
diff --git a/src/librustc/hir/lowering/item.rs b/src/librustc/hir/lowering/item.rs
index 5f82e42..61be40a 100644
--- a/src/librustc/hir/lowering/item.rs
+++ b/src/librustc/hir/lowering/item.rs
@@ -1071,10 +1071,7 @@
}
fn lower_fn_body_block(&mut self, decl: &FnDecl, body: &Block) -> hir::BodyId {
- self.lower_fn_body(decl, |this| {
- let body = this.lower_block(body, false);
- this.expr_block(body, ThinVec::new())
- })
+ self.lower_fn_body(decl, |this| this.lower_block_expr(body))
}
pub(super) fn lower_const_body(&mut self, expr: &Expr) -> hir::BodyId {
@@ -1102,8 +1099,7 @@
// from:
//
// async fn foo(<pattern>: <ty>, <pattern>: <ty>, <pattern>: <ty>) {
- // async move {
- // }
+ // <body>
// }
//
// into:
@@ -1116,11 +1112,19 @@
// let <pattern> = __arg1;
// let __arg0 = __arg0;
// let <pattern> = __arg0;
+ // drop-temps { <body> } // see comments later in fn for details
// }
// }
//
// If `<pattern>` is a simple ident, then it is lowered to a single
// `let <pattern> = <pattern>;` statement as an optimization.
+ //
+ // Note that the body is embedded in `drop-temps`; an
+ // equivalent desugaring would be `return { <body>
+ // };`. The key point is that we wish to drop all the
+ // let-bound variables and temporaries created in the body
+ // (and its tail expression!) before we drop the
+ // parameters (c.f. rust-lang/rust#64512).
for (index, parameter) in decl.inputs.iter().enumerate() {
let parameter = this.lower_param(parameter);
let span = parameter.pat.span;
@@ -1219,8 +1223,36 @@
let async_expr = this.make_async_expr(
CaptureBy::Value, closure_id, None, body.span,
|this| {
- let body = this.lower_block_with_stmts(body, false, statements);
- this.expr_block(body, ThinVec::new())
+ // Create a block from the user's function body:
+ let user_body = this.lower_block_expr(body);
+
+ // Transform into `drop-temps { <user-body> }`, an expression:
+ let desugared_span = this.mark_span_with_reason(
+ DesugaringKind::Async,
+ user_body.span,
+ None,
+ );
+ let user_body = this.expr_drop_temps(
+ desugared_span,
+ P(user_body),
+ ThinVec::new(),
+ );
+
+ // As noted above, create the final block like
+ //
+ // ```
+ // {
+ // let $param_pattern = $raw_param;
+ // ...
+ // drop-temps { <user-body> }
+ // }
+ // ```
+ let body = this.block_all(
+ desugared_span,
+ statements.into(),
+ Some(P(user_body)),
+ );
+ this.expr_block(P(body), ThinVec::new())
});
(HirVec::from(parameters), this.expr(body.span, async_expr, ThinVec::new()))
})
diff --git a/src/librustc/infer/equate.rs b/src/librustc/infer/equate.rs
index 5dfa0d2..96d40bc 100644
--- a/src/librustc/infer/equate.rs
+++ b/src/librustc/infer/equate.rs
@@ -97,7 +97,7 @@
self.tag(),
a,
b);
- let origin = Subtype(self.fields.trace.clone());
+ let origin = Subtype(box self.fields.trace.clone());
self.fields.infcx.borrow_region_constraints()
.make_eqregion(origin, a, b);
Ok(a)
diff --git a/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs b/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs
index b4fb018..bfa8353 100644
--- a/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs
+++ b/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs
@@ -30,7 +30,7 @@
Some(RegionResolutionError::SubSupConflict(
vid,
_,
- SubregionOrigin::Subtype(TypeTrace {
+ SubregionOrigin::Subtype(box TypeTrace {
cause,
values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
}),
@@ -50,7 +50,7 @@
Some(RegionResolutionError::SubSupConflict(
vid,
_,
- SubregionOrigin::Subtype(TypeTrace {
+ SubregionOrigin::Subtype(box TypeTrace {
cause,
values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
}),
@@ -70,7 +70,7 @@
Some(RegionResolutionError::SubSupConflict(
vid,
_,
- SubregionOrigin::Subtype(TypeTrace {
+ SubregionOrigin::Subtype(box TypeTrace {
cause,
values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
}),
@@ -92,7 +92,7 @@
_,
_,
_,
- SubregionOrigin::Subtype(TypeTrace {
+ SubregionOrigin::Subtype(box TypeTrace {
cause,
values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
}),
@@ -108,7 +108,7 @@
)),
Some(RegionResolutionError::ConcreteFailure(
- SubregionOrigin::Subtype(TypeTrace {
+ SubregionOrigin::Subtype(box TypeTrace {
cause,
values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
}),
@@ -125,7 +125,7 @@
)),
Some(RegionResolutionError::ConcreteFailure(
- SubregionOrigin::Subtype(TypeTrace {
+ SubregionOrigin::Subtype(box TypeTrace {
cause,
values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
}),
@@ -142,7 +142,7 @@
)),
Some(RegionResolutionError::ConcreteFailure(
- SubregionOrigin::Subtype(TypeTrace {
+ SubregionOrigin::Subtype(box TypeTrace {
cause,
values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
}),
@@ -192,23 +192,28 @@
vid, sub_placeholder, sup_placeholder, trait_def_id, expected_substs, actual_substs
);
- let mut err = self.tcx().sess.struct_span_err(
- cause.span(self.tcx()),
- &format!(
- "implementation of `{}` is not general enough",
- self.tcx().def_path_str(trait_def_id),
- ),
+ let span = cause.span(self.tcx());
+ let msg = format!(
+ "implementation of `{}` is not general enough",
+ self.tcx().def_path_str(trait_def_id),
+ );
+ let mut err = self.tcx().sess.struct_span_err(span, &msg);
+ err.span_label(
+ self.tcx().def_span(trait_def_id),
+ format!("trait `{}` defined here", self.tcx().def_path_str(trait_def_id)),
);
- match cause.code {
- ObligationCauseCode::ItemObligation(def_id) => {
- err.note(&format!(
- "Due to a where-clause on `{}`,",
- self.tcx().def_path_str(def_id),
- ));
- }
- _ => (),
- }
+ let leading_ellipsis = if let ObligationCauseCode::ItemObligation(def_id) = cause.code {
+ err.span_label(span, "doesn't satisfy where-clause");
+ err.span_label(
+ self.tcx().def_span(def_id),
+ &format!("due to a where-clause on `{}`...", self.tcx().def_path_str(def_id)),
+ );
+ true
+ } else {
+ err.span_label(span, &msg);
+ false
+ };
let expected_trait_ref = self.infcx.resolve_vars_if_possible(&ty::TraitRef {
def_id: trait_def_id,
@@ -295,6 +300,7 @@
expected_has_vid,
actual_has_vid,
any_self_ty_has_vid,
+ leading_ellipsis,
);
err
@@ -318,6 +324,7 @@
expected_has_vid: Option<usize>,
actual_has_vid: Option<usize>,
any_self_ty_has_vid: bool,
+ leading_ellipsis: bool,
) {
// HACK(eddyb) maybe move this in a more central location.
#[derive(Copy, Clone)]
@@ -392,13 +399,15 @@
let mut note = if passive_voice {
format!(
- "`{}` would have to be implemented for the type `{}`",
+ "{}`{}` would have to be implemented for the type `{}`",
+ if leading_ellipsis { "..." } else { "" },
expected_trait_ref,
expected_trait_ref.map(|tr| tr.self_ty()),
)
} else {
format!(
- "`{}` must implement `{}`",
+ "{}`{}` must implement `{}`",
+ if leading_ellipsis { "..." } else { "" },
expected_trait_ref.map(|tr| tr.self_ty()),
expected_trait_ref,
)
@@ -407,20 +416,20 @@
match (has_sub, has_sup) {
(Some(n1), Some(n2)) => {
let _ = write!(note,
- ", for any two lifetimes `'{}` and `'{}`",
+ ", for any two lifetimes `'{}` and `'{}`...",
std::cmp::min(n1, n2),
std::cmp::max(n1, n2),
);
}
(Some(n), _) | (_, Some(n)) => {
let _ = write!(note,
- ", for any lifetime `'{}`",
+ ", for any lifetime `'{}`...",
n,
);
}
(None, None) => if let Some(n) = expected_has_vid {
let _ = write!(note,
- ", for some specific lifetime `'{}`",
+ ", for some specific lifetime `'{}`...",
n,
);
},
@@ -439,13 +448,13 @@
let mut note = if passive_voice {
format!(
- "but `{}` is actually implemented for the type `{}`",
+ "...but `{}` is actually implemented for the type `{}`",
actual_trait_ref,
actual_trait_ref.map(|tr| tr.self_ty()),
)
} else {
format!(
- "but `{}` actually implements `{}`",
+ "...but `{}` actually implements `{}`",
actual_trait_ref.map(|tr| tr.self_ty()),
actual_trait_ref,
)
diff --git a/src/librustc/infer/error_reporting/note.rs b/src/librustc/infer/error_reporting/note.rs
index caed428..115ffea 100644
--- a/src/librustc/infer/error_reporting/note.rs
+++ b/src/librustc/infer/error_reporting/note.rs
@@ -138,7 +138,7 @@
sup: Region<'tcx>)
-> DiagnosticBuilder<'tcx> {
match origin {
- infer::Subtype(trace) => {
+ infer::Subtype(box trace) => {
let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
let mut err = self.report_and_explain_type_error(trace, &terr);
self.tcx.note_and_explain_region(region_scope_tree, &mut err, "", sup, "...");
@@ -450,7 +450,7 @@
) -> DiagnosticBuilder<'tcx> {
// I can't think how to do better than this right now. -nikomatsakis
match placeholder_origin {
- infer::Subtype(trace) => {
+ infer::Subtype(box trace) => {
let terr = TypeError::RegionsPlaceholderMismatch;
self.report_and_explain_type_error(trace, &terr)
}
diff --git a/src/librustc/infer/glb.rs b/src/librustc/infer/glb.rs
index 2cef521..10e4532 100644
--- a/src/librustc/infer/glb.rs
+++ b/src/librustc/infer/glb.rs
@@ -57,7 +57,7 @@
a,
b);
- let origin = Subtype(self.fields.trace.clone());
+ let origin = Subtype(box self.fields.trace.clone());
Ok(self.fields.infcx.borrow_region_constraints().glb_regions(self.tcx(), origin, a, b))
}
diff --git a/src/librustc/infer/lub.rs b/src/librustc/infer/lub.rs
index e20372f..8b64cda 100644
--- a/src/librustc/infer/lub.rs
+++ b/src/librustc/infer/lub.rs
@@ -57,7 +57,7 @@
a,
b);
- let origin = Subtype(self.fields.trace.clone());
+ let origin = Subtype(box self.fields.trace.clone());
Ok(self.fields.infcx.borrow_region_constraints().lub_regions(self.tcx(), origin, a, b))
}
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 8638f42..a886c44 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -254,7 +254,7 @@
#[derive(Clone, Debug)]
pub enum SubregionOrigin<'tcx> {
/// Arose from a subtyping relation
- Subtype(TypeTrace<'tcx>),
+ Subtype(Box<TypeTrace<'tcx>>),
/// Stack-allocated closures cannot outlive innermost loop
/// or function so as to ensure we only require finite stack
@@ -340,6 +340,10 @@
},
}
+// `SubregionOrigin` is used a lot. Make sure it doesn't unintentionally get bigger.
+#[cfg(target_arch = "x86_64")]
+static_assert_size!(SubregionOrigin<'_>, 32);
+
/// Places that type/region parameters can appear.
#[derive(Clone, Copy, Debug)]
pub enum ParameterOrigin {
diff --git a/src/librustc/infer/sub.rs b/src/librustc/infer/sub.rs
index cd1d206..76db55e 100644
--- a/src/librustc/infer/sub.rs
+++ b/src/librustc/infer/sub.rs
@@ -130,7 +130,7 @@
// FIXME -- we have more fine-grained information available
// from the "cause" field, we could perhaps give more tailored
// error messages.
- let origin = SubregionOrigin::Subtype(self.fields.trace.clone());
+ let origin = SubregionOrigin::Subtype(box self.fields.trace.clone());
self.fields.infcx.borrow_region_constraints()
.make_subregion(origin, a, b);
diff --git a/src/librustc/mir/interpret/allocation.rs b/src/librustc/mir/interpret/allocation.rs
index 755cda7..15e6cb6 100644
--- a/src/librustc/mir/interpret/allocation.rs
+++ b/src/librustc/mir/interpret/allocation.rs
@@ -130,9 +130,9 @@
}
}
-impl Allocation<()> {
+impl Allocation<(), ()> {
/// Add Tag and Extra fields
- pub fn retag<T, E>(
+ pub fn with_tags_and_extra<T, E>(
self,
mut tagger: impl FnMut(AllocId) -> T,
extra: E,
diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs
index 09c822f..ac99ccd 100644
--- a/src/librustc/mir/interpret/error.rs
+++ b/src/librustc/mir/interpret/error.rs
@@ -213,6 +213,15 @@
eprintln!("\n\nAn error occurred in miri:\n{:?}", backtrace);
}
+impl From<ErrorHandled> for InterpErrorInfo<'tcx> {
+ fn from(err: ErrorHandled) -> Self {
+ match err {
+ ErrorHandled::Reported => err_inval!(ReferencedConstant),
+ ErrorHandled::TooGeneric => err_inval!(TooGeneric),
+ }.into()
+ }
+}
+
impl<'tcx> From<InterpError<'tcx>> for InterpErrorInfo<'tcx> {
fn from(kind: InterpError<'tcx>) -> Self {
let backtrace = match env::var("RUSTC_CTFE_BACKTRACE") {
@@ -313,6 +322,9 @@
}
}
+/// Error information for when the program we executed turned out not to actually be a valid
+/// program. This cannot happen in stand-alone Miri, but it can happen during CTFE/ConstProp
+/// where we work on generic code or execution does not have all information available.
#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
pub enum InvalidProgramInfo<'tcx> {
/// Resolution can fail if we are in a too generic context.
@@ -342,6 +354,7 @@
}
}
+/// Error information for when the program caused Undefined Behavior.
#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
pub enum UndefinedBehaviorInfo {
/// Free-form case. Only for errors that are never caught!
@@ -364,12 +377,19 @@
}
}
+/// Error information for when the program did something that might (or might not) be correct
+/// to do according to the Rust spec, but due to limitations in the interpreter, the
+/// operation could not be carried out. These limitations can differ between CTFE and the
+/// Miri engine, e.g., CTFE does not support casting pointers to "real" integers.
+///
+/// Currently, we also use this as fall-back error kind for errors that have not been
+/// categorized yet.
#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
pub enum UnsupportedOpInfo<'tcx> {
/// Free-form case. Only for errors that are never caught!
Unsupported(String),
- // -- Everything below is not classified yet --
+ // -- Everything below is not categorized yet --
FunctionAbiMismatch(Abi, Abi),
FunctionArgMismatch(Ty<'tcx>, Ty<'tcx>),
FunctionRetMismatch(Ty<'tcx>, Ty<'tcx>),
@@ -536,6 +556,8 @@
}
}
+/// Error information for when the program exhausted the resources granted to it
+/// by the interpreter.
#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
pub enum ResourceExhaustionInfo {
/// The stack grew too big.
diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs
index 4ebc2e7..c726094 100644
--- a/src/librustc/query/mod.rs
+++ b/src/librustc/query/mod.rs
@@ -462,15 +462,6 @@
no_force
desc { "extract field of const" }
}
-
- /// Produces an absolute path representation of the given type. See also the documentation
- /// on `std::any::type_name`.
- query type_name(key: Ty<'tcx>) -> &'tcx ty::Const<'tcx> {
- eval_always
- no_force
- desc { "get absolute path of type" }
- }
-
}
TypeChecking {
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 17eb4a8..5ca819e 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1938,9 +1938,15 @@
pub vis: Visibility,
}
-/// The definition of an abstract data type -- a struct or enum.
+/// The definition of a user-defined type, e.g., a `struct`, `enum`, or `union`.
///
/// These are all interned (by `intern_adt_def`) into the `adt_defs` table.
+///
+/// The initialism *"Adt"* stands for an [*algebraic data type (ADT)*][adt].
+/// This is slightly wrong because `union`s are not ADTs.
+/// Moreover, Rust only allows recursive data types through indirection.
+///
+/// [adt]: https://en.wikipedia.org/wiki/Algebraic_data_type
pub struct AdtDef {
/// `DefId` of the struct, enum or union item.
pub did: DefId,
diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs
index 5fbfe91..3f3c5ac1 100644
--- a/src/librustc_codegen_llvm/intrinsic.rs
+++ b/src/librustc_codegen_llvm/intrinsic.rs
@@ -15,6 +15,7 @@
use rustc_codegen_ssa::base::{to_immediate, wants_msvc_seh, compare_simd_types};
use rustc::ty::{self, Ty};
use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, Primitive};
+use rustc::mir::interpret::GlobalId;
use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
use rustc::hir;
use syntax::ast::{self, FloatTy};
@@ -81,13 +82,14 @@
impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
fn codegen_intrinsic_call(
&mut self,
- callee_ty: Ty<'tcx>,
+ instance: ty::Instance<'tcx>,
fn_ty: &FnType<'tcx, Ty<'tcx>>,
args: &[OperandRef<'tcx, &'ll Value>],
llresult: &'ll Value,
span: Span,
) {
let tcx = self.tcx;
+ let callee_ty = instance.ty(tcx);
let (def_id, substs) = match callee_ty.sty {
ty::FnDef(def_id, substs) => (def_id, substs),
@@ -133,10 +135,6 @@
let llfn = self.get_intrinsic(&("llvm.debugtrap"));
self.call(llfn, &[], None)
}
- "size_of" => {
- let tp_ty = substs.type_at(0);
- self.const_usize(self.size_of(tp_ty).bytes())
- }
"va_start" => {
self.va_start(args[0].immediate())
}
@@ -188,10 +186,6 @@
self.const_usize(self.size_of(tp_ty).bytes())
}
}
- "min_align_of" => {
- let tp_ty = substs.type_at(0);
- self.const_usize(self.align_of(tp_ty).bytes())
- }
"min_align_of_val" => {
let tp_ty = substs.type_at(0);
if let OperandValue::Pair(_, meta) = args[0].val {
@@ -201,18 +195,19 @@
self.const_usize(self.align_of(tp_ty).bytes())
}
}
- "pref_align_of" => {
- let tp_ty = substs.type_at(0);
- self.const_usize(self.layout_of(tp_ty).align.pref.bytes())
- }
+ "size_of" |
+ "pref_align_of" |
+ "min_align_of" |
+ "needs_drop" |
+ "type_id" |
"type_name" => {
- let tp_ty = substs.type_at(0);
- let ty_name = self.tcx.type_name(tp_ty);
+ let gid = GlobalId {
+ instance,
+ promoted: None,
+ };
+ let ty_name = self.tcx.const_eval(ty::ParamEnv::reveal_all().and(gid)).unwrap();
OperandRef::from_const(self, ty_name).immediate_or_packed_pair(self)
}
- "type_id" => {
- self.const_u64(self.tcx.type_id_hash(substs.type_at(0)))
- }
"init" => {
let ty = substs.type_at(0);
if !self.layout_of(ty).is_zst() {
@@ -235,11 +230,6 @@
"uninit" | "forget" => {
return;
}
- "needs_drop" => {
- let tp_ty = substs.type_at(0);
-
- self.const_bool(self.type_needs_drop(tp_ty))
- }
"offset" => {
let ptr = args[0].immediate();
let offset = args[1].immediate();
diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs
index 8829a33..1bb0ea5 100644
--- a/src/librustc_codegen_ssa/mir/block.rs
+++ b/src/librustc_codegen_ssa/mir/block.rs
@@ -667,8 +667,7 @@
}).collect();
- let callee_ty = instance.as_ref().unwrap().ty(bx.tcx());
- bx.codegen_intrinsic_call(callee_ty, &fn_ty, &args, dest,
+ bx.codegen_intrinsic_call(*instance.as_ref().unwrap(), &fn_ty, &args, dest,
terminator.source_info.span);
if let ReturnDest::IndirectOperand(dst, _) = ret_dest {
diff --git a/src/librustc_codegen_ssa/traits/intrinsic.rs b/src/librustc_codegen_ssa/traits/intrinsic.rs
index ede30a0..7c79cd6 100644
--- a/src/librustc_codegen_ssa/traits/intrinsic.rs
+++ b/src/librustc_codegen_ssa/traits/intrinsic.rs
@@ -1,6 +1,6 @@
use super::BackendTypes;
use crate::mir::operand::OperandRef;
-use rustc::ty::Ty;
+use rustc::ty::{self, Ty};
use rustc_target::abi::call::FnType;
use syntax_pos::Span;
@@ -10,7 +10,7 @@
/// add them to librustc_codegen_llvm/context.rs
fn codegen_intrinsic_call(
&mut self,
- callee_ty: Ty<'tcx>,
+ instance: ty::Instance<'tcx>,
fn_ty: &FnType<'tcx, Ty<'tcx>>,
args: &[OperandRef<'tcx, Self::Value>],
llresult: Self::Value,
diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs
index 6f40d05..6e80b48 100644
--- a/src/librustc_data_structures/indexed_vec.rs
+++ b/src/librustc_data_structures/indexed_vec.rs
@@ -149,7 +149,7 @@
#[inline]
$v const unsafe fn from_u32_unchecked(value: u32) -> Self {
- unsafe { $type { private: value } }
+ $type { private: value }
}
/// Extracts the value of this index as an integer.
diff --git a/src/librustc_data_structures/obligation_forest/graphviz.rs b/src/librustc_data_structures/obligation_forest/graphviz.rs
index a0363e1..b2120b1 100644
--- a/src/librustc_data_structures/obligation_forest/graphviz.rs
+++ b/src/librustc_data_structures/obligation_forest/graphviz.rs
@@ -74,9 +74,9 @@
.flat_map(|i| {
let node = &self.nodes[i];
- node.parent.iter().map(|p| p.get())
- .chain(node.dependents.iter().map(|p| p.get()))
- .map(move |p| (p, i))
+ node.parent.iter()
+ .chain(node.dependents.iter())
+ .map(move |p| (p.index(), i))
})
.collect()
}
diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs
index 6c52e62..189506b 100644
--- a/src/librustc_data_structures/obligation_forest/mod.rs
+++ b/src/librustc_data_structures/obligation_forest/mod.rs
@@ -9,7 +9,7 @@
//! `ObligationForest` supports two main public operations (there are a
//! few others not discussed here):
//!
-//! 1. Add a new root obligations (`push_tree`).
+//! 1. Add a new root obligations (`register_obligation`).
//! 2. Process the pending obligations (`process_obligations`).
//!
//! When a new obligation `N` is added, it becomes the root of an
@@ -20,13 +20,13 @@
//! with every pending obligation (so that will include `N`, the first
//! time). The callback also receives a (mutable) reference to the
//! per-tree state `T`. The callback should process the obligation `O`
-//! that it is given and return one of three results:
+//! that it is given and return a `ProcessResult`:
//!
-//! - `Ok(None)` -> ambiguous result. Obligation was neither a success
+//! - `Unchanged` -> ambiguous result. Obligation was neither a success
//! nor a failure. It is assumed that further attempts to process the
//! obligation will yield the same result unless something in the
//! surrounding environment changes.
-//! - `Ok(Some(C))` - the obligation was *shallowly successful*. The
+//! - `Changed(C)` - the obligation was *shallowly successful*. The
//! vector `C` is a list of subobligations. The meaning of this is that
//! `O` was successful on the assumption that all the obligations in `C`
//! are also successful. Therefore, `O` is only considered a "true"
@@ -34,7 +34,7 @@
//! state and the obligations in `C` become the new pending
//! obligations. They will be processed the next time you call
//! `process_obligations`.
-//! - `Err(E)` -> obligation failed with error `E`. We will collect this
+//! - `Error(E)` -> obligation failed with error `E`. We will collect this
//! error and return it from `process_obligations`, along with the
//! "backtrace" of obligations (that is, the list of obligations up to
//! and including the root of the failed obligation). No further
@@ -47,55 +47,50 @@
//! - `completed`: a list of obligations where processing was fully
//! completed without error (meaning that all transitive subobligations
//! have also been completed). So, for example, if the callback from
-//! `process_obligations` returns `Ok(Some(C))` for some obligation `O`,
+//! `process_obligations` returns `Changed(C)` for some obligation `O`,
//! then `O` will be considered completed right away if `C` is the
//! empty vector. Otherwise it will only be considered completed once
//! all the obligations in `C` have been found completed.
//! - `errors`: a list of errors that occurred and associated backtraces
//! at the time of error, which can be used to give context to the user.
//! - `stalled`: if true, then none of the existing obligations were
-//! *shallowly successful* (that is, no callback returned `Ok(Some(_))`).
+//! *shallowly successful* (that is, no callback returned `Changed(_)`).
//! This implies that all obligations were either errors or returned an
//! ambiguous result, which means that any further calls to
//! `process_obligations` would simply yield back further ambiguous
//! results. This is used by the `FulfillmentContext` to decide when it
//! has reached a steady state.
//!
-//! #### Snapshots
-//!
-//! The `ObligationForest` supports a limited form of snapshots; see
-//! `start_snapshot`, `commit_snapshot`, and `rollback_snapshot`. In
-//! particular, you can use a snapshot to roll back new root
-//! obligations. However, it is an error to attempt to
-//! `process_obligations` during a snapshot.
-//!
//! ### Implementation details
//!
//! For the most part, comments specific to the implementation are in the
//! code. This file only contains a very high-level overview. Basically,
//! the forest is stored in a vector. Each element of the vector is a node
-//! in some tree. Each node in the vector has the index of an (optional)
-//! parent and (for convenience) its root (which may be itself). It also
-//! has a current state, described by `NodeState`. After each
-//! processing step, we compress the vector to remove completed and error
-//! nodes, which aren't needed anymore.
+//! in some tree. Each node in the vector has the index of its dependents,
+//! including the first dependent which is known as the parent. It also
+//! has a current state, described by `NodeState`. After each processing
+//! step, we compress the vector to remove completed and error nodes, which
+//! aren't needed anymore.
use crate::fx::{FxHashMap, FxHashSet};
+use crate::indexed_vec::Idx;
+use crate::newtype_index;
-use std::cell::Cell;
+use std::cell::{Cell, RefCell};
use std::collections::hash_map::Entry;
use std::fmt::Debug;
use std::hash;
use std::marker::PhantomData;
-mod node_index;
-use self::node_index::NodeIndex;
-
mod graphviz;
#[cfg(test)]
mod tests;
+newtype_index! {
+ pub struct NodeIndex { .. }
+}
+
pub trait ForestObligation : Clone + Debug {
type Predicate : Clone + hash::Hash + Eq + Debug;
@@ -148,18 +143,22 @@
/// At the end of processing, those nodes will be removed by a
/// call to `compress`.
///
- /// At all times we maintain the invariant that every node appears
- /// at a higher index than its parent. This is needed by the
- /// backtrace iterator (which uses `split_at`).
+ /// Ideally, this would be an `IndexVec<NodeIndex, Node<O>>`. But that is
+ /// slower, because this vector is accessed so often that the
+ /// `u32`-to-`usize` conversions required for accesses are significant.
nodes: Vec<Node<O>>,
/// A cache of predicates that have been successfully completed.
done_cache: FxHashSet<O::Predicate>,
- /// An cache of the nodes in `nodes`, indexed by predicate.
+ /// A cache of the nodes in `nodes`, indexed by predicate. Unfortunately,
+ /// its contents are not guaranteed to match those of `nodes`. See the
+ /// comments in `process_obligation` for details.
waiting_cache: FxHashMap<O::Predicate, NodeIndex>,
- scratch: Option<Vec<usize>>,
+ /// A scratch vector reused in various operations, to avoid allocating new
+ /// vectors.
+ scratch: RefCell<Vec<usize>>,
obligation_tree_id_generator: ObligationTreeIdGenerator,
@@ -178,19 +177,41 @@
obligation: O,
state: Cell<NodeState>,
- /// The parent of a node - the original obligation of
- /// which it is a subobligation. Except for error reporting,
- /// it is just like any member of `dependents`.
+ /// The parent of a node - the original obligation of which it is a
+ /// subobligation. Except for error reporting, it is just like any member
+ /// of `dependents`.
+ ///
+ /// Unlike `ObligationForest::nodes`, this uses `NodeIndex` rather than
+ /// `usize` for the index, because keeping the size down is more important
+ /// than the cost of converting to a `usize` for indexing.
parent: Option<NodeIndex>,
- /// Obligations that depend on this obligation for their
- /// completion. They must all be in a non-pending state.
+ /// Obligations that depend on this obligation for their completion. They
+ /// must all be in a non-pending state.
+ ///
+ /// This uses `NodeIndex` for the same reason as `parent`.
dependents: Vec<NodeIndex>,
/// Identifier of the obligation tree to which this node belongs.
obligation_tree_id: ObligationTreeId,
}
+impl<O> Node<O> {
+ fn new(
+ parent: Option<NodeIndex>,
+ obligation: O,
+ obligation_tree_id: ObligationTreeId
+ ) -> Node<O> {
+ Node {
+ obligation,
+ state: Cell::new(NodeState::Pending),
+ parent,
+ dependents: vec![],
+ obligation_tree_id,
+ }
+ }
+}
+
/// The state of one node in some tree within the forest. This
/// represents the current state of processing for the obligation (of
/// type `O`) associated with this node.
@@ -262,7 +283,7 @@
nodes: vec![],
done_cache: Default::default(),
waiting_cache: Default::default(),
- scratch: Some(vec![]),
+ scratch: RefCell::new(vec![]),
obligation_tree_id_generator: (0..).map(ObligationTreeId),
error_cache: Default::default(),
}
@@ -275,14 +296,12 @@
}
/// Registers an obligation.
- ///
- /// This CAN be done in a snapshot
pub fn register_obligation(&mut self, obligation: O) {
// Ignore errors here - there is no guarantee of success.
let _ = self.register_obligation_at(obligation, None);
}
- // returns Err(()) if we already know this obligation failed.
+ // Returns Err(()) if we already know this obligation failed.
fn register_obligation_at(&mut self, obligation: O, parent: Option<NodeIndex>)
-> Result<(), ()>
{
@@ -294,15 +313,16 @@
Entry::Occupied(o) => {
debug!("register_obligation_at({:?}, {:?}) - duplicate of {:?}!",
obligation, parent, o.get());
- let node = &mut self.nodes[o.get().get()];
- if let Some(parent) = parent {
+ let node = &mut self.nodes[o.get().index()];
+ if let Some(parent_index) = parent {
// If the node is already in `waiting_cache`, it's already
// been marked with a parent. (It's possible that parent
// has been cleared by `apply_rewrites`, though.) So just
// dump `parent` into `node.dependents`... unless it's
// already in `node.dependents` or `node.parent`.
- if !node.dependents.contains(&parent) && Some(parent) != node.parent {
- node.dependents.push(parent);
+ if !node.dependents.contains(&parent_index) &&
+ Some(parent_index) != node.parent {
+ node.dependents.push(parent_index);
}
}
if let NodeState::Error = node.state.get() {
@@ -316,9 +336,8 @@
obligation, parent, self.nodes.len());
let obligation_tree_id = match parent {
- Some(p) => {
- let parent_node = &self.nodes[p.get()];
- parent_node.obligation_tree_id
+ Some(parent_index) => {
+ self.nodes[parent_index.index()].obligation_tree_id
}
None => self.obligation_tree_id_generator.next().unwrap()
};
@@ -342,13 +361,11 @@
}
/// Converts all remaining obligations to the given error.
- ///
- /// This cannot be done during a snapshot.
pub fn to_errors<E: Clone>(&mut self, error: E) -> Vec<Error<O, E>> {
let mut errors = vec![];
- for index in 0..self.nodes.len() {
- if let NodeState::Pending = self.nodes[index].state.get() {
- let backtrace = self.error_at(index);
+ for (i, node) in self.nodes.iter().enumerate() {
+ if let NodeState::Pending = node.state.get() {
+ let backtrace = self.error_at(i);
errors.push(Error {
error: error.clone(),
backtrace,
@@ -373,7 +390,6 @@
fn insert_into_error_cache(&mut self, node_index: usize) {
let node = &self.nodes[node_index];
-
self.error_cache
.entry(node.obligation_tree_id)
.or_default()
@@ -393,16 +409,22 @@
let mut errors = vec![];
let mut stalled = true;
- for index in 0..self.nodes.len() {
- debug!("process_obligations: node {} == {:?}", index, self.nodes[index]);
+ for i in 0..self.nodes.len() {
+ let node = &mut self.nodes[i];
- let result = match self.nodes[index] {
- Node { ref state, ref mut obligation, .. } if state.get() == NodeState::Pending =>
- processor.process_obligation(obligation),
+ debug!("process_obligations: node {} == {:?}", i, node);
+
+ // `processor.process_obligation` can modify the predicate within
+ // `node.obligation`, and that predicate is the key used for
+ // `self.waiting_cache`. This means that `self.waiting_cache` can
+ // get out of sync with `nodes`. It's not very common, but it does
+ // happen, and code in `compress` has to allow for it.
+ let result = match node.state.get() {
+ NodeState::Pending => processor.process_obligation(&mut node.obligation),
_ => continue
};
- debug!("process_obligations: node {} got result {:?}", index, result);
+ debug!("process_obligations: node {} got result {:?}", i, result);
match result {
ProcessResult::Unchanged => {
@@ -411,23 +433,23 @@
ProcessResult::Changed(children) => {
// We are not (yet) stalled.
stalled = false;
- self.nodes[index].state.set(NodeState::Success);
+ node.state.set(NodeState::Success);
for child in children {
let st = self.register_obligation_at(
child,
- Some(NodeIndex::new(index))
+ Some(NodeIndex::new(i))
);
if let Err(()) = st {
- // error already reported - propagate it
+ // Error already reported - propagate it
// to our node.
- self.error_at(index);
+ self.error_at(i);
}
}
}
ProcessResult::Error(err) => {
stalled = false;
- let backtrace = self.error_at(index);
+ let backtrace = self.error_at(i);
errors.push(Error {
error: err,
backtrace,
@@ -448,8 +470,6 @@
self.mark_as_waiting();
self.process_cycles(processor);
-
- // Now we have to compress the result
let completed = self.compress(do_completed);
debug!("process_obligations: complete");
@@ -465,97 +485,92 @@
/// report all cycles between them. This should be called
/// after `mark_as_waiting` marks all nodes with pending
/// subobligations as NodeState::Waiting.
- fn process_cycles<P>(&mut self, processor: &mut P)
+ fn process_cycles<P>(&self, processor: &mut P)
where P: ObligationProcessor<Obligation=O>
{
- let mut stack = self.scratch.take().unwrap();
+ let mut stack = self.scratch.replace(vec![]);
debug_assert!(stack.is_empty());
debug!("process_cycles()");
- for index in 0..self.nodes.len() {
+ for (i, node) in self.nodes.iter().enumerate() {
// For rustc-benchmarks/inflate-0.1.0 this state test is extremely
// hot and the state is almost always `Pending` or `Waiting`. It's
// a win to handle the no-op cases immediately to avoid the cost of
// the function call.
- let state = self.nodes[index].state.get();
- match state {
+ match node.state.get() {
NodeState::Waiting | NodeState::Pending | NodeState::Done | NodeState::Error => {},
- _ => self.find_cycles_from_node(&mut stack, processor, index),
+ _ => self.find_cycles_from_node(&mut stack, processor, i),
}
}
debug!("process_cycles: complete");
debug_assert!(stack.is_empty());
- self.scratch = Some(stack);
+ self.scratch.replace(stack);
}
- fn find_cycles_from_node<P>(&self, stack: &mut Vec<usize>,
- processor: &mut P, index: usize)
+ fn find_cycles_from_node<P>(&self, stack: &mut Vec<usize>, processor: &mut P, i: usize)
where P: ObligationProcessor<Obligation=O>
{
- let node = &self.nodes[index];
- let state = node.state.get();
- match state {
+ let node = &self.nodes[i];
+ match node.state.get() {
NodeState::OnDfsStack => {
- let index =
- stack.iter().rposition(|n| *n == index).unwrap();
- processor.process_backedge(stack[index..].iter().map(GetObligation(&self.nodes)),
+ let i = stack.iter().rposition(|n| *n == i).unwrap();
+ processor.process_backedge(stack[i..].iter().map(GetObligation(&self.nodes)),
PhantomData);
}
NodeState::Success => {
node.state.set(NodeState::OnDfsStack);
- stack.push(index);
- for dependent in node.parent.iter().chain(node.dependents.iter()) {
- self.find_cycles_from_node(stack, processor, dependent.get());
+ stack.push(i);
+ for index in node.parent.iter().chain(node.dependents.iter()) {
+ self.find_cycles_from_node(stack, processor, index.index());
}
stack.pop();
node.state.set(NodeState::Done);
},
NodeState::Waiting | NodeState::Pending => {
- // this node is still reachable from some pending node. We
+ // This node is still reachable from some pending node. We
// will get to it when they are all processed.
}
NodeState::Done | NodeState::Error => {
- // already processed that node
+ // Already processed that node.
}
};
}
/// Returns a vector of obligations for `p` and all of its
/// ancestors, putting them into the error state in the process.
- fn error_at(&mut self, p: usize) -> Vec<O> {
- let mut error_stack = self.scratch.take().unwrap();
+ fn error_at(&self, mut i: usize) -> Vec<O> {
+ let mut error_stack = self.scratch.replace(vec![]);
let mut trace = vec![];
- let mut n = p;
loop {
- self.nodes[n].state.set(NodeState::Error);
- trace.push(self.nodes[n].obligation.clone());
- error_stack.extend(self.nodes[n].dependents.iter().map(|x| x.get()));
+ let node = &self.nodes[i];
+ node.state.set(NodeState::Error);
+ trace.push(node.obligation.clone());
+ error_stack.extend(node.dependents.iter().map(|index| index.index()));
- // loop to the parent
- match self.nodes[n].parent {
- Some(q) => n = q.get(),
+ // Loop to the parent.
+ match node.parent {
+ Some(parent_index) => i = parent_index.index(),
None => break
}
}
while let Some(i) = error_stack.pop() {
- match self.nodes[i].state.get() {
+ let node = &self.nodes[i];
+ match node.state.get() {
NodeState::Error => continue,
- _ => self.nodes[i].state.set(NodeState::Error),
+ _ => node.state.set(NodeState::Error),
}
- let node = &self.nodes[i];
-
error_stack.extend(
- node.parent.iter().chain(node.dependents.iter()).map(|x| x.get())
+ node.parent.iter().chain(node.dependents.iter()).map(|index| index.index())
);
}
- self.scratch = Some(error_stack);
+ self.scratch.replace(error_stack);
trace
}
@@ -563,7 +578,7 @@
#[inline(always)]
fn inlined_mark_neighbors_as_waiting_from(&self, node: &Node<O>) {
for dependent in node.parent.iter().chain(node.dependents.iter()) {
- self.mark_as_waiting_from(&self.nodes[dependent.get()]);
+ self.mark_as_waiting_from(&self.nodes[dependent.index()]);
}
}
@@ -609,7 +624,7 @@
#[inline(never)]
fn compress(&mut self, do_completed: DoCompleted) -> Option<Vec<O>> {
let nodes_len = self.nodes.len();
- let mut node_rewrites: Vec<_> = self.scratch.take().unwrap();
+ let mut node_rewrites: Vec<_> = self.scratch.replace(vec![]);
node_rewrites.extend(0..nodes_len);
let mut dead_nodes = 0;
@@ -620,7 +635,8 @@
// self.nodes[i - dead_nodes..i] are all dead
// self.nodes[i..] are unchanged
for i in 0..self.nodes.len() {
- match self.nodes[i].state.get() {
+ let node = &self.nodes[i];
+ match node.state.get() {
NodeState::Pending | NodeState::Waiting => {
if dead_nodes > 0 {
self.nodes.swap(i, i - dead_nodes);
@@ -628,13 +644,16 @@
}
}
NodeState::Done => {
- // Avoid cloning the key (predicate) in case it exists in the waiting cache
+ // This lookup can fail because the contents of
+ // `self.waiting_cache` is not guaranteed to match those of
+ // `self.nodes`. See the comment in `process_obligation`
+ // for more details.
if let Some((predicate, _)) = self.waiting_cache
- .remove_entry(self.nodes[i].obligation.as_predicate())
+ .remove_entry(node.obligation.as_predicate())
{
self.done_cache.insert(predicate);
} else {
- self.done_cache.insert(self.nodes[i].obligation.as_predicate().clone());
+ self.done_cache.insert(node.obligation.as_predicate().clone());
}
node_rewrites[i] = nodes_len;
dead_nodes += 1;
@@ -643,7 +662,7 @@
// We *intentionally* remove the node from the cache at this point. Otherwise
// tests must come up with a different type on every type error they
// check against.
- self.waiting_cache.remove(self.nodes[i].obligation.as_predicate());
+ self.waiting_cache.remove(node.obligation.as_predicate());
node_rewrites[i] = nodes_len;
dead_nodes += 1;
self.insert_into_error_cache(i);
@@ -655,12 +674,11 @@
// No compression needed.
if dead_nodes == 0 {
node_rewrites.truncate(0);
- self.scratch = Some(node_rewrites);
+ self.scratch.replace(node_rewrites);
return if do_completed == DoCompleted::Yes { Some(vec![]) } else { None };
}
- // Pop off all the nodes we killed and extract the success
- // stories.
+ // Pop off all the nodes we killed and extract the success stories.
let successful = if do_completed == DoCompleted::Yes {
Some((0..dead_nodes)
.map(|_| self.nodes.pop().unwrap())
@@ -679,7 +697,7 @@
self.apply_rewrites(&node_rewrites);
node_rewrites.truncate(0);
- self.scratch = Some(node_rewrites);
+ self.scratch.replace(node_rewrites);
successful
}
@@ -689,58 +707,41 @@
for node in &mut self.nodes {
if let Some(index) = node.parent {
- let new_index = node_rewrites[index.get()];
- if new_index >= nodes_len {
- // parent dead due to error
+ let new_i = node_rewrites[index.index()];
+ if new_i >= nodes_len {
node.parent = None;
} else {
- node.parent = Some(NodeIndex::new(new_index));
+ node.parent = Some(NodeIndex::new(new_i));
}
}
let mut i = 0;
while i < node.dependents.len() {
- let new_index = node_rewrites[node.dependents[i].get()];
- if new_index >= nodes_len {
+ let new_i = node_rewrites[node.dependents[i].index()];
+ if new_i >= nodes_len {
node.dependents.swap_remove(i);
} else {
- node.dependents[i] = NodeIndex::new(new_index);
+ node.dependents[i] = NodeIndex::new(new_i);
i += 1;
}
}
}
- let mut kill_list = vec![];
- for (predicate, index) in &mut self.waiting_cache {
- let new_index = node_rewrites[index.get()];
- if new_index >= nodes_len {
- kill_list.push(predicate.clone());
+ // This updating of `self.waiting_cache` is necessary because the
+ // removal of nodes within `compress` can fail. See above.
+ self.waiting_cache.retain(|_predicate, index| {
+ let new_i = node_rewrites[index.index()];
+ if new_i >= nodes_len {
+ false
} else {
- *index = NodeIndex::new(new_index);
+ *index = NodeIndex::new(new_i);
+ true
}
- }
-
- for predicate in kill_list { self.waiting_cache.remove(&predicate); }
+ });
}
}
-impl<O> Node<O> {
- fn new(
- parent: Option<NodeIndex>,
- obligation: O,
- obligation_tree_id: ObligationTreeId
- ) -> Node<O> {
- Node {
- obligation,
- state: Cell::new(NodeState::Pending),
- parent,
- dependents: vec![],
- obligation_tree_id,
- }
- }
-}
-
-// I need a Clone closure
+// I need a Clone closure.
#[derive(Clone)]
struct GetObligation<'a, O>(&'a [Node<O>]);
diff --git a/src/librustc_data_structures/obligation_forest/node_index.rs b/src/librustc_data_structures/obligation_forest/node_index.rs
deleted file mode 100644
index 69ea473..0000000
--- a/src/librustc_data_structures/obligation_forest/node_index.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-use std::num::NonZeroU32;
-use std::u32;
-
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub struct NodeIndex {
- index: NonZeroU32,
-}
-
-impl NodeIndex {
- #[inline]
- pub fn new(value: usize) -> NodeIndex {
- assert!(value < (u32::MAX as usize));
- NodeIndex { index: NonZeroU32::new((value as u32) + 1).unwrap() }
- }
-
- #[inline]
- pub fn get(self) -> usize {
- (self.index.get() - 1) as usize
- }
-}
diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs
index c4d3ad9..fa9504e 100644
--- a/src/librustc_driver/pretty.rs
+++ b/src/librustc_driver/pretty.rs
@@ -326,6 +326,7 @@
}
fn post(&self, s: &mut pprust::State<'_>, node: pprust::AnnNode<'_>) {
match node {
+ pprust::AnnNode::Crate(_) |
pprust::AnnNode::Ident(_) |
pprust::AnnNode::Name(_) => {},
@@ -431,14 +432,18 @@
match node {
pprust::AnnNode::Ident(&ast::Ident { name, span }) => {
s.s.space();
- // FIXME #16420: this doesn't display the connections
- // between syntax contexts
s.synth_comment(format!("{}{:?}", name.as_u32(), span.ctxt()))
}
pprust::AnnNode::Name(&name) => {
s.s.space();
s.synth_comment(name.as_u32().to_string())
}
+ pprust::AnnNode::Crate(_) => {
+ s.s.hardbreak();
+ let verbose = self.sess.verbose();
+ s.synth_comment(syntax_pos::hygiene::debug_hygiene_data(verbose));
+ s.s.hardbreak_if_not_bol();
+ }
_ => {}
}
}
diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs
index 6660836..d238de2 100644
--- a/src/librustc_errors/emitter.rs
+++ b/src/librustc_errors/emitter.rs
@@ -1144,15 +1144,18 @@
buffer.prepend(0, " ", Style::NoStyle);
}
draw_note_separator(&mut buffer, 0, max_line_num_len + 1);
- let level_str = level.to_string();
- if !level_str.is_empty() {
- buffer.append(0, &level_str, Style::MainHeaderMsg);
- buffer.append(0, ": ", Style::NoStyle);
+ if *level != Level::FailureNote {
+ let level_str = level.to_string();
+ if !level_str.is_empty() {
+ buffer.append(0, &level_str, Style::MainHeaderMsg);
+ buffer.append(0, ": ", Style::NoStyle);
+ }
}
self.msg_to_buffer(&mut buffer, msg, max_line_num_len, "note", None);
} else {
let level_str = level.to_string();
- if !level_str.is_empty() {
+ // The failure note level itself does not provide any useful diagnostic information
+ if *level != Level::FailureNote && !level_str.is_empty() {
buffer.append(0, &level_str, Style::Level(level.clone()));
}
// only render error codes, not lint codes
@@ -1161,7 +1164,7 @@
buffer.append(0, &code, Style::Level(level.clone()));
buffer.append(0, "]", Style::Level(level.clone()));
}
- if !level_str.is_empty() {
+ if *level != Level::FailureNote && !level_str.is_empty() {
buffer.append(0, ": ", header_style);
}
for &(ref text, _) in msg.iter() {
diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs
index c1fba41..8b543be 100644
--- a/src/librustc_errors/lib.rs
+++ b/src/librustc_errors/lib.rs
@@ -833,7 +833,7 @@
Warning => "warning",
Note => "note",
Help => "help",
- FailureNote => "",
+ FailureNote => "failure-note",
Cancelled => panic!("Shouldn't call on cancelled error"),
}
}
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 75d7261..34c84b1 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -489,7 +489,11 @@
fn raw_proc_macro(&self, id: DefIndex) -> &ProcMacro {
// DefIndex's in root.proc_macro_data have a one-to-one correspondence
- // with items in 'raw_proc_macros'
+ // with items in 'raw_proc_macros'.
+ // NOTE: If you update the order of macros in 'proc_macro_data' for any reason,
+ // you must also update src/libsyntax_ext/proc_macro_harness.rs
+ // Failing to do so will result in incorrect data being associated
+ // with proc macros when deserialized.
let pos = self.root.proc_macro_data.unwrap().decode(self).position(|i| i == id).unwrap();
&self.raw_proc_macros.unwrap()[pos]
}
diff --git a/src/librustc_mir/Cargo.toml b/src/librustc_mir/Cargo.toml
index e027360..0691390 100644
--- a/src/librustc_mir/Cargo.toml
+++ b/src/librustc_mir/Cargo.toml
@@ -24,6 +24,6 @@
rustc_serialize = { path = "../libserialize", package = "serialize" }
syntax = { path = "../libsyntax" }
syntax_pos = { path = "../libsyntax_pos" }
-byteorder = { version = "1.1", features = ["i128"] }
+byteorder = { version = "1.3" }
rustc_apfloat = { path = "../librustc_apfloat" }
smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
diff --git a/src/librustc_mir/borrow_check/conflict_errors.rs b/src/librustc_mir/borrow_check/conflict_errors.rs
index 4b4516d..81359c6 100644
--- a/src/librustc_mir/borrow_check/conflict_errors.rs
+++ b/src/librustc_mir/borrow_check/conflict_errors.rs
@@ -614,8 +614,9 @@
projection,
} = first_borrowed_place;
- for (i, elem) in projection.iter().enumerate().rev() {
- let proj_base = &projection[..i];
+ let mut cursor = &**projection;
+ while let [proj_base @ .., elem] = cursor {
+ cursor = proj_base;
match elem {
ProjectionElem::Field(field, _) if union_ty(base, proj_base).is_some() => {
@@ -637,8 +638,9 @@
projection,
} = second_borrowed_place;
- for (i, elem) in projection.iter().enumerate().rev() {
- let proj_base = &projection[..i];
+ let mut cursor = &**projection;
+ while let [proj_base @ .., elem] = cursor {
+ cursor = proj_base;
if let ProjectionElem::Field(field, _) = elem {
if let Some(union_ty) = union_ty(base, proj_base) {
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 5ef7046..1d35762 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -1758,7 +1758,10 @@
debug!("check_if_assigned_path_is_moved place: {:?}", place);
// None case => assigning to `x` does not require `x` be initialized.
- for (i, elem) in place.projection.iter().enumerate().rev() {
+ let mut cursor = &*place.projection;
+ while let [proj_base @ .., elem] = cursor {
+ cursor = proj_base;
+
match elem {
ProjectionElem::Index(_/*operand*/) |
ProjectionElem::ConstantIndex { .. } |
@@ -1771,8 +1774,6 @@
// assigning to (*P) requires P to be initialized
ProjectionElem::Deref => {
- let proj_base = &place.projection[..i];
-
self.check_if_full_path_is_moved(
location, InitializationRequiringAction::Use,
(PlaceRef {
@@ -1790,7 +1791,6 @@
}
ProjectionElem::Field(..) => {
- let proj_base = &place.projection[..i];
// if type of `P` has a dtor, then
// assigning to `P.f` requires `P` itself
// be already initialized
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs
index efa1858..26a89b4 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs
@@ -13,7 +13,7 @@
use rustc::mir::{ConstraintCategory, Location, Body};
use rustc::ty::{self, RegionVid};
use rustc_data_structures::indexed_vec::IndexVec;
-use rustc_errors::{Diagnostic, DiagnosticBuilder};
+use rustc_errors::DiagnosticBuilder;
use std::collections::VecDeque;
use syntax::errors::Applicability;
use syntax::symbol::kw;
@@ -22,7 +22,7 @@
mod region_name;
mod var_name;
-crate use self::region_name::{RegionName, RegionNameSource};
+crate use self::region_name::{RegionName, RegionNameSource, RegionErrorNamingCtx};
impl ConstraintDescription for ConstraintCategory {
fn description(&self) -> &'static str {
@@ -54,6 +54,39 @@
NotVisited,
}
+/// Various pieces of state used when reporting borrow checker errors.
+pub struct ErrorReportingCtx<'a, 'b, 'tcx> {
+ /// The region inference context used for borrow chekcing this MIR body.
+ #[allow(dead_code)] // FIXME(mark-i-m): used by outlives suggestions
+ region_infcx: &'b RegionInferenceContext<'tcx>,
+
+ /// The inference context used for type checking.
+ infcx: &'b InferCtxt<'a, 'tcx>,
+
+ /// The MIR def we are reporting errors on.
+ mir_def_id: DefId,
+
+ /// The MIR body we are reporting errors on (for convenience).
+ body: &'b Body<'tcx>,
+
+ /// Any upvars for the MIR body we have kept track of during borrow checking.
+ upvars: &'b [Upvar],
+}
+
+/// Information about the various region constraints involved in a borrow checker error.
+#[derive(Clone, Debug)]
+pub struct ErrorConstraintInfo {
+ // fr: outlived_fr
+ fr: RegionVid,
+ fr_is_local: bool,
+ outlived_fr: RegionVid,
+ outlived_fr_is_local: bool,
+
+ // Category and span for best blame constraint
+ category: ConstraintCategory,
+ span: Span,
+}
+
impl<'tcx> RegionInferenceContext<'tcx> {
/// Tries to find the best constraint to blame for the fact that
/// `R: from_region`, where `R` is some region that meets
@@ -257,16 +290,16 @@
/// ```
///
/// Here we would be invoked with `fr = 'a` and `outlived_fr = `'b`.
- pub(super) fn report_error(
- &self,
+ pub(super) fn report_error<'a>(
+ &'a self,
body: &Body<'tcx>,
upvars: &[Upvar],
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &'a InferCtxt<'a, 'tcx>,
mir_def_id: DefId,
fr: RegionVid,
outlived_fr: RegionVid,
- errors_buffer: &mut Vec<Diagnostic>,
- ) {
+ renctx: &mut RegionErrorNamingCtx,
+ ) -> DiagnosticBuilder<'a> {
debug!("report_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);
let (category, _, span) = self.best_blame_constraint(body, fr, |r| {
@@ -279,8 +312,7 @@
let tables = infcx.tcx.typeck_tables_of(mir_def_id);
let nice = NiceRegionError::new_from_span(infcx, span, o, f, Some(tables));
if let Some(diag) = nice.try_report_from_nll() {
- diag.buffer(errors_buffer);
- return;
+ return diag;
}
}
@@ -293,45 +325,28 @@
"report_error: fr_is_local={:?} outlived_fr_is_local={:?} category={:?}",
fr_is_local, outlived_fr_is_local, category
);
+
+ let errctx = ErrorReportingCtx {
+ region_infcx: self,
+ infcx,
+ mir_def_id,
+ body,
+ upvars,
+ };
+
+ let errci = ErrorConstraintInfo {
+ fr, outlived_fr, fr_is_local, outlived_fr_is_local, category, span
+ };
+
match (category, fr_is_local, outlived_fr_is_local) {
(ConstraintCategory::Return, true, false) if self.is_closure_fn_mut(infcx, fr) => {
- self.report_fnmut_error(
- body,
- upvars,
- infcx,
- mir_def_id,
- fr,
- outlived_fr,
- span,
- errors_buffer,
- )
+ self.report_fnmut_error(&errctx, &errci, renctx)
}
(ConstraintCategory::Assignment, true, false)
- | (ConstraintCategory::CallArgument, true, false) => self.report_escaping_data_error(
- body,
- upvars,
- infcx,
- mir_def_id,
- fr,
- outlived_fr,
- category,
- span,
- errors_buffer,
- ),
- _ => self.report_general_error(
- body,
- upvars,
- infcx,
- mir_def_id,
- fr,
- fr_is_local,
- outlived_fr,
- outlived_fr_is_local,
- category,
- span,
- errors_buffer,
- ),
- };
+ | (ConstraintCategory::CallArgument, true, false) =>
+ self.report_escaping_data_error(&errctx, &errci, renctx),
+ _ => self.report_general_error(&errctx, &errci, renctx),
+ }
}
/// We have a constraint `fr1: fr2` that is not satisfied, where
@@ -379,19 +394,19 @@
/// ```
fn report_fnmut_error(
&self,
- body: &Body<'tcx>,
- upvars: &[Upvar],
- infcx: &InferCtxt<'_, 'tcx>,
- mir_def_id: DefId,
- _fr: RegionVid,
- outlived_fr: RegionVid,
- span: Span,
- errors_buffer: &mut Vec<Diagnostic>,
- ) {
- let mut diag = infcx
+ errctx: &ErrorReportingCtx<'_, '_, 'tcx>,
+ errci: &ErrorConstraintInfo,
+ renctx: &mut RegionErrorNamingCtx,
+ ) -> DiagnosticBuilder<'_> {
+ let ErrorConstraintInfo {
+ outlived_fr, span, ..
+ } = errci;
+
+ let mut diag = errctx
+ .infcx
.tcx
.sess
- .struct_span_err(span, "captured variable cannot escape `FnMut` closure body");
+ .struct_span_err(*span, "captured variable cannot escape `FnMut` closure body");
// We should check if the return type of this closure is in fact a closure - in that
// case, we can special case the error further.
@@ -403,11 +418,9 @@
"returns a reference to a captured variable which escapes the closure body"
};
- diag.span_label(span, message);
+ diag.span_label(*span, message);
- match self.give_region_a_name(infcx, body, upvars, mir_def_id, outlived_fr, &mut 1)
- .unwrap().source
- {
+ match self.give_region_a_name(errctx, renctx, *outlived_fr).unwrap().source {
RegionNameSource::NamedEarlyBoundRegion(fr_span)
| RegionNameSource::NamedFreeRegion(fr_span)
| RegionNameSource::SynthesizedFreeEnvRegion(fr_span, _)
@@ -427,7 +440,7 @@
);
diag.note("...therefore, they cannot allow references to captured variables to escape");
- diag.buffer(errors_buffer);
+ diag
}
/// Reports a error specifically for when data is escaping a closure.
@@ -444,20 +457,22 @@
/// ```
fn report_escaping_data_error(
&self,
- body: &Body<'tcx>,
- upvars: &[Upvar],
- infcx: &InferCtxt<'_, 'tcx>,
- mir_def_id: DefId,
- fr: RegionVid,
- outlived_fr: RegionVid,
- category: ConstraintCategory,
- span: Span,
- errors_buffer: &mut Vec<Diagnostic>,
- ) {
+ errctx: &ErrorReportingCtx<'_, '_, 'tcx>,
+ errci: &ErrorConstraintInfo,
+ renctx: &mut RegionErrorNamingCtx,
+ ) -> DiagnosticBuilder<'_> {
+ let ErrorReportingCtx {
+ infcx, body, upvars, ..
+ } = errctx;
+
+ let ErrorConstraintInfo {
+ span, category, ..
+ } = errci;
+
let fr_name_and_span =
- self.get_var_name_and_span_for_region(infcx.tcx, body, upvars, fr);
+ self.get_var_name_and_span_for_region(infcx.tcx, body, upvars, errci.fr);
let outlived_fr_name_and_span =
- self.get_var_name_and_span_for_region(infcx.tcx, body, upvars, outlived_fr);
+ self.get_var_name_and_span_for_region(infcx.tcx, body, upvars, errci.outlived_fr);
let escapes_from = match self.universal_regions.defining_ty {
DefiningTy::Closure(..) => "closure",
@@ -469,27 +484,23 @@
// Revert to the normal error in these cases.
// Assignments aren't "escapes" in function items.
if (fr_name_and_span.is_none() && outlived_fr_name_and_span.is_none())
- || (category == ConstraintCategory::Assignment && escapes_from == "function")
+ || (*category == ConstraintCategory::Assignment && escapes_from == "function")
|| escapes_from == "const"
{
return self.report_general_error(
- body,
- upvars,
- infcx,
- mir_def_id,
- fr,
- true,
- outlived_fr,
- false,
- category,
- span,
- errors_buffer,
+ errctx,
+ &ErrorConstraintInfo {
+ fr_is_local: true,
+ outlived_fr_is_local: false,
+ .. *errci
+ },
+ renctx,
);
}
let mut diag = borrowck_errors::borrowed_data_escapes_closure(
infcx.tcx,
- span,
+ *span,
escapes_from,
);
@@ -513,12 +524,12 @@
);
diag.span_label(
- span,
+ *span,
format!("`{}` escapes the {} body here", fr_name, escapes_from),
);
}
- diag.buffer(errors_buffer);
+ diag
}
/// Reports a region inference error for the general case with named/synthesized lifetimes to
@@ -538,41 +549,37 @@
/// ```
fn report_general_error(
&self,
- body: &Body<'tcx>,
- upvars: &[Upvar],
- infcx: &InferCtxt<'_, 'tcx>,
- mir_def_id: DefId,
- fr: RegionVid,
- fr_is_local: bool,
- outlived_fr: RegionVid,
- outlived_fr_is_local: bool,
- category: ConstraintCategory,
- span: Span,
- errors_buffer: &mut Vec<Diagnostic>,
- ) {
+ errctx: &ErrorReportingCtx<'_, '_, 'tcx>,
+ errci: &ErrorConstraintInfo,
+ renctx: &mut RegionErrorNamingCtx,
+ ) -> DiagnosticBuilder<'_> {
+ let ErrorReportingCtx {
+ infcx, mir_def_id, ..
+ } = errctx;
+ let ErrorConstraintInfo {
+ fr, fr_is_local, outlived_fr, outlived_fr_is_local, span, category, ..
+ } = errci;
+
let mut diag = infcx.tcx.sess.struct_span_err(
- span,
+ *span,
"lifetime may not live long enough"
);
- let counter = &mut 1;
- let fr_name = self.give_region_a_name(
- infcx, body, upvars, mir_def_id, fr, counter).unwrap();
- fr_name.highlight_region_name(&mut diag);
- let outlived_fr_name =
- self.give_region_a_name(infcx, body, upvars, mir_def_id, outlived_fr, counter).unwrap();
- outlived_fr_name.highlight_region_name(&mut diag);
-
- let mir_def_name = if infcx.tcx.is_closure(mir_def_id) {
+ let mir_def_name = if infcx.tcx.is_closure(*mir_def_id) {
"closure"
} else {
"function"
};
+ let fr_name = self.give_region_a_name(errctx, renctx, *fr).unwrap();
+ fr_name.highlight_region_name(&mut diag);
+ let outlived_fr_name = self.give_region_a_name(errctx, renctx, *outlived_fr).unwrap();
+ outlived_fr_name.highlight_region_name(&mut diag);
+
match (category, outlived_fr_is_local, fr_is_local) {
(ConstraintCategory::Return, true, _) => {
diag.span_label(
- span,
+ *span,
format!(
"{} was supposed to return data with lifetime `{}` but it is returning \
data with lifetime `{}`",
@@ -582,7 +589,7 @@
}
_ => {
diag.span_label(
- span,
+ *span,
format!(
"{}requires that `{}` must outlive `{}`",
category.description(),
@@ -593,9 +600,9 @@
}
}
- self.add_static_impl_trait_suggestion(infcx, &mut diag, fr, fr_name, outlived_fr);
+ self.add_static_impl_trait_suggestion(infcx, &mut diag, *fr, fr_name, *outlived_fr);
- diag.buffer(errors_buffer);
+ diag
}
/// Adds a suggestion to errors where a `impl Trait` is returned.
@@ -704,8 +711,14 @@
borrow_region,
|r| self.provides_universal_region(r, borrow_region, outlived_region)
);
- let outlived_fr_name =
- self.give_region_a_name(infcx, body, upvars, mir_def_id, outlived_region, &mut 1);
+
+ let mut renctx = RegionErrorNamingCtx::new();
+ let errctx = ErrorReportingCtx {
+ infcx, body, upvars, mir_def_id,
+ region_infcx: self,
+ };
+ let outlived_fr_name = self.give_region_a_name(&errctx, &mut renctx, outlived_region);
+
(category, from_closure, span, outlived_fr_name)
}
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs
index 75a3162..6fa9426 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs
@@ -1,5 +1,9 @@
use std::fmt::{self, Display};
-use crate::borrow_check::nll::region_infer::RegionInferenceContext;
+
+use crate::borrow_check::nll::region_infer::{
+ RegionInferenceContext,
+ error_reporting::ErrorReportingCtx,
+};
use crate::borrow_check::nll::universal_regions::DefiningTy;
use crate::borrow_check::nll::ToRegionVid;
use crate::borrow_check::Upvar;
@@ -13,29 +17,75 @@
use rustc::ty::print::RegionHighlightMode;
use rustc_errors::DiagnosticBuilder;
use syntax::symbol::kw;
-use syntax_pos::Span;
-use syntax_pos::symbol::InternedString;
+use rustc_data_structures::fx::FxHashMap;
+use syntax_pos::{Span, symbol::InternedString};
-#[derive(Debug)]
+/// A name for a particular region used in emitting diagnostics. This name could be a generated
+/// name like `'1`, a name used by the user like `'a`, or a name like `'static`.
+#[derive(Debug, Clone)]
crate struct RegionName {
+ /// The name of the region (interned).
crate name: InternedString,
+ /// Where the region comes from.
crate source: RegionNameSource,
}
-#[derive(Debug)]
+/// Denotes the source of a region that is named by a `RegionName`. For example, a free region that
+/// was named by the user would get `NamedFreeRegion` and `'static` lifetime would get `Static`.
+/// This helps to print the right kinds of diagnostics.
+#[derive(Debug, Clone)]
crate enum RegionNameSource {
+ /// A bound (not free) region that was substituted at the def site (not an HRTB).
NamedEarlyBoundRegion(Span),
+ /// A free region that the user has a name (`'a`) for.
NamedFreeRegion(Span),
+ /// The `'static` region.
Static,
+ /// The free region corresponding to the environment of a closure.
SynthesizedFreeEnvRegion(Span, String),
+ /// The region name corresponds to a region where the type annotation is completely missing
+ /// from the code, e.g. in a closure arguments `|x| { ... }`, where `x` is a reference.
CannotMatchHirTy(Span, String),
+ /// The region name corresponds a reference that was found by traversing the type in the HIR.
MatchedHirTy(Span),
+ /// A region name from the generics list of a struct/enum/union.
MatchedAdtAndSegment(Span),
+ /// The region corresponding to a closure upvar.
AnonRegionFromUpvar(Span, String),
+ /// The region corresponding to the return type of a closure.
AnonRegionFromOutput(Span, String, String),
AnonRegionFromYieldTy(Span, String),
}
+/// Records region names that have been assigned before so that we can use the same ones in later
+/// diagnostics.
+#[derive(Debug, Clone)]
+crate struct RegionErrorNamingCtx {
+ /// Record the region names generated for each region in the given
+ /// MIR def so that we can reuse them later in help/error messages.
+ renctx: FxHashMap<RegionVid, RegionName>,
+
+ /// The counter for generating new region names.
+ counter: usize,
+}
+
+impl RegionErrorNamingCtx {
+ crate fn new() -> Self {
+ Self {
+ counter: 1,
+ renctx: FxHashMap::default(),
+ }
+ }
+
+ crate fn get(&self, region: &RegionVid) -> Option<&RegionName> {
+ self.renctx.get(region)
+ }
+
+ crate fn insert(&mut self, region: RegionVid, name: RegionName) {
+ self.renctx.insert(region, name);
+ }
+}
+
impl RegionName {
#[allow(dead_code)]
crate fn was_named(&self) -> bool {
@@ -63,43 +113,40 @@
self.name
}
- crate fn highlight_region_name(
- &self,
- diag: &mut DiagnosticBuilder<'_>
- ) {
+ crate fn highlight_region_name(&self, diag: &mut DiagnosticBuilder<'_>) {
match &self.source {
- RegionNameSource::NamedFreeRegion(span) |
- RegionNameSource::NamedEarlyBoundRegion(span) => {
- diag.span_label(
- *span,
- format!("lifetime `{}` defined here", self),
- );
- },
+ RegionNameSource::NamedFreeRegion(span)
+ | RegionNameSource::NamedEarlyBoundRegion(span) => {
+ diag.span_label(*span, format!("lifetime `{}` defined here", self));
+ }
RegionNameSource::SynthesizedFreeEnvRegion(span, note) => {
diag.span_label(
*span,
format!("lifetime `{}` represents this closure's body", self),
);
diag.note(¬e);
- },
+ }
RegionNameSource::CannotMatchHirTy(span, type_name) => {
diag.span_label(*span, format!("has type `{}`", type_name));
- },
+ }
RegionNameSource::MatchedHirTy(span) => {
diag.span_label(
*span,
format!("let's call the lifetime of this reference `{}`", self),
);
- },
+ }
RegionNameSource::MatchedAdtAndSegment(span) => {
diag.span_label(*span, format!("let's call this `{}`", self));
- },
+ }
RegionNameSource::AnonRegionFromUpvar(span, upvar_name) => {
diag.span_label(
*span,
- format!("lifetime `{}` appears in the type of `{}`", self, upvar_name),
+ format!(
+ "lifetime `{}` appears in the type of `{}`",
+ self, upvar_name
+ ),
);
- },
+ }
RegionNameSource::AnonRegionFromOutput(span, mir_description, type_name) => {
diag.span_label(
*span,
@@ -151,39 +198,49 @@
/// and then return the name `'1` for us to use.
crate fn give_region_a_name(
&self,
- infcx: &InferCtxt<'_, 'tcx>,
- body: &Body<'tcx>,
- upvars: &[Upvar],
- mir_def_id: DefId,
+ errctx: &ErrorReportingCtx<'_, '_, 'tcx>,
+ renctx: &mut RegionErrorNamingCtx,
fr: RegionVid,
- counter: &mut usize,
) -> Option<RegionName> {
- debug!("give_region_a_name(fr={:?}, counter={})", fr, counter);
+ let ErrorReportingCtx {
+ infcx, body, mir_def_id, upvars, ..
+ } = errctx;
+
+ debug!("give_region_a_name(fr={:?}, counter={:?})", fr, renctx.counter);
assert!(self.universal_regions.is_universal_region(fr));
- let value = self.give_name_from_error_region(infcx.tcx, mir_def_id, fr, counter)
+ if let Some(value) = renctx.get(&fr) {
+ return Some(value.clone());
+ }
+
+ let value = self
+ .give_name_from_error_region(infcx.tcx, *mir_def_id, fr, renctx)
.or_else(|| {
self.give_name_if_anonymous_region_appears_in_arguments(
- infcx, body, mir_def_id, fr, counter,
+ infcx, body, *mir_def_id, fr, renctx,
)
})
.or_else(|| {
self.give_name_if_anonymous_region_appears_in_upvars(
- infcx.tcx, upvars, fr, counter,
+ infcx.tcx, upvars, fr, renctx
)
})
.or_else(|| {
self.give_name_if_anonymous_region_appears_in_output(
- infcx, body, mir_def_id, fr, counter,
+ infcx, body, *mir_def_id, fr, renctx,
)
})
.or_else(|| {
self.give_name_if_anonymous_region_appears_in_yield_ty(
- infcx, body, mir_def_id, fr, counter,
+ infcx, body, *mir_def_id, fr, renctx,
)
});
+ if let Some(ref value) = value {
+ renctx.insert(fr, value.clone());
+ }
+
debug!("give_region_a_name: gave name {:?}", value);
value
}
@@ -197,7 +254,7 @@
tcx: TyCtxt<'tcx>,
mir_def_id: DefId,
fr: RegionVid,
- counter: &mut usize,
+ renctx: &mut RegionErrorNamingCtx,
) -> Option<RegionName> {
let error_region = self.to_error_region(fr)?;
@@ -208,7 +265,7 @@
let span = self.get_named_span(tcx, error_region, ebr.name);
Some(RegionName {
name: ebr.name,
- source: RegionNameSource::NamedEarlyBoundRegion(span)
+ source: RegionNameSource::NamedEarlyBoundRegion(span),
})
} else {
None
@@ -227,12 +284,10 @@
name,
source: RegionNameSource::NamedFreeRegion(span),
})
- },
+ }
ty::BoundRegion::BrEnv => {
- let mir_hir_id = tcx.hir()
- .as_local_hir_id(mir_def_id)
- .expect("non-local mir");
+ let mir_hir_id = tcx.hir().as_local_hir_id(mir_def_id).expect("non-local mir");
let def_ty = self.universal_regions.defining_ty;
if let DefiningTy::Closure(def_id, substs) = def_ty {
@@ -243,7 +298,7 @@
} else {
bug!("Closure is not defined by a closure expr");
};
- let region_name = self.synthesize_region_name(counter);
+ let region_name = self.synthesize_region_name(renctx);
let closure_kind_ty = substs.closure_kind_ty(def_id, tcx);
let note = match closure_kind_ty.to_opt_closure_kind() {
@@ -265,7 +320,7 @@
name: region_name,
source: RegionNameSource::SynthesizedFreeEnvRegion(
args_span,
- note.to_string()
+ note.to_string(),
),
})
} else {
@@ -335,7 +390,7 @@
body: &Body<'tcx>,
mir_def_id: DefId,
fr: RegionVid,
- counter: &mut usize,
+ renctx: &mut RegionErrorNamingCtx,
) -> Option<RegionName> {
let implicit_inputs = self.universal_regions.defining_ty.implicit_inputs();
let argument_index = self.get_argument_index_for_region(infcx.tcx, fr)?;
@@ -349,12 +404,12 @@
fr,
arg_ty,
argument_index,
- counter,
+ renctx,
) {
return Some(region_name);
}
- self.give_name_if_we_cannot_match_hir_ty(infcx, body, fr, arg_ty, counter)
+ self.give_name_if_we_cannot_match_hir_ty(infcx, body, fr, arg_ty, renctx)
}
fn give_name_if_we_can_match_hir_ty_from_argument(
@@ -365,7 +420,7 @@
needle_fr: RegionVid,
argument_ty: Ty<'tcx>,
argument_index: usize,
- counter: &mut usize,
+ renctx: &mut RegionErrorNamingCtx,
) -> Option<RegionName> {
let mir_hir_id = infcx.tcx.hir().as_local_hir_id(mir_def_id)?;
let fn_decl = infcx.tcx.hir().fn_decl_by_hir_id(mir_hir_id)?;
@@ -379,7 +434,7 @@
body,
needle_fr,
argument_ty,
- counter,
+ renctx,
),
_ => self.give_name_if_we_can_match_hir_ty(
@@ -387,7 +442,7 @@
needle_fr,
argument_ty,
argument_hir_ty,
- counter,
+ renctx,
),
}
}
@@ -409,10 +464,11 @@
body: &Body<'tcx>,
needle_fr: RegionVid,
argument_ty: Ty<'tcx>,
- counter: &mut usize,
+ renctx: &mut RegionErrorNamingCtx,
) -> Option<RegionName> {
+ let counter = renctx.counter;
let mut highlight = RegionHighlightMode::default();
- highlight.highlighting_region_vid(needle_fr, *counter);
+ highlight.highlighting_region_vid(needle_fr, counter);
let type_name = infcx.extract_type_name(&argument_ty, Some(highlight)).0;
debug!(
@@ -428,7 +484,7 @@
// This counter value will already have been used, so this function will increment
// it so the next value will be used next and return the region name that would
// have been used.
- name: self.synthesize_region_name(counter),
+ name: self.synthesize_region_name(renctx),
source: RegionNameSource::CannotMatchHirTy(span, type_name),
})
} else {
@@ -455,7 +511,7 @@
/// type. Once we find that, we can use the span of the `hir::Ty`
/// to add the highlight.
///
- /// This is a somewhat imperfect process, so long the way we also
+ /// This is a somewhat imperfect process, so along the way we also
/// keep track of the **closest** type we've found. If we fail to
/// find the exact `&` or `'_` to highlight, then we may fall back
/// to highlighting that closest type instead.
@@ -465,7 +521,7 @@
needle_fr: RegionVid,
argument_ty: Ty<'tcx>,
argument_hir_ty: &hir::Ty,
- counter: &mut usize,
+ renctx: &mut RegionErrorNamingCtx,
) -> Option<RegionName> {
let search_stack: &mut Vec<(Ty<'tcx>, &hir::Ty)> =
&mut vec![(argument_ty, argument_hir_ty)];
@@ -483,7 +539,7 @@
hir::TyKind::Rptr(_lifetime, referent_hir_ty),
) => {
if region.to_region_vid() == needle_fr {
- let region_name = self.synthesize_region_name(counter);
+ let region_name = self.synthesize_region_name(renctx);
// Just grab the first character, the `&`.
let source_map = tcx.sess.source_map();
@@ -515,7 +571,7 @@
substs,
needle_fr,
last_segment,
- counter,
+ renctx,
search_stack,
) {
return Some(name);
@@ -559,18 +615,19 @@
substs: SubstsRef<'tcx>,
needle_fr: RegionVid,
last_segment: &'hir hir::PathSegment,
- counter: &mut usize,
+ renctx: &mut RegionErrorNamingCtx,
search_stack: &mut Vec<(Ty<'tcx>, &'hir hir::Ty)>,
) -> Option<RegionName> {
// Did the user give explicit arguments? (e.g., `Foo<..>`)
let args = last_segment.args.as_ref()?;
- let lifetime = self.try_match_adt_and_generic_args(substs, needle_fr, args, search_stack)?;
+ let lifetime =
+ self.try_match_adt_and_generic_args(substs, needle_fr, args, search_stack)?;
match lifetime.name {
hir::LifetimeName::Param(_)
| hir::LifetimeName::Error
| hir::LifetimeName::Static
| hir::LifetimeName::Underscore => {
- let region_name = self.synthesize_region_name(counter);
+ let region_name = self.synthesize_region_name(renctx);
let ampersand_span = lifetime.span;
Some(RegionName {
name: region_name,
@@ -657,12 +714,12 @@
tcx: TyCtxt<'tcx>,
upvars: &[Upvar],
fr: RegionVid,
- counter: &mut usize,
+ renctx: &mut RegionErrorNamingCtx,
) -> Option<RegionName> {
let upvar_index = self.get_upvar_index_for_region(tcx, fr)?;
let (upvar_name, upvar_span) =
self.get_upvar_name_and_span_for_region(tcx, upvars, upvar_index);
- let region_name = self.synthesize_region_name(counter);
+ let region_name = self.synthesize_region_name(renctx);
Some(RegionName {
name: region_name,
@@ -680,7 +737,7 @@
body: &Body<'tcx>,
mir_def_id: DefId,
fr: RegionVid,
- counter: &mut usize,
+ renctx: &mut RegionErrorNamingCtx,
) -> Option<RegionName> {
let tcx = infcx.tcx;
@@ -694,7 +751,7 @@
}
let mut highlight = RegionHighlightMode::default();
- highlight.highlighting_region_vid(fr, *counter);
+ highlight.highlighting_region_vid(fr, renctx.counter);
let type_name = infcx.extract_type_name(&return_ty, Some(highlight)).0;
let mir_hir_id = tcx.hir().as_local_hir_id(mir_def_id).expect("non-local mir");
@@ -725,11 +782,11 @@
// This counter value will already have been used, so this function will increment it
// so the next value will be used next and return the region name that would have been
// used.
- name: self.synthesize_region_name(counter),
+ name: self.synthesize_region_name(renctx),
source: RegionNameSource::AnonRegionFromOutput(
return_span,
mir_description.to_string(),
- type_name
+ type_name,
),
})
}
@@ -740,7 +797,7 @@
body: &Body<'tcx>,
mir_def_id: DefId,
fr: RegionVid,
- counter: &mut usize,
+ renctx: &mut RegionErrorNamingCtx,
) -> Option<RegionName> {
// Note: generators from `async fn` yield `()`, so we don't have to
// worry about them here.
@@ -757,7 +814,7 @@
}
let mut highlight = RegionHighlightMode::default();
- highlight.highlighting_region_vid(fr, *counter);
+ highlight.highlighting_region_vid(fr, renctx.counter);
let type_name = infcx.extract_type_name(&yield_ty, Some(highlight)).0;
let mir_hir_id = tcx.hir().as_local_hir_id(mir_def_id).expect("non-local mir");
@@ -780,16 +837,15 @@
);
Some(RegionName {
- name: self.synthesize_region_name(counter),
+ name: self.synthesize_region_name(renctx),
source: RegionNameSource::AnonRegionFromYieldTy(yield_span, type_name),
})
}
- /// Creates a synthetic region named `'1`, incrementing the
- /// counter.
- fn synthesize_region_name(&self, counter: &mut usize) -> InternedString {
- let c = *counter;
- *counter += 1;
+ /// Creates a synthetic region named `'1`, incrementing the counter.
+ fn synthesize_region_name(&self, renctx: &mut RegionErrorNamingCtx) -> InternedString {
+ let c = renctx.counter;
+ renctx.counter += 1;
InternedString::intern(&format!("'{:?}", c))
}
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
index 4038872..78e7943 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
@@ -1,15 +1,20 @@
-use super::universal_regions::UniversalRegions;
-use crate::borrow_check::nll::constraints::graph::NormalConstraintGraph;
-use crate::borrow_check::nll::constraints::{
- ConstraintSccIndex, OutlivesConstraint, OutlivesConstraintSet,
+use std::rc::Rc;
+
+use crate::borrow_check::nll::{
+ constraints::{
+ graph::NormalConstraintGraph,
+ ConstraintSccIndex,
+ OutlivesConstraint,
+ OutlivesConstraintSet,
+ },
+ member_constraints::{MemberConstraintSet, NllMemberConstraintIndex},
+ region_infer::values::{
+ PlaceholderIndices, RegionElement, ToElementIndex
+ },
+ type_check::{free_region_relations::UniversalRegionRelations, Locations},
};
-use crate::borrow_check::nll::member_constraints::{MemberConstraintSet, NllMemberConstraintIndex};
-use crate::borrow_check::nll::region_infer::values::{
- PlaceholderIndices, RegionElement, ToElementIndex,
-};
-use crate::borrow_check::nll::type_check::free_region_relations::UniversalRegionRelations;
-use crate::borrow_check::nll::type_check::Locations;
use crate::borrow_check::Upvar;
+
use rustc::hir::def_id::DefId;
use rustc::infer::canonical::QueryOutlivesConstraint;
use rustc::infer::opaque_types;
@@ -31,16 +36,16 @@
use rustc_errors::{Diagnostic, DiagnosticBuilder};
use syntax_pos::Span;
-use std::rc::Rc;
+crate use self::error_reporting::{RegionName, RegionNameSource, RegionErrorNamingCtx};
+use self::values::{LivenessValues, RegionValueElements, RegionValues};
+use super::universal_regions::UniversalRegions;
+use super::ToRegionVid;
mod dump_mir;
mod error_reporting;
-crate use self::error_reporting::{RegionName, RegionNameSource};
mod graphviz;
-pub mod values;
-use self::values::{LivenessValues, RegionValueElements, RegionValues};
-use super::ToRegionVid;
+pub mod values;
pub struct RegionInferenceContext<'tcx> {
/// Contains the definition for every region variable. Region
@@ -487,6 +492,12 @@
errors_buffer,
);
+ // If we produce any errors, we keep track of the names of all regions, so that we can use
+ // the same error names in any suggestions we produce. Note that we need names to be unique
+ // across different errors for the same MIR def so that we can make suggestions that fix
+ // multiple problems.
+ let mut region_naming = RegionErrorNamingCtx::new();
+
self.check_universal_regions(
infcx,
body,
@@ -494,6 +505,7 @@
mir_def_id,
outlives_requirements.as_mut(),
errors_buffer,
+ &mut region_naming,
);
self.check_member_constraints(infcx, mir_def_id, errors_buffer);
@@ -1312,6 +1324,7 @@
mir_def_id: DefId,
mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
errors_buffer: &mut Vec<Diagnostic>,
+ region_naming: &mut RegionErrorNamingCtx,
) {
for (fr, fr_definition) in self.definitions.iter_enumerated() {
match fr_definition.origin {
@@ -1327,6 +1340,7 @@
fr,
&mut propagated_outlives_requirements,
errors_buffer,
+ region_naming,
);
}
@@ -1358,6 +1372,7 @@
longer_fr: RegionVid,
propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
errors_buffer: &mut Vec<Diagnostic>,
+ region_naming: &mut RegionErrorNamingCtx,
) {
debug!("check_universal_region(fr={:?})", longer_fr);
@@ -1385,6 +1400,7 @@
mir_def_id,
propagated_outlives_requirements,
errors_buffer,
+ region_naming,
);
return;
}
@@ -1401,8 +1417,13 @@
mir_def_id,
propagated_outlives_requirements,
errors_buffer,
+ region_naming,
) {
// continuing to iterate just reports more errors than necessary
+ //
+ // FIXME It would also allow us to report more Outlives Suggestions, though, so
+ // it's not clear that that's a bad thing. Somebody should try commenting out this
+ // line and see it is actually a regression.
return;
}
}
@@ -1418,6 +1439,7 @@
mir_def_id: DefId,
propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
errors_buffer: &mut Vec<Diagnostic>,
+ region_naming: &mut RegionErrorNamingCtx,
) -> Option<ErrorReported> {
// If it is known that `fr: o`, carry on.
if self.universal_region_relations.outlives(longer_fr, shorter_fr) {
@@ -1466,7 +1488,18 @@
//
// Note: in this case, we use the unapproximated regions to report the
// error. This gives better error messages in some cases.
- self.report_error(body, upvars, infcx, mir_def_id, longer_fr, shorter_fr, errors_buffer);
+ let db = self.report_error(
+ body,
+ upvars,
+ infcx,
+ mir_def_id,
+ longer_fr,
+ shorter_fr,
+ region_naming,
+ );
+
+ db.buffer(errors_buffer);
+
Some(ErrorReported)
}
diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index 1d17bae..62bff34 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -2417,9 +2417,12 @@
"add_reborrow_constraint({:?}, {:?}, {:?})",
location, borrow_region, borrowed_place
);
- for (i, elem) in borrowed_place.projection.iter().enumerate().rev() {
+
+ let mut cursor = &*borrowed_place.projection;
+ while let [proj_base @ .., elem] = cursor {
+ cursor = proj_base;
+
debug!("add_reborrow_constraint - iteration {:?}", elem);
- let proj_base = &borrowed_place.projection[..i];
match elem {
ProjectionElem::Deref => {
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index aa261f8..2b0237c 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -1296,8 +1296,9 @@
// Insert a Shallow borrow of the prefixes of any fake borrows.
for place in fake_borrows
{
- for (i, elem) in place.projection.iter().enumerate().rev() {
- let proj_base = &place.projection[..i];
+ let mut cursor = &*place.projection;
+ while let [proj_base @ .., elem] = cursor {
+ cursor = proj_base;
if let ProjectionElem::Deref = elem {
// Insert a shallow borrow after a deref. For other
diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs
index 3f53f84..4351598 100644
--- a/src/librustc_mir/const_eval.rs
+++ b/src/librustc_mir/const_eval.rs
@@ -15,6 +15,7 @@
use rustc::ty::layout::{self, LayoutOf, VariantIdx};
use rustc::traits::Reveal;
use rustc_data_structures::fx::FxHashMap;
+use crate::interpret::eval_nullary_intrinsic;
use syntax::source_map::{Span, DUMMY_SP};
@@ -602,6 +603,23 @@
other => return other,
}
}
+
+ // We call `const_eval` for zero arg intrinsics, too, in order to cache their value.
+ // Catch such calls and evaluate them instead of trying to load a constant's MIR.
+ if let ty::InstanceDef::Intrinsic(def_id) = key.value.instance.def {
+ let ty = key.value.instance.ty(tcx);
+ let substs = match ty.sty {
+ ty::FnDef(_, substs) => substs,
+ _ => bug!("intrinsic with type {:?}", ty),
+ };
+ return eval_nullary_intrinsic(tcx, key.param_env, def_id, substs)
+ .map_err(|error| {
+ let span = tcx.def_span(def_id);
+ let error = ConstEvalErr { error: error.kind, stacktrace: vec![], span };
+ error.report_as_error(tcx.at(span), "could not evaluate nullary intrinsic")
+ })
+ }
+
tcx.const_eval_raw(key).and_then(|val| {
validate_and_turn_into_const(tcx, val, key)
})
diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs
index a4dc398..319abbb 100644
--- a/src/librustc_mir/dataflow/mod.rs
+++ b/src/librustc_mir/dataflow/mod.rs
@@ -56,7 +56,7 @@
/// string (as well as that of rendering up-front); in exchange, you
/// don't have to hand over ownership of your value or deal with
/// borrowing it.
-pub(crate) struct DebugFormatted(String);
+pub struct DebugFormatted(String);
impl DebugFormatted {
pub fn new(input: &dyn fmt::Debug) -> DebugFormatted {
@@ -70,7 +70,7 @@
}
}
-pub(crate) trait Dataflow<'tcx, BD: BitDenotation<'tcx>> {
+pub trait Dataflow<'tcx, BD: BitDenotation<'tcx>> {
/// Sets up and runs the dataflow problem, using `p` to render results if
/// implementation so chooses.
fn dataflow<P>(&mut self, p: P) where P: Fn(&BD, BD::Idx) -> DebugFormatted {
@@ -121,7 +121,7 @@
pub(crate) param_env: ty::ParamEnv<'tcx>,
}
-pub(crate) fn do_dataflow<'a, 'tcx, BD, P>(
+pub fn do_dataflow<'a, 'tcx, BD, P>(
tcx: TyCtxt<'tcx>,
body: &'a Body<'tcx>,
def_id: DefId,
@@ -541,7 +541,7 @@
pub(crate) kill_set: T,
}
-type GenKillSet<T> = GenKill<HybridBitSet<T>>;
+pub type GenKillSet<T> = GenKill<HybridBitSet<T>>;
impl<T> GenKill<T> {
/// Creates a new tuple where `gen_set == kill_set == elem`.
@@ -556,28 +556,28 @@
}
impl<E:Idx> GenKillSet<E> {
- pub(crate) fn clear(&mut self) {
+ pub fn clear(&mut self) {
self.gen_set.clear();
self.kill_set.clear();
}
- fn gen(&mut self, e: E) {
+ pub fn gen(&mut self, e: E) {
self.gen_set.insert(e);
self.kill_set.remove(e);
}
- fn gen_all(&mut self, i: impl IntoIterator<Item: Borrow<E>>) {
+ pub fn gen_all(&mut self, i: impl IntoIterator<Item: Borrow<E>>) {
for j in i {
self.gen(*j.borrow());
}
}
- fn kill(&mut self, e: E) {
+ pub fn kill(&mut self, e: E) {
self.gen_set.remove(e);
self.kill_set.insert(e);
}
- fn kill_all(&mut self, i: impl IntoIterator<Item: Borrow<E>>) {
+ pub fn kill_all(&mut self, i: impl IntoIterator<Item: Borrow<E>>) {
for j in i {
self.kill(*j.borrow());
}
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index 054b65f..78996ed 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -14,7 +14,6 @@
use rustc::ty::query::TyCtxtAt;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc::mir::interpret::{
- ErrorHandled,
GlobalId, Scalar, Pointer, FrameInfo, AllocId,
InterpResult, truncate, sign_extend,
};
@@ -672,14 +671,7 @@
// Our result will later be validated anyway, and there seems no good reason
// to have to fail early here. This is also more consistent with
// `Memory::get_static_alloc` which has to use `const_eval_raw` to avoid cycles.
- let val = self.tcx.const_eval_raw(param_env.and(gid)).map_err(|err| {
- match err {
- ErrorHandled::Reported =>
- err_inval!(ReferencedConstant),
- ErrorHandled::TooGeneric =>
- err_inval!(TooGeneric),
- }
- })?;
+ let val = self.tcx.const_eval_raw(param_env.and(gid))?;
self.raw_const_to_mplace(val)
}
diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs
index 0f2305e..ec09e69 100644
--- a/src/librustc_mir/interpret/intrinsics.rs
+++ b/src/librustc_mir/interpret/intrinsics.rs
@@ -5,17 +5,18 @@
use syntax::symbol::Symbol;
use rustc::ty;
use rustc::ty::layout::{LayoutOf, Primitive, Size};
+use rustc::ty::subst::SubstsRef;
+use rustc::hir::def_id::DefId;
+use rustc::ty::TyCtxt;
use rustc::mir::BinOp;
-use rustc::mir::interpret::{InterpResult, Scalar};
+use rustc::mir::interpret::{InterpResult, Scalar, GlobalId, ConstValue};
use super::{
- Machine, PlaceTy, OpTy, InterpCx, Immediate,
+ Machine, PlaceTy, OpTy, InterpCx,
};
mod type_name;
-pub use type_name::*;
-
fn numeric_intrinsic<'tcx, Tag>(
name: &str,
bits: u128,
@@ -37,6 +38,50 @@
Ok(Scalar::from_uint(bits_out, size))
}
+/// The logic for all nullary intrinsics is implemented here. These intrinsics don't get evaluated
+/// inside an `InterpCx` and instead have their value computed directly from rustc internal info.
+crate fn eval_nullary_intrinsic<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ def_id: DefId,
+ substs: SubstsRef<'tcx>,
+) -> InterpResult<'tcx, &'tcx ty::Const<'tcx>> {
+ let tp_ty = substs.type_at(0);
+ let name = &*tcx.item_name(def_id).as_str();
+ Ok(match name {
+ "type_name" => {
+ let alloc = type_name::alloc_type_name(tcx, tp_ty);
+ tcx.mk_const(ty::Const {
+ val: ConstValue::Slice {
+ data: alloc,
+ start: 0,
+ end: alloc.len(),
+ },
+ ty: tcx.mk_static_str(),
+ })
+ },
+ "needs_drop" => ty::Const::from_bool(tcx, tp_ty.needs_drop(tcx, param_env)),
+ "size_of" |
+ "min_align_of" |
+ "pref_align_of" => {
+ let layout = tcx.layout_of(param_env.and(tp_ty)).map_err(|e| err_inval!(Layout(e)))?;
+ let n = match name {
+ "pref_align_of" => layout.align.pref.bytes(),
+ "min_align_of" => layout.align.abi.bytes(),
+ "size_of" => layout.size.bytes(),
+ _ => bug!(),
+ };
+ ty::Const::from_usize(tcx, n)
+ },
+ "type_id" => ty::Const::from_bits(
+ tcx,
+ tcx.type_id_hash(tp_ty).into(),
+ param_env.and(tcx.types.u64),
+ ),
+ other => bug!("`{}` is not a zero arg intrinsic", other),
+ })
+}
+
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
/// Returns `true` if emulation happened.
pub fn emulate_intrinsic(
@@ -49,41 +94,19 @@
let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..];
match intrinsic_name {
- "min_align_of" => {
- let elem_ty = substs.type_at(0);
- let elem_align = self.layout_of(elem_ty)?.align.abi.bytes();
- let align_val = Scalar::from_uint(elem_align, dest.layout.size);
- self.write_scalar(align_val, dest)?;
- }
-
- "needs_drop" => {
- let ty = substs.type_at(0);
- let ty_needs_drop = ty.needs_drop(self.tcx.tcx, self.param_env);
- let val = Scalar::from_bool(ty_needs_drop);
- self.write_scalar(val, dest)?;
- }
-
- "size_of" => {
- let ty = substs.type_at(0);
- let size = self.layout_of(ty)?.size.bytes() as u128;
- let size_val = Scalar::from_uint(size, dest.layout.size);
- self.write_scalar(size_val, dest)?;
- }
-
- "type_id" => {
- let ty = substs.type_at(0);
- let type_id = self.tcx.type_id_hash(ty) as u128;
- let id_val = Scalar::from_uint(type_id, dest.layout.size);
- self.write_scalar(id_val, dest)?;
- }
-
+ "min_align_of" |
+ "pref_align_of" |
+ "needs_drop" |
+ "size_of" |
+ "type_id" |
"type_name" => {
- let alloc = alloc_type_name(self.tcx.tcx, substs.type_at(0));
- let name_id = self.tcx.alloc_map.lock().create_memory_alloc(alloc);
- let id_ptr = self.memory.tag_static_base_pointer(name_id.into());
- let alloc_len = alloc.size.bytes();
- let name_val = Immediate::new_slice(Scalar::Ptr(id_ptr), alloc_len, self);
- self.write_immediate(name_val, dest)?;
+ let gid = GlobalId {
+ instance,
+ promoted: None,
+ };
+ let val = self.tcx.const_eval(self.param_env.and(gid))?;
+ let val = self.eval_const_to_op(val, None)?;
+ self.copy_op(val, dest)?;
}
| "ctpop"
diff --git a/src/librustc_mir/interpret/intrinsics/type_name.rs b/src/librustc_mir/interpret/intrinsics/type_name.rs
index 032d16a..1e765a4 100644
--- a/src/librustc_mir/interpret/intrinsics/type_name.rs
+++ b/src/librustc_mir/interpret/intrinsics/type_name.rs
@@ -7,7 +7,7 @@
use rustc::hir::map::{DefPathData, DisambiguatedDefPathData};
use rustc::hir::def_id::CrateNum;
use std::fmt::Write;
-use rustc::mir::interpret::{Allocation, ConstValue};
+use rustc::mir::interpret::Allocation;
struct AbsolutePathPrinter<'tcx> {
tcx: TyCtxt<'tcx>,
@@ -213,22 +213,11 @@
}
}
-/// Produces an absolute path representation of the given type. See also the documentation on
-/// `std::any::type_name`
-pub fn type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx ty::Const<'tcx> {
- let alloc = alloc_type_name(tcx, ty);
- tcx.mk_const(ty::Const {
- val: ConstValue::Slice {
- data: alloc,
- start: 0,
- end: alloc.len(),
- },
- ty: tcx.mk_static_str(),
- })
-}
-
/// Directly returns an `Allocation` containing an absolute path representation of the given type.
-pub(super) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx Allocation {
+crate fn alloc_type_name<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ ty: Ty<'tcx>
+) -> &'tcx Allocation {
let path = AbsolutePathPrinter { tcx, path: String::new() }.print_type(ty).unwrap().path;
let alloc = Allocation::from_byte_aligned_bytes(path.into_bytes());
tcx.intern_const_alloc(alloc)
diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs
index 45d2434..0c61be2 100644
--- a/src/librustc_mir/interpret/mod.rs
+++ b/src/librustc_mir/interpret/mod.rs
@@ -34,6 +34,6 @@
pub use self::validity::RefTracking;
-pub(super) use self::intrinsics::type_name;
-
pub use self::intern::intern_const_alloc_recursive;
+
+crate use self::intrinsics::eval_nullary_intrinsic;
diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs
index f27db35..6a49ed6 100644
--- a/src/librustc_mir/lib.rs
+++ b/src/librustc_mir/lib.rs
@@ -35,7 +35,7 @@
mod borrow_check;
mod build;
-mod dataflow;
+pub mod dataflow;
mod hair;
mod lints;
mod shim;
@@ -59,5 +59,4 @@
let (param_env, (value, field)) = param_env_and_value.into_parts();
const_eval::const_field(tcx, param_env, None, field, value)
};
- providers.type_name = interpret::type_name;
}
diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index f8af9b9..39aa5c7 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -407,8 +407,9 @@
place: &Place<'tcx>,
is_mut_use: bool,
) {
- for (i, elem) in place.projection.iter().enumerate().rev() {
- let proj_base = &place.projection[..i];
+ let mut cursor = &*place.projection;
+ while let [proj_base @ .., elem] = cursor {
+ cursor = proj_base;
match elem {
ProjectionElem::Field(..) => {
diff --git a/src/librustc_mir/util/alignment.rs b/src/librustc_mir/util/alignment.rs
index b4c97f9..a75c1af 100644
--- a/src/librustc_mir/util/alignment.rs
+++ b/src/librustc_mir/util/alignment.rs
@@ -38,8 +38,9 @@
where
L: HasLocalDecls<'tcx>,
{
- for (i, elem) in place.projection.iter().enumerate().rev() {
- let proj_base = &place.projection[..i];
+ let mut cursor = &*place.projection;
+ while let [proj_base @ .., elem] = cursor {
+ cursor = proj_base;
match elem {
// encountered a Deref, which is ABI-aligned
diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs
index 0386dbd..be364a1 100644
--- a/src/libstd/io/mod.rs
+++ b/src/libstd/io/mod.rs
@@ -2326,10 +2326,10 @@
/// An iterator over the contents of an instance of `BufRead` split on a
/// particular byte.
///
-/// This struct is generally created by calling [`split`][split] on a
-/// `BufRead`. Please see the documentation of `split()` for more details.
+/// This struct is generally created by calling [`split`] on a `BufRead`.
+/// Please see the documentation of [`split`] for more details.
///
-/// [split]: trait.BufRead.html#method.split
+/// [`split`]: trait.BufRead.html#method.split
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Debug)]
pub struct Split<B> {
@@ -2358,10 +2358,10 @@
/// An iterator over the lines of an instance of `BufRead`.
///
-/// This struct is generally created by calling [`lines`][lines] on a
-/// `BufRead`. Please see the documentation of `lines()` for more details.
+/// This struct is generally created by calling [`lines`] on a `BufRead`.
+/// Please see the documentation of [`lines`] for more details.
///
-/// [lines]: trait.BufRead.html#method.lines
+/// [`lines`]: trait.BufRead.html#method.lines
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Debug)]
pub struct Lines<B> {
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index bcbc0a1..b634dcc 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -2387,7 +2387,7 @@
),
/// A macro invocation.
///
- /// E.g., `macro_rules! foo { .. }` or `foo!(..)`.
+ /// E.g., `foo!(..)`.
Mac(Mac),
/// A macro definition.
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 5d8498f..bf36c0d 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -35,6 +35,7 @@
SubItem(ast::NodeId),
Expr(&'a ast::Expr),
Pat(&'a ast::Pat),
+ Crate(&'a ast::Crate),
}
pub trait PpAnn {
@@ -140,6 +141,7 @@
s.print_mod(&krate.module, &krate.attrs);
s.print_remaining_comments();
+ s.ann.post(&mut s, AnnNode::Crate(krate));
s.s.eof()
}
@@ -1369,8 +1371,12 @@
}
}
ast::ItemKind::MacroDef(ref macro_def) => {
- let (kw, has_bang) =
- if macro_def.legacy { ("macro_rules", true) } else { ("macro", false) };
+ let (kw, has_bang) = if macro_def.legacy {
+ ("macro_rules", true)
+ } else {
+ self.print_visibility(&item.vis);
+ ("macro", false)
+ };
self.print_mac_common(
Some(MacHeader::Keyword(kw)),
has_bang,
diff --git a/src/libsyntax_ext/proc_macro_harness.rs b/src/libsyntax_ext/proc_macro_harness.rs
index a5dcfb9..f33c813 100644
--- a/src/libsyntax_ext/proc_macro_harness.rs
+++ b/src/libsyntax_ext/proc_macro_harness.rs
@@ -20,15 +20,24 @@
attrs: Vec<ast::Name>,
}
+enum ProcMacroDefType {
+ Attr,
+ Bang
+}
+
struct ProcMacroDef {
function_name: Ident,
span: Span,
+ def_type: ProcMacroDefType
+}
+
+enum ProcMacro {
+ Derive(ProcMacroDerive),
+ Def(ProcMacroDef)
}
struct CollectProcMacros<'a> {
- derives: Vec<ProcMacroDerive>,
- attr_macros: Vec<ProcMacroDef>,
- bang_macros: Vec<ProcMacroDef>,
+ macros: Vec<ProcMacro>,
in_root: bool,
handler: &'a errors::Handler,
is_proc_macro_crate: bool,
@@ -46,22 +55,22 @@
let ecfg = ExpansionConfig::default("proc_macro".to_string());
let mut cx = ExtCtxt::new(sess, ecfg, resolver);
- let (derives, attr_macros, bang_macros) = {
- let mut collect = CollectProcMacros {
- derives: Vec::new(),
- attr_macros: Vec::new(),
- bang_macros: Vec::new(),
- in_root: true,
- handler,
- is_proc_macro_crate,
- is_test_crate,
- };
- if has_proc_macro_decls || is_proc_macro_crate {
- visit::walk_crate(&mut collect, &krate);
- }
- (collect.derives, collect.attr_macros, collect.bang_macros)
+ let mut collect = CollectProcMacros {
+ macros: Vec::new(),
+ in_root: true,
+ handler,
+ is_proc_macro_crate,
+ is_test_crate,
};
+ if has_proc_macro_decls || is_proc_macro_crate {
+ visit::walk_crate(&mut collect, &krate);
+ }
+ // NOTE: If you change the order of macros in this vec
+ // for any reason, you must also update 'raw_proc_macro'
+ // in src/librustc_metadata/decoder.rs
+ let macros = collect.macros;
+
if !is_proc_macro_crate {
return krate
}
@@ -74,7 +83,7 @@
return krate;
}
- krate.module.items.push(mk_decls(&mut cx, &derives, &attr_macros, &bang_macros));
+ krate.module.items.push(mk_decls(&mut cx, ¯os));
krate
}
@@ -161,12 +170,12 @@
};
if self.in_root && item.vis.node.is_pub() {
- self.derives.push(ProcMacroDerive {
+ self.macros.push(ProcMacro::Derive(ProcMacroDerive {
span: item.span,
trait_name: trait_ident.name,
function_name: item.ident,
attrs: proc_attrs,
- });
+ }));
} else {
let msg = if !self.in_root {
"functions tagged with `#[proc_macro_derive]` must \
@@ -180,10 +189,11 @@
fn collect_attr_proc_macro(&mut self, item: &'a ast::Item) {
if self.in_root && item.vis.node.is_pub() {
- self.attr_macros.push(ProcMacroDef {
+ self.macros.push(ProcMacro::Def(ProcMacroDef {
span: item.span,
function_name: item.ident,
- });
+ def_type: ProcMacroDefType::Attr
+ }));
} else {
let msg = if !self.in_root {
"functions tagged with `#[proc_macro_attribute]` must \
@@ -197,10 +207,11 @@
fn collect_bang_proc_macro(&mut self, item: &'a ast::Item) {
if self.in_root && item.vis.node.is_pub() {
- self.bang_macros.push(ProcMacroDef {
+ self.macros.push(ProcMacro::Def(ProcMacroDef {
span: item.span,
function_name: item.ident,
- });
+ def_type: ProcMacroDefType::Bang
+ }));
} else {
let msg = if !self.in_root {
"functions tagged with `#[proc_macro]` must \
@@ -322,9 +333,7 @@
// }
fn mk_decls(
cx: &mut ExtCtxt<'_>,
- custom_derives: &[ProcMacroDerive],
- custom_attrs: &[ProcMacroDef],
- custom_macros: &[ProcMacroDef],
+ macros: &[ProcMacro],
) -> P<ast::Item> {
let expn_id = cx.resolver.expansion_for_ast_pass(
DUMMY_SP,
@@ -354,26 +363,32 @@
let proc_macro_ty_method_path = |method| cx.expr_path(cx.path(span, vec![
proc_macro, bridge, client, proc_macro_ty, method,
]));
- custom_derives.iter().map(|cd| {
- cx.expr_call(span, proc_macro_ty_method_path(custom_derive), vec![
- cx.expr_str(cd.span, cd.trait_name),
- cx.expr_vec_slice(
- span,
- cd.attrs.iter().map(|&s| cx.expr_str(cd.span, s)).collect::<Vec<_>>()
- ),
- local_path(cd.span, cd.function_name),
- ])
- }).chain(custom_attrs.iter().map(|ca| {
- cx.expr_call(span, proc_macro_ty_method_path(attr), vec![
- cx.expr_str(ca.span, ca.function_name.name),
- local_path(ca.span, ca.function_name),
- ])
- })).chain(custom_macros.iter().map(|cm| {
- cx.expr_call(span, proc_macro_ty_method_path(bang), vec![
- cx.expr_str(cm.span, cm.function_name.name),
- local_path(cm.span, cm.function_name),
- ])
- })).collect()
+ macros.iter().map(|m| {
+ match m {
+ ProcMacro::Derive(cd) => {
+ cx.expr_call(span, proc_macro_ty_method_path(custom_derive), vec![
+ cx.expr_str(cd.span, cd.trait_name),
+ cx.expr_vec_slice(
+ span,
+ cd.attrs.iter().map(|&s| cx.expr_str(cd.span, s)).collect::<Vec<_>>()
+ ),
+ local_path(cd.span, cd.function_name),
+ ])
+ },
+ ProcMacro::Def(ca) => {
+ let ident = match ca.def_type {
+ ProcMacroDefType::Attr => attr,
+ ProcMacroDefType::Bang => bang
+ };
+
+ cx.expr_call(span, proc_macro_ty_method_path(ident), vec![
+ cx.expr_str(ca.span, ca.function_name.name),
+ local_path(ca.span, ca.function_name),
+ ])
+
+ }
+ }
+ }).collect()
};
let decls_static = cx.item_static(
diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs
index 8971638..e28d932 100644
--- a/src/libsyntax_pos/hygiene.rs
+++ b/src/libsyntax_pos/hygiene.rs
@@ -343,6 +343,38 @@
}))
}
+pub fn debug_hygiene_data(verbose: bool) -> String {
+ HygieneData::with(|data| {
+ if verbose {
+ format!("{:#?}", data)
+ } else {
+ let mut s = String::from("");
+ s.push_str("Expansions:");
+ data.expn_data.iter().enumerate().for_each(|(id, expn_info)| {
+ let expn_info = expn_info.as_ref().expect("no expansion data for an expansion ID");
+ s.push_str(&format!(
+ "\n{}: parent: {:?}, call_site_ctxt: {:?}, kind: {:?}",
+ id,
+ expn_info.parent,
+ expn_info.call_site.ctxt(),
+ expn_info.kind,
+ ));
+ });
+ s.push_str("\n\nSyntaxContexts:");
+ data.syntax_context_data.iter().enumerate().for_each(|(id, ctxt)| {
+ s.push_str(&format!(
+ "\n#{}: parent: {:?}, outer_mark: ({:?}, {:?})",
+ id,
+ ctxt.parent,
+ ctxt.outer_expn,
+ ctxt.outer_transparency,
+ ));
+ });
+ s
+ }
+ })
+}
+
impl SyntaxContext {
#[inline]
pub const fn root() -> Self {
diff --git a/src/test/ui/issues/issue-44415.rs b/src/test/compile-fail/issue-44415.rs
similarity index 100%
rename from src/test/ui/issues/issue-44415.rs
rename to src/test/compile-fail/issue-44415.rs
diff --git a/src/test/pretty/macro.rs b/src/test/pretty/macro.rs
index 39677d1..1e1e1db 100644
--- a/src/test/pretty/macro.rs
+++ b/src/test/pretty/macro.rs
@@ -2,6 +2,6 @@
#![feature(decl_macro)]
-macro mac { ($ arg : expr) => { $ arg + $ arg } }
+pub(crate) macro mac { ($ arg : expr) => { $ arg + $ arg } }
fn main() { }
diff --git a/src/test/rustdoc/inline_cross/proc_macro.rs b/src/test/rustdoc/inline_cross/proc_macro.rs
index 6880e30..3dc8de3 100644
--- a/src/test/rustdoc/inline_cross/proc_macro.rs
+++ b/src/test/rustdoc/inline_cross/proc_macro.rs
@@ -10,8 +10,19 @@
// @has proc_macro/macro.some_proc_macro.html
// @has proc_macro/attr.some_proc_attr.html
// @has proc_macro/derive.SomeDerive.html
-pub use some_macros::{some_proc_macro, some_proc_attr, SomeDerive};
+
+// @has proc_macro/macro.some_proc_macro.html
+// @has - 'a proc-macro that swallows its input and does nothing.'
+pub use some_macros::some_proc_macro;
// @has proc_macro/macro.reexported_macro.html
// @has - 'Doc comment from the original crate'
pub use some_macros::reexported_macro;
+
+// @has proc_macro/attr.some_proc_attr.html
+// @has - 'a proc-macro attribute that passes its item through verbatim.'
+pub use some_macros::some_proc_attr;
+
+// @has proc_macro/derive.SomeDerive.html
+// @has - 'a derive attribute that adds nothing to its input.'
+pub use some_macros::SomeDerive;
diff --git a/src/test/ui/async-await/drop-order/drop-order-for-temporary-in-tail-return-expr.rs b/src/test/ui/async-await/drop-order/drop-order-for-temporary-in-tail-return-expr.rs
new file mode 100644
index 0000000..e40acff
--- /dev/null
+++ b/src/test/ui/async-await/drop-order/drop-order-for-temporary-in-tail-return-expr.rs
@@ -0,0 +1,95 @@
+// aux-build:arc_wake.rs
+// edition:2018
+// run-pass
+
+#![allow(unused_variables)]
+
+// Test the drop order for parameters relative to local variables and
+// temporaries created in the tail return expression of the function
+// body. In particular, check that this drop order is the same between
+// a `async fn` and an ordinary `fn`. See #64512.
+
+extern crate arc_wake;
+
+use arc_wake::ArcWake;
+use std::cell::RefCell;
+use std::future::Future;
+use std::sync::Arc;
+use std::rc::Rc;
+use std::task::Context;
+
+struct EmptyWaker;
+
+impl ArcWake for EmptyWaker {
+ fn wake(self: Arc<Self>) {}
+}
+
+#[derive(Debug, Eq, PartialEq)]
+enum DropOrder {
+ Function,
+ Val(&'static str),
+}
+
+type DropOrderListPtr = Rc<RefCell<Vec<DropOrder>>>;
+
+struct D(&'static str, DropOrderListPtr);
+
+impl Drop for D {
+ fn drop(&mut self) {
+ self.1.borrow_mut().push(DropOrder::Val(self.0));
+ }
+}
+
+/// Check drop order of temporary "temp" as compared to `x`, `y`, and `z`.
+///
+/// Expected order:
+/// - `z`
+/// - temp
+/// - `y`
+/// - `x`
+async fn foo_async(x: D, _y: D) {
+ let l = x.1.clone();
+ let z = D("z", l.clone());
+ l.borrow_mut().push(DropOrder::Function);
+ helper_async(&D("temp", l)).await
+}
+
+async fn helper_async(v: &D) { }
+
+fn foo_sync(x: D, _y: D) {
+ let l = x.1.clone();
+ let z = D("z", l.clone());
+ l.borrow_mut().push(DropOrder::Function);
+ helper_sync(&D("temp", l))
+}
+
+fn helper_sync(v: &D) { }
+
+fn assert_drop_order_after_poll<Fut: Future<Output = ()>>(
+ f: impl FnOnce(DropOrderListPtr) -> Fut,
+ g: impl FnOnce(DropOrderListPtr),
+) {
+ let empty = Arc::new(EmptyWaker);
+ let waker = ArcWake::into_waker(empty);
+ let mut cx = Context::from_waker(&waker);
+
+ let actual_order = Rc::new(RefCell::new(Vec::new()));
+ let mut fut = Box::pin(f(actual_order.clone()));
+ let r = fut.as_mut().poll(&mut cx);
+
+ assert!(match r {
+ std::task::Poll::Ready(()) => true,
+ _ => false,
+ });
+
+ let expected_order = Rc::new(RefCell::new(Vec::new()));
+ g(expected_order.clone());
+
+ assert_eq!(*actual_order.borrow(), *expected_order.borrow());
+}
+
+fn main() {
+ // Free functions (see doc comment on function for what it tests).
+ assert_drop_order_after_poll(|l| foo_async(D("x", l.clone()), D("_y", l.clone())),
+ |l| foo_sync(D("x", l.clone()), D("_y", l.clone())));
+}
diff --git a/src/test/ui/async-await/issue-64391.rs b/src/test/ui/async-await/issue-64391.rs
new file mode 100644
index 0000000..c6faad3
--- /dev/null
+++ b/src/test/ui/async-await/issue-64391.rs
@@ -0,0 +1,14 @@
+// Regression test for Issue #64391. The goal here is that this
+// function compiles. In the past, due to incorrect drop order for
+// temporaries in the tail expression, we failed to compile this
+// example. The drop order itself is directly tested in
+// `drop-order/drop-order-for-temporary-in-tail-return-expr.rs`.
+//
+// check-pass
+// edition:2018
+
+async fn add(x: u32, y: u32) -> u32 {
+ async { x + y }.await
+}
+
+fn main() { }
diff --git a/src/test/ui/c-variadic/variadic-ffi-4.nll.stderr b/src/test/ui/c-variadic/variadic-ffi-4.nll.stderr
index 4947d6e..ab8398e 100644
--- a/src/test/ui/c-variadic/variadic-ffi-4.nll.stderr
+++ b/src/test/ui/c-variadic/variadic-ffi-4.nll.stderr
@@ -37,11 +37,11 @@
--> $DIR/variadic-ffi-4.rs:20:5
|
LL | pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
- | ------- ------- has type `core::ffi::VaListImpl<'1>`
+ | ------- ------- has type `core::ffi::VaListImpl<'2>`
| |
- | has type `&mut core::ffi::VaListImpl<'2>`
+ | has type `&mut core::ffi::VaListImpl<'1>`
LL | *ap0 = ap1;
- | ^^^^ assignment requires that `'1` must outlive `'2`
+ | ^^^^ assignment requires that `'2` must outlive `'1`
error: lifetime may not live long enough
--> $DIR/variadic-ffi-4.rs:25:5
@@ -57,11 +57,11 @@
--> $DIR/variadic-ffi-4.rs:25:5
|
LL | pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) {
- | --- ------- has type `core::ffi::VaListImpl<'1>`
+ | --- ------- has type `core::ffi::VaListImpl<'2>`
| |
- | has type `&mut core::ffi::VaListImpl<'2>`
+ | has type `&mut core::ffi::VaListImpl<'1>`
LL | ap0 = &mut ap1;
- | ^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2`
+ | ^^^^^^^^^^^^^^ assignment requires that `'2` must outlive `'1`
error[E0384]: cannot assign to immutable argument `ap0`
--> $DIR/variadic-ffi-4.rs:25:5
@@ -99,11 +99,11 @@
--> $DIR/variadic-ffi-4.rs:33:12
|
LL | pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
- | ------- ------- has type `core::ffi::VaListImpl<'1>`
+ | ------- ------- has type `core::ffi::VaListImpl<'2>`
| |
- | has type `&mut core::ffi::VaListImpl<'2>`
+ | has type `&mut core::ffi::VaListImpl<'1>`
LL | *ap0 = ap1.clone();
- | ^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
+ | ^^^^^^^^^^^ argument requires that `'2` must outlive `'1`
error: aborting due to 11 previous errors
diff --git a/src/test/ui/consts/const-size_of-cycle.stderr b/src/test/ui/consts/const-size_of-cycle.stderr
index fdba359..1ae39e7 100644
--- a/src/test/ui/consts/const-size_of-cycle.stderr
+++ b/src/test/ui/consts/const-size_of-cycle.stderr
@@ -14,6 +14,11 @@
|
LL | intrinsics::size_of::<T>()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires const-evaluating + checking `std::intrinsics::size_of`...
+ --> $SRC_DIR/libcore/intrinsics.rs:LL:COL
+ |
+LL | pub fn size_of<T>() -> usize;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires computing layout of `Foo`...
= note: ...which requires normalizing `ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: All, def_id: None }, value: [u8; _] }`...
= note: ...which again requires const-evaluating + checking `Foo::bytes::{{constant}}#0`, completing the cycle
diff --git a/src/test/ui/generator/auto-trait-regions.stderr b/src/test/ui/generator/auto-trait-regions.stderr
index 92f92e2..dab4d34 100644
--- a/src/test/ui/generator/auto-trait-regions.stderr
+++ b/src/test/ui/generator/auto-trait-regions.stderr
@@ -1,20 +1,26 @@
error: implementation of `Foo` is not general enough
--> $DIR/auto-trait-regions.rs:30:5
|
+LL | auto trait Foo {}
+ | ----------------- trait `Foo` defined here
+...
LL | assert_foo(gen);
- | ^^^^^^^^^^
+ | ^^^^^^^^^^ implementation of `Foo` is not general enough
|
- = note: `Foo` would have to be implemented for the type `&'0 OnlyFooIfStaticRef`, for any lifetime `'0`
- = note: but `Foo` is actually implemented for the type `&'1 OnlyFooIfStaticRef`, for some specific lifetime `'1`
+ = note: `Foo` would have to be implemented for the type `&'0 OnlyFooIfStaticRef`, for any lifetime `'0`...
+ = note: ...but `Foo` is actually implemented for the type `&'1 OnlyFooIfStaticRef`, for some specific lifetime `'1`
error: implementation of `Foo` is not general enough
--> $DIR/auto-trait-regions.rs:48:5
|
+LL | auto trait Foo {}
+ | ----------------- trait `Foo` defined here
+...
LL | assert_foo(gen);
- | ^^^^^^^^^^
+ | ^^^^^^^^^^ implementation of `Foo` is not general enough
|
- = note: `Foo` would have to be implemented for the type `A<'0, '1>`, for any two lifetimes `'0` and `'1`
- = note: but `Foo` is actually implemented for the type `A<'_, '2>`, for some specific lifetime `'2`
+ = note: `Foo` would have to be implemented for the type `A<'0, '1>`, for any two lifetimes `'0` and `'1`...
+ = note: ...but `Foo` is actually implemented for the type `A<'_, '2>`, for some specific lifetime `'2`
error: aborting due to 2 previous errors
diff --git a/src/test/ui/hrtb/due-to-where-clause.rs b/src/test/ui/hrtb/due-to-where-clause.rs
new file mode 100644
index 0000000..04e2ddd
--- /dev/null
+++ b/src/test/ui/hrtb/due-to-where-clause.rs
@@ -0,0 +1,16 @@
+// ignore-compare-mode-nll
+// ^ This code works in nll mode.
+
+fn main() {
+ test::<FooS>(&mut 42); //~ ERROR implementation of `Foo` is not general enough
+}
+
+trait Foo<'a> {}
+
+struct FooS<'a> {
+ data: &'a mut u32,
+}
+
+impl<'a, 'b: 'a> Foo<'b> for FooS<'a> {}
+
+fn test<'a, F>(data: &'a mut u32) where F: for<'b> Foo<'b> {}
diff --git a/src/test/ui/hrtb/due-to-where-clause.stderr b/src/test/ui/hrtb/due-to-where-clause.stderr
new file mode 100644
index 0000000..e698584
--- /dev/null
+++ b/src/test/ui/hrtb/due-to-where-clause.stderr
@@ -0,0 +1,17 @@
+error: implementation of `Foo` is not general enough
+ --> $DIR/due-to-where-clause.rs:5:5
+ |
+LL | test::<FooS>(&mut 42);
+ | ^^^^^^^^^^^^ doesn't satisfy where-clause
+...
+LL | trait Foo<'a> {}
+ | ---------------- trait `Foo` defined here
+...
+LL | fn test<'a, F>(data: &'a mut u32) where F: for<'b> Foo<'b> {}
+ | ------------------------------------------------------------- due to a where-clause on `test`...
+ |
+ = note: ...`FooS<'_>` must implement `Foo<'0>`, for any lifetime `'0`...
+ = note: ...but `FooS<'_>` actually implements `Foo<'1>`, for some specific lifetime `'1`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/hrtb/hrtb-cache-issue-54302.stderr b/src/test/ui/hrtb/hrtb-cache-issue-54302.stderr
index 77a5491..003f326 100644
--- a/src/test/ui/hrtb/hrtb-cache-issue-54302.stderr
+++ b/src/test/ui/hrtb/hrtb-cache-issue-54302.stderr
@@ -1,11 +1,14 @@
error: implementation of `Deserialize` is not general enough
--> $DIR/hrtb-cache-issue-54302.rs:19:5
|
+LL | trait Deserialize<'de> {}
+ | ------------------------- trait `Deserialize` defined here
+...
LL | assert_deserialize_owned::<&'static str>();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Deserialize` is not general enough
|
- = note: `&'static str` must implement `Deserialize<'0>`, for any lifetime `'0`
- = note: but `&str` actually implements `Deserialize<'1>`, for some specific lifetime `'1`
+ = note: `&'static str` must implement `Deserialize<'0>`, for any lifetime `'0`...
+ = note: ...but `&str` actually implements `Deserialize<'1>`, for some specific lifetime `'1`
error: aborting due to previous error
diff --git a/src/test/ui/hrtb/issue-30786.migrate.stderr b/src/test/ui/hrtb/issue-30786.migrate.stderr
index e7deca7..c0e3fd3 100644
--- a/src/test/ui/hrtb/issue-30786.migrate.stderr
+++ b/src/test/ui/hrtb/issue-30786.migrate.stderr
@@ -1,11 +1,17 @@
error: implementation of `Stream` is not general enough
--> $DIR/issue-30786.rs:108:22
|
-LL | let map = source.map(|x: &_| x);
- | ^^^
+LL | / pub trait Stream {
+LL | | type Item;
+LL | | fn next(self) -> Option<Self::Item>;
+LL | | }
+ | |_- trait `Stream` defined here
+...
+LL | let map = source.map(|x: &_| x);
+ | ^^^ implementation of `Stream` is not general enough
|
- = note: `Stream` would have to be implemented for the type `&'0 mut Map<Repeat, [closure@$DIR/issue-30786.rs:108:26: 108:35]>`, for any lifetime `'0`
- = note: but `Stream` is actually implemented for the type `&'1 mut Map<Repeat, [closure@$DIR/issue-30786.rs:108:26: 108:35]>`, for some specific lifetime `'1`
+ = note: `Stream` would have to be implemented for the type `&'0 mut Map<Repeat, [closure@$DIR/issue-30786.rs:108:26: 108:35]>`, for any lifetime `'0`...
+ = note: ...but `Stream` is actually implemented for the type `&'1 mut Map<Repeat, [closure@$DIR/issue-30786.rs:108:26: 108:35]>`, for some specific lifetime `'1`
error: aborting due to previous error
diff --git a/src/test/ui/hrtb/issue-30786.nll.stderr b/src/test/ui/hrtb/issue-30786.nll.stderr
index 8614d86..1cfd93e 100644
--- a/src/test/ui/hrtb/issue-30786.nll.stderr
+++ b/src/test/ui/hrtb/issue-30786.nll.stderr
@@ -1,11 +1,11 @@
error: higher-ranked subtype error
- --> $DIR/issue-30786.rs:112:18
+ --> $DIR/issue-30786.rs:113:18
|
LL | let filter = map.filter(|x: &_| true);
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: higher-ranked subtype error
- --> $DIR/issue-30786.rs:114:17
+ --> $DIR/issue-30786.rs:115:17
|
LL | let count = filter.count(); // Assert that we still have a valid stream.
| ^^^^^^^^^^^^^^
diff --git a/src/test/ui/hrtb/issue-30786.rs b/src/test/ui/hrtb/issue-30786.rs
index b9920a1..c42297c 100644
--- a/src/test/ui/hrtb/issue-30786.rs
+++ b/src/test/ui/hrtb/issue-30786.rs
@@ -16,7 +16,7 @@
//[nll]compile-flags: -Z borrowck=mir
-pub trait Stream {
+pub trait Stream { //[migrate]~ NOTE trait `Stream` defined here
type Item;
fn next(self) -> Option<Self::Item>;
}
@@ -109,6 +109,7 @@
//[migrate]~^ ERROR implementation of `Stream` is not general enough
//[migrate]~| NOTE `Stream` would have to be implemented for the type `&'0 mut Map
//[migrate]~| NOTE but `Stream` is actually implemented for the type `&'1
+ //[migrate]~| NOTE implementation of `Stream` is not general enough
let filter = map.filter(|x: &_| true);
//[nll]~^ ERROR higher-ranked subtype error
let count = filter.count(); // Assert that we still have a valid stream.
diff --git a/src/test/ui/hygiene/unpretty-debug.stdout b/src/test/ui/hygiene/unpretty-debug.stdout
index beac4c1..6971873 100644
--- a/src/test/ui/hygiene/unpretty-debug.stdout
+++ b/src/test/ui/hygiene/unpretty-debug.stdout
@@ -13,3 +13,13 @@
fn bar /* 0#0 */() { let x /* 0#0 */ = 1; y /* 0#1 */ + x /* 0#0 */ }
fn y /* 0#0 */() { }
+
+/*
+Expansions:
+0: parent: ExpnId(0), call_site_ctxt: #0, kind: Root
+1: parent: ExpnId(0), call_site_ctxt: #0, kind: Macro(Bang, foo)
+
+SyntaxContexts:
+#0: parent: #0, outer_mark: (ExpnId(0), Opaque)
+#1: parent: #0, outer_mark: (ExpnId(1), SemiTransparent)
+*/
diff --git a/src/test/ui/issues/issue-44415.stderr b/src/test/ui/issues/issue-44415.stderr
deleted file mode 100644
index 8008e53..0000000
--- a/src/test/ui/issues/issue-44415.stderr
+++ /dev/null
@@ -1,28 +0,0 @@
-error[E0391]: cycle detected when const-evaluating + checking `Foo::bytes::{{constant}}#0`
- --> $DIR/issue-44415.rs:6:17
- |
-LL | bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
- | ^^^^^^
- |
-note: ...which requires const-evaluating + checking `Foo::bytes::{{constant}}#0`...
- --> $DIR/issue-44415.rs:6:17
- |
-LL | bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
- | ^^^^^^
-note: ...which requires const-evaluating `Foo::bytes::{{constant}}#0`...
- --> $DIR/issue-44415.rs:6:26
- |
-LL | bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- = note: ...which requires computing layout of `Foo`...
- = note: ...which requires normalizing `ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: All, def_id: None }, value: [u8; _] }`...
- = note: ...which again requires const-evaluating + checking `Foo::bytes::{{constant}}#0`, completing the cycle
-note: cycle used when processing `Foo`
- --> $DIR/issue-44415.rs:5:1
- |
-LL | struct Foo {
- | ^^^^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0391`.
diff --git a/src/test/ui/issues/issue-54302-cases.stderr b/src/test/ui/issues/issue-54302-cases.stderr
index 9863761..3ed2779 100644
--- a/src/test/ui/issues/issue-54302-cases.stderr
+++ b/src/test/ui/issues/issue-54302-cases.stderr
@@ -1,38 +1,58 @@
error: implementation of `Foo` is not general enough
--> $DIR/issue-54302-cases.rs:63:5
|
-LL | <u32 as RefFoo<u32>>::ref_foo(a)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | / trait Foo<'x, T> {
+LL | | fn foo(self) -> &'x T;
+LL | | }
+ | |_- trait `Foo` defined here
+...
+LL | <u32 as RefFoo<u32>>::ref_foo(a)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
|
- = note: `Foo<'static, u32>` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`
- = note: but `Foo<'_, u32>` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1`
+ = note: `Foo<'static, u32>` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`...
+ = note: ...but `Foo<'_, u32>` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1`
error: implementation of `Foo` is not general enough
--> $DIR/issue-54302-cases.rs:69:5
|
-LL | <i32 as RefFoo<i32>>::ref_foo(a)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | / trait Foo<'x, T> {
+LL | | fn foo(self) -> &'x T;
+LL | | }
+ | |_- trait `Foo` defined here
+...
+LL | <i32 as RefFoo<i32>>::ref_foo(a)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
|
- = note: `Foo<'static, i32>` would have to be implemented for the type `&'0 i32`, for any lifetime `'0`
- = note: but `Foo<'_, i32>` is actually implemented for the type `&'1 i32`, for some specific lifetime `'1`
+ = note: `Foo<'static, i32>` would have to be implemented for the type `&'0 i32`, for any lifetime `'0`...
+ = note: ...but `Foo<'_, i32>` is actually implemented for the type `&'1 i32`, for some specific lifetime `'1`
error: implementation of `Foo` is not general enough
--> $DIR/issue-54302-cases.rs:75:5
|
-LL | <u64 as RefFoo<u64>>::ref_foo(a)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | / trait Foo<'x, T> {
+LL | | fn foo(self) -> &'x T;
+LL | | }
+ | |_- trait `Foo` defined here
+...
+LL | <u64 as RefFoo<u64>>::ref_foo(a)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
|
- = note: `Foo<'static, u64>` would have to be implemented for the type `&'0 u64`, for any lifetime `'0`
- = note: but `Foo<'_, u64>` is actually implemented for the type `&'1 u64`, for some specific lifetime `'1`
+ = note: `Foo<'static, u64>` would have to be implemented for the type `&'0 u64`, for any lifetime `'0`...
+ = note: ...but `Foo<'_, u64>` is actually implemented for the type `&'1 u64`, for some specific lifetime `'1`
error: implementation of `Foo` is not general enough
--> $DIR/issue-54302-cases.rs:81:5
|
-LL | <i64 as RefFoo<i64>>::ref_foo(a)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | / trait Foo<'x, T> {
+LL | | fn foo(self) -> &'x T;
+LL | | }
+ | |_- trait `Foo` defined here
+...
+LL | <i64 as RefFoo<i64>>::ref_foo(a)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
|
- = note: `Foo<'static, i64>` would have to be implemented for the type `&'0 i64`, for any lifetime `'0`
- = note: but `Foo<'_, i64>` is actually implemented for the type `&'1 i64`, for some specific lifetime `'1`
+ = note: `Foo<'static, i64>` would have to be implemented for the type `&'0 i64`, for any lifetime `'0`...
+ = note: ...but `Foo<'_, i64>` is actually implemented for the type `&'1 i64`, for some specific lifetime `'1`
error: aborting due to 4 previous errors
diff --git a/src/test/ui/issues/issue-54302.stderr b/src/test/ui/issues/issue-54302.stderr
index c6d0805..1b3f57b 100644
--- a/src/test/ui/issues/issue-54302.stderr
+++ b/src/test/ui/issues/issue-54302.stderr
@@ -1,11 +1,14 @@
error: implementation of `Deserialize` is not general enough
--> $DIR/issue-54302.rs:13:5
|
+LL | trait Deserialize<'de> {}
+ | ------------------------- trait `Deserialize` defined here
+...
LL | assert_deserialize_owned::<&'static str>();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Deserialize` is not general enough
|
- = note: `&'static str` must implement `Deserialize<'0>`, for any lifetime `'0`
- = note: but `&str` actually implements `Deserialize<'1>`, for some specific lifetime `'1`
+ = note: `&'static str` must implement `Deserialize<'0>`, for any lifetime `'0`...
+ = note: ...but `&str` actually implements `Deserialize<'1>`, for some specific lifetime `'1`
error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-55731.stderr b/src/test/ui/issues/issue-55731.stderr
index f25e18e..f44c842 100644
--- a/src/test/ui/issues/issue-55731.stderr
+++ b/src/test/ui/issues/issue-55731.stderr
@@ -1,11 +1,16 @@
error: implementation of `DistributedIteratorMulti` is not general enough
--> $DIR/issue-55731.rs:48:5
|
-LL | multi(Map {
- | ^^^^^
+LL | / trait DistributedIteratorMulti<Source> {
+LL | | type Item;
+LL | | }
+ | |_- trait `DistributedIteratorMulti` defined here
+...
+LL | multi(Map {
+ | ^^^^^ implementation of `DistributedIteratorMulti` is not general enough
|
- = note: `DistributedIteratorMulti<&'0 ()>` would have to be implemented for the type `Cloned<&()>`, for any lifetime `'0`
- = note: but `DistributedIteratorMulti<&'1 ()>` is actually implemented for the type `Cloned<&'1 ()>`, for some specific lifetime `'1`
+ = note: `DistributedIteratorMulti<&'0 ()>` would have to be implemented for the type `Cloned<&()>`, for any lifetime `'0`...
+ = note: ...but `DistributedIteratorMulti<&'1 ()>` is actually implemented for the type `Cloned<&'1 ()>`, for some specific lifetime `'1`
error: aborting due to previous error
diff --git a/src/test/ui/json-short.stderr b/src/test/ui/json-short.stderr
index 86cb2f0..0a1fb56 100644
--- a/src/test/ui/json-short.stderr
+++ b/src/test/ui/json-short.stderr
@@ -15,5 +15,5 @@
"}
{"message":"aborting due to previous error","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to previous error
"}
-{"message":"For more information about this error, try `rustc --explain E0601`.","code":null,"level":"","spans":[],"children":[],"rendered":"For more information about this error, try `rustc --explain E0601`.
+{"message":"For more information about this error, try `rustc --explain E0601`.","code":null,"level":"failure-note","spans":[],"children":[],"rendered":"For more information about this error, try `rustc --explain E0601`.
"}
diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-3.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-3.nll.stderr
index 779e2eb..2ed4d6d 100644
--- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-3.nll.stderr
+++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-3.nll.stderr
@@ -12,11 +12,11 @@
--> $DIR/ex3-both-anon-regions-3.rs:2:5
|
LL | fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) {
- | - - let's call the lifetime of this reference `'1`
+ | - - let's call the lifetime of this reference `'3`
| |
- | let's call the lifetime of this reference `'2`
+ | let's call the lifetime of this reference `'4`
LL | z.push((x,y));
- | ^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
+ | ^^^^^^^^^^^^^ argument requires that `'3` must outlive `'4`
error: aborting due to 2 previous errors
diff --git a/src/test/ui/lint/use_suggestion_json.stderr b/src/test/ui/lint/use_suggestion_json.stderr
index c7c53ab..678c888 100644
--- a/src/test/ui/lint/use_suggestion_json.stderr
+++ b/src/test/ui/lint/use_suggestion_json.stderr
@@ -412,7 +412,7 @@
{
"message": "For more information about this error, try `rustc --explain E0412`.",
"code": null,
- "level": "",
+ "level": "failure-note",
"spans": [],
"children": [],
"rendered": "\u001b[0m\u001b[1mFor more information about this error, try `rustc --explain E0412`.\u001b[0m
diff --git a/src/tools/build-manifest/Cargo.toml b/src/tools/build-manifest/Cargo.toml
index 63ae445..c364479 100644
--- a/src/tools/build-manifest/Cargo.toml
+++ b/src/tools/build-manifest/Cargo.toml
@@ -7,5 +7,3 @@
[dependencies]
toml = "0.5"
serde = { version = "1.0", features = ["derive"] }
-serde_json = "1.0"
-reqwest = "0.9"
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index c2d642b..eab23f3 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -10,10 +10,9 @@
use std::collections::BTreeMap;
use std::env;
use std::fs;
-use std::io::{self, Read, Write, BufRead, BufReader};
+use std::io::{self, Read, Write};
use std::path::{PathBuf, Path};
use std::process::{Command, Stdio};
-use std::collections::HashMap;
static HOSTS: &[&str] = &[
"aarch64-unknown-linux-gnu",
@@ -153,9 +152,6 @@
"x86_64-pc-windows-gnu",
];
-static TOOLSTATE: &str =
- "https://raw.githubusercontent.com/rust-lang-nursery/rust-toolstate/master/history/linux.tsv";
-
#[derive(Serialize)]
#[serde(rename_all = "kebab-case")]
struct Manifest {
@@ -364,7 +360,6 @@
self.lldb_git_commit_hash = self.git_commit_hash("lldb", "x86_64-unknown-linux-gnu");
self.miri_git_commit_hash = self.git_commit_hash("miri", "x86_64-unknown-linux-gnu");
- self.check_toolstate();
self.digest_and_sign();
let manifest = self.build_manifest();
self.write_channel_files(&self.rust_release, &manifest);
@@ -374,36 +369,6 @@
}
}
- /// If a tool does not pass its tests, don't ship it.
- /// Right now, we do this only for Miri.
- fn check_toolstate(&mut self) {
- // Get the toolstate for this rust revision.
- let rev = self.rust_git_commit_hash.as_ref().expect("failed to determine rust git hash");
- let toolstates = reqwest::get(TOOLSTATE).expect("failed to get toolstates");
- let toolstates = BufReader::new(toolstates);
- let toolstate = toolstates.lines()
- .find_map(|line| {
- let line = line.expect("failed to read toolstate lines");
- let mut pieces = line.splitn(2, '\t');
- let commit = pieces.next().expect("malformed toolstate line");
- if commit != rev {
- // Not the right commit.
- return None;
- }
- // Return the 2nd piece, the JSON.
- Some(pieces.next().expect("malformed toolstate line").to_owned())
- })
- .expect("failed to find toolstate for rust commit");
- let toolstate: HashMap<String, String> =
- serde_json::from_str(&toolstate).expect("toolstate is malformed JSON");
- // Mark some tools as missing based on toolstate.
- if toolstate.get("miri").map(|s| &*s as &str) != Some("test-pass") {
- println!("Miri tests are not passing, removing component");
- self.miri_version = None;
- self.miri_git_commit_hash = None;
- }
- }
-
/// Hash all files, compute their signatures, and collect the hashes in `self.digests`.
fn digest_and_sign(&mut self) {
for file in t!(self.input.read_dir()).map(|e| t!(e).path()) {
diff --git a/src/tools/miri b/src/tools/miri
index dd94c7c..130f948 160000
--- a/src/tools/miri
+++ b/src/tools/miri
@@ -1 +1 @@
-Subproject commit dd94c7c5a32be2ee0adeeaf9d46f26f14925797c
+Subproject commit 130f9488d3b861e02c9282b686eec717e30912cf
diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py
index 4060b90..7cf3cc7 100755
--- a/src/tools/publish_toolstate.py
+++ b/src/tools/publish_toolstate.py
@@ -201,7 +201,9 @@
new = s.get(tool, old)
status[os] = new
maintainers = ' '.join('@'+name for name in MAINTAINERS[tool])
- if new > old: # comparing the strings, but they are ordered appropriately!
+ # comparing the strings, but they are ordered appropriately:
+ # "test-pass" > "test-fail" > "build-fail"
+ if new > old:
# things got fixed or at least the status quo improved
changed = True
message += '🎉 {} on {}: {} → {} (cc {}, @rust-lang/infra).\n' \
@@ -213,10 +215,17 @@
.format(tool, os, old, new)
message += '{} (cc {}, @rust-lang/infra).\n' \
.format(title, maintainers)
- # Most tools only create issues for build failures.
- # Other failures can be spurious.
- if new == 'build-fail' or (tool == 'miri' and new == 'test-fail'):
- create_issue_for_status = new
+ # See if we need to create an issue.
+ if tool == 'miri':
+ # Create issue if tests used to pass before. Don't open a *second*
+ # issue when we regress from "test-fail" to "build-fail".
+ if old == 'test-pass':
+ create_issue_for_status = new
+ else:
+ # Create issue if things no longer build.
+ # (No issue for mere test failures to avoid spurious issues.)
+ if new == 'build-fail':
+ create_issue_for_status = new
if create_issue_for_status is not None:
try:
diff --git a/src/tools/rustc-workspace-hack/Cargo.toml b/src/tools/rustc-workspace-hack/Cargo.toml
index d068e1c..930279c 100644
--- a/src/tools/rustc-workspace-hack/Cargo.toml
+++ b/src/tools/rustc-workspace-hack/Cargo.toml
@@ -62,7 +62,6 @@
serde = { version = "1.0.82", features = ['derive'] }
serde_json = { version = "1.0.31", features = ["raw_value"] }
smallvec = { version = "0.6", features = ['union', 'may_dangle'] }
-byteorder = { version = "1.2.7", features = ["i128"] }
[target.'cfg(not(windows))'.dependencies]