Auto merge of #67096 - mark-i-m:fix-rustc-guide-2, r=ehuss
Update rustc-guide
diff --git a/Cargo.lock b/Cargo.lock
index 26727c5..113b7e7 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2055,12 +2055,13 @@
[[package]]
name = "measureme"
-version = "0.4.0"
+version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd21b0e6e1af976b269ce062038fe5e1b9ca2f817ab7a3af09ec4210aebf0d30"
+checksum = "c420bbc064623934620b5ab2dc0cf96451b34163329e82f95e7fa1b7b99a6ac8"
dependencies = [
"byteorder",
"memmap",
+ "parking_lot 0.9.0",
"rustc-hash",
]
@@ -2072,9 +2073,9 @@
[[package]]
name = "memmap"
-version = "0.6.2"
+version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff"
+checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
dependencies = [
"libc",
"winapi 0.3.8",
@@ -2213,6 +2214,7 @@
"rand 0.7.0",
"rustc-workspace-hack",
"rustc_version",
+ "serde",
"shell-escape",
"vergen",
]
@@ -2575,9 +2577,9 @@
[[package]]
name = "polonius-engine"
-version = "0.10.0"
+version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50fa9dbfd0d3d60594da338cfe6f94028433eecae4b11b7e83fd99759227bbfe"
+checksum = "1e478d7c38eb785c6416cbe58df12aa55d7aefa3759b6d3e044b2ed03f423cec"
dependencies = [
"datafrog",
"log",
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 39d7ea9..7ea2bb1 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -810,6 +810,7 @@
!target.contains("emscripten") &&
!target.contains("wasm32") &&
!target.contains("nvptx") &&
+ !target.contains("fortanix") &&
!target.contains("fuchsia") {
Some(self.cc(target))
} else {
diff --git a/src/ci/docker/README.md b/src/ci/docker/README.md
index a2d83ec..872f2c3 100644
--- a/src/ci/docker/README.md
+++ b/src/ci/docker/README.md
@@ -16,6 +16,13 @@
Images will output artifacts in an `obj` dir at the root of a repository.
+**NOTE**: Re-using the same `obj` dir with different docker images with
+the same target triple (e.g. `dist-x86_64-linux` and `dist-various-1`)
+may result in strange linker errors, due shared library versions differing between platforms.
+
+If you encounter any issues when using multiple Docker images, try deleting your `obj` directory
+before running your command.
+
## Filesystem layout
- Each directory, excluding `scripts` and `disabled`, corresponds to a docker image
diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs
index 66d27a2..854942d 100644
--- a/src/libarena/lib.rs
+++ b/src/libarena/lib.rs
@@ -202,53 +202,18 @@
#[inline]
pub fn alloc_from_iter<I: IntoIterator<Item = T>>(&self, iter: I) -> &mut [T] {
assert!(mem::size_of::<T>() != 0);
- let mut iter = iter.into_iter();
- let size_hint = iter.size_hint();
-
- match size_hint {
- (min, Some(max)) if min == max => {
- // We know the exact number of elements the iterator will produce here
- let len = min;
-
- if len == 0 {
- return &mut [];
- }
-
- self.ensure_capacity(len);
-
- let slice = self.ptr.get();
-
- unsafe {
- let mut ptr = self.ptr.get();
- for _ in 0..len {
- // Write into uninitialized memory.
- ptr::write(ptr, iter.next().unwrap());
- // Advance the pointer.
- ptr = ptr.offset(1);
- // Update the pointer per iteration so if `iter.next()` panics
- // we destroy the correct amount
- self.ptr.set(ptr);
- }
- slice::from_raw_parts_mut(slice, len)
- }
- }
- _ => {
- cold_path(move || -> &mut [T] {
- let mut vec: SmallVec<[_; 8]> = iter.collect();
- if vec.is_empty() {
- return &mut [];
- }
- // Move the content to the arena by copying it and then forgetting
- // the content of the SmallVec
- unsafe {
- let len = vec.len();
- let start_ptr = self.alloc_raw_slice(len);
- vec.as_ptr().copy_to_nonoverlapping(start_ptr, len);
- vec.set_len(0);
- slice::from_raw_parts_mut(start_ptr, len)
- }
- })
- }
+ let mut vec: SmallVec<[_; 8]> = iter.into_iter().collect();
+ if vec.is_empty() {
+ return &mut [];
+ }
+ // Move the content to the arena by copying it and then forgetting
+ // the content of the SmallVec
+ unsafe {
+ let len = vec.len();
+ let start_ptr = self.alloc_raw_slice(len);
+ vec.as_ptr().copy_to_nonoverlapping(start_ptr, len);
+ vec.set_len(0);
+ slice::from_raw_parts_mut(start_ptr, len)
}
}
diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs
index 4798769..20248f7 100644
--- a/src/libcore/alloc.rs
+++ b/src/libcore/alloc.rs
@@ -53,7 +53,7 @@
impl Layout {
/// Constructs a `Layout` from a given `size` and `align`,
- /// or returns `LayoutErr` if either of the following conditions
+ /// or returns `LayoutErr` if any of the following conditions
/// are not met:
///
/// * `align` must not be zero,
@@ -137,7 +137,7 @@
#[inline]
pub fn for_value<T: ?Sized>(t: &T) -> Self {
let (size, align) = (mem::size_of_val(t), mem::align_of_val(t));
- // See rationale in `new` for why this us using an unsafe variant below
+ // See rationale in `new` for why this is using an unsafe variant below
debug_assert!(Layout::from_size_align(size, align).is_ok());
unsafe {
Layout::from_size_align_unchecked(size, align)
@@ -196,7 +196,7 @@
// valid.
//
// 2. `len + align - 1` can overflow by at most `align - 1`,
- // so the &-mask wth `!(align - 1)` will ensure that in the
+ // so the &-mask with `!(align - 1)` will ensure that in the
// case of overflow, `len_rounded_up` will itself be 0.
// Thus the returned padding, when added to `len`, yields 0,
// which trivially satisfies the alignment `align`.
diff --git a/src/libcore/bool.rs b/src/libcore/bool.rs
index 617bdd2..1b3c254 100644
--- a/src/libcore/bool.rs
+++ b/src/libcore/bool.rs
@@ -9,12 +9,12 @@
/// ```
/// #![feature(bool_to_option)]
///
- /// assert_eq!(false.then(0), None);
- /// assert_eq!(true.then(0), Some(0));
+ /// assert_eq!(false.then_some(0), None);
+ /// assert_eq!(true.then_some(0), Some(0));
/// ```
#[unstable(feature = "bool_to_option", issue = "64260")]
#[inline]
- pub fn then<T>(self, t: T) -> Option<T> {
+ pub fn then_some<T>(self, t: T) -> Option<T> {
if self {
Some(t)
} else {
@@ -29,12 +29,12 @@
/// ```
/// #![feature(bool_to_option)]
///
- /// assert_eq!(false.then_with(|| 0), None);
- /// assert_eq!(true.then_with(|| 0), Some(0));
+ /// assert_eq!(false.then(|| 0), None);
+ /// assert_eq!(true.then(|| 0), Some(0));
/// ```
#[unstable(feature = "bool_to_option", issue = "64260")]
#[inline]
- pub fn then_with<T, F: FnOnce() -> T>(self, f: F) -> Option<T> {
+ pub fn then<T, F: FnOnce() -> T>(self, f: F) -> Option<T> {
if self {
Some(f())
} else {
diff --git a/src/libcore/convert.rs b/src/libcore/convert/mod.rs
similarity index 98%
rename from src/libcore/convert.rs
rename to src/libcore/convert/mod.rs
index 08802b3..5414d9a 100644
--- a/src/libcore/convert.rs
+++ b/src/libcore/convert/mod.rs
@@ -40,6 +40,11 @@
#![stable(feature = "rust1", since = "1.0.0")]
+mod num;
+
+#[unstable(feature = "convert_float_to_int", issue = "67057")]
+pub use num::FloatToInt;
+
/// The identity function.
///
/// Two things are important to note about this function:
@@ -562,6 +567,7 @@
///
/// [#64715]: https://github.com/rust-lang/rust/issues/64715
#[stable(feature = "convert_infallible", since = "1.34.0")]
+#[allow(unused_attributes)] // FIXME(#58633): do a principled fix instead.
#[rustc_reservation_impl = "permitting this impl would forbid us from adding \
`impl<T> From<!> for T` later; see rust-lang/rust#64715 for details"]
impl<T> From<!> for T {
diff --git a/src/libcore/convert/num.rs b/src/libcore/convert/num.rs
new file mode 100644
index 0000000..0877dac
--- /dev/null
+++ b/src/libcore/convert/num.rs
@@ -0,0 +1,369 @@
+use super::{From, TryFrom};
+use crate::num::TryFromIntError;
+
+mod private {
+ /// This trait being unreachable from outside the crate
+ /// prevents other implementations of the `FloatToInt` trait,
+ /// which allows potentially adding more trait methods after the trait is `#[stable]`.
+ #[unstable(feature = "convert_float_to_int", issue = "67057")]
+ pub trait Sealed {}
+}
+
+/// Supporting trait for inherent methods of `f32` and `f64` such as `round_unchecked_to`.
+/// Typically doesn’t need to be used directly.
+#[unstable(feature = "convert_float_to_int", issue = "67057")]
+pub trait FloatToInt<Int>: private::Sealed + Sized {
+ #[cfg(not(bootstrap))]
+ #[unstable(feature = "float_approx_unchecked_to", issue = "67058")]
+ #[doc(hidden)]
+ unsafe fn approx_unchecked(self) -> Int;
+}
+
+macro_rules! impl_float_to_int {
+ ( $Float: ident => $( $Int: ident )+ ) => {
+ #[unstable(feature = "convert_float_to_int", issue = "67057")]
+ impl private::Sealed for $Float {}
+ $(
+ #[unstable(feature = "convert_float_to_int", issue = "67057")]
+ impl FloatToInt<$Int> for $Float {
+ #[cfg(not(bootstrap))]
+ #[doc(hidden)]
+ #[inline]
+ unsafe fn approx_unchecked(self) -> $Int {
+ crate::intrinsics::float_to_int_approx_unchecked(self)
+ }
+ }
+ )+
+ }
+}
+
+impl_float_to_int!(f32 => u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize);
+impl_float_to_int!(f64 => u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize);
+
+// Conversion traits for primitive integer and float types
+// Conversions T -> T are covered by a blanket impl and therefore excluded
+// Some conversions from and to usize/isize are not implemented due to portability concerns
+macro_rules! impl_from {
+ ($Small: ty, $Large: ty, #[$attr:meta], $doc: expr) => {
+ #[$attr]
+ #[doc = $doc]
+ impl From<$Small> for $Large {
+ #[inline]
+ fn from(small: $Small) -> $Large {
+ small as $Large
+ }
+ }
+ };
+ ($Small: ty, $Large: ty, #[$attr:meta]) => {
+ impl_from!($Small,
+ $Large,
+ #[$attr],
+ concat!("Converts `",
+ stringify!($Small),
+ "` to `",
+ stringify!($Large),
+ "` losslessly."));
+ }
+}
+
+macro_rules! impl_from_bool {
+ ($target: ty, #[$attr:meta]) => {
+ impl_from!(bool, $target, #[$attr], concat!("Converts a `bool` to a `",
+ stringify!($target), "`. The resulting value is `0` for `false` and `1` for `true`
+values.
+
+# Examples
+
+```
+assert_eq!(", stringify!($target), "::from(true), 1);
+assert_eq!(", stringify!($target), "::from(false), 0);
+```"));
+ };
+}
+
+// Bool -> Any
+impl_from_bool! { u8, #[stable(feature = "from_bool", since = "1.28.0")] }
+impl_from_bool! { u16, #[stable(feature = "from_bool", since = "1.28.0")] }
+impl_from_bool! { u32, #[stable(feature = "from_bool", since = "1.28.0")] }
+impl_from_bool! { u64, #[stable(feature = "from_bool", since = "1.28.0")] }
+impl_from_bool! { u128, #[stable(feature = "from_bool", since = "1.28.0")] }
+impl_from_bool! { usize, #[stable(feature = "from_bool", since = "1.28.0")] }
+impl_from_bool! { i8, #[stable(feature = "from_bool", since = "1.28.0")] }
+impl_from_bool! { i16, #[stable(feature = "from_bool", since = "1.28.0")] }
+impl_from_bool! { i32, #[stable(feature = "from_bool", since = "1.28.0")] }
+impl_from_bool! { i64, #[stable(feature = "from_bool", since = "1.28.0")] }
+impl_from_bool! { i128, #[stable(feature = "from_bool", since = "1.28.0")] }
+impl_from_bool! { isize, #[stable(feature = "from_bool", since = "1.28.0")] }
+
+// Unsigned -> Unsigned
+impl_from! { u8, u16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { u8, u32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { u8, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { u8, u128, #[stable(feature = "i128", since = "1.26.0")] }
+impl_from! { u8, usize, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { u16, u32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { u16, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { u16, u128, #[stable(feature = "i128", since = "1.26.0")] }
+impl_from! { u32, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { u32, u128, #[stable(feature = "i128", since = "1.26.0")] }
+impl_from! { u64, u128, #[stable(feature = "i128", since = "1.26.0")] }
+
+// Signed -> Signed
+impl_from! { i8, i16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { i8, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { i8, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { i8, i128, #[stable(feature = "i128", since = "1.26.0")] }
+impl_from! { i8, isize, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { i16, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { i16, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { i16, i128, #[stable(feature = "i128", since = "1.26.0")] }
+impl_from! { i32, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { i32, i128, #[stable(feature = "i128", since = "1.26.0")] }
+impl_from! { i64, i128, #[stable(feature = "i128", since = "1.26.0")] }
+
+// Unsigned -> Signed
+impl_from! { u8, i16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { u8, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { u8, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { u8, i128, #[stable(feature = "i128", since = "1.26.0")] }
+impl_from! { u16, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { u16, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { u16, i128, #[stable(feature = "i128", since = "1.26.0")] }
+impl_from! { u32, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { u32, i128, #[stable(feature = "i128", since = "1.26.0")] }
+impl_from! { u64, i128, #[stable(feature = "i128", since = "1.26.0")] }
+
+// The C99 standard defines bounds on INTPTR_MIN, INTPTR_MAX, and UINTPTR_MAX
+// which imply that pointer-sized integers must be at least 16 bits:
+// https://port70.net/~nsz/c/c99/n1256.html#7.18.2.4
+impl_from! { u16, usize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")] }
+impl_from! { u8, isize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")] }
+impl_from! { i16, isize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")] }
+
+// RISC-V defines the possibility of a 128-bit address space (RV128).
+
+// CHERI proposes 256-bit “capabilities”. Unclear if this would be relevant to usize/isize.
+// https://www.cl.cam.ac.uk/research/security/ctsrd/pdfs/20171017a-cheri-poster.pdf
+// http://www.csl.sri.com/users/neumann/2012resolve-cheri.pdf
+
+
+// Note: integers can only be represented with full precision in a float if
+// they fit in the significand, which is 24 bits in f32 and 53 bits in f64.
+// Lossy float conversions are not implemented at this time.
+
+// Signed -> Float
+impl_from! { i8, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
+impl_from! { i8, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
+impl_from! { i16, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
+impl_from! { i16, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
+impl_from! { i32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
+
+// Unsigned -> Float
+impl_from! { u8, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
+impl_from! { u8, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
+impl_from! { u16, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
+impl_from! { u16, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
+impl_from! { u32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
+
+// Float -> Float
+impl_from! { f32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
+
+// no possible bounds violation
+macro_rules! try_from_unbounded {
+ ($source:ty, $($target:ty),*) => {$(
+ #[stable(feature = "try_from", since = "1.34.0")]
+ impl TryFrom<$source> for $target {
+ type Error = TryFromIntError;
+
+ /// Try to create the target number type from a source
+ /// number type. This returns an error if the source value
+ /// is outside of the range of the target type.
+ #[inline]
+ fn try_from(value: $source) -> Result<Self, Self::Error> {
+ Ok(value as $target)
+ }
+ }
+ )*}
+}
+
+// only negative bounds
+macro_rules! try_from_lower_bounded {
+ ($source:ty, $($target:ty),*) => {$(
+ #[stable(feature = "try_from", since = "1.34.0")]
+ impl TryFrom<$source> for $target {
+ type Error = TryFromIntError;
+
+ /// Try to create the target number type from a source
+ /// number type. This returns an error if the source value
+ /// is outside of the range of the target type.
+ #[inline]
+ fn try_from(u: $source) -> Result<$target, TryFromIntError> {
+ if u >= 0 {
+ Ok(u as $target)
+ } else {
+ Err(TryFromIntError(()))
+ }
+ }
+ }
+ )*}
+}
+
+// unsigned to signed (only positive bound)
+macro_rules! try_from_upper_bounded {
+ ($source:ty, $($target:ty),*) => {$(
+ #[stable(feature = "try_from", since = "1.34.0")]
+ impl TryFrom<$source> for $target {
+ type Error = TryFromIntError;
+
+ /// Try to create the target number type from a source
+ /// number type. This returns an error if the source value
+ /// is outside of the range of the target type.
+ #[inline]
+ fn try_from(u: $source) -> Result<$target, TryFromIntError> {
+ if u > (<$target>::max_value() as $source) {
+ Err(TryFromIntError(()))
+ } else {
+ Ok(u as $target)
+ }
+ }
+ }
+ )*}
+}
+
+// all other cases
+macro_rules! try_from_both_bounded {
+ ($source:ty, $($target:ty),*) => {$(
+ #[stable(feature = "try_from", since = "1.34.0")]
+ impl TryFrom<$source> for $target {
+ type Error = TryFromIntError;
+
+ /// Try to create the target number type from a source
+ /// number type. This returns an error if the source value
+ /// is outside of the range of the target type.
+ #[inline]
+ fn try_from(u: $source) -> Result<$target, TryFromIntError> {
+ let min = <$target>::min_value() as $source;
+ let max = <$target>::max_value() as $source;
+ if u < min || u > max {
+ Err(TryFromIntError(()))
+ } else {
+ Ok(u as $target)
+ }
+ }
+ }
+ )*}
+}
+
+macro_rules! rev {
+ ($mac:ident, $source:ty, $($target:ty),*) => {$(
+ $mac!($target, $source);
+ )*}
+}
+
+// intra-sign conversions
+try_from_upper_bounded!(u16, u8);
+try_from_upper_bounded!(u32, u16, u8);
+try_from_upper_bounded!(u64, u32, u16, u8);
+try_from_upper_bounded!(u128, u64, u32, u16, u8);
+
+try_from_both_bounded!(i16, i8);
+try_from_both_bounded!(i32, i16, i8);
+try_from_both_bounded!(i64, i32, i16, i8);
+try_from_both_bounded!(i128, i64, i32, i16, i8);
+
+// unsigned-to-signed
+try_from_upper_bounded!(u8, i8);
+try_from_upper_bounded!(u16, i8, i16);
+try_from_upper_bounded!(u32, i8, i16, i32);
+try_from_upper_bounded!(u64, i8, i16, i32, i64);
+try_from_upper_bounded!(u128, i8, i16, i32, i64, i128);
+
+// signed-to-unsigned
+try_from_lower_bounded!(i8, u8, u16, u32, u64, u128);
+try_from_lower_bounded!(i16, u16, u32, u64, u128);
+try_from_lower_bounded!(i32, u32, u64, u128);
+try_from_lower_bounded!(i64, u64, u128);
+try_from_lower_bounded!(i128, u128);
+try_from_both_bounded!(i16, u8);
+try_from_both_bounded!(i32, u16, u8);
+try_from_both_bounded!(i64, u32, u16, u8);
+try_from_both_bounded!(i128, u64, u32, u16, u8);
+
+// usize/isize
+try_from_upper_bounded!(usize, isize);
+try_from_lower_bounded!(isize, usize);
+
+#[cfg(target_pointer_width = "16")]
+mod ptr_try_from_impls {
+ use super::TryFromIntError;
+ use crate::convert::TryFrom;
+
+ try_from_upper_bounded!(usize, u8);
+ try_from_unbounded!(usize, u16, u32, u64, u128);
+ try_from_upper_bounded!(usize, i8, i16);
+ try_from_unbounded!(usize, i32, i64, i128);
+
+ try_from_both_bounded!(isize, u8);
+ try_from_lower_bounded!(isize, u16, u32, u64, u128);
+ try_from_both_bounded!(isize, i8);
+ try_from_unbounded!(isize, i16, i32, i64, i128);
+
+ rev!(try_from_upper_bounded, usize, u32, u64, u128);
+ rev!(try_from_lower_bounded, usize, i8, i16);
+ rev!(try_from_both_bounded, usize, i32, i64, i128);
+
+ rev!(try_from_upper_bounded, isize, u16, u32, u64, u128);
+ rev!(try_from_both_bounded, isize, i32, i64, i128);
+}
+
+#[cfg(target_pointer_width = "32")]
+mod ptr_try_from_impls {
+ use super::TryFromIntError;
+ use crate::convert::TryFrom;
+
+ try_from_upper_bounded!(usize, u8, u16);
+ try_from_unbounded!(usize, u32, u64, u128);
+ try_from_upper_bounded!(usize, i8, i16, i32);
+ try_from_unbounded!(usize, i64, i128);
+
+ try_from_both_bounded!(isize, u8, u16);
+ try_from_lower_bounded!(isize, u32, u64, u128);
+ try_from_both_bounded!(isize, i8, i16);
+ try_from_unbounded!(isize, i32, i64, i128);
+
+ rev!(try_from_unbounded, usize, u32);
+ rev!(try_from_upper_bounded, usize, u64, u128);
+ rev!(try_from_lower_bounded, usize, i8, i16, i32);
+ rev!(try_from_both_bounded, usize, i64, i128);
+
+ rev!(try_from_unbounded, isize, u16);
+ rev!(try_from_upper_bounded, isize, u32, u64, u128);
+ rev!(try_from_unbounded, isize, i32);
+ rev!(try_from_both_bounded, isize, i64, i128);
+}
+
+#[cfg(target_pointer_width = "64")]
+mod ptr_try_from_impls {
+ use super::TryFromIntError;
+ use crate::convert::TryFrom;
+
+ try_from_upper_bounded!(usize, u8, u16, u32);
+ try_from_unbounded!(usize, u64, u128);
+ try_from_upper_bounded!(usize, i8, i16, i32, i64);
+ try_from_unbounded!(usize, i128);
+
+ try_from_both_bounded!(isize, u8, u16, u32);
+ try_from_lower_bounded!(isize, u64, u128);
+ try_from_both_bounded!(isize, i8, i16, i32);
+ try_from_unbounded!(isize, i64, i128);
+
+ rev!(try_from_unbounded, usize, u32, u64);
+ rev!(try_from_upper_bounded, usize, u128);
+ rev!(try_from_lower_bounded, usize, i8, i16, i32, i64);
+ rev!(try_from_both_bounded, usize, i128);
+
+ rev!(try_from_unbounded, isize, u16, u32);
+ rev!(try_from_upper_bounded, isize, u64, u128);
+ rev!(try_from_unbounded, isize, i32, i64);
+ rev!(try_from_both_bounded, isize, i128);
+}
diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs
index 19928f3..18aae59 100644
--- a/src/libcore/intrinsics.rs
+++ b/src/libcore/intrinsics.rs
@@ -1144,6 +1144,11 @@
/// May assume inputs are finite.
pub fn frem_fast<T>(a: T, b: T) -> T;
+ /// Convert with LLVM’s fptoui/fptosi, which may return undef for values out of range
+ /// https://github.com/rust-lang/rust/issues/10184
+ #[cfg(not(bootstrap))]
+ pub fn float_to_int_approx_unchecked<Float, Int>(value: Float) -> Int;
+
/// Returns the number of bits set in an integer type `T`
pub fn ctpop<T>(x: T) -> T;
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index 188ea1a..8a514f1 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -102,6 +102,7 @@
#![feature(staged_api)]
#![feature(std_internals)]
#![feature(stmt_expr_attributes)]
+#![cfg_attr(not(bootstrap), feature(track_caller))]
#![feature(transparent_unions)]
#![feature(unboxed_closures)]
#![feature(unsized_locals)]
diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs
index 913c0f9..ac06f95 100644
--- a/src/libcore/num/f32.rs
+++ b/src/libcore/num/f32.rs
@@ -7,9 +7,10 @@
#![stable(feature = "rust1", since = "1.0.0")]
+#[cfg(not(bootstrap))]
+use crate::convert::FloatToInt;
#[cfg(not(test))]
use crate::intrinsics;
-
use crate::mem;
use crate::num::FpCategory;
@@ -400,6 +401,35 @@
intrinsics::minnumf32(self, other)
}
+ /// Rounds toward zero and converts to any primitive integer type,
+ /// assuming that the value is finite and fits in that type.
+ ///
+ /// ```
+ /// #![feature(float_approx_unchecked_to)]
+ ///
+ /// let value = 4.6_f32;
+ /// let rounded = unsafe { value.approx_unchecked_to::<u16>() };
+ /// assert_eq!(rounded, 4);
+ ///
+ /// let value = -128.9_f32;
+ /// let rounded = unsafe { value.approx_unchecked_to::<i8>() };
+ /// assert_eq!(rounded, std::i8::MIN);
+ /// ```
+ ///
+ /// # Safety
+ ///
+ /// The value must:
+ ///
+ /// * Not be `NaN`
+ /// * Not be infinite
+ /// * Be representable in the return type `Int`, after truncating off its fractional part
+ #[cfg(not(bootstrap))]
+ #[unstable(feature = "float_approx_unchecked_to", issue = "67058")]
+ #[inline]
+ pub unsafe fn approx_unchecked_to<Int>(self) -> Int where Self: FloatToInt<Int> {
+ FloatToInt::<Int>::approx_unchecked(self)
+ }
+
/// Raw transmutation to `u32`.
///
/// This is currently identical to `transmute::<f32, u32>(self)` on all platforms.
diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs
index 6ca830b..794f77f 100644
--- a/src/libcore/num/f64.rs
+++ b/src/libcore/num/f64.rs
@@ -7,9 +7,10 @@
#![stable(feature = "rust1", since = "1.0.0")]
+#[cfg(not(bootstrap))]
+use crate::convert::FloatToInt;
#[cfg(not(test))]
use crate::intrinsics;
-
use crate::mem;
use crate::num::FpCategory;
@@ -413,6 +414,35 @@
intrinsics::minnumf64(self, other)
}
+ /// Rounds toward zero and converts to any primitive integer type,
+ /// assuming that the value is finite and fits in that type.
+ ///
+ /// ```
+ /// #![feature(float_approx_unchecked_to)]
+ ///
+ /// let value = 4.6_f32;
+ /// let rounded = unsafe { value.approx_unchecked_to::<u16>() };
+ /// assert_eq!(rounded, 4);
+ ///
+ /// let value = -128.9_f32;
+ /// let rounded = unsafe { value.approx_unchecked_to::<i8>() };
+ /// assert_eq!(rounded, std::i8::MIN);
+ /// ```
+ ///
+ /// # Safety
+ ///
+ /// The value must:
+ ///
+ /// * Not be `NaN`
+ /// * Not be infinite
+ /// * Be representable in the return type `Int`, after truncating off its fractional part
+ #[cfg(not(bootstrap))]
+ #[unstable(feature = "float_approx_unchecked_to", issue = "67058")]
+ #[inline]
+ pub unsafe fn approx_unchecked_to<Int>(self) -> Int where Self: FloatToInt<Int> {
+ FloatToInt::<Int>::approx_unchecked(self)
+ }
+
/// Raw transmutation to `u64`.
///
/// This is currently identical to `transmute::<f64, u64>(self)` on all platforms.
diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs
index 4313248..585f144 100644
--- a/src/libcore/num/mod.rs
+++ b/src/libcore/num/mod.rs
@@ -4,7 +4,6 @@
#![stable(feature = "rust1", since = "1.0.0")]
-use crate::convert::TryFrom;
use crate::fmt;
use crate::intrinsics;
use crate::mem;
@@ -4701,7 +4700,7 @@
/// The error type returned when a checked integral type conversion fails.
#[stable(feature = "try_from", since = "1.34.0")]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub struct TryFromIntError(());
+pub struct TryFromIntError(pub(crate) ());
impl TryFromIntError {
#[unstable(feature = "int_error_internals",
@@ -4728,206 +4727,6 @@
}
}
-// no possible bounds violation
-macro_rules! try_from_unbounded {
- ($source:ty, $($target:ty),*) => {$(
- #[stable(feature = "try_from", since = "1.34.0")]
- impl TryFrom<$source> for $target {
- type Error = TryFromIntError;
-
- /// Try to create the target number type from a source
- /// number type. This returns an error if the source value
- /// is outside of the range of the target type.
- #[inline]
- fn try_from(value: $source) -> Result<Self, Self::Error> {
- Ok(value as $target)
- }
- }
- )*}
-}
-
-// only negative bounds
-macro_rules! try_from_lower_bounded {
- ($source:ty, $($target:ty),*) => {$(
- #[stable(feature = "try_from", since = "1.34.0")]
- impl TryFrom<$source> for $target {
- type Error = TryFromIntError;
-
- /// Try to create the target number type from a source
- /// number type. This returns an error if the source value
- /// is outside of the range of the target type.
- #[inline]
- fn try_from(u: $source) -> Result<$target, TryFromIntError> {
- if u >= 0 {
- Ok(u as $target)
- } else {
- Err(TryFromIntError(()))
- }
- }
- }
- )*}
-}
-
-// unsigned to signed (only positive bound)
-macro_rules! try_from_upper_bounded {
- ($source:ty, $($target:ty),*) => {$(
- #[stable(feature = "try_from", since = "1.34.0")]
- impl TryFrom<$source> for $target {
- type Error = TryFromIntError;
-
- /// Try to create the target number type from a source
- /// number type. This returns an error if the source value
- /// is outside of the range of the target type.
- #[inline]
- fn try_from(u: $source) -> Result<$target, TryFromIntError> {
- if u > (<$target>::max_value() as $source) {
- Err(TryFromIntError(()))
- } else {
- Ok(u as $target)
- }
- }
- }
- )*}
-}
-
-// all other cases
-macro_rules! try_from_both_bounded {
- ($source:ty, $($target:ty),*) => {$(
- #[stable(feature = "try_from", since = "1.34.0")]
- impl TryFrom<$source> for $target {
- type Error = TryFromIntError;
-
- /// Try to create the target number type from a source
- /// number type. This returns an error if the source value
- /// is outside of the range of the target type.
- #[inline]
- fn try_from(u: $source) -> Result<$target, TryFromIntError> {
- let min = <$target>::min_value() as $source;
- let max = <$target>::max_value() as $source;
- if u < min || u > max {
- Err(TryFromIntError(()))
- } else {
- Ok(u as $target)
- }
- }
- }
- )*}
-}
-
-macro_rules! rev {
- ($mac:ident, $source:ty, $($target:ty),*) => {$(
- $mac!($target, $source);
- )*}
-}
-
-// intra-sign conversions
-try_from_upper_bounded!(u16, u8);
-try_from_upper_bounded!(u32, u16, u8);
-try_from_upper_bounded!(u64, u32, u16, u8);
-try_from_upper_bounded!(u128, u64, u32, u16, u8);
-
-try_from_both_bounded!(i16, i8);
-try_from_both_bounded!(i32, i16, i8);
-try_from_both_bounded!(i64, i32, i16, i8);
-try_from_both_bounded!(i128, i64, i32, i16, i8);
-
-// unsigned-to-signed
-try_from_upper_bounded!(u8, i8);
-try_from_upper_bounded!(u16, i8, i16);
-try_from_upper_bounded!(u32, i8, i16, i32);
-try_from_upper_bounded!(u64, i8, i16, i32, i64);
-try_from_upper_bounded!(u128, i8, i16, i32, i64, i128);
-
-// signed-to-unsigned
-try_from_lower_bounded!(i8, u8, u16, u32, u64, u128);
-try_from_lower_bounded!(i16, u16, u32, u64, u128);
-try_from_lower_bounded!(i32, u32, u64, u128);
-try_from_lower_bounded!(i64, u64, u128);
-try_from_lower_bounded!(i128, u128);
-try_from_both_bounded!(i16, u8);
-try_from_both_bounded!(i32, u16, u8);
-try_from_both_bounded!(i64, u32, u16, u8);
-try_from_both_bounded!(i128, u64, u32, u16, u8);
-
-// usize/isize
-try_from_upper_bounded!(usize, isize);
-try_from_lower_bounded!(isize, usize);
-
-#[cfg(target_pointer_width = "16")]
-mod ptr_try_from_impls {
- use super::TryFromIntError;
- use crate::convert::TryFrom;
-
- try_from_upper_bounded!(usize, u8);
- try_from_unbounded!(usize, u16, u32, u64, u128);
- try_from_upper_bounded!(usize, i8, i16);
- try_from_unbounded!(usize, i32, i64, i128);
-
- try_from_both_bounded!(isize, u8);
- try_from_lower_bounded!(isize, u16, u32, u64, u128);
- try_from_both_bounded!(isize, i8);
- try_from_unbounded!(isize, i16, i32, i64, i128);
-
- rev!(try_from_upper_bounded, usize, u32, u64, u128);
- rev!(try_from_lower_bounded, usize, i8, i16);
- rev!(try_from_both_bounded, usize, i32, i64, i128);
-
- rev!(try_from_upper_bounded, isize, u16, u32, u64, u128);
- rev!(try_from_both_bounded, isize, i32, i64, i128);
-}
-
-#[cfg(target_pointer_width = "32")]
-mod ptr_try_from_impls {
- use super::TryFromIntError;
- use crate::convert::TryFrom;
-
- try_from_upper_bounded!(usize, u8, u16);
- try_from_unbounded!(usize, u32, u64, u128);
- try_from_upper_bounded!(usize, i8, i16, i32);
- try_from_unbounded!(usize, i64, i128);
-
- try_from_both_bounded!(isize, u8, u16);
- try_from_lower_bounded!(isize, u32, u64, u128);
- try_from_both_bounded!(isize, i8, i16);
- try_from_unbounded!(isize, i32, i64, i128);
-
- rev!(try_from_unbounded, usize, u32);
- rev!(try_from_upper_bounded, usize, u64, u128);
- rev!(try_from_lower_bounded, usize, i8, i16, i32);
- rev!(try_from_both_bounded, usize, i64, i128);
-
- rev!(try_from_unbounded, isize, u16);
- rev!(try_from_upper_bounded, isize, u32, u64, u128);
- rev!(try_from_unbounded, isize, i32);
- rev!(try_from_both_bounded, isize, i64, i128);
-}
-
-#[cfg(target_pointer_width = "64")]
-mod ptr_try_from_impls {
- use super::TryFromIntError;
- use crate::convert::TryFrom;
-
- try_from_upper_bounded!(usize, u8, u16, u32);
- try_from_unbounded!(usize, u64, u128);
- try_from_upper_bounded!(usize, i8, i16, i32, i64);
- try_from_unbounded!(usize, i128);
-
- try_from_both_bounded!(isize, u8, u16, u32);
- try_from_lower_bounded!(isize, u64, u128);
- try_from_both_bounded!(isize, i8, i16, i32);
- try_from_unbounded!(isize, i64, i128);
-
- rev!(try_from_unbounded, usize, u32, u64);
- rev!(try_from_upper_bounded, usize, u128);
- rev!(try_from_lower_bounded, usize, i8, i16, i32, i64);
- rev!(try_from_both_bounded, usize, i128);
-
- rev!(try_from_unbounded, isize, u16, u32);
- rev!(try_from_upper_bounded, isize, u64, u128);
- rev!(try_from_unbounded, isize, i32, i64);
- rev!(try_from_both_bounded, isize, i128);
-}
-
#[doc(hidden)]
trait FromStrRadixHelper: PartialOrd + Copy {
fn min_value() -> Self;
@@ -5110,131 +4909,3 @@
#[stable(feature = "rust1", since = "1.0.0")]
pub use crate::num::dec2flt::ParseFloatError;
-
-// Conversion traits for primitive integer and float types
-// Conversions T -> T are covered by a blanket impl and therefore excluded
-// Some conversions from and to usize/isize are not implemented due to portability concerns
-macro_rules! impl_from {
- ($Small: ty, $Large: ty, #[$attr:meta], $doc: expr) => {
- #[$attr]
- #[doc = $doc]
- impl From<$Small> for $Large {
- #[inline]
- fn from(small: $Small) -> $Large {
- small as $Large
- }
- }
- };
- ($Small: ty, $Large: ty, #[$attr:meta]) => {
- impl_from!($Small,
- $Large,
- #[$attr],
- concat!("Converts `",
- stringify!($Small),
- "` to `",
- stringify!($Large),
- "` losslessly."));
- }
-}
-
-macro_rules! impl_from_bool {
- ($target: ty, #[$attr:meta]) => {
- impl_from!(bool, $target, #[$attr], concat!("Converts a `bool` to a `",
- stringify!($target), "`. The resulting value is `0` for `false` and `1` for `true`
-values.
-
-# Examples
-
-```
-assert_eq!(", stringify!($target), "::from(true), 1);
-assert_eq!(", stringify!($target), "::from(false), 0);
-```"));
- };
-}
-
-// Bool -> Any
-impl_from_bool! { u8, #[stable(feature = "from_bool", since = "1.28.0")] }
-impl_from_bool! { u16, #[stable(feature = "from_bool", since = "1.28.0")] }
-impl_from_bool! { u32, #[stable(feature = "from_bool", since = "1.28.0")] }
-impl_from_bool! { u64, #[stable(feature = "from_bool", since = "1.28.0")] }
-impl_from_bool! { u128, #[stable(feature = "from_bool", since = "1.28.0")] }
-impl_from_bool! { usize, #[stable(feature = "from_bool", since = "1.28.0")] }
-impl_from_bool! { i8, #[stable(feature = "from_bool", since = "1.28.0")] }
-impl_from_bool! { i16, #[stable(feature = "from_bool", since = "1.28.0")] }
-impl_from_bool! { i32, #[stable(feature = "from_bool", since = "1.28.0")] }
-impl_from_bool! { i64, #[stable(feature = "from_bool", since = "1.28.0")] }
-impl_from_bool! { i128, #[stable(feature = "from_bool", since = "1.28.0")] }
-impl_from_bool! { isize, #[stable(feature = "from_bool", since = "1.28.0")] }
-
-// Unsigned -> Unsigned
-impl_from! { u8, u16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { u8, u32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { u8, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { u8, u128, #[stable(feature = "i128", since = "1.26.0")] }
-impl_from! { u8, usize, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { u16, u32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { u16, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { u16, u128, #[stable(feature = "i128", since = "1.26.0")] }
-impl_from! { u32, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { u32, u128, #[stable(feature = "i128", since = "1.26.0")] }
-impl_from! { u64, u128, #[stable(feature = "i128", since = "1.26.0")] }
-
-// Signed -> Signed
-impl_from! { i8, i16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { i8, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { i8, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { i8, i128, #[stable(feature = "i128", since = "1.26.0")] }
-impl_from! { i8, isize, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { i16, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { i16, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { i16, i128, #[stable(feature = "i128", since = "1.26.0")] }
-impl_from! { i32, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { i32, i128, #[stable(feature = "i128", since = "1.26.0")] }
-impl_from! { i64, i128, #[stable(feature = "i128", since = "1.26.0")] }
-
-// Unsigned -> Signed
-impl_from! { u8, i16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { u8, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { u8, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { u8, i128, #[stable(feature = "i128", since = "1.26.0")] }
-impl_from! { u16, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { u16, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { u16, i128, #[stable(feature = "i128", since = "1.26.0")] }
-impl_from! { u32, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { u32, i128, #[stable(feature = "i128", since = "1.26.0")] }
-impl_from! { u64, i128, #[stable(feature = "i128", since = "1.26.0")] }
-
-// The C99 standard defines bounds on INTPTR_MIN, INTPTR_MAX, and UINTPTR_MAX
-// which imply that pointer-sized integers must be at least 16 bits:
-// https://port70.net/~nsz/c/c99/n1256.html#7.18.2.4
-impl_from! { u16, usize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")] }
-impl_from! { u8, isize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")] }
-impl_from! { i16, isize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")] }
-
-// RISC-V defines the possibility of a 128-bit address space (RV128).
-
-// CHERI proposes 256-bit “capabilities”. Unclear if this would be relevant to usize/isize.
-// https://www.cl.cam.ac.uk/research/security/ctsrd/pdfs/20171017a-cheri-poster.pdf
-// http://www.csl.sri.com/users/neumann/2012resolve-cheri.pdf
-
-
-// Note: integers can only be represented with full precision in a float if
-// they fit in the significand, which is 24 bits in f32 and 53 bits in f64.
-// Lossy float conversions are not implemented at this time.
-
-// Signed -> Float
-impl_from! { i8, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
-impl_from! { i8, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
-impl_from! { i16, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
-impl_from! { i16, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
-impl_from! { i32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
-
-// Unsigned -> Float
-impl_from! { u8, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
-impl_from! { u8, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
-impl_from! { u16, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
-impl_from! { u16, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
-impl_from! { u32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
-
-// Float -> Float
-impl_from! { f32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
diff --git a/src/libcore/panic.rs b/src/libcore/panic.rs
index 99b372d..e924ee2 100644
--- a/src/libcore/panic.rs
+++ b/src/libcore/panic.rs
@@ -177,6 +177,60 @@
}
impl<'a> Location<'a> {
+ /// Returns the source location of the caller of this function. If that function's caller is
+ /// annotated then its call location will be returned, and so on up the stack to the first call
+ /// within a non-tracked function body.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(track_caller)]
+ /// use core::panic::Location;
+ ///
+ /// /// Returns the [`Location`] at which it is called.
+ /// #[track_caller]
+ /// fn get_caller_location() -> &'static Location<'static> {
+ /// Location::caller()
+ /// }
+ ///
+ /// /// Returns a [`Location`] from within this function's definition.
+ /// fn get_just_one_location() -> &'static Location<'static> {
+ /// get_caller_location()
+ /// }
+ ///
+ /// let fixed_location = get_just_one_location();
+ /// assert_eq!(fixed_location.file(), file!());
+ /// assert_eq!(fixed_location.line(), 15);
+ /// assert_eq!(fixed_location.column(), 5);
+ ///
+ /// // running the same untracked function in a different location gives us the same result
+ /// let second_fixed_location = get_just_one_location();
+ /// assert_eq!(fixed_location.file(), second_fixed_location.file());
+ /// assert_eq!(fixed_location.line(), second_fixed_location.line());
+ /// assert_eq!(fixed_location.column(), second_fixed_location.column());
+ ///
+ /// let this_location = get_caller_location();
+ /// assert_eq!(this_location.file(), file!());
+ /// assert_eq!(this_location.line(), 29);
+ /// assert_eq!(this_location.column(), 21);
+ ///
+ /// // running the tracked function in a different location produces a different value
+ /// let another_location = get_caller_location();
+ /// assert_eq!(this_location.file(), another_location.file());
+ /// assert_ne!(this_location.line(), another_location.line());
+ /// assert_ne!(this_location.column(), another_location.column());
+ /// ```
+ #[cfg(not(bootstrap))]
+ #[unstable(feature = "track_caller",
+ reason = "uses #[track_caller] which is not yet stable",
+ issue = "47809")]
+ #[track_caller]
+ pub const fn caller() -> &'static Location<'static> {
+ crate::intrinsics::caller_location()
+ }
+}
+
+impl<'a> Location<'a> {
#![unstable(feature = "panic_internals",
reason = "internal details of the implementation of the `panic!` \
and related macros",
diff --git a/src/libcore/tests/bool.rs b/src/libcore/tests/bool.rs
index 0f1e6e8..e89eb2c 100644
--- a/src/libcore/tests/bool.rs
+++ b/src/libcore/tests/bool.rs
@@ -1,7 +1,7 @@
#[test]
fn test_bool_to_option() {
- assert_eq!(false.then(0), None);
- assert_eq!(true.then(0), Some(0));
- assert_eq!(false.then_with(|| 0), None);
- assert_eq!(true.then_with(|| 0), Some(0));
+ assert_eq!(false.then_some(0), None);
+ assert_eq!(true.then_some(0), Some(0));
+ assert_eq!(false.then(|| 0), None);
+ assert_eq!(true.then(|| 0), Some(0));
}
diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs
index 900c6ed..2ecbe77 100644
--- a/src/libfmt_macros/lib.rs
+++ b/src/libfmt_macros/lib.rs
@@ -11,6 +11,7 @@
#![feature(nll)]
#![feature(rustc_private)]
#![feature(unicode_internals)]
+#![feature(bool_to_option)]
pub use Piece::*;
pub use Position::*;
@@ -644,11 +645,7 @@
break;
}
}
- if found {
- Some(cur)
- } else {
- None
- }
+ found.then_some(cur)
}
}
diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml
index f8ad6f8..a4536bb 100644
--- a/src/librustc/Cargo.toml
+++ b/src/librustc/Cargo.toml
@@ -20,7 +20,7 @@
log = { version = "0.4", features = ["release_max_level_info", "std"] }
rustc-rayon = "0.3.0"
rustc-rayon-core = "0.3.0"
-polonius-engine = "0.10.0"
+polonius-engine = "0.11.0"
rustc_apfloat = { path = "../librustc_apfloat" }
rustc_feature = { path = "../librustc_feature" }
rustc_target = { path = "../librustc_target" }
@@ -37,6 +37,6 @@
chalk-engine = { version = "0.9.0", default-features=false }
rustc_fs_util = { path = "../librustc_fs_util" }
smallvec = { version = "1.0", features = ["union", "may_dangle"] }
-measureme = "0.4"
+measureme = "0.5"
rustc_error_codes = { path = "../librustc_error_codes" }
rustc_session = { path = "../librustc_session" }
diff --git a/src/librustc/arena.rs b/src/librustc/arena.rs
index 364a35f..eb7a170 100644
--- a/src/librustc/arena.rs
+++ b/src/librustc/arena.rs
@@ -23,17 +23,17 @@
[] generics: rustc::ty::Generics,
[] trait_def: rustc::ty::TraitDef,
[] adt_def: rustc::ty::AdtDef,
- [] steal_mir: rustc::ty::steal::Steal<rustc::mir::BodyCache<$tcx>>,
- [] mir: rustc::mir::BodyCache<$tcx>,
+ [] steal_mir: rustc::ty::steal::Steal<rustc::mir::BodyAndCache<$tcx>>,
+ [] mir: rustc::mir::BodyAndCache<$tcx>,
[] steal_promoted: rustc::ty::steal::Steal<
rustc_index::vec::IndexVec<
rustc::mir::Promoted,
- rustc::mir::BodyCache<$tcx>
+ rustc::mir::BodyAndCache<$tcx>
>
>,
[] promoted: rustc_index::vec::IndexVec<
rustc::mir::Promoted,
- rustc::mir::BodyCache<$tcx>
+ rustc::mir::BodyAndCache<$tcx>
>,
[] tables: rustc::ty::TypeckTables<$tcx>,
[] const_allocs: rustc::mir::interpret::Allocation,
diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs
index 0104507..d952bf7 100644
--- a/src/librustc/dep_graph/graph.rs
+++ b/src/librustc/dep_graph/graph.rs
@@ -710,14 +710,25 @@
return None
}
None => {
- if !tcx.sess.has_errors() {
+ if !tcx.sess.has_errors_or_delayed_span_bugs() {
bug!("try_mark_previous_green() - Forcing the DepNode \
should have set its color")
} else {
- // If the query we just forced has resulted
- // in some kind of compilation error, we
- // don't expect that the corresponding
- // dep-node color has been updated.
+ // If the query we just forced has resulted in
+ // some kind of compilation error, we cannot rely on
+ // the dep-node color having been properly updated.
+ // This means that the query system has reached an
+ // invalid state. We let the compiler continue (by
+ // returning `None`) so it can emit error messages
+ // and wind down, but rely on the fact that this
+ // invalid state will not be persisted to the
+ // incremental compilation cache because of
+ // compilation errors being present.
+ debug!("try_mark_previous_green({:?}) - END - \
+ dependency {:?} resulted in compilation error",
+ dep_node,
+ dep_dep_node);
+ return None
}
}
}
diff --git a/src/librustc/hir/map/blocks.rs b/src/librustc/hir/map/blocks.rs
index f25f3b5..8f9f398 100644
--- a/src/librustc/hir/map/blocks.rs
+++ b/src/librustc/hir/map/blocks.rs
@@ -147,13 +147,7 @@
map::Node::Expr(e) => e.is_fn_like(),
_ => false
};
- if fn_like {
- Some(FnLikeNode {
- node,
- })
- } else {
- None
- }
+ fn_like.then_some(FnLikeNode { node })
}
pub fn body(self) -> ast::BodyId {
diff --git a/src/librustc/infer/outlives/verify.rs b/src/librustc/infer/outlives/verify.rs
index 3110b02..3e28145 100644
--- a/src/librustc/infer/outlives/verify.rs
+++ b/src/librustc/infer/outlives/verify.rs
@@ -211,11 +211,7 @@
(r, p)
);
let p_ty = p.to_ty(tcx);
- if compare_ty(p_ty) {
- Some(ty::OutlivesPredicate(p_ty, r))
- } else {
- None
- }
+ compare_ty(p_ty).then_some(ty::OutlivesPredicate(p_ty, r))
});
param_bounds
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index e708c5a..24b87ff 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -29,6 +29,7 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
#![feature(arbitrary_self_types)]
+#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(const_fn)]
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index 1aba73e..c4bc977 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -329,7 +329,7 @@
declare_lint! {
pub UNUSED_LABELS,
- Allow,
+ Warn,
"detects labels that are never used"
}
diff --git a/src/librustc/mir/cache.rs b/src/librustc/mir/cache.rs
index 95e9f09..0704771 100644
--- a/src/librustc/mir/cache.rs
+++ b/src/librustc/mir/cache.rs
@@ -115,16 +115,16 @@
}
#[derive(Clone, Debug, HashStable, RustcEncodable, RustcDecodable, TypeFoldable)]
-pub struct BodyCache<'tcx> {
- cache: Cache,
+pub struct BodyAndCache<'tcx> {
body: Body<'tcx>,
+ cache: Cache,
}
-impl BodyCache<'tcx> {
+impl BodyAndCache<'tcx> {
pub fn new(body: Body<'tcx>) -> Self {
Self {
- cache: Cache::new(),
body,
+ cache: Cache::new(),
}
}
}
@@ -139,7 +139,7 @@
};
}
-impl BodyCache<'tcx> {
+impl BodyAndCache<'tcx> {
pub fn ensure_predecessors(&mut self) {
self.cache.ensure_predecessors(&self.body);
}
@@ -148,8 +148,8 @@
self.cache.predecessors(&self.body)
}
- pub fn unwrap_read_only(&self) -> ReadOnlyBodyCache<'_, 'tcx> {
- ReadOnlyBodyCache::new(&self.cache, &self.body)
+ pub fn unwrap_read_only(&self) -> ReadOnlyBodyAndCache<'_, 'tcx> {
+ ReadOnlyBodyAndCache::new(&self.body, &self.cache)
}
pub fn basic_blocks_mut(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'tcx>> {
@@ -163,7 +163,7 @@
}
}
-impl<'tcx> Index<BasicBlock> for BodyCache<'tcx> {
+impl<'tcx> Index<BasicBlock> for BodyAndCache<'tcx> {
type Output = BasicBlockData<'tcx>;
fn index(&self, index: BasicBlock) -> &BasicBlockData<'tcx> {
@@ -171,13 +171,13 @@
}
}
-impl<'tcx> IndexMut<BasicBlock> for BodyCache<'tcx> {
+impl<'tcx> IndexMut<BasicBlock> for BodyAndCache<'tcx> {
fn index_mut(&mut self, index: BasicBlock) -> &mut Self::Output {
&mut self.basic_blocks_mut()[index]
}
}
-impl<'tcx> Deref for BodyCache<'tcx> {
+impl<'tcx> Deref for BodyAndCache<'tcx> {
type Target = Body<'tcx>;
fn deref(&self) -> &Self::Target {
@@ -185,26 +185,26 @@
}
}
-impl<'tcx> DerefMut for BodyCache<'tcx> {
+impl<'tcx> DerefMut for BodyAndCache<'tcx> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.body
}
}
#[derive(Copy, Clone, Debug)]
-pub struct ReadOnlyBodyCache<'a, 'tcx> {
- cache: &'a Cache,
+pub struct ReadOnlyBodyAndCache<'a, 'tcx> {
body: &'a Body<'tcx>,
+ cache: &'a Cache,
}
-impl ReadOnlyBodyCache<'a, 'tcx> {
- fn new(cache: &'a Cache, body: &'a Body<'tcx>) -> Self {
+impl ReadOnlyBodyAndCache<'a, 'tcx> {
+ fn new(body: &'a Body<'tcx>, cache: &'a Cache) -> Self {
assert!(
cache.predecessors.is_some(),
- "Cannot construct ReadOnlyBodyCache without computed predecessors");
+ "Cannot construct ReadOnlyBodyAndCache without computed predecessors");
Self {
- cache,
body,
+ cache,
}
}
@@ -220,10 +220,6 @@
self.cache.unwrap_predecessor_locations(loc, self.body)
}
- pub fn body(&self) -> &'a Body<'tcx> {
- self.body
- }
-
pub fn basic_blocks(&self) -> &IndexVec<BasicBlock, BasicBlockData<'tcx>> {
&self.body.basic_blocks
}
@@ -233,16 +229,16 @@
}
}
-impl graph::DirectedGraph for ReadOnlyBodyCache<'a, 'tcx> {
+impl graph::DirectedGraph for ReadOnlyBodyAndCache<'a, 'tcx> {
type Node = BasicBlock;
}
-impl graph::GraphPredecessors<'graph> for ReadOnlyBodyCache<'a, 'tcx> {
+impl graph::GraphPredecessors<'graph> for ReadOnlyBodyAndCache<'a, 'tcx> {
type Item = BasicBlock;
type Iter = IntoIter<BasicBlock>;
}
-impl graph::WithPredecessors for ReadOnlyBodyCache<'a, 'tcx> {
+impl graph::WithPredecessors for ReadOnlyBodyAndCache<'a, 'tcx> {
fn predecessors(
&self,
node: Self::Node,
@@ -251,19 +247,19 @@
}
}
-impl graph::WithNumNodes for ReadOnlyBodyCache<'a, 'tcx> {
+impl graph::WithNumNodes for ReadOnlyBodyAndCache<'a, 'tcx> {
fn num_nodes(&self) -> usize {
self.body.num_nodes()
}
}
-impl graph::WithStartNode for ReadOnlyBodyCache<'a, 'tcx> {
+impl graph::WithStartNode for ReadOnlyBodyAndCache<'a, 'tcx> {
fn start_node(&self) -> Self::Node {
self.body.start_node()
}
}
-impl graph::WithSuccessors for ReadOnlyBodyCache<'a, 'tcx> {
+impl graph::WithSuccessors for ReadOnlyBodyAndCache<'a, 'tcx> {
fn successors(
&self,
node: Self::Node,
@@ -272,13 +268,13 @@
}
}
-impl<'a, 'b, 'tcx> graph::GraphSuccessors<'b> for ReadOnlyBodyCache<'a, 'tcx> {
+impl<'a, 'b, 'tcx> graph::GraphSuccessors<'b> for ReadOnlyBodyAndCache<'a, 'tcx> {
type Item = BasicBlock;
type Iter = iter::Cloned<Successors<'b>>;
}
-impl Deref for ReadOnlyBodyCache<'a, 'tcx> {
+impl Deref for ReadOnlyBodyAndCache<'a, 'tcx> {
type Target = &'a Body<'tcx>;
fn deref(&self) -> &Self::Target {
diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs
index 5573106..0dec7c0 100644
--- a/src/librustc/mir/interpret/error.rs
+++ b/src/librustc/mir/interpret/error.rs
@@ -370,6 +370,14 @@
Unreachable,
/// An enum discriminant was set to a value which was outside the range of valid values.
InvalidDiscriminant(ScalarMaybeUndef),
+ /// A slice/array index projection went out-of-bounds.
+ BoundsCheckFailed { len: u64, index: u64 },
+ /// Something was divided by 0 (x / 0).
+ DivisionByZero,
+ /// Something was "remainded" by 0 (x % 0).
+ RemainderByZero,
+ /// Overflowing inbounds pointer arithmetic.
+ PointerArithOverflow,
}
impl fmt::Debug for UndefinedBehaviorInfo {
@@ -379,9 +387,18 @@
Ub(msg) | UbExperimental(msg) =>
write!(f, "{}", msg),
Unreachable =>
- write!(f, "entered unreachable code"),
+ write!(f, "entering unreachable code"),
InvalidDiscriminant(val) =>
- write!(f, "encountered invalid enum discriminant {}", val),
+ write!(f, "encountering invalid enum discriminant {}", val),
+ BoundsCheckFailed { ref len, ref index } =>
+ write!(f, "indexing out of bounds: the len is {:?} but the index is {:?}",
+ len, index),
+ DivisionByZero =>
+ write!(f, "dividing by zero"),
+ RemainderByZero =>
+ write!(f, "calculating the remainder with a divisor of zero"),
+ PointerArithOverflow =>
+ write!(f, "overflowing in-bounds pointer arithmetic"),
}
}
}
diff --git a/src/librustc/mir/interpret/pointer.rs b/src/librustc/mir/interpret/pointer.rs
index 78320c7..0b27f51 100644
--- a/src/librustc/mir/interpret/pointer.rs
+++ b/src/librustc/mir/interpret/pointer.rs
@@ -1,6 +1,5 @@
use super::{AllocId, InterpResult};
-use crate::mir;
use crate::ty::layout::{self, HasDataLayout, Size};
use rustc_macros::HashStable;
@@ -88,13 +87,13 @@
#[inline]
fn offset<'tcx>(&self, val: u64, i: u64) -> InterpResult<'tcx, u64> {
let (res, over) = self.overflowing_offset(val, i);
- if over { throw_panic!(Overflow(mir::BinOp::Add)) } else { Ok(res) }
+ if over { throw_ub!(PointerArithOverflow) } else { Ok(res) }
}
#[inline]
fn signed_offset<'tcx>(&self, val: u64, i: i64) -> InterpResult<'tcx, u64> {
let (res, over) = self.overflowing_signed_offset(val, i128::from(i));
- if over { throw_panic!(Overflow(mir::BinOp::Add)) } else { Ok(res) }
+ if over { throw_ub!(PointerArithOverflow) } else { Ok(res) }
}
}
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index df5d499..a7f5a22 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -38,7 +38,7 @@
use syntax_pos::{Span, DUMMY_SP};
pub use crate::mir::interpret::AssertMessage;
-pub use crate::mir::cache::{BodyCache, ReadOnlyBodyCache};
+pub use crate::mir::cache::{BodyAndCache, ReadOnlyBodyAndCache};
pub use crate::read_only;
mod cache;
@@ -108,7 +108,7 @@
pub yield_ty: Option<Ty<'tcx>>,
/// Generator drop glue.
- pub generator_drop: Option<Box<BodyCache<'tcx>>>,
+ pub generator_drop: Option<Box<BodyAndCache<'tcx>>>,
/// The layout of a generator. Produced by the state transformation.
pub generator_layout: Option<GeneratorLayout<'tcx>>,
@@ -242,11 +242,7 @@
pub fn vars_iter<'a>(&'a self) -> impl Iterator<Item = Local> + 'a {
(self.arg_count + 1..self.local_decls.len()).filter_map(move |index| {
let local = Local::new(index);
- if self.local_decls[local].is_user_variable() {
- Some(local)
- } else {
- None
- }
+ self.local_decls[local].is_user_variable().then_some(local)
})
}
@@ -2601,7 +2597,7 @@
pub fn is_predecessor_of<'tcx>(
&self,
other: Location,
- body: ReadOnlyBodyCache<'_, 'tcx>
+ body: ReadOnlyBodyAndCache<'_, 'tcx>
) -> bool {
// If we are in the same block as the other location and are an earlier statement
// then we are a predecessor of `other`.
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index 47a1d67..703e0cc 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -67,10 +67,10 @@
macro_rules! body_cache_type {
(mut $a:lifetime, $tcx:lifetime) => {
- &mut BodyCache<$tcx>
+ &mut BodyAndCache<$tcx>
};
($a:lifetime, $tcx:lifetime) => {
- ReadOnlyBodyCache<$a, $tcx>
+ ReadOnlyBodyAndCache<$a, $tcx>
};
}
diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs
index a6d7e5c..538b13c 100644
--- a/src/librustc/query/mod.rs
+++ b/src/librustc/query/mod.rs
@@ -106,30 +106,30 @@
/// Fetch the MIR for a given `DefId` right after it's built - this includes
/// unreachable code.
- query mir_built(_: DefId) -> &'tcx Steal<mir::BodyCache<'tcx>> {}
+ query mir_built(_: DefId) -> &'tcx Steal<mir::BodyAndCache<'tcx>> {}
/// Fetch the MIR for a given `DefId` up till the point where it is
/// ready for const evaluation.
///
/// See the README for the `mir` module for details.
- query mir_const(_: DefId) -> &'tcx Steal<mir::BodyCache<'tcx>> {
+ query mir_const(_: DefId) -> &'tcx Steal<mir::BodyAndCache<'tcx>> {
no_hash
}
query mir_validated(_: DefId) ->
(
- &'tcx Steal<mir::BodyCache<'tcx>>,
- &'tcx Steal<IndexVec<mir::Promoted, mir::BodyCache<'tcx>>>
+ &'tcx Steal<mir::BodyAndCache<'tcx>>,
+ &'tcx Steal<IndexVec<mir::Promoted, mir::BodyAndCache<'tcx>>>
) {
no_hash
}
/// MIR after our optimization passes have run. This is MIR that is ready
/// for codegen. This is also the only query that can fetch non-local MIR, at present.
- query optimized_mir(key: DefId) -> &'tcx mir::BodyCache<'tcx> {
+ query optimized_mir(key: DefId) -> &'tcx mir::BodyAndCache<'tcx> {
cache_on_disk_if { key.is_local() }
load_cached(tcx, id) {
- let mir: Option<crate::mir::BodyCache<'tcx>>
+ let mir: Option<crate::mir::BodyAndCache<'tcx>>
= tcx.queries.on_disk_cache.try_load_query_result(tcx, id);
mir.map(|x| {
let cache = tcx.arena.alloc(x);
@@ -139,13 +139,13 @@
}
}
- query promoted_mir(key: DefId) -> &'tcx IndexVec<mir::Promoted, mir::BodyCache<'tcx>> {
+ query promoted_mir(key: DefId) -> &'tcx IndexVec<mir::Promoted, mir::BodyAndCache<'tcx>> {
cache_on_disk_if { key.is_local() }
load_cached(tcx, id) {
let promoted: Option<
rustc_index::vec::IndexVec<
crate::mir::Promoted,
- crate::mir::BodyCache<'tcx>
+ crate::mir::BodyAndCache<'tcx>
>> = tcx.queries.on_disk_cache.try_load_query_result(tcx, id);
promoted.map(|p| {
let cache = tcx.arena.alloc(p);
@@ -512,7 +512,7 @@
/// in the case of closures, this will be redirected to the enclosing function.
query region_scope_tree(_: DefId) -> &'tcx region::ScopeTree {}
- query mir_shims(key: ty::InstanceDef<'tcx>) -> &'tcx mir::BodyCache<'tcx> {
+ query mir_shims(key: ty::InstanceDef<'tcx>) -> &'tcx mir::BodyAndCache<'tcx> {
no_force
desc { |tcx| "generating MIR shim for `{}`", tcx.def_path_str(key.def_id()) }
}
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index ba44c6c..35017d6 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -363,11 +363,7 @@
return None
};
- if tcx.has_attr(impl_def_id, sym::rustc_on_unimplemented) {
- Some(impl_def_id)
- } else {
- None
- }
+ tcx.has_attr(impl_def_id, sym::rustc_on_unimplemented).then_some(impl_def_id)
}
fn describe_generator(&self, body_id: hir::BodyId) -> Option<&'static str> {
@@ -2214,6 +2210,10 @@
}
let span = self.tcx.def_span(generator_did);
+ // Do not ICE on closure typeck (#66868).
+ if let None = self.tcx.hir().as_local_hir_id(generator_did) {
+ return false;
+ }
let tables = self.tcx.typeck_tables_of(generator_did);
debug!("note_obligation_cause_for_async_await: generator_did={:?} span={:?} ",
generator_did, span);
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 6a0002c..f7e422b 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -8,6 +8,7 @@
use crate::session::config::{BorrowckMode, OutputFilenames};
use crate::session::config::CrateType;
use crate::middle;
+use crate::middle::lang_items::PanicLocationLangItem;
use crate::hir::{self, TraitCandidate, HirId, ItemKind, ItemLocalId, Node};
use crate::hir::def::{Res, DefKind, Export};
use crate::hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE};
@@ -22,7 +23,7 @@
use crate::middle::lang_items;
use crate::middle::resolve_lifetime::{self, ObjectLifetimeDefault};
use crate::middle::stability;
-use crate::mir::{BodyCache, Field, interpret, Local, Place, PlaceElem, ProjectionKind, Promoted};
+use crate::mir::{BodyAndCache, Field, interpret, Local, Place, PlaceElem, ProjectionKind, Promoted};
use crate::mir::interpret::{ConstValue, Allocation, Scalar};
use crate::ty::subst::{GenericArg, InternalSubsts, SubstsRef, Subst};
use crate::ty::ReprOptions;
@@ -1083,17 +1084,17 @@
&self.hir_map
}
- pub fn alloc_steal_mir(self, mir: BodyCache<'tcx>) -> &'tcx Steal<BodyCache<'tcx>> {
+ pub fn alloc_steal_mir(self, mir: BodyAndCache<'tcx>) -> &'tcx Steal<BodyAndCache<'tcx>> {
self.arena.alloc(Steal::new(mir))
}
- pub fn alloc_steal_promoted(self, promoted: IndexVec<Promoted, BodyCache<'tcx>>) ->
- &'tcx Steal<IndexVec<Promoted, BodyCache<'tcx>>> {
+ pub fn alloc_steal_promoted(self, promoted: IndexVec<Promoted, BodyAndCache<'tcx>>) ->
+ &'tcx Steal<IndexVec<Promoted, BodyAndCache<'tcx>>> {
self.arena.alloc(Steal::new(promoted))
}
- pub fn intern_promoted(self, promoted: IndexVec<Promoted, BodyCache<'tcx>>) ->
- &'tcx IndexVec<Promoted, BodyCache<'tcx>> {
+ pub fn intern_promoted(self, promoted: IndexVec<Promoted, BodyAndCache<'tcx>>) ->
+ &'tcx IndexVec<Promoted, BodyAndCache<'tcx>> {
self.arena.alloc(promoted)
}
@@ -1588,6 +1589,15 @@
pub fn has_strict_asm_symbol_naming(&self) -> bool {
self.sess.target.target.arch.contains("nvptx")
}
+
+ /// Returns `&'static core::panic::Location<'static>`.
+ pub fn caller_location_ty(&self) -> Ty<'tcx> {
+ self.mk_imm_ref(
+ self.lifetimes.re_static,
+ self.type_of(self.require_lang_item(PanicLocationLangItem, None))
+ .subst(*self, self.mk_substs([self.lifetimes.re_static.into()].iter())),
+ )
+ }
}
impl<'tcx> GlobalCtxt<'tcx> {
diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs
index 801dfa8..366951b 100644
--- a/src/librustc/ty/instance.rs
+++ b/src/librustc/ty/instance.rs
@@ -116,6 +116,10 @@
}
tcx.codegen_fn_attrs(self.def_id()).requests_inline()
}
+
+ pub fn requires_caller_location(&self, tcx: TyCtxt<'_>) -> bool {
+ tcx.codegen_fn_attrs(self.def_id()).flags.contains(CodegenFnAttrFlags::TRACK_CALLER)
+ }
}
impl<'tcx> fmt::Display for Instance<'tcx> {
@@ -255,11 +259,8 @@
) -> Option<Instance<'tcx>> {
debug!("resolve(def_id={:?}, substs={:?})", def_id, substs);
Instance::resolve(tcx, param_env, def_id, substs).map(|mut resolved| {
- let has_track_caller = |def| tcx.codegen_fn_attrs(def).flags
- .contains(CodegenFnAttrFlags::TRACK_CALLER);
-
match resolved.def {
- InstanceDef::Item(def_id) if has_track_caller(def_id) => {
+ InstanceDef::Item(def_id) if resolved.def.requires_caller_location(tcx) => {
debug!(" => fn pointer created for function with #[track_caller]");
resolved.def = InstanceDef::ReifyShim(def_id);
}
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index 7f93e8c..c7278dc 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -2434,6 +2434,7 @@
cx: &C,
sig: ty::PolyFnSig<'tcx>,
extra_args: &[Ty<'tcx>],
+ caller_location: Option<Ty<'tcx>>,
mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgAbi<'tcx, Ty<'tcx>>,
) -> Self;
fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi);
@@ -2448,13 +2449,19 @@
+ HasParamEnv<'tcx>,
{
fn of_fn_ptr(cx: &C, sig: ty::PolyFnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
- call::FnAbi::new_internal(cx, sig, extra_args, |ty, _| ArgAbi::new(cx.layout_of(ty)))
+ call::FnAbi::new_internal(cx, sig, extra_args, None, |ty, _| ArgAbi::new(cx.layout_of(ty)))
}
fn of_instance(cx: &C, instance: ty::Instance<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
let sig = instance.fn_sig_for_fn_abi(cx.tcx());
- call::FnAbi::new_internal(cx, sig, extra_args, |ty, arg_idx| {
+ let caller_location = if instance.def.requires_caller_location(cx.tcx()) {
+ Some(cx.tcx().caller_location_ty())
+ } else {
+ None
+ };
+
+ call::FnAbi::new_internal(cx, sig, extra_args, caller_location, |ty, arg_idx| {
let mut layout = cx.layout_of(ty);
// Don't pass the vtable, it's not an argument of the virtual fn.
// Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait`
@@ -2479,7 +2486,7 @@
'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr()
&& !fat_pointer_layout.ty.is_region_ptr()
{
- 'iter_fields: for i in 0..fat_pointer_layout.fields.count() {
+ for i in 0..fat_pointer_layout.fields.count() {
let field_layout = fat_pointer_layout.field(cx, i);
if !field_layout.is_zst() {
@@ -2512,6 +2519,7 @@
cx: &C,
sig: ty::PolyFnSig<'tcx>,
extra_args: &[Ty<'tcx>],
+ caller_location: Option<Ty<'tcx>>,
mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgAbi<'tcx, Ty<'tcx>>,
) -> Self {
debug!("FnAbi::new_internal({:?}, {:?})", sig, extra_args);
@@ -2684,6 +2692,7 @@
.iter()
.cloned()
.chain(extra_args)
+ .chain(caller_location)
.enumerate()
.map(|(i, ty)| arg_of(ty, Some(i)))
.collect(),
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index c9a934e..78a31f4 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -18,7 +18,7 @@
use crate::middle::cstore::CrateStoreDyn;
use crate::middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
use crate::middle::resolve_lifetime::ObjectLifetimeDefault;
-use crate::mir::ReadOnlyBodyCache;
+use crate::mir::ReadOnlyBodyAndCache;
use crate::mir::interpret::{GlobalId, ErrorHandled};
use crate::mir::GeneratorLayout;
use crate::session::CrateDisambiguator;
@@ -2784,11 +2784,7 @@
}
};
- if is_associated_item {
- Some(self.associated_item(def_id))
- } else {
- None
- }
+ is_associated_item.then(|| self.associated_item(def_id))
}
fn associated_item_from_trait_item_ref(self,
@@ -2985,7 +2981,7 @@
}
/// Returns the possibly-auto-generated MIR of a `(DefId, Subst)` pair.
- pub fn instance_mir(self, instance: ty::InstanceDef<'tcx>) -> ReadOnlyBodyCache<'tcx, 'tcx> {
+ pub fn instance_mir(self, instance: ty::InstanceDef<'tcx>) -> ReadOnlyBodyAndCache<'tcx, 'tcx> {
match instance {
ty::InstanceDef::Item(did) => {
self.optimized_mir(did).unwrap_read_only()
@@ -3253,7 +3249,7 @@
let unnormalized_env = ty::ParamEnv::new(
tcx.intern_predicates(&predicates),
traits::Reveal::UserFacing,
- if tcx.sess.opts.debugging_opts.chalk { Some(def_id) } else { None }
+ tcx.sess.opts.debugging_opts.chalk.then_some(def_id),
);
let body_id = tcx.hir().as_local_hir_id(def_id).map_or(hir::DUMMY_HIR_ID, |id| {
diff --git a/src/librustc/ty/query/job.rs b/src/librustc/ty/query/job.rs
index e5f4e79..2f30b79 100644
--- a/src/librustc/ty/query/job.rs
+++ b/src/librustc/ty/query/job.rs
@@ -303,13 +303,8 @@
return true;
}
- visit_waiters(query, |_, successor| {
- if connected_to_root(successor, visited) {
- Some(None)
- } else {
- None
- }
- }).is_some()
+ visit_waiters(query, |_, successor| connected_to_root(successor, visited).then_some(None))
+ .is_some()
}
// Deterministically pick an query from a list
diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs
index 33dc251..1ea9362 100644
--- a/src/librustc_codegen_llvm/attributes.rs
+++ b/src/librustc_codegen_llvm/attributes.rs
@@ -375,11 +375,7 @@
let native_libs = tcx.native_libraries(cnum);
let def_id_to_native_lib = native_libs.iter().filter_map(|lib|
- if let Some(id) = lib.foreign_module {
- Some((id, lib))
- } else {
- None
- }
+ lib.foreign_module.map(|id| (id, lib))
).collect::<FxHashMap<_, _>>();
let mut ret = FxHashMap::default();
diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs
index a05ba9c..ada29c3 100644
--- a/src/librustc_codegen_llvm/back/write.rs
+++ b/src/librustc_codegen_llvm/back/write.rs
@@ -22,7 +22,7 @@
use rustc_data_structures::small_c_str::SmallCStr;
use errors::{Handler, FatalError};
-use std::ffi::{CString, CStr};
+use std::ffi::CString;
use std::fs;
use std::io::{self, Write};
use std::path::{Path, PathBuf};
@@ -833,8 +833,8 @@
})
.filter_map(|val| {
// Exclude some symbols that we know are not Rust symbols.
- let name = CStr::from_ptr(llvm::LLVMGetValueName(val));
- if ignored(name.to_bytes()) {
+ let name = llvm::get_value_name(val);
+ if ignored(name) {
None
} else {
Some((val, name))
@@ -842,7 +842,7 @@
})
.map(move |(val, name)| {
let mut imp_name = prefix.as_bytes().to_vec();
- imp_name.extend(name.to_bytes());
+ imp_name.extend(name);
let imp_name = CString::new(imp_name).unwrap();
(imp_name, val)
})
diff --git a/src/librustc_codegen_llvm/common.rs b/src/librustc_codegen_llvm/common.rs
index f38f9df..419e99d 100644
--- a/src/librustc_codegen_llvm/common.rs
+++ b/src/librustc_codegen_llvm/common.rs
@@ -245,11 +245,7 @@
let (mut lo, mut hi) = (0u64, 0u64);
let success = llvm::LLVMRustConstInt128Get(v, sign_ext,
&mut hi, &mut lo);
- if success {
- Some(hi_lo_to_u128(lo, hi))
- } else {
- None
- }
+ success.then_some(hi_lo_to_u128(lo, hi))
})
}
diff --git a/src/librustc_codegen_llvm/consts.rs b/src/librustc_codegen_llvm/consts.rs
index 541b3d9..297aff9 100644
--- a/src/librustc_codegen_llvm/consts.rs
+++ b/src/librustc_codegen_llvm/consts.rs
@@ -21,7 +21,7 @@
use rustc::hir::{self, CodegenFnAttrs, CodegenFnAttrFlags};
-use std::ffi::{CStr, CString};
+use std::ffi::CStr;
pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll Value {
let mut llvals = Vec::with_capacity(alloc.relocations().len() + 1);
@@ -392,16 +392,14 @@
} else {
// If we created the global with the wrong type,
// correct the type.
- let empty_string = const_cstr!("");
- let name_str_ref = CStr::from_ptr(llvm::LLVMGetValueName(g));
- let name_string = CString::new(name_str_ref.to_bytes()).unwrap();
- llvm::LLVMSetValueName(g, empty_string.as_ptr());
+ let name = llvm::get_value_name(g).to_vec();
+ llvm::set_value_name(g, b"");
let linkage = llvm::LLVMRustGetLinkage(g);
let visibility = llvm::LLVMRustGetVisibility(g);
let new_g = llvm::LLVMRustGetOrInsertGlobal(
- self.llmod, name_string.as_ptr(), val_llty);
+ self.llmod, name.as_ptr().cast(), name.len(), val_llty);
llvm::LLVMRustSetLinkage(new_g, linkage);
llvm::LLVMRustSetVisibility(new_g, visibility);
diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs
index c2359a2..a3782ec 100644
--- a/src/librustc_codegen_llvm/debuginfo/mod.rs
+++ b/src/librustc_codegen_llvm/debuginfo/mod.rs
@@ -32,7 +32,7 @@
use libc::c_uint;
use std::cell::RefCell;
-use std::ffi::{CStr, CString};
+use std::ffi::CString;
use smallvec::SmallVec;
use syntax_pos::{self, BytePos, Span, Pos};
@@ -255,23 +255,11 @@
return;
}
- let old_name = unsafe {
- CStr::from_ptr(llvm::LLVMGetValueName(value))
- };
- match old_name.to_str() {
- Ok("") => {}
- Ok(_) => {
- // Avoid replacing the name if it already exists.
- // While we could combine the names somehow, it'd
- // get noisy quick, and the usefulness is dubious.
- return;
- }
- Err(_) => return,
- }
-
- let cname = SmallCStr::new(name);
- unsafe {
- llvm::LLVMSetValueName(value, cname.as_ptr());
+ // Avoid replacing the name if it already exists.
+ // While we could combine the names somehow, it'd
+ // get noisy quick, and the usefulness is dubious.
+ if llvm::get_value_name(value).is_empty() {
+ llvm::set_value_name(value, name.as_bytes());
}
}
}
diff --git a/src/librustc_codegen_llvm/declare.rs b/src/librustc_codegen_llvm/declare.rs
index 8b6fedc..fa9fc46 100644
--- a/src/librustc_codegen_llvm/declare.rs
+++ b/src/librustc_codegen_llvm/declare.rs
@@ -76,9 +76,8 @@
name: &str, ty: &'ll Type
) -> &'ll Value {
debug!("declare_global(name={:?})", name);
- let namebuf = SmallCStr::new(name);
unsafe {
- llvm::LLVMRustGetOrInsertGlobal(self.llmod, namebuf.as_ptr(), ty)
+ llvm::LLVMRustGetOrInsertGlobal(self.llmod, name.as_ptr().cast(), name.len(), ty)
}
}
diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs
index 9df75a8..1767ad1 100644
--- a/src/librustc_codegen_llvm/intrinsic.rs
+++ b/src/librustc_codegen_llvm/intrinsic.rs
@@ -516,9 +516,36 @@
return;
}
}
-
},
+ "float_to_int_approx_unchecked" => {
+ if float_type_width(arg_tys[0]).is_none() {
+ span_invalid_monomorphization_error(
+ tcx.sess, span,
+ &format!("invalid monomorphization of `float_to_int_approx_unchecked` \
+ intrinsic: expected basic float type, \
+ found `{}`", arg_tys[0]));
+ return;
+ }
+ match int_type_width_signed(ret_ty, self.cx) {
+ Some((width, signed)) => {
+ if signed {
+ self.fptosi(args[0].immediate(), self.cx.type_ix(width))
+ } else {
+ self.fptoui(args[0].immediate(), self.cx.type_ix(width))
+ }
+ }
+ None => {
+ span_invalid_monomorphization_error(
+ tcx.sess, span,
+ &format!("invalid monomorphization of `float_to_int_approx_unchecked` \
+ intrinsic: expected basic integer type, \
+ found `{}`", ret_ty));
+ return;
+ }
+ }
+ }
+
"discriminant_value" => {
args[0].deref(self.cx()).codegen_get_discr(self, ret_ty)
}
diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs
index 2ff5872..00a84f8 100644
--- a/src/librustc_codegen_llvm/lib.rs
+++ b/src/librustc_codegen_llvm/lib.rs
@@ -6,6 +6,7 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(const_cstr_unchecked)]
diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs
index 5362d18..5da3275 100644
--- a/src/librustc_codegen_llvm/llvm/ffi.rs
+++ b/src/librustc_codegen_llvm/llvm/ffi.rs
@@ -701,8 +701,8 @@
// Operations on all values
pub fn LLVMTypeOf(Val: &Value) -> &Type;
- pub fn LLVMGetValueName(Val: &Value) -> *const c_char;
- pub fn LLVMSetValueName(Val: &Value, Name: *const c_char);
+ pub fn LLVMGetValueName2(Val: &Value, Length: *mut size_t) -> *const c_char;
+ pub fn LLVMSetValueName2(Val: &Value, Name: *const c_char, NameLen: size_t);
pub fn LLVMReplaceAllUsesWith(OldVal: &'a Value, NewVal: &'a Value);
pub fn LLVMSetMetadata(Val: &'a Value, KindID: c_uint, Node: &'a Value);
@@ -774,7 +774,8 @@
pub fn LLVMIsAGlobalVariable(GlobalVar: &Value) -> Option<&Value>;
pub fn LLVMAddGlobal(M: &'a Module, Ty: &'a Type, Name: *const c_char) -> &'a Value;
pub fn LLVMGetNamedGlobal(M: &Module, Name: *const c_char) -> Option<&Value>;
- pub fn LLVMRustGetOrInsertGlobal(M: &'a Module, Name: *const c_char, T: &'a Type) -> &'a Value;
+ pub fn LLVMRustGetOrInsertGlobal(M: &'a Module, Name: *const c_char, NameLen: size_t,
+ T: &'a Type) -> &'a Value;
pub fn LLVMRustInsertPrivateGlobal(M: &'a Module, T: &'a Type) -> &'a Value;
pub fn LLVMGetFirstGlobal(M: &Module) -> Option<&Value>;
pub fn LLVMGetNextGlobal(GlobalVar: &Value) -> Option<&Value>;
@@ -1811,7 +1812,7 @@
pub fn LLVMRustPositionBuilderAtStart(B: &Builder<'a>, BB: &'a BasicBlock);
- pub fn LLVMRustSetComdat(M: &'a Module, V: &'a Value, Name: *const c_char);
+ pub fn LLVMRustSetComdat(M: &'a Module, V: &'a Value, Name: *const c_char, NameLen: size_t);
pub fn LLVMRustUnsetComdat(V: &Value);
pub fn LLVMRustSetModulePICLevel(M: &Module);
pub fn LLVMRustSetModulePIELevel(M: &Module);
diff --git a/src/librustc_codegen_llvm/llvm/mod.rs b/src/librustc_codegen_llvm/llvm/mod.rs
index 5781593..d2d4187 100644
--- a/src/librustc_codegen_llvm/llvm/mod.rs
+++ b/src/librustc_codegen_llvm/llvm/mod.rs
@@ -115,7 +115,8 @@
// For more details on COMDAT sections see e.g., http://www.airs.com/blog/archives/52
pub fn SetUniqueComdat(llmod: &Module, val: &'a Value) {
unsafe {
- LLVMRustSetComdat(llmod, val, LLVMGetValueName(val));
+ let name = get_value_name(val);
+ LLVMRustSetComdat(llmod, val, name.as_ptr().cast(), name.len());
}
}
@@ -217,6 +218,23 @@
}
}
+/// Safe wrapper for `LLVMGetValueName2` into a byte slice
+pub fn get_value_name(value: &'a Value) -> &'a [u8] {
+ unsafe {
+ let mut len = 0;
+ let data = LLVMGetValueName2(value, &mut len);
+ std::slice::from_raw_parts(data.cast(), len)
+ }
+}
+
+/// Safe wrapper for `LLVMSetValueName2` from a byte slice
+pub fn set_value_name(value: &Value, name: &[u8]) {
+ unsafe {
+ let data = name.as_ptr().cast();
+ LLVMSetValueName2(value, data, name.len());
+ }
+}
+
pub fn build_string(f: impl FnOnce(&RustString)) -> Result<String, FromUtf8Error> {
let sr = RustString {
bytes: RefCell::new(Vec::new()),
diff --git a/src/librustc_codegen_ssa/Cargo.toml b/src/librustc_codegen_ssa/Cargo.toml
index 53d3c51..d489852 100644
--- a/src/librustc_codegen_ssa/Cargo.toml
+++ b/src/librustc_codegen_ssa/Cargo.toml
@@ -13,7 +13,7 @@
bitflags = "1.2.1"
cc = "1.0.1"
num_cpus = "1.0"
-memmap = "0.6"
+memmap = "0.7"
log = "0.4.5"
libc = "0.2.44"
jobserver = "0.1.11"
diff --git a/src/librustc_codegen_ssa/back/rpath.rs b/src/librustc_codegen_ssa/back/rpath.rs
index e27cb6d..cd3d999 100644
--- a/src/librustc_codegen_ssa/back/rpath.rs
+++ b/src/librustc_codegen_ssa/back/rpath.rs
@@ -119,11 +119,7 @@
use std::path::Component;
if path.is_absolute() != base.is_absolute() {
- if path.is_absolute() {
- Some(PathBuf::from(path))
- } else {
- None
- }
+ path.is_absolute().then(|| PathBuf::from(path))
} else {
let mut ita = path.components();
let mut itb = base.components();
diff --git a/src/librustc_codegen_ssa/back/symbol_export.rs b/src/librustc_codegen_ssa/back/symbol_export.rs
index f8b3e0f..cea5dc1 100644
--- a/src/librustc_codegen_ssa/back/symbol_export.rs
+++ b/src/librustc_codegen_ssa/back/symbol_export.rs
@@ -85,11 +85,7 @@
match tcx.hir().get(hir_id) {
Node::ForeignItem(..) => {
let def_id = tcx.hir().local_def_id(hir_id);
- if tcx.is_statically_included_foreign_item(def_id) {
- Some(def_id)
- } else {
- None
- }
+ tcx.is_statically_included_foreign_item(def_id).then_some(def_id)
}
// Only consider nodes that actually have exported symbols.
diff --git a/src/librustc_codegen_ssa/lib.rs b/src/librustc_codegen_ssa/lib.rs
index 9784d87..9919666 100644
--- a/src/librustc_codegen_ssa/lib.rs
+++ b/src/librustc_codegen_ssa/lib.rs
@@ -1,5 +1,6 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(core_intrinsics)]
@@ -68,22 +69,14 @@
emit_bc: bool,
emit_bc_compressed: bool,
outputs: &OutputFilenames) -> CompiledModule {
- let object = if emit_obj {
- Some(outputs.temp_path(OutputType::Object, Some(&self.name)))
- } else {
- None
- };
- let bytecode = if emit_bc {
- Some(outputs.temp_path(OutputType::Bitcode, Some(&self.name)))
- } else {
- None
- };
- let bytecode_compressed = if emit_bc_compressed {
- Some(outputs.temp_path(OutputType::Bitcode, Some(&self.name))
- .with_extension(RLIB_BYTECODE_EXTENSION))
- } else {
- None
- };
+ let object = emit_obj
+ .then(|| outputs.temp_path(OutputType::Object, Some(&self.name)));
+ let bytecode = emit_bc
+ .then(|| outputs.temp_path(OutputType::Bitcode, Some(&self.name)));
+ let bytecode_compressed = emit_bc_compressed.then(|| {
+ outputs.temp_path(OutputType::Bitcode, Some(&self.name))
+ .with_extension(RLIB_BYTECODE_EXTENSION)
+ });
CompiledModule {
name: self.name.clone(),
diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs
index 6dccf32..dabd097 100644
--- a/src/librustc_codegen_ssa/mir/block.rs
+++ b/src/librustc_codegen_ssa/mir/block.rs
@@ -153,7 +153,7 @@
// a loop.
fn maybe_sideeffect<Bx: BuilderMethods<'a, 'tcx>>(
&self,
- mir: mir::ReadOnlyBodyCache<'tcx, 'tcx>,
+ mir: mir::ReadOnlyBodyAndCache<'tcx, 'tcx>,
bx: &mut Bx,
targets: &[mir::BasicBlock],
) {
@@ -261,7 +261,11 @@
if self.fn_abi.ret.layout.abi.is_uninhabited() {
// Functions with uninhabited return values are marked `noreturn`,
// so we should make sure that we never actually do.
+ // We play it safe by using a well-defined `abort`, but we could go for immediate UB
+ // if that turns out to be helpful.
bx.abort();
+ // `abort` does not terminate the block, so we still need to generate
+ // an `unreachable` terminator after it.
bx.unreachable();
return;
}
@@ -714,7 +718,7 @@
'descend_newtypes: while !op.layout.ty.is_unsafe_ptr()
&& !op.layout.ty.is_region_ptr()
{
- 'iter_fields: for i in 0..op.layout.fields.count() {
+ for i in 0..op.layout.fields.count() {
let field = op.extract_field(&mut bx, i);
if !field.layout.is_zst() {
// we found the one non-zero-sized field that is allowed
@@ -770,6 +774,18 @@
&fn_abi.args[first_args.len()..])
}
+ let needs_location =
+ instance.map_or(false, |i| i.def.requires_caller_location(self.cx.tcx()));
+ if needs_location {
+ assert_eq!(
+ fn_abi.args.len(), args.len() + 1,
+ "#[track_caller] fn's must have 1 more argument in their ABI than in their MIR",
+ );
+ let location = self.get_caller_location(&mut bx, span);
+ let last_arg = fn_abi.args.last().unwrap();
+ self.codegen_argument(&mut bx, location, &mut llargs, last_arg);
+ }
+
let fn_ptr = match (llfn, instance) {
(Some(llfn), _) => llfn,
(None, Some(instance)) => bx.get_fn_addr(instance),
@@ -825,6 +841,8 @@
mir::TerminatorKind::Abort => {
bx.abort();
+ // `abort` does not terminate the block, so we still need to generate
+ // an `unreachable` terminator after it.
bx.unreachable();
}
@@ -1004,14 +1022,16 @@
bx: &mut Bx,
span: Span,
) -> OperandRef<'tcx, Bx::Value> {
- let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
- let caller = bx.tcx().sess.source_map().lookup_char_pos(topmost.lo());
- let const_loc = bx.tcx().const_caller_location((
- Symbol::intern(&caller.file.name.to_string()),
- caller.line as u32,
- caller.col_display as u32 + 1,
- ));
- OperandRef::from_const(bx, const_loc)
+ self.caller_location.unwrap_or_else(|| {
+ let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
+ let caller = bx.tcx().sess.source_map().lookup_char_pos(topmost.lo());
+ let const_loc = bx.tcx().const_caller_location((
+ Symbol::intern(&caller.file.name.to_string()),
+ caller.line as u32,
+ caller.col_display as u32 + 1,
+ ));
+ OperandRef::from_const(bx, const_loc)
+ })
}
fn get_personality_slot(
diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs
index 3a157ca..e535aec 100644
--- a/src/librustc_codegen_ssa/mir/mod.rs
+++ b/src/librustc_codegen_ssa/mir/mod.rs
@@ -21,7 +21,7 @@
pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
instance: Instance<'tcx>,
- mir: mir::ReadOnlyBodyCache<'tcx, 'tcx>,
+ mir: mir::ReadOnlyBodyAndCache<'tcx, 'tcx>,
debug_context: Option<FunctionDebugContext<Bx::DIScope>>,
@@ -77,6 +77,9 @@
/// All `VarDebuginfo` from the MIR body, partitioned by `Local`.
/// This is `None` if no variable debuginfo/names are needed.
per_local_var_debug_info: Option<IndexVec<mir::Local, Vec<&'tcx mir::VarDebugInfo<'tcx>>>>,
+
+ /// Caller location propagated if this function has `#[track_caller]`.
+ caller_location: Option<OperandRef<'tcx, Bx::Value>>,
}
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
@@ -156,7 +159,7 @@
}).collect();
let (landing_pads, funclets) = create_funclets(&mir, &mut bx, &cleanup_kinds, &block_bxs);
- let mir_body: &mir::Body<'_> = mir.body();
+ let mir_body: &mir::Body<'_> = *mir;
let mut fx = FunctionCx {
instance,
mir,
@@ -172,13 +175,14 @@
locals: IndexVec::new(),
debug_context,
per_local_var_debug_info: debuginfo::per_local_var_debug_info(cx.tcx(), mir_body),
+ caller_location: None,
};
let memory_locals = analyze::non_ssa_locals(&fx);
// Allocate variable and temp allocas
fx.locals = {
- let args = arg_local_refs(&mut bx, &fx, &memory_locals);
+ let args = arg_local_refs(&mut bx, &mut fx, &memory_locals);
let mut allocate_local = |local| {
let decl = &mir_body.local_decls[local];
@@ -320,14 +324,14 @@
/// indirect.
fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
bx: &mut Bx,
- fx: &FunctionCx<'a, 'tcx, Bx>,
+ fx: &mut FunctionCx<'a, 'tcx, Bx>,
memory_locals: &BitSet<mir::Local>,
) -> Vec<LocalRef<'tcx, Bx::Value>> {
let mir = fx.mir;
let mut idx = 0;
let mut llarg_idx = fx.fn_abi.ret.is_indirect() as usize;
- mir.args_iter().enumerate().map(|(arg_index, local)| {
+ let args = mir.args_iter().enumerate().map(|(arg_index, local)| {
let arg_decl = &mir.local_decls[local];
if Some(local) == mir.spread_arg {
@@ -423,7 +427,27 @@
bx.store_fn_arg(arg, &mut llarg_idx, tmp);
LocalRef::Place(tmp)
}
- }).collect()
+ }).collect::<Vec<_>>();
+
+ if fx.instance.def.requires_caller_location(bx.tcx()) {
+ assert_eq!(
+ fx.fn_abi.args.len(), args.len() + 1,
+ "#[track_caller] fn's must have 1 more argument in their ABI than in their MIR",
+ );
+
+ let arg = fx.fn_abi.args.last().unwrap();
+ match arg.mode {
+ PassMode::Direct(_) => (),
+ _ => bug!("caller location must be PassMode::Direct, found {:?}", arg.mode),
+ }
+
+ fx.caller_location = Some(OperandRef {
+ val: OperandValue::Immediate(bx.get_param(llarg_idx)),
+ layout: arg.layout,
+ });
+ }
+
+ args
}
mod analyze;
diff --git a/src/librustc_codegen_ssa/mir/operand.rs b/src/librustc_codegen_ssa/mir/operand.rs
index 310b8ae..a6dec81 100644
--- a/src/librustc_codegen_ssa/mir/operand.rs
+++ b/src/librustc_codegen_ssa/mir/operand.rs
@@ -475,9 +475,10 @@
},
}
// Allow RalfJ to sleep soundly knowing that even refactorings that remove
- // the above error (or silence it under some conditions) will not cause UB
+ // the above error (or silence it under some conditions) will not cause UB.
bx.abort();
- // We've errored, so we don't have to produce working code.
+ // We still have to return an operand but it doesn't matter,
+ // this code is unreachable.
let ty = self.monomorphize(&constant.literal.ty);
let layout = bx.cx().layout_of(ty);
bx.load_operand(PlaceRef::new_sized(
diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs
index e250739..e60b886 100644
--- a/src/librustc_codegen_ssa/mir/place.rs
+++ b/src/librustc_codegen_ssa/mir/place.rs
@@ -333,6 +333,9 @@
variant_index: VariantIdx
) {
if self.layout.for_variant(bx.cx(), variant_index).abi.is_uninhabited() {
+ // We play it safe by using a well-defined `abort`, but we could go for immediate UB
+ // if that turns out to be helpful.
+ bx.abort();
return;
}
match self.layout.variants {
@@ -488,10 +491,12 @@
},
Err(_) => {
// This is unreachable as long as runtime
- // and compile-time agree on values
+ // and compile-time agree perfectly.
// With floats that won't always be true,
- // so we generate an abort.
+ // so we generate a (safe) abort.
bx.abort();
+ // We still have to return a place but it doesn't matter,
+ // this code is unreachable.
let llval = bx.cx().const_undef(
bx.cx().type_ptr_to(bx.cx().backend_type(layout))
);
diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml
index 0fd4711..7fa40b8 100644
--- a/src/librustc_data_structures/Cargo.toml
+++ b/src/librustc_data_structures/Cargo.toml
@@ -26,7 +26,7 @@
smallvec = { version = "1.0", features = ["union", "may_dangle"] }
rustc_index = { path = "../librustc_index", package = "rustc_index" }
bitflags = "1.2.1"
-measureme = "0.4"
+measureme = "0.5"
[dependencies.parking_lot]
version = "0.9"
diff --git a/src/librustc_data_structures/profiling.rs b/src/librustc_data_structures/profiling.rs
index 86f59bf..f9bfe5a 100644
--- a/src/librustc_data_structures/profiling.rs
+++ b/src/librustc_data_structures/profiling.rs
@@ -7,7 +7,7 @@
use std::thread::ThreadId;
use std::u32;
-use measureme::{StringId, TimestampKind};
+use measureme::{StringId};
/// MmapSerializatioSink is faster on macOS and Linux
/// but FileSerializationSink is faster on Windows
@@ -63,8 +63,8 @@
("incr-cache-load", EventFilter::INCR_CACHE_LOADS),
];
-fn thread_id_to_u64(tid: ThreadId) -> u64 {
- unsafe { mem::transmute::<ThreadId, u64>(tid) }
+fn thread_id_to_u32(tid: ThreadId) -> u32 {
+ unsafe { mem::transmute::<ThreadId, u64>(tid) as u32 }
}
@@ -149,11 +149,10 @@
/// Record a query in-memory cache hit.
#[inline(always)]
pub fn query_cache_hit(&self, query_name: impl QueryName) {
- self.non_guard_query_event(
+ self.instant_query_event(
|profiler| profiler.query_cache_hit_event_kind,
query_name,
EventFilter::QUERY_CACHE_HITS,
- TimestampKind::Instant,
);
}
@@ -184,22 +183,20 @@
}
#[inline(always)]
- fn non_guard_query_event(
+ fn instant_query_event(
&self,
event_kind: fn(&SelfProfiler) -> StringId,
query_name: impl QueryName,
event_filter: EventFilter,
- timestamp_kind: TimestampKind
) {
drop(self.exec(event_filter, |profiler| {
let event_id = SelfProfiler::get_query_name_string_id(query_name);
- let thread_id = thread_id_to_u64(std::thread::current().id());
+ let thread_id = thread_id_to_u32(std::thread::current().id());
- profiler.profiler.record_event(
+ profiler.profiler.record_instant_event(
event_kind(profiler),
event_id,
thread_id,
- timestamp_kind,
);
TimingGuard::none()
@@ -306,7 +303,7 @@
event_kind: StringId,
event_id: StringId,
) -> TimingGuard<'a> {
- let thread_id = thread_id_to_u64(std::thread::current().id());
+ let thread_id = thread_id_to_u32(std::thread::current().id());
let raw_profiler = &profiler.profiler;
let timing_guard = raw_profiler.start_recording_interval_event(event_kind,
event_id,
diff --git a/src/librustc_data_structures/transitive_relation.rs b/src/librustc_data_structures/transitive_relation.rs
index a3926c1..bbf6999 100644
--- a/src/librustc_data_structures/transitive_relation.rs
+++ b/src/librustc_data_structures/transitive_relation.rs
@@ -373,6 +373,14 @@
}
matrix
}
+
+ /// Lists all the base edges in the graph: the initial _non-transitive_ set of element
+ /// relations, which will be later used as the basis for the transitive closure computation.
+ pub fn base_edges(&self) -> impl Iterator<Item=(&T, &T)> {
+ self.edges
+ .iter()
+ .map(move |edge| (&self.elements[edge.source.0], &self.elements[edge.target.0]))
+ }
}
/// Pare down is used as a step in the LUB computation. It edits the
diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs
index 9e4b704..9c1bec3 100644
--- a/src/librustc_error_codes/error_codes.rs
+++ b/src/librustc_error_codes/error_codes.rs
@@ -18,7 +18,6 @@
E0013: include_str!("./error_codes/E0013.md"),
E0014: include_str!("./error_codes/E0014.md"),
E0015: include_str!("./error_codes/E0015.md"),
-E0017: include_str!("./error_codes/E0017.md"),
E0019: include_str!("./error_codes/E0019.md"),
E0023: include_str!("./error_codes/E0023.md"),
E0025: include_str!("./error_codes/E0025.md"),
diff --git a/src/librustc_error_codes/error_codes/E0017.md b/src/librustc_error_codes/error_codes/E0017.md
deleted file mode 100644
index d5e6857..0000000
--- a/src/librustc_error_codes/error_codes/E0017.md
+++ /dev/null
@@ -1,20 +0,0 @@
-References in statics and constants may only refer to immutable values.
-
-Erroneous code example:
-
-```compile_fail,E0017
-static X: i32 = 1;
-const C: i32 = 2;
-
-// these three are not allowed:
-const CR: &mut i32 = &mut C;
-static STATIC_REF: &'static mut i32 = &mut X;
-static CONST_REF: &'static mut i32 = &mut C;
-```
-
-Statics are shared everywhere, and if they refer to mutable data one might
-violate memory safety since holding multiple mutable references to shared data
-is not allowed.
-
-If you really want global mutable state, try using `static mut` or a global
-`UnsafeCell`.
diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs
index fc880b9..363621b 100644
--- a/src/librustc_feature/active.rs
+++ b/src/librustc_feature/active.rs
@@ -523,6 +523,9 @@
/// Allows the use of `#[cfg(sanitize = "option")]`; set when -Zsanitizer is used.
(active, cfg_sanitize, "1.41.0", Some(39699), None),
+ /// Allows using `&mut` in constant functions.
+ (active, const_mut_refs, "1.41.0", Some(57349), None),
+
// -------------------------------------------------------------------------
// feature-group-end: actual feature gates
// -------------------------------------------------------------------------
@@ -538,5 +541,4 @@
sym::or_patterns,
sym::let_chains,
sym::raw_dylib,
- sym::track_caller,
];
diff --git a/src/librustc_interface/lib.rs b/src/librustc_interface/lib.rs
index 76af434..9bb1878 100644
--- a/src/librustc_interface/lib.rs
+++ b/src/librustc_interface/lib.rs
@@ -1,3 +1,4 @@
+#![feature(bool_to_option)]
#![feature(box_syntax)]
#![feature(set_stdio)]
#![feature(nll)]
diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs
index 2351843..2a4bc41 100644
--- a/src/librustc_interface/passes.rs
+++ b/src/librustc_interface/passes.rs
@@ -547,13 +547,7 @@
}
fn output_conflicts_with_dir(output_paths: &[PathBuf]) -> Option<PathBuf> {
- let check = |output_path: &PathBuf| {
- if output_path.is_dir() {
- Some(output_path.clone())
- } else {
- None
- }
- };
+ let check = |output_path: &PathBuf| output_path.is_dir().then(|| output_path.clone());
check_output(output_paths, check)
}
diff --git a/src/librustc_interface/queries.rs b/src/librustc_interface/queries.rs
index 6103d42..e429b4d 100644
--- a/src/librustc_interface/queries.rs
+++ b/src/librustc_interface/queries.rs
@@ -22,7 +22,7 @@
use syntax::{self, ast};
/// Represent the result of a query.
-/// This result can be stolen with the `take` method and returned with the `give` method.
+/// This result can be stolen with the `take` method and generated with the `compute` method.
pub struct Query<T> {
result: RefCell<Option<Result<T>>>,
}
@@ -37,7 +37,7 @@
}
/// Takes ownership of the query result. Further attempts to take or peek the query
- /// result will panic unless it is returned by calling the `give` method.
+ /// result will panic unless it is generated by calling the `compute` method.
pub fn take(&self) -> T {
self.result
.borrow_mut()
@@ -117,11 +117,9 @@
pub fn dep_graph_future(&self) -> Result<&Query<Option<DepGraphFuture>>> {
self.dep_graph_future.compute(|| {
- Ok(if self.session().opts.build_dep_graph() {
- Some(rustc_incremental::load_dep_graph(self.session()))
- } else {
- None
- })
+ Ok(self.session().opts.build_dep_graph().then(|| {
+ rustc_incremental::load_dep_graph(self.session())
+ }))
})
}
diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs
index d8e20e1..8c225b8 100644
--- a/src/librustc_interface/util.rs
+++ b/src/librustc_interface/util.rs
@@ -107,11 +107,7 @@
fn get_stack_size() -> Option<usize> {
// FIXME: Hacks on hacks. If the env is trying to override the stack size
// then *don't* set it explicitly.
- if env::var_os("RUST_MIN_STACK").is_none() {
- Some(STACK_SIZE)
- } else {
- None
- }
+ env::var_os("RUST_MIN_STACK").is_none().then_some(STACK_SIZE)
}
struct Sink(Arc<Mutex<Vec<u8>>>);
@@ -285,11 +281,7 @@
} else {
"rustc"
});
- if candidate.exists() {
- Some(candidate)
- } else {
- None
- }
+ candidate.exists().then_some(candidate)
})
.next()
}
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 0fd7145f..10b00d3 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -1491,11 +1491,7 @@
match pred {
ty::Predicate::TypeOutlives(outlives) => {
let outlives = outlives.skip_binder();
- if outlives.0.is_param(index) {
- Some(outlives.1)
- } else {
- None
- }
+ outlives.0.is_param(index).then_some(outlives.1)
}
_ => None
}
@@ -1554,11 +1550,7 @@
}),
_ => false,
};
- if is_inferred {
- Some((i, bound.span()))
- } else {
- None
- }
+ is_inferred.then_some((i, bound.span()))
} else {
None
}
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index e60c025..b77f2cb 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -12,6 +12,7 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
#![cfg_attr(test, feature(test))]
+#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(nll)]
@@ -340,7 +341,7 @@
"converted into hard error, see https://github.com/rust-lang/rust/issues/46205");
store.register_removed("legacy_constructor_visibility",
"converted into hard error, see https://github.com/rust-lang/rust/issues/39207");
- store.register_removed("legacy_disrectory_ownership",
+ store.register_removed("legacy_directory_ownership",
"converted into hard error, see https://github.com/rust-lang/rust/issues/37872");
store.register_removed("safe_extern_statics",
"converted into hard error, see https://github.com/rust-lang/rust/issues/36247");
diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml
index b70cc52..88d1c50 100644
--- a/src/librustc_metadata/Cargo.toml
+++ b/src/librustc_metadata/Cargo.toml
@@ -12,7 +12,7 @@
[dependencies]
flate2 = "1.0"
log = "0.4"
-memmap = "0.6"
+memmap = "0.7"
smallvec = { version = "1.0", features = ["union", "may_dangle"] }
rustc = { path = "../librustc" }
rustc_data_structures = { path = "../librustc_data_structures" }
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index dbf2dcf..25bd2c4 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -802,11 +802,8 @@
// First up we check for global allocators. Look at the crate graph here
// and see what's a global allocator, including if we ourselves are a
// global allocator.
- let mut global_allocator = if self.cstore.has_global_allocator {
- Some(Symbol::intern("this crate"))
- } else {
- None
- };
+ let mut global_allocator = self.cstore.has_global_allocator
+ .then(|| Symbol::intern("this crate"));
self.cstore.iter_crate_data(|_, data| {
if !data.has_global_allocator() {
return
diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs
index 8c0b734..aaaff7e 100644
--- a/src/librustc_metadata/lib.rs
+++ b/src/librustc_metadata/lib.rs
@@ -1,5 +1,6 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(core_intrinsics)]
#![feature(crate_visibility_modifier)]
diff --git a/src/librustc_metadata/rmeta/decoder.rs b/src/librustc_metadata/rmeta/decoder.rs
index 6edd17f..0107a22 100644
--- a/src/librustc_metadata/rmeta/decoder.rs
+++ b/src/librustc_metadata/rmeta/decoder.rs
@@ -18,7 +18,7 @@
use rustc_data_structures::svh::Svh;
use rustc::dep_graph::{self, DepNodeIndex};
use rustc::middle::lang_items;
-use rustc::mir::{self, BodyCache, interpret, Promoted};
+use rustc::mir::{self, BodyAndCache, interpret, Promoted};
use rustc::mir::interpret::{AllocDecodingSession, AllocDecodingState};
use rustc::session::Session;
use rustc::ty::{self, Ty, TyCtxt};
@@ -1079,7 +1079,7 @@
self.root.per_def.mir.get(self, id).is_some()
}
- fn get_optimized_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> BodyCache<'tcx> {
+ fn get_optimized_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> BodyAndCache<'tcx> {
let mut cache = self.root.per_def.mir.get(self, id)
.filter(|_| !self.is_proc_macro(id))
.unwrap_or_else(|| {
@@ -1094,7 +1094,7 @@
&self,
tcx: TyCtxt<'tcx>,
id: DefIndex,
- ) -> IndexVec<Promoted, BodyCache<'tcx>> {
+ ) -> IndexVec<Promoted, BodyAndCache<'tcx>> {
let mut cache = self.root.per_def.promoted_mir.get(self, id)
.filter(|_| !self.is_proc_macro(id))
.unwrap_or_else(|| {
diff --git a/src/librustc_metadata/rmeta/mod.rs b/src/librustc_metadata/rmeta/mod.rs
index fdf43f0..5abae42 100644
--- a/src/librustc_metadata/rmeta/mod.rs
+++ b/src/librustc_metadata/rmeta/mod.rs
@@ -276,8 +276,8 @@
// Also, as an optimization, a missing entry indicates an empty `&[]`.
inferred_outlives: Table<DefIndex, Lazy!(&'tcx [(ty::Predicate<'tcx>, Span)])>,
super_predicates: Table<DefIndex, Lazy!(ty::GenericPredicates<'tcx>)>,
- mir: Table<DefIndex, Lazy!(mir::BodyCache<'tcx>)>,
- promoted_mir: Table<DefIndex, Lazy!(IndexVec<mir::Promoted, mir::BodyCache<'tcx>>)>,
+ mir: Table<DefIndex, Lazy!(mir::BodyAndCache<'tcx>)>,
+ promoted_mir: Table<DefIndex, Lazy!(IndexVec<mir::Promoted, mir::BodyAndCache<'tcx>>)>,
}
#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
diff --git a/src/librustc_mir/Cargo.toml b/src/librustc_mir/Cargo.toml
index 4afbb4d..7e3bd98 100644
--- a/src/librustc_mir/Cargo.toml
+++ b/src/librustc_mir/Cargo.toml
@@ -16,7 +16,7 @@
itertools = "0.8"
log = "0.4"
log_settings = "0.1.1"
-polonius-engine = "0.10.0"
+polonius-engine = "0.11.0"
rustc = { path = "../librustc" }
rustc_target = { path = "../librustc_target" }
rustc_data_structures = { path = "../librustc_data_structures" }
diff --git a/src/librustc_mir/borrow_check/borrow_set.rs b/src/librustc_mir/borrow_check/borrow_set.rs
index 802464c..2980483 100644
--- a/src/librustc_mir/borrow_check/borrow_set.rs
+++ b/src/librustc_mir/borrow_check/borrow_set.rs
@@ -5,7 +5,7 @@
use crate::dataflow::move_paths::MoveData;
use rustc::mir::traversal;
use rustc::mir::visit::{PlaceContext, Visitor, NonUseContext, MutatingUseContext};
-use rustc::mir::{self, Location, Body, Local, ReadOnlyBodyCache};
+use rustc::mir::{self, Location, Body, Local, ReadOnlyBodyAndCache};
use rustc::ty::{RegionVid, TyCtxt};
use rustc::util::nodemap::{FxHashMap, FxHashSet};
use rustc_index::vec::IndexVec;
@@ -90,7 +90,7 @@
impl LocalsStateAtExit {
fn build(
locals_are_invalidated_at_exit: bool,
- body: ReadOnlyBodyCache<'_, 'tcx>,
+ body: ReadOnlyBodyAndCache<'_, 'tcx>,
move_data: &MoveData<'tcx>
) -> Self {
struct HasStorageDead(BitSet<Local>);
@@ -124,7 +124,7 @@
impl<'tcx> BorrowSet<'tcx> {
pub fn build(
tcx: TyCtxt<'tcx>,
- body: ReadOnlyBodyCache<'_, 'tcx>,
+ body: ReadOnlyBodyAndCache<'_, 'tcx>,
locals_are_invalidated_at_exit: bool,
move_data: &MoveData<'tcx>,
) -> Self {
diff --git a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
index d14957b..a0f126f 100644
--- a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
@@ -240,15 +240,16 @@
let tcx = self.infcx.tcx;
let generics = tcx.generics_of(self.mir_def_id);
let param = generics.type_param(¶m_ty, tcx);
- let generics = tcx.hir().get_generics(self.mir_def_id).unwrap();
- suggest_constraining_type_param(
- generics,
- &mut err,
- ¶m.name.as_str(),
- "Copy",
- tcx.sess.source_map(),
- span,
- );
+ if let Some(generics) = tcx.hir().get_generics(self.mir_def_id) {
+ suggest_constraining_type_param(
+ generics,
+ &mut err,
+ ¶m.name.as_str(),
+ "Copy",
+ tcx.sess.source_map(),
+ span,
+ );
+ }
}
let span = if let Some(local) = place.as_local() {
let decl = &self.body.local_decls[local];
diff --git a/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs b/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs
index 6449ae3..016a319 100644
--- a/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs
@@ -1,6 +1,6 @@
use rustc::hir;
use rustc::hir::Node;
-use rustc::mir::{self, ClearCrossCrate, Local, LocalInfo, Location, ReadOnlyBodyCache};
+use rustc::mir::{self, ClearCrossCrate, Local, LocalInfo, Location, ReadOnlyBodyAndCache};
use rustc::mir::{Mutability, Place, PlaceRef, PlaceBase, ProjectionElem};
use rustc::ty::{self, Ty, TyCtxt};
use rustc_index::vec::Idx;
@@ -533,7 +533,7 @@
// by trying (3.), then (2.) and finally falling back on (1.).
fn suggest_ampmut<'tcx>(
tcx: TyCtxt<'tcx>,
- body: ReadOnlyBodyCache<'_, 'tcx>,
+ body: ReadOnlyBodyAndCache<'_, 'tcx>,
local: Local,
local_decl: &mir::LocalDecl<'tcx>,
opt_ty_info: Option<Span>,
diff --git a/src/librustc_mir/borrow_check/flows.rs b/src/librustc_mir/borrow_check/flows.rs
index ce5d2a1..57c544f 100644
--- a/src/librustc_mir/borrow_check/flows.rs
+++ b/src/librustc_mir/borrow_check/flows.rs
@@ -3,16 +3,15 @@
//! FIXME: this might be better as a "generic" fixed-point combinator,
//! but is not as ugly as it is right now.
-use rustc::mir::{BasicBlock, Local, Location};
-use rustc::ty::RegionVid;
+use rustc::mir::{BasicBlock, Location};
use rustc_index::bit_set::BitIter;
use crate::borrow_check::location::LocationIndex;
-use polonius_engine::Output;
+use crate::borrow_check::nll::PoloniusOutput;
use crate::dataflow::indexes::BorrowIndex;
-use crate::dataflow::move_paths::{HasMoveData, MovePathIndex};
+use crate::dataflow::move_paths::HasMoveData;
use crate::dataflow::Borrows;
use crate::dataflow::EverInitializedPlaces;
use crate::dataflow::MaybeUninitializedPlaces;
@@ -21,8 +20,6 @@
use std::fmt;
use std::rc::Rc;
-crate type PoloniusOutput = Output<RegionVid, BorrowIndex, LocationIndex, Local, MovePathIndex>;
-
crate struct Flows<'b, 'tcx> {
borrows: FlowAtLocation<'tcx, Borrows<'b, 'tcx>>,
pub uninits: FlowAtLocation<'tcx, MaybeUninitializedPlaces<'b, 'tcx>>,
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index a1932b5..427003f 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -9,8 +9,8 @@
use rustc::lint::builtin::{MUTABLE_BORROW_RESERVATION_CONFLICT};
use rustc::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
use rustc::mir::{
- ClearCrossCrate, Local, Location, Body, BodyCache, Mutability, Operand, Place, PlaceBase,
- PlaceElem, PlaceRef, ReadOnlyBodyCache, Static, StaticKind, read_only
+ ClearCrossCrate, Local, Location, Body, BodyAndCache, Mutability, Operand, Place, PlaceBase,
+ PlaceElem, PlaceRef, ReadOnlyBodyAndCache, Static, StaticKind, read_only
};
use rustc::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind};
use rustc::mir::{Terminator, TerminatorKind};
@@ -99,7 +99,7 @@
fn do_mir_borrowck<'a, 'tcx>(
infcx: &InferCtxt<'a, 'tcx>,
input_body: &Body<'tcx>,
- input_promoted: &IndexVec<Promoted, BodyCache<'tcx>>,
+ input_promoted: &IndexVec<Promoted, BodyAndCache<'tcx>>,
def_id: DefId,
) -> BorrowCheckResult<'tcx> {
debug!("do_mir_borrowck(def_id = {:?})", def_id);
@@ -161,7 +161,7 @@
// will have a lifetime tied to the inference context.
let body_clone: Body<'tcx> = input_body.clone();
let mut promoted = input_promoted.clone();
- let mut body = BodyCache::new(body_clone);
+ let mut body = BodyAndCache::new(body_clone);
let free_regions =
nll::replace_regions_in_mir(infcx, def_id, param_env, &mut body, &mut promoted);
let body = read_only!(body); // no further changes
@@ -402,7 +402,7 @@
crate struct MirBorrowckCtxt<'cx, 'tcx> {
crate infcx: &'cx InferCtxt<'cx, 'tcx>,
- body: ReadOnlyBodyCache<'cx, 'tcx>,
+ body: ReadOnlyBodyAndCache<'cx, 'tcx>,
mir_def_id: DefId,
param_env: ty::ParamEnv<'tcx>,
move_data: &'cx MoveData<'tcx>,
@@ -493,7 +493,7 @@
type FlowState = Flows<'cx, 'tcx>;
fn body(&self) -> &'cx Body<'tcx> {
- self.body.body()
+ *self.body
}
fn visit_block_entry(&mut self, bb: BasicBlock, flow_state: &Self::FlowState) {
diff --git a/src/librustc_mir/borrow_check/nll/facts.rs b/src/librustc_mir/borrow_check/nll/facts.rs
index 13e5769..a16c36d 100644
--- a/src/librustc_mir/borrow_check/nll/facts.rs
+++ b/src/librustc_mir/borrow_check/nll/facts.rs
@@ -1,6 +1,6 @@
use crate::borrow_check::location::{LocationIndex, LocationTable};
use crate::dataflow::indexes::{BorrowIndex, MovePathIndex};
-use polonius_engine::AllFacts as PoloniusAllFacts;
+use polonius_engine::AllFacts as PoloniusFacts;
use polonius_engine::Atom;
use rustc::mir::Local;
use rustc::ty::{RegionVid, TyCtxt};
@@ -11,7 +11,18 @@
use std::io::Write;
use std::path::Path;
-crate type AllFacts = PoloniusAllFacts<RegionVid, BorrowIndex, LocationIndex, Local, MovePathIndex>;
+#[derive(Copy, Clone, Debug)]
+crate struct RustcFacts;
+
+impl polonius_engine::FactTypes for RustcFacts {
+ type Origin = RegionVid;
+ type Loan = BorrowIndex;
+ type Point = LocationIndex;
+ type Variable = Local;
+ type Path = MovePathIndex;
+}
+
+crate type AllFacts = PoloniusFacts<RustcFacts>;
crate trait AllFactsExt {
/// Returns `true` if there is a need to gather `AllFacts` given the
@@ -55,6 +66,7 @@
wr.write_facts_to_path(self.[
borrow_region,
universal_region,
+ placeholder,
cfg_edge,
killed,
outlives,
@@ -69,6 +81,7 @@
initialized_at,
moved_out_at,
path_accessed_at,
+ known_subset,
])
}
Ok(())
diff --git a/src/librustc_mir/borrow_check/nll/invalidation.rs b/src/librustc_mir/borrow_check/nll/invalidation.rs
index 98679f2..2442bdf 100644
--- a/src/librustc_mir/borrow_check/nll/invalidation.rs
+++ b/src/librustc_mir/borrow_check/nll/invalidation.rs
@@ -11,7 +11,7 @@
use crate::dataflow::indexes::BorrowIndex;
use rustc::ty::{self, TyCtxt};
use rustc::mir::visit::Visitor;
-use rustc::mir::{BasicBlock, Location, Body, Place, ReadOnlyBodyCache, Rvalue};
+use rustc::mir::{BasicBlock, Location, Body, Place, ReadOnlyBodyAndCache, Rvalue};
use rustc::mir::{Statement, StatementKind};
use rustc::mir::TerminatorKind;
use rustc::mir::{Operand, BorrowKind};
@@ -22,7 +22,7 @@
param_env: ty::ParamEnv<'tcx>,
all_facts: &mut Option<AllFacts>,
location_table: &LocationTable,
- body: ReadOnlyBodyCache<'_, 'tcx>,
+ body: ReadOnlyBodyAndCache<'_, 'tcx>,
borrow_set: &BorrowSet<'tcx>,
) {
if all_facts.is_none() {
diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs
index b936320..bbcb823 100644
--- a/src/librustc_mir/borrow_check/nll/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/mod.rs
@@ -1,10 +1,9 @@
use crate::borrow_check::borrow_set::BorrowSet;
-use crate::borrow_check::location::{LocationIndex, LocationTable};
+use crate::borrow_check::location::LocationTable;
use crate::borrow_check::nll::facts::AllFactsExt;
use crate::borrow_check::nll::type_check::{MirTypeckResults, MirTypeckRegionConstraints};
use crate::borrow_check::nll::region_infer::values::RegionValueElements;
-use crate::dataflow::indexes::BorrowIndex;
-use crate::dataflow::move_paths::{InitLocation, MoveData, MovePathIndex, InitKind};
+use crate::dataflow::move_paths::{InitLocation, MoveData, InitKind};
use crate::dataflow::FlowAtLocation;
use crate::dataflow::MaybeInitializedPlaces;
use crate::transform::MirSource;
@@ -12,8 +11,8 @@
use rustc::hir::def_id::DefId;
use rustc::infer::InferCtxt;
use rustc::mir::{ClosureOutlivesSubject, ClosureRegionRequirements,
- Local, Location, Body, BodyCache, LocalKind, BasicBlock,
- Promoted, ReadOnlyBodyCache};
+ Local, Location, Body, BodyAndCache, LocalKind, BasicBlock,
+ Promoted, ReadOnlyBodyAndCache};
use rustc::ty::{self, RegionKind, RegionVid};
use rustc_index::vec::IndexVec;
use rustc_errors::Diagnostic;
@@ -43,10 +42,12 @@
crate mod type_check;
crate mod region_infer;
-use self::facts::AllFacts;
+use self::facts::{AllFacts, RustcFacts};
use self::region_infer::RegionInferenceContext;
use self::universal_regions::UniversalRegions;
+crate type PoloniusOutput = Output<RustcFacts>;
+
/// Rewrites the regions in the MIR to use NLL variables, also
/// scraping out the set of universal regions (e.g., region parameters)
/// declared on the function. That set will need to be given to
@@ -55,8 +56,8 @@
infcx: &InferCtxt<'cx, 'tcx>,
def_id: DefId,
param_env: ty::ParamEnv<'tcx>,
- body: &mut BodyCache<'tcx>,
- promoted: &mut IndexVec<Promoted, BodyCache<'tcx>>,
+ body: &mut BodyAndCache<'tcx>,
+ promoted: &mut IndexVec<Promoted, BodyAndCache<'tcx>>,
) -> UniversalRegions<'tcx> {
debug!("replace_regions_in_mir(def_id={:?})", def_id);
@@ -158,8 +159,8 @@
infcx: &InferCtxt<'cx, 'tcx>,
def_id: DefId,
universal_regions: UniversalRegions<'tcx>,
- body: ReadOnlyBodyCache<'_, 'tcx>,
- promoted: &IndexVec<Promoted, ReadOnlyBodyCache<'_, 'tcx>>,
+ body: ReadOnlyBodyAndCache<'_, 'tcx>,
+ promoted: &IndexVec<Promoted, ReadOnlyBodyAndCache<'_, 'tcx>>,
local_names: &IndexVec<Local, Option<Symbol>>,
upvars: &[Upvar],
location_table: &LocationTable,
@@ -170,14 +171,10 @@
errors_buffer: &mut Vec<Diagnostic>,
) -> (
RegionInferenceContext<'tcx>,
- Option<Rc<Output<RegionVid, BorrowIndex, LocationIndex, Local, MovePathIndex>>>,
+ Option<Rc<PoloniusOutput>>,
Option<ClosureRegionRequirements<'tcx>>,
) {
- let mut all_facts = if AllFacts::enabled(infcx.tcx) {
- Some(AllFacts::default())
- } else {
- None
- };
+ let mut all_facts = AllFacts::enabled(infcx.tcx).then_some(AllFacts::default());
let universal_regions = Rc::new(universal_regions);
@@ -208,6 +205,39 @@
.universal_region
.extend(universal_regions.universal_regions());
populate_polonius_move_facts(all_facts, move_data, location_table, &body);
+
+ // Emit universal regions facts, and their relations, for Polonius.
+ //
+ // 1: universal regions are modeled in Polonius as a pair:
+ // - the universal region vid itself.
+ // - a "placeholder loan" associated to this universal region. Since they don't exist in
+ // the `borrow_set`, their `BorrowIndex` are synthesized as the universal region index
+ // added to the existing number of loans, as if they succeeded them in the set.
+ //
+ let borrow_count = borrow_set.borrows.len();
+ debug!(
+ "compute_regions: polonius placeholders, num_universals={}, borrow_count={}",
+ universal_regions.len(),
+ borrow_count
+ );
+
+ for universal_region in universal_regions.universal_regions() {
+ let universal_region_idx = universal_region.index();
+ let placeholder_loan_idx = borrow_count + universal_region_idx;
+ all_facts.placeholder.push((universal_region, placeholder_loan_idx.into()));
+ }
+
+ // 2: the universal region relations `outlives` constraints are emitted as
+ // `known_subset` facts.
+ for (fr1, fr2) in universal_region_relations.known_outlives() {
+ if fr1 != fr2 {
+ debug!(
+ "compute_regions: emitting polonius `known_subset` fr1={:?}, fr2={:?}",
+ fr1, fr2
+ );
+ all_facts.known_subset.push((*fr1, *fr2));
+ }
+ }
}
// Create the region inference context, taking ownership of the
@@ -269,7 +299,7 @@
if infcx.tcx.sess.opts.debugging_opts.polonius {
let algorithm = env::var("POLONIUS_ALGORITHM")
- .unwrap_or_else(|_| String::from("Hybrid"));
+ .unwrap_or_else(|_| String::from("Naive"));
let algorithm = Algorithm::from_str(&algorithm).unwrap();
debug!("compute_regions: using polonius algorithm {:?}", algorithm);
Some(Rc::new(Output::compute(
@@ -283,8 +313,15 @@
});
// Solve the region constraints.
- let closure_region_requirements =
- regioncx.solve(infcx, &body, local_names, upvars, def_id, errors_buffer);
+ let closure_region_requirements = regioncx.solve(
+ infcx,
+ &body,
+ local_names,
+ upvars,
+ def_id,
+ errors_buffer,
+ polonius_output.clone(),
+ );
// Dump MIR results into a file, if that is enabled. This let us
// write unit-tests, as well as helping with debugging.
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 85031d6..d62537b 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
@@ -44,7 +44,7 @@
use self::values::{LivenessValues, RegionValueElements, RegionValues};
use super::universal_regions::UniversalRegions;
-use super::ToRegionVid;
+use super::{PoloniusOutput, ToRegionVid};
mod dump_mir;
mod graphviz;
@@ -484,6 +484,7 @@
upvars: &[Upvar],
mir_def_id: DefId,
errors_buffer: &mut Vec<Diagnostic>,
+ polonius_output: Option<Rc<PoloniusOutput>>,
) -> Option<ClosureRegionRequirements<'tcx>> {
self.propagate_constraints(body);
@@ -493,7 +494,7 @@
// functions below, which will trigger them to report errors
// eagerly.
let mut outlives_requirements =
- if infcx.tcx.is_closure(mir_def_id) { Some(vec![]) } else { None };
+ infcx.tcx.is_closure(mir_def_id).then(|| vec![]);
self.check_type_tests(
infcx,
@@ -509,16 +510,33 @@
// multiple problems.
let mut region_naming = RegionErrorNamingCtx::new();
- self.check_universal_regions(
- infcx,
- body,
- local_names,
- upvars,
- mir_def_id,
- outlives_requirements.as_mut(),
- errors_buffer,
- &mut region_naming,
- );
+ // In Polonius mode, the errors about missing universal region relations are in the output
+ // and need to be emitted or propagated. Otherwise, we need to check whether the
+ // constraints were too strong, and if so, emit or propagate those errors.
+ if infcx.tcx.sess.opts.debugging_opts.polonius {
+ self.check_polonius_subset_errors(
+ infcx,
+ body,
+ local_names,
+ upvars,
+ mir_def_id,
+ outlives_requirements.as_mut(),
+ errors_buffer,
+ &mut region_naming,
+ polonius_output.expect("Polonius output is unavailable despite `-Z polonius`"),
+ );
+ } else {
+ self.check_universal_regions(
+ infcx,
+ body,
+ local_names,
+ upvars,
+ mir_def_id,
+ outlives_requirements.as_mut(),
+ errors_buffer,
+ &mut region_naming,
+ );
+ }
self.check_member_constraints(infcx, mir_def_id, errors_buffer);
@@ -709,14 +727,11 @@
let min = |r1: ty::RegionVid, r2: ty::RegionVid| -> Option<ty::RegionVid> {
let r1_outlives_r2 = self.universal_region_relations.outlives(r1, r2);
let r2_outlives_r1 = self.universal_region_relations.outlives(r2, r1);
- if r1_outlives_r2 && r2_outlives_r1 {
- Some(r1.min(r2))
- } else if r1_outlives_r2 {
- Some(r2)
- } else if r2_outlives_r1 {
- Some(r1)
- } else {
- None
+ match (r1_outlives_r2, r2_outlives_r1) {
+ (true, true) => Some(r1.min(r2)),
+ (true, false) => Some(r2),
+ (false, true) => Some(r1),
+ (false, false) => None,
}
};
let mut min_choice = choice_regions[0];
@@ -1375,6 +1390,114 @@
outlives_suggestion.add_suggestion(body, self, infcx, errors_buffer, region_naming);
}
+ /// Checks if Polonius has found any unexpected free region relations.
+ ///
+ /// In Polonius terms, a "subset error" (or "illegal subset relation error") is the equivalent
+ /// of NLL's "checking if any region constraints were too strong": a placeholder origin `'a`
+ /// was unexpectedly found to be a subset of another placeholder origin `'b`, and means in NLL
+ /// terms that the "longer free region" `'a` outlived the "shorter free region" `'b`.
+ ///
+ /// More details can be found in this blog post by Niko:
+ /// http://smallcultfollowing.com/babysteps/blog/2019/01/17/polonius-and-region-errors/
+ ///
+ /// In the canonical example
+ ///
+ /// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x }
+ ///
+ /// returning `x` requires `&'a u32 <: &'b u32` and hence we establish (transitively) a
+ /// constraint that `'a: 'b`. It is an error that we have no evidence that this
+ /// constraint holds.
+ ///
+ /// If `propagated_outlives_requirements` is `Some`, then we will
+ /// push unsatisfied obligations into there. Otherwise, we'll
+ /// report them as errors.
+ fn check_polonius_subset_errors(
+ &self,
+ infcx: &InferCtxt<'_, 'tcx>,
+ body: &Body<'tcx>,
+ local_names: &IndexVec<Local, Option<Symbol>>,
+ upvars: &[Upvar],
+ mir_def_id: DefId,
+ mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
+ errors_buffer: &mut Vec<Diagnostic>,
+ region_naming: &mut RegionErrorNamingCtx,
+ polonius_output: Rc<PoloniusOutput>,
+ ) {
+ debug!(
+ "check_polonius_subset_errors: {} subset_errors",
+ polonius_output.subset_errors.len()
+ );
+
+ let mut outlives_suggestion = OutlivesSuggestionBuilder::new(mir_def_id, local_names);
+
+ // Similarly to `check_universal_regions`: a free region relation, which was not explicitly
+ // declared ("known") was found by Polonius, so emit an error, or propagate the
+ // requirements for our caller into the `propagated_outlives_requirements` vector.
+ //
+ // Polonius doesn't model regions ("origins") as CFG-subsets or durations, but the
+ // `longer_fr` and `shorter_fr` terminology will still be used here, for consistency with
+ // the rest of the NLL infrastructure. The "subset origin" is the "longer free region",
+ // and the "superset origin" is the outlived "shorter free region".
+ //
+ // Note: Polonius will produce a subset error at every point where the unexpected
+ // `longer_fr`'s "placeholder loan" is contained in the `shorter_fr`. This can be helpful
+ // for diagnostics in the future, e.g. to point more precisely at the key locations
+ // requiring this constraint to hold. However, the error and diagnostics code downstream
+ // expects that these errors are not duplicated (and that they are in a certain order).
+ // Otherwise, diagnostics messages such as the ones giving names like `'1` to elided or
+ // anonymous lifetimes for example, could give these names differently, while others like
+ // the outlives suggestions or the debug output from `#[rustc_regions]` would be
+ // duplicated. The polonius subset errors are deduplicated here, while keeping the
+ // CFG-location ordering.
+ let mut subset_errors: Vec<_> = polonius_output
+ .subset_errors
+ .iter()
+ .flat_map(|(_location, subset_errors)| subset_errors.iter())
+ .collect();
+ subset_errors.sort();
+ subset_errors.dedup();
+
+ for (longer_fr, shorter_fr) in subset_errors.into_iter() {
+ debug!("check_polonius_subset_errors: subset_error longer_fr={:?},\
+ shorter_fr={:?}", longer_fr, shorter_fr);
+
+ self.report_or_propagate_universal_region_error(
+ *longer_fr,
+ *shorter_fr,
+ infcx,
+ body,
+ local_names,
+ upvars,
+ mir_def_id,
+ &mut propagated_outlives_requirements,
+ &mut outlives_suggestion,
+ errors_buffer,
+ region_naming,
+ );
+ }
+
+ // Handle the placeholder errors as usual, until the chalk-rustc-polonius triumvirate has
+ // a more complete picture on how to separate this responsibility.
+ for (fr, fr_definition) in self.definitions.iter_enumerated() {
+ match fr_definition.origin {
+ NLLRegionVariableOrigin::FreeRegion => {
+ // handled by polonius above
+ }
+
+ NLLRegionVariableOrigin::Placeholder(placeholder) => {
+ self.check_bound_universal_region(infcx, body, mir_def_id, fr, placeholder);
+ }
+
+ NLLRegionVariableOrigin::Existential { .. } => {
+ // nothing to check here
+ }
+ }
+ }
+
+ // Emit outlives suggestions
+ outlives_suggestion.add_suggestion(body, self, infcx, errors_buffer, region_naming);
+ }
+
/// Checks the final value for the free region `fr` to see if it
/// grew too large. In particular, examine what `end(X)` points
/// wound up in `fr`'s final value; for each `end(X)` where `X !=
@@ -1474,8 +1597,37 @@
return None;
}
+ self.report_or_propagate_universal_region_error(
+ longer_fr,
+ shorter_fr,
+ infcx,
+ body,
+ local_names,
+ upvars,
+ mir_def_id,
+ propagated_outlives_requirements,
+ outlives_suggestion,
+ errors_buffer,
+ region_naming,
+ )
+ }
+
+ fn report_or_propagate_universal_region_error(
+ &self,
+ longer_fr: RegionVid,
+ shorter_fr: RegionVid,
+ infcx: &InferCtxt<'_, 'tcx>,
+ body: &Body<'tcx>,
+ local_names: &IndexVec<Local, Option<Symbol>>,
+ upvars: &[Upvar],
+ mir_def_id: DefId,
+ propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
+ outlives_suggestion: &mut OutlivesSuggestionBuilder<'_>,
+ errors_buffer: &mut Vec<Diagnostic>,
+ region_naming: &mut RegionErrorNamingCtx,
+ ) -> Option<ErrorReported> {
debug!(
- "check_universal_region_relation: fr={:?} does not outlive shorter_fr={:?}",
+ "report_or_propagate_universal_region_error: fr={:?} does not outlive shorter_fr={:?}",
longer_fr, shorter_fr,
);
@@ -1484,9 +1636,9 @@
// We'll call it `fr-` -- it's ever so slightly smaller than
// `longer_fr`.
- if let Some(fr_minus) = self.universal_region_relations.non_local_lower_bound(longer_fr)
- {
- debug!("check_universal_region: fr_minus={:?}", fr_minus);
+ if let Some(fr_minus) =
+ self.universal_region_relations.non_local_lower_bound(longer_fr) {
+ debug!("report_or_propagate_universal_region_error: fr_minus={:?}", fr_minus);
let blame_span_category =
self.find_outlives_blame_span(body, longer_fr,
@@ -1495,9 +1647,13 @@
// Grow `shorter_fr` until we find some non-local regions. (We
// always will.) We'll call them `shorter_fr+` -- they're ever
// so slightly larger than `shorter_fr`.
- let shorter_fr_plus =
- self.universal_region_relations.non_local_upper_bounds(&shorter_fr);
- debug!("check_universal_region: shorter_fr_plus={:?}", shorter_fr_plus);
+ let shorter_fr_plus = self
+ .universal_region_relations
+ .non_local_upper_bounds(&shorter_fr);
+ debug!(
+ "report_or_propagate_universal_region_error: shorter_fr_plus={:?}",
+ shorter_fr_plus
+ );
for &&fr in &shorter_fr_plus {
// Push the constraint `fr-: shorter_fr+`
propagated_outlives_requirements.push(ClosureOutlivesRequirement {
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/values.rs b/src/librustc_mir/borrow_check/nll/region_infer/values.rs
index b4414c5..0bf0cd3 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/values.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/values.rs
@@ -1,4 +1,4 @@
-use rustc::mir::{BasicBlock, Location, Body, ReadOnlyBodyCache};
+use rustc::mir::{BasicBlock, Location, Body, ReadOnlyBodyAndCache};
use rustc::ty::{self, RegionVid};
use rustc_index::bit_set::{HybridBitSet, SparseBitMatrix};
use rustc_data_structures::fx::FxHashMap;
@@ -92,7 +92,7 @@
/// Pushes all predecessors of `index` onto `stack`.
crate fn push_predecessors(
&self,
- body: ReadOnlyBodyCache<'_, '_>,
+ body: ReadOnlyBodyAndCache<'_, '_>,
index: PointIndex,
stack: &mut Vec<PointIndex>,
) {
diff --git a/src/librustc_mir/borrow_check/nll/renumber.rs b/src/librustc_mir/borrow_check/nll/renumber.rs
index db15d2c..ba323b1 100644
--- a/src/librustc_mir/borrow_check/nll/renumber.rs
+++ b/src/librustc_mir/borrow_check/nll/renumber.rs
@@ -1,6 +1,6 @@
use rustc::ty::subst::SubstsRef;
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
-use rustc::mir::{BodyCache, Location, PlaceElem, Promoted};
+use rustc::mir::{BodyAndCache, Location, PlaceElem, Promoted};
use rustc::mir::visit::{MutVisitor, TyContext};
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
use rustc_index::vec::IndexVec;
@@ -9,8 +9,8 @@
/// inference variables, returning the number of variables created.
pub fn renumber_mir<'tcx>(
infcx: &InferCtxt<'_, 'tcx>,
- body: &mut BodyCache<'tcx>,
- promoted: &mut IndexVec<Promoted, BodyCache<'tcx>>,
+ body: &mut BodyAndCache<'tcx>,
+ promoted: &mut IndexVec<Promoted, BodyAndCache<'tcx>>,
) {
debug!("renumber_mir()");
debug!("renumber_mir: body.arg_count={:?}", body.arg_count);
diff --git a/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs b/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs
index d18a8e8..8bb6838 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs
@@ -217,6 +217,11 @@
crate fn regions_outlived_by(&self, fr1: RegionVid) -> Vec<&RegionVid> {
self.outlives.reachable_from(&fr1)
}
+
+ /// Returns the _non-transitive_ set of known `outlives` constraints between free regions.
+ crate fn known_outlives(&self) -> impl Iterator<Item=(&RegionVid, &RegionVid)> {
+ self.outlives.base_edges()
+ }
}
struct UniversalRegionRelationsBuilder<'this, 'tcx> {
diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs
index d6aa314..ab8c6f2 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs
@@ -1,7 +1,7 @@
use crate::borrow_check::nll::region_infer::values::{PointIndex, RegionValueElements};
use crate::util::liveness::{categorize, DefUse};
use rustc::mir::visit::{PlaceContext, Visitor};
-use rustc::mir::{Local, Location, ReadOnlyBodyCache};
+use rustc::mir::{Local, Location, ReadOnlyBodyAndCache};
use rustc_index::vec::{Idx, IndexVec};
use rustc_data_structures::vec_linked_list as vll;
@@ -60,7 +60,7 @@
crate fn build(
live_locals: &Vec<Local>,
elements: &RegionValueElements,
- body: ReadOnlyBodyCache<'_, '_>,
+ body: ReadOnlyBodyAndCache<'_, '_>,
) -> Self {
let nones = IndexVec::from_elem_n(None, body.local_decls.len());
let mut local_use_map = LocalUseMap {
diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs
index dfd505f..8f8e9af 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs
@@ -7,7 +7,7 @@
use crate::dataflow::move_paths::MoveData;
use crate::dataflow::FlowAtLocation;
use crate::dataflow::MaybeInitializedPlaces;
-use rustc::mir::{Body, Local, ReadOnlyBodyCache};
+use rustc::mir::{Body, Local, ReadOnlyBodyAndCache};
use rustc::ty::{RegionVid, TyCtxt};
use rustc_data_structures::fx::FxHashSet;
use std::rc::Rc;
@@ -28,7 +28,7 @@
/// performed before
pub(super) fn generate<'tcx>(
typeck: &mut TypeChecker<'_, 'tcx>,
- body: ReadOnlyBodyCache<'_, 'tcx>,
+ body: ReadOnlyBodyAndCache<'_, 'tcx>,
elements: &Rc<RegionValueElements>,
flow_inits: &mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'_, 'tcx>>,
move_data: &MoveData<'tcx>,
diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/polonius.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/polonius.rs
index e67de6c..810811f 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/liveness/polonius.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/polonius.rs
@@ -3,7 +3,7 @@
use crate::dataflow::move_paths::{LookupResult, MoveData};
use crate::util::liveness::{categorize, DefUse};
use rustc::mir::visit::{MutatingUseContext, PlaceContext, Visitor};
-use rustc::mir::{Local, Location, Place, ReadOnlyBodyCache};
+use rustc::mir::{Local, Location, Place, ReadOnlyBodyAndCache};
use rustc::ty::subst::GenericArg;
use rustc::ty::Ty;
@@ -97,7 +97,7 @@
pub(super) fn populate_access_facts(
typeck: &mut TypeChecker<'_, 'tcx>,
- body: ReadOnlyBodyCache<'_, 'tcx>,
+ body: ReadOnlyBodyAndCache<'_, 'tcx>,
location_table: &LocationTable,
move_data: &MoveData<'_>,
drop_used: &mut Vec<(Local, Location)>,
diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs
index 229cbed..ba6fd75 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs
@@ -7,7 +7,7 @@
use crate::dataflow::move_paths::MoveData;
use crate::dataflow::{FlowAtLocation, FlowsAtLocation, MaybeInitializedPlaces};
use rustc::infer::canonical::QueryRegionConstraints;
-use rustc::mir::{BasicBlock, ConstraintCategory, Local, Location, ReadOnlyBodyCache};
+use rustc::mir::{BasicBlock, ConstraintCategory, Local, Location, ReadOnlyBodyAndCache};
use rustc::traits::query::dropck_outlives::DropckOutlivesResult;
use rustc::traits::query::type_op::outlives::DropckOutlives;
use rustc::traits::query::type_op::TypeOp;
@@ -32,7 +32,7 @@
/// this respects `#[may_dangle]` annotations).
pub(super) fn trace(
typeck: &mut TypeChecker<'_, 'tcx>,
- body: ReadOnlyBodyCache<'_, 'tcx>,
+ body: ReadOnlyBodyAndCache<'_, 'tcx>,
elements: &Rc<RegionValueElements>,
flow_inits: &mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'_, 'tcx>>,
move_data: &MoveData<'tcx>,
@@ -71,7 +71,7 @@
elements: &'me RegionValueElements,
/// MIR we are analyzing.
- body: ReadOnlyBodyCache<'me, 'tcx>,
+ body: ReadOnlyBodyAndCache<'me, 'tcx>,
/// Mapping to/from the various indices used for initialization tracking.
move_data: &'me MoveData<'tcx>,
@@ -249,7 +249,7 @@
// Reverse DFS. But for drops, we do it a bit differently.
// The stack only ever stores *terminators of blocks*. Within
// a block, we walk back the statements in an inner loop.
- 'next_block: while let Some(term_point) = self.stack.pop() {
+ while let Some(term_point) = self.stack.pop() {
self.compute_drop_live_points_for_block(mpi, term_point);
}
}
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 de30420..8d4e76c 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -117,8 +117,8 @@
pub(crate) fn type_check<'tcx>(
infcx: &InferCtxt<'_, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
- body: ReadOnlyBodyCache<'_, 'tcx>,
- promoted: &IndexVec<Promoted, ReadOnlyBodyCache<'_, 'tcx>>,
+ body: ReadOnlyBodyAndCache<'_, 'tcx>,
+ promoted: &IndexVec<Promoted, ReadOnlyBodyAndCache<'_, 'tcx>>,
mir_def_id: DefId,
universal_regions: &Rc<UniversalRegions<'tcx>>,
location_table: &LocationTable,
@@ -196,8 +196,8 @@
infcx: &'a InferCtxt<'a, 'tcx>,
mir_def_id: DefId,
param_env: ty::ParamEnv<'tcx>,
- body: ReadOnlyBodyCache<'a, 'tcx>,
- promoted: &'a IndexVec<Promoted, ReadOnlyBodyCache<'_, 'tcx>>,
+ body: ReadOnlyBodyAndCache<'a, 'tcx>,
+ promoted: &'a IndexVec<Promoted, ReadOnlyBodyAndCache<'_, 'tcx>>,
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
implicit_region_bound: ty::Region<'tcx>,
borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
@@ -206,7 +206,7 @@
) -> R {
let mut checker = TypeChecker::new(
infcx,
- body.body(),
+ *body,
mir_def_id,
param_env,
region_bound_pairs,
@@ -215,7 +215,7 @@
universal_region_relations,
);
let errors_reported = {
- let mut verifier = TypeVerifier::new(&mut checker, body.body(), promoted);
+ let mut verifier = TypeVerifier::new(&mut checker, *body, promoted);
verifier.visit_body(body);
verifier.errors_reported
};
@@ -272,7 +272,7 @@
struct TypeVerifier<'a, 'b, 'tcx> {
cx: &'a mut TypeChecker<'b, 'tcx>,
body: &'b Body<'tcx>,
- promoted: &'b IndexVec<Promoted, ReadOnlyBodyCache<'b, 'tcx>>,
+ promoted: &'b IndexVec<Promoted, ReadOnlyBodyAndCache<'b, 'tcx>>,
last_span: Span,
mir_def_id: DefId,
errors_reported: bool,
@@ -396,7 +396,7 @@
}
}
- fn visit_body(&mut self, body: ReadOnlyBodyCache<'_, 'tcx>) {
+ fn visit_body(&mut self, body: ReadOnlyBodyAndCache<'_, 'tcx>) {
self.sanitize_type(&"return type", body.return_ty());
for local_decl in &body.local_decls {
self.sanitize_type(local_decl, local_decl.ty);
@@ -412,7 +412,7 @@
fn new(
cx: &'a mut TypeChecker<'b, 'tcx>,
body: &'b Body<'tcx>,
- promoted: &'b IndexVec<Promoted, ReadOnlyBodyCache<'b, 'tcx>>,
+ promoted: &'b IndexVec<Promoted, ReadOnlyBodyAndCache<'b, 'tcx>>,
) -> Self {
TypeVerifier {
body,
@@ -548,14 +548,14 @@
fn sanitize_promoted(
&mut self,
- promoted_body: ReadOnlyBodyCache<'b, 'tcx>,
+ promoted_body: ReadOnlyBodyAndCache<'b, 'tcx>,
location: Location
) {
// Determine the constraints from the promoted MIR by running the type
// checker on the promoted MIR, then transfer the constraints back to
// the main MIR, changing the locations to the provided location.
- let parent_body = mem::replace(&mut self.body, promoted_body.body());
+ let parent_body = mem::replace(&mut self.body, *promoted_body);
// Use new sets of constraints and closure bounds so that we can
// modify their locations.
@@ -1378,7 +1378,7 @@
fn check_stmt(
&mut self,
- body: ReadOnlyBodyCache<'_, 'tcx>,
+ body: ReadOnlyBodyAndCache<'_, 'tcx>,
stmt: &Statement<'tcx>,
location: Location)
{
@@ -1994,7 +1994,7 @@
fn check_rvalue(
&mut self,
- body: ReadOnlyBodyCache<'_, 'tcx>,
+ body: ReadOnlyBodyAndCache<'_, 'tcx>,
rvalue: &Rvalue<'tcx>,
location: Location)
{
@@ -2766,7 +2766,7 @@
})
}
- fn typeck_mir(&mut self, body: ReadOnlyBodyCache<'_, 'tcx>) {
+ fn typeck_mir(&mut self, body: ReadOnlyBodyAndCache<'_, 'tcx>) {
self.last_span = body.span;
debug!("run_on_mir: {:?}", body.span);
diff --git a/src/librustc_mir/borrow_check/prefixes.rs b/src/librustc_mir/borrow_check/prefixes.rs
index b58bf73..248faa5 100644
--- a/src/librustc_mir/borrow_check/prefixes.rs
+++ b/src/librustc_mir/borrow_check/prefixes.rs
@@ -11,7 +11,7 @@
use rustc::hir;
use rustc::ty::{self, TyCtxt};
-use rustc::mir::{Place, PlaceBase, PlaceRef, ProjectionElem, ReadOnlyBodyCache};
+use rustc::mir::{Place, PlaceBase, PlaceRef, ProjectionElem, ReadOnlyBodyAndCache};
pub trait IsPrefixOf<'cx, 'tcx> {
fn is_prefix_of(&self, other: PlaceRef<'cx, 'tcx>) -> bool;
@@ -26,7 +26,7 @@
}
pub(super) struct Prefixes<'cx, 'tcx> {
- body: ReadOnlyBodyCache<'cx, 'tcx>,
+ body: ReadOnlyBodyAndCache<'cx, 'tcx>,
tcx: TyCtxt<'tcx>,
kind: PrefixSet,
next: Option<PlaceRef<'cx, 'tcx>>,
diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs
index c893d6f..e320811 100644
--- a/src/librustc_mir/build/matches/test.rs
+++ b/src/librustc_mir/build/matches/test.rs
@@ -680,7 +680,7 @@
}
})();
- if no_overlap == Some(true) {
+ if let Some(true) = no_overlap {
// Testing range does not overlap with pattern range,
// so the pattern can be matched only if this test fails.
Some(1)
@@ -690,7 +690,7 @@
}
(&TestKind::Range(range), &PatKind::Constant { value }) => {
- if self.const_range_contains(range, value) == Some(false) {
+ if let Some(false) = self.const_range_contains(range, value) {
// `value` is not contained in the testing range,
// so `value` can be matched only if this test fails.
Some(1)
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index b84461d..0009eb4 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -24,7 +24,7 @@
use super::lints;
/// Construct the MIR for a given `DefId`.
-pub fn mir_build(tcx: TyCtxt<'_>, def_id: DefId) -> BodyCache<'_> {
+pub fn mir_build(tcx: TyCtxt<'_>, def_id: DefId) -> BodyAndCache<'_> {
let id = tcx.hir().as_local_hir_id(def_id).unwrap();
// Figure out what primary body this item has.
@@ -196,7 +196,7 @@
lints::check(tcx, &body, def_id);
- let mut body = BodyCache::new(body);
+ let mut body = BodyAndCache::new(body);
body.ensure_predecessors();
body
})
diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs
index 968a8a7..b219fec 100644
--- a/src/librustc_mir/const_eval.rs
+++ b/src/librustc_mir/const_eval.rs
@@ -9,11 +9,10 @@
use rustc::hir::def::DefKind;
use rustc::hir::def_id::DefId;
-use rustc::middle::lang_items::PanicLocationLangItem;
use rustc::mir::interpret::{ConstEvalErr, ErrorHandled, ScalarMaybeUndef};
use rustc::mir;
use rustc::ty::{self, Ty, TyCtxt, subst::Subst};
-use rustc::ty::layout::{self, LayoutOf, VariantIdx};
+use rustc::ty::layout::{self, HasTyCtxt, LayoutOf, VariantIdx};
use rustc::traits::Reveal;
use rustc_data_structures::fx::FxHashMap;
use crate::interpret::eval_nullary_intrinsic;
@@ -348,7 +347,11 @@
//
// For the moment we only do this for functions which take no arguments
// (or all arguments are ZSTs) so that we don't memoize too much.
- if args.iter().all(|a| a.layout.is_zst()) {
+ //
+ // Because `#[track_caller]` adds an implicit non-ZST argument, we also cannot
+ // perform this optimization on items tagged with it.
+ let no_implicit_args = !instance.def.requires_caller_location(ecx.tcx());
+ if args.iter().all(|a| a.layout.is_zst()) && no_implicit_args {
let gid = GlobalId { instance, promoted: None };
ecx.eval_const_fn_call(gid, ret)?;
return Ok(None);
@@ -366,7 +369,7 @@
}
// This is a const fn. Call it.
Ok(Some(match ecx.load_mir(instance.def, None) {
- Ok(body) => body.body(),
+ Ok(body) => *body,
Err(err) => {
if let err_unsup!(NoMirFor(ref path)) = err.kind {
return Err(
@@ -559,11 +562,7 @@
trace!("const_caller_location: {}:{}:{}", file, line, col);
let mut ecx = mk_eval_cx(tcx, DUMMY_SP, ty::ParamEnv::reveal_all());
- let loc_ty = tcx.mk_imm_ref(
- tcx.lifetimes.re_static,
- tcx.type_of(tcx.require_lang_item(PanicLocationLangItem, None))
- .subst(tcx, tcx.mk_substs([tcx.lifetimes.re_static.into()].iter())),
- );
+ let loc_ty = tcx.caller_location_ty();
let loc_place = ecx.alloc_caller_location(file, line, col);
intern_const_alloc_recursive(&mut ecx, None, loc_place).unwrap();
let loc_const = ty::Const {
@@ -743,7 +742,7 @@
let res = ecx.load_mir(cid.instance.def, cid.promoted);
res.and_then(
- |body| eval_body_using_ecx(&mut ecx, cid, body.body())
+ |body| eval_body_using_ecx(&mut ecx, cid, *body)
).and_then(|place| {
Ok(RawConst {
alloc_id: place.ptr.assert_ptr().alloc_id,
diff --git a/src/librustc_mir/dataflow/impls/storage_liveness.rs b/src/librustc_mir/dataflow/impls/storage_liveness.rs
index c4b97d1..b8abe6d 100644
--- a/src/librustc_mir/dataflow/impls/storage_liveness.rs
+++ b/src/librustc_mir/dataflow/impls/storage_liveness.rs
@@ -75,20 +75,20 @@
/// Dataflow analysis that determines whether each local requires storage at a
/// given location; i.e. whether its storage can go away without being observed.
pub struct RequiresStorage<'mir, 'tcx> {
- body: ReadOnlyBodyCache<'mir, 'tcx>,
+ body: ReadOnlyBodyAndCache<'mir, 'tcx>,
borrowed_locals:
RefCell<DataflowResultsRefCursor<'mir, 'tcx, HaveBeenBorrowedLocals<'mir, 'tcx>>>,
}
impl<'mir, 'tcx: 'mir> RequiresStorage<'mir, 'tcx> {
pub fn new(
- body: ReadOnlyBodyCache<'mir, 'tcx>,
+ body: ReadOnlyBodyAndCache<'mir, 'tcx>,
borrowed_locals: &'mir DataflowResults<'tcx, HaveBeenBorrowedLocals<'mir, 'tcx>>,
) -> Self {
RequiresStorage {
body,
borrowed_locals: RefCell::new(
- DataflowResultsCursor::new(borrowed_locals, body.body())
+ DataflowResultsCursor::new(borrowed_locals, *body)
),
}
}
diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs
index 92c7178..0086c3b 100644
--- a/src/librustc_mir/hair/pattern/mod.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -1154,13 +1154,7 @@
) -> Option<Ordering> {
trace!("compare_const_vals: {:?}, {:?}", a, b);
- let from_bool = |v: bool| {
- if v {
- Some(Ordering::Equal)
- } else {
- None
- }
- };
+ let from_bool = |v: bool| v.then_some(Ordering::Equal);
let fallback = || from_bool(a == b);
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index 9af47f3..653718c 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -312,7 +312,7 @@
&self,
instance: ty::InstanceDef<'tcx>,
promoted: Option<mir::Promoted>,
- ) -> InterpResult<'tcx, mir::ReadOnlyBodyCache<'tcx, 'tcx>> {
+ ) -> InterpResult<'tcx, mir::ReadOnlyBodyAndCache<'tcx, 'tcx>> {
// do not continue if typeck errors occurred (can only occur in local crate)
let did = instance.def_id();
if did.is_local()
diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs
index ad5df5a..67f0aed 100644
--- a/src/librustc_mir/interpret/intrinsics.rs
+++ b/src/librustc_mir/interpret/intrinsics.rs
@@ -112,6 +112,7 @@
// `src/librustc/ty/constness.rs`
match intrinsic_name {
sym::caller_location => {
+ let span = self.find_closest_untracked_caller_location().unwrap_or(span);
let location = self.alloc_caller_location_for_span(span);
self.write_scalar(location.ptr, dest)?;
}
diff --git a/src/librustc_mir/interpret/intrinsics/caller_location.rs b/src/librustc_mir/interpret/intrinsics/caller_location.rs
index ecf4b7a..ec843ef 100644
--- a/src/librustc_mir/interpret/intrinsics/caller_location.rs
+++ b/src/librustc_mir/interpret/intrinsics/caller_location.rs
@@ -6,6 +6,21 @@
use crate::interpret::{Scalar, MemoryKind, MPlaceTy, intrinsics::{InterpCx, Machine}};
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
+ /// Walks up the callstack from the intrinsic's callsite, searching for the first frame which is
+ /// not `#[track_caller]`.
+ crate fn find_closest_untracked_caller_location(&self) -> Option<Span> {
+ let mut caller_span = None;
+ for next_caller in self.stack.iter().rev() {
+ if !next_caller.instance.def.requires_caller_location(*self.tcx) {
+ return caller_span;
+ }
+ caller_span = Some(next_caller.span);
+ }
+
+ caller_span
+ }
+
+ /// Allocate a `const core::panic::Location` with the provided filename and line/column numbers.
crate fn alloc_caller_location(
&mut self,
filename: Symbol,
diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs
index ee7fb18..8f177ad 100644
--- a/src/librustc_mir/interpret/memory.rs
+++ b/src/librustc_mir/interpret/memory.rs
@@ -324,7 +324,7 @@
size: Size,
align: Align,
) -> InterpResult<'tcx, Option<Pointer<M::PointerTag>>> {
- let align = if M::CHECK_ALIGN { Some(align) } else { None };
+ let align = M::CHECK_ALIGN.then_some(align);
self.check_ptr_access_align(sptr, size, align, CheckInAllocMsg::MemoryAccessTest)
}
diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs
index 176b084..6800429 100644
--- a/src/librustc_mir/interpret/operator.rs
+++ b/src/librustc_mir/interpret/operator.rs
@@ -177,8 +177,8 @@
return Ok((Scalar::from_bool(op(&l, &r)), false, self.tcx.types.bool));
}
let op: Option<fn(i128, i128) -> (i128, bool)> = match bin_op {
- Div if r == 0 => throw_panic!(DivisionByZero),
- Rem if r == 0 => throw_panic!(RemainderByZero),
+ Div if r == 0 => throw_ub!(DivisionByZero),
+ Rem if r == 0 => throw_ub!(RemainderByZero),
Div => Some(i128::overflowing_div),
Rem => Some(i128::overflowing_rem),
Add => Some(i128::overflowing_add),
@@ -234,8 +234,8 @@
Add => u128::overflowing_add,
Sub => u128::overflowing_sub,
Mul => u128::overflowing_mul,
- Div if r == 0 => throw_panic!(DivisionByZero),
- Rem if r == 0 => throw_panic!(RemainderByZero),
+ Div if r == 0 => throw_ub!(DivisionByZero),
+ Rem if r == 0 => throw_ub!(RemainderByZero),
Div => u128::overflowing_div,
Rem => u128::overflowing_rem,
_ => bug!(),
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index 902472d..a600eb1 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -384,10 +384,8 @@
layout::FieldPlacement::Array { stride, .. } => {
let len = base.len(self)?;
if field >= len {
- // This can be violated because the index (field) can be a runtime value
- // provided by the user.
- debug!("tried to access element {} of array/slice with length {}", field, len);
- throw_panic!(BoundsCheck { len, index: field });
+ // This can only be reached in ConstProp and non-rustc-MIR.
+ throw_ub!(BoundsCheckFailed { len, index: field });
}
stride * field
}
diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs
index d749333..55b9427 100644
--- a/src/librustc_mir/interpret/step.rs
+++ b/src/librustc_mir/interpret/step.rs
@@ -157,9 +157,9 @@
}
BinaryOp(bin_op, ref left, ref right) => {
- let layout = if binop_left_homogeneous(bin_op) { Some(dest.layout) } else { None };
+ let layout = binop_left_homogeneous(bin_op).then_some(dest.layout);
let left = self.read_immediate(self.eval_operand(left, layout)?)?;
- let layout = if binop_right_homogeneous(bin_op) { Some(left.layout) } else { None };
+ let layout = binop_right_homogeneous(bin_op).then_some(left.layout);
let right = self.read_immediate(self.eval_operand(right, layout)?)?;
self.binop_ignore_overflow(
bin_op,
@@ -172,7 +172,7 @@
CheckedBinaryOp(bin_op, ref left, ref right) => {
// Due to the extra boolean in the result, we can never reuse the `dest.layout`.
let left = self.read_immediate(self.eval_operand(left, None)?)?;
- let layout = if binop_right_homogeneous(bin_op) { Some(left.layout) } else { None };
+ let layout = binop_right_homogeneous(bin_op).then_some(left.layout);
let right = self.read_immediate(self.eval_operand(right, layout)?)?;
self.binop_with_overflow(
bin_op,
diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs
index f4fb9a5..42b72b6 100644
--- a/src/librustc_mir/lib.rs
+++ b/src/librustc_mir/lib.rs
@@ -8,6 +8,7 @@
#![feature(in_band_lifetimes)]
#![feature(inner_deref)]
#![feature(slice_patterns)]
+#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(crate_visibility_modifier)]
@@ -27,7 +28,6 @@
#![feature(associated_type_bounds)]
#![feature(range_is_empty)]
#![feature(stmt_expr_attributes)]
-#![feature(bool_to_option)]
#![feature(trait_alias)]
#![feature(matches_macro)]
diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs
index 42f0877..591f220 100644
--- a/src/librustc_mir/monomorphize/partitioning.rs
+++ b/src/librustc_mir/monomorphize/partitioning.rs
@@ -761,11 +761,7 @@
.iter()
.map(|part| part.data.as_symbol());
- let volatile_suffix = if volatile {
- Some("volatile")
- } else {
- None
- };
+ let volatile_suffix = volatile.then_some("volatile");
name_builder.build_cgu_name(def_path.krate, components, volatile_suffix)
}).clone()
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index 5b208dd..47b0804 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -26,7 +26,7 @@
providers.mir_shims = make_shim;
}
-fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> &'tcx BodyCache<'tcx> {
+fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> &'tcx BodyAndCache<'tcx> {
debug!("make_shim({:?})", instance);
let mut result = match instance {
@@ -170,7 +170,7 @@
fn build_drop_shim<'tcx>(
tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>
-) -> BodyCache<'tcx> {
+) -> BodyAndCache<'tcx> {
debug!("build_drop_shim(def_id={:?}, ty={:?})", def_id, ty);
// Check if this is a generator, if so, return the drop glue for it
@@ -208,7 +208,7 @@
sig.inputs().len(),
span);
- let mut body = BodyCache::new(body);
+ let mut body = BodyAndCache::new(body);
if let Some(..) = ty {
// The first argument (index 0), but add 1 for the return value.
@@ -322,7 +322,11 @@
}
/// Builds a `Clone::clone` shim for `self_ty`. Here, `def_id` is `Clone::clone`.
-fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> BodyCache<'tcx> {
+fn build_clone_shim<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ def_id: DefId,
+ self_ty: Ty<'tcx>,
+) -> BodyAndCache<'tcx> {
debug!("build_clone_shim(def_id={:?})", def_id);
let param_env = tcx.param_env(def_id);
@@ -351,7 +355,7 @@
}
};
- BodyCache::new(builder.into_mir())
+ BodyAndCache::new(builder.into_mir())
}
struct CloneShimBuilder<'tcx> {
@@ -712,7 +716,7 @@
rcvr_adjustment: Adjustment,
call_kind: CallKind,
untuple_args: Option<&[Ty<'tcx>]>,
-) -> BodyCache<'tcx> {
+) -> BodyAndCache<'tcx> {
debug!("build_call_shim(instance={:?}, rcvr_adjustment={:?}, \
call_kind={:?}, untuple_args={:?})",
instance, rcvr_adjustment, call_kind, untuple_args);
@@ -853,10 +857,10 @@
if let Abi::RustCall = sig.abi {
body.spread_arg = Some(Local::new(sig.inputs().len()));
}
- BodyCache::new(body)
+ BodyAndCache::new(body)
}
-pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> &BodyCache<'_> {
+pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> &BodyAndCache<'_> {
debug_assert!(tcx.is_constructor(ctor_id));
let span = tcx.hir().span_if_local(ctor_id)
@@ -940,7 +944,7 @@
|_, _| Ok(()),
);
- let mut body = BodyCache::new(body);
+ let mut body = BodyAndCache::new(body);
body.ensure_predecessors();
tcx.arena.alloc(body)
}
diff --git a/src/librustc_mir/transform/add_call_guards.rs b/src/librustc_mir/transform/add_call_guards.rs
index 35238e2..d1832eb 100644
--- a/src/librustc_mir/transform/add_call_guards.rs
+++ b/src/librustc_mir/transform/add_call_guards.rs
@@ -32,14 +32,14 @@
impl<'tcx> MirPass<'tcx> for AddCallGuards {
fn run_pass(
- &self, _tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut BodyCache<'tcx>
+ &self, _tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>
) {
self.add_call_guards(body);
}
}
impl AddCallGuards {
- pub fn add_call_guards(&self, body: &mut BodyCache<'_>) {
+ pub fn add_call_guards(&self, body: &mut BodyAndCache<'_>) {
let pred_count: IndexVec<_, _> = body.predecessors().iter().map(|ps| ps.len()).collect();
// We need a place to store the new blocks generated
diff --git a/src/librustc_mir/transform/add_moves_for_packed_drops.rs b/src/librustc_mir/transform/add_moves_for_packed_drops.rs
index 98c6a5e..861e7fe 100644
--- a/src/librustc_mir/transform/add_moves_for_packed_drops.rs
+++ b/src/librustc_mir/transform/add_moves_for_packed_drops.rs
@@ -40,14 +40,14 @@
pub struct AddMovesForPackedDrops;
impl<'tcx> MirPass<'tcx> for AddMovesForPackedDrops {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyCache<'tcx>) {
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
debug!("add_moves_for_packed_drops({:?} @ {:?})", src, body.span);
add_moves_for_packed_drops(tcx, body, src.def_id());
}
}
pub fn add_moves_for_packed_drops<'tcx>(
- tcx: TyCtxt<'tcx>, body: &mut BodyCache<'tcx>, def_id: DefId
+ tcx: TyCtxt<'tcx>, body: &mut BodyAndCache<'tcx>, def_id: DefId
) {
let patch = add_moves_for_packed_drops_patch(tcx, body, def_id);
patch.apply(body);
diff --git a/src/librustc_mir/transform/add_retag.rs b/src/librustc_mir/transform/add_retag.rs
index e6ad37a..dc21c67 100644
--- a/src/librustc_mir/transform/add_retag.rs
+++ b/src/librustc_mir/transform/add_retag.rs
@@ -59,7 +59,7 @@
}
impl<'tcx> MirPass<'tcx> for AddRetag {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut BodyCache<'tcx>) {
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
if !tcx.sess.opts.debugging_opts.mir_emit_retag {
return;
}
diff --git a/src/librustc_mir/transform/check_consts/mod.rs b/src/librustc_mir/transform/check_consts/mod.rs
index 82ffafb..89672e8 100644
--- a/src/librustc_mir/transform/check_consts/mod.rs
+++ b/src/librustc_mir/transform/check_consts/mod.rs
@@ -20,7 +20,7 @@
/// Information about the item currently being const-checked, as well as a reference to the global
/// context.
pub struct Item<'mir, 'tcx> {
- pub body: mir::ReadOnlyBodyCache<'mir, 'tcx>,
+ pub body: mir::ReadOnlyBodyAndCache<'mir, 'tcx>,
pub tcx: TyCtxt<'tcx>,
pub def_id: DefId,
pub param_env: ty::ParamEnv<'tcx>,
@@ -31,7 +31,7 @@
pub fn new(
tcx: TyCtxt<'tcx>,
def_id: DefId,
- body: mir::ReadOnlyBodyCache<'mir, 'tcx>,
+ body: mir::ReadOnlyBodyAndCache<'mir, 'tcx>,
) -> Self {
let param_env = tcx.param_env(def_id);
let const_kind = ConstKind::for_item(tcx, def_id);
diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs
index aec3cf0..393ae94 100644
--- a/src/librustc_mir/transform/check_consts/ops.rs
+++ b/src/librustc_mir/transform/check_consts/ops.rs
@@ -1,7 +1,6 @@
//! Concrete error types for all operations which may be invalid in a certain const context.
use rustc::hir::def_id::DefId;
-use rustc::mir::BorrowKind;
use rustc::session::config::nightly_options;
use rustc::ty::TyCtxt;
use syntax::feature_gate::feature_err;
@@ -181,38 +180,53 @@
}
#[derive(Debug)]
-pub struct MutBorrow(pub BorrowKind);
-impl NonConstOp for MutBorrow {
+pub struct CellBorrow;
+impl NonConstOp for CellBorrow {
fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
- let kind = self.0;
- if let BorrowKind::Mut { .. } = kind {
- let mut err = struct_span_err!(item.tcx.sess, span, E0017,
- "references in {}s may only refer \
- to immutable values", item.const_kind());
- err.span_label(span, format!("{}s require immutable values",
- item.const_kind()));
- if item.tcx.sess.teach(&err.get_code().unwrap()) {
- err.note("References in statics and constants may only refer \
- to immutable values.\n\n\
- Statics are shared everywhere, and if they refer to \
- mutable data one might violate memory safety since \
- holding multiple mutable references to shared data \
- is not allowed.\n\n\
- If you really want global mutable state, try using \
- static mut or a global UnsafeCell.");
- }
- err.emit();
- } else {
- span_err!(item.tcx.sess, span, E0492,
- "cannot borrow a constant which may contain \
- interior mutability, create a static instead");
+ span_err!(item.tcx.sess, span, E0492,
+ "cannot borrow a constant which may contain \
+ interior mutability, create a static instead");
+ }
+}
+
+#[derive(Debug)]
+pub struct MutBorrow;
+impl NonConstOp for MutBorrow {
+ fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
+ Some(tcx.features().const_mut_refs)
+ }
+
+ fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
+ let mut err = feature_err(
+ &item.tcx.sess.parse_sess,
+ sym::const_mut_refs,
+ span,
+ &format!("references in {}s may only refer \
+ to immutable values", item.const_kind())
+ );
+ err.span_label(span, format!("{}s require immutable values",
+ item.const_kind()));
+ if item.tcx.sess.teach(&err.get_code().unwrap()) {
+ err.note("References in statics and constants may only refer \
+ to immutable values.\n\n\
+ Statics are shared everywhere, and if they refer to \
+ mutable data one might violate memory safety since \
+ holding multiple mutable references to shared data \
+ is not allowed.\n\n\
+ If you really want global mutable state, try using \
+ static mut or a global UnsafeCell.");
}
+ err.emit();
}
}
#[derive(Debug)]
pub struct MutDeref;
-impl NonConstOp for MutDeref {}
+impl NonConstOp for MutDeref {
+ fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
+ Some(tcx.features().const_mut_refs)
+ }
+}
#[derive(Debug)]
pub struct Panic;
diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs
index f44bac1..6261315 100644
--- a/src/librustc_mir/transform/check_consts/validation.rs
+++ b/src/librustc_mir/transform/check_consts/validation.rs
@@ -40,7 +40,7 @@
let results =
dataflow::Engine::new(item.tcx, &item.body, item.def_id, dead_unwinds, analysis)
.iterate_to_fixpoint();
- let cursor = dataflow::ResultsCursor::new(item.body.body(), results);
+ let cursor = dataflow::ResultsCursor::new(*item.body, results);
let mut in_any_value_of_ty = BitSet::new_empty(item.body.local_decls.len());
for (local, decl) in item.body.local_decls.iter_enumerated() {
@@ -175,13 +175,13 @@
item.def_id,
&item.tcx.get_attrs(item.def_id),
&dead_unwinds,
- old_dataflow::IndirectlyMutableLocals::new(item.tcx, item.body.body(), item.param_env),
+ old_dataflow::IndirectlyMutableLocals::new(item.tcx, *item.body, item.param_env),
|_, local| old_dataflow::DebugFormatted::new(&local),
);
let indirectly_mutable = old_dataflow::DataflowResultsCursor::new(
indirectly_mutable,
- item.body.body(),
+ *item.body,
);
let qualifs = Qualifs {
@@ -359,7 +359,11 @@
};
if !is_allowed {
- self.check_op(ops::MutBorrow(kind));
+ if let BorrowKind::Mut{ .. } = kind {
+ self.check_op(ops::MutBorrow);
+ } else {
+ self.check_op(ops::CellBorrow);
+ }
}
}
@@ -384,7 +388,11 @@
);
if borrowed_place_has_mut_interior {
- self.check_op(ops::MutBorrow(kind));
+ if let BorrowKind::Mut{ .. } = kind {
+ self.check_op(ops::MutBorrow);
+ } else {
+ self.check_op(ops::CellBorrow);
+ }
}
}
@@ -451,7 +459,6 @@
}
}
}
-
fn visit_projection_elem(
&mut self,
place_base: &PlaceBase<'tcx>,
diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index 2c45dcf..284285c 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -658,7 +658,7 @@
let mut unsafe_blocks: Vec<_> = unsafe_blocks.into_iter().collect();
unsafe_blocks.sort_by_cached_key(|(hir_id, _)| tcx.hir().hir_to_node_id(*hir_id));
let used_unsafe: FxHashSet<_> = unsafe_blocks.iter()
- .flat_map(|&&(id, used)| if used { Some(id) } else { None })
+ .flat_map(|&&(id, used)| used.then_some(id))
.collect();
for &(block_id, is_used) in unsafe_blocks {
if !is_used {
diff --git a/src/librustc_mir/transform/cleanup_post_borrowck.rs b/src/librustc_mir/transform/cleanup_post_borrowck.rs
index d9dd7c9..34519bc 100644
--- a/src/librustc_mir/transform/cleanup_post_borrowck.rs
+++ b/src/librustc_mir/transform/cleanup_post_borrowck.rs
@@ -16,7 +16,7 @@
//! [`FakeRead`]: rustc::mir::StatementKind::FakeRead
//! [`Nop`]: rustc::mir::StatementKind::Nop
-use rustc::mir::{BodyCache, BorrowKind, Rvalue, Location};
+use rustc::mir::{BodyAndCache, BorrowKind, Rvalue, Location};
use rustc::mir::{Statement, StatementKind};
use rustc::mir::visit::MutVisitor;
use rustc::ty::TyCtxt;
@@ -30,7 +30,7 @@
impl<'tcx> MirPass<'tcx> for CleanupNonCodegenStatements {
fn run_pass(
- &self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut BodyCache<'tcx>
+ &self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>
) {
let mut delete = DeleteNonCodegenStatements { tcx };
delete.visit_body(body);
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index 95de635..8843125 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -7,9 +7,9 @@
use rustc::hir::def::DefKind;
use rustc::hir::def_id::DefId;
use rustc::mir::{
- AggregateKind, Constant, Location, Place, PlaceBase, Body, BodyCache, Operand, Local, UnOp,
- Rvalue, StatementKind, Statement, LocalKind, TerminatorKind, Terminator, ClearCrossCrate,
- SourceInfo, BinOp, SourceScope, SourceScopeData, LocalDecl, BasicBlock, ReadOnlyBodyCache,
+ AggregateKind, Constant, Location, Place, PlaceBase, Body, BodyAndCache, Operand, Local, UnOp,
+ Rvalue, StatementKind, Statement, LocalKind, TerminatorKind, Terminator, ClearCrossCrate,
+ SourceInfo, BinOp, SourceScope, SourceScopeData, LocalDecl, BasicBlock, ReadOnlyBodyAndCache,
read_only, RETURN_PLACE
};
use rustc::mir::visit::{
@@ -43,7 +43,7 @@
impl<'tcx> MirPass<'tcx> for ConstProp {
fn run_pass(
- &self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut BodyCache<'tcx>
+ &self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>
) {
// will be evaluated by miri and produce its errors there
if source.promoted.is_some() {
@@ -296,7 +296,7 @@
impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
fn new(
- body: ReadOnlyBodyCache<'_, 'tcx>,
+ body: ReadOnlyBodyAndCache<'_, 'tcx>,
dummy_body: &'mir Body<'tcx>,
tcx: TyCtxt<'tcx>,
source: MirSource<'tcx>,
@@ -690,7 +690,7 @@
impl CanConstProp {
/// returns true if `local` can be propagated
- fn check(body: ReadOnlyBodyCache<'_, '_>) -> IndexVec<Local, bool> {
+ fn check(body: ReadOnlyBodyAndCache<'_, '_>) -> IndexVec<Local, bool> {
let mut cpv = CanConstProp {
can_const_prop: IndexVec::from_elem(true, &body.local_decls),
found_assignment: IndexVec::from_elem(false, &body.local_decls),
diff --git a/src/librustc_mir/transform/copy_prop.rs b/src/librustc_mir/transform/copy_prop.rs
index 5e4caf2..272f6e9 100644
--- a/src/librustc_mir/transform/copy_prop.rs
+++ b/src/librustc_mir/transform/copy_prop.rs
@@ -20,7 +20,7 @@
//! future.
use rustc::mir::{
- Constant, Local, LocalKind, Location, Place, Body, BodyCache, Operand, Rvalue,
+ Constant, Local, LocalKind, Location, Place, Body, BodyAndCache, Operand, Rvalue,
StatementKind, read_only
};
use rustc::mir::visit::MutVisitor;
@@ -32,7 +32,7 @@
impl<'tcx> MirPass<'tcx> for CopyPropagation {
fn run_pass(
- &self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut BodyCache<'tcx>
+ &self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>
) {
// We only run when the MIR optimization level is > 1.
// This avoids a slow pass, and messing up debug info.
@@ -250,7 +250,7 @@
}
fn perform(self,
- body: &mut BodyCache<'tcx>,
+ body: &mut BodyAndCache<'tcx>,
def_use_analysis: &DefUseAnalysis,
dest_local: Local,
location: Location,
diff --git a/src/librustc_mir/transform/deaggregator.rs b/src/librustc_mir/transform/deaggregator.rs
index 933936e..cd77c9c 100644
--- a/src/librustc_mir/transform/deaggregator.rs
+++ b/src/librustc_mir/transform/deaggregator.rs
@@ -7,7 +7,7 @@
impl<'tcx> MirPass<'tcx> for Deaggregator {
fn run_pass(
- &self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut BodyCache<'tcx>
+ &self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>
) {
let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
let local_decls = &*local_decls;
diff --git a/src/librustc_mir/transform/dump_mir.rs b/src/librustc_mir/transform/dump_mir.rs
index 13b3bb6..221ced3 100644
--- a/src/librustc_mir/transform/dump_mir.rs
+++ b/src/librustc_mir/transform/dump_mir.rs
@@ -5,7 +5,7 @@
use std::fs::File;
use std::io;
-use rustc::mir::{Body, BodyCache};
+use rustc::mir::{Body, BodyAndCache};
use rustc::session::config::{OutputFilenames, OutputType};
use rustc::ty::TyCtxt;
use crate::transform::{MirPass, MirSource};
@@ -19,7 +19,7 @@
}
fn run_pass(
- &self, _tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, _body: &mut BodyCache<'tcx>
+ &self, _tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, _body: &mut BodyAndCache<'tcx>
) {}
}
diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs
index 42daba9..9970752 100644
--- a/src/librustc_mir/transform/elaborate_drops.rs
+++ b/src/librustc_mir/transform/elaborate_drops.rs
@@ -21,7 +21,7 @@
pub struct ElaborateDrops;
impl<'tcx> MirPass<'tcx> for ElaborateDrops {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyCache<'tcx>) {
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
debug!("elaborate_drops({:?} @ {:?})", src, body.span);
let def_id = src.def_id();
diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs
index 882e674..1eef3f2 100644
--- a/src/librustc_mir/transform/erase_regions.rs
+++ b/src/librustc_mir/transform/erase_regions.rs
@@ -62,7 +62,7 @@
pub struct EraseRegions;
impl<'tcx> MirPass<'tcx> for EraseRegions {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut BodyCache<'tcx>) {
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
EraseRegionsVisitor::new(tcx).visit_body(body);
}
}
diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs
index e55737e..3d15d04 100644
--- a/src/librustc_mir/transform/generator.rs
+++ b/src/librustc_mir/transform/generator.rs
@@ -378,7 +378,7 @@
fn make_generator_state_argument_indirect<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: DefId,
- body: &mut BodyCache<'tcx>,
+ body: &mut BodyAndCache<'tcx>,
) {
let gen_ty = body.local_decls.raw[1].ty;
@@ -401,7 +401,7 @@
DerefArgVisitor { tcx }.visit_body(body);
}
-fn make_generator_state_argument_pinned<'tcx>(tcx: TyCtxt<'tcx>, body: &mut BodyCache<'tcx>) {
+fn make_generator_state_argument_pinned<'tcx>(tcx: TyCtxt<'tcx>, body: &mut BodyAndCache<'tcx>) {
let ref_gen_ty = body.local_decls.raw[1].ty;
let pin_did = tcx.lang_items().pin_type().unwrap();
@@ -418,7 +418,7 @@
fn replace_result_variable<'tcx>(
ret_ty: Ty<'tcx>,
- body: &mut BodyCache<'tcx>,
+ body: &mut BodyAndCache<'tcx>,
tcx: TyCtxt<'tcx>,
) -> Local {
let source_info = source_info(body);
@@ -481,7 +481,7 @@
fn locals_live_across_suspend_points(
tcx: TyCtxt<'tcx>,
- body: ReadOnlyBodyCache<'_, 'tcx>,
+ body: ReadOnlyBodyAndCache<'_, 'tcx>,
source: MirSource<'tcx>,
movable: bool,
) -> LivenessInfo {
@@ -751,7 +751,7 @@
upvars: &Vec<Ty<'tcx>>,
interior: Ty<'tcx>,
movable: bool,
- body: &mut BodyCache<'tcx>,
+ body: &mut BodyAndCache<'tcx>,
) -> (
FxHashMap<Local, (Ty<'tcx>, VariantIdx, usize)>,
GeneratorLayout<'tcx>,
@@ -830,7 +830,7 @@
}
fn insert_switch<'tcx>(
- body: &mut BodyCache<'tcx>,
+ body: &mut BodyAndCache<'tcx>,
cases: Vec<(usize, BasicBlock)>,
transform: &TransformVisitor<'tcx>,
default: TerminatorKind<'tcx>,
@@ -862,7 +862,7 @@
}
fn elaborate_generator_drops<'tcx>(
- tcx: TyCtxt<'tcx>, def_id: DefId, body: &mut BodyCache<'tcx>
+ tcx: TyCtxt<'tcx>, def_id: DefId, body: &mut BodyAndCache<'tcx>
) {
use crate::util::elaborate_drops::{elaborate_drop, Unwind};
use crate::util::patch::MirPatch;
@@ -928,9 +928,9 @@
def_id: DefId,
source: MirSource<'tcx>,
gen_ty: Ty<'tcx>,
- body: &mut BodyCache<'tcx>,
+ body: &mut BodyAndCache<'tcx>,
drop_clean: BasicBlock,
-) -> BodyCache<'tcx> {
+) -> BodyAndCache<'tcx> {
let mut body = body.clone();
let source_info = source_info(&body);
@@ -997,7 +997,7 @@
}
fn insert_term_block<'tcx>(
- body: &mut BodyCache<'tcx>, kind: TerminatorKind<'tcx>
+ body: &mut BodyAndCache<'tcx>, kind: TerminatorKind<'tcx>
) -> BasicBlock {
let term_block = BasicBlock::new(body.basic_blocks().len());
let source_info = source_info(body);
@@ -1014,7 +1014,7 @@
fn insert_panic_block<'tcx>(
tcx: TyCtxt<'tcx>,
- body: &mut BodyCache<'tcx>,
+ body: &mut BodyAndCache<'tcx>,
message: AssertMessage<'tcx>,
) -> BasicBlock {
let assert_block = BasicBlock::new(body.basic_blocks().len());
@@ -1048,7 +1048,7 @@
transform: TransformVisitor<'tcx>,
def_id: DefId,
source: MirSource<'tcx>,
- body: &mut BodyCache<'tcx>,
+ body: &mut BodyAndCache<'tcx>,
) {
// Poison the generator when it unwinds
for block in body.basic_blocks_mut() {
@@ -1101,7 +1101,7 @@
}
}
-fn insert_clean_drop(body: &mut BodyCache<'_>) -> BasicBlock {
+fn insert_clean_drop(body: &mut BodyAndCache<'_>) -> BasicBlock {
let return_block = insert_term_block(body, TerminatorKind::Return);
// Create a block to destroy an unresumed generators. This can only destroy upvars.
@@ -1125,7 +1125,7 @@
}
fn create_cases<'tcx, F>(
- body: &mut BodyCache<'tcx>,
+ body: &mut BodyAndCache<'tcx>,
transform: &TransformVisitor<'tcx>,
target: F,
) -> Vec<(usize, BasicBlock)>
@@ -1170,7 +1170,7 @@
impl<'tcx> MirPass<'tcx> for StateTransform {
fn run_pass(
- &self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut BodyCache<'tcx>
+ &self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>
) {
let yield_ty = if let Some(yield_ty) = body.yield_ty {
yield_ty
diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs
index 79cb7fb..9763913 100644
--- a/src/librustc_mir/transform/inline.rs
+++ b/src/librustc_mir/transform/inline.rs
@@ -39,7 +39,7 @@
impl<'tcx> MirPass<'tcx> for Inline {
fn run_pass(
- &self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut BodyCache<'tcx>
+ &self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>
) {
if tcx.sess.opts.debugging_opts.mir_opt_level >= 2 {
Inliner { tcx, source }.run_pass(body);
@@ -53,7 +53,7 @@
}
impl Inliner<'tcx> {
- fn run_pass(&self, caller_body: &mut BodyCache<'tcx>) {
+ fn run_pass(&self, caller_body: &mut BodyAndCache<'tcx>) {
// Keep a queue of callsites to try inlining on. We take
// advantage of the fact that queries detect cycles here to
// allow us to try and fetch the fully optimized MIR of a
@@ -230,6 +230,11 @@
let codegen_fn_attrs = tcx.codegen_fn_attrs(callsite.callee);
+ if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::TRACK_CALLER) {
+ debug!("`#[track_caller]` present - not inlining");
+ return false;
+ }
+
let hinted = match codegen_fn_attrs.inline {
// Just treat inline(always) as a hint for now,
// there are cases that prevent inlining that we
@@ -380,8 +385,8 @@
fn inline_call(&self,
callsite: CallSite<'tcx>,
- caller_body: &mut BodyCache<'tcx>,
- mut callee_body: BodyCache<'tcx>) -> bool {
+ caller_body: &mut BodyAndCache<'tcx>,
+ mut callee_body: BodyAndCache<'tcx>) -> bool {
let terminator = caller_body[callsite.bb].terminator.take().unwrap();
match terminator.kind {
// FIXME: Handle inlining of diverging calls
@@ -517,7 +522,7 @@
&self,
args: Vec<Operand<'tcx>>,
callsite: &CallSite<'tcx>,
- caller_body: &mut BodyCache<'tcx>,
+ caller_body: &mut BodyAndCache<'tcx>,
) -> Vec<Local> {
let tcx = self.tcx;
@@ -590,7 +595,7 @@
&self,
arg: Operand<'tcx>,
callsite: &CallSite<'tcx>,
- caller_body: &mut BodyCache<'tcx>,
+ caller_body: &mut BodyAndCache<'tcx>,
) -> Local {
// FIXME: Analysis of the usage of the arguments to avoid
// unnecessary temporaries.
diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs
index bd237b5..eca1b59 100644
--- a/src/librustc_mir/transform/instcombine.rs
+++ b/src/librustc_mir/transform/instcombine.rs
@@ -1,7 +1,7 @@
//! Performs various peephole optimizations.
use rustc::mir::{
- Constant, Location, Place, PlaceBase, PlaceRef, Body, BodyCache, Operand, ProjectionElem,
+ Constant, Location, Place, PlaceBase, PlaceRef, Body, BodyAndCache, Operand, ProjectionElem,
Rvalue, Local, read_only
};
use rustc::mir::visit::{MutVisitor, Visitor};
@@ -14,7 +14,7 @@
pub struct InstCombine;
impl<'tcx> MirPass<'tcx> for InstCombine {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut BodyCache<'tcx>) {
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
// We only run when optimizing MIR (at any level).
if tcx.sess.opts.debugging_opts.mir_opt_level == 0 {
return
diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs
index df4cb76..bedf2a9 100644
--- a/src/librustc_mir/transform/mod.rs
+++ b/src/librustc_mir/transform/mod.rs
@@ -1,7 +1,7 @@
use crate::{build, shim};
use rustc_index::vec::IndexVec;
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
-use rustc::mir::{BodyCache, MirPhase, Promoted, ConstQualifs};
+use rustc::mir::{BodyAndCache, MirPhase, Promoted, ConstQualifs};
use rustc::ty::{TyCtxt, InstanceDef, TypeFoldable};
use rustc::ty::query::Providers;
use rustc::ty::steal::Steal;
@@ -97,7 +97,7 @@
tcx.arena.alloc(set)
}
-fn mir_built(tcx: TyCtxt<'_>, def_id: DefId) -> &Steal<BodyCache<'_>> {
+fn mir_built(tcx: TyCtxt<'_>, def_id: DefId) -> &Steal<BodyAndCache<'_>> {
let mir = build::mir_build(tcx, def_id);
tcx.alloc_steal_mir(mir)
}
@@ -144,12 +144,12 @@
default_name::<Self>()
}
- fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut BodyCache<'tcx>);
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>);
}
pub fn run_passes(
tcx: TyCtxt<'tcx>,
- body: &mut BodyCache<'tcx>,
+ body: &mut BodyAndCache<'tcx>,
instance: InstanceDef<'tcx>,
promoted: Option<Promoted>,
mir_phase: MirPhase,
@@ -220,7 +220,7 @@
validator.qualifs_in_return_place().into()
}
-fn mir_const(tcx: TyCtxt<'_>, def_id: DefId) -> &Steal<BodyCache<'_>> {
+fn mir_const(tcx: TyCtxt<'_>, def_id: DefId) -> &Steal<BodyAndCache<'_>> {
// Unsafety check uses the raw mir, so make sure it is run
let _ = tcx.unsafety_check_result(def_id);
@@ -238,7 +238,7 @@
fn mir_validated(
tcx: TyCtxt<'tcx>,
def_id: DefId,
-) -> (&'tcx Steal<BodyCache<'tcx>>, &'tcx Steal<IndexVec<Promoted, BodyCache<'tcx>>>) {
+) -> (&'tcx Steal<BodyAndCache<'tcx>>, &'tcx Steal<IndexVec<Promoted, BodyAndCache<'tcx>>>) {
// Ensure that we compute the `mir_const_qualif` for constants at
// this point, before we steal the mir-const result.
let _ = tcx.mir_const_qualif(def_id);
@@ -257,7 +257,7 @@
fn run_optimization_passes<'tcx>(
tcx: TyCtxt<'tcx>,
- body: &mut BodyCache<'tcx>,
+ body: &mut BodyAndCache<'tcx>,
def_id: DefId,
promoted: Option<Promoted>,
) {
@@ -319,7 +319,7 @@
]);
}
-fn optimized_mir(tcx: TyCtxt<'_>, def_id: DefId) -> &BodyCache<'_> {
+fn optimized_mir(tcx: TyCtxt<'_>, def_id: DefId) -> &BodyAndCache<'_> {
if tcx.is_constructor(def_id) {
// There's no reason to run all of the MIR passes on constructors when
// we can just output the MIR we want directly. This also saves const
@@ -339,7 +339,7 @@
tcx.arena.alloc(body)
}
-fn promoted_mir(tcx: TyCtxt<'_>, def_id: DefId) -> &IndexVec<Promoted, BodyCache<'_>> {
+fn promoted_mir(tcx: TyCtxt<'_>, def_id: DefId) -> &IndexVec<Promoted, BodyAndCache<'_>> {
if tcx.is_constructor(def_id) {
return tcx.intern_promoted(IndexVec::new());
}
diff --git a/src/librustc_mir/transform/no_landing_pads.rs b/src/librustc_mir/transform/no_landing_pads.rs
index 5e1d29d..d4fe72f 100644
--- a/src/librustc_mir/transform/no_landing_pads.rs
+++ b/src/librustc_mir/transform/no_landing_pads.rs
@@ -17,12 +17,12 @@
}
impl<'tcx> MirPass<'tcx> for NoLandingPads<'tcx> {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut BodyCache<'tcx>) {
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
no_landing_pads(tcx, body)
}
}
-pub fn no_landing_pads<'tcx>(tcx: TyCtxt<'tcx>, body: &mut BodyCache<'tcx>) {
+pub fn no_landing_pads<'tcx>(tcx: TyCtxt<'tcx>, body: &mut BodyAndCache<'tcx>) {
if tcx.sess.no_landing_pads() {
NoLandingPads::new(tcx).visit_body(body);
}
diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs
index c758ccf..4c72319 100644
--- a/src/librustc_mir/transform/promote_consts.rs
+++ b/src/librustc_mir/transform/promote_consts.rs
@@ -41,11 +41,11 @@
/// newly created `StaticKind::Promoted`.
#[derive(Default)]
pub struct PromoteTemps<'tcx> {
- pub promoted_fragments: Cell<IndexVec<Promoted, BodyCache<'tcx>>>,
+ pub promoted_fragments: Cell<IndexVec<Promoted, BodyAndCache<'tcx>>>,
}
impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyCache<'tcx>) {
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
// There's not really any point in promoting errorful MIR.
//
// This does not include MIR that failed const-checking, which we still try to promote.
@@ -742,7 +742,7 @@
// FIXME(eddyb) remove the differences for promotability in `static`, `const`, `const fn`.
pub fn validate_candidates(
tcx: TyCtxt<'tcx>,
- body: ReadOnlyBodyCache<'_, 'tcx>,
+ body: ReadOnlyBodyAndCache<'_, 'tcx>,
def_id: DefId,
temps: &IndexVec<Local, TempState>,
candidates: &[Candidate],
@@ -775,8 +775,8 @@
struct Promoter<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
- source: &'a mut BodyCache<'tcx>,
- promoted: BodyCache<'tcx>,
+ source: &'a mut BodyAndCache<'tcx>,
+ promoted: BodyAndCache<'tcx>,
temps: &'a mut IndexVec<Local, TempState>,
/// If true, all nested temps are also kept in the
@@ -924,7 +924,7 @@
def_id: DefId,
candidate: Candidate,
next_promoted_id: usize,
- ) -> Option<BodyCache<'tcx>> {
+ ) -> Option<BodyAndCache<'tcx>> {
let mut operand = {
let promoted = &mut self.promoted;
let promoted_id = Promoted::new(next_promoted_id);
@@ -1045,11 +1045,11 @@
pub fn promote_candidates<'tcx>(
def_id: DefId,
- body: &mut BodyCache<'tcx>,
+ body: &mut BodyAndCache<'tcx>,
tcx: TyCtxt<'tcx>,
mut temps: IndexVec<Local, TempState>,
candidates: Vec<Candidate>,
-) -> IndexVec<Promoted, BodyCache<'tcx>> {
+) -> IndexVec<Promoted, BodyAndCache<'tcx>> {
// Visit candidates in reverse, in case they're nested.
debug!("promote_candidates({:?})", candidates);
@@ -1081,7 +1081,7 @@
).collect();
let promoter = Promoter {
- promoted: BodyCache::new(Body::new(
+ promoted: BodyAndCache::new(Body::new(
IndexVec::new(),
// FIXME: maybe try to filter this to avoid blowing up
// memory usage?
@@ -1150,7 +1150,7 @@
crate fn should_suggest_const_in_array_repeat_expressions_attribute<'tcx>(
tcx: TyCtxt<'tcx>,
mir_def_id: DefId,
- body: ReadOnlyBodyCache<'_, 'tcx>,
+ body: ReadOnlyBodyAndCache<'_, 'tcx>,
operand: &Operand<'tcx>,
) -> bool {
let mut rpo = traversal::reverse_postorder(&body);
diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs
index 3030d2e..cf2e130 100644
--- a/src/librustc_mir/transform/qualify_min_const_fn.rs
+++ b/src/librustc_mir/transform/qualify_min_const_fn.rs
@@ -79,10 +79,14 @@
fn check_ty(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span, fn_def_id: DefId) -> McfResult {
for ty in ty.walk() {
match ty.kind {
- ty::Ref(_, _, hir::Mutability::Mutable) => return Err((
- span,
- "mutable references in const fn are unstable".into(),
- )),
+ ty::Ref(_, _, hir::Mutability::Mutable) => {
+ if !tcx.features().const_mut_refs {
+ return Err((
+ span,
+ "mutable references in const fn are unstable".into(),
+ ))
+ }
+ }
ty::Opaque(..) => return Err((span, "`impl Trait` in const fn is unstable".into())),
ty::FnPtr(..) => {
if !tcx.const_fn_is_allowed_fn_ptr(fn_def_id) {
diff --git a/src/librustc_mir/transform/remove_noop_landing_pads.rs b/src/librustc_mir/transform/remove_noop_landing_pads.rs
index c636aba..5799d0c 100644
--- a/src/librustc_mir/transform/remove_noop_landing_pads.rs
+++ b/src/librustc_mir/transform/remove_noop_landing_pads.rs
@@ -9,7 +9,7 @@
/// code for these.
pub struct RemoveNoopLandingPads;
-pub fn remove_noop_landing_pads<'tcx>(tcx: TyCtxt<'tcx>, body: &mut BodyCache<'tcx>) {
+pub fn remove_noop_landing_pads<'tcx>(tcx: TyCtxt<'tcx>, body: &mut BodyAndCache<'tcx>) {
if tcx.sess.no_landing_pads() {
return
}
@@ -19,7 +19,7 @@
}
impl<'tcx> MirPass<'tcx> for RemoveNoopLandingPads {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut BodyCache<'tcx>) {
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
remove_noop_landing_pads(tcx, body);
}
}
@@ -84,7 +84,7 @@
}
}
- fn remove_nop_landing_pads(&self, body: &mut BodyCache<'_>) {
+ fn remove_nop_landing_pads(&self, body: &mut BodyAndCache<'_>) {
// make sure there's a single resume block
let resume_block = {
let patch = MirPatch::new(body);
diff --git a/src/librustc_mir/transform/rustc_peek.rs b/src/librustc_mir/transform/rustc_peek.rs
index 794ced1..2a81e97 100644
--- a/src/librustc_mir/transform/rustc_peek.rs
+++ b/src/librustc_mir/transform/rustc_peek.rs
@@ -5,7 +5,7 @@
use rustc::ty::{self, TyCtxt, Ty};
use rustc::hir::def_id::DefId;
-use rustc::mir::{self, Body, BodyCache, Location, Local};
+use rustc::mir::{self, Body, BodyAndCache, Location, Local};
use rustc_index::bit_set::BitSet;
use crate::transform::{MirPass, MirSource};
@@ -26,7 +26,7 @@
pub struct SanityCheck;
impl<'tcx> MirPass<'tcx> for SanityCheck {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyCache<'tcx>) {
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
let def_id = src.def_id();
if !tcx.has_attr(def_id, sym::rustc_mir) {
debug!("skipping rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id));
diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs
index 900752d..eef39f8 100644
--- a/src/librustc_mir/transform/simplify.rs
+++ b/src/librustc_mir/transform/simplify.rs
@@ -43,7 +43,7 @@
}
}
-pub fn simplify_cfg(body: &mut BodyCache<'_>) {
+pub fn simplify_cfg(body: &mut BodyAndCache<'_>) {
CfgSimplifier::new(body).simplify();
remove_dead_blocks(body);
@@ -57,7 +57,7 @@
}
fn run_pass(
- &self, _tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut BodyCache<'tcx>
+ &self, _tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>
) {
debug!("SimplifyCfg({:?}) - simplifying {:?}", self.label, body);
simplify_cfg(body);
@@ -70,7 +70,7 @@
}
impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
- pub fn new(body: &'a mut BodyCache<'tcx>) -> Self {
+ pub fn new(body: &'a mut BodyAndCache<'tcx>) -> Self {
let mut pred_count = IndexVec::from_elem(0u32, body.basic_blocks());
// we can't use mir.predecessors() here because that counts
@@ -262,7 +262,7 @@
}
}
-pub fn remove_dead_blocks(body: &mut BodyCache<'_>) {
+pub fn remove_dead_blocks(body: &mut BodyAndCache<'_>) {
let mut seen = BitSet::new_empty(body.basic_blocks().len());
for (bb, _) in traversal::preorder(body) {
seen.insert(bb.index());
@@ -296,7 +296,7 @@
impl<'tcx> MirPass<'tcx> for SimplifyLocals {
fn run_pass(
- &self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut BodyCache<'tcx>
+ &self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>
) {
trace!("running SimplifyLocals on {:?}", source);
let locals = {
diff --git a/src/librustc_mir/transform/simplify_branches.rs b/src/librustc_mir/transform/simplify_branches.rs
index c8d0f37..aa3c5b0 100644
--- a/src/librustc_mir/transform/simplify_branches.rs
+++ b/src/librustc_mir/transform/simplify_branches.rs
@@ -19,7 +19,7 @@
Cow::Borrowed(&self.label)
}
- fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyCache<'tcx>) {
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
let param_env = tcx.param_env(src.def_id());
for block in body.basic_blocks_mut() {
let terminator = block.terminator_mut();
diff --git a/src/librustc_mir/transform/simplify_try.rs b/src/librustc_mir/transform/simplify_try.rs
index 2235de9..752e852 100644
--- a/src/librustc_mir/transform/simplify_try.rs
+++ b/src/librustc_mir/transform/simplify_try.rs
@@ -33,7 +33,7 @@
pub struct SimplifyArmIdentity;
impl<'tcx> MirPass<'tcx> for SimplifyArmIdentity {
- fn run_pass(&self, _: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut BodyCache<'tcx>) {
+ fn run_pass(&self, _: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
for bb in basic_blocks {
// Need 3 statements:
@@ -151,7 +151,7 @@
pub struct SimplifyBranchSame;
impl<'tcx> MirPass<'tcx> for SimplifyBranchSame {
- fn run_pass(&self, _: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut BodyCache<'tcx>) {
+ fn run_pass(&self, _: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
let mut did_remove_blocks = false;
let bbs = body.basic_blocks_mut();
for bb_idx in bbs.indices() {
diff --git a/src/librustc_mir/transform/uniform_array_move_out.rs b/src/librustc_mir/transform/uniform_array_move_out.rs
index 3fc76ef..71dd405 100644
--- a/src/librustc_mir/transform/uniform_array_move_out.rs
+++ b/src/librustc_mir/transform/uniform_array_move_out.rs
@@ -37,7 +37,7 @@
pub struct UniformArrayMoveOut;
impl<'tcx> MirPass<'tcx> for UniformArrayMoveOut {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyCache<'tcx>) {
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
let mut patch = MirPatch::new(body);
let param_env = tcx.param_env(src.def_id());
{
@@ -186,7 +186,7 @@
}
impl<'tcx> MirPass<'tcx> for RestoreSubsliceArrayMoveOut<'tcx> {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyCache<'tcx>) {
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
let mut patch = MirPatch::new(body);
let param_env = tcx.param_env(src.def_id());
{
diff --git a/src/librustc_mir/transform/uninhabited_enum_branching.rs b/src/librustc_mir/transform/uninhabited_enum_branching.rs
index de070d7..0bf0ff2 100644
--- a/src/librustc_mir/transform/uninhabited_enum_branching.rs
+++ b/src/librustc_mir/transform/uninhabited_enum_branching.rs
@@ -2,7 +2,7 @@
use crate::transform::{MirPass, MirSource};
use rustc::mir::{
- BasicBlock, BasicBlockData, Body, BodyCache, Local, Operand, Rvalue, StatementKind,
+ BasicBlock, BasicBlockData, Body, BodyAndCache, Local, Operand, Rvalue, StatementKind,
TerminatorKind,
};
use rustc::ty::layout::{Abi, TyLayout, Variants};
@@ -29,7 +29,7 @@
// Only bother checking blocks which terminate by switching on a local.
if let Some(local) = get_discriminant_local(&terminator.kind) {
let stmt_before_term = (block_data.statements.len() > 0)
- .then_with(|| &block_data.statements[block_data.statements.len() - 1].kind);
+ .then(|| &block_data.statements[block_data.statements.len() - 1].kind);
if let Some(StatementKind::Assign(box (l, Rvalue::Discriminant(place)))) = stmt_before_term
{
@@ -59,14 +59,14 @@
.iter_enumerated()
.filter_map(|(idx, layout)| {
(layout.abi != Abi::Uninhabited)
- .then_with(|| ty.discriminant_for_variant(tcx, idx).unwrap().val)
+ .then(|| ty.discriminant_for_variant(tcx, idx).unwrap().val)
})
.collect(),
}
}
impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut BodyCache<'tcx>) {
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
if source.promoted.is_some() {
return;
}
diff --git a/src/librustc_mir/util/collect_writes.rs b/src/librustc_mir/util/collect_writes.rs
index f94bea2..4006787 100644
--- a/src/librustc_mir/util/collect_writes.rs
+++ b/src/librustc_mir/util/collect_writes.rs
@@ -1,5 +1,5 @@
use rustc::mir::{Local, Location};
-use rustc::mir::ReadOnlyBodyCache;
+use rustc::mir::ReadOnlyBodyAndCache;
use rustc::mir::visit::PlaceContext;
use rustc::mir::visit::Visitor;
@@ -9,7 +9,7 @@
fn find_assignments(&self, local: Local) -> Vec<Location>;
}
-impl<'a, 'tcx> FindAssignments for ReadOnlyBodyCache<'a, 'tcx>{
+impl<'a, 'tcx> FindAssignments for ReadOnlyBodyAndCache<'a, 'tcx>{
fn find_assignments(&self, local: Local) -> Vec<Location>{
let mut visitor = FindLocalAssignmentVisitor{ needle: local, locations: vec![]};
visitor.visit_body(*self);
diff --git a/src/librustc_mir/util/def_use.rs b/src/librustc_mir/util/def_use.rs
index 1907e9b..cf98755 100644
--- a/src/librustc_mir/util/def_use.rs
+++ b/src/librustc_mir/util/def_use.rs
@@ -1,6 +1,8 @@
//! Def-use analysis.
-use rustc::mir::{Body, BodyCache, Local, Location, PlaceElem, ReadOnlyBodyCache, VarDebugInfo};
+use rustc::mir::{
+ Body, BodyAndCache, Local, Location, PlaceElem, ReadOnlyBodyAndCache, VarDebugInfo,
+};
use rustc::mir::visit::{PlaceContext, MutVisitor, Visitor};
use rustc::ty::TyCtxt;
use rustc_index::vec::IndexVec;
@@ -30,7 +32,7 @@
}
}
- pub fn analyze(&mut self, body: ReadOnlyBodyCache<'_, '_>) {
+ pub fn analyze(&mut self, body: ReadOnlyBodyAndCache<'_, '_>) {
self.clear();
let mut finder = DefUseFinder {
@@ -55,7 +57,7 @@
fn mutate_defs_and_uses(
&self,
local: Local,
- body: &mut BodyCache<'tcx>,
+ body: &mut BodyAndCache<'tcx>,
new_local: Local,
tcx: TyCtxt<'tcx>,
) {
@@ -73,7 +75,7 @@
// FIXME(pcwalton): this should update the def-use chains.
pub fn replace_all_defs_and_uses_with(&self,
local: Local,
- body: &mut BodyCache<'tcx>,
+ body: &mut BodyAndCache<'tcx>,
new_local: Local,
tcx: TyCtxt<'tcx>) {
self.mutate_defs_and_uses(local, body, new_local, tcx)
diff --git a/src/librustc_mir/util/graphviz.rs b/src/librustc_mir/util/graphviz.rs
index 3a7ec9f..a44d401 100644
--- a/src/librustc_mir/util/graphviz.rs
+++ b/src/librustc_mir/util/graphviz.rs
@@ -202,7 +202,7 @@
}
for var_debug_info in &body.var_debug_info {
- write!(w, r#"debug {} => {};<br align="left"/>"#,
+ write!(w, r#"debug {} => {};<br align="left"/>"#,
var_debug_info.name, escape(&var_debug_info.place))?;
}
diff --git a/src/librustc_mir/util/liveness.rs b/src/librustc_mir/util/liveness.rs
index 3349753..68c2e16 100644
--- a/src/librustc_mir/util/liveness.rs
+++ b/src/librustc_mir/util/liveness.rs
@@ -57,7 +57,7 @@
/// Computes which local variables are live within the given function
/// `mir`, including drops.
pub fn liveness_of_locals(
- body: ReadOnlyBodyCache<'_, '_>,
+ body: ReadOnlyBodyAndCache<'_, '_>,
) -> LivenessResult {
let num_live_vars = body.local_decls.len();
diff --git a/src/librustc_mir/util/patch.rs b/src/librustc_mir/util/patch.rs
index 47bb0b6..575b6d2 100644
--- a/src/librustc_mir/util/patch.rs
+++ b/src/librustc_mir/util/patch.rs
@@ -127,7 +127,7 @@
self.make_nop.push(loc);
}
- pub fn apply(self, body: &mut BodyCache<'tcx>) {
+ pub fn apply(self, body: &mut BodyAndCache<'tcx>) {
debug!("MirPatch: make nops at: {:?}", self.make_nop);
for loc in self.make_nop {
body.make_statement_nop(loc);
diff --git a/src/librustc_parse/config.rs b/src/librustc_parse/config.rs
index 30e056e..1e9203f 100644
--- a/src/librustc_parse/config.rs
+++ b/src/librustc_parse/config.rs
@@ -8,18 +8,19 @@
//!
//! [#64197]: https://github.com/rust-lang/rust/issues/64197
-use crate::validate_attr;
+use crate::{parse_in, validate_attr};
use rustc_feature::Features;
use rustc_errors::Applicability;
use syntax::attr::HasAttrs;
use syntax::feature_gate::{feature_err, get_features};
use syntax::attr;
-use syntax::ast;
+use syntax::ast::{self, Attribute, AttrItem, MetaItem};
use syntax::edition::Edition;
use syntax::mut_visit::*;
use syntax::ptr::P;
use syntax::sess::ParseSess;
use syntax::util::map_in_place::MapInPlace;
+use syntax_pos::Span;
use syntax_pos::symbol::sym;
use smallvec::SmallVec;
@@ -72,10 +73,15 @@
}
}
+const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]";
+const CFG_ATTR_NOTE_REF: &str = "for more information, visit \
+ <https://doc.rust-lang.org/reference/conditional-compilation.html\
+ #the-cfg_attr-attribute>";
+
impl<'a> StripUnconfigured<'a> {
pub fn configure<T: HasAttrs>(&mut self, mut node: T) -> Option<T> {
self.process_cfg_attrs(&mut node);
- if self.in_cfg(node.attrs()) { Some(node) } else { None }
+ self.in_cfg(node.attrs()).then_some(node)
}
/// Parse and expand all `cfg_attr` attributes into a list of attributes
@@ -97,34 +103,14 @@
/// Gives a compiler warning when the `cfg_attr` contains no attributes and
/// is in the original source file. Gives a compiler error if the syntax of
/// the attribute is incorrect.
- fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Vec<ast::Attribute> {
+ fn process_cfg_attr(&mut self, attr: Attribute) -> Vec<Attribute> {
if !attr.has_name(sym::cfg_attr) {
return vec![attr];
}
- if let ast::MacArgs::Empty = attr.get_normal_item().args {
- self.sess.span_diagnostic
- .struct_span_err(
- attr.span,
- "malformed `cfg_attr` attribute input",
- ).span_suggestion(
- attr.span,
- "missing condition and attribute",
- "#[cfg_attr(condition, attribute, other_attribute, ...)]".to_owned(),
- Applicability::HasPlaceholders,
- ).note("for more information, visit \
- <https://doc.rust-lang.org/reference/conditional-compilation.html\
- #the-cfg_attr-attribute>")
- .emit();
- return vec![];
- }
- let res = crate::parse_in_attr(self.sess, &attr, |p| p.parse_cfg_attr());
- let (cfg_predicate, expanded_attrs) = match res {
- Ok(result) => result,
- Err(mut e) => {
- e.emit();
- return vec![];
- }
+ let (cfg_predicate, expanded_attrs) = match self.parse_cfg_attr(&attr) {
+ None => return vec![],
+ Some(r) => r,
};
// Lint on zero attributes in source.
@@ -135,24 +121,56 @@
// At this point we know the attribute is considered used.
attr::mark_used(&attr);
- if attr::cfg_matches(&cfg_predicate, self.sess, self.features) {
- // We call `process_cfg_attr` recursively in case there's a
- // `cfg_attr` inside of another `cfg_attr`. E.g.
- // `#[cfg_attr(false, cfg_attr(true, some_attr))]`.
- expanded_attrs.into_iter()
- .flat_map(|(item, span)| self.process_cfg_attr(attr::mk_attr_from_item(
- attr.style,
- item,
- span,
- )))
- .collect()
- } else {
- vec![]
+ if !attr::cfg_matches(&cfg_predicate, self.sess, self.features) {
+ return vec![];
}
+
+ // We call `process_cfg_attr` recursively in case there's a
+ // `cfg_attr` inside of another `cfg_attr`. E.g.
+ // `#[cfg_attr(false, cfg_attr(true, some_attr))]`.
+ expanded_attrs
+ .into_iter()
+ .flat_map(|(item, span)| {
+ let attr = attr::mk_attr_from_item(attr.style, item, span);
+ self.process_cfg_attr(attr)
+ })
+ .collect()
+ }
+
+ fn parse_cfg_attr(&self, attr: &Attribute) -> Option<(MetaItem, Vec<(AttrItem, Span)>)> {
+ match attr.get_normal_item().args {
+ ast::MacArgs::Delimited(dspan, delim, ref tts) if !tts.is_empty() => {
+ let msg = "wrong `cfg_attr` delimiters";
+ validate_attr::check_meta_bad_delim(self.sess, dspan, delim, msg);
+ match parse_in(self.sess, tts.clone(), "`cfg_attr` input", |p| p.parse_cfg_attr()) {
+ Ok(r) => return Some(r),
+ Err(mut e) => e
+ .help(&format!("the valid syntax is `{}`", CFG_ATTR_GRAMMAR_HELP))
+ .note(CFG_ATTR_NOTE_REF)
+ .emit(),
+ }
+ }
+ _ => self.error_malformed_cfg_attr_missing(attr.span),
+ }
+ None
+ }
+
+ fn error_malformed_cfg_attr_missing(&self, span: Span) {
+ self.sess
+ .span_diagnostic
+ .struct_span_err(span, "malformed `cfg_attr` attribute input")
+ .span_suggestion(
+ span,
+ "missing condition and attribute",
+ CFG_ATTR_GRAMMAR_HELP.to_string(),
+ Applicability::HasPlaceholders,
+ )
+ .note(CFG_ATTR_NOTE_REF)
+ .emit();
}
/// Determines if a node with the given attributes should be included in this configuration.
- pub fn in_cfg(&self, attrs: &[ast::Attribute]) -> bool {
+ pub fn in_cfg(&self, attrs: &[Attribute]) -> bool {
attrs.iter().all(|attr| {
if !is_cfg(attr) {
return true;
@@ -199,7 +217,7 @@
}
/// Visit attributes on expression and statements (but not attributes on items in blocks).
- fn visit_expr_attrs(&mut self, attrs: &[ast::Attribute]) {
+ fn visit_expr_attrs(&mut self, attrs: &[Attribute]) {
// flag the offending attributes
for attr in attrs.iter() {
self.maybe_emit_expr_attr_err(attr);
@@ -207,7 +225,7 @@
}
/// If attributes are not allowed on expressions, emit an error for `attr`
- pub fn maybe_emit_expr_attr_err(&self, attr: &ast::Attribute) {
+ pub fn maybe_emit_expr_attr_err(&self, attr: &Attribute) {
if !self.features.map(|features| features.stmt_expr_attributes).unwrap_or(true) {
let mut err = feature_err(self.sess,
sym::stmt_expr_attributes,
@@ -350,7 +368,7 @@
}
}
-fn is_cfg(attr: &ast::Attribute) -> bool {
+fn is_cfg(attr: &Attribute) -> bool {
attr.check_name(sym::cfg)
}
@@ -359,8 +377,8 @@
pub fn process_configure_mod(
sess: &ParseSess,
cfg_mods: bool,
- attrs: &[ast::Attribute],
-) -> (bool, Vec<ast::Attribute>) {
+ attrs: &[Attribute],
+) -> (bool, Vec<Attribute>) {
// Don't perform gated feature checking.
let mut strip_unconfigured = StripUnconfigured { sess, features: None };
let mut attrs = attrs.to_owned();
diff --git a/src/librustc_parse/lib.rs b/src/librustc_parse/lib.rs
index a222f3f..faff386 100644
--- a/src/librustc_parse/lib.rs
+++ b/src/librustc_parse/lib.rs
@@ -1,5 +1,6 @@
//! The main parser interface.
+#![feature(bool_to_option)]
#![feature(crate_visibility_modifier)]
use syntax::ast;
@@ -270,21 +271,13 @@
}
/// Runs the given subparser `f` on the tokens of the given `attr`'s item.
-pub fn parse_in_attr<'a, T>(
+pub fn parse_in<'a, T>(
sess: &'a ParseSess,
- attr: &ast::Attribute,
+ tts: TokenStream,
+ name: &'static str,
mut f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
) -> PResult<'a, T> {
- let mut parser = Parser::new(
- sess,
- // FIXME(#66940, Centril | petrochenkov): refactor this function so it doesn't
- // require reconstructing and immediately re-parsing delimiters.
- attr.get_normal_item().args.outer_tokens(),
- None,
- false,
- false,
- Some("attribute"),
- );
+ let mut parser = Parser::new(sess, tts, None, false, false, Some(name));
let result = f(&mut parser)?;
if parser.token != token::Eof {
parser.unexpected()?;
diff --git a/src/librustc_parse/parser/attr.rs b/src/librustc_parse/parser/attr.rs
index b2ae934..00fd6b8 100644
--- a/src/librustc_parse/parser/attr.rs
+++ b/src/librustc_parse/parser/attr.rs
@@ -220,7 +220,7 @@
Ok(attrs)
}
- pub(super) fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> {
+ crate fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> {
let lit = self.parse_lit()?;
debug!("checking if {:?} is unusuffixed", lit);
@@ -238,25 +238,36 @@
/// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited.
pub fn parse_cfg_attr(&mut self) -> PResult<'a, (ast::MetaItem, Vec<(ast::AttrItem, Span)>)> {
- self.expect(&token::OpenDelim(token::Paren))?;
-
let cfg_predicate = self.parse_meta_item()?;
self.expect(&token::Comma)?;
// Presumably, the majority of the time there will only be one attr.
let mut expanded_attrs = Vec::with_capacity(1);
-
- while !self.check(&token::CloseDelim(token::Paren)) {
- let lo = self.token.span.lo();
+ while self.token.kind != token::Eof {
+ let lo = self.token.span;
let item = self.parse_attr_item()?;
- expanded_attrs.push((item, self.prev_span.with_lo(lo)));
- self.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Paren)])?;
+ expanded_attrs.push((item, lo.to(self.prev_span)));
+ if !self.eat(&token::Comma) {
+ break;
+ }
}
- self.expect(&token::CloseDelim(token::Paren))?;
Ok((cfg_predicate, expanded_attrs))
}
+ /// Matches `COMMASEP(meta_item_inner)`.
+ crate fn parse_meta_seq_top(&mut self) -> PResult<'a, Vec<ast::NestedMetaItem>> {
+ // Presumably, the majority of the time there will only be one attr.
+ let mut nmis = Vec::with_capacity(1);
+ while self.token.kind != token::Eof {
+ nmis.push(self.parse_meta_item_inner()?);
+ if !self.eat(&token::Comma) {
+ break;
+ }
+ }
+ Ok(nmis)
+ }
+
/// Matches the following grammar (per RFC 1559).
///
/// meta_item : PATH ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ;
diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs
index ccf78e6..34ef12e 100644
--- a/src/librustc_parse/parser/item.rs
+++ b/src/librustc_parse/parser/item.rs
@@ -1181,6 +1181,7 @@
attrs,
vis: visibility,
kind: ForeignItemKind::Macro(mac),
+ tokens: None,
}
)
}
@@ -1211,6 +1212,7 @@
id: DUMMY_NODE_ID,
span: lo.to(hi),
vis,
+ tokens: None,
})
}
@@ -1228,7 +1230,8 @@
kind: ForeignItemKind::Ty,
id: DUMMY_NODE_ID,
span: lo.to(hi),
- vis
+ vis,
+ tokens: None,
})
}
@@ -1727,9 +1730,10 @@
/// Checks if current token is one of tokens which cannot be nested like `kw::Enum`. In case
/// it is, we try to parse the item and report error about nested types.
fn recover_nested_adt_item(&mut self, keyword: Symbol) -> PResult<'a, bool> {
- if self.token.is_keyword(kw::Enum) ||
+ if (self.token.is_keyword(kw::Enum) ||
self.token.is_keyword(kw::Struct) ||
- self.token.is_keyword(kw::Union)
+ self.token.is_keyword(kw::Union))
+ && self.look_ahead(1, |t| t.is_ident())
{
let kw_token = self.token.clone();
let kw_str = pprust::token_to_string(&kw_token);
@@ -1825,6 +1829,7 @@
id: DUMMY_NODE_ID,
span,
vis,
+ tokens: None,
})
}
diff --git a/src/librustc_parse/parser/path.rs b/src/librustc_parse/parser/path.rs
index 70c3458..5334fc4 100644
--- a/src/librustc_parse/parser/path.rs
+++ b/src/librustc_parse/parser/path.rs
@@ -3,7 +3,6 @@
use rustc_errors::{PResult, Applicability, pluralize};
use syntax::ast::{self, QSelf, Path, PathSegment, Ident, ParenthesizedArgs, AngleBracketedArgs};
use syntax::ast::{AnonConst, GenericArg, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode};
-use syntax::ast::MacArgs;
use syntax::ThinVec;
use syntax::token::{self, Token};
use syntax_pos::source_map::{Span, BytePos};
@@ -109,42 +108,6 @@
Ok(Path { segments, span: lo.to(self.prev_span) })
}
- /// Like `parse_path`, but also supports parsing `Word` meta items into paths for
- /// backwards-compatibility. This is used when parsing derive macro paths in `#[derive]`
- /// attributes.
- fn parse_path_allowing_meta(&mut self, style: PathStyle) -> PResult<'a, Path> {
- let meta_ident = match self.token.kind {
- token::Interpolated(ref nt) => match **nt {
- token::NtMeta(ref item) => match item.args {
- MacArgs::Empty => Some(item.path.clone()),
- _ => None,
- },
- _ => None,
- },
- _ => None,
- };
- if let Some(path) = meta_ident {
- self.bump();
- return Ok(path);
- }
- self.parse_path(style)
- }
-
- /// Parse a list of paths inside `#[derive(path_0, ..., path_n)]`.
- pub fn parse_derive_paths(&mut self) -> PResult<'a, Vec<Path>> {
- self.expect(&token::OpenDelim(token::Paren))?;
- let mut list = Vec::new();
- while !self.eat(&token::CloseDelim(token::Paren)) {
- let path = self.parse_path_allowing_meta(PathStyle::Mod)?;
- list.push(path);
- if !self.eat(&token::Comma) {
- self.expect(&token::CloseDelim(token::Paren))?;
- break
- }
- }
- Ok(list)
- }
-
pub(super) fn parse_path_segments(
&mut self,
segments: &mut Vec<PathSegment>,
diff --git a/src/librustc_parse/validate_attr.rs b/src/librustc_parse/validate_attr.rs
index 97e9cb8..94d3fe7 100644
--- a/src/librustc_parse/validate_attr.rs
+++ b/src/librustc_parse/validate_attr.rs
@@ -1,10 +1,13 @@
//! Meta-syntax validation logic of attributes for post-expansion.
+use crate::parse_in;
+
use rustc_errors::{PResult, Applicability};
use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP};
-use syntax::ast::{self, Attribute, AttrKind, Ident, MacArgs, MetaItem, MetaItemKind};
+use syntax::ast::{self, Attribute, AttrKind, Ident, MacArgs, MacDelimiter, MetaItem, MetaItemKind};
use syntax::attr::mk_name_value_item_str;
use syntax::early_buffered_lints::ILL_FORMED_ATTRIBUTE_INPUT;
+use syntax::tokenstream::DelimSpan;
use syntax::sess::ParseSess;
use syntax_pos::{Symbol, sym};
@@ -27,9 +30,20 @@
pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, MetaItem> {
Ok(match attr.kind {
AttrKind::Normal(ref item) => MetaItem {
- path: item.path.clone(),
- kind: super::parse_in_attr(sess, attr, |p| p.parse_meta_item_kind())?,
span: attr.span,
+ path: item.path.clone(),
+ kind: match &attr.get_normal_item().args {
+ MacArgs::Empty => MetaItemKind::Word,
+ MacArgs::Eq(_, t) => {
+ let v = parse_in(sess, t.clone(), "name value", |p| p.parse_unsuffixed_lit())?;
+ MetaItemKind::NameValue(v)
+ }
+ MacArgs::Delimited(dspan, delim, t) => {
+ check_meta_bad_delim(sess, *dspan, *delim, "wrong meta list delimiters");
+ let nmis = parse_in(sess, t.clone(), "meta list", |p| p.parse_meta_seq_top())?;
+ MetaItemKind::List(nmis)
+ }
+ }
},
AttrKind::DocComment(comment) => {
mk_name_value_item_str(Ident::new(sym::doc, attr.span), comment, attr.span)
@@ -37,6 +51,24 @@
})
}
+crate fn check_meta_bad_delim(sess: &ParseSess, span: DelimSpan, delim: MacDelimiter, msg: &str) {
+ if let ast::MacDelimiter::Parenthesis = delim {
+ return;
+ }
+
+ sess.span_diagnostic
+ .struct_span_err(span.entire(), msg)
+ .multipart_suggestion(
+ "the delimiters should be `(` and `)`",
+ vec![
+ (span.open, "(".to_string()),
+ (span.close, ")".to_string()),
+ ],
+ Applicability::MachineApplicable,
+ )
+ .emit();
+}
+
/// Checks that the given meta-item is compatible with this `AttributeTemplate`.
fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaItemKind) -> bool {
match meta {
diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs
index 4dcafb6..8dd45f5 100644
--- a/src/librustc_resolve/diagnostics.rs
+++ b/src/librustc_resolve/diagnostics.rs
@@ -422,11 +422,7 @@
Scope::MacroUsePrelude => {
suggestions.extend(this.macro_use_prelude.iter().filter_map(|(name, binding)| {
let res = binding.res();
- if filter_fn(res) {
- Some(TypoSuggestion::from_res(*name, res))
- } else {
- None
- }
+ filter_fn(res).then_some(TypoSuggestion::from_res(*name, res))
}));
}
Scope::BuiltinAttrs => {
@@ -440,11 +436,7 @@
Scope::ExternPrelude => {
suggestions.extend(this.extern_prelude.iter().filter_map(|(ident, _)| {
let res = Res::Def(DefKind::Mod, DefId::local(CRATE_DEF_INDEX));
- if filter_fn(res) {
- Some(TypoSuggestion::from_res(ident.name, res))
- } else {
- None
- }
+ filter_fn(res).then_some(TypoSuggestion::from_res(ident.name, res))
}));
}
Scope::ToolPrelude => {
@@ -467,11 +459,7 @@
suggestions.extend(
primitive_types.iter().flat_map(|(name, prim_ty)| {
let res = Res::PrimTy(*prim_ty);
- if filter_fn(res) {
- Some(TypoSuggestion::from_res(*name, res))
- } else {
- None
- }
+ filter_fn(res).then_some(TypoSuggestion::from_res(*name, res))
})
)
}
diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs
index 666c482..4f95d6f 100644
--- a/src/librustc_resolve/late.rs
+++ b/src/librustc_resolve/late.rs
@@ -496,11 +496,7 @@
GenericParamKind::Lifetime { .. } => None,
GenericParamKind::Type { ref default, .. } => {
found_default |= default.is_some();
- if found_default {
- Some((Ident::with_dummy_span(param.ident.name), Res::Err))
- } else {
- None
- }
+ found_default.then_some((Ident::with_dummy_span(param.ident.name), Res::Err))
}
}));
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index be36e02..31f59e4 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -9,6 +9,7 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![feature(bool_to_option)]
#![feature(crate_visibility_modifier)]
#![feature(label_break_value)]
#![feature(nll)]
diff --git a/src/librustc_session/session.rs b/src/librustc_session/session.rs
index 9369c17..150d207 100644
--- a/src/librustc_session/session.rs
+++ b/src/librustc_session/session.rs
@@ -752,11 +752,7 @@
}
pub fn incr_comp_session_dir_opt(&self) -> Option<cell::Ref<'_, PathBuf>> {
- if self.opts.incremental.is_some() {
- Some(self.incr_comp_session_dir())
- } else {
- None
- }
+ self.opts.incremental.as_ref().map(|_| self.incr_comp_session_dir())
}
pub fn print_perf_stats(&self) {
@@ -1079,8 +1075,9 @@
None
}
}
- }
- else { None };
+ } else {
+ None
+ };
let host_triple = TargetTriple::from_triple(config::host_triple());
let host = Target::search(&host_triple).unwrap_or_else(|e|
diff --git a/src/librustc_target/abi/call/aarch64.rs b/src/librustc_target/abi/call/aarch64.rs
index 45fe475..06c001e 100644
--- a/src/librustc_target/abi/call/aarch64.rs
+++ b/src/librustc_target/abi/call/aarch64.rs
@@ -20,14 +20,7 @@
RegKind::Vector => size.bits() == 64 || size.bits() == 128
};
- if valid_unit {
- Some(Uniform {
- unit,
- total: size
- })
- } else {
- None
- }
+ valid_unit.then_some(Uniform { unit, total: size })
})
}
diff --git a/src/librustc_target/abi/call/arm.rs b/src/librustc_target/abi/call/arm.rs
index ff929f3..36971c1 100644
--- a/src/librustc_target/abi/call/arm.rs
+++ b/src/librustc_target/abi/call/arm.rs
@@ -21,14 +21,7 @@
RegKind::Vector => size.bits() == 64 || size.bits() == 128
};
- if valid_unit {
- Some(Uniform {
- unit,
- total: size
- })
- } else {
- None
- }
+ valid_unit.then_some(Uniform { unit, total: size })
})
}
diff --git a/src/librustc_target/abi/call/mod.rs b/src/librustc_target/abi/call/mod.rs
index 6f53577..5119464 100644
--- a/src/librustc_target/abi/call/mod.rs
+++ b/src/librustc_target/abi/call/mod.rs
@@ -416,11 +416,7 @@
// i686-pc-windows-msvc, it results in wrong stack offsets.
// attrs.pointee_align = Some(self.layout.align.abi);
- let extra_attrs = if self.layout.is_unsized() {
- Some(ArgAttributes::new())
- } else {
- None
- };
+ let extra_attrs = self.layout.is_unsized().then_some(ArgAttributes::new());
self.mode = PassMode::Indirect(attrs, extra_attrs);
}
diff --git a/src/librustc_target/abi/call/powerpc64.rs b/src/librustc_target/abi/call/powerpc64.rs
index f967a83..fe45948 100644
--- a/src/librustc_target/abi/call/powerpc64.rs
+++ b/src/librustc_target/abi/call/powerpc64.rs
@@ -32,14 +32,7 @@
RegKind::Vector => arg.layout.size.bits() == 128
};
- if valid_unit {
- Some(Uniform {
- unit,
- total: arg.layout.size
- })
- } else {
- None
- }
+ valid_unit.then_some(Uniform { unit, total: arg.layout.size })
})
}
diff --git a/src/librustc_target/abi/call/sparc64.rs b/src/librustc_target/abi/call/sparc64.rs
index fe2c427..32be7b8 100644
--- a/src/librustc_target/abi/call/sparc64.rs
+++ b/src/librustc_target/abi/call/sparc64.rs
@@ -20,14 +20,7 @@
RegKind::Vector => arg.layout.size.bits() == 128
};
- if valid_unit {
- Some(Uniform {
- unit,
- total: arg.layout.size
- })
- } else {
- None
- }
+ valid_unit.then_some(Uniform { unit, total: arg.layout.size })
})
}
diff --git a/src/librustc_target/lib.rs b/src/librustc_target/lib.rs
index 5582eaf..6a1498e 100644
--- a/src/librustc_target/lib.rs
+++ b/src/librustc_target/lib.rs
@@ -10,6 +10,7 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
#![feature(box_syntax)]
+#![feature(bool_to_option)]
#![feature(nll)]
#![feature(slice_patterns)]
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 901a219..253fc55 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -1284,6 +1284,10 @@
augment_error(&mut err);
}
+ if let Some(expr) = expression {
+ fcx.emit_coerce_suggestions(&mut err, expr, found, expected);
+ }
+
// Error possibly reported in `check_assign` so avoid emitting error again.
err.emit_unless(expression.filter(|e| fcx.is_assign_to_bool(e, expected))
.is_some());
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index 32df6c4..16a55d2 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -15,6 +15,22 @@
use super::method::probe;
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+
+ pub fn emit_coerce_suggestions(
+ &self,
+ err: &mut DiagnosticBuilder<'_>,
+ expr: &hir::Expr,
+ expr_ty: Ty<'tcx>,
+ expected: Ty<'tcx>
+ ) {
+ self.annotate_expected_due_to_let_ty(err, expr);
+ self.suggest_compatible_variants(err, expr, expected, expr_ty);
+ self.suggest_ref_or_into(err, expr, expected, expr_ty);
+ self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty);
+ self.suggest_missing_await(err, expr, expected, expr_ty);
+ }
+
+
// Requires that the two types unify, and prints an error message if
// they don't.
pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
@@ -137,11 +153,7 @@
return (expected, None)
}
- self.annotate_expected_due_to_let_ty(&mut err, expr);
- self.suggest_compatible_variants(&mut err, expr, expected, expr_ty);
- self.suggest_ref_or_into(&mut err, expr, expected, expr_ty);
- self.suggest_boxing_when_appropriate(&mut err, expr, expected, expr_ty);
- self.suggest_missing_await(&mut err, expr, expected, expr_ty);
+ self.emit_coerce_suggestions(&mut err, expr, expr_ty, expected);
(expected, Some(err))
}
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index 9f034e65..cec8311 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -1,7 +1,6 @@
//! Type-checking for the rust-intrinsic and platform-intrinsic
//! intrinsics that the compiler exposes.
-use rustc::middle::lang_items::PanicLocationLangItem;
use rustc::traits::{ObligationCause, ObligationCauseCode};
use rustc::ty::{self, TyCtxt, Ty};
use rustc::ty::subst::Subst;
@@ -148,15 +147,7 @@
], tcx.types.usize)
}
"rustc_peek" => (1, vec![param(0)], param(0)),
- "caller_location" => (
- 0,
- vec![],
- tcx.mk_imm_ref(
- tcx.lifetimes.re_static,
- tcx.type_of(tcx.require_lang_item(PanicLocationLangItem, None))
- .subst(tcx, tcx.mk_substs([tcx.lifetimes.re_static.into()].iter())),
- ),
- ),
+ "caller_location" => (0, vec![], tcx.caller_location_ty()),
"panic_if_uninhabited" => (1, Vec::new(), tcx.mk_unit()),
"init" => (1, Vec::new(), param(0)),
"uninit" => (1, Vec::new(), param(0)),
@@ -336,6 +327,7 @@
(1, vec![param(0), param(0)], param(0)),
"fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" =>
(1, vec![param(0), param(0)], param(0)),
+ "float_to_int_approx_unchecked" => (2, vec![ param(0) ], param(1)),
"assume" => (0, vec![tcx.types.bool], tcx.mk_unit()),
"likely" => (0, vec![tcx.types.bool], tcx.types.bool),
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 9717190..9923081 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -1105,11 +1105,7 @@
r.map(|mut pick| {
pick.autoderefs = step.autoderefs;
pick.autoref = Some(mutbl);
- pick.unsize = if step.unsize {
- Some(self_ty)
- } else {
- None
- };
+ pick.unsize = step.unsize.then_some(self_ty);
pick
})
})
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index c7a0190..a956aba 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -4584,8 +4584,6 @@
pointing_at_return_type = self.suggest_missing_return_type(
err, &fn_decl, expected, found, can_suggest);
}
- self.suggest_ref_or_into(err, expr, expected, found);
- self.suggest_boxing_when_appropriate(err, expr, expected, found);
pointing_at_return_type
}
@@ -4957,7 +4955,9 @@
ty: expected,
}));
let obligation = traits::Obligation::new(self.misc(sp), self.param_env, predicate);
+ debug!("suggest_missing_await: trying obligation {:?}", obligation);
if self.infcx.predicate_may_hold(&obligation) {
+ debug!("suggest_missing_await: obligation held: {:?}", obligation);
if let Ok(code) = self.sess().source_map().span_to_snippet(sp) {
err.span_suggestion(
sp,
@@ -4965,7 +4965,11 @@
format!("{}.await", code),
Applicability::MaybeIncorrect,
);
+ } else {
+ debug!("suggest_missing_await: no snippet for {:?}", sp);
}
+ } else {
+ debug!("suggest_missing_await: obligation did not hold: {:?}", obligation)
}
}
}
diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs
index 3002459..c5a6c07 100644
--- a/src/librustc_typeck/check/upvar.rs
+++ b/src/librustc_typeck/check/upvar.rs
@@ -114,11 +114,7 @@
};
let infer_kind = if let UpvarSubsts::Closure(closure_substs) = substs {
- if self.closure_kind(closure_def_id, closure_substs).is_none() {
- Some(closure_substs)
- } else {
- None
- }
+ self.closure_kind(closure_def_id, closure_substs).is_none().then_some(closure_substs)
} else {
None
};
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 6d6e768..b982979 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -2616,7 +2616,7 @@
tcx.sess,
attr.span,
E0737,
- "Rust ABI is required to use `#[track_caller]`"
+ "`#[track_caller]` requires Rust ABI"
).emit();
}
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index c606fea..6a6294b 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -59,6 +59,7 @@
#![allow(non_camel_case_types)]
+#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(crate_visibility_modifier)]
diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs
index 078948c..fb2cce3 100644
--- a/src/librustdoc/clean/cfg.rs
+++ b/src/librustdoc/clean/cfg.rs
@@ -209,6 +209,9 @@
impl ops::BitAndAssign for Cfg {
fn bitand_assign(&mut self, other: Cfg) {
+ if *self == other {
+ return;
+ }
match (self, other) {
(&mut Cfg::False, _) | (_, Cfg::True) => {},
(s, Cfg::False) => *s = Cfg::False,
@@ -238,6 +241,9 @@
impl ops::BitOrAssign for Cfg {
fn bitor_assign(&mut self, other: Cfg) {
+ if *self == other {
+ return;
+ }
match (self, other) {
(&mut Cfg::True, _) | (_, Cfg::False) => {},
(s, Cfg::True) => *s = Cfg::True,
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 4d8d004..327be40 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -5,12 +5,12 @@
pub mod inline;
pub mod cfg;
-mod simplify;
mod auto_trait;
mod blanket_impl;
+mod simplify;
+pub mod types;
use rustc_index::vec::{IndexVec, Idx};
-use rustc_target::spec::abi::Abi;
use rustc_typeck::hir_ty_to_ty;
use rustc::infer::region_constraints::{RegionConstraintData, Constraint};
use rustc::middle::resolve_lifetime as rl;
@@ -24,46 +24,33 @@
use rustc::ty::subst::{InternalSubsts, SubstsRef, GenericArgKind};
use rustc::ty::{self, DefIdTree, TyCtxt, Region, RegionVid, Ty, AdtKind};
use rustc::ty::fold::TypeFolder;
-use rustc::ty::layout::VariantIdx;
use rustc::util::nodemap::{FxHashMap, FxHashSet};
-use syntax::ast::{self, Attribute, AttrStyle, AttrKind, Ident};
+use syntax::ast::{self, Ident};
use syntax::attr;
-use syntax::util::comments;
-use syntax::source_map::DUMMY_SP;
use syntax_pos::symbol::{Symbol, kw, sym};
use syntax_pos::hygiene::MacroKind;
-use syntax_pos::{self, Pos, FileName};
+use syntax_pos::{self, Pos};
use std::collections::hash_map::Entry;
-use std::fmt;
-use std::hash::{Hash, Hasher};
+use std::hash::Hash;
use std::default::Default;
-use std::{mem, slice, vec};
-use std::num::NonZeroU32;
-use std::iter::FromIterator;
+use std::{mem, vec};
use std::rc::Rc;
-use std::cell::RefCell;
-use std::sync::Arc;
use std::u32;
use crate::core::{self, DocContext, ImplTraitParam};
use crate::doctree;
-use crate::html::render::{cache, ExternalLocation};
-use crate::html::item_type::ItemType;
-
-use self::cfg::Cfg;
use self::auto_trait::AutoTraitFinder;
use self::blanket_impl::BlanketImplFinder;
-pub use self::Type::*;
-pub use self::Mutability::*;
-pub use self::ItemEnum::*;
-pub use self::SelfTy::*;
-pub use self::FunctionRetTy::*;
-pub use self::Visibility::{Public, Inherited};
-
-thread_local!(pub static MAX_DEF_ID: RefCell<FxHashMap<CrateNum, DefId>> = Default::default());
+pub use self::types::*;
+pub use self::types::Type::*;
+pub use self::types::Mutability::*;
+pub use self::types::ItemEnum::*;
+pub use self::types::SelfTy::*;
+pub use self::types::FunctionRetTy::*;
+pub use self::types::Visibility::{Public, Inherited};
const FN_OUTPUT_NAME: &'static str = "Output";
@@ -122,21 +109,6 @@
}
}
-#[derive(Clone, Debug)]
-pub struct Crate {
- pub name: String,
- pub version: Option<String>,
- pub src: FileName,
- pub module: Option<Item>,
- pub externs: Vec<(CrateNum, ExternalCrate)>,
- pub primitives: Vec<(DefId, PrimitiveType, Attributes)>,
- // These are later on moved into `CACHEKEY`, leaving the map empty.
- // Only here so that they can be filtered through the rustdoc passes.
- pub external_traits: Rc<RefCell<FxHashMap<DefId, Trait>>>,
- pub masked_crates: FxHashSet<CrateNum>,
- pub collapsed: bool,
-}
-
pub fn krate(mut cx: &mut DocContext<'_>) -> Crate {
use crate::visit_lib::LibEmbargoVisitor;
@@ -222,15 +194,6 @@
}
}
-#[derive(Clone, Debug)]
-pub struct ExternalCrate {
- pub name: String,
- pub src: FileName,
- pub attrs: Attributes,
- pub primitives: Vec<(DefId, PrimitiveType, Attributes)>,
- pub keywords: Vec<(DefId, String, Attributes)>,
-}
-
impl Clean<ExternalCrate> for CrateNum {
fn clean(&self, cx: &DocContext<'_>) -> ExternalCrate {
let root = DefId { krate: *self, index: CRATE_DEF_INDEX };
@@ -351,237 +314,6 @@
}
}
-/// Anything with a source location and set of attributes and, optionally, a
-/// name. That is, anything that can be documented. This doesn't correspond
-/// directly to the AST's concept of an item; it's a strict superset.
-#[derive(Clone)]
-pub struct Item {
- /// Stringified span
- pub source: Span,
- /// Not everything has a name. E.g., impls
- pub name: Option<String>,
- pub attrs: Attributes,
- pub inner: ItemEnum,
- pub visibility: Visibility,
- pub def_id: DefId,
- pub stability: Option<Stability>,
- pub deprecation: Option<Deprecation>,
-}
-
-impl fmt::Debug for Item {
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-
- let fake = MAX_DEF_ID.with(|m| m.borrow().get(&self.def_id.krate)
- .map(|id| self.def_id >= *id).unwrap_or(false));
- let def_id: &dyn fmt::Debug = if fake { &"**FAKE**" } else { &self.def_id };
-
- fmt.debug_struct("Item")
- .field("source", &self.source)
- .field("name", &self.name)
- .field("attrs", &self.attrs)
- .field("inner", &self.inner)
- .field("visibility", &self.visibility)
- .field("def_id", def_id)
- .field("stability", &self.stability)
- .field("deprecation", &self.deprecation)
- .finish()
- }
-}
-
-impl Item {
- /// Finds the `doc` attribute as a NameValue and returns the corresponding
- /// value found.
- pub fn doc_value(&self) -> Option<&str> {
- self.attrs.doc_value()
- }
- /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined
- /// with newlines.
- pub fn collapsed_doc_value(&self) -> Option<String> {
- self.attrs.collapsed_doc_value()
- }
-
- pub fn links(&self) -> Vec<(String, String)> {
- self.attrs.links(&self.def_id.krate)
- }
-
- pub fn is_crate(&self) -> bool {
- match self.inner {
- StrippedItem(box ModuleItem(Module { is_crate: true, ..})) |
- ModuleItem(Module { is_crate: true, ..}) => true,
- _ => false,
- }
- }
- pub fn is_mod(&self) -> bool {
- self.type_() == ItemType::Module
- }
- pub fn is_trait(&self) -> bool {
- self.type_() == ItemType::Trait
- }
- pub fn is_struct(&self) -> bool {
- self.type_() == ItemType::Struct
- }
- pub fn is_enum(&self) -> bool {
- self.type_() == ItemType::Enum
- }
- pub fn is_variant(&self) -> bool {
- self.type_() == ItemType::Variant
- }
- pub fn is_associated_type(&self) -> bool {
- self.type_() == ItemType::AssocType
- }
- pub fn is_associated_const(&self) -> bool {
- self.type_() == ItemType::AssocConst
- }
- pub fn is_method(&self) -> bool {
- self.type_() == ItemType::Method
- }
- pub fn is_ty_method(&self) -> bool {
- self.type_() == ItemType::TyMethod
- }
- pub fn is_typedef(&self) -> bool {
- self.type_() == ItemType::Typedef
- }
- pub fn is_primitive(&self) -> bool {
- self.type_() == ItemType::Primitive
- }
- pub fn is_union(&self) -> bool {
- self.type_() == ItemType::Union
- }
- pub fn is_import(&self) -> bool {
- self.type_() == ItemType::Import
- }
- pub fn is_extern_crate(&self) -> bool {
- self.type_() == ItemType::ExternCrate
- }
- pub fn is_keyword(&self) -> bool {
- self.type_() == ItemType::Keyword
- }
-
- pub fn is_stripped(&self) -> bool {
- match self.inner { StrippedItem(..) => true, _ => false }
- }
- pub fn has_stripped_fields(&self) -> Option<bool> {
- match self.inner {
- StructItem(ref _struct) => Some(_struct.fields_stripped),
- UnionItem(ref union) => Some(union.fields_stripped),
- VariantItem(Variant { kind: VariantKind::Struct(ref vstruct)} ) => {
- Some(vstruct.fields_stripped)
- },
- _ => None,
- }
- }
-
- pub fn stability_class(&self) -> Option<String> {
- self.stability.as_ref().and_then(|ref s| {
- let mut classes = Vec::with_capacity(2);
-
- if s.level == stability::Unstable {
- classes.push("unstable");
- }
-
- if s.deprecation.is_some() {
- classes.push("deprecated");
- }
-
- if classes.len() != 0 {
- Some(classes.join(" "))
- } else {
- None
- }
- })
- }
-
- pub fn stable_since(&self) -> Option<&str> {
- self.stability.as_ref().map(|s| &s.since[..])
- }
-
- pub fn is_non_exhaustive(&self) -> bool {
- self.attrs.other_attrs.iter()
- .any(|a| a.check_name(sym::non_exhaustive))
- }
-
- /// Returns a documentation-level item type from the item.
- pub fn type_(&self) -> ItemType {
- ItemType::from(self)
- }
-
- /// Returns the info in the item's `#[deprecated]` or `#[rustc_deprecated]` attributes.
- ///
- /// If the item is not deprecated, returns `None`.
- pub fn deprecation(&self) -> Option<&Deprecation> {
- self.deprecation
- .as_ref()
- .or_else(|| self.stability.as_ref().and_then(|s| s.deprecation.as_ref()))
- }
- pub fn is_default(&self) -> bool {
- match self.inner {
- ItemEnum::MethodItem(ref meth) => {
- if let Some(defaultness) = meth.defaultness {
- defaultness.has_value() && !defaultness.is_final()
- } else {
- false
- }
- }
- _ => false,
- }
- }
-}
-
-#[derive(Clone, Debug)]
-pub enum ItemEnum {
- ExternCrateItem(String, Option<String>),
- ImportItem(Import),
- StructItem(Struct),
- UnionItem(Union),
- EnumItem(Enum),
- FunctionItem(Function),
- ModuleItem(Module),
- TypedefItem(Typedef, bool /* is associated type */),
- OpaqueTyItem(OpaqueTy, bool /* is associated type */),
- StaticItem(Static),
- ConstantItem(Constant),
- TraitItem(Trait),
- TraitAliasItem(TraitAlias),
- ImplItem(Impl),
- /// A method signature only. Used for required methods in traits (ie,
- /// non-default-methods).
- TyMethodItem(TyMethod),
- /// A method with a body.
- MethodItem(Method),
- StructFieldItem(Type),
- VariantItem(Variant),
- /// `fn`s from an extern block
- ForeignFunctionItem(Function),
- /// `static`s from an extern block
- ForeignStaticItem(Static),
- /// `type`s from an extern block
- ForeignTypeItem,
- MacroItem(Macro),
- ProcMacroItem(ProcMacro),
- PrimitiveItem(PrimitiveType),
- AssocConstItem(Type, Option<String>),
- AssocTypeItem(Vec<GenericBound>, Option<Type>),
- /// An item that has been stripped by a rustdoc pass
- StrippedItem(Box<ItemEnum>),
- KeywordItem(String),
-}
-
-impl ItemEnum {
- pub fn is_associated(&self) -> bool {
- match *self {
- ItemEnum::TypedefItem(_, _) |
- ItemEnum::AssocTypeItem(_, _) => true,
- _ => false,
- }
- }
-}
-
-#[derive(Clone, Debug)]
-pub struct Module {
- pub items: Vec<Item>,
- pub is_crate: bool,
-}
-
impl Clean<Item> for doctree::Module<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item {
let name = if self.name.is_some() {
@@ -645,465 +377,12 @@
}
}
-pub struct ListAttributesIter<'a> {
- attrs: slice::Iter<'a, ast::Attribute>,
- current_list: vec::IntoIter<ast::NestedMetaItem>,
- name: Symbol,
-}
-
-impl<'a> Iterator for ListAttributesIter<'a> {
- type Item = ast::NestedMetaItem;
-
- fn next(&mut self) -> Option<Self::Item> {
- if let Some(nested) = self.current_list.next() {
- return Some(nested);
- }
-
- for attr in &mut self.attrs {
- if let Some(list) = attr.meta_item_list() {
- if attr.check_name(self.name) {
- self.current_list = list.into_iter();
- if let Some(nested) = self.current_list.next() {
- return Some(nested);
- }
- }
- }
- }
-
- None
- }
-
- fn size_hint(&self) -> (usize, Option<usize>) {
- let lower = self.current_list.len();
- (lower, None)
- }
-}
-
-pub trait AttributesExt {
- /// Finds an attribute as List and returns the list of attributes nested inside.
- fn lists(&self, name: Symbol) -> ListAttributesIter<'_>;
-}
-
-impl AttributesExt for [ast::Attribute] {
- fn lists(&self, name: Symbol) -> ListAttributesIter<'_> {
- ListAttributesIter {
- attrs: self.iter(),
- current_list: Vec::new().into_iter(),
- name,
- }
- }
-}
-
-pub trait NestedAttributesExt {
- /// Returns `true` if the attribute list contains a specific `Word`
- fn has_word(self, word: Symbol) -> bool;
-}
-
-impl<I: IntoIterator<Item=ast::NestedMetaItem>> NestedAttributesExt for I {
- fn has_word(self, word: Symbol) -> bool {
- self.into_iter().any(|attr| attr.is_word() && attr.check_name(word))
- }
-}
-
-/// A portion of documentation, extracted from a `#[doc]` attribute.
-///
-/// Each variant contains the line number within the complete doc-comment where the fragment
-/// starts, as well as the Span where the corresponding doc comment or attribute is located.
-///
-/// Included files are kept separate from inline doc comments so that proper line-number
-/// information can be given when a doctest fails. Sugared doc comments and "raw" doc comments are
-/// kept separate because of issue #42760.
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub enum DocFragment {
- /// A doc fragment created from a `///` or `//!` doc comment.
- SugaredDoc(usize, syntax_pos::Span, String),
- /// A doc fragment created from a "raw" `#[doc=""]` attribute.
- RawDoc(usize, syntax_pos::Span, String),
- /// A doc fragment created from a `#[doc(include="filename")]` attribute. Contains both the
- /// given filename and the file contents.
- Include(usize, syntax_pos::Span, String, String),
-}
-
-impl DocFragment {
- pub fn as_str(&self) -> &str {
- match *self {
- DocFragment::SugaredDoc(_, _, ref s) => &s[..],
- DocFragment::RawDoc(_, _, ref s) => &s[..],
- DocFragment::Include(_, _, _, ref s) => &s[..],
- }
- }
-
- pub fn span(&self) -> syntax_pos::Span {
- match *self {
- DocFragment::SugaredDoc(_, span, _) |
- DocFragment::RawDoc(_, span, _) |
- DocFragment::Include(_, span, _, _) => span,
- }
- }
-}
-
-impl<'a> FromIterator<&'a DocFragment> for String {
- fn from_iter<T>(iter: T) -> Self
- where
- T: IntoIterator<Item = &'a DocFragment>
- {
- iter.into_iter().fold(String::new(), |mut acc, frag| {
- if !acc.is_empty() {
- acc.push('\n');
- }
- match *frag {
- DocFragment::SugaredDoc(_, _, ref docs)
- | DocFragment::RawDoc(_, _, ref docs)
- | DocFragment::Include(_, _, _, ref docs) =>
- acc.push_str(docs),
- }
-
- acc
- })
- }
-}
-
-#[derive(Clone, Debug, Default)]
-pub struct Attributes {
- pub doc_strings: Vec<DocFragment>,
- pub other_attrs: Vec<ast::Attribute>,
- pub cfg: Option<Arc<Cfg>>,
- pub span: Option<syntax_pos::Span>,
- /// map from Rust paths to resolved defs and potential URL fragments
- pub links: Vec<(String, Option<DefId>, Option<String>)>,
- pub inner_docs: bool,
-}
-
-impl Attributes {
- /// Extracts the content from an attribute `#[doc(cfg(content))]`.
- fn extract_cfg(mi: &ast::MetaItem) -> Option<&ast::MetaItem> {
- use syntax::ast::NestedMetaItem::MetaItem;
-
- if let ast::MetaItemKind::List(ref nmis) = mi.kind {
- if nmis.len() == 1 {
- if let MetaItem(ref cfg_mi) = nmis[0] {
- if cfg_mi.check_name(sym::cfg) {
- if let ast::MetaItemKind::List(ref cfg_nmis) = cfg_mi.kind {
- if cfg_nmis.len() == 1 {
- if let MetaItem(ref content_mi) = cfg_nmis[0] {
- return Some(content_mi);
- }
- }
- }
- }
- }
- }
- }
-
- None
- }
-
- /// Reads a `MetaItem` from within an attribute, looks for whether it is a
- /// `#[doc(include="file")]`, and returns the filename and contents of the file as loaded from
- /// its expansion.
- fn extract_include(mi: &ast::MetaItem)
- -> Option<(String, String)>
- {
- mi.meta_item_list().and_then(|list| {
- for meta in list {
- if meta.check_name(sym::include) {
- // the actual compiled `#[doc(include="filename")]` gets expanded to
- // `#[doc(include(file="filename", contents="file contents")]` so we need to
- // look for that instead
- return meta.meta_item_list().and_then(|list| {
- let mut filename: Option<String> = None;
- let mut contents: Option<String> = None;
-
- for it in list {
- if it.check_name(sym::file) {
- if let Some(name) = it.value_str() {
- filename = Some(name.to_string());
- }
- } else if it.check_name(sym::contents) {
- if let Some(docs) = it.value_str() {
- contents = Some(docs.to_string());
- }
- }
- }
-
- if let (Some(filename), Some(contents)) = (filename, contents) {
- Some((filename, contents))
- } else {
- None
- }
- });
- }
- }
-
- None
- })
- }
-
- pub fn has_doc_flag(&self, flag: Symbol) -> bool {
- for attr in &self.other_attrs {
- if !attr.check_name(sym::doc) { continue; }
-
- if let Some(items) = attr.meta_item_list() {
- if items.iter().filter_map(|i| i.meta_item()).any(|it| it.check_name(flag)) {
- return true;
- }
- }
- }
-
- false
- }
-
- pub fn from_ast(diagnostic: &::errors::Handler,
- attrs: &[ast::Attribute]) -> Attributes {
- let mut doc_strings = vec![];
- let mut sp = None;
- let mut cfg = Cfg::True;
- let mut doc_line = 0;
-
- /// If `attr` is a doc comment, strips the leading and (if present)
- /// trailing comments symbols, e.g. `///`, `/**`, and `*/`. Otherwise,
- /// returns `attr` unchanged.
- pub fn with_doc_comment_markers_stripped<T>(
- attr: &Attribute,
- f: impl FnOnce(&Attribute) -> T
- ) -> T {
- match attr.kind {
- AttrKind::Normal(_) => {
- f(attr)
- }
- AttrKind::DocComment(comment) => {
- let comment =
- Symbol::intern(&comments::strip_doc_comment_decoration(&comment.as_str()));
- f(&Attribute {
- kind: AttrKind::DocComment(comment),
- id: attr.id,
- style: attr.style,
- span: attr.span,
- })
- }
- }
- }
-
- let other_attrs = attrs.iter().filter_map(|attr| {
- with_doc_comment_markers_stripped(attr, |attr| {
- if attr.check_name(sym::doc) {
- if let Some(mi) = attr.meta() {
- if let Some(value) = mi.value_str() {
- // Extracted #[doc = "..."]
- let value = value.to_string();
- let line = doc_line;
- doc_line += value.lines().count();
-
- if attr.is_doc_comment() {
- doc_strings.push(DocFragment::SugaredDoc(line, attr.span, value));
- } else {
- doc_strings.push(DocFragment::RawDoc(line, attr.span, value));
- }
-
- if sp.is_none() {
- sp = Some(attr.span);
- }
- return None;
- } else if let Some(cfg_mi) = Attributes::extract_cfg(&mi) {
- // Extracted #[doc(cfg(...))]
- match Cfg::parse(cfg_mi) {
- Ok(new_cfg) => cfg &= new_cfg,
- Err(e) => diagnostic.span_err(e.span, e.msg),
- }
- return None;
- } else if let Some((filename, contents)) = Attributes::extract_include(&mi)
- {
- let line = doc_line;
- doc_line += contents.lines().count();
- doc_strings.push(DocFragment::Include(line,
- attr.span,
- filename,
- contents));
- }
- }
- }
- Some(attr.clone())
- })
- }).collect();
-
- // treat #[target_feature(enable = "feat")] attributes as if they were
- // #[doc(cfg(target_feature = "feat"))] attributes as well
- for attr in attrs.lists(sym::target_feature) {
- if attr.check_name(sym::enable) {
- if let Some(feat) = attr.value_str() {
- let meta = attr::mk_name_value_item_str(
- Ident::with_dummy_span(sym::target_feature), feat, DUMMY_SP
- );
- if let Ok(feat_cfg) = Cfg::parse(&meta) {
- cfg &= feat_cfg;
- }
- }
- }
- }
-
- let inner_docs = attrs.iter()
- .filter(|a| a.check_name(sym::doc))
- .next()
- .map_or(true, |a| a.style == AttrStyle::Inner);
-
- Attributes {
- doc_strings,
- other_attrs,
- cfg: if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) },
- span: sp,
- links: vec![],
- inner_docs,
- }
- }
-
- /// Finds the `doc` attribute as a NameValue and returns the corresponding
- /// value found.
- pub fn doc_value(&self) -> Option<&str> {
- self.doc_strings.first().map(|s| s.as_str())
- }
-
- /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined
- /// with newlines.
- pub fn collapsed_doc_value(&self) -> Option<String> {
- if !self.doc_strings.is_empty() {
- Some(self.doc_strings.iter().collect())
- } else {
- None
- }
- }
-
- /// Gets links as a vector
- ///
- /// Cache must be populated before call
- pub fn links(&self, krate: &CrateNum) -> Vec<(String, String)> {
- use crate::html::format::href;
-
- self.links.iter().filter_map(|&(ref s, did, ref fragment)| {
- match did {
- Some(did) => {
- if let Some((mut href, ..)) = href(did) {
- if let Some(ref fragment) = *fragment {
- href.push_str("#");
- href.push_str(fragment);
- }
- Some((s.clone(), href))
- } else {
- None
- }
- }
- None => {
- if let Some(ref fragment) = *fragment {
- let cache = cache();
- let url = match cache.extern_locations.get(krate) {
- Some(&(_, ref src, ExternalLocation::Local)) =>
- src.to_str().expect("invalid file path"),
- Some(&(_, _, ExternalLocation::Remote(ref s))) => s,
- Some(&(_, _, ExternalLocation::Unknown)) | None =>
- "https://doc.rust-lang.org/nightly",
- };
- // This is a primitive so the url is done "by hand".
- let tail = fragment.find('#').unwrap_or_else(|| fragment.len());
- Some((s.clone(),
- format!("{}{}std/primitive.{}.html{}",
- url,
- if !url.ends_with('/') { "/" } else { "" },
- &fragment[..tail],
- &fragment[tail..])))
- } else {
- panic!("This isn't a primitive?!");
- }
- }
- }
- }).collect()
- }
-}
-
-impl PartialEq for Attributes {
- fn eq(&self, rhs: &Self) -> bool {
- self.doc_strings == rhs.doc_strings &&
- self.cfg == rhs.cfg &&
- self.span == rhs.span &&
- self.links == rhs.links &&
- self.other_attrs.iter().map(|attr| attr.id).eq(rhs.other_attrs.iter().map(|attr| attr.id))
- }
-}
-
-impl Eq for Attributes {}
-
-impl Hash for Attributes {
- fn hash<H: Hasher>(&self, hasher: &mut H) {
- self.doc_strings.hash(hasher);
- self.cfg.hash(hasher);
- self.span.hash(hasher);
- self.links.hash(hasher);
- for attr in &self.other_attrs {
- attr.id.hash(hasher);
- }
- }
-}
-
-impl AttributesExt for Attributes {
- fn lists(&self, name: Symbol) -> ListAttributesIter<'_> {
- self.other_attrs.lists(name)
- }
-}
-
impl Clean<Attributes> for [ast::Attribute] {
fn clean(&self, cx: &DocContext<'_>) -> Attributes {
Attributes::from_ast(cx.sess().diagnostic(), self)
}
}
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub enum GenericBound {
- TraitBound(PolyTrait, hir::TraitBoundModifier),
- Outlives(Lifetime),
-}
-
-impl GenericBound {
- fn maybe_sized(cx: &DocContext<'_>) -> GenericBound {
- let did = cx.tcx.require_lang_item(lang_items::SizedTraitLangItem, None);
- let empty = cx.tcx.intern_substs(&[]);
- let path = external_path(cx, cx.tcx.item_name(did),
- Some(did), false, vec![], empty);
- inline::record_extern_fqn(cx, did, TypeKind::Trait);
- GenericBound::TraitBound(PolyTrait {
- trait_: ResolvedPath {
- path,
- param_names: None,
- did,
- is_generic: false,
- },
- generic_params: Vec::new(),
- }, hir::TraitBoundModifier::Maybe)
- }
-
- fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool {
- use rustc::hir::TraitBoundModifier as TBM;
- if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self {
- if trait_.def_id() == cx.tcx.lang_items().sized_trait() {
- return true;
- }
- }
- false
- }
-
- fn get_poly_trait(&self) -> Option<PolyTrait> {
- if let GenericBound::TraitBound(ref p, _) = *self {
- return Some(p.clone())
- }
- None
- }
-
- fn get_trait_type(&self) -> Option<Type> {
- if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self {
- Some(trait_.clone())
- } else {
- None
- }
- }
-}
-
impl Clean<GenericBound> for hir::GenericBound {
fn clean(&self, cx: &DocContext<'_>) -> GenericBound {
match *self {
@@ -1237,21 +516,6 @@
}
}
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub struct Lifetime(String);
-
-impl Lifetime {
- pub fn get_ref<'a>(&'a self) -> &'a str {
- let Lifetime(ref s) = *self;
- let s: &'a str = s;
- s
- }
-
- pub fn statik() -> Lifetime {
- Lifetime("'static".to_string())
- }
-}
-
impl Clean<Lifetime> for hir::Lifetime {
fn clean(&self, cx: &DocContext<'_>) -> Lifetime {
if self.hir_id != hir::DUMMY_HIR_ID {
@@ -1332,23 +596,6 @@
}
}
-#[derive(Clone, Debug)]
-pub enum WherePredicate {
- BoundPredicate { ty: Type, bounds: Vec<GenericBound> },
- RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
- EqPredicate { lhs: Type, rhs: Type },
-}
-
-impl WherePredicate {
- pub fn get_bounds(&self) -> Option<&[GenericBound]> {
- match *self {
- WherePredicate::BoundPredicate { ref bounds, .. } => Some(bounds),
- WherePredicate::RegionPredicate { ref bounds, .. } => Some(bounds),
- _ => None,
- }
- }
-}
-
impl Clean<WherePredicate> for hir::WherePredicate {
fn clean(&self, cx: &DocContext<'_>) -> WherePredicate {
match *self {
@@ -1470,73 +717,6 @@
}
}
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub enum GenericParamDefKind {
- Lifetime,
- Type {
- did: DefId,
- bounds: Vec<GenericBound>,
- default: Option<Type>,
- synthetic: Option<hir::SyntheticTyParamKind>,
- },
- Const {
- did: DefId,
- ty: Type,
- },
-}
-
-impl GenericParamDefKind {
- pub fn is_type(&self) -> bool {
- match *self {
- GenericParamDefKind::Type { .. } => true,
- _ => false,
- }
- }
-
- // FIXME(eddyb) this either returns the default of a type parameter, or the
- // type of a `const` parameter. It seems that the intention is to *visit*
- // any embedded types, but `get_type` seems to be the wrong name for that.
- pub fn get_type(&self) -> Option<Type> {
- match self {
- GenericParamDefKind::Type { default, .. } => default.clone(),
- GenericParamDefKind::Const { ty, .. } => Some(ty.clone()),
- GenericParamDefKind::Lifetime => None,
- }
- }
-}
-
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub struct GenericParamDef {
- pub name: String,
-
- pub kind: GenericParamDefKind,
-}
-
-impl GenericParamDef {
- pub fn is_synthetic_type_param(&self) -> bool {
- match self.kind {
- GenericParamDefKind::Lifetime |
- GenericParamDefKind::Const { .. } => false,
- GenericParamDefKind::Type { ref synthetic, .. } => synthetic.is_some(),
- }
- }
-
- pub fn is_type(&self) -> bool {
- self.kind.is_type()
- }
-
- pub fn get_type(&self) -> Option<Type> {
- self.kind.get_type()
- }
-
- pub fn get_bounds(&self) -> Option<&[GenericBound]> {
- match self.kind {
- GenericParamDefKind::Type { ref bounds, .. } => Some(bounds),
- _ => None,
- }
- }
-}
-
impl Clean<GenericParamDef> for ty::GenericParamDef {
fn clean(&self, cx: &DocContext<'_>) -> GenericParamDef {
let (name, kind) = match self.kind {
@@ -1614,13 +794,6 @@
}
}
-// maybe use a Generic enum and use Vec<Generic>?
-#[derive(Clone, Debug, Default)]
-pub struct Generics {
- pub params: Vec<GenericParamDef>,
- pub where_predicates: Vec<WherePredicate>,
-}
-
impl Clean<Generics> for hir::Generics {
fn clean(&self, cx: &DocContext<'_>) -> Generics {
// Synthetic type-parameters are inserted after normal ones.
@@ -1975,16 +1148,6 @@
(all_types.into_iter().collect(), ret_types)
}
-#[derive(Clone, Debug)]
-pub struct Method {
- pub generics: Generics,
- pub decl: FnDecl,
- pub header: hir::FnHeader,
- pub defaultness: Option<hir::Defaultness>,
- pub all_types: Vec<Type>,
- pub ret_types: Vec<Type>,
-}
-
impl<'a> Clean<Method> for (&'a hir::FnSig, &'a hir::Generics, hir::BodyId,
Option<hir::Defaultness>) {
fn clean(&self, cx: &DocContext<'_>) -> Method {
@@ -2003,24 +1166,6 @@
}
}
-#[derive(Clone, Debug)]
-pub struct TyMethod {
- pub header: hir::FnHeader,
- pub decl: FnDecl,
- pub generics: Generics,
- pub all_types: Vec<Type>,
- pub ret_types: Vec<Type>,
-}
-
-#[derive(Clone, Debug)]
-pub struct Function {
- pub decl: FnDecl,
- pub generics: Generics,
- pub header: hir::FnHeader,
- pub all_types: Vec<Type>,
- pub ret_types: Vec<Type>,
-}
-
impl Clean<Item> for doctree::Function<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item {
let (generics, decl) = enter_impl_trait(cx, || {
@@ -2053,49 +1198,6 @@
}
}
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub struct FnDecl {
- pub inputs: Arguments,
- pub output: FunctionRetTy,
- pub c_variadic: bool,
- pub attrs: Attributes,
-}
-
-impl FnDecl {
- pub fn self_type(&self) -> Option<SelfTy> {
- self.inputs.values.get(0).and_then(|v| v.to_self())
- }
-
- /// Returns the sugared return type for an async function.
- ///
- /// For example, if the return type is `impl std::future::Future<Output = i32>`, this function
- /// will return `i32`.
- ///
- /// # Panics
- ///
- /// This function will panic if the return type does not match the expected sugaring for async
- /// functions.
- pub fn sugared_async_return_type(&self) -> FunctionRetTy {
- match &self.output {
- FunctionRetTy::Return(Type::ImplTrait(bounds)) => {
- match &bounds[0] {
- GenericBound::TraitBound(PolyTrait { trait_, .. }, ..) => {
- let bindings = trait_.bindings().unwrap();
- FunctionRetTy::Return(bindings[0].ty().clone())
- }
- _ => panic!("unexpected desugaring of async function"),
- }
- }
- _ => panic!("unexpected desugaring of async function"),
- }
- }
-}
-
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub struct Arguments {
- pub values: Vec<Argument>,
-}
-
impl<'a> Clean<Arguments> for (&'a [hir::Ty], &'a [ast::Ident]) {
fn clean(&self, cx: &DocContext<'_>) -> Arguments {
Arguments {
@@ -2167,42 +1269,6 @@
}
}
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub struct Argument {
- pub type_: Type,
- pub name: String,
-}
-
-#[derive(Clone, PartialEq, Debug)]
-pub enum SelfTy {
- SelfValue,
- SelfBorrowed(Option<Lifetime>, Mutability),
- SelfExplicit(Type),
-}
-
-impl Argument {
- pub fn to_self(&self) -> Option<SelfTy> {
- if self.name != "self" {
- return None;
- }
- if self.type_.is_self_type() {
- return Some(SelfValue);
- }
- match self.type_ {
- BorrowedRef{ref lifetime, mutability, ref type_} if type_.is_self_type() => {
- Some(SelfBorrowed(lifetime.clone(), mutability))
- }
- _ => Some(SelfExplicit(self.type_.clone()))
- }
- }
-}
-
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub enum FunctionRetTy {
- Return(Type),
- DefaultReturn,
-}
-
impl Clean<FunctionRetTy> for hir::FunctionRetTy {
fn clean(&self, cx: &DocContext<'_>) -> FunctionRetTy {
match *self {
@@ -2212,26 +1278,6 @@
}
}
-impl GetDefId for FunctionRetTy {
- fn def_id(&self) -> Option<DefId> {
- match *self {
- Return(ref ty) => ty.def_id(),
- DefaultReturn => None,
- }
- }
-}
-
-#[derive(Clone, Debug)]
-pub struct Trait {
- pub auto: bool,
- pub unsafety: hir::Unsafety,
- pub items: Vec<Item>,
- pub generics: Generics,
- pub bounds: Vec<GenericBound>,
- pub is_spotlight: bool,
- pub is_auto: bool,
-}
-
impl Clean<Item> for doctree::Trait<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item {
let attrs = self.attrs.clean(cx);
@@ -2257,12 +1303,6 @@
}
}
-#[derive(Clone, Debug)]
-pub struct TraitAlias {
- pub generics: Generics,
- pub bounds: Vec<GenericBound>,
-}
-
impl Clean<Item> for doctree::TraitAlias<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item {
let attrs = self.attrs.clean(cx);
@@ -2541,321 +1581,6 @@
}
}
-/// A trait reference, which may have higher ranked lifetimes.
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub struct PolyTrait {
- pub trait_: Type,
- pub generic_params: Vec<GenericParamDef>,
-}
-
-/// A representation of a type suitable for hyperlinking purposes. Ideally, one can get the original
-/// type out of the AST/`TyCtxt` given one of these, if more information is needed. Most
-/// importantly, it does not preserve mutability or boxes.
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub enum Type {
- /// Structs/enums/traits (most that would be an `hir::TyKind::Path`).
- ResolvedPath {
- path: Path,
- param_names: Option<Vec<GenericBound>>,
- did: DefId,
- /// `true` if is a `T::Name` path for associated types.
- is_generic: bool,
- },
- /// For parameterized types, so the consumer of the JSON don't go
- /// looking for types which don't exist anywhere.
- Generic(String),
- /// Primitives are the fixed-size numeric types (plus int/usize/float), char,
- /// arrays, slices, and tuples.
- Primitive(PrimitiveType),
- /// `extern "ABI" fn`
- BareFunction(Box<BareFunctionDecl>),
- Tuple(Vec<Type>),
- Slice(Box<Type>),
- Array(Box<Type>, String),
- Never,
- RawPointer(Mutability, Box<Type>),
- BorrowedRef {
- lifetime: Option<Lifetime>,
- mutability: Mutability,
- type_: Box<Type>,
- },
-
- // `<Type as Trait>::Name`
- QPath {
- name: String,
- self_type: Box<Type>,
- trait_: Box<Type>
- },
-
- // `_`
- Infer,
-
- // `impl TraitA + TraitB + ...`
- ImplTrait(Vec<GenericBound>),
-}
-
-#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)]
-pub enum PrimitiveType {
- Isize, I8, I16, I32, I64, I128,
- Usize, U8, U16, U32, U64, U128,
- F32, F64,
- Char,
- Bool,
- Str,
- Slice,
- Array,
- Tuple,
- Unit,
- RawPointer,
- Reference,
- Fn,
- Never,
-}
-
-#[derive(Clone, Copy, Debug)]
-pub enum TypeKind {
- Enum,
- Function,
- Module,
- Const,
- Static,
- Struct,
- Union,
- Trait,
- Typedef,
- Foreign,
- Macro,
- Attr,
- Derive,
- TraitAlias,
-}
-
-pub trait GetDefId {
- fn def_id(&self) -> Option<DefId>;
-}
-
-impl<T: GetDefId> GetDefId for Option<T> {
- fn def_id(&self) -> Option<DefId> {
- self.as_ref().and_then(|d| d.def_id())
- }
-}
-
-impl Type {
- pub fn primitive_type(&self) -> Option<PrimitiveType> {
- match *self {
- Primitive(p) | BorrowedRef { type_: box Primitive(p), ..} => Some(p),
- Slice(..) | BorrowedRef { type_: box Slice(..), .. } => Some(PrimitiveType::Slice),
- Array(..) | BorrowedRef { type_: box Array(..), .. } => Some(PrimitiveType::Array),
- Tuple(ref tys) => if tys.is_empty() {
- Some(PrimitiveType::Unit)
- } else {
- Some(PrimitiveType::Tuple)
- },
- RawPointer(..) => Some(PrimitiveType::RawPointer),
- BorrowedRef { type_: box Generic(..), .. } => Some(PrimitiveType::Reference),
- BareFunction(..) => Some(PrimitiveType::Fn),
- Never => Some(PrimitiveType::Never),
- _ => None,
- }
- }
-
- pub fn is_generic(&self) -> bool {
- match *self {
- ResolvedPath { is_generic, .. } => is_generic,
- _ => false,
- }
- }
-
- pub fn is_self_type(&self) -> bool {
- match *self {
- Generic(ref name) => name == "Self",
- _ => false
- }
- }
-
- pub fn generics(&self) -> Option<Vec<Type>> {
- match *self {
- ResolvedPath { ref path, .. } => {
- path.segments.last().and_then(|seg| {
- if let GenericArgs::AngleBracketed { ref args, .. } = seg.args {
- Some(args.iter().filter_map(|arg| match arg {
- GenericArg::Type(ty) => Some(ty.clone()),
- _ => None,
- }).collect())
- } else {
- None
- }
- })
- }
- _ => None,
- }
- }
-
- pub fn bindings(&self) -> Option<&[TypeBinding]> {
- match *self {
- ResolvedPath { ref path, .. } => {
- path.segments.last().and_then(|seg| {
- if let GenericArgs::AngleBracketed { ref bindings, .. } = seg.args {
- Some(&**bindings)
- } else {
- None
- }
- })
- }
- _ => None
- }
- }
-
- pub fn is_full_generic(&self) -> bool {
- match *self {
- Type::Generic(_) => true,
- _ => false,
- }
- }
-
- pub fn projection(&self) -> Option<(&Type, DefId, &str)> {
- let (self_, trait_, name) = match self {
- QPath { ref self_type, ref trait_, ref name } => {
- (self_type, trait_, name)
- }
- _ => return None,
- };
- let trait_did = match **trait_ {
- ResolvedPath { did, .. } => did,
- _ => return None,
- };
- Some((&self_, trait_did, name))
- }
-
-}
-
-impl GetDefId for Type {
- fn def_id(&self) -> Option<DefId> {
- match *self {
- ResolvedPath { did, .. } => Some(did),
- Primitive(p) => crate::html::render::cache().primitive_locations.get(&p).cloned(),
- BorrowedRef { type_: box Generic(..), .. } =>
- Primitive(PrimitiveType::Reference).def_id(),
- BorrowedRef { ref type_, .. } => type_.def_id(),
- Tuple(ref tys) => if tys.is_empty() {
- Primitive(PrimitiveType::Unit).def_id()
- } else {
- Primitive(PrimitiveType::Tuple).def_id()
- },
- BareFunction(..) => Primitive(PrimitiveType::Fn).def_id(),
- Never => Primitive(PrimitiveType::Never).def_id(),
- Slice(..) => Primitive(PrimitiveType::Slice).def_id(),
- Array(..) => Primitive(PrimitiveType::Array).def_id(),
- RawPointer(..) => Primitive(PrimitiveType::RawPointer).def_id(),
- QPath { ref self_type, .. } => self_type.def_id(),
- _ => None,
- }
- }
-}
-
-impl PrimitiveType {
- fn from_str(s: &str) -> Option<PrimitiveType> {
- match s {
- "isize" => Some(PrimitiveType::Isize),
- "i8" => Some(PrimitiveType::I8),
- "i16" => Some(PrimitiveType::I16),
- "i32" => Some(PrimitiveType::I32),
- "i64" => Some(PrimitiveType::I64),
- "i128" => Some(PrimitiveType::I128),
- "usize" => Some(PrimitiveType::Usize),
- "u8" => Some(PrimitiveType::U8),
- "u16" => Some(PrimitiveType::U16),
- "u32" => Some(PrimitiveType::U32),
- "u64" => Some(PrimitiveType::U64),
- "u128" => Some(PrimitiveType::U128),
- "bool" => Some(PrimitiveType::Bool),
- "char" => Some(PrimitiveType::Char),
- "str" => Some(PrimitiveType::Str),
- "f32" => Some(PrimitiveType::F32),
- "f64" => Some(PrimitiveType::F64),
- "array" => Some(PrimitiveType::Array),
- "slice" => Some(PrimitiveType::Slice),
- "tuple" => Some(PrimitiveType::Tuple),
- "unit" => Some(PrimitiveType::Unit),
- "pointer" => Some(PrimitiveType::RawPointer),
- "reference" => Some(PrimitiveType::Reference),
- "fn" => Some(PrimitiveType::Fn),
- "never" => Some(PrimitiveType::Never),
- _ => None,
- }
- }
-
- pub fn as_str(&self) -> &'static str {
- use self::PrimitiveType::*;
- match *self {
- Isize => "isize",
- I8 => "i8",
- I16 => "i16",
- I32 => "i32",
- I64 => "i64",
- I128 => "i128",
- Usize => "usize",
- U8 => "u8",
- U16 => "u16",
- U32 => "u32",
- U64 => "u64",
- U128 => "u128",
- F32 => "f32",
- F64 => "f64",
- Str => "str",
- Bool => "bool",
- Char => "char",
- Array => "array",
- Slice => "slice",
- Tuple => "tuple",
- Unit => "unit",
- RawPointer => "pointer",
- Reference => "reference",
- Fn => "fn",
- Never => "never",
- }
- }
-
- pub fn to_url_str(&self) -> &'static str {
- self.as_str()
- }
-}
-
-impl From<ast::IntTy> for PrimitiveType {
- fn from(int_ty: ast::IntTy) -> PrimitiveType {
- match int_ty {
- ast::IntTy::Isize => PrimitiveType::Isize,
- ast::IntTy::I8 => PrimitiveType::I8,
- ast::IntTy::I16 => PrimitiveType::I16,
- ast::IntTy::I32 => PrimitiveType::I32,
- ast::IntTy::I64 => PrimitiveType::I64,
- ast::IntTy::I128 => PrimitiveType::I128,
- }
- }
-}
-
-impl From<ast::UintTy> for PrimitiveType {
- fn from(uint_ty: ast::UintTy) -> PrimitiveType {
- match uint_ty {
- ast::UintTy::Usize => PrimitiveType::Usize,
- ast::UintTy::U8 => PrimitiveType::U8,
- ast::UintTy::U16 => PrimitiveType::U16,
- ast::UintTy::U32 => PrimitiveType::U32,
- ast::UintTy::U64 => PrimitiveType::U64,
- ast::UintTy::U128 => PrimitiveType::U128,
- }
- }
-}
-
-impl From<ast::FloatTy> for PrimitiveType {
- fn from(float_ty: ast::FloatTy) -> PrimitiveType {
- match float_ty {
- ast::FloatTy::F32 => PrimitiveType::F32,
- ast::FloatTy::F64 => PrimitiveType::F64,
- }
- }
-}
-
impl Clean<Type> for hir::Ty {
fn clean(&self, cx: &DocContext<'_>) -> Type {
use rustc::hir::*;
@@ -3310,14 +2035,6 @@
}
}
-#[derive(Clone, PartialEq, Eq, Debug)]
-pub enum Visibility {
- Public,
- Inherited,
- Crate,
- Restricted(DefId, Path),
-}
-
impl Clean<Visibility> for hir::Visibility {
fn clean(&self, cx: &DocContext<'_>) -> Visibility {
match self.node {
@@ -3339,22 +2056,6 @@
}
}
-#[derive(Clone, Debug)]
-pub struct Struct {
- pub struct_type: doctree::StructType,
- pub generics: Generics,
- pub fields: Vec<Item>,
- pub fields_stripped: bool,
-}
-
-#[derive(Clone, Debug)]
-pub struct Union {
- pub struct_type: doctree::StructType,
- pub generics: Generics,
- pub fields: Vec<Item>,
- pub fields_stripped: bool,
-}
-
impl Clean<Item> for doctree::Struct<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item {
Item {
@@ -3395,16 +2096,6 @@
}
}
-/// This is a more limited form of the standard Struct, different in that
-/// it lacks the things most items have (name, id, parameterization). Found
-/// only as a variant in an enum.
-#[derive(Clone, Debug)]
-pub struct VariantStruct {
- pub struct_type: doctree::StructType,
- pub fields: Vec<Item>,
- pub fields_stripped: bool,
-}
-
impl Clean<VariantStruct> for ::rustc::hir::VariantData {
fn clean(&self, cx: &DocContext<'_>) -> VariantStruct {
VariantStruct {
@@ -3415,13 +2106,6 @@
}
}
-#[derive(Clone, Debug)]
-pub struct Enum {
- pub variants: IndexVec<VariantIdx, Item>,
- pub generics: Generics,
- pub variants_stripped: bool,
-}
-
impl Clean<Item> for doctree::Enum<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item {
Item {
@@ -3441,11 +2125,6 @@
}
}
-#[derive(Clone, Debug)]
-pub struct Variant {
- pub kind: VariantKind,
-}
-
impl Clean<Item> for doctree::Variant<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item {
Item {
@@ -3504,13 +2183,6 @@
}
}
-#[derive(Clone, Debug)]
-pub enum VariantKind {
- CLike,
- Tuple(Vec<Type>),
- Struct(VariantStruct),
-}
-
impl Clean<VariantKind> for hir::VariantData {
fn clean(&self, cx: &DocContext<'_>) -> VariantKind {
match self {
@@ -3522,31 +2194,6 @@
}
}
-#[derive(Clone, Debug)]
-pub struct Span {
- pub filename: FileName,
- pub loline: usize,
- pub locol: usize,
- pub hiline: usize,
- pub hicol: usize,
- pub original: syntax_pos::Span,
-}
-
-impl Span {
- pub fn empty() -> Span {
- Span {
- filename: FileName::Anon(0),
- loline: 0, locol: 0,
- hiline: 0, hicol: 0,
- original: syntax_pos::DUMMY_SP,
- }
- }
-
- pub fn span(&self) -> syntax_pos::Span {
- self.original
- }
-}
-
impl Clean<Span> for syntax_pos::Span {
fn clean(&self, cx: &DocContext<'_>) -> Span {
if self.is_dummy() {
@@ -3568,19 +2215,6 @@
}
}
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub struct Path {
- pub global: bool,
- pub res: Res,
- pub segments: Vec<PathSegment>,
-}
-
-impl Path {
- pub fn last_name(&self) -> &str {
- self.segments.last().expect("segments were empty").name.as_str()
- }
-}
-
impl Clean<Path> for hir::Path {
fn clean(&self, cx: &DocContext<'_>) -> Path {
Path {
@@ -3591,25 +2225,6 @@
}
}
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub enum GenericArg {
- Lifetime(Lifetime),
- Type(Type),
- Const(Constant),
-}
-
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub enum GenericArgs {
- AngleBracketed {
- args: Vec<GenericArg>,
- bindings: Vec<TypeBinding>,
- },
- Parenthesized {
- inputs: Vec<Type>,
- output: Option<Type>,
- }
-}
-
impl Clean<GenericArgs> for hir::GenericArgs {
fn clean(&self, cx: &DocContext<'_>) -> GenericArgs {
if self.parenthesized {
@@ -3638,12 +2253,6 @@
}
}
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub struct PathSegment {
- pub name: String,
- pub args: GenericArgs,
-}
-
impl Clean<PathSegment> for hir::PathSegment {
fn clean(&self, cx: &DocContext<'_>) -> PathSegment {
PathSegment {
@@ -3727,12 +2336,6 @@
}
}
-#[derive(Clone, Debug)]
-pub struct Typedef {
- pub type_: Type,
- pub generics: Generics,
-}
-
impl Clean<Item> for doctree::Typedef<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item {
Item {
@@ -3751,12 +2354,6 @@
}
}
-#[derive(Clone, Debug)]
-pub struct OpaqueTy {
- pub bounds: Vec<GenericBound>,
- pub generics: Generics,
-}
-
impl Clean<Item> for doctree::OpaqueTy<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item {
Item {
@@ -3775,14 +2372,6 @@
}
}
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub struct BareFunctionDecl {
- pub unsafety: hir::Unsafety,
- pub generic_params: Vec<GenericParamDef>,
- pub decl: FnDecl,
- pub abi: Abi,
-}
-
impl Clean<BareFunctionDecl> for hir::BareFnTy {
fn clean(&self, cx: &DocContext<'_>) -> BareFunctionDecl {
let (generic_params, decl) = enter_impl_trait(cx, || {
@@ -3797,16 +2386,6 @@
}
}
-#[derive(Clone, Debug)]
-pub struct Static {
- pub type_: Type,
- pub mutability: Mutability,
- /// It's useful to have the value of a static documented, but I have no
- /// desire to represent expressions (that'd basically be all of the AST,
- /// which is huge!). So, have a string.
- pub expr: String,
-}
-
impl Clean<Item> for doctree::Static<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item {
debug!("cleaning static {}: {:?}", self.name.clean(cx), self);
@@ -3827,12 +2406,6 @@
}
}
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
-pub struct Constant {
- pub type_: Type,
- pub expr: String,
-}
-
impl Clean<Item> for doctree::Constant<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item {
Item {
@@ -3851,12 +2424,6 @@
}
}
-#[derive(Debug, Clone, PartialEq, Eq, Copy, Hash)]
-pub enum Mutability {
- Mutable,
- Immutable,
-}
-
impl Clean<Mutability> for hir::Mutability {
fn clean(&self, _: &DocContext<'_>) -> Mutability {
match self {
@@ -3866,12 +2433,6 @@
}
}
-#[derive(Clone, PartialEq, Debug)]
-pub enum ImplPolarity {
- Positive,
- Negative,
-}
-
impl Clean<ImplPolarity> for ty::ImplPolarity {
fn clean(&self, _: &DocContext<'_>) -> ImplPolarity {
match self {
@@ -3883,19 +2444,6 @@
}
}
-#[derive(Clone, Debug)]
-pub struct Impl {
- pub unsafety: hir::Unsafety,
- pub generics: Generics,
- pub provided_trait_methods: FxHashSet<String>,
- pub trait_: Option<Type>,
- pub for_: Type,
- pub items: Vec<Item>,
- pub polarity: Option<ImplPolarity>,
- pub synthetic: bool,
- pub blanket_impl: Option<Type>,
-}
-
pub fn get_auto_trait_and_blanket_impls(
cx: &DocContext<'tcx>,
ty: Ty<'tcx>,
@@ -4115,20 +2663,6 @@
}
}
-#[derive(Clone, Debug)]
-pub enum Import {
- // use source as str;
- Simple(String, ImportSource),
- // use source::*;
- Glob(ImportSource)
-}
-
-#[derive(Clone, Debug)]
-pub struct ImportSource {
- pub path: Path,
- pub did: Option<DefId>,
-}
-
impl Clean<Item> for doctree::ForeignItem<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item {
let inner = match self.kind {
@@ -4340,12 +2874,6 @@
}
}
-#[derive(Clone, Debug)]
-pub struct Macro {
- pub source: String,
- pub imported_from: Option<String>,
-}
-
impl Clean<Item> for doctree::Macro<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item {
let name = self.name.clean(cx);
@@ -4369,12 +2897,6 @@
}
}
-#[derive(Clone, Debug)]
-pub struct ProcMacro {
- pub kind: MacroKind,
- pub helpers: Vec<String>,
-}
-
impl Clean<Item> for doctree::ProcMacro<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item {
Item {
@@ -4393,22 +2915,6 @@
}
}
-#[derive(Clone, Debug)]
-pub struct Stability {
- pub level: stability::StabilityLevel,
- pub feature: Option<String>,
- pub since: String,
- pub deprecation: Option<Deprecation>,
- pub unstable_reason: Option<String>,
- pub issue: Option<NonZeroU32>,
-}
-
-#[derive(Clone, Debug)]
-pub struct Deprecation {
- pub since: Option<String>,
- pub note: Option<String>,
-}
-
impl Clean<Stability> for attr::Stability {
fn clean(&self, _: &DocContext<'_>) -> Stability {
Stability {
@@ -4451,33 +2957,6 @@
}
}
-/// An type binding on an associated type (e.g., `A = Bar` in `Foo<A = Bar>` or
-/// `A: Send + Sync` in `Foo<A: Send + Sync>`).
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub struct TypeBinding {
- pub name: String,
- pub kind: TypeBindingKind,
-}
-
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub enum TypeBindingKind {
- Equality {
- ty: Type,
- },
- Constraint {
- bounds: Vec<GenericBound>,
- },
-}
-
-impl TypeBinding {
- pub fn ty(&self) -> &Type {
- match self.kind {
- TypeBindingKind::Equality { ref ty } => ty,
- _ => panic!("expected equality type binding for parenthesized generic args"),
- }
- }
-}
-
impl Clean<TypeBinding> for hir::TypeBinding {
fn clean(&self, cx: &DocContext<'_>) -> TypeBinding {
TypeBinding {
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
new file mode 100644
index 0000000..bd3f2a3
--- /dev/null
+++ b/src/librustdoc/clean/types.rs
@@ -0,0 +1,1545 @@
+use std::fmt;
+use std::hash::{Hash, Hasher};
+use std::default::Default;
+use std::{slice, vec};
+use std::num::NonZeroU32;
+use std::iter::FromIterator;
+use std::rc::Rc;
+use std::cell::RefCell;
+use std::sync::Arc;
+
+use rustc::middle::lang_items;
+use rustc::middle::stability;
+use rustc::hir;
+use rustc::hir::def::Res;
+use rustc::hir::def_id::{CrateNum, DefId};
+use rustc::ty::layout::VariantIdx;
+use rustc::util::nodemap::{FxHashMap, FxHashSet};
+use rustc_index::vec::IndexVec;
+use rustc_target::spec::abi::Abi;
+use syntax::ast::{self, Attribute, AttrStyle, AttrKind, Ident};
+use syntax::attr;
+use syntax::util::comments;
+use syntax::source_map::DUMMY_SP;
+use syntax_pos::hygiene::MacroKind;
+use syntax_pos::symbol::{Symbol, sym};
+use syntax_pos::{self, FileName};
+
+use crate::core::DocContext;
+use crate::clean::cfg::Cfg;
+use crate::clean::inline;
+use crate::clean::external_path;
+use crate::clean::types::Type::{QPath, ResolvedPath};
+use crate::doctree;
+use crate::html::item_type::ItemType;
+use crate::html::render::{cache, ExternalLocation};
+
+use self::Type::*;
+use self::ItemEnum::*;
+use self::SelfTy::*;
+use self::FunctionRetTy::*;
+
+thread_local!(pub static MAX_DEF_ID: RefCell<FxHashMap<CrateNum, DefId>> = Default::default());
+
+#[derive(Clone, Debug)]
+pub struct Crate {
+ pub name: String,
+ pub version: Option<String>,
+ pub src: FileName,
+ pub module: Option<Item>,
+ pub externs: Vec<(CrateNum, ExternalCrate)>,
+ pub primitives: Vec<(DefId, PrimitiveType, Attributes)>,
+ // These are later on moved into `CACHEKEY`, leaving the map empty.
+ // Only here so that they can be filtered through the rustdoc passes.
+ pub external_traits: Rc<RefCell<FxHashMap<DefId, Trait>>>,
+ pub masked_crates: FxHashSet<CrateNum>,
+ pub collapsed: bool,
+}
+
+#[derive(Clone, Debug)]
+pub struct ExternalCrate {
+ pub name: String,
+ pub src: FileName,
+ pub attrs: Attributes,
+ pub primitives: Vec<(DefId, PrimitiveType, Attributes)>,
+ pub keywords: Vec<(DefId, String, Attributes)>,
+}
+
+/// Anything with a source location and set of attributes and, optionally, a
+/// name. That is, anything that can be documented. This doesn't correspond
+/// directly to the AST's concept of an item; it's a strict superset.
+#[derive(Clone)]
+pub struct Item {
+ /// Stringified span
+ pub source: Span,
+ /// Not everything has a name. E.g., impls
+ pub name: Option<String>,
+ pub attrs: Attributes,
+ pub inner: ItemEnum,
+ pub visibility: Visibility,
+ pub def_id: DefId,
+ pub stability: Option<Stability>,
+ pub deprecation: Option<Deprecation>,
+}
+
+impl fmt::Debug for Item {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let fake = MAX_DEF_ID.with(|m| m.borrow().get(&self.def_id.krate)
+ .map(|id| self.def_id >= *id).unwrap_or(false));
+ let def_id: &dyn fmt::Debug = if fake { &"**FAKE**" } else { &self.def_id };
+
+ fmt.debug_struct("Item")
+ .field("source", &self.source)
+ .field("name", &self.name)
+ .field("attrs", &self.attrs)
+ .field("inner", &self.inner)
+ .field("visibility", &self.visibility)
+ .field("def_id", def_id)
+ .field("stability", &self.stability)
+ .field("deprecation", &self.deprecation)
+ .finish()
+ }
+}
+
+impl Item {
+ /// Finds the `doc` attribute as a NameValue and returns the corresponding
+ /// value found.
+ pub fn doc_value(&self) -> Option<&str> {
+ self.attrs.doc_value()
+ }
+
+ /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined
+ /// with newlines.
+ pub fn collapsed_doc_value(&self) -> Option<String> {
+ self.attrs.collapsed_doc_value()
+ }
+
+ pub fn links(&self) -> Vec<(String, String)> {
+ self.attrs.links(&self.def_id.krate)
+ }
+
+ pub fn is_crate(&self) -> bool {
+ match self.inner {
+ StrippedItem(box ModuleItem(Module { is_crate: true, ..})) |
+ ModuleItem(Module { is_crate: true, ..}) => true,
+ _ => false,
+ }
+ }
+ pub fn is_mod(&self) -> bool {
+ self.type_() == ItemType::Module
+ }
+ pub fn is_trait(&self) -> bool {
+ self.type_() == ItemType::Trait
+ }
+ pub fn is_struct(&self) -> bool {
+ self.type_() == ItemType::Struct
+ }
+ pub fn is_enum(&self) -> bool {
+ self.type_() == ItemType::Enum
+ }
+ pub fn is_variant(&self) -> bool {
+ self.type_() == ItemType::Variant
+ }
+ pub fn is_associated_type(&self) -> bool {
+ self.type_() == ItemType::AssocType
+ }
+ pub fn is_associated_const(&self) -> bool {
+ self.type_() == ItemType::AssocConst
+ }
+ pub fn is_method(&self) -> bool {
+ self.type_() == ItemType::Method
+ }
+ pub fn is_ty_method(&self) -> bool {
+ self.type_() == ItemType::TyMethod
+ }
+ pub fn is_typedef(&self) -> bool {
+ self.type_() == ItemType::Typedef
+ }
+ pub fn is_primitive(&self) -> bool {
+ self.type_() == ItemType::Primitive
+ }
+ pub fn is_union(&self) -> bool {
+ self.type_() == ItemType::Union
+ }
+ pub fn is_import(&self) -> bool {
+ self.type_() == ItemType::Import
+ }
+ pub fn is_extern_crate(&self) -> bool {
+ self.type_() == ItemType::ExternCrate
+ }
+ pub fn is_keyword(&self) -> bool {
+ self.type_() == ItemType::Keyword
+ }
+ pub fn is_stripped(&self) -> bool {
+ match self.inner { StrippedItem(..) => true, _ => false }
+ }
+ pub fn has_stripped_fields(&self) -> Option<bool> {
+ match self.inner {
+ StructItem(ref _struct) => Some(_struct.fields_stripped),
+ UnionItem(ref union) => Some(union.fields_stripped),
+ VariantItem(Variant { kind: VariantKind::Struct(ref vstruct)} ) => {
+ Some(vstruct.fields_stripped)
+ },
+ _ => None,
+ }
+ }
+
+ pub fn stability_class(&self) -> Option<String> {
+ self.stability.as_ref().and_then(|ref s| {
+ let mut classes = Vec::with_capacity(2);
+
+ if s.level == stability::Unstable {
+ classes.push("unstable");
+ }
+
+ if s.deprecation.is_some() {
+ classes.push("deprecated");
+ }
+
+ if classes.len() != 0 {
+ Some(classes.join(" "))
+ } else {
+ None
+ }
+ })
+ }
+
+ pub fn stable_since(&self) -> Option<&str> {
+ self.stability.as_ref().map(|s| &s.since[..])
+ }
+
+ pub fn is_non_exhaustive(&self) -> bool {
+ self.attrs.other_attrs.iter()
+ .any(|a| a.check_name(sym::non_exhaustive))
+ }
+
+ /// Returns a documentation-level item type from the item.
+ pub fn type_(&self) -> ItemType {
+ ItemType::from(self)
+ }
+
+ /// Returns the info in the item's `#[deprecated]` or `#[rustc_deprecated]` attributes.
+ ///
+ /// If the item is not deprecated, returns `None`.
+ pub fn deprecation(&self) -> Option<&Deprecation> {
+ self.deprecation
+ .as_ref()
+ .or_else(|| self.stability.as_ref().and_then(|s| s.deprecation.as_ref()))
+ }
+ pub fn is_default(&self) -> bool {
+ match self.inner {
+ ItemEnum::MethodItem(ref meth) => {
+ if let Some(defaultness) = meth.defaultness {
+ defaultness.has_value() && !defaultness.is_final()
+ } else {
+ false
+ }
+ }
+ _ => false,
+ }
+ }
+}
+
+#[derive(Clone, Debug)]
+pub enum ItemEnum {
+ ExternCrateItem(String, Option<String>),
+ ImportItem(Import),
+ StructItem(Struct),
+ UnionItem(Union),
+ EnumItem(Enum),
+ FunctionItem(Function),
+ ModuleItem(Module),
+ TypedefItem(Typedef, bool /* is associated type */),
+ OpaqueTyItem(OpaqueTy, bool /* is associated type */),
+ StaticItem(Static),
+ ConstantItem(Constant),
+ TraitItem(Trait),
+ TraitAliasItem(TraitAlias),
+ ImplItem(Impl),
+ /// A method signature only. Used for required methods in traits (ie,
+ /// non-default-methods).
+ TyMethodItem(TyMethod),
+ /// A method with a body.
+ MethodItem(Method),
+ StructFieldItem(Type),
+ VariantItem(Variant),
+ /// `fn`s from an extern block
+ ForeignFunctionItem(Function),
+ /// `static`s from an extern block
+ ForeignStaticItem(Static),
+ /// `type`s from an extern block
+ ForeignTypeItem,
+ MacroItem(Macro),
+ ProcMacroItem(ProcMacro),
+ PrimitiveItem(PrimitiveType),
+ AssocConstItem(Type, Option<String>),
+ AssocTypeItem(Vec<GenericBound>, Option<Type>),
+ /// An item that has been stripped by a rustdoc pass
+ StrippedItem(Box<ItemEnum>),
+ KeywordItem(String),
+}
+
+impl ItemEnum {
+ pub fn is_associated(&self) -> bool {
+ match *self {
+ ItemEnum::TypedefItem(_, _) |
+ ItemEnum::AssocTypeItem(_, _) => true,
+ _ => false,
+ }
+ }
+}
+
+#[derive(Clone, Debug)]
+pub struct Module {
+ pub items: Vec<Item>,
+ pub is_crate: bool,
+}
+
+pub struct ListAttributesIter<'a> {
+ attrs: slice::Iter<'a, ast::Attribute>,
+ current_list: vec::IntoIter<ast::NestedMetaItem>,
+ name: Symbol,
+}
+
+impl<'a> Iterator for ListAttributesIter<'a> {
+ type Item = ast::NestedMetaItem;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if let Some(nested) = self.current_list.next() {
+ return Some(nested);
+ }
+
+ for attr in &mut self.attrs {
+ if let Some(list) = attr.meta_item_list() {
+ if attr.check_name(self.name) {
+ self.current_list = list.into_iter();
+ if let Some(nested) = self.current_list.next() {
+ return Some(nested);
+ }
+ }
+ }
+ }
+
+ None
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let lower = self.current_list.len();
+ (lower, None)
+ }
+}
+
+pub trait AttributesExt {
+ /// Finds an attribute as List and returns the list of attributes nested inside.
+ fn lists(&self, name: Symbol) -> ListAttributesIter<'_>;
+}
+
+impl AttributesExt for [ast::Attribute] {
+ fn lists(&self, name: Symbol) -> ListAttributesIter<'_> {
+ ListAttributesIter {
+ attrs: self.iter(),
+ current_list: Vec::new().into_iter(),
+ name,
+ }
+ }
+}
+
+pub trait NestedAttributesExt {
+ /// Returns `true` if the attribute list contains a specific `Word`
+ fn has_word(self, word: Symbol) -> bool;
+}
+
+impl<I: IntoIterator<Item=ast::NestedMetaItem>> NestedAttributesExt for I {
+ fn has_word(self, word: Symbol) -> bool {
+ self.into_iter().any(|attr| attr.is_word() && attr.check_name(word))
+ }
+}
+
+/// A portion of documentation, extracted from a `#[doc]` attribute.
+///
+/// Each variant contains the line number within the complete doc-comment where the fragment
+/// starts, as well as the Span where the corresponding doc comment or attribute is located.
+///
+/// Included files are kept separate from inline doc comments so that proper line-number
+/// information can be given when a doctest fails. Sugared doc comments and "raw" doc comments are
+/// kept separate because of issue #42760.
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub enum DocFragment {
+ /// A doc fragment created from a `///` or `//!` doc comment.
+ SugaredDoc(usize, syntax_pos::Span, String),
+ /// A doc fragment created from a "raw" `#[doc=""]` attribute.
+ RawDoc(usize, syntax_pos::Span, String),
+ /// A doc fragment created from a `#[doc(include="filename")]` attribute. Contains both the
+ /// given filename and the file contents.
+ Include(usize, syntax_pos::Span, String, String),
+}
+
+impl DocFragment {
+ pub fn as_str(&self) -> &str {
+ match *self {
+ DocFragment::SugaredDoc(_, _, ref s) => &s[..],
+ DocFragment::RawDoc(_, _, ref s) => &s[..],
+ DocFragment::Include(_, _, _, ref s) => &s[..],
+ }
+ }
+
+ pub fn span(&self) -> syntax_pos::Span {
+ match *self {
+ DocFragment::SugaredDoc(_, span, _) |
+ DocFragment::RawDoc(_, span, _) |
+ DocFragment::Include(_, span, _, _) => span,
+ }
+ }
+}
+
+impl<'a> FromIterator<&'a DocFragment> for String {
+ fn from_iter<T>(iter: T) -> Self
+ where
+ T: IntoIterator<Item = &'a DocFragment>
+ {
+ iter.into_iter().fold(String::new(), |mut acc, frag| {
+ if !acc.is_empty() {
+ acc.push('\n');
+ }
+ match *frag {
+ DocFragment::SugaredDoc(_, _, ref docs)
+ | DocFragment::RawDoc(_, _, ref docs)
+ | DocFragment::Include(_, _, _, ref docs) =>
+ acc.push_str(docs),
+ }
+
+ acc
+ })
+ }
+}
+
+#[derive(Clone, Debug, Default)]
+pub struct Attributes {
+ pub doc_strings: Vec<DocFragment>,
+ pub other_attrs: Vec<ast::Attribute>,
+ pub cfg: Option<Arc<Cfg>>,
+ pub span: Option<syntax_pos::Span>,
+ /// map from Rust paths to resolved defs and potential URL fragments
+ pub links: Vec<(String, Option<DefId>, Option<String>)>,
+ pub inner_docs: bool,
+}
+
+impl Attributes {
+ /// Extracts the content from an attribute `#[doc(cfg(content))]`.
+ pub fn extract_cfg(mi: &ast::MetaItem) -> Option<&ast::MetaItem> {
+ use syntax::ast::NestedMetaItem::MetaItem;
+
+ if let ast::MetaItemKind::List(ref nmis) = mi.kind {
+ if nmis.len() == 1 {
+ if let MetaItem(ref cfg_mi) = nmis[0] {
+ if cfg_mi.check_name(sym::cfg) {
+ if let ast::MetaItemKind::List(ref cfg_nmis) = cfg_mi.kind {
+ if cfg_nmis.len() == 1 {
+ if let MetaItem(ref content_mi) = cfg_nmis[0] {
+ return Some(content_mi);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ None
+ }
+
+ /// Reads a `MetaItem` from within an attribute, looks for whether it is a
+ /// `#[doc(include="file")]`, and returns the filename and contents of the file as loaded from
+ /// its expansion.
+ pub fn extract_include(mi: &ast::MetaItem) -> Option<(String, String)> {
+ mi.meta_item_list().and_then(|list| {
+ for meta in list {
+ if meta.check_name(sym::include) {
+ // the actual compiled `#[doc(include="filename")]` gets expanded to
+ // `#[doc(include(file="filename", contents="file contents")]` so we need to
+ // look for that instead
+ return meta.meta_item_list().and_then(|list| {
+ let mut filename: Option<String> = None;
+ let mut contents: Option<String> = None;
+
+ for it in list {
+ if it.check_name(sym::file) {
+ if let Some(name) = it.value_str() {
+ filename = Some(name.to_string());
+ }
+ } else if it.check_name(sym::contents) {
+ if let Some(docs) = it.value_str() {
+ contents = Some(docs.to_string());
+ }
+ }
+ }
+
+ if let (Some(filename), Some(contents)) = (filename, contents) {
+ Some((filename, contents))
+ } else {
+ None
+ }
+ });
+ }
+ }
+
+ None
+ })
+ }
+
+ pub fn has_doc_flag(&self, flag: Symbol) -> bool {
+ for attr in &self.other_attrs {
+ if !attr.check_name(sym::doc) { continue; }
+
+ if let Some(items) = attr.meta_item_list() {
+ if items.iter().filter_map(|i| i.meta_item()).any(|it| it.check_name(flag)) {
+ return true;
+ }
+ }
+ }
+
+ false
+ }
+
+ pub fn from_ast(diagnostic: &::errors::Handler, attrs: &[ast::Attribute]) -> Attributes {
+ let mut doc_strings = vec![];
+ let mut sp = None;
+ let mut cfg = Cfg::True;
+ let mut doc_line = 0;
+
+ /// If `attr` is a doc comment, strips the leading and (if present)
+ /// trailing comments symbols, e.g. `///`, `/**`, and `*/`. Otherwise,
+ /// returns `attr` unchanged.
+ pub fn with_doc_comment_markers_stripped<T>(
+ attr: &Attribute,
+ f: impl FnOnce(&Attribute) -> T,
+ ) -> T {
+ match attr.kind {
+ AttrKind::Normal(_) => {
+ f(attr)
+ }
+ AttrKind::DocComment(comment) => {
+ let comment =
+ Symbol::intern(&comments::strip_doc_comment_decoration(&comment.as_str()));
+ f(&Attribute {
+ kind: AttrKind::DocComment(comment),
+ id: attr.id,
+ style: attr.style,
+ span: attr.span,
+ })
+ }
+ }
+ }
+
+ let other_attrs = attrs.iter().filter_map(|attr| {
+ with_doc_comment_markers_stripped(attr, |attr| {
+ if attr.check_name(sym::doc) {
+ if let Some(mi) = attr.meta() {
+ if let Some(value) = mi.value_str() {
+ // Extracted #[doc = "..."]
+ let value = value.to_string();
+ let line = doc_line;
+ doc_line += value.lines().count();
+
+ if attr.is_doc_comment() {
+ doc_strings.push(DocFragment::SugaredDoc(line, attr.span, value));
+ } else {
+ doc_strings.push(DocFragment::RawDoc(line, attr.span, value));
+ }
+
+ if sp.is_none() {
+ sp = Some(attr.span);
+ }
+ return None;
+ } else if let Some(cfg_mi) = Attributes::extract_cfg(&mi) {
+ // Extracted #[doc(cfg(...))]
+ match Cfg::parse(cfg_mi) {
+ Ok(new_cfg) => cfg &= new_cfg,
+ Err(e) => diagnostic.span_err(e.span, e.msg),
+ }
+ return None;
+ } else if let Some((filename, contents)) = Attributes::extract_include(&mi)
+ {
+ let line = doc_line;
+ doc_line += contents.lines().count();
+ doc_strings.push(DocFragment::Include(line,
+ attr.span,
+ filename,
+ contents));
+ }
+ }
+ }
+ Some(attr.clone())
+ })
+ }).collect();
+
+ // treat #[target_feature(enable = "feat")] attributes as if they were
+ // #[doc(cfg(target_feature = "feat"))] attributes as well
+ for attr in attrs.lists(sym::target_feature) {
+ if attr.check_name(sym::enable) {
+ if let Some(feat) = attr.value_str() {
+ let meta = attr::mk_name_value_item_str(
+ Ident::with_dummy_span(sym::target_feature), feat, DUMMY_SP
+ );
+ if let Ok(feat_cfg) = Cfg::parse(&meta) {
+ cfg &= feat_cfg;
+ }
+ }
+ }
+ }
+
+ let inner_docs = attrs.iter()
+ .filter(|a| a.check_name(sym::doc))
+ .next()
+ .map_or(true, |a| a.style == AttrStyle::Inner);
+
+ Attributes {
+ doc_strings,
+ other_attrs,
+ cfg: if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) },
+ span: sp,
+ links: vec![],
+ inner_docs,
+ }
+ }
+
+ /// Finds the `doc` attribute as a NameValue and returns the corresponding
+ /// value found.
+ pub fn doc_value(&self) -> Option<&str> {
+ self.doc_strings.first().map(|s| s.as_str())
+ }
+
+ /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined
+ /// with newlines.
+ pub fn collapsed_doc_value(&self) -> Option<String> {
+ if !self.doc_strings.is_empty() {
+ Some(self.doc_strings.iter().collect())
+ } else {
+ None
+ }
+ }
+
+ /// Gets links as a vector
+ ///
+ /// Cache must be populated before call
+ pub fn links(&self, krate: &CrateNum) -> Vec<(String, String)> {
+ use crate::html::format::href;
+
+ self.links.iter().filter_map(|&(ref s, did, ref fragment)| {
+ match did {
+ Some(did) => {
+ if let Some((mut href, ..)) = href(did) {
+ if let Some(ref fragment) = *fragment {
+ href.push_str("#");
+ href.push_str(fragment);
+ }
+ Some((s.clone(), href))
+ } else {
+ None
+ }
+ }
+ None => {
+ if let Some(ref fragment) = *fragment {
+ let cache = cache();
+ let url = match cache.extern_locations.get(krate) {
+ Some(&(_, ref src, ExternalLocation::Local)) =>
+ src.to_str().expect("invalid file path"),
+ Some(&(_, _, ExternalLocation::Remote(ref s))) => s,
+ Some(&(_, _, ExternalLocation::Unknown)) | None =>
+ "https://doc.rust-lang.org/nightly",
+ };
+ // This is a primitive so the url is done "by hand".
+ let tail = fragment.find('#').unwrap_or_else(|| fragment.len());
+ Some((s.clone(),
+ format!("{}{}std/primitive.{}.html{}",
+ url,
+ if !url.ends_with('/') { "/" } else { "" },
+ &fragment[..tail],
+ &fragment[tail..])))
+ } else {
+ panic!("This isn't a primitive?!");
+ }
+ }
+ }
+ }).collect()
+ }
+}
+
+impl PartialEq for Attributes {
+ fn eq(&self, rhs: &Self) -> bool {
+ self.doc_strings == rhs.doc_strings &&
+ self.cfg == rhs.cfg &&
+ self.span == rhs.span &&
+ self.links == rhs.links &&
+ self.other_attrs.iter().map(|attr| attr.id).eq(rhs.other_attrs.iter().map(|attr| attr.id))
+ }
+}
+
+impl Eq for Attributes {}
+
+impl Hash for Attributes {
+ fn hash<H: Hasher>(&self, hasher: &mut H) {
+ self.doc_strings.hash(hasher);
+ self.cfg.hash(hasher);
+ self.span.hash(hasher);
+ self.links.hash(hasher);
+ for attr in &self.other_attrs {
+ attr.id.hash(hasher);
+ }
+ }
+}
+
+impl AttributesExt for Attributes {
+ fn lists(&self, name: Symbol) -> ListAttributesIter<'_> {
+ self.other_attrs.lists(name)
+ }
+}
+
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub enum GenericBound {
+ TraitBound(PolyTrait, hir::TraitBoundModifier),
+ Outlives(Lifetime),
+}
+
+impl GenericBound {
+ pub fn maybe_sized(cx: &DocContext<'_>) -> GenericBound {
+ let did = cx.tcx.require_lang_item(lang_items::SizedTraitLangItem, None);
+ let empty = cx.tcx.intern_substs(&[]);
+ let path = external_path(cx, cx.tcx.item_name(did),
+ Some(did), false, vec![], empty);
+ inline::record_extern_fqn(cx, did, TypeKind::Trait);
+ GenericBound::TraitBound(PolyTrait {
+ trait_: ResolvedPath {
+ path,
+ param_names: None,
+ did,
+ is_generic: false,
+ },
+ generic_params: Vec::new(),
+ }, hir::TraitBoundModifier::Maybe)
+ }
+
+ pub fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool {
+ use rustc::hir::TraitBoundModifier as TBM;
+ if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self {
+ if trait_.def_id() == cx.tcx.lang_items().sized_trait() {
+ return true;
+ }
+ }
+ false
+ }
+
+ pub fn get_poly_trait(&self) -> Option<PolyTrait> {
+ if let GenericBound::TraitBound(ref p, _) = *self {
+ return Some(p.clone())
+ }
+ None
+ }
+
+ pub fn get_trait_type(&self) -> Option<Type> {
+ if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self {
+ Some(trait_.clone())
+ } else {
+ None
+ }
+ }
+}
+
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub struct Lifetime(pub String);
+
+impl Lifetime {
+ pub fn get_ref<'a>(&'a self) -> &'a str {
+ let Lifetime(ref s) = *self;
+ let s: &'a str = s;
+ s
+ }
+
+ pub fn statik() -> Lifetime {
+ Lifetime("'static".to_string())
+ }
+}
+
+#[derive(Clone, Debug)]
+pub enum WherePredicate {
+ BoundPredicate { ty: Type, bounds: Vec<GenericBound> },
+ RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
+ EqPredicate { lhs: Type, rhs: Type },
+}
+
+impl WherePredicate {
+ pub fn get_bounds(&self) -> Option<&[GenericBound]> {
+ match *self {
+ WherePredicate::BoundPredicate { ref bounds, .. } => Some(bounds),
+ WherePredicate::RegionPredicate { ref bounds, .. } => Some(bounds),
+ _ => None,
+ }
+ }
+}
+
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub enum GenericParamDefKind {
+ Lifetime,
+ Type {
+ did: DefId,
+ bounds: Vec<GenericBound>,
+ default: Option<Type>,
+ synthetic: Option<hir::SyntheticTyParamKind>,
+ },
+ Const {
+ did: DefId,
+ ty: Type,
+ },
+}
+
+impl GenericParamDefKind {
+ pub fn is_type(&self) -> bool {
+ match *self {
+ GenericParamDefKind::Type { .. } => true,
+ _ => false,
+ }
+ }
+
+ // FIXME(eddyb) this either returns the default of a type parameter, or the
+ // type of a `const` parameter. It seems that the intention is to *visit*
+ // any embedded types, but `get_type` seems to be the wrong name for that.
+ pub fn get_type(&self) -> Option<Type> {
+ match self {
+ GenericParamDefKind::Type { default, .. } => default.clone(),
+ GenericParamDefKind::Const { ty, .. } => Some(ty.clone()),
+ GenericParamDefKind::Lifetime => None,
+ }
+ }
+}
+
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub struct GenericParamDef {
+ pub name: String,
+ pub kind: GenericParamDefKind,
+}
+
+impl GenericParamDef {
+ pub fn is_synthetic_type_param(&self) -> bool {
+ match self.kind {
+ GenericParamDefKind::Lifetime |
+ GenericParamDefKind::Const { .. } => false,
+ GenericParamDefKind::Type { ref synthetic, .. } => synthetic.is_some(),
+ }
+ }
+
+ pub fn is_type(&self) -> bool {
+ self.kind.is_type()
+ }
+
+ pub fn get_type(&self) -> Option<Type> {
+ self.kind.get_type()
+ }
+
+ pub fn get_bounds(&self) -> Option<&[GenericBound]> {
+ match self.kind {
+ GenericParamDefKind::Type { ref bounds, .. } => Some(bounds),
+ _ => None,
+ }
+ }
+}
+
+// maybe use a Generic enum and use Vec<Generic>?
+#[derive(Clone, Debug, Default)]
+pub struct Generics {
+ pub params: Vec<GenericParamDef>,
+ pub where_predicates: Vec<WherePredicate>,
+}
+
+#[derive(Clone, Debug)]
+pub struct Method {
+ pub generics: Generics,
+ pub decl: FnDecl,
+ pub header: hir::FnHeader,
+ pub defaultness: Option<hir::Defaultness>,
+ pub all_types: Vec<Type>,
+ pub ret_types: Vec<Type>,
+}
+
+#[derive(Clone, Debug)]
+pub struct TyMethod {
+ pub header: hir::FnHeader,
+ pub decl: FnDecl,
+ pub generics: Generics,
+ pub all_types: Vec<Type>,
+ pub ret_types: Vec<Type>,
+}
+
+#[derive(Clone, Debug)]
+pub struct Function {
+ pub decl: FnDecl,
+ pub generics: Generics,
+ pub header: hir::FnHeader,
+ pub all_types: Vec<Type>,
+ pub ret_types: Vec<Type>,
+}
+
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub struct FnDecl {
+ pub inputs: Arguments,
+ pub output: FunctionRetTy,
+ pub c_variadic: bool,
+ pub attrs: Attributes,
+}
+
+impl FnDecl {
+ pub fn self_type(&self) -> Option<SelfTy> {
+ self.inputs.values.get(0).and_then(|v| v.to_self())
+ }
+
+ /// Returns the sugared return type for an async function.
+ ///
+ /// For example, if the return type is `impl std::future::Future<Output = i32>`, this function
+ /// will return `i32`.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if the return type does not match the expected sugaring for async
+ /// functions.
+ pub fn sugared_async_return_type(&self) -> FunctionRetTy {
+ match &self.output {
+ FunctionRetTy::Return(Type::ImplTrait(bounds)) => {
+ match &bounds[0] {
+ GenericBound::TraitBound(PolyTrait { trait_, .. }, ..) => {
+ let bindings = trait_.bindings().unwrap();
+ FunctionRetTy::Return(bindings[0].ty().clone())
+ }
+ _ => panic!("unexpected desugaring of async function"),
+ }
+ }
+ _ => panic!("unexpected desugaring of async function"),
+ }
+ }
+}
+
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub struct Arguments {
+ pub values: Vec<Argument>,
+}
+
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub struct Argument {
+ pub type_: Type,
+ pub name: String,
+}
+
+#[derive(Clone, PartialEq, Debug)]
+pub enum SelfTy {
+ SelfValue,
+ SelfBorrowed(Option<Lifetime>, Mutability),
+ SelfExplicit(Type),
+}
+
+impl Argument {
+ pub fn to_self(&self) -> Option<SelfTy> {
+ if self.name != "self" {
+ return None;
+ }
+ if self.type_.is_self_type() {
+ return Some(SelfValue);
+ }
+ match self.type_ {
+ BorrowedRef{ref lifetime, mutability, ref type_} if type_.is_self_type() => {
+ Some(SelfBorrowed(lifetime.clone(), mutability))
+ }
+ _ => Some(SelfExplicit(self.type_.clone()))
+ }
+ }
+}
+
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub enum FunctionRetTy {
+ Return(Type),
+ DefaultReturn,
+}
+
+impl GetDefId for FunctionRetTy {
+ fn def_id(&self) -> Option<DefId> {
+ match *self {
+ Return(ref ty) => ty.def_id(),
+ DefaultReturn => None,
+ }
+ }
+}
+
+#[derive(Clone, Debug)]
+pub struct Trait {
+ pub auto: bool,
+ pub unsafety: hir::Unsafety,
+ pub items: Vec<Item>,
+ pub generics: Generics,
+ pub bounds: Vec<GenericBound>,
+ pub is_spotlight: bool,
+ pub is_auto: bool,
+}
+
+#[derive(Clone, Debug)]
+pub struct TraitAlias {
+ pub generics: Generics,
+ pub bounds: Vec<GenericBound>,
+}
+
+/// A trait reference, which may have higher ranked lifetimes.
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub struct PolyTrait {
+ pub trait_: Type,
+ pub generic_params: Vec<GenericParamDef>,
+}
+
+/// A representation of a type suitable for hyperlinking purposes. Ideally, one can get the original
+/// type out of the AST/`TyCtxt` given one of these, if more information is needed. Most
+/// importantly, it does not preserve mutability or boxes.
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub enum Type {
+ /// Structs/enums/traits (most that would be an `hir::TyKind::Path`).
+ ResolvedPath {
+ path: Path,
+ param_names: Option<Vec<GenericBound>>,
+ did: DefId,
+ /// `true` if is a `T::Name` path for associated types.
+ is_generic: bool,
+ },
+ /// For parameterized types, so the consumer of the JSON don't go
+ /// looking for types which don't exist anywhere.
+ Generic(String),
+ /// Primitives are the fixed-size numeric types (plus int/usize/float), char,
+ /// arrays, slices, and tuples.
+ Primitive(PrimitiveType),
+ /// `extern "ABI" fn`
+ BareFunction(Box<BareFunctionDecl>),
+ Tuple(Vec<Type>),
+ Slice(Box<Type>),
+ Array(Box<Type>, String),
+ Never,
+ RawPointer(Mutability, Box<Type>),
+ BorrowedRef {
+ lifetime: Option<Lifetime>,
+ mutability: Mutability,
+ type_: Box<Type>,
+ },
+
+ // `<Type as Trait>::Name`
+ QPath {
+ name: String,
+ self_type: Box<Type>,
+ trait_: Box<Type>
+ },
+
+ // `_`
+ Infer,
+
+ // `impl TraitA + TraitB + ...`
+ ImplTrait(Vec<GenericBound>),
+}
+
+#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)]
+pub enum PrimitiveType {
+ Isize, I8, I16, I32, I64, I128,
+ Usize, U8, U16, U32, U64, U128,
+ F32, F64,
+ Char,
+ Bool,
+ Str,
+ Slice,
+ Array,
+ Tuple,
+ Unit,
+ RawPointer,
+ Reference,
+ Fn,
+ Never,
+}
+
+#[derive(Clone, Copy, Debug)]
+pub enum TypeKind {
+ Enum,
+ Function,
+ Module,
+ Const,
+ Static,
+ Struct,
+ Union,
+ Trait,
+ Typedef,
+ Foreign,
+ Macro,
+ Attr,
+ Derive,
+ TraitAlias,
+}
+
+pub trait GetDefId {
+ fn def_id(&self) -> Option<DefId>;
+}
+
+impl<T: GetDefId> GetDefId for Option<T> {
+ fn def_id(&self) -> Option<DefId> {
+ self.as_ref().and_then(|d| d.def_id())
+ }
+}
+
+impl Type {
+ pub fn primitive_type(&self) -> Option<PrimitiveType> {
+ match *self {
+ Primitive(p) | BorrowedRef { type_: box Primitive(p), ..} => Some(p),
+ Slice(..) | BorrowedRef { type_: box Slice(..), .. } => Some(PrimitiveType::Slice),
+ Array(..) | BorrowedRef { type_: box Array(..), .. } => Some(PrimitiveType::Array),
+ Tuple(ref tys) => if tys.is_empty() {
+ Some(PrimitiveType::Unit)
+ } else {
+ Some(PrimitiveType::Tuple)
+ },
+ RawPointer(..) => Some(PrimitiveType::RawPointer),
+ BorrowedRef { type_: box Generic(..), .. } => Some(PrimitiveType::Reference),
+ BareFunction(..) => Some(PrimitiveType::Fn),
+ Never => Some(PrimitiveType::Never),
+ _ => None,
+ }
+ }
+
+ pub fn is_generic(&self) -> bool {
+ match *self {
+ ResolvedPath { is_generic, .. } => is_generic,
+ _ => false,
+ }
+ }
+
+ pub fn is_self_type(&self) -> bool {
+ match *self {
+ Generic(ref name) => name == "Self",
+ _ => false
+ }
+ }
+
+ pub fn generics(&self) -> Option<Vec<Type>> {
+ match *self {
+ ResolvedPath { ref path, .. } => {
+ path.segments.last().and_then(|seg| {
+ if let GenericArgs::AngleBracketed { ref args, .. } = seg.args {
+ Some(args.iter().filter_map(|arg| match arg {
+ GenericArg::Type(ty) => Some(ty.clone()),
+ _ => None,
+ }).collect())
+ } else {
+ None
+ }
+ })
+ }
+ _ => None,
+ }
+ }
+
+ pub fn bindings(&self) -> Option<&[TypeBinding]> {
+ match *self {
+ ResolvedPath { ref path, .. } => {
+ path.segments.last().and_then(|seg| {
+ if let GenericArgs::AngleBracketed { ref bindings, .. } = seg.args {
+ Some(&**bindings)
+ } else {
+ None
+ }
+ })
+ }
+ _ => None
+ }
+ }
+
+ pub fn is_full_generic(&self) -> bool {
+ match *self {
+ Type::Generic(_) => true,
+ _ => false,
+ }
+ }
+
+ pub fn projection(&self) -> Option<(&Type, DefId, &str)> {
+ let (self_, trait_, name) = match self {
+ QPath { ref self_type, ref trait_, ref name } => {
+ (self_type, trait_, name)
+ }
+ _ => return None,
+ };
+ let trait_did = match **trait_ {
+ ResolvedPath { did, .. } => did,
+ _ => return None,
+ };
+ Some((&self_, trait_did, name))
+ }
+
+}
+
+impl GetDefId for Type {
+ fn def_id(&self) -> Option<DefId> {
+ match *self {
+ ResolvedPath { did, .. } => Some(did),
+ Primitive(p) => crate::html::render::cache().primitive_locations.get(&p).cloned(),
+ BorrowedRef { type_: box Generic(..), .. } =>
+ Primitive(PrimitiveType::Reference).def_id(),
+ BorrowedRef { ref type_, .. } => type_.def_id(),
+ Tuple(ref tys) => if tys.is_empty() {
+ Primitive(PrimitiveType::Unit).def_id()
+ } else {
+ Primitive(PrimitiveType::Tuple).def_id()
+ },
+ BareFunction(..) => Primitive(PrimitiveType::Fn).def_id(),
+ Never => Primitive(PrimitiveType::Never).def_id(),
+ Slice(..) => Primitive(PrimitiveType::Slice).def_id(),
+ Array(..) => Primitive(PrimitiveType::Array).def_id(),
+ RawPointer(..) => Primitive(PrimitiveType::RawPointer).def_id(),
+ QPath { ref self_type, .. } => self_type.def_id(),
+ _ => None,
+ }
+ }
+}
+
+impl PrimitiveType {
+ pub fn from_str(s: &str) -> Option<PrimitiveType> {
+ match s {
+ "isize" => Some(PrimitiveType::Isize),
+ "i8" => Some(PrimitiveType::I8),
+ "i16" => Some(PrimitiveType::I16),
+ "i32" => Some(PrimitiveType::I32),
+ "i64" => Some(PrimitiveType::I64),
+ "i128" => Some(PrimitiveType::I128),
+ "usize" => Some(PrimitiveType::Usize),
+ "u8" => Some(PrimitiveType::U8),
+ "u16" => Some(PrimitiveType::U16),
+ "u32" => Some(PrimitiveType::U32),
+ "u64" => Some(PrimitiveType::U64),
+ "u128" => Some(PrimitiveType::U128),
+ "bool" => Some(PrimitiveType::Bool),
+ "char" => Some(PrimitiveType::Char),
+ "str" => Some(PrimitiveType::Str),
+ "f32" => Some(PrimitiveType::F32),
+ "f64" => Some(PrimitiveType::F64),
+ "array" => Some(PrimitiveType::Array),
+ "slice" => Some(PrimitiveType::Slice),
+ "tuple" => Some(PrimitiveType::Tuple),
+ "unit" => Some(PrimitiveType::Unit),
+ "pointer" => Some(PrimitiveType::RawPointer),
+ "reference" => Some(PrimitiveType::Reference),
+ "fn" => Some(PrimitiveType::Fn),
+ "never" => Some(PrimitiveType::Never),
+ _ => None,
+ }
+ }
+
+ pub fn as_str(&self) -> &'static str {
+ use self::PrimitiveType::*;
+ match *self {
+ Isize => "isize",
+ I8 => "i8",
+ I16 => "i16",
+ I32 => "i32",
+ I64 => "i64",
+ I128 => "i128",
+ Usize => "usize",
+ U8 => "u8",
+ U16 => "u16",
+ U32 => "u32",
+ U64 => "u64",
+ U128 => "u128",
+ F32 => "f32",
+ F64 => "f64",
+ Str => "str",
+ Bool => "bool",
+ Char => "char",
+ Array => "array",
+ Slice => "slice",
+ Tuple => "tuple",
+ Unit => "unit",
+ RawPointer => "pointer",
+ Reference => "reference",
+ Fn => "fn",
+ Never => "never",
+ }
+ }
+
+ pub fn to_url_str(&self) -> &'static str {
+ self.as_str()
+ }
+}
+
+impl From<ast::IntTy> for PrimitiveType {
+ fn from(int_ty: ast::IntTy) -> PrimitiveType {
+ match int_ty {
+ ast::IntTy::Isize => PrimitiveType::Isize,
+ ast::IntTy::I8 => PrimitiveType::I8,
+ ast::IntTy::I16 => PrimitiveType::I16,
+ ast::IntTy::I32 => PrimitiveType::I32,
+ ast::IntTy::I64 => PrimitiveType::I64,
+ ast::IntTy::I128 => PrimitiveType::I128,
+ }
+ }
+}
+
+impl From<ast::UintTy> for PrimitiveType {
+ fn from(uint_ty: ast::UintTy) -> PrimitiveType {
+ match uint_ty {
+ ast::UintTy::Usize => PrimitiveType::Usize,
+ ast::UintTy::U8 => PrimitiveType::U8,
+ ast::UintTy::U16 => PrimitiveType::U16,
+ ast::UintTy::U32 => PrimitiveType::U32,
+ ast::UintTy::U64 => PrimitiveType::U64,
+ ast::UintTy::U128 => PrimitiveType::U128,
+ }
+ }
+}
+
+impl From<ast::FloatTy> for PrimitiveType {
+ fn from(float_ty: ast::FloatTy) -> PrimitiveType {
+ match float_ty {
+ ast::FloatTy::F32 => PrimitiveType::F32,
+ ast::FloatTy::F64 => PrimitiveType::F64,
+ }
+ }
+}
+
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub enum Visibility {
+ Public,
+ Inherited,
+ Crate,
+ Restricted(DefId, Path),
+}
+
+#[derive(Clone, Debug)]
+pub struct Struct {
+ pub struct_type: doctree::StructType,
+ pub generics: Generics,
+ pub fields: Vec<Item>,
+ pub fields_stripped: bool,
+}
+
+#[derive(Clone, Debug)]
+pub struct Union {
+ pub struct_type: doctree::StructType,
+ pub generics: Generics,
+ pub fields: Vec<Item>,
+ pub fields_stripped: bool,
+}
+
+/// This is a more limited form of the standard Struct, different in that
+/// it lacks the things most items have (name, id, parameterization). Found
+/// only as a variant in an enum.
+#[derive(Clone, Debug)]
+pub struct VariantStruct {
+ pub struct_type: doctree::StructType,
+ pub fields: Vec<Item>,
+ pub fields_stripped: bool,
+}
+
+#[derive(Clone, Debug)]
+pub struct Enum {
+ pub variants: IndexVec<VariantIdx, Item>,
+ pub generics: Generics,
+ pub variants_stripped: bool,
+}
+
+#[derive(Clone, Debug)]
+pub struct Variant {
+ pub kind: VariantKind,
+}
+
+#[derive(Clone, Debug)]
+pub enum VariantKind {
+ CLike,
+ Tuple(Vec<Type>),
+ Struct(VariantStruct),
+}
+
+#[derive(Clone, Debug)]
+pub struct Span {
+ pub filename: FileName,
+ pub loline: usize,
+ pub locol: usize,
+ pub hiline: usize,
+ pub hicol: usize,
+ pub original: syntax_pos::Span,
+}
+
+impl Span {
+ pub fn empty() -> Span {
+ Span {
+ filename: FileName::Anon(0),
+ loline: 0, locol: 0,
+ hiline: 0, hicol: 0,
+ original: syntax_pos::DUMMY_SP,
+ }
+ }
+
+ pub fn span(&self) -> syntax_pos::Span {
+ self.original
+ }
+}
+
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub struct Path {
+ pub global: bool,
+ pub res: Res,
+ pub segments: Vec<PathSegment>,
+}
+
+impl Path {
+ pub fn last_name(&self) -> &str {
+ self.segments.last().expect("segments were empty").name.as_str()
+ }
+}
+
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub enum GenericArg {
+ Lifetime(Lifetime),
+ Type(Type),
+ Const(Constant),
+}
+
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub enum GenericArgs {
+ AngleBracketed {
+ args: Vec<GenericArg>,
+ bindings: Vec<TypeBinding>,
+ },
+ Parenthesized {
+ inputs: Vec<Type>,
+ output: Option<Type>,
+ }
+}
+
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub struct PathSegment {
+ pub name: String,
+ pub args: GenericArgs,
+}
+
+#[derive(Clone, Debug)]
+pub struct Typedef {
+ pub type_: Type,
+ pub generics: Generics,
+}
+
+#[derive(Clone, Debug)]
+pub struct OpaqueTy {
+ pub bounds: Vec<GenericBound>,
+ pub generics: Generics,
+}
+
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub struct BareFunctionDecl {
+ pub unsafety: hir::Unsafety,
+ pub generic_params: Vec<GenericParamDef>,
+ pub decl: FnDecl,
+ pub abi: Abi,
+}
+
+#[derive(Clone, Debug)]
+pub struct Static {
+ pub type_: Type,
+ pub mutability: Mutability,
+ /// It's useful to have the value of a static documented, but I have no
+ /// desire to represent expressions (that'd basically be all of the AST,
+ /// which is huge!). So, have a string.
+ pub expr: String,
+}
+
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+pub struct Constant {
+ pub type_: Type,
+ pub expr: String,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Copy, Hash)]
+pub enum Mutability {
+ Mutable,
+ Immutable,
+}
+
+#[derive(Clone, PartialEq, Debug)]
+pub enum ImplPolarity {
+ Positive,
+ Negative,
+}
+
+#[derive(Clone, Debug)]
+pub struct Impl {
+ pub unsafety: hir::Unsafety,
+ pub generics: Generics,
+ pub provided_trait_methods: FxHashSet<String>,
+ pub trait_: Option<Type>,
+ pub for_: Type,
+ pub items: Vec<Item>,
+ pub polarity: Option<ImplPolarity>,
+ pub synthetic: bool,
+ pub blanket_impl: Option<Type>,
+}
+
+#[derive(Clone, Debug)]
+pub enum Import {
+ // use source as str;
+ Simple(String, ImportSource),
+ // use source::*;
+ Glob(ImportSource)
+}
+
+#[derive(Clone, Debug)]
+pub struct ImportSource {
+ pub path: Path,
+ pub did: Option<DefId>,
+}
+
+#[derive(Clone, Debug)]
+pub struct Macro {
+ pub source: String,
+ pub imported_from: Option<String>,
+}
+
+#[derive(Clone, Debug)]
+pub struct ProcMacro {
+ pub kind: MacroKind,
+ pub helpers: Vec<String>,
+}
+
+#[derive(Clone, Debug)]
+pub struct Stability {
+ pub level: stability::StabilityLevel,
+ pub feature: Option<String>,
+ pub since: String,
+ pub deprecation: Option<Deprecation>,
+ pub unstable_reason: Option<String>,
+ pub issue: Option<NonZeroU32>,
+}
+
+#[derive(Clone, Debug)]
+pub struct Deprecation {
+ pub since: Option<String>,
+ pub note: Option<String>,
+}
+
+/// An type binding on an associated type (e.g., `A = Bar` in `Foo<A = Bar>` or
+/// `A: Send + Sync` in `Foo<A: Send + Sync>`).
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub struct TypeBinding {
+ pub name: String,
+ pub kind: TypeBindingKind,
+}
+
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub enum TypeBindingKind {
+ Equality {
+ ty: Type,
+ },
+ Constraint {
+ bounds: Vec<GenericBound>,
+ },
+}
+
+impl TypeBinding {
+ pub fn ty(&self) -> &Type {
+ match self.kind {
+ TypeBindingKind::Equality { ref ty } => ty,
+ _ => panic!("expected equality type binding for parenthesized generic args"),
+ }
+ }
+}
diff --git a/src/libstd/build.rs b/src/libstd/build.rs
index 1f839f1..8db7bc1 100644
--- a/src/libstd/build.rs
+++ b/src/libstd/build.rs
@@ -54,7 +54,5 @@
}
println!("cargo:rustc-link-lib=c");
println!("cargo:rustc-link-lib=compiler_rt");
- } else if target.contains("hermit") {
- println!("cargo:rustc-link-lib=hermit");
}
}
diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs
index e5cf022..a109e38 100644
--- a/src/libstd/fs.rs
+++ b/src/libstd/fs.rs
@@ -2339,8 +2339,10 @@
let filename = &tmpdir.join("file_that_does_not_exist.txt");
let result = File::open(filename);
- #[cfg(unix)]
+ #[cfg(all(unix, not(target_os = "vxworks")))]
error!(result, "No such file or directory");
+ #[cfg(target_os = "vxworks")]
+ error!(result, "no such file or directory");
#[cfg(windows)]
error!(result, 2); // ERROR_FILE_NOT_FOUND
}
@@ -2352,8 +2354,10 @@
let result = fs::remove_file(filename);
- #[cfg(unix)]
+ #[cfg(all(unix, not(target_os = "vxworks")))]
error!(result, "No such file or directory");
+ #[cfg(target_os = "vxworks")]
+ error!(result, "no such file or directory");
#[cfg(windows)]
error!(result, 2); // ERROR_FILE_NOT_FOUND
}
@@ -2553,7 +2557,10 @@
check!(fs::set_permissions(filename, fs::Permissions::from_mode(0o1777)));
let metadata1 = check!(fs::metadata(filename));
+ #[cfg(all(unix, not(target_os = "vxworks")))]
assert_eq!(mask & metadata1.permissions().mode(), 0o1777);
+ #[cfg(target_os = "vxworks")]
+ assert_eq!(mask & metadata1.permissions().mode(), 0o0777);
}
#[test]
diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs
index 20c1c5c..a1a33ba 100644
--- a/src/libstd/io/mod.rs
+++ b/src/libstd/io/mod.rs
@@ -987,7 +987,6 @@
/// #![feature(io_slice_advance)]
///
/// use std::io::IoSliceMut;
- /// use std::mem;
/// use std::ops::Deref;
///
/// let mut buf1 = [1; 8];
@@ -1000,7 +999,7 @@
/// ][..];
///
/// // Mark 10 bytes as read.
- /// bufs = IoSliceMut::advance(mem::replace(&mut bufs, &mut []), 10);
+ /// bufs = IoSliceMut::advance(bufs, 10);
/// assert_eq!(bufs[0].deref(), [2; 14].as_ref());
/// assert_eq!(bufs[1].deref(), [3; 8].as_ref());
/// ```
@@ -1090,20 +1089,19 @@
/// #![feature(io_slice_advance)]
///
/// use std::io::IoSlice;
- /// use std::mem;
/// use std::ops::Deref;
///
- /// let mut buf1 = [1; 8];
- /// let mut buf2 = [2; 16];
- /// let mut buf3 = [3; 8];
+ /// let buf1 = [1; 8];
+ /// let buf2 = [2; 16];
+ /// let buf3 = [3; 8];
/// let mut bufs = &mut [
- /// IoSlice::new(&mut buf1),
- /// IoSlice::new(&mut buf2),
- /// IoSlice::new(&mut buf3),
+ /// IoSlice::new(&buf1),
+ /// IoSlice::new(&buf2),
+ /// IoSlice::new(&buf3),
/// ][..];
///
/// // Mark 10 bytes as written.
- /// bufs = IoSlice::advance(mem::replace(&mut bufs, &mut []), 10);
+ /// bufs = IoSlice::advance(bufs, 10);
/// assert_eq!(bufs[0].deref(), [2; 14].as_ref());
/// assert_eq!(bufs[1].deref(), [3; 8].as_ref());
#[unstable(feature = "io_slice_advance", issue = "62726")]
@@ -2415,7 +2413,6 @@
use crate::cmp;
use crate::io::prelude::*;
use crate::io::{self, IoSlice, IoSliceMut};
- use crate::mem;
use crate::ops::Deref;
#[test]
@@ -2731,26 +2728,26 @@
][..];
// Only in a single buffer..
- bufs = IoSliceMut::advance(mem::replace(&mut bufs, &mut []), 1);
+ bufs = IoSliceMut::advance(bufs, 1);
assert_eq!(bufs[0].deref(), [1; 7].as_ref());
assert_eq!(bufs[1].deref(), [2; 16].as_ref());
assert_eq!(bufs[2].deref(), [3; 8].as_ref());
// Removing a buffer, leaving others as is.
- bufs = IoSliceMut::advance(mem::replace(&mut bufs, &mut []), 7);
+ bufs = IoSliceMut::advance(bufs, 7);
assert_eq!(bufs[0].deref(), [2; 16].as_ref());
assert_eq!(bufs[1].deref(), [3; 8].as_ref());
// Removing a buffer and removing from the next buffer.
- bufs = IoSliceMut::advance(mem::replace(&mut bufs, &mut []), 18);
+ bufs = IoSliceMut::advance(bufs, 18);
assert_eq!(bufs[0].deref(), [3; 6].as_ref());
}
#[test]
fn io_slice_mut_advance_empty_slice() {
- let mut empty_bufs = &mut [][..];
+ let empty_bufs = &mut [][..];
// Shouldn't panic.
- IoSliceMut::advance(&mut empty_bufs, 1);
+ IoSliceMut::advance(empty_bufs, 1);
}
#[test]
@@ -2759,48 +2756,48 @@
let mut bufs = &mut [IoSliceMut::new(&mut buf1)][..];
// Going beyond the total length should be ok.
- bufs = IoSliceMut::advance(mem::replace(&mut bufs, &mut []), 9);
+ bufs = IoSliceMut::advance(bufs, 9);
assert!(bufs.is_empty());
}
#[test]
fn io_slice_advance() {
- let mut buf1 = [1; 8];
- let mut buf2 = [2; 16];
- let mut buf3 = [3; 8];
+ let buf1 = [1; 8];
+ let buf2 = [2; 16];
+ let buf3 = [3; 8];
let mut bufs =
- &mut [IoSlice::new(&mut buf1), IoSlice::new(&mut buf2), IoSlice::new(&mut buf3)][..];
+ &mut [IoSlice::new(&buf1), IoSlice::new(&buf2), IoSlice::new(&buf3)][..];
// Only in a single buffer..
- bufs = IoSlice::advance(mem::replace(&mut bufs, &mut []), 1);
+ bufs = IoSlice::advance(bufs, 1);
assert_eq!(bufs[0].deref(), [1; 7].as_ref());
assert_eq!(bufs[1].deref(), [2; 16].as_ref());
assert_eq!(bufs[2].deref(), [3; 8].as_ref());
// Removing a buffer, leaving others as is.
- bufs = IoSlice::advance(mem::replace(&mut bufs, &mut []), 7);
+ bufs = IoSlice::advance(bufs, 7);
assert_eq!(bufs[0].deref(), [2; 16].as_ref());
assert_eq!(bufs[1].deref(), [3; 8].as_ref());
// Removing a buffer and removing from the next buffer.
- bufs = IoSlice::advance(mem::replace(&mut bufs, &mut []), 18);
+ bufs = IoSlice::advance(bufs, 18);
assert_eq!(bufs[0].deref(), [3; 6].as_ref());
}
#[test]
fn io_slice_advance_empty_slice() {
- let mut empty_bufs = &mut [][..];
+ let empty_bufs = &mut [][..];
// Shouldn't panic.
- IoSlice::advance(&mut empty_bufs, 1);
+ IoSlice::advance(empty_bufs, 1);
}
#[test]
fn io_slice_advance_beyond_total_length() {
- let mut buf1 = [1; 8];
- let mut bufs = &mut [IoSlice::new(&mut buf1)][..];
+ let buf1 = [1; 8];
+ let mut bufs = &mut [IoSlice::new(&buf1)][..];
// Going beyond the total length should be ok.
- bufs = IoSlice::advance(mem::replace(&mut bufs, &mut []), 9);
+ bufs = IoSlice::advance(bufs, 9);
assert!(bufs.is_empty());
}
}
diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs
index 5b7bef9..de7ced3 100644
--- a/src/libstd/keyword_docs.rs
+++ b/src/libstd/keyword_docs.rs
@@ -57,7 +57,7 @@
/// 'outer: for i in 1..=5 {
/// println!("outer iteration (i): {}", i);
///
-/// 'inner: for j in 1..=200 {
+/// '_inner: for j in 1..=200 {
/// println!(" inner iteration (j): {}", j);
/// if j >= 3 {
/// // breaks from inner loop, let's outer loop continue.
@@ -178,7 +178,7 @@
///```rust
/// // Print Odd numbers under 30 with unit <= 5
/// 'tens: for ten in 0..3 {
-/// 'units: for unit in 0..=9 {
+/// '_units: for unit in 0..=9 {
/// if unit % 2 == 0 {
/// continue;
/// }
diff --git a/src/libstd/net/parser.rs b/src/libstd/net/parser.rs
index 8106d1c..686fa8c 100644
--- a/src/libstd/net/parser.rs
+++ b/src/libstd/net/parser.rs
@@ -44,19 +44,6 @@
self.read_atomically(move |p| cb(p).filter(|_| p.is_eof()))
}
- // Return result of first successful parser
- fn read_or<T>(
- &mut self,
- parsers: &mut [Box<dyn FnMut(&mut Parser<'_>) -> Option<T> + 'static>],
- ) -> Option<T> {
- for pf in parsers {
- if let Some(r) = self.read_atomically(|p: &mut Parser<'_>| pf(p)) {
- return Some(r);
- }
- }
- None
- }
-
// Apply 3 parsers sequentially
fn read_seq_3<A, B, C, PA, PB, PC>(&mut self, pa: PA, pb: PB, pc: PC) -> Option<(A, B, C)>
where
@@ -235,9 +222,8 @@
}
fn read_ip_addr(&mut self) -> Option<IpAddr> {
- let ipv4_addr = |p: &mut Parser<'_>| p.read_ipv4_addr().map(IpAddr::V4);
- let ipv6_addr = |p: &mut Parser<'_>| p.read_ipv6_addr().map(IpAddr::V6);
- self.read_or(&mut [Box::new(ipv4_addr), Box::new(ipv6_addr)])
+ self.read_ipv4_addr().map(IpAddr::V4)
+ .or_else(|| self.read_ipv6_addr().map(IpAddr::V6))
}
fn read_socket_addr_v4(&mut self) -> Option<SocketAddrV4> {
@@ -268,9 +254,8 @@
}
fn read_socket_addr(&mut self) -> Option<SocketAddr> {
- let v4 = |p: &mut Parser<'_>| p.read_socket_addr_v4().map(SocketAddr::V4);
- let v6 = |p: &mut Parser<'_>| p.read_socket_addr_v6().map(SocketAddr::V6);
- self.read_or(&mut [Box::new(v4), Box::new(v6)])
+ self.read_socket_addr_v4().map(SocketAddr::V4)
+ .or_else(|| self.read_socket_addr_v6().map(SocketAddr::V6))
}
}
diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs
index 87c2318..e90da69 100644
--- a/src/libstd/sync/mutex.rs
+++ b/src/libstd/sync/mutex.rs
@@ -143,10 +143,8 @@
#[must_use = "if unused the Mutex will immediately unlock"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct MutexGuard<'a, T: ?Sized + 'a> {
- // funny underscores due to how Deref/DerefMut currently work (they
- // disregard field privacy).
- __lock: &'a Mutex<T>,
- __poison: poison::Guard,
+ lock: &'a Mutex<T>,
+ poison: poison::Guard,
}
#[stable(feature = "rust1", since = "1.0.0")]
@@ -417,8 +415,8 @@
unsafe fn new(lock: &'mutex Mutex<T>) -> LockResult<MutexGuard<'mutex, T>> {
poison::map_result(lock.poison.borrow(), |guard| {
MutexGuard {
- __lock: lock,
- __poison: guard,
+ lock: lock,
+ poison: guard,
}
})
}
@@ -429,14 +427,14 @@
type Target = T;
fn deref(&self) -> &T {
- unsafe { &*self.__lock.data.get() }
+ unsafe { &*self.lock.data.get() }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> DerefMut for MutexGuard<'_, T> {
fn deref_mut(&mut self) -> &mut T {
- unsafe { &mut *self.__lock.data.get() }
+ unsafe { &mut *self.lock.data.get() }
}
}
@@ -445,8 +443,8 @@
#[inline]
fn drop(&mut self) {
unsafe {
- self.__lock.poison.done(&self.__poison);
- self.__lock.inner.raw_unlock();
+ self.lock.poison.done(&self.poison);
+ self.lock.inner.raw_unlock();
}
}
}
@@ -466,11 +464,11 @@
}
pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex {
- &guard.__lock.inner
+ &guard.lock.inner
}
pub fn guard_poison<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a poison::Flag {
- &guard.__lock.poison
+ &guard.lock.poison
}
#[cfg(all(test, not(target_os = "emscripten")))]
diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs
index b1b56f3..c217291 100644
--- a/src/libstd/sync/rwlock.rs
+++ b/src/libstd/sync/rwlock.rs
@@ -87,7 +87,7 @@
#[must_use = "if unused the RwLock will immediately unlock"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct RwLockReadGuard<'a, T: ?Sized + 'a> {
- __lock: &'a RwLock<T>,
+ lock: &'a RwLock<T>,
}
#[stable(feature = "rust1", since = "1.0.0")]
@@ -108,8 +108,8 @@
#[must_use = "if unused the RwLock will immediately unlock"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> {
- __lock: &'a RwLock<T>,
- __poison: poison::Guard,
+ lock: &'a RwLock<T>,
+ poison: poison::Guard,
}
#[stable(feature = "rust1", since = "1.0.0")]
@@ -465,7 +465,7 @@
-> LockResult<RwLockReadGuard<'rwlock, T>> {
poison::map_result(lock.poison.borrow(), |_| {
RwLockReadGuard {
- __lock: lock,
+ lock: lock,
}
})
}
@@ -476,8 +476,8 @@
-> LockResult<RwLockWriteGuard<'rwlock, T>> {
poison::map_result(lock.poison.borrow(), |guard| {
RwLockWriteGuard {
- __lock: lock,
- __poison: guard,
+ lock: lock,
+ poison: guard,
}
})
}
@@ -487,7 +487,7 @@
impl<T: fmt::Debug> fmt::Debug for RwLockReadGuard<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RwLockReadGuard")
- .field("lock", &self.__lock)
+ .field("lock", &self.lock)
.finish()
}
}
@@ -503,7 +503,7 @@
impl<T: fmt::Debug> fmt::Debug for RwLockWriteGuard<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RwLockWriteGuard")
- .field("lock", &self.__lock)
+ .field("lock", &self.lock)
.finish()
}
}
@@ -520,7 +520,7 @@
type Target = T;
fn deref(&self) -> &T {
- unsafe { &*self.__lock.data.get() }
+ unsafe { &*self.lock.data.get() }
}
}
@@ -529,29 +529,29 @@
type Target = T;
fn deref(&self) -> &T {
- unsafe { &*self.__lock.data.get() }
+ unsafe { &*self.lock.data.get() }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> DerefMut for RwLockWriteGuard<'_, T> {
fn deref_mut(&mut self) -> &mut T {
- unsafe { &mut *self.__lock.data.get() }
+ unsafe { &mut *self.lock.data.get() }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Drop for RwLockReadGuard<'_, T> {
fn drop(&mut self) {
- unsafe { self.__lock.inner.read_unlock(); }
+ unsafe { self.lock.inner.read_unlock(); }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Drop for RwLockWriteGuard<'_, T> {
fn drop(&mut self) {
- self.__lock.poison.done(&self.__poison);
- unsafe { self.__lock.inner.write_unlock(); }
+ self.lock.poison.done(&self.poison);
+ unsafe { self.lock.inner.write_unlock(); }
}
}
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 75ddf10..92ba071 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -2488,14 +2488,14 @@
///
/// The name might be a dummy name in case of anonymous items.
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
-pub struct Item {
+pub struct Item<K = ItemKind> {
pub attrs: Vec<Attribute>,
pub id: NodeId,
pub span: Span,
pub vis: Visibility,
pub ident: Ident,
- pub kind: ItemKind,
+ pub kind: K,
/// Original tokens this item was parsed from. This isn't necessarily
/// available for all items, although over time more and more items should
@@ -2650,16 +2650,7 @@
}
}
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
-pub struct ForeignItem {
- pub attrs: Vec<Attribute>,
- pub id: NodeId,
- pub span: Span,
- pub vis: Visibility,
- pub ident: Ident,
-
- pub kind: ForeignItemKind,
-}
+pub type ForeignItem = Item<ForeignItemKind>;
/// An item within an `extern` block.
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index a947426..3617380 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -7,6 +7,7 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/",
test(attr(deny(warnings))))]
+#![feature(bool_to_option)]
#![feature(box_syntax)]
#![feature(const_fn)]
#![feature(const_transmute)]
diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs
index 8889e5d..f8795d8 100644
--- a/src/libsyntax/mut_visit.rs
+++ b/src/libsyntax/mut_visit.rs
@@ -1053,7 +1053,7 @@
pub fn noop_flat_map_foreign_item<T: MutVisitor>(mut item: ForeignItem, visitor: &mut T)
-> SmallVec<[ForeignItem; 1]>
{
- let ForeignItem { ident, attrs, kind, id, span, vis } = &mut item;
+ let ForeignItem { ident, attrs, id, kind, vis, span, tokens: _ } = &mut item;
visitor.visit_ident(ident);
visit_attrs(attrs, visitor);
match kind {
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 4821bbd..b2e8d85 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -317,7 +317,7 @@
}
fn token_to_string_ext(token: &Token, convert_dollar_crate: bool) -> String {
- let convert_dollar_crate = if convert_dollar_crate { Some(token.span) } else { None };
+ let convert_dollar_crate = convert_dollar_crate.then_some(token.span);
token_kind_to_string_ext(&token.kind, convert_dollar_crate)
}
diff --git a/src/libsyntax/util/lev_distance.rs b/src/libsyntax/util/lev_distance.rs
index 4127a8c..efb3c23 100644
--- a/src/libsyntax/util/lev_distance.rs
+++ b/src/libsyntax/util/lev_distance.rs
@@ -77,6 +77,6 @@
if let Some(candidate) = case_insensitive_match {
Some(candidate) // exact case insensitive match has a higher priority
} else {
- if let Some((candidate, _)) = levenstein_match { Some(candidate) } else { None }
+ levenstein_match.map(|(candidate, _)| candidate)
}
}
diff --git a/src/libsyntax_expand/placeholders.rs b/src/libsyntax_expand/placeholders.rs
index 74ade1d..faea04e 100644
--- a/src/libsyntax_expand/placeholders.rs
+++ b/src/libsyntax_expand/placeholders.rs
@@ -65,6 +65,7 @@
AstFragment::ForeignItems(smallvec![ast::ForeignItem {
id, span, ident, vis, attrs,
kind: ast::ForeignItemKind::Macro(mac_placeholder()),
+ tokens: None,
}]),
AstFragmentKind::Pat => AstFragment::Pat(P(ast::Pat {
id, span, kind: ast::PatKind::Mac(mac_placeholder()),
diff --git a/src/libsyntax_expand/proc_macro.rs b/src/libsyntax_expand/proc_macro.rs
index 8e56e2b..520488c 100644
--- a/src/libsyntax_expand/proc_macro.rs
+++ b/src/libsyntax_expand/proc_macro.rs
@@ -1,7 +1,7 @@
use crate::base::{self, *};
use crate::proc_macro_server;
-use syntax::ast::{self, ItemKind, MacArgs};
+use syntax::ast::{self, ItemKind, MetaItemKind, NestedMetaItem};
use syntax::errors::{Applicability, FatalError};
use syntax::symbol::sym;
use syntax::token;
@@ -171,34 +171,71 @@
if !attr.has_name(sym::derive) {
return true;
}
- if !attr.is_meta_item_list() {
- cx.struct_span_err(attr.span, "malformed `derive` attribute input")
- .span_suggestion(
- attr.span,
- "missing traits to be derived",
- "#[derive(Trait1, Trait2, ...)]".to_owned(),
- Applicability::HasPlaceholders,
- ).emit();
- return false;
- }
- let parse_derive_paths = |attr: &ast::Attribute| {
- if let MacArgs::Empty = attr.get_normal_item().args {
- return Ok(Vec::new());
+ // 1) First let's ensure that it's a meta item.
+ let nmis = match attr.meta_item_list() {
+ None => {
+ cx.struct_span_err(attr.span, "malformed `derive` attribute input")
+ .span_suggestion(
+ attr.span,
+ "missing traits to be derived",
+ "#[derive(Trait1, Trait2, ...)]".to_owned(),
+ Applicability::HasPlaceholders,
+ )
+ .emit();
+ return false;
}
- rustc_parse::parse_in_attr(cx.parse_sess, attr, |p| p.parse_derive_paths())
+ Some(x) => x,
};
- match parse_derive_paths(attr) {
- Ok(traits) => {
- result.extend(traits);
- true
- }
- Err(mut e) => {
- e.emit();
- false
- }
- }
+ let mut error_reported_filter_map = false;
+ let mut error_reported_map = false;
+ let traits = nmis
+ .into_iter()
+ // 2) Moreover, let's ensure we have a path and not `#[derive("foo")]`.
+ .filter_map(|nmi| match nmi {
+ NestedMetaItem::Literal(lit) => {
+ error_reported_filter_map = true;
+ cx.struct_span_err(lit.span, "expected path to a trait, found literal")
+ .help("for example, write `#[derive(Debug)]` for `Debug`")
+ .emit();
+ None
+ }
+ NestedMetaItem::MetaItem(mi) => Some(mi),
+ })
+ // 3) Finally, we only accept `#[derive($path_0, $path_1, ..)]`
+ // but not e.g. `#[derive($path_0 = "value", $path_1(abc))]`.
+ // In this case we can still at least determine that the user
+ // wanted this trait to be derived, so let's keep it.
+ .map(|mi| {
+ let mut traits_dont_accept = |title, action| {
+ error_reported_map = true;
+ let sp = mi.span.with_lo(mi.path.span.hi());
+ cx.struct_span_err(sp, title)
+ .span_suggestion(
+ sp,
+ action,
+ String::new(),
+ Applicability::MachineApplicable,
+ )
+ .emit();
+ };
+ match &mi.kind {
+ MetaItemKind::List(..) => traits_dont_accept(
+ "traits in `#[derive(...)]` don't accept arguments",
+ "remove the arguments",
+ ),
+ MetaItemKind::NameValue(..) => traits_dont_accept(
+ "traits in `#[derive(...)]` don't accept values",
+ "remove the value",
+ ),
+ MetaItemKind::Word => {}
+ }
+ mi.path
+ });
+
+ result.extend(traits);
+ !error_reported_filter_map && !error_reported_map
});
result
}
diff --git a/src/libsyntax_ext/format_foreign.rs b/src/libsyntax_ext/format_foreign.rs
index 3d4f827..0d1d292 100644
--- a/src/libsyntax_ext/format_foreign.rs
+++ b/src/libsyntax_ext/format_foreign.rs
@@ -95,12 +95,12 @@
};
// Has a special form in Rust for numbers.
- let fill = if c_zero { Some("0") } else { None };
+ let fill = c_zero.then_some("0");
- let align = if c_left { Some("<") } else { None };
+ let align = c_left.then_some("<");
// Rust doesn't have an equivalent to the `' '` flag.
- let sign = if c_plus { Some("+") } else { None };
+ let sign = c_plus.then_some("+");
// Not *quite* the same, depending on the type...
let alt = c_alt;
diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs
index b9287d2..55c7f3f 100644
--- a/src/libsyntax_ext/lib.rs
+++ b/src/libsyntax_ext/lib.rs
@@ -3,6 +3,7 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![feature(bool_to_option)]
#![feature(crate_visibility_modifier)]
#![feature(decl_macro)]
#![feature(nll)]
diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs
index c68e03be..e8f7a12 100644
--- a/src/libsyntax_pos/symbol.rs
+++ b/src/libsyntax_pos/symbol.rs
@@ -213,6 +213,7 @@
const_indexing,
const_in_array_repeat_expressions,
const_let,
+ const_mut_refs,
const_panic,
const_raw_ptr_deref,
const_raw_ptr_to_usize_cast,
diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs
index 7647978..0097558 100644
--- a/src/libtest/lib.rs
+++ b/src/libtest/lib.rs
@@ -24,6 +24,7 @@
#![cfg_attr(any(unix, target_os = "cloudabi"), feature(libc))]
#![feature(rustc_private)]
#![feature(nll)]
+#![feature(bool_to_option)]
#![feature(set_stdio)]
#![feature(panic_unwind)]
#![feature(staged_api)]
@@ -562,11 +563,7 @@
None
};
- let start = if report_time {
- Some(Instant::now())
- } else {
- None
- };
+ let start = report_time.then(Instant::now);
let result = catch_unwind(AssertUnwindSafe(testfn));
let exec_time = start.map(|start| {
let duration = start.elapsed();
@@ -597,11 +594,7 @@
let args = env::args().collect::<Vec<_>>();
let current_exe = &args[0];
- let start = if report_time {
- Some(Instant::now())
- } else {
- None
- };
+ let start = report_time.then(Instant::now);
let output = match Command::new(current_exe)
.env(SECONDARY_TEST_INVOKER_VAR, desc.name.as_slice())
.output() {
diff --git a/src/llvm-project b/src/llvm-project
index de1a7db..2cb4100 160000
--- a/src/llvm-project
+++ b/src/llvm-project
@@ -1 +1 @@
-Subproject commit de1a7dbf6c6b34f56e65732d45970ff27a8e84bf
+Subproject commit 2cb41005ed5c4747b10d2bf01d8779d3bb4ae32d
diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp
index a83ba9a..720928e 100644
--- a/src/rustllvm/RustWrapper.cpp
+++ b/src/rustllvm/RustWrapper.cpp
@@ -129,8 +129,9 @@
}
extern "C" LLVMValueRef
-LLVMRustGetOrInsertGlobal(LLVMModuleRef M, const char *Name, LLVMTypeRef Ty) {
- return wrap(unwrap(M)->getOrInsertGlobal(Name, unwrap(Ty)));
+LLVMRustGetOrInsertGlobal(LLVMModuleRef M, const char *Name, size_t NameLen, LLVMTypeRef Ty) {
+ StringRef NameRef(Name, NameLen);
+ return wrap(unwrap(M)->getOrInsertGlobal(NameRef, unwrap(Ty)));
}
extern "C" LLVMValueRef
@@ -1287,11 +1288,12 @@
}
extern "C" void LLVMRustSetComdat(LLVMModuleRef M, LLVMValueRef V,
- const char *Name) {
+ const char *Name, size_t NameLen) {
Triple TargetTriple(unwrap(M)->getTargetTriple());
GlobalObject *GV = unwrap<GlobalObject>(V);
if (!TargetTriple.isOSBinFormatMachO()) {
- GV->setComdat(unwrap(M)->getOrInsertComdat(Name));
+ StringRef NameRef(Name, NameLen);
+ GV->setComdat(unwrap(M)->getOrInsertComdat(NameRef));
}
}
diff --git a/src/test/codegen/set-discriminant-invalid.rs b/src/test/codegen/set-discriminant-invalid.rs
new file mode 100644
index 0000000..d9614f0
--- /dev/null
+++ b/src/test/codegen/set-discriminant-invalid.rs
@@ -0,0 +1,43 @@
+// compile-flags: -C opt-level=0
+#![crate_type = "lib"]
+
+pub enum ApiError {}
+#[allow(dead_code)]
+pub struct TokioError {
+ b: bool,
+}
+pub enum Error {
+ Api {
+ source: ApiError,
+ },
+ Ethereum,
+ Tokio {
+ source: TokioError,
+ },
+}
+struct Api;
+impl IntoError<Error> for Api
+{
+ type Source = ApiError;
+ // CHECK-LABEL: @into_error
+ // CHECK: llvm.trap()
+ // Also check the next two instructions to make sure we do not match against `trap`
+ // elsewhere in the code.
+ // CHECK-NEXT: load
+ // CHECK-NEXT: ret
+ #[no_mangle]
+ fn into_error(self, error: Self::Source) -> Error {
+ Error::Api {
+ source: (|v| v)(error),
+ }
+ }
+}
+
+pub trait IntoError<E>
+{
+ /// The underlying error
+ type Source;
+
+ /// Combine the information to produce the error
+ fn into_error(self, source: Self::Source) -> E;
+}
diff --git a/src/test/compile-fail/consts/const-err3.rs b/src/test/compile-fail/consts/const-err3.rs
index add4eef..fc10824 100644
--- a/src/test/compile-fail/consts/const-err3.rs
+++ b/src/test/compile-fail/consts/const-err3.rs
@@ -14,7 +14,6 @@
//~^ ERROR const_err
let _e = [5u8][1];
//~^ ERROR const_err
- //~| ERROR this expression will panic at runtime
black_box(b);
black_box(c);
black_box(d);
diff --git a/src/test/compile-fail/consts/const-fn-error.rs b/src/test/compile-fail/consts/const-fn-error.rs
index 1a4fc72..5d26059 100644
--- a/src/test/compile-fail/consts/const-fn-error.rs
+++ b/src/test/compile-fail/consts/const-fn-error.rs
@@ -6,7 +6,7 @@
let mut sum = 0;
for i in 0..x {
//~^ ERROR E0015
- //~| ERROR E0017
+ //~| ERROR E0658
//~| ERROR E0080
//~| ERROR E0744
//~| ERROR E0019
diff --git a/src/test/incremental/issue-61323.rs b/src/test/incremental/issue-61323.rs
new file mode 100644
index 0000000..448ce36
--- /dev/null
+++ b/src/test/incremental/issue-61323.rs
@@ -0,0 +1,15 @@
+// revisions: rpass cfail
+
+enum A {
+ //[cfail]~^ ERROR 3:1: 3:7: recursive type `A` has infinite size [E0072]
+ B(C),
+}
+
+#[cfg(rpass)]
+struct C(Box<A>);
+
+#[cfg(cfail)]
+struct C(A);
+//[cfail]~^ ERROR 12:1: 12:13: recursive type `C` has infinite size [E0072]
+
+fn main() {}
diff --git a/src/test/rustdoc-ui/issue-61732.rs b/src/test/rustdoc-ui/issue-61732.rs
new file mode 100644
index 0000000..d4835c0
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-61732.rs
@@ -0,0 +1,4 @@
+// This previously triggered an ICE.
+
+pub(in crate::r#mod) fn main() {}
+//~^ ERROR expected module, found unresolved item
diff --git a/src/test/rustdoc-ui/issue-61732.stderr b/src/test/rustdoc-ui/issue-61732.stderr
new file mode 100644
index 0000000..6c8ba48
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-61732.stderr
@@ -0,0 +1,11 @@
+error[E0577]: expected module, found unresolved item `crate::r#mod`
+ --> $DIR/issue-61732.rs:3:8
+ |
+LL | pub(in crate::r#mod) fn main() {}
+ | ^^^^^^^^^^^^ not a module
+
+error: Compilation failed, aborting rustdoc
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0577`.
diff --git a/src/test/rustdoc/duplicate-cfg.rs b/src/test/rustdoc/duplicate-cfg.rs
new file mode 100644
index 0000000..505d6ee
--- /dev/null
+++ b/src/test/rustdoc/duplicate-cfg.rs
@@ -0,0 +1,15 @@
+#![crate_name = "foo"]
+#![feature(doc_cfg)]
+
+// @has 'foo/index.html'
+// @!has '-' '//*[@class="stab portability"]' 'feature="sync" and'
+// @has '-' '//*[@class="stab portability"]' 'feature="sync"'
+#[doc(cfg(feature = "sync"))]
+#[doc(cfg(feature = "sync"))]
+pub struct Foo;
+
+#[doc(cfg(feature = "sync"))]
+pub mod bar {
+ #[doc(cfg(feature = "sync"))]
+ pub struct Bar;
+}
diff --git a/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.rs b/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.rs
new file mode 100644
index 0000000..c8c2702
--- /dev/null
+++ b/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.rs
@@ -0,0 +1,15 @@
+// edition:2018
+
+struct Ia<S>(S);
+
+impl<S> Ia<S> {
+ fn partial(_: S) {}
+ fn full(self) {}
+
+ async fn crash(self) {
+ Self::partial(self.0);
+ Self::full(self); //~ ERROR use of moved value: `self`
+ }
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.stderr b/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.stderr
new file mode 100644
index 0000000..9177b83
--- /dev/null
+++ b/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.stderr
@@ -0,0 +1,13 @@
+error[E0382]: use of moved value: `self`
+ --> $DIR/issue-66958-non-copy-infered-type-arg.rs:11:20
+ |
+LL | Self::partial(self.0);
+ | ------ value moved here
+LL | Self::full(self);
+ | ^^^^ value used here after partial move
+ |
+ = note: move occurs because `self.0` has type `S`, which does not implement the `Copy` trait
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/async-await/suggest-missing-await.fixed b/src/test/ui/async-await/suggest-missing-await.fixed
index 7c02a90..1ec59d9 100644
--- a/src/test/ui/async-await/suggest-missing-await.fixed
+++ b/src/test/ui/async-await/suggest-missing-await.fixed
@@ -16,4 +16,15 @@
//~| SUGGESTION x.await
}
+async fn dummy() {}
+
+#[allow(unused)]
+async fn suggest_await_in_async_fn_return() {
+ dummy().await;
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP try adding a semicolon
+ //~| HELP consider using `.await` here
+ //~| SUGGESTION dummy().await
+}
+
fn main() {}
diff --git a/src/test/ui/async-await/suggest-missing-await.rs b/src/test/ui/async-await/suggest-missing-await.rs
index 91abd44..70cc1f1 100644
--- a/src/test/ui/async-await/suggest-missing-await.rs
+++ b/src/test/ui/async-await/suggest-missing-await.rs
@@ -16,4 +16,15 @@
//~| SUGGESTION x.await
}
+async fn dummy() {}
+
+#[allow(unused)]
+async fn suggest_await_in_async_fn_return() {
+ dummy()
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP try adding a semicolon
+ //~| HELP consider using `.await` here
+ //~| SUGGESTION dummy().await
+}
+
fn main() {}
diff --git a/src/test/ui/async-await/suggest-missing-await.stderr b/src/test/ui/async-await/suggest-missing-await.stderr
index 7a635a3..7ab0244 100644
--- a/src/test/ui/async-await/suggest-missing-await.stderr
+++ b/src/test/ui/async-await/suggest-missing-await.stderr
@@ -10,6 +10,23 @@
= note: expected type `u32`
found opaque type `impl std::future::Future`
-error: aborting due to previous error
+error[E0308]: mismatched types
+ --> $DIR/suggest-missing-await.rs:23:5
+ |
+LL | dummy()
+ | ^^^^^^^ expected `()`, found opaque type
+ |
+ = note: expected unit type `()`
+ found opaque type `impl std::future::Future`
+help: try adding a semicolon
+ |
+LL | dummy();
+ | ^
+help: consider using `.await` here
+ |
+LL | dummy().await
+ |
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/check-static-immutable-mut-slices.stderr b/src/test/ui/check-static-immutable-mut-slices.stderr
index 4f4bf16..39da824 100644
--- a/src/test/ui/check-static-immutable-mut-slices.stderr
+++ b/src/test/ui/check-static-immutable-mut-slices.stderr
@@ -1,9 +1,12 @@
-error[E0017]: references in statics may only refer to immutable values
+error[E0658]: references in statics may only refer to immutable values
--> $DIR/check-static-immutable-mut-slices.rs:3:37
|
LL | static TEST: &'static mut [isize] = &mut [];
| ^^^^^^^ statics require immutable values
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0017`.
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/closures/closure-expected-type/expect-region-supply-region.polonius.stderr b/src/test/ui/closures/closure-expected-type/expect-region-supply-region.polonius.stderr
new file mode 100644
index 0000000..2a7461f
--- /dev/null
+++ b/src/test/ui/closures/closure-expected-type/expect-region-supply-region.polonius.stderr
@@ -0,0 +1,56 @@
+error[E0521]: borrowed data escapes outside of closure
+ --> $DIR/expect-region-supply-region.rs:18:9
+ |
+LL | let mut f: Option<&u32> = None;
+ | ----- `f` is declared here, outside of the closure body
+LL | closure_expecting_bound(|x| {
+ | - `x` is a reference that is only valid in the closure body
+LL | f = Some(x);
+ | ^^^^^^^^^^^ `x` escapes the closure body here
+
+error[E0521]: borrowed data escapes outside of closure
+ --> $DIR/expect-region-supply-region.rs:28:9
+ |
+LL | let mut f: Option<&u32> = None;
+ | ----- `f` is declared here, outside of the closure body
+LL | closure_expecting_bound(|x: &u32| {
+ | - `x` is a reference that is only valid in the closure body
+LL | f = Some(x);
+ | ^^^^^^^^^^^ `x` escapes the closure body here
+
+error: lifetime may not live long enough
+ --> $DIR/expect-region-supply-region.rs:37:30
+ |
+LL | fn expect_bound_supply_named<'x>() {
+ | -- lifetime `'x` defined here
+...
+LL | closure_expecting_bound(|x: &'x u32| {
+ | ^ - let's call the lifetime of this reference `'1`
+ | |
+ | requires that `'1` must outlive `'x`
+
+error[E0521]: borrowed data escapes outside of closure
+ --> $DIR/expect-region-supply-region.rs:42:9
+ |
+LL | let mut f: Option<&u32> = None;
+ | ----- `f` is declared here, outside of the closure body
+...
+LL | closure_expecting_bound(|x: &'x u32| {
+ | - `x` is a reference that is only valid in the closure body
+...
+LL | f = Some(x);
+ | ^^^^^^^^^^^ `x` escapes the closure body here
+
+error: lifetime may not live long enough
+ --> $DIR/expect-region-supply-region.rs:37:30
+ |
+LL | fn expect_bound_supply_named<'x>() {
+ | -- lifetime `'x` defined here
+...
+LL | closure_expecting_bound(|x: &'x u32| {
+ | ^ requires that `'x` must outlive `'static`
+ |
+ = help: consider replacing `'x` with `'static`
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/ui/conditional-compilation/cfg-attr-parse.rs b/src/test/ui/conditional-compilation/cfg-attr-parse.rs
index 93aef72..8ca31c1 100644
--- a/src/test/ui/conditional-compilation/cfg-attr-parse.rs
+++ b/src/test/ui/conditional-compilation/cfg-attr-parse.rs
@@ -1,11 +1,11 @@
// Parse `cfg_attr` with varying numbers of attributes and trailing commas
// Completely empty `cfg_attr` input
-#[cfg_attr()] //~ error: expected identifier, found `)`
+#[cfg_attr()] //~ error: malformed `cfg_attr` attribute input
struct NoConfigurationPredicate;
// Zero attributes, zero trailing comma (comma manatory here)
-#[cfg_attr(all())] //~ error: expected `,`, found `)`
+#[cfg_attr(all())] //~ error: expected `,`, found end of `cfg_attr`
struct A0C0;
// Zero attributes, one trailing comma
@@ -40,4 +40,16 @@
#[cfg_attr(all(), must_use, deprecated,,)] //~ ERROR expected identifier
struct A2C2;
+// Wrong delimiter `[`
+#[cfg_attr[all(),,]]
+//~^ ERROR wrong `cfg_attr` delimiters
+//~| ERROR expected identifier, found `,`
+struct BracketZero;
+
+// Wrong delimiter `{`
+#[cfg_attr{all(),,}]
+//~^ ERROR wrong `cfg_attr` delimiters
+//~| ERROR expected identifier, found `,`
+struct BraceZero;
+
fn main() {}
diff --git a/src/test/ui/conditional-compilation/cfg-attr-parse.stderr b/src/test/ui/conditional-compilation/cfg-attr-parse.stderr
index 3dfbd6d..3a590d3 100644
--- a/src/test/ui/conditional-compilation/cfg-attr-parse.stderr
+++ b/src/test/ui/conditional-compilation/cfg-attr-parse.stderr
@@ -1,32 +1,86 @@
-error: expected identifier, found `)`
- --> $DIR/cfg-attr-parse.rs:4:12
+error: malformed `cfg_attr` attribute input
+ --> $DIR/cfg-attr-parse.rs:4:1
|
LL | #[cfg_attr()]
- | ^ expected identifier
+ | ^^^^^^^^^^^^^ help: missing condition and attribute: `#[cfg_attr(condition, attribute, other_attribute, ...)]`
+ |
+ = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
-error: expected `,`, found `)`
+error: expected `,`, found end of `cfg_attr` input
--> $DIR/cfg-attr-parse.rs:8:17
|
LL | #[cfg_attr(all())]
| ^ expected `,`
+ |
+ = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]`
+ = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
error: expected identifier, found `,`
--> $DIR/cfg-attr-parse.rs:16:18
|
LL | #[cfg_attr(all(),,)]
| ^ expected identifier
+ |
+ = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]`
+ = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
error: expected identifier, found `,`
--> $DIR/cfg-attr-parse.rs:28:28
|
LL | #[cfg_attr(all(), must_use,,)]
| ^ expected identifier
+ |
+ = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]`
+ = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
error: expected identifier, found `,`
--> $DIR/cfg-attr-parse.rs:40:40
|
LL | #[cfg_attr(all(), must_use, deprecated,,)]
| ^ expected identifier
+ |
+ = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]`
+ = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
-error: aborting due to 5 previous errors
+error: wrong `cfg_attr` delimiters
+ --> $DIR/cfg-attr-parse.rs:44:11
+ |
+LL | #[cfg_attr[all(),,]]
+ | ^^^^^^^^^
+ |
+help: the delimiters should be `(` and `)`
+ |
+LL | #[cfg_attr(all(),,)]
+ | ^ ^
+
+error: expected identifier, found `,`
+ --> $DIR/cfg-attr-parse.rs:44:18
+ |
+LL | #[cfg_attr[all(),,]]
+ | ^ expected identifier
+ |
+ = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]`
+ = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
+
+error: wrong `cfg_attr` delimiters
+ --> $DIR/cfg-attr-parse.rs:50:11
+ |
+LL | #[cfg_attr{all(),,}]
+ | ^^^^^^^^^
+ |
+help: the delimiters should be `(` and `)`
+ |
+LL | #[cfg_attr(all(),,)]
+ | ^ ^
+
+error: expected identifier, found `,`
+ --> $DIR/cfg-attr-parse.rs:50:18
+ |
+LL | #[cfg_attr{all(),,}]
+ | ^ expected identifier
+ |
+ = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]`
+ = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
+
+error: aborting due to 9 previous errors
diff --git a/src/test/ui/consts/array-literal-index-oob.stderr b/src/test/ui/consts/array-literal-index-oob.stderr
index 0ddc2a0..f4d4e6f 100644
--- a/src/test/ui/consts/array-literal-index-oob.stderr
+++ b/src/test/ui/consts/array-literal-index-oob.stderr
@@ -12,7 +12,7 @@
LL | &{[1, 2, 3][4]};
| --^^^^^^^^^^^^-
| |
- | index out of bounds: the len is 3 but the index is 4
+ | indexing out of bounds: the len is 3 but the index is 4
error: aborting due to 2 previous errors
diff --git a/src/test/ui/consts/const-err2.rs b/src/test/ui/consts/const-err2.rs
index e5ee90f..ecbcc2a 100644
--- a/src/test/ui/consts/const-err2.rs
+++ b/src/test/ui/consts/const-err2.rs
@@ -23,7 +23,6 @@
//~^ ERROR const_err
let _e = [5u8][1];
//~^ ERROR index out of bounds
- //~| ERROR this expression will panic at runtime
black_box(a);
black_box(b);
black_box(c);
diff --git a/src/test/ui/consts/const-err2.stderr b/src/test/ui/consts/const-err2.stderr
index 0a09a72..1d84d44 100644
--- a/src/test/ui/consts/const-err2.stderr
+++ b/src/test/ui/consts/const-err2.stderr
@@ -34,11 +34,5 @@
LL | let _e = [5u8][1];
| ^^^^^^^^
-error: this expression will panic at runtime
- --> $DIR/const-err2.rs:24:14
- |
-LL | let _e = [5u8][1];
- | ^^^^^^^^ index out of bounds: the len is 1 but the index is 1
-
-error: aborting due to 6 previous errors
+error: aborting due to 5 previous errors
diff --git a/src/test/ui/consts/const-err3.rs b/src/test/ui/consts/const-err3.rs
index 89373f9..a9cf04c 100644
--- a/src/test/ui/consts/const-err3.rs
+++ b/src/test/ui/consts/const-err3.rs
@@ -23,7 +23,6 @@
//~^ ERROR const_err
let _e = [5u8][1];
//~^ ERROR const_err
- //~| ERROR this expression will panic at runtime
black_box(a);
black_box(b);
black_box(c);
diff --git a/src/test/ui/consts/const-err3.stderr b/src/test/ui/consts/const-err3.stderr
index 42de247..0602707 100644
--- a/src/test/ui/consts/const-err3.stderr
+++ b/src/test/ui/consts/const-err3.stderr
@@ -34,11 +34,5 @@
LL | let _e = [5u8][1];
| ^^^^^^^^
-error: this expression will panic at runtime
- --> $DIR/const-err3.rs:24:14
- |
-LL | let _e = [5u8][1];
- | ^^^^^^^^ index out of bounds: the len is 1 but the index is 1
-
-error: aborting due to 6 previous errors
+error: aborting due to 5 previous errors
diff --git a/src/test/ui/consts/const-eval/const_caller_location.rs b/src/test/ui/consts/const-eval/const_caller_location.rs
deleted file mode 100644
index c63822f..0000000
--- a/src/test/ui/consts/const-eval/const_caller_location.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-// run-pass
-
-#![feature(const_fn, core_intrinsics)]
-
-use std::{intrinsics::caller_location, panic::Location};
-
-const LOCATION: &Location = caller_location();
-const NESTED: &Location = {
- const fn nested_location() -> &'static Location<'static> {
- caller_location()
- };
- nested_location()
-};
-
-fn main() {
- assert_eq!(LOCATION.file(), file!());
- assert_eq!(LOCATION.line(), 7);
- assert_eq!(LOCATION.column(), 29);
-
- assert_eq!(NESTED.file(), file!());
- assert_eq!(NESTED.line(), 10);
- assert_eq!(NESTED.column(), 9);
-}
diff --git a/src/test/ui/consts/const-eval/issue-65394.stderr b/src/test/ui/consts/const-eval/issue-65394.stderr
index acf5cba..54b3507 100644
--- a/src/test/ui/consts/const-eval/issue-65394.stderr
+++ b/src/test/ui/consts/const-eval/issue-65394.stderr
@@ -1,8 +1,11 @@
-error[E0017]: references in constants may only refer to immutable values
+error[E0658]: references in constants may only refer to immutable values
--> $DIR/issue-65394.rs:8:13
|
LL | let r = &mut x;
| ^^^^^^ constants require immutable values
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
error[E0493]: destructors cannot be evaluated at compile-time
--> $DIR/issue-65394.rs:7:9
@@ -12,5 +15,5 @@
error: aborting due to 2 previous errors
-Some errors have detailed explanations: E0017, E0493.
-For more information about an error, try `rustc --explain E0017`.
+Some errors have detailed explanations: E0493, E0658.
+For more information about an error, try `rustc --explain E0493`.
diff --git a/src/test/ui/consts/const-eval/promoted_errors.rs b/src/test/ui/consts/const-eval/promoted_errors.rs
index 4594139..dfa6863 100644
--- a/src/test/ui/consts/const-eval/promoted_errors.rs
+++ b/src/test/ui/consts/const-eval/promoted_errors.rs
@@ -8,14 +8,12 @@
//~^ ERROR const_err
println!("{}", 1/(1-1));
//~^ ERROR attempt to divide by zero [const_err]
- //~| ERROR reaching this expression at runtime will panic or abort [const_err]
+ //~| ERROR const_err
let _x = 1/(1-1);
//~^ ERROR const_err
- //~| ERROR const_err
println!("{}", 1/(false as u32));
//~^ ERROR attempt to divide by zero [const_err]
- //~| ERROR reaching this expression at runtime will panic or abort [const_err]
+ //~| ERROR const_err
let _x = 1/(false as u32);
//~^ ERROR const_err
- //~| ERROR const_err
}
diff --git a/src/test/ui/consts/const-eval/promoted_errors.stderr b/src/test/ui/consts/const-eval/promoted_errors.stderr
index 40d5c73..848a880 100644
--- a/src/test/ui/consts/const-eval/promoted_errors.stderr
+++ b/src/test/ui/consts/const-eval/promoted_errors.stderr
@@ -20,7 +20,7 @@
--> $DIR/promoted_errors.rs:9:20
|
LL | println!("{}", 1/(1-1));
- | ^^^^^^^ attempt to divide by zero
+ | ^^^^^^^ dividing by zero
error: attempt to divide by zero
--> $DIR/promoted_errors.rs:12:14
@@ -28,35 +28,23 @@
LL | let _x = 1/(1-1);
| ^^^^^^^
-error: this expression will panic at runtime
- --> $DIR/promoted_errors.rs:12:14
- |
-LL | let _x = 1/(1-1);
- | ^^^^^^^ attempt to divide by zero
-
error: attempt to divide by zero
- --> $DIR/promoted_errors.rs:15:20
+ --> $DIR/promoted_errors.rs:14:20
|
LL | println!("{}", 1/(false as u32));
| ^^^^^^^^^^^^^^^^
error: reaching this expression at runtime will panic or abort
- --> $DIR/promoted_errors.rs:15:20
+ --> $DIR/promoted_errors.rs:14:20
|
LL | println!("{}", 1/(false as u32));
- | ^^^^^^^^^^^^^^^^ attempt to divide by zero
+ | ^^^^^^^^^^^^^^^^ dividing by zero
error: attempt to divide by zero
- --> $DIR/promoted_errors.rs:18:14
+ --> $DIR/promoted_errors.rs:17:14
|
LL | let _x = 1/(false as u32);
| ^^^^^^^^^^^^^^^^
-error: this expression will panic at runtime
- --> $DIR/promoted_errors.rs:18:14
- |
-LL | let _x = 1/(false as u32);
- | ^^^^^^^^^^^^^^^^ attempt to divide by zero
-
-error: aborting due to 9 previous errors
+error: aborting due to 7 previous errors
diff --git a/src/test/ui/consts/const-eval/promoted_errors2.rs b/src/test/ui/consts/const-eval/promoted_errors2.rs
index 7adb394..58b1794 100644
--- a/src/test/ui/consts/const-eval/promoted_errors2.rs
+++ b/src/test/ui/consts/const-eval/promoted_errors2.rs
@@ -9,14 +9,12 @@
//~^ ERROR attempt to subtract with overflow
println!("{}", 1/(1-1));
//~^ ERROR attempt to divide by zero [const_err]
- //~| ERROR reaching this expression at runtime will panic or abort [const_err]
+ //~| ERROR const_err
let _x = 1/(1-1);
//~^ ERROR const_err
- //~| ERROR const_err
println!("{}", 1/(false as u32));
//~^ ERROR attempt to divide by zero [const_err]
- //~| ERROR reaching this expression at runtime will panic or abort [const_err]
+ //~| ERROR const_err
let _x = 1/(false as u32);
//~^ ERROR const_err
- //~| ERROR const_err
}
diff --git a/src/test/ui/consts/const-eval/promoted_errors2.stderr b/src/test/ui/consts/const-eval/promoted_errors2.stderr
index 2819e6e..6f4b1c0 100644
--- a/src/test/ui/consts/const-eval/promoted_errors2.stderr
+++ b/src/test/ui/consts/const-eval/promoted_errors2.stderr
@@ -26,7 +26,7 @@
--> $DIR/promoted_errors2.rs:10:20
|
LL | println!("{}", 1/(1-1));
- | ^^^^^^^ attempt to divide by zero
+ | ^^^^^^^ dividing by zero
error: attempt to divide by zero
--> $DIR/promoted_errors2.rs:13:14
@@ -34,35 +34,23 @@
LL | let _x = 1/(1-1);
| ^^^^^^^
-error: this expression will panic at runtime
- --> $DIR/promoted_errors2.rs:13:14
- |
-LL | let _x = 1/(1-1);
- | ^^^^^^^ attempt to divide by zero
-
error: attempt to divide by zero
- --> $DIR/promoted_errors2.rs:16:20
+ --> $DIR/promoted_errors2.rs:15:20
|
LL | println!("{}", 1/(false as u32));
| ^^^^^^^^^^^^^^^^
error: reaching this expression at runtime will panic or abort
- --> $DIR/promoted_errors2.rs:16:20
+ --> $DIR/promoted_errors2.rs:15:20
|
LL | println!("{}", 1/(false as u32));
- | ^^^^^^^^^^^^^^^^ attempt to divide by zero
+ | ^^^^^^^^^^^^^^^^ dividing by zero
error: attempt to divide by zero
- --> $DIR/promoted_errors2.rs:19:14
+ --> $DIR/promoted_errors2.rs:18:14
|
LL | let _x = 1/(false as u32);
| ^^^^^^^^^^^^^^^^
-error: this expression will panic at runtime
- --> $DIR/promoted_errors2.rs:19:14
- |
-LL | let _x = 1/(false as u32);
- | ^^^^^^^^^^^^^^^^ attempt to divide by zero
-
-error: aborting due to 10 previous errors
+error: aborting due to 8 previous errors
diff --git a/src/test/ui/consts/const-multi-ref.stderr b/src/test/ui/consts/const-multi-ref.stderr
index ed3837e..0809c77 100644
--- a/src/test/ui/consts/const-multi-ref.stderr
+++ b/src/test/ui/consts/const-multi-ref.stderr
@@ -1,8 +1,11 @@
-error[E0017]: references in constants may only refer to immutable values
+error[E0658]: references in constants may only refer to immutable values
--> $DIR/const-multi-ref.rs:6:13
|
LL | let p = &mut a;
| ^^^^^^ constants require immutable values
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
--> $DIR/const-multi-ref.rs:16:13
@@ -12,5 +15,5 @@
error: aborting due to 2 previous errors
-Some errors have detailed explanations: E0017, E0492.
-For more information about an error, try `rustc --explain E0017`.
+Some errors have detailed explanations: E0492, E0658.
+For more information about an error, try `rustc --explain E0492`.
diff --git a/src/test/ui/consts/const-mut-refs/const_mut_refs.rs b/src/test/ui/consts/const-mut-refs/const_mut_refs.rs
new file mode 100644
index 0000000..99006a2
--- /dev/null
+++ b/src/test/ui/consts/const-mut-refs/const_mut_refs.rs
@@ -0,0 +1,36 @@
+// run-pass
+
+#![feature(const_mut_refs)]
+
+struct Foo {
+ x: usize
+}
+
+const fn foo() -> Foo {
+ Foo { x: 0 }
+}
+
+impl Foo {
+ const fn bar(&mut self) -> usize {
+ self.x = 1;
+ self.x
+ }
+
+}
+
+const fn baz(foo: &mut Foo) -> usize {
+ let x = &mut foo.x;
+ *x = 2;
+ *x
+}
+
+const fn bazz(foo: &mut Foo) -> usize {
+ foo.x = 3;
+ foo.x
+}
+
+fn main() {
+ let _: [(); foo().bar()] = [(); 1];
+ let _: [(); baz(&mut foo())] = [(); 2];
+ let _: [(); bazz(&mut foo())] = [(); 3];
+}
diff --git a/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs b/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs
new file mode 100644
index 0000000..2207599
--- /dev/null
+++ b/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs
@@ -0,0 +1,7 @@
+fn main() {
+ foo(&mut 5);
+}
+
+const fn foo(x: &mut i32) -> i32 { //~ ERROR mutable references in const fn are unstable
+ *x + 1
+}
diff --git a/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.stderr b/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.stderr
new file mode 100644
index 0000000..4fae119
--- /dev/null
+++ b/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.stderr
@@ -0,0 +1,12 @@
+error[E0723]: mutable references in const fn are unstable
+ --> $DIR/feature-gate-const_mut_refs.rs:5:14
+ |
+LL | const fn foo(x: &mut i32) -> i32 {
+ | ^
+ |
+ = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+ = help: add `#![feature(const_fn)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0723`.
diff --git a/src/test/ui/consts/const-prop-ice.rs b/src/test/ui/consts/const-prop-ice.rs
index 48c4b7d..13309f9 100644
--- a/src/test/ui/consts/const-prop-ice.rs
+++ b/src/test/ui/consts/const-prop-ice.rs
@@ -1,4 +1,3 @@
fn main() {
[0; 3][3u64 as usize]; //~ ERROR the len is 3 but the index is 3
- //~| ERROR this expression will panic at runtime
}
diff --git a/src/test/ui/consts/const-prop-ice.stderr b/src/test/ui/consts/const-prop-ice.stderr
index 8ecc6f4..4b38801 100644
--- a/src/test/ui/consts/const-prop-ice.stderr
+++ b/src/test/ui/consts/const-prop-ice.stderr
@@ -6,11 +6,5 @@
|
= note: `#[deny(const_err)]` on by default
-error: this expression will panic at runtime
- --> $DIR/const-prop-ice.rs:2:5
- |
-LL | [0; 3][3u64 as usize];
- | ^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the len is 3 but the index is 3
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
diff --git a/src/test/ui/consts/const_let_assign3.stderr b/src/test/ui/consts/const_let_assign3.stderr
index 53b960b..7852874 100644
--- a/src/test/ui/consts/const_let_assign3.stderr
+++ b/src/test/ui/consts/const_let_assign3.stderr
@@ -4,17 +4,23 @@
LL | self.state = x;
| ^^^^^^^^^^^^^^
-error[E0017]: references in constants may only refer to immutable values
+error[E0658]: references in constants may only refer to immutable values
--> $DIR/const_let_assign3.rs:16:5
|
LL | s.foo(3);
| ^ constants require immutable values
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
-error[E0017]: references in constants may only refer to immutable values
+error[E0658]: references in constants may only refer to immutable values
--> $DIR/const_let_assign3.rs:22:13
|
LL | let y = &mut x;
| ^^^^^^ constants require immutable values
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
error[E0019]: constant contains unimplemented expression type
--> $DIR/const_let_assign3.rs:24:5
@@ -24,5 +30,5 @@
error: aborting due to 4 previous errors
-Some errors have detailed explanations: E0017, E0019.
-For more information about an error, try `rustc --explain E0017`.
+Some errors have detailed explanations: E0019, E0658.
+For more information about an error, try `rustc --explain E0019`.
diff --git a/src/test/ui/consts/miri_unleashed/mutable_const.rs b/src/test/ui/consts/miri_unleashed/mutable_const.rs
index 44b4084..972f595 100644
--- a/src/test/ui/consts/miri_unleashed/mutable_const.rs
+++ b/src/test/ui/consts/miri_unleashed/mutable_const.rs
@@ -1,6 +1,7 @@
// compile-flags: -Zunleash-the-miri-inside-of-you
#![feature(const_raw_ptr_deref)]
+#![feature(const_mut_refs)]
#![deny(const_err)]
use std::cell::UnsafeCell;
@@ -12,9 +13,7 @@
const MUTATING_BEHIND_RAW: () = {
// Test that `MUTABLE_BEHIND_RAW` is actually immutable, by doing this at const time.
unsafe {
- *MUTABLE_BEHIND_RAW = 99 //~ WARN skipping const checks
- //~^ ERROR any use of this value will cause an error
- //~^^ tried to modify constant memory
+ *MUTABLE_BEHIND_RAW = 99 //~ ERROR any use of this value will cause an error
}
};
diff --git a/src/test/ui/consts/miri_unleashed/mutable_const.stderr b/src/test/ui/consts/miri_unleashed/mutable_const.stderr
index 757f0ff..9daca76 100644
--- a/src/test/ui/consts/miri_unleashed/mutable_const.stderr
+++ b/src/test/ui/consts/miri_unleashed/mutable_const.stderr
@@ -1,30 +1,23 @@
warning: skipping const checks
- --> $DIR/mutable_const.rs:9:38
+ --> $DIR/mutable_const.rs:10:38
|
LL | const MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _;
| ^^^^^^^^^^^^^^^^^^^^
-warning: skipping const checks
- --> $DIR/mutable_const.rs:15:9
- |
-LL | *MUTABLE_BEHIND_RAW = 99
- | ^^^^^^^^^^^^^^^^^^^^^^^^
-
error: any use of this value will cause an error
- --> $DIR/mutable_const.rs:15:9
+ --> $DIR/mutable_const.rs:16:9
|
LL | / const MUTATING_BEHIND_RAW: () = {
LL | | // Test that `MUTABLE_BEHIND_RAW` is actually immutable, by doing this at const time.
LL | | unsafe {
LL | | *MUTABLE_BEHIND_RAW = 99
| | ^^^^^^^^^^^^^^^^^^^^^^^^ tried to modify constant memory
-... |
LL | | }
LL | | };
| |__-
|
note: lint level defined here
- --> $DIR/mutable_const.rs:4:9
+ --> $DIR/mutable_const.rs:5:9
|
LL | #![deny(const_err)]
| ^^^^^^^^^
diff --git a/src/test/ui/consts/miri_unleashed/mutable_references.rs b/src/test/ui/consts/miri_unleashed/mutable_references.rs
index 59dafcb..fe3c4ee 100644
--- a/src/test/ui/consts/miri_unleashed/mutable_references.rs
+++ b/src/test/ui/consts/miri_unleashed/mutable_references.rs
@@ -1,20 +1,22 @@
// compile-flags: -Zunleash-the-miri-inside-of-you
+#![feature(const_mut_refs)]
#![allow(const_err)]
use std::cell::UnsafeCell;
// a test demonstrating what things we could allow with a smarter const qualification
+// this is fine because is not possible to mutate through an immutable reference.
static FOO: &&mut u32 = &&mut 42;
-//~^ WARN: skipping const checks
+// this is fine because accessing an immutable static `BAR` is equivalent to accessing `*&BAR`
+// which puts the mutable reference behind an immutable one.
static BAR: &mut () = &mut ();
-//~^ WARN: skipping const checks
struct Foo<T>(T);
+// this is fine for the same reason as `BAR`.
static BOO: &mut Foo<()> = &mut Foo(());
-//~^ WARN: skipping const checks
struct Meh {
x: &'static UnsafeCell<i32>,
@@ -27,8 +29,8 @@
//~^ WARN: skipping const checks
};
+// this is fine for the same reason as `BAR`.
static OH_YES: &mut i32 = &mut 42;
-//~^ WARN: skipping const checks
fn main() {
unsafe {
diff --git a/src/test/ui/consts/miri_unleashed/mutable_references.stderr b/src/test/ui/consts/miri_unleashed/mutable_references.stderr
index b9c0af3..3e1300c 100644
--- a/src/test/ui/consts/miri_unleashed/mutable_references.stderr
+++ b/src/test/ui/consts/miri_unleashed/mutable_references.stderr
@@ -1,35 +1,11 @@
warning: skipping const checks
- --> $DIR/mutable_references.rs:8:26
- |
-LL | static FOO: &&mut u32 = &&mut 42;
- | ^^^^^^^
-
-warning: skipping const checks
- --> $DIR/mutable_references.rs:11:23
- |
-LL | static BAR: &mut () = &mut ();
- | ^^^^^^^
-
-warning: skipping const checks
- --> $DIR/mutable_references.rs:16:28
- |
-LL | static BOO: &mut Foo<()> = &mut Foo(());
- | ^^^^^^^^^^^^
-
-warning: skipping const checks
- --> $DIR/mutable_references.rs:26:8
+ --> $DIR/mutable_references.rs:28:8
|
LL | x: &UnsafeCell::new(42),
| ^^^^^^^^^^^^^^^^^^^^
-warning: skipping const checks
- --> $DIR/mutable_references.rs:30:27
- |
-LL | static OH_YES: &mut i32 = &mut 42;
- | ^^^^^^^
-
error[E0594]: cannot assign to `*OH_YES`, as `OH_YES` is an immutable static item
- --> $DIR/mutable_references.rs:37:5
+ --> $DIR/mutable_references.rs:39:5
|
LL | *OH_YES = 99;
| ^^^^^^^^^^^^ cannot assign
diff --git a/src/test/ui/consts/miri_unleashed/read_from_static.rs b/src/test/ui/consts/miri_unleashed/read_from_static.rs
new file mode 100644
index 0000000..821c501
--- /dev/null
+++ b/src/test/ui/consts/miri_unleashed/read_from_static.rs
@@ -0,0 +1,11 @@
+// run-pass
+// compile-flags: -Zunleash-the-miri-inside-of-you
+#![feature(const_mut_refs)]
+#![allow(const_err)]
+
+static OH_YES: &mut i32 = &mut 42;
+
+fn main() {
+ // Make sure `OH_YES` can be read.
+ assert_eq!(*OH_YES, 42);
+}
diff --git a/src/test/ui/consts/projection_qualif.mut_refs.stderr b/src/test/ui/consts/projection_qualif.mut_refs.stderr
new file mode 100644
index 0000000..2353877
--- /dev/null
+++ b/src/test/ui/consts/projection_qualif.mut_refs.stderr
@@ -0,0 +1,12 @@
+error[E0658]: dereferencing raw pointers in constants is unstable
+ --> $DIR/projection_qualif.rs:11:18
+ |
+LL | unsafe { *b = 5; }
+ | ^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/51911
+ = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/projection_qualif.rs b/src/test/ui/consts/projection_qualif.rs
index dedb7db..cfe8e7f 100644
--- a/src/test/ui/consts/projection_qualif.rs
+++ b/src/test/ui/consts/projection_qualif.rs
@@ -1,11 +1,15 @@
+// revisions: stock mut_refs
+
+#![cfg_attr(mut_refs, feature(const_mut_refs))]
+
use std::cell::Cell;
const FOO: &u32 = {
let mut a = 42;
{
- let b: *mut u32 = &mut a; //~ ERROR may only refer to immutable values
+ let b: *mut u32 = &mut a; //[stock]~ ERROR may only refer to immutable values
unsafe { *b = 5; } //~ ERROR dereferencing raw pointers in constants
- //~^ contains unimplemented expression
+ //[stock]~^ contains unimplemented expression
}
&{a}
};
diff --git a/src/test/ui/consts/projection_qualif.stderr b/src/test/ui/consts/projection_qualif.stderr
deleted file mode 100644
index 0efb6bf..0000000
--- a/src/test/ui/consts/projection_qualif.stderr
+++ /dev/null
@@ -1,25 +0,0 @@
-error[E0017]: references in constants may only refer to immutable values
- --> $DIR/projection_qualif.rs:6:27
- |
-LL | let b: *mut u32 = &mut a;
- | ^^^^^^ constants require immutable values
-
-error[E0658]: dereferencing raw pointers in constants is unstable
- --> $DIR/projection_qualif.rs:7:18
- |
-LL | unsafe { *b = 5; }
- | ^^^^^^
- |
- = note: for more information, see https://github.com/rust-lang/rust/issues/51911
- = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable
-
-error[E0019]: constant contains unimplemented expression type
- --> $DIR/projection_qualif.rs:7:18
- |
-LL | unsafe { *b = 5; }
- | ^^^^^^
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0017, E0019, E0658.
-For more information about an error, try `rustc --explain E0017`.
diff --git a/src/test/ui/consts/projection_qualif.stock.stderr b/src/test/ui/consts/projection_qualif.stock.stderr
new file mode 100644
index 0000000..472d260
--- /dev/null
+++ b/src/test/ui/consts/projection_qualif.stock.stderr
@@ -0,0 +1,28 @@
+error[E0658]: references in constants may only refer to immutable values
+ --> $DIR/projection_qualif.rs:10:27
+ |
+LL | let b: *mut u32 = &mut a;
+ | ^^^^^^ constants require immutable values
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
+error[E0658]: dereferencing raw pointers in constants is unstable
+ --> $DIR/projection_qualif.rs:11:18
+ |
+LL | unsafe { *b = 5; }
+ | ^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/51911
+ = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable
+
+error[E0019]: constant contains unimplemented expression type
+ --> $DIR/projection_qualif.rs:11:18
+ |
+LL | unsafe { *b = 5; }
+ | ^^^^^^
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0019, E0658.
+For more information about an error, try `rustc --explain E0019`.
diff --git a/src/test/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr b/src/test/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr
new file mode 100644
index 0000000..b43fbc8
--- /dev/null
+++ b/src/test/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr
@@ -0,0 +1,9 @@
+error[E0080]: could not evaluate static initializer
+ --> $DIR/static_mut_containing_mut_ref2.rs:7:45
+ |
+LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tried to modify a static's initial value from another static's initializer
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/static_mut_containing_mut_ref2.rs b/src/test/ui/consts/static_mut_containing_mut_ref2.rs
index ef378fa..74162fb 100644
--- a/src/test/ui/consts/static_mut_containing_mut_ref2.rs
+++ b/src/test/ui/consts/static_mut_containing_mut_ref2.rs
@@ -1,7 +1,12 @@
+// revisions: stock mut_refs
+
+#![cfg_attr(mut_refs, feature(const_mut_refs))]
+
static mut STDERR_BUFFER_SPACE: u8 = 0;
pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; };
-//~^ ERROR references in statics may only refer to immutable values
-//~| ERROR static contains unimplemented expression type
+//[mut_refs]~^ ERROR could not evaluate static initializer
+//[stock]~^^ ERROR references in statics may only refer to immutable values
+//[stock]~| ERROR static contains unimplemented expression type
fn main() {}
diff --git a/src/test/ui/consts/static_mut_containing_mut_ref2.stderr b/src/test/ui/consts/static_mut_containing_mut_ref2.stderr
deleted file mode 100644
index ca691b0..0000000
--- a/src/test/ui/consts/static_mut_containing_mut_ref2.stderr
+++ /dev/null
@@ -1,16 +0,0 @@
-error[E0017]: references in statics may only refer to immutable values
- --> $DIR/static_mut_containing_mut_ref2.rs:3:46
- |
-LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ statics require immutable values
-
-error[E0019]: static contains unimplemented expression type
- --> $DIR/static_mut_containing_mut_ref2.rs:3:45
- |
-LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0017, E0019.
-For more information about an error, try `rustc --explain E0017`.
diff --git a/src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr b/src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr
new file mode 100644
index 0000000..430cef9
--- /dev/null
+++ b/src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr
@@ -0,0 +1,19 @@
+error[E0658]: references in statics may only refer to immutable values
+ --> $DIR/static_mut_containing_mut_ref2.rs:7:46
+ |
+LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ statics require immutable values
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
+error[E0019]: static contains unimplemented expression type
+ --> $DIR/static_mut_containing_mut_ref2.rs:7:45
+ |
+LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0019, E0658.
+For more information about an error, try `rustc --explain E0019`.
diff --git a/src/test/ui/enum/union-in-enum.rs b/src/test/ui/enum/union-in-enum.rs
new file mode 100644
index 0000000..048913e
--- /dev/null
+++ b/src/test/ui/enum/union-in-enum.rs
@@ -0,0 +1,13 @@
+// This test checks that the union keyword
+// is accepted as the name of an enum variant
+// when not followed by an identifier
+// This special case exists because `union` is a contextual keyword.
+
+#![allow(warnings)]
+
+// check-pass
+
+enum A { union }
+enum B { union {} }
+enum C { union() }
+fn main(){}
diff --git a/src/test/ui/error-codes/E0017.rs b/src/test/ui/error-codes/E0017.rs
index 3bc518c..64be411 100644
--- a/src/test/ui/error-codes/E0017.rs
+++ b/src/test/ui/error-codes/E0017.rs
@@ -2,10 +2,10 @@
const C: i32 = 2;
static mut M: i32 = 3;
-const CR: &'static mut i32 = &mut C; //~ ERROR E0017
-static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017
+const CR: &'static mut i32 = &mut C; //~ ERROR E0658
+static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0658
//~| ERROR E0019
//~| ERROR cannot borrow
-static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017
-static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; //~ ERROR E0017
+static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0658
+static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; //~ ERROR E0658
fn main() {}
diff --git a/src/test/ui/error-codes/E0017.stderr b/src/test/ui/error-codes/E0017.stderr
index 8c8660a..9a87195 100644
--- a/src/test/ui/error-codes/E0017.stderr
+++ b/src/test/ui/error-codes/E0017.stderr
@@ -1,8 +1,11 @@
-error[E0017]: references in constants may only refer to immutable values
+error[E0658]: references in constants may only refer to immutable values
--> $DIR/E0017.rs:5:30
|
LL | const CR: &'static mut i32 = &mut C;
| ^^^^^^ constants require immutable values
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
error[E0019]: static contains unimplemented expression type
--> $DIR/E0017.rs:6:39
@@ -10,11 +13,14 @@
LL | static STATIC_REF: &'static mut i32 = &mut X;
| ^^^^^^
-error[E0017]: references in statics may only refer to immutable values
+error[E0658]: references in statics may only refer to immutable values
--> $DIR/E0017.rs:6:39
|
LL | static STATIC_REF: &'static mut i32 = &mut X;
| ^^^^^^ statics require immutable values
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
error[E0596]: cannot borrow immutable static item `X` as mutable
--> $DIR/E0017.rs:6:39
@@ -22,19 +28,25 @@
LL | static STATIC_REF: &'static mut i32 = &mut X;
| ^^^^^^ cannot borrow as mutable
-error[E0017]: references in statics may only refer to immutable values
+error[E0658]: references in statics may only refer to immutable values
--> $DIR/E0017.rs:9:38
|
LL | static CONST_REF: &'static mut i32 = &mut C;
| ^^^^^^ statics require immutable values
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
-error[E0017]: references in statics may only refer to immutable values
+error[E0658]: references in statics may only refer to immutable values
--> $DIR/E0017.rs:10:52
|
LL | static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M };
| ^^^^^^ statics require immutable values
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
error: aborting due to 6 previous errors
-Some errors have detailed explanations: E0017, E0019, E0596.
-For more information about an error, try `rustc --explain E0017`.
+Some errors have detailed explanations: E0019, E0596, E0658.
+For more information about an error, try `rustc --explain E0019`.
diff --git a/src/test/ui/error-codes/E0388.rs b/src/test/ui/error-codes/E0388.rs
new file mode 100644
index 0000000..5954e34
--- /dev/null
+++ b/src/test/ui/error-codes/E0388.rs
@@ -0,0 +1,10 @@
+static X: i32 = 1;
+const C: i32 = 2;
+
+const CR: &'static mut i32 = &mut C; //~ ERROR E0658
+static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0658
+ //~| ERROR cannot borrow
+ //~| ERROR E0019
+static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0658
+
+fn main() {}
diff --git a/src/test/ui/error-codes/E0388.stderr b/src/test/ui/error-codes/E0388.stderr
new file mode 100644
index 0000000..986307d
--- /dev/null
+++ b/src/test/ui/error-codes/E0388.stderr
@@ -0,0 +1,43 @@
+error[E0658]: references in constants may only refer to immutable values
+ --> $DIR/E0388.rs:4:30
+ |
+LL | const CR: &'static mut i32 = &mut C;
+ | ^^^^^^ constants require immutable values
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
+error[E0019]: static contains unimplemented expression type
+ --> $DIR/E0388.rs:5:39
+ |
+LL | static STATIC_REF: &'static mut i32 = &mut X;
+ | ^^^^^^
+
+error[E0658]: references in statics may only refer to immutable values
+ --> $DIR/E0388.rs:5:39
+ |
+LL | static STATIC_REF: &'static mut i32 = &mut X;
+ | ^^^^^^ statics require immutable values
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
+error[E0596]: cannot borrow immutable static item `X` as mutable
+ --> $DIR/E0388.rs:5:39
+ |
+LL | static STATIC_REF: &'static mut i32 = &mut X;
+ | ^^^^^^ cannot borrow as mutable
+
+error[E0658]: references in statics may only refer to immutable values
+ --> $DIR/E0388.rs:8:38
+ |
+LL | static CONST_REF: &'static mut i32 = &mut C;
+ | ^^^^^^ statics require immutable values
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0019, E0596, E0658.
+For more information about an error, try `rustc --explain E0019`.
diff --git a/src/test/ui/for-loop-while/label_break_value.rs b/src/test/ui/for-loop-while/label_break_value.rs
index eb5be77..18930ac 100644
--- a/src/test/ui/for-loop-while/label_break_value.rs
+++ b/src/test/ui/for-loop-while/label_break_value.rs
@@ -77,7 +77,7 @@
}
// Labeled breaking an outer loop still works
'd: loop {
- 'e: {
+ {
if v == r {
break 'b;
}
diff --git a/src/test/ui/for-loop-while/loop-label-shadowing.rs b/src/test/ui/for-loop-while/loop-label-shadowing.rs
index acb53e2..9bedde6 100644
--- a/src/test/ui/for-loop-while/loop-label-shadowing.rs
+++ b/src/test/ui/for-loop-while/loop-label-shadowing.rs
@@ -5,6 +5,7 @@
fn main() {
let mut foo = Vec::new();
+ #[allow(unused_labels)]
'foo: for i in &[1, 2, 3] {
foo.push(*i);
}
diff --git a/src/test/ui/fully-qualified-type/fully-qualified-type-name4.stderr b/src/test/ui/fully-qualified-type/fully-qualified-type-name4.stderr
index b388f38..ca61fb0 100644
--- a/src/test/ui/fully-qualified-type/fully-qualified-type-name4.stderr
+++ b/src/test/ui/fully-qualified-type/fully-qualified-type-name4.stderr
@@ -4,7 +4,10 @@
LL | fn bar(x: usize) -> Option<usize> {
| ------------- expected `std::option::Option<usize>` because of return type
LL | return x;
- | ^ expected enum `std::option::Option`, found `usize`
+ | ^
+ | |
+ | expected enum `std::option::Option`, found `usize`
+ | help: try using a variant of the expected enum: `Some(x)`
|
= note: expected enum `std::option::Option<usize>`
found type `usize`
diff --git a/src/test/ui/hrtb/hrtb-perfect-forwarding.polonius.stderr b/src/test/ui/hrtb/hrtb-perfect-forwarding.polonius.stderr
new file mode 100644
index 0000000..558d643
--- /dev/null
+++ b/src/test/ui/hrtb/hrtb-perfect-forwarding.polonius.stderr
@@ -0,0 +1,68 @@
+warning: function cannot return without recursing
+ --> $DIR/hrtb-perfect-forwarding.rs:22:1
+ |
+LL | / fn no_hrtb<'b,T>(mut t: T)
+LL | | where T : Bar<&'b isize>
+LL | | {
+LL | | // OK -- `T : Bar<&'b isize>`, and thus the impl above ensures that
+LL | | // `&mut T : Bar<&'b isize>`.
+LL | | no_hrtb(&mut t);
+ | | --------------- recursive call site
+LL | | }
+ | |_^ cannot return without recursing
+ |
+ = note: `#[warn(unconditional_recursion)]` on by default
+ = help: a `loop` may express intention better if this is on purpose
+
+warning: function cannot return without recursing
+ --> $DIR/hrtb-perfect-forwarding.rs:30:1
+ |
+LL | / fn bar_hrtb<T>(mut t: T)
+LL | | where T : for<'b> Bar<&'b isize>
+LL | | {
+LL | | // OK -- `T : for<'b> Bar<&'b isize>`, and thus the impl above
+... |
+LL | | bar_hrtb(&mut t);
+ | | ---------------- recursive call site
+LL | | }
+ | |_^ cannot return without recursing
+ |
+ = help: a `loop` may express intention better if this is on purpose
+
+warning: function cannot return without recursing
+ --> $DIR/hrtb-perfect-forwarding.rs:39:1
+ |
+LL | / fn foo_hrtb_bar_not<'b,T>(mut t: T)
+LL | | where T : for<'a> Foo<&'a isize> + Bar<&'b isize>
+LL | | {
+LL | | // Not OK -- The forwarding impl for `Foo` requires that `Bar` also
+... |
+LL | | foo_hrtb_bar_not(&mut t);
+ | | ------------------------ recursive call site
+LL | | }
+ | |_^ cannot return without recursing
+ |
+ = help: a `loop` may express intention better if this is on purpose
+
+error: higher-ranked subtype error
+ --> $DIR/hrtb-perfect-forwarding.rs:46:5
+ |
+LL | foo_hrtb_bar_not(&mut t);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: function cannot return without recursing
+ --> $DIR/hrtb-perfect-forwarding.rs:49:1
+ |
+LL | / fn foo_hrtb_bar_hrtb<T>(mut t: T)
+LL | | where T : for<'a> Foo<&'a isize> + for<'b> Bar<&'b isize>
+LL | | {
+LL | | // OK -- now we have `T : for<'b> Bar&'b isize>`.
+LL | | foo_hrtb_bar_hrtb(&mut t);
+ | | ------------------------- recursive call site
+LL | | }
+ | |_^ cannot return without recursing
+ |
+ = help: a `loop` may express intention better if this is on purpose
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/hygiene/hygienic-labels-in-let.rs b/src/test/ui/hygiene/hygienic-labels-in-let.rs
index 5d22cf8..491855d 100644
--- a/src/test/ui/hygiene/hygienic-labels-in-let.rs
+++ b/src/test/ui/hygiene/hygienic-labels-in-let.rs
@@ -1,5 +1,6 @@
// run-pass
#![allow(unreachable_code)]
+#![allow(unused_labels)]
// Test that labels injected by macros do not break hygiene. This
// checks cases where the macros invocations are under the rhs of a
diff --git a/src/test/ui/hygiene/hygienic-labels-in-let.stderr b/src/test/ui/hygiene/hygienic-labels-in-let.stderr
index d88470f..4acb34f 100644
--- a/src/test/ui/hygiene/hygienic-labels-in-let.stderr
+++ b/src/test/ui/hygiene/hygienic-labels-in-let.stderr
@@ -1,5 +1,5 @@
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:15:9
+ --> $DIR/hygienic-labels-in-let.rs:16:9
|
LL | 'x: loop { $e }
| ^^ lifetime 'x already in scope
@@ -11,7 +11,7 @@
| ------------------ in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:63:9
+ --> $DIR/hygienic-labels-in-let.rs:64:9
|
LL | 'x: loop {
| -- first declared here
@@ -20,7 +20,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:63:9
+ --> $DIR/hygienic-labels-in-let.rs:64:9
|
LL | 'x: loop { $e }
| -- first declared here
@@ -29,7 +29,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:15:9
+ --> $DIR/hygienic-labels-in-let.rs:16:9
|
LL | 'x: loop { $e }
| ^^ lifetime 'x already in scope
@@ -41,7 +41,7 @@
| ------------------ in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:15:9
+ --> $DIR/hygienic-labels-in-let.rs:16:9
|
LL | 'x: loop { $e }
| ^^
@@ -53,7 +53,7 @@
| ------------------ in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:15:9
+ --> $DIR/hygienic-labels-in-let.rs:16:9
|
LL | 'x: loop { $e }
| ^^ lifetime 'x already in scope
@@ -65,7 +65,7 @@
| ------------------ in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:75:9
+ --> $DIR/hygienic-labels-in-let.rs:76:9
|
LL | 'x: loop {
| -- first declared here
@@ -74,7 +74,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:75:9
+ --> $DIR/hygienic-labels-in-let.rs:76:9
|
LL | 'x: loop { $e }
| -- first declared here
@@ -83,7 +83,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:75:9
+ --> $DIR/hygienic-labels-in-let.rs:76:9
|
LL | 'x: for _ in 0..1 {
| -- first declared here
@@ -92,7 +92,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:75:9
+ --> $DIR/hygienic-labels-in-let.rs:76:9
|
LL | 'x: loop { $e }
| -- first declared here
@@ -101,7 +101,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:26:9
+ --> $DIR/hygienic-labels-in-let.rs:27:9
|
LL | 'x: while 1 + 1 == 2 { $e }
| ^^ lifetime 'x already in scope
@@ -113,7 +113,7 @@
| ---------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:26:9
+ --> $DIR/hygienic-labels-in-let.rs:27:9
|
LL | 'x: loop { $e }
| -- first declared here
@@ -125,7 +125,7 @@
| ---------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:26:9
+ --> $DIR/hygienic-labels-in-let.rs:27:9
|
LL | 'x: while 1 + 1 == 2 { $e }
| ^^ lifetime 'x already in scope
@@ -137,7 +137,7 @@
| ---------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:26:9
+ --> $DIR/hygienic-labels-in-let.rs:27:9
|
LL | 'x: loop { $e }
| -- first declared here
@@ -149,7 +149,7 @@
| ---------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:26:9
+ --> $DIR/hygienic-labels-in-let.rs:27:9
|
LL | 'x: while 1 + 1 == 2 { $e }
| ^^ lifetime 'x already in scope
@@ -161,7 +161,7 @@
| ---------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:89:9
+ --> $DIR/hygienic-labels-in-let.rs:90:9
|
LL | 'x: loop {
| -- first declared here
@@ -170,7 +170,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:89:9
+ --> $DIR/hygienic-labels-in-let.rs:90:9
|
LL | 'x: loop { $e }
| -- first declared here
@@ -179,7 +179,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:89:9
+ --> $DIR/hygienic-labels-in-let.rs:90:9
|
LL | 'x: for _ in 0..1 {
| -- first declared here
@@ -188,7 +188,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:89:9
+ --> $DIR/hygienic-labels-in-let.rs:90:9
|
LL | 'x: loop { $e }
| -- first declared here
@@ -197,7 +197,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:89:9
+ --> $DIR/hygienic-labels-in-let.rs:90:9
|
LL | 'x: for _ in 0..1 {
| -- first declared here
@@ -206,7 +206,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:89:9
+ --> $DIR/hygienic-labels-in-let.rs:90:9
|
LL | 'x: while 1 + 1 == 2 { $e }
| -- first declared here
@@ -215,7 +215,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:38:9
+ --> $DIR/hygienic-labels-in-let.rs:39:9
|
LL | 'x: for _ in 0..1 { $e }
| ^^ lifetime 'x already in scope
@@ -227,7 +227,7 @@
| ----------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:38:9
+ --> $DIR/hygienic-labels-in-let.rs:39:9
|
LL | 'x: loop { $e }
| -- first declared here
@@ -239,7 +239,7 @@
| ----------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:38:9
+ --> $DIR/hygienic-labels-in-let.rs:39:9
|
LL | 'x: for _ in 0..1 { $e }
| ^^ lifetime 'x already in scope
@@ -251,7 +251,7 @@
| ----------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:38:9
+ --> $DIR/hygienic-labels-in-let.rs:39:9
|
LL | 'x: loop { $e }
| -- first declared here
@@ -263,7 +263,7 @@
| ----------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:38:9
+ --> $DIR/hygienic-labels-in-let.rs:39:9
|
LL | 'x: for _ in 0..1 { $e }
| ^^ lifetime 'x already in scope
@@ -275,7 +275,7 @@
| ----------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:38:9
+ --> $DIR/hygienic-labels-in-let.rs:39:9
|
LL | 'x: while 1 + 1 == 2 { $e }
| -- first declared here
@@ -287,7 +287,7 @@
| ----------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:38:9
+ --> $DIR/hygienic-labels-in-let.rs:39:9
|
LL | 'x: for _ in 0..1 { $e }
| ^^ lifetime 'x already in scope
diff --git a/src/test/ui/hygiene/hygienic-labels.rs b/src/test/ui/hygiene/hygienic-labels.rs
index 8eafb4c..c9f494b 100644
--- a/src/test/ui/hygiene/hygienic-labels.rs
+++ b/src/test/ui/hygiene/hygienic-labels.rs
@@ -1,5 +1,6 @@
// run-pass
#![allow(unreachable_code)]
+#![allow(unused_labels)]
// Test that labels injected by macros do not break hygiene.
// Issue #24278: The label/lifetime shadowing checker from #24162
diff --git a/src/test/ui/hygiene/hygienic-labels.stderr b/src/test/ui/hygiene/hygienic-labels.stderr
index 285e903..0833825 100644
--- a/src/test/ui/hygiene/hygienic-labels.stderr
+++ b/src/test/ui/hygiene/hygienic-labels.stderr
@@ -1,5 +1,5 @@
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:12:9
+ --> $DIR/hygienic-labels.rs:13:9
|
LL | 'x: loop { $e }
| ^^ lifetime 'x already in scope
@@ -11,7 +11,7 @@
| ------------------ in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:53:5
+ --> $DIR/hygienic-labels.rs:54:5
|
LL | 'x: for _ in 0..1 {
| -- first declared here
@@ -20,7 +20,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:53:5
+ --> $DIR/hygienic-labels.rs:54:5
|
LL | 'x: loop { $e }
| -- first declared here
@@ -29,7 +29,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:12:9
+ --> $DIR/hygienic-labels.rs:13:9
|
LL | 'x: loop { $e }
| ^^ lifetime 'x already in scope
@@ -41,7 +41,7 @@
| ------------------ in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:12:9
+ --> $DIR/hygienic-labels.rs:13:9
|
LL | 'x: loop { $e }
| ^^
@@ -53,7 +53,7 @@
| ------------------ in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:12:9
+ --> $DIR/hygienic-labels.rs:13:9
|
LL | 'x: loop { $e }
| ^^ lifetime 'x already in scope
@@ -65,7 +65,7 @@
| ------------------ in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:62:5
+ --> $DIR/hygienic-labels.rs:63:5
|
LL | 'x: for _ in 0..1 {
| -- first declared here
@@ -74,7 +74,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:62:5
+ --> $DIR/hygienic-labels.rs:63:5
|
LL | 'x: loop { $e }
| -- first declared here
@@ -83,7 +83,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:62:5
+ --> $DIR/hygienic-labels.rs:63:5
|
LL | 'x: loop {
| -- first declared here
@@ -92,7 +92,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:62:5
+ --> $DIR/hygienic-labels.rs:63:5
|
LL | 'x: loop { $e }
| -- first declared here
@@ -101,7 +101,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:37:9
+ --> $DIR/hygienic-labels.rs:38:9
|
LL | 'x: while 1 + 1 == 2 { $e }
| ^^ lifetime 'x already in scope
@@ -113,7 +113,7 @@
| ------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:37:9
+ --> $DIR/hygienic-labels.rs:38:9
|
LL | 'x: loop { $e }
| -- first declared here
@@ -125,7 +125,7 @@
| ------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:37:9
+ --> $DIR/hygienic-labels.rs:38:9
|
LL | 'x: while 1 + 1 == 2 { $e }
| ^^ lifetime 'x already in scope
@@ -137,7 +137,7 @@
| ------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:37:9
+ --> $DIR/hygienic-labels.rs:38:9
|
LL | 'x: loop { $e }
| -- first declared here
@@ -149,7 +149,7 @@
| ------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:37:9
+ --> $DIR/hygienic-labels.rs:38:9
|
LL | 'x: while 1 + 1 == 2 { $e }
| ^^ lifetime 'x already in scope
@@ -161,7 +161,7 @@
| ------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:72:5
+ --> $DIR/hygienic-labels.rs:73:5
|
LL | 'x: for _ in 0..1 {
| -- first declared here
@@ -170,7 +170,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:72:5
+ --> $DIR/hygienic-labels.rs:73:5
|
LL | 'x: loop { $e }
| -- first declared here
@@ -179,7 +179,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:72:5
+ --> $DIR/hygienic-labels.rs:73:5
|
LL | 'x: loop {
| -- first declared here
@@ -188,7 +188,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:72:5
+ --> $DIR/hygienic-labels.rs:73:5
|
LL | 'x: loop { $e }
| -- first declared here
@@ -197,7 +197,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:72:5
+ --> $DIR/hygienic-labels.rs:73:5
|
LL | 'x: while 1 + 1 == 2 {
| -- first declared here
@@ -206,7 +206,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:72:5
+ --> $DIR/hygienic-labels.rs:73:5
|
LL | 'x: while 1 + 1 == 2 { $e }
| -- first declared here
@@ -215,7 +215,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:23:9
+ --> $DIR/hygienic-labels.rs:24:9
|
LL | 'x: for _ in 0..1 { $e }
| ^^ lifetime 'x already in scope
@@ -227,7 +227,7 @@
| ----------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:23:9
+ --> $DIR/hygienic-labels.rs:24:9
|
LL | 'x: loop { $e }
| -- first declared here
@@ -239,7 +239,7 @@
| ----------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:23:9
+ --> $DIR/hygienic-labels.rs:24:9
|
LL | 'x: for _ in 0..1 { $e }
| ^^ lifetime 'x already in scope
@@ -251,7 +251,7 @@
| ----------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:23:9
+ --> $DIR/hygienic-labels.rs:24:9
|
LL | 'x: loop { $e }
| -- first declared here
@@ -263,7 +263,7 @@
| ----------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:23:9
+ --> $DIR/hygienic-labels.rs:24:9
|
LL | 'x: for _ in 0..1 { $e }
| ^^ lifetime 'x already in scope
@@ -275,7 +275,7 @@
| ----------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:23:9
+ --> $DIR/hygienic-labels.rs:24:9
|
LL | 'x: for _ in 0..1 { $e }
| ^^ lifetime 'x already in scope
@@ -287,7 +287,7 @@
| ----------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:23:9
+ --> $DIR/hygienic-labels.rs:24:9
|
LL | 'x: for _ in 0..1 { $e }
| ^^ lifetime 'x already in scope
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.polonius.stderr b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.polonius.stderr
new file mode 100644
index 0000000..72e8fa3
--- /dev/null
+++ b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.polonius.stderr
@@ -0,0 +1,12 @@
+error: lifetime may not live long enough
+ --> $DIR/error-handling.rs:13:56
+ |
+LL | fn foo<'a, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> {
+ | -- -- lifetime `'b` defined here ^^^^^^^^^ opaque type requires that `'a` must outlive `'b`
+ | |
+ | lifetime `'a` defined here
+ |
+ = help: consider adding the following bound: `'a: 'b`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/issues/issue-17718-const-bad-values.stderr b/src/test/ui/issues/issue-17718-const-bad-values.stderr
index 8d875d3..7e4a62a 100644
--- a/src/test/ui/issues/issue-17718-const-bad-values.stderr
+++ b/src/test/ui/issues/issue-17718-const-bad-values.stderr
@@ -1,8 +1,11 @@
-error[E0017]: references in constants may only refer to immutable values
+error[E0658]: references in constants may only refer to immutable values
--> $DIR/issue-17718-const-bad-values.rs:1:34
|
LL | const C1: &'static mut [usize] = &mut [];
| ^^^^^^^ constants require immutable values
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
error[E0013]: constants cannot refer to statics, use a constant instead
--> $DIR/issue-17718-const-bad-values.rs:5:46
@@ -10,13 +13,16 @@
LL | const C2: &'static mut usize = unsafe { &mut S };
| ^
-error[E0017]: references in constants may only refer to immutable values
+error[E0658]: references in constants may only refer to immutable values
--> $DIR/issue-17718-const-bad-values.rs:5:41
|
LL | const C2: &'static mut usize = unsafe { &mut S };
| ^^^^^^ constants require immutable values
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
error: aborting due to 3 previous errors
-Some errors have detailed explanations: E0013, E0017.
+Some errors have detailed explanations: E0013, E0658.
For more information about an error, try `rustc --explain E0013`.
diff --git a/src/test/ui/issues/issue-2216.rs b/src/test/ui/issues/issue-2216.rs
index fa712ed..ad54107 100644
--- a/src/test/ui/issues/issue-2216.rs
+++ b/src/test/ui/issues/issue-2216.rs
@@ -5,7 +5,7 @@
'foo: loop {
'bar: loop {
- 'quux: loop {
+ loop {
if 1 == 2 {
break 'foo;
}
diff --git a/src/test/ui/issues/issue-46604.rs b/src/test/ui/issues/issue-46604.rs
index 4f1ad38..e1967eb 100644
--- a/src/test/ui/issues/issue-46604.rs
+++ b/src/test/ui/issues/issue-46604.rs
@@ -1,4 +1,4 @@
-static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; //~ ERROR E0017
+static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; //~ ERROR E0658
fn write<T: AsRef<[u8]>>(buffer: T) { }
fn main() {
diff --git a/src/test/ui/issues/issue-46604.stderr b/src/test/ui/issues/issue-46604.stderr
index c72f580..32c7ecb 100644
--- a/src/test/ui/issues/issue-46604.stderr
+++ b/src/test/ui/issues/issue-46604.stderr
@@ -1,8 +1,11 @@
-error[E0017]: references in statics may only refer to immutable values
+error[E0658]: references in statics may only refer to immutable values
--> $DIR/issue-46604.rs:1:25
|
LL | static buf: &mut [u8] = &mut [1u8,2,3,4,5,7];
| ^^^^^^^^^^^^^^^^^^^^ statics require immutable values
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
error[E0594]: cannot assign to `buf[_]`, as `buf` is an immutable static item
--> $DIR/issue-46604.rs:6:5
@@ -12,5 +15,5 @@
error: aborting due to 2 previous errors
-Some errors have detailed explanations: E0017, E0594.
-For more information about an error, try `rustc --explain E0017`.
+Some errors have detailed explanations: E0594, E0658.
+For more information about an error, try `rustc --explain E0594`.
diff --git a/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr b/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr
index aef6dc5..9ca983d 100644
--- a/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr
+++ b/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr
@@ -2,13 +2,18 @@
--> $DIR/issue-51632-try-desugar-incompatible-types.rs:8:5
|
LL | missing_discourses()?
- | ^^^^^^^^^^^^^^^^^^^^-
- | | |
- | | help: try removing this `?`
- | expected enum `std::result::Result`, found `isize`
+ | ^^^^^^^^^^^^^^^^^^^^^ expected enum `std::result::Result`, found `isize`
|
= note: expected enum `std::result::Result<isize, ()>`
found type `isize`
+help: try removing this `?`
+ |
+LL | missing_discourses()
+ | --
+help: try using a variant of the expected enum
+ |
+LL | Ok(missing_discourses()?)
+ |
error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-54348.rs b/src/test/ui/issues/issue-54348.rs
index e7221e2..68d8380 100644
--- a/src/test/ui/issues/issue-54348.rs
+++ b/src/test/ui/issues/issue-54348.rs
@@ -1,7 +1,5 @@
fn main() {
[1][0u64 as usize];
[1][1.5 as usize]; //~ ERROR index out of bounds
- //~| ERROR this expression will panic at runtime
[1][1u64 as usize]; //~ ERROR index out of bounds
- //~| ERROR this expression will panic at runtime
}
diff --git a/src/test/ui/issues/issue-54348.stderr b/src/test/ui/issues/issue-54348.stderr
index 79320ef..fa77bd6 100644
--- a/src/test/ui/issues/issue-54348.stderr
+++ b/src/test/ui/issues/issue-54348.stderr
@@ -6,23 +6,11 @@
|
= note: `#[deny(const_err)]` on by default
-error: this expression will panic at runtime
- --> $DIR/issue-54348.rs:3:5
- |
-LL | [1][1.5 as usize];
- | ^^^^^^^^^^^^^^^^^ index out of bounds: the len is 1 but the index is 1
-
error: index out of bounds: the len is 1 but the index is 1
- --> $DIR/issue-54348.rs:5:5
+ --> $DIR/issue-54348.rs:4:5
|
LL | [1][1u64 as usize];
| ^^^^^^^^^^^^^^^^^^
-error: this expression will panic at runtime
- --> $DIR/issue-54348.rs:5:5
- |
-LL | [1][1u64 as usize];
- | ^^^^^^^^^^^^^^^^^^ index out of bounds: the len is 1 but the index is 1
-
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
diff --git a/src/test/ui/issues/issue-59756.rs b/src/test/ui/issues/issue-59756.rs
index cccae39..d6df059 100644
--- a/src/test/ui/issues/issue-59756.rs
+++ b/src/test/ui/issues/issue-59756.rs
@@ -1,4 +1,8 @@
// run-rustfix
+// ignore-test
+//
+// FIXME: Re-enable this test once we support choosing
+// between multiple mutually exclusive suggestions for the same span
#![allow(warnings)]
diff --git a/src/test/ui/issues/issue-59756.stderr b/src/test/ui/issues/issue-59756.stderr
index 150916c..9066e57 100644
--- a/src/test/ui/issues/issue-59756.stderr
+++ b/src/test/ui/issues/issue-59756.stderr
@@ -2,13 +2,18 @@
--> $DIR/issue-59756.rs:13:5
|
LL | foo()?
- | ^^^^^-
- | | |
- | | help: try removing this `?`
- | expected enum `std::result::Result`, found struct `A`
+ | ^^^^^^ expected enum `std::result::Result`, found struct `A`
|
= note: expected enum `std::result::Result<A, B>`
found struct `A`
+help: try removing this `?`
+ |
+LL | foo()
+ | --
+help: try using a variant of the expected enum
+ |
+LL | Ok(foo()?)
+ |
error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-8460-const.rs b/src/test/ui/issues/issue-8460-const.rs
index 4637814..71e2b58 100644
--- a/src/test/ui/issues/issue-8460-const.rs
+++ b/src/test/ui/issues/issue-8460-const.rs
@@ -23,19 +23,14 @@
//~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
//~^ ERROR attempt to divide by zero
- //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err());
//~^ ERROR attempt to divide by zero
- //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err());
//~^ ERROR attempt to divide by zero
- //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err());
//~^ ERROR attempt to divide by zero
- //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
//~^ ERROR attempt to divide by zero
- //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
//~^ ERROR attempt to calculate the remainder with overflow
//~| ERROR this expression will panic at runtime
@@ -53,17 +48,12 @@
//~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
//~^ ERROR attempt to calculate the remainder with a divisor of zero
- //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
//~^ ERROR attempt to calculate the remainder with a divisor of zero
- //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
//~^ ERROR attempt to calculate the remainder with a divisor of zero
- //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
//~^ ERROR attempt to calculate the remainder with a divisor of zero
- //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
//~^ ERROR attempt to calculate the remainder with a divisor of zero
- //~| ERROR this expression will panic at runtime
}
diff --git a/src/test/ui/issues/issue-8460-const.stderr b/src/test/ui/issues/issue-8460-const.stderr
index 7e5a22e..c6750e6 100644
--- a/src/test/ui/issues/issue-8460-const.stderr
+++ b/src/test/ui/issues/issue-8460-const.stderr
@@ -70,179 +70,119 @@
LL | assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
| ^^^^^^^^^^
-error: this expression will panic at runtime
- --> $DIR/issue-8460-const.rs:24:36
- |
-LL | assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
- | ^^^^^^^^^^ attempt to divide by zero
-
error: attempt to divide by zero
- --> $DIR/issue-8460-const.rs:27:36
+ --> $DIR/issue-8460-const.rs:26:36
|
LL | assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err());
| ^^^^^^^
-error: this expression will panic at runtime
- --> $DIR/issue-8460-const.rs:27:36
- |
-LL | assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err());
- | ^^^^^^^ attempt to divide by zero
-
error: attempt to divide by zero
- --> $DIR/issue-8460-const.rs:30:36
+ --> $DIR/issue-8460-const.rs:28:36
|
LL | assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err());
| ^^^^^^^^
-error: this expression will panic at runtime
+error: attempt to divide by zero
--> $DIR/issue-8460-const.rs:30:36
|
-LL | assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err());
- | ^^^^^^^^ attempt to divide by zero
-
-error: attempt to divide by zero
- --> $DIR/issue-8460-const.rs:33:36
- |
LL | assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err());
| ^^^^^^^^
-error: this expression will panic at runtime
- --> $DIR/issue-8460-const.rs:33:36
- |
-LL | assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err());
- | ^^^^^^^^ attempt to divide by zero
-
error: attempt to divide by zero
- --> $DIR/issue-8460-const.rs:36:36
+ --> $DIR/issue-8460-const.rs:32:36
|
LL | assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
| ^^^^^^^^
-error: this expression will panic at runtime
- --> $DIR/issue-8460-const.rs:36:36
- |
-LL | assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
- | ^^^^^^^^ attempt to divide by zero
-
error: attempt to calculate the remainder with overflow
- --> $DIR/issue-8460-const.rs:39:36
+ --> $DIR/issue-8460-const.rs:34:36
|
LL | assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
| ^^^^^^^^^^^^^^^
error: this expression will panic at runtime
- --> $DIR/issue-8460-const.rs:39:36
+ --> $DIR/issue-8460-const.rs:34:36
|
LL | assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
| ^^^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
error: attempt to calculate the remainder with overflow
- --> $DIR/issue-8460-const.rs:42:36
+ --> $DIR/issue-8460-const.rs:37:36
|
LL | assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
| ^^^^^^^^^^^^
error: this expression will panic at runtime
- --> $DIR/issue-8460-const.rs:42:36
+ --> $DIR/issue-8460-const.rs:37:36
|
LL | assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
| ^^^^^^^^^^^^ attempt to calculate the remainder with overflow
error: attempt to calculate the remainder with overflow
- --> $DIR/issue-8460-const.rs:45:36
+ --> $DIR/issue-8460-const.rs:40:36
|
LL | assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err());
| ^^^^^^^^^^^^^
error: this expression will panic at runtime
- --> $DIR/issue-8460-const.rs:45:36
+ --> $DIR/issue-8460-const.rs:40:36
|
LL | assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err());
| ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
error: attempt to calculate the remainder with overflow
- --> $DIR/issue-8460-const.rs:48:36
+ --> $DIR/issue-8460-const.rs:43:36
|
LL | assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err());
| ^^^^^^^^^^^^^
error: this expression will panic at runtime
- --> $DIR/issue-8460-const.rs:48:36
+ --> $DIR/issue-8460-const.rs:43:36
|
LL | assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err());
| ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
error: attempt to calculate the remainder with overflow
- --> $DIR/issue-8460-const.rs:51:36
+ --> $DIR/issue-8460-const.rs:46:36
|
LL | assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
| ^^^^^^^^^^^^^
error: this expression will panic at runtime
- --> $DIR/issue-8460-const.rs:51:36
+ --> $DIR/issue-8460-const.rs:46:36
|
LL | assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
| ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
error: attempt to calculate the remainder with a divisor of zero
- --> $DIR/issue-8460-const.rs:54:36
+ --> $DIR/issue-8460-const.rs:49:36
|
LL | assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
| ^^^^^^^^^^
-error: this expression will panic at runtime
- --> $DIR/issue-8460-const.rs:54:36
- |
-LL | assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
- | ^^^^^^^^^^ attempt to calculate the remainder with a divisor of zero
-
error: attempt to calculate the remainder with a divisor of zero
- --> $DIR/issue-8460-const.rs:57:36
+ --> $DIR/issue-8460-const.rs:51:36
|
LL | assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
| ^^^^^^^
-error: this expression will panic at runtime
+error: attempt to calculate the remainder with a divisor of zero
+ --> $DIR/issue-8460-const.rs:53:36
+ |
+LL | assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
+ | ^^^^^^^^
+
+error: attempt to calculate the remainder with a divisor of zero
+ --> $DIR/issue-8460-const.rs:55:36
+ |
+LL | assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
+ | ^^^^^^^^
+
+error: attempt to calculate the remainder with a divisor of zero
--> $DIR/issue-8460-const.rs:57:36
|
-LL | assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
- | ^^^^^^^ attempt to calculate the remainder with a divisor of zero
-
-error: attempt to calculate the remainder with a divisor of zero
- --> $DIR/issue-8460-const.rs:60:36
- |
-LL | assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
- | ^^^^^^^^
-
-error: this expression will panic at runtime
- --> $DIR/issue-8460-const.rs:60:36
- |
-LL | assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
- | ^^^^^^^^ attempt to calculate the remainder with a divisor of zero
-
-error: attempt to calculate the remainder with a divisor of zero
- --> $DIR/issue-8460-const.rs:63:36
- |
-LL | assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
- | ^^^^^^^^
-
-error: this expression will panic at runtime
- --> $DIR/issue-8460-const.rs:63:36
- |
-LL | assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
- | ^^^^^^^^ attempt to calculate the remainder with a divisor of zero
-
-error: attempt to calculate the remainder with a divisor of zero
- --> $DIR/issue-8460-const.rs:66:36
- |
LL | assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
| ^^^^^^^^
-error: this expression will panic at runtime
- --> $DIR/issue-8460-const.rs:66:36
- |
-LL | assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
- | ^^^^^^^^ attempt to calculate the remainder with a divisor of zero
-
-error: aborting due to 40 previous errors
+error: aborting due to 30 previous errors
diff --git a/src/test/ui/issues/issue-8460-const2.rs b/src/test/ui/issues/issue-8460-const2.rs
index c3f53e3..723a179 100644
--- a/src/test/ui/issues/issue-8460-const2.rs
+++ b/src/test/ui/issues/issue-8460-const2.rs
@@ -18,19 +18,14 @@
//~^ ERROR attempt to divide with overflow
assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
//~^ ERROR attempt to divide by zero
- //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err());
//~^ ERROR attempt to divide by zero
- //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err());
//~^ ERROR attempt to divide by zero
- //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err());
//~^ ERROR attempt to divide by zero
- //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
//~^ ERROR attempt to divide by zero
- //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
//~^ ERROR attempt to calculate the remainder with overflow
assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
@@ -43,17 +38,12 @@
//~^ ERROR attempt to calculate the remainder with overflow
assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
//~^ ERROR attempt to calculate the remainder with a divisor of zero
- //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
//~^ ERROR attempt to calculate the remainder with a divisor of zero
- //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
//~^ ERROR attempt to calculate the remainder with a divisor of zero
- //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
//~^ ERROR attempt to calculate the remainder with a divisor of zero
- //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
//~^ ERROR attempt to calculate the remainder with a divisor of zero
- //~| ERROR this expression will panic at runtime
}
diff --git a/src/test/ui/issues/issue-8460-const2.stderr b/src/test/ui/issues/issue-8460-const2.stderr
index b688ec1..87b9b2d 100644
--- a/src/test/ui/issues/issue-8460-const2.stderr
+++ b/src/test/ui/issues/issue-8460-const2.stderr
@@ -40,149 +40,89 @@
LL | assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
| ^^^^^^^^^^
-error: this expression will panic at runtime
- --> $DIR/issue-8460-const2.rs:19:36
- |
-LL | assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
- | ^^^^^^^^^^ attempt to divide by zero
-
error: attempt to divide by zero
- --> $DIR/issue-8460-const2.rs:22:36
+ --> $DIR/issue-8460-const2.rs:21:36
|
LL | assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err());
| ^^^^^^^
-error: this expression will panic at runtime
- --> $DIR/issue-8460-const2.rs:22:36
- |
-LL | assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err());
- | ^^^^^^^ attempt to divide by zero
-
error: attempt to divide by zero
- --> $DIR/issue-8460-const2.rs:25:36
+ --> $DIR/issue-8460-const2.rs:23:36
|
LL | assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err());
| ^^^^^^^^
-error: this expression will panic at runtime
+error: attempt to divide by zero
--> $DIR/issue-8460-const2.rs:25:36
|
-LL | assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err());
- | ^^^^^^^^ attempt to divide by zero
-
-error: attempt to divide by zero
- --> $DIR/issue-8460-const2.rs:28:36
- |
LL | assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err());
| ^^^^^^^^
-error: this expression will panic at runtime
- --> $DIR/issue-8460-const2.rs:28:36
- |
-LL | assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err());
- | ^^^^^^^^ attempt to divide by zero
-
error: attempt to divide by zero
- --> $DIR/issue-8460-const2.rs:31:36
+ --> $DIR/issue-8460-const2.rs:27:36
|
LL | assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
| ^^^^^^^^
-error: this expression will panic at runtime
- --> $DIR/issue-8460-const2.rs:31:36
- |
-LL | assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
- | ^^^^^^^^ attempt to divide by zero
-
error: attempt to calculate the remainder with overflow
- --> $DIR/issue-8460-const2.rs:34:36
+ --> $DIR/issue-8460-const2.rs:29:36
|
LL | assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
| ^^^^^^^^^^^^^^^
error: attempt to calculate the remainder with overflow
- --> $DIR/issue-8460-const2.rs:36:36
+ --> $DIR/issue-8460-const2.rs:31:36
|
LL | assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
| ^^^^^^^^^^^^
error: attempt to calculate the remainder with overflow
- --> $DIR/issue-8460-const2.rs:38:36
+ --> $DIR/issue-8460-const2.rs:33:36
|
LL | assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err());
| ^^^^^^^^^^^^^
error: attempt to calculate the remainder with overflow
- --> $DIR/issue-8460-const2.rs:40:36
+ --> $DIR/issue-8460-const2.rs:35:36
|
LL | assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err());
| ^^^^^^^^^^^^^
error: attempt to calculate the remainder with overflow
- --> $DIR/issue-8460-const2.rs:42:36
+ --> $DIR/issue-8460-const2.rs:37:36
|
LL | assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
| ^^^^^^^^^^^^^
error: attempt to calculate the remainder with a divisor of zero
- --> $DIR/issue-8460-const2.rs:44:36
+ --> $DIR/issue-8460-const2.rs:39:36
|
LL | assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
| ^^^^^^^^^^
-error: this expression will panic at runtime
- --> $DIR/issue-8460-const2.rs:44:36
- |
-LL | assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
- | ^^^^^^^^^^ attempt to calculate the remainder with a divisor of zero
-
error: attempt to calculate the remainder with a divisor of zero
- --> $DIR/issue-8460-const2.rs:47:36
+ --> $DIR/issue-8460-const2.rs:41:36
|
LL | assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
| ^^^^^^^
-error: this expression will panic at runtime
+error: attempt to calculate the remainder with a divisor of zero
+ --> $DIR/issue-8460-const2.rs:43:36
+ |
+LL | assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
+ | ^^^^^^^^
+
+error: attempt to calculate the remainder with a divisor of zero
+ --> $DIR/issue-8460-const2.rs:45:36
+ |
+LL | assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
+ | ^^^^^^^^
+
+error: attempt to calculate the remainder with a divisor of zero
--> $DIR/issue-8460-const2.rs:47:36
|
-LL | assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
- | ^^^^^^^ attempt to calculate the remainder with a divisor of zero
-
-error: attempt to calculate the remainder with a divisor of zero
- --> $DIR/issue-8460-const2.rs:50:36
- |
-LL | assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
- | ^^^^^^^^
-
-error: this expression will panic at runtime
- --> $DIR/issue-8460-const2.rs:50:36
- |
-LL | assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
- | ^^^^^^^^ attempt to calculate the remainder with a divisor of zero
-
-error: attempt to calculate the remainder with a divisor of zero
- --> $DIR/issue-8460-const2.rs:53:36
- |
-LL | assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
- | ^^^^^^^^
-
-error: this expression will panic at runtime
- --> $DIR/issue-8460-const2.rs:53:36
- |
-LL | assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
- | ^^^^^^^^ attempt to calculate the remainder with a divisor of zero
-
-error: attempt to calculate the remainder with a divisor of zero
- --> $DIR/issue-8460-const2.rs:56:36
- |
LL | assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
| ^^^^^^^^
-error: this expression will panic at runtime
- --> $DIR/issue-8460-const2.rs:56:36
- |
-LL | assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
- | ^^^^^^^^ attempt to calculate the remainder with a divisor of zero
-
-error: aborting due to 30 previous errors
+error: aborting due to 20 previous errors
diff --git a/src/test/ui/macros/macro-lifetime-used-with-labels.rs b/src/test/ui/macros/macro-lifetime-used-with-labels.rs
index 86a3e9f..2e9da6f 100644
--- a/src/test/ui/macros/macro-lifetime-used-with-labels.rs
+++ b/src/test/ui/macros/macro-lifetime-used-with-labels.rs
@@ -1,6 +1,6 @@
// run-pass
#![allow(stable_features)]
-
+#![allow(unused_labels)]
#![allow(unreachable_code)]
macro_rules! x {
diff --git a/src/test/ui/malformed/malformed-derive-entry.rs b/src/test/ui/malformed/malformed-derive-entry.rs
index a6d8863..77fa2f5 100644
--- a/src/test/ui/malformed/malformed-derive-entry.rs
+++ b/src/test/ui/malformed/malformed-derive-entry.rs
@@ -1,7 +1,11 @@
-#[derive(Copy(Bad))] //~ ERROR expected one of `)`, `,`, or `::`, found `(`
+#[derive(Copy(Bad))]
+//~^ ERROR traits in `#[derive(...)]` don't accept arguments
+//~| ERROR the trait bound
struct Test1;
-#[derive(Copy="bad")] //~ ERROR expected one of `)`, `,`, or `::`, found `=`
+#[derive(Copy="bad")]
+//~^ ERROR traits in `#[derive(...)]` don't accept values
+//~| ERROR the trait bound
struct Test2;
#[derive] //~ ERROR malformed `derive` attribute input
diff --git a/src/test/ui/malformed/malformed-derive-entry.stderr b/src/test/ui/malformed/malformed-derive-entry.stderr
index 8d750b6..1f1ee39 100644
--- a/src/test/ui/malformed/malformed-derive-entry.stderr
+++ b/src/test/ui/malformed/malformed-derive-entry.stderr
@@ -1,20 +1,33 @@
-error: expected one of `)`, `,`, or `::`, found `(`
+error: traits in `#[derive(...)]` don't accept arguments
--> $DIR/malformed-derive-entry.rs:1:14
|
LL | #[derive(Copy(Bad))]
- | ^ expected one of `)`, `,`, or `::`
+ | ^^^^^ help: remove the arguments
-error: expected one of `)`, `,`, or `::`, found `=`
- --> $DIR/malformed-derive-entry.rs:4:14
+error: traits in `#[derive(...)]` don't accept values
+ --> $DIR/malformed-derive-entry.rs:6:14
|
LL | #[derive(Copy="bad")]
- | ^ expected one of `)`, `,`, or `::`
+ | ^^^^^^ help: remove the value
error: malformed `derive` attribute input
- --> $DIR/malformed-derive-entry.rs:7:1
+ --> $DIR/malformed-derive-entry.rs:11:1
|
LL | #[derive]
| ^^^^^^^^^ help: missing traits to be derived: `#[derive(Trait1, Trait2, ...)]`
-error: aborting due to 3 previous errors
+error[E0277]: the trait bound `Test1: std::clone::Clone` is not satisfied
+ --> $DIR/malformed-derive-entry.rs:1:10
+ |
+LL | #[derive(Copy(Bad))]
+ | ^^^^ the trait `std::clone::Clone` is not implemented for `Test1`
+error[E0277]: the trait bound `Test2: std::clone::Clone` is not satisfied
+ --> $DIR/malformed-derive-entry.rs:6:10
+ |
+LL | #[derive(Copy="bad")]
+ | ^^^^ the trait `std::clone::Clone` is not implemented for `Test2`
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/malformed/malformed-meta-delim.rs b/src/test/ui/malformed/malformed-meta-delim.rs
new file mode 100644
index 0000000..5b1614b
--- /dev/null
+++ b/src/test/ui/malformed/malformed-meta-delim.rs
@@ -0,0 +1,11 @@
+fn main() {}
+
+#[allow { foo_lint } ]
+//~^ ERROR wrong meta list delimiters
+//~| HELP the delimiters should be `(` and `)`
+fn delim_brace() {}
+
+#[allow [ foo_lint ] ]
+//~^ ERROR wrong meta list delimiters
+//~| HELP the delimiters should be `(` and `)`
+fn delim_bracket() {}
diff --git a/src/test/ui/malformed/malformed-meta-delim.stderr b/src/test/ui/malformed/malformed-meta-delim.stderr
new file mode 100644
index 0000000..407193d
--- /dev/null
+++ b/src/test/ui/malformed/malformed-meta-delim.stderr
@@ -0,0 +1,24 @@
+error: wrong meta list delimiters
+ --> $DIR/malformed-meta-delim.rs:3:9
+ |
+LL | #[allow { foo_lint } ]
+ | ^^^^^^^^^^^^
+ |
+help: the delimiters should be `(` and `)`
+ |
+LL | #[allow ( foo_lint ) ]
+ | ^ ^
+
+error: wrong meta list delimiters
+ --> $DIR/malformed-meta-delim.rs:8:9
+ |
+LL | #[allow [ foo_lint ] ]
+ | ^^^^^^^^^^^^
+ |
+help: the delimiters should be `(` and `)`
+ |
+LL | #[allow ( foo_lint ) ]
+ | ^ ^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/malformed/malformed-special-attrs.rs b/src/test/ui/malformed/malformed-special-attrs.rs
index e67fbdd..05b7ebe 100644
--- a/src/test/ui/malformed/malformed-special-attrs.rs
+++ b/src/test/ui/malformed/malformed-special-attrs.rs
@@ -1,7 +1,7 @@
#[cfg_attr] //~ ERROR malformed `cfg_attr` attribute
struct S1;
-#[cfg_attr = ""] //~ ERROR expected `(`, found `=`
+#[cfg_attr = ""] //~ ERROR malformed `cfg_attr` attribute
struct S2;
#[derive] //~ ERROR malformed `derive` attribute
diff --git a/src/test/ui/malformed/malformed-special-attrs.stderr b/src/test/ui/malformed/malformed-special-attrs.stderr
index 319c05e..6f535e0 100644
--- a/src/test/ui/malformed/malformed-special-attrs.stderr
+++ b/src/test/ui/malformed/malformed-special-attrs.stderr
@@ -6,11 +6,13 @@
|
= note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
-error: expected `(`, found `=`
- --> $DIR/malformed-special-attrs.rs:4:12
+error: malformed `cfg_attr` attribute input
+ --> $DIR/malformed-special-attrs.rs:4:1
|
LL | #[cfg_attr = ""]
- | ^ expected `(`
+ | ^^^^^^^^^^^^^^^^ help: missing condition and attribute: `#[cfg_attr(condition, attribute, other_attribute, ...)]`
+ |
+ = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
error: malformed `derive` attribute input
--> $DIR/malformed-special-attrs.rs:7:1
diff --git a/src/test/ui/mismatched_types/abridged.stderr b/src/test/ui/mismatched_types/abridged.stderr
index c208187..c731306 100644
--- a/src/test/ui/mismatched_types/abridged.stderr
+++ b/src/test/ui/mismatched_types/abridged.stderr
@@ -26,7 +26,10 @@
LL | fn b() -> Option<Foo> {
| ----------- expected `std::option::Option<Foo>` because of return type
LL | Foo { bar: 1 }
- | ^^^^^^^^^^^^^^ expected enum `std::option::Option`, found struct `Foo`
+ | ^^^^^^^^^^^^^^
+ | |
+ | expected enum `std::option::Option`, found struct `Foo`
+ | help: try using a variant of the expected enum: `Some(Foo { bar: 1 })`
|
= note: expected enum `std::option::Option<Foo>`
found struct `Foo`
@@ -37,7 +40,10 @@
LL | fn c() -> Result<Foo, Bar> {
| ---------------- expected `std::result::Result<Foo, Bar>` because of return type
LL | Foo { bar: 1 }
- | ^^^^^^^^^^^^^^ expected enum `std::result::Result`, found struct `Foo`
+ | ^^^^^^^^^^^^^^
+ | |
+ | expected enum `std::result::Result`, found struct `Foo`
+ | help: try using a variant of the expected enum: `Ok(Foo { bar: 1 })`
|
= note: expected enum `std::result::Result<Foo, Bar>`
found struct `Foo`
diff --git a/src/test/ui/nll/outlives-suggestion-simple.polonius.stderr b/src/test/ui/nll/outlives-suggestion-simple.polonius.stderr
new file mode 100644
index 0000000..8157446
--- /dev/null
+++ b/src/test/ui/nll/outlives-suggestion-simple.polonius.stderr
@@ -0,0 +1,121 @@
+error: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-simple.rs:6:5
+ |
+LL | fn foo1<'a, 'b>(x: &'a usize) -> &'b usize {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | x
+ | ^ returning this value requires that `'a` must outlive `'b`
+ |
+ = help: consider adding the following bound: `'a: 'b`
+
+error: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-simple.rs:10:5
+ |
+LL | fn foo2<'a>(x: &'a usize) -> &'static usize {
+ | -- lifetime `'a` defined here
+LL | x
+ | ^ returning this value requires that `'a` must outlive `'static`
+ |
+ = help: consider replacing `'a` with `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-simple.rs:14:5
+ |
+LL | fn foo3<'a, 'b>(x: &'a usize, y: &'b usize) -> (&'b usize, &'a usize) {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | (x, y)
+ | ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+ |
+ = help: consider adding the following bound: `'a: 'b`
+
+error: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-simple.rs:14:5
+ |
+LL | fn foo3<'a, 'b>(x: &'a usize, y: &'b usize) -> (&'b usize, &'a usize) {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | (x, y)
+ | ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+
+help: `'a` and `'b` must be the same: replace one with the other
+
+error: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-simple.rs:22:5
+ |
+LL | fn foo4<'a, 'b, 'c>(x: &'a usize) -> (&'b usize, &'c usize) {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | (x, x)
+ | ^^^^^^ returning this value requires that `'a` must outlive `'b`
+ |
+ = help: consider adding the following bound: `'a: 'b`
+
+error: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-simple.rs:22:5
+ |
+LL | fn foo4<'a, 'b, 'c>(x: &'a usize) -> (&'b usize, &'c usize) {
+ | -- -- lifetime `'c` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | (x, x)
+ | ^^^^^^ returning this value requires that `'a` must outlive `'c`
+ |
+ = help: consider adding the following bound: `'a: 'c`
+
+error: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-simple.rs:31:9
+ |
+LL | pub fn foo<'a>(x: &'a usize) -> Self {
+ | -- lifetime `'a` defined here
+LL | Foo { x }
+ | ^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+ |
+ = help: consider replacing `'a` with `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-simple.rs:41:9
+ |
+LL | impl<'a> Bar<'a> {
+ | -- lifetime `'a` defined here
+LL | pub fn get<'b>(&self) -> &'b usize {
+ | -- lifetime `'b` defined here
+LL | self.x
+ | ^^^^^^ returning this value requires that `'a` must outlive `'b`
+ |
+ = help: consider adding the following bound: `'a: 'b`
+
+error: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-simple.rs:52:9
+ |
+LL | impl<'a> Baz<'a> {
+ | -- lifetime `'a` defined here
+LL | fn get<'b>(&'b self) -> &'a i32 {
+ | -- lifetime `'b` defined here
+LL | self.x
+ | ^^^^^^ returning this value requires that `'b` must outlive `'a`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+
+error[E0521]: borrowed data escapes outside of function
+ --> $DIR/outlives-suggestion-simple.rs:73:9
+ |
+LL | fn get_bar(&self) -> Bar2 {
+ | -----
+ | |
+ | `self` is declared here, outside of the function body
+ | `self` is a reference that is only valid in the function body
+LL | Bar2::new(&self)
+ | ^^^^^^^^^^^^^^^^ `self` escapes the function body here
+
+error: aborting due to 10 previous errors
+
diff --git a/src/test/ui/nll/polonius/subset-relations.rs b/src/test/ui/nll/polonius/subset-relations.rs
new file mode 100644
index 0000000..3f6f67e
--- /dev/null
+++ b/src/test/ui/nll/polonius/subset-relations.rs
@@ -0,0 +1,30 @@
+// Checks that Polonius can compute cases of universal regions errors:
+// "illegal subset relation errors", cases where analysis finds that
+// two free regions outlive each other, without any evidence that this
+// relation holds.
+
+// ignore-compare-mode-nll
+// compile-flags: -Z borrowck=mir -Zpolonius
+
+// returning `y` requires that `'b: 'a`, but it's not known to be true
+fn missing_subset<'a, 'b>(x: &'a u32, y: &'b u32) -> &'a u32 {
+ y //~ ERROR
+}
+
+// `'b: 'a` is explicitly declared
+fn valid_subset<'a, 'b: 'a>(x: &'a u32, y: &'b u32) -> &'a u32 {
+ y
+}
+
+// because of `x`, it is implied that `'b: 'a` holds
+fn implied_bounds_subset<'a, 'b>(x: &'a &'b mut u32) -> &'a u32 {
+ x
+}
+
+// `'b: 'a` is declared, and `'a: 'c` is known via implied bounds:
+// `'b: 'c` is therefore known to hold transitively
+fn transitively_valid_subset<'a, 'b: 'a, 'c>(x: &'c &'a u32, y: &'b u32) -> &'c u32 {
+ y
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/polonius/subset-relations.stderr b/src/test/ui/nll/polonius/subset-relations.stderr
new file mode 100644
index 0000000..6364510
--- /dev/null
+++ b/src/test/ui/nll/polonius/subset-relations.stderr
@@ -0,0 +1,14 @@
+error: lifetime may not live long enough
+ --> $DIR/subset-relations.rs:11:5
+ |
+LL | fn missing_subset<'a, 'b>(x: &'a u32, y: &'b u32) -> &'a u32 {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | y
+ | ^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/nll/user-annotations/closure-substs.polonius.stderr b/src/test/ui/nll/user-annotations/closure-substs.polonius.stderr
new file mode 100644
index 0000000..d5bcdf6
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/closure-substs.polonius.stderr
@@ -0,0 +1,60 @@
+error: lifetime may not live long enough
+ --> $DIR/closure-substs.rs:8:16
+ |
+LL | fn foo<'a>() {
+ | -- lifetime `'a` defined here
+...
+LL | return x;
+ | ^ returning this value requires that `'a` must outlive `'static`
+ |
+ = help: consider replacing `'a` with `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/closure-substs.rs:15:16
+ |
+LL | |x: &i32| -> &'static i32 {
+ | - let's call the lifetime of this reference `'1`
+LL | return x;
+ | ^ returning this value requires that `'1` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/closure-substs.rs:15:16
+ |
+LL | |x: &i32| -> &'static i32 {
+ | - ------------ return type of closure is &'2 i32
+ | |
+ | let's call the lifetime of this reference `'1`
+LL | return x;
+ | ^ returning this value requires that `'1` must outlive `'2`
+
+error: lifetime may not live long enough
+ --> $DIR/closure-substs.rs:22:9
+ |
+LL | fn bar<'a>() {
+ | -- lifetime `'a` defined here
+...
+LL | b(x);
+ | ^^^^ argument requires that `'a` must outlive `'static`
+ |
+ = help: consider replacing `'a` with `'static`
+
+error[E0521]: borrowed data escapes outside of closure
+ --> $DIR/closure-substs.rs:29:9
+ |
+LL | |x: &i32, b: fn(&'static i32)| {
+ | - `x` is a reference that is only valid in the closure body
+LL | b(x);
+ | ^^^^ `x` escapes the closure body here
+
+error[E0521]: borrowed data escapes outside of closure
+ --> $DIR/closure-substs.rs:29:9
+ |
+LL | |x: &i32, b: fn(&'static i32)| {
+ | - - `b` is declared here, outside of the closure body
+ | |
+ | `x` is a reference that is only valid in the closure body
+LL | b(x);
+ | ^^^^ `x` escapes the closure body here
+
+error: aborting due to 6 previous errors
+
diff --git a/src/test/ui/on-unimplemented/expected-comma-found-token.rs b/src/test/ui/on-unimplemented/expected-comma-found-token.rs
index 77c0ea1..8fb34f2 100644
--- a/src/test/ui/on-unimplemented/expected-comma-found-token.rs
+++ b/src/test/ui/on-unimplemented/expected-comma-found-token.rs
@@ -6,7 +6,7 @@
#[rustc_on_unimplemented(
message="the message"
- label="the label" //~ ERROR expected one of `)` or `,`, found `label`
+ label="the label" //~ ERROR expected `,`, found `label`
)]
trait T {}
diff --git a/src/test/ui/on-unimplemented/expected-comma-found-token.stderr b/src/test/ui/on-unimplemented/expected-comma-found-token.stderr
index 2e1d484..048b72e 100644
--- a/src/test/ui/on-unimplemented/expected-comma-found-token.stderr
+++ b/src/test/ui/on-unimplemented/expected-comma-found-token.stderr
@@ -1,11 +1,8 @@
-error: expected one of `)` or `,`, found `label`
+error: expected `,`, found `label`
--> $DIR/expected-comma-found-token.rs:9:5
|
LL | message="the message"
- | -
- | |
- | expected one of `)` or `,`
- | help: missing `,`
+ | - expected `,`
LL | label="the label"
| ^^^^^ unexpected token
diff --git a/src/test/ui/proc-macro/span-preservation.stderr b/src/test/ui/proc-macro/span-preservation.stderr
index cd6f0ea..a77e920 100644
--- a/src/test/ui/proc-macro/span-preservation.stderr
+++ b/src/test/ui/proc-macro/span-preservation.stderr
@@ -14,6 +14,11 @@
LL | match x {
LL | Some(x) => { return x },
| ^ expected `usize`, found `isize`
+ |
+help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit
+ |
+LL | Some(x) => { return x.try_into().unwrap() },
+ | ^^^^^^^^^^^^^^^^^^^^^
error[E0308]: mismatched types
--> $DIR/span-preservation.rs:33:22
diff --git a/src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs b/src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs
index 1c4d466..0a79aea 100644
--- a/src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs
+++ b/src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs
@@ -1,21 +1,27 @@
// run-pass
-#![feature(core_intrinsics)]
+#![feature(track_caller)]
+
+#[inline(never)]
+#[track_caller]
+fn defeat_const_prop() -> &'static core::panic::Location<'static> {
+ core::panic::Location::caller()
+}
macro_rules! caller_location_from_macro {
- () => (core::intrinsics::caller_location());
+ () => (defeat_const_prop());
}
fn main() {
- let loc = core::intrinsics::caller_location();
+ let loc = defeat_const_prop();
assert_eq!(loc.file(), file!());
- assert_eq!(loc.line(), 10);
+ assert_eq!(loc.line(), 16);
assert_eq!(loc.column(), 15);
- // `caller_location()` in a macro should behave similarly to `file!` and `line!`,
+ // `Location::caller()` in a macro should behave similarly to `file!` and `line!`,
// i.e. point to where the macro was invoked, instead of the macro itself.
let loc2 = caller_location_from_macro!();
assert_eq!(loc2.file(), file!());
- assert_eq!(loc2.line(), 17);
+ assert_eq!(loc2.line(), 23);
assert_eq!(loc2.column(), 16);
}
diff --git a/src/test/ui/rfc-2091-track-caller/const-caller-location.rs b/src/test/ui/rfc-2091-track-caller/const-caller-location.rs
new file mode 100644
index 0000000..0614c52
--- /dev/null
+++ b/src/test/ui/rfc-2091-track-caller/const-caller-location.rs
@@ -0,0 +1,41 @@
+// run-pass
+
+#![feature(const_fn, track_caller)]
+
+use std::panic::Location;
+
+const LOCATION: &Location = Location::caller();
+
+const TRACKED: &Location = tracked();
+#[track_caller]
+const fn tracked() -> &'static Location <'static> {
+ Location::caller()
+}
+
+const NESTED: &Location = nested_location();
+const fn nested_location() -> &'static Location<'static> {
+ Location::caller()
+}
+
+const CONTAINED: &Location = contained();
+const fn contained() -> &'static Location<'static> {
+ tracked()
+}
+
+fn main() {
+ assert_eq!(LOCATION.file(), file!());
+ assert_eq!(LOCATION.line(), 7);
+ assert_eq!(LOCATION.column(), 29);
+
+ assert_eq!(TRACKED.file(), file!());
+ assert_eq!(TRACKED.line(), 9);
+ assert_eq!(TRACKED.column(), 28);
+
+ assert_eq!(NESTED.file(), file!());
+ assert_eq!(NESTED.line(), 17);
+ assert_eq!(NESTED.column(), 5);
+
+ assert_eq!(CONTAINED.file(), file!());
+ assert_eq!(CONTAINED.line(), 22);
+ assert_eq!(CONTAINED.column(), 5);
+}
diff --git a/src/test/ui/rfc-2091-track-caller/error-odd-syntax.rs b/src/test/ui/rfc-2091-track-caller/error-odd-syntax.rs
index d400db8..d656023 100644
--- a/src/test/ui/rfc-2091-track-caller/error-odd-syntax.rs
+++ b/src/test/ui/rfc-2091-track-caller/error-odd-syntax.rs
@@ -1,4 +1,4 @@
-#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
+#![feature(track_caller)]
#[track_caller(1)]
fn f() {}
diff --git a/src/test/ui/rfc-2091-track-caller/error-odd-syntax.stderr b/src/test/ui/rfc-2091-track-caller/error-odd-syntax.stderr
index a53a8ee..8906fa5 100644
--- a/src/test/ui/rfc-2091-track-caller/error-odd-syntax.stderr
+++ b/src/test/ui/rfc-2091-track-caller/error-odd-syntax.stderr
@@ -4,13 +4,5 @@
LL | #[track_caller(1)]
| ^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[track_caller]`
-warning: the feature `track_caller` is incomplete and may cause the compiler to crash
- --> $DIR/error-odd-syntax.rs:1:12
- |
-LL | #![feature(track_caller)]
- | ^^^^^^^^^^^^
- |
- = note: `#[warn(incomplete_features)]` on by default
-
error: aborting due to previous error
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs b/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs
index 162c638..20d2961 100644
--- a/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs
+++ b/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs
@@ -1,6 +1,7 @@
-#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
+#![feature(track_caller)]
-#[track_caller] //~ ERROR Rust ABI is required to use `#[track_caller]`
+#[track_caller]
extern "C" fn f() {}
+//~^^ ERROR `#[track_caller]` requires Rust ABI
fn main() {}
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr b/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr
index ad89b14..2a3a438 100644
--- a/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr
+++ b/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr
@@ -1,12 +1,4 @@
-warning: the feature `track_caller` is incomplete and may cause the compiler to crash
- --> $DIR/error-with-invalid-abi.rs:1:12
- |
-LL | #![feature(track_caller)]
- | ^^^^^^^^^^^^
- |
- = note: `#[warn(incomplete_features)]` on by default
-
-error[E0737]: Rust ABI is required to use `#[track_caller]`
+error[E0737]: `#[track_caller]` requires Rust ABI
--> $DIR/error-with-invalid-abi.rs:3:1
|
LL | #[track_caller]
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-naked.rs b/src/test/ui/rfc-2091-track-caller/error-with-naked.rs
index bbbcec3..dd9e5d0 100644
--- a/src/test/ui/rfc-2091-track-caller/error-with-naked.rs
+++ b/src/test/ui/rfc-2091-track-caller/error-with-naked.rs
@@ -1,4 +1,4 @@
-#![feature(naked_functions, track_caller)] //~ WARN the feature `track_caller` is incomplete
+#![feature(naked_functions, track_caller)]
#[track_caller]
#[naked]
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr b/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr
index 93e6f7a..2f5003c 100644
--- a/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr
+++ b/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr
@@ -1,11 +1,3 @@
-warning: the feature `track_caller` is incomplete and may cause the compiler to crash
- --> $DIR/error-with-naked.rs:1:29
- |
-LL | #![feature(naked_functions, track_caller)]
- | ^^^^^^^^^^^^
- |
- = note: `#[warn(incomplete_features)]` on by default
-
error[E0736]: cannot use `#[track_caller]` with `#[naked]`
--> $DIR/error-with-naked.rs:3:1
|
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.rs b/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.rs
index 4fd768d..ef037ab 100644
--- a/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.rs
+++ b/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.rs
@@ -1,4 +1,4 @@
-#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
+#![feature(track_caller)]
trait Trait {
#[track_caller] //~ ERROR: `#[track_caller]` may not be used on trait methods
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.stderr b/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.stderr
index 72ed6f8..ded721d 100644
--- a/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.stderr
+++ b/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.stderr
@@ -1,11 +1,3 @@
-warning: the feature `track_caller` is incomplete and may cause the compiler to crash
- --> $DIR/error-with-trait-decl.rs:1:12
- |
-LL | #![feature(track_caller)]
- | ^^^^^^^^^^^^
- |
- = note: `#[warn(incomplete_features)]` on by default
-
error[E0738]: `#[track_caller]` may not be used on trait methods
--> $DIR/error-with-trait-decl.rs:4:5
|
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.rs b/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.rs
index 2139ba5..17e4bf4 100644
--- a/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.rs
+++ b/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.rs
@@ -1,4 +1,4 @@
-#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
+#![feature(track_caller)]
trait Trait {
#[track_caller] //~ ERROR: `#[track_caller]` may not be used on trait methods
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.stderr b/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.stderr
index 05689c9..867eb91 100644
--- a/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.stderr
+++ b/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.stderr
@@ -1,11 +1,3 @@
-warning: the feature `track_caller` is incomplete and may cause the compiler to crash
- --> $DIR/error-with-trait-default-impl.rs:1:12
- |
-LL | #![feature(track_caller)]
- | ^^^^^^^^^^^^
- |
- = note: `#[warn(incomplete_features)]` on by default
-
error[E0738]: `#[track_caller]` may not be used on trait methods
--> $DIR/error-with-trait-default-impl.rs:4:5
|
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.rs b/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.rs
index b565e11..75f20f7 100644
--- a/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.rs
+++ b/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.rs
@@ -1,6 +1,6 @@
// check-fail
-#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
+#![feature(track_caller)]
trait Trait {
fn unwrap(&self);
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.stderr b/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.stderr
index 707b367..fafceef 100644
--- a/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.stderr
+++ b/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.stderr
@@ -1,11 +1,3 @@
-warning: the feature `track_caller` is incomplete and may cause the compiler to crash
- --> $DIR/error-with-trait-fn-impl.rs:3:12
- |
-LL | #![feature(track_caller)]
- | ^^^^^^^^^^^^
- |
- = note: `#[warn(incomplete_features)]` on by default
-
error[E0738]: `#[track_caller]` may not be used on trait methods
--> $DIR/error-with-trait-fn-impl.rs:10:5
|
diff --git a/src/test/ui/rfc-2091-track-caller/intrinsic-wrapper.rs b/src/test/ui/rfc-2091-track-caller/intrinsic-wrapper.rs
new file mode 100644
index 0000000..76e62b8
--- /dev/null
+++ b/src/test/ui/rfc-2091-track-caller/intrinsic-wrapper.rs
@@ -0,0 +1,21 @@
+// run-pass
+
+#![feature(track_caller)]
+
+macro_rules! caller_location_from_macro {
+ () => (core::panic::Location::caller());
+}
+
+fn main() {
+ let loc = core::panic::Location::caller();
+ assert_eq!(loc.file(), file!());
+ assert_eq!(loc.line(), 10);
+ assert_eq!(loc.column(), 15);
+
+ // `Location::caller()` in a macro should behave similarly to `file!` and `line!`,
+ // i.e. point to where the macro was invoked, instead of the macro itself.
+ let loc2 = caller_location_from_macro!();
+ assert_eq!(loc2.file(), file!());
+ assert_eq!(loc2.line(), 17);
+ assert_eq!(loc2.column(), 16);
+}
diff --git a/src/test/ui/rfc-2091-track-caller/only-for-fns.rs b/src/test/ui/rfc-2091-track-caller/only-for-fns.rs
index 01ebf13..0fd59b4 100644
--- a/src/test/ui/rfc-2091-track-caller/only-for-fns.rs
+++ b/src/test/ui/rfc-2091-track-caller/only-for-fns.rs
@@ -1,4 +1,4 @@
-#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
+#![feature(track_caller)]
#[track_caller]
struct S;
diff --git a/src/test/ui/rfc-2091-track-caller/only-for-fns.stderr b/src/test/ui/rfc-2091-track-caller/only-for-fns.stderr
index 3301da7..7becb9c 100644
--- a/src/test/ui/rfc-2091-track-caller/only-for-fns.stderr
+++ b/src/test/ui/rfc-2091-track-caller/only-for-fns.stderr
@@ -1,11 +1,3 @@
-warning: the feature `track_caller` is incomplete and may cause the compiler to crash
- --> $DIR/only-for-fns.rs:1:12
- |
-LL | #![feature(track_caller)]
- | ^^^^^^^^^^^^
- |
- = note: `#[warn(incomplete_features)]` on by default
-
error[E0739]: attribute should be applied to function
--> $DIR/only-for-fns.rs:3:1
|
diff --git a/src/test/ui/rfc-2091-track-caller/pass.rs b/src/test/ui/rfc-2091-track-caller/pass.rs
index f2c3f0d..eef83b3 100644
--- a/src/test/ui/rfc-2091-track-caller/pass.rs
+++ b/src/test/ui/rfc-2091-track-caller/pass.rs
@@ -1,5 +1,5 @@
// run-pass
-#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
+#![feature(track_caller)]
#[track_caller]
fn f() {}
diff --git a/src/test/ui/rfc-2091-track-caller/pass.stderr b/src/test/ui/rfc-2091-track-caller/pass.stderr
deleted file mode 100644
index b1fd23a..0000000
--- a/src/test/ui/rfc-2091-track-caller/pass.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-warning: the feature `track_caller` is incomplete and may cause the compiler to crash
- --> $DIR/pass.rs:2:12
- |
-LL | #![feature(track_caller)]
- | ^^^^^^^^^^^^
- |
- = note: `#[warn(incomplete_features)]` on by default
-
diff --git a/src/test/ui/rfc-2091-track-caller/track-caller-attribute.rs b/src/test/ui/rfc-2091-track-caller/track-caller-attribute.rs
new file mode 100644
index 0000000..8436ee5
--- /dev/null
+++ b/src/test/ui/rfc-2091-track-caller/track-caller-attribute.rs
@@ -0,0 +1,40 @@
+// run-pass
+
+#![feature(const_fn, track_caller)]
+
+use std::panic::Location;
+
+#[track_caller]
+fn tracked() -> &'static Location<'static> {
+ Location::caller()
+}
+
+fn nested_intrinsic() -> &'static Location<'static> {
+ Location::caller()
+}
+
+fn nested_tracked() -> &'static Location<'static> {
+ tracked()
+}
+
+fn main() {
+ let location = Location::caller();
+ assert_eq!(location.file(), file!());
+ assert_eq!(location.line(), 21);
+ assert_eq!(location.column(), 20);
+
+ let tracked = tracked();
+ assert_eq!(tracked.file(), file!());
+ assert_eq!(tracked.line(), 26);
+ assert_eq!(tracked.column(), 19);
+
+ let nested = nested_intrinsic();
+ assert_eq!(nested.file(), file!());
+ assert_eq!(nested.line(), 13);
+ assert_eq!(nested.column(), 5);
+
+ let contained = nested_tracked();
+ assert_eq!(contained.file(), file!());
+ assert_eq!(contained.line(), 17);
+ assert_eq!(contained.column(), 5);
+}
diff --git a/src/test/ui/span/macro-ty-params.rs b/src/test/ui/span/macro-ty-params.rs
index b077d59..713b9eb 100644
--- a/src/test/ui/span/macro-ty-params.rs
+++ b/src/test/ui/span/macro-ty-params.rs
@@ -10,5 +10,4 @@
foo::<T>!(); //~ ERROR generic arguments in macro path
foo::<>!(); //~ ERROR generic arguments in macro path
m!(Default<>); //~ ERROR generic arguments in macro path
- //~^ ERROR unexpected generic arguments in path
}
diff --git a/src/test/ui/span/macro-ty-params.stderr b/src/test/ui/span/macro-ty-params.stderr
index 39b3edc..21683b2 100644
--- a/src/test/ui/span/macro-ty-params.stderr
+++ b/src/test/ui/span/macro-ty-params.stderr
@@ -10,17 +10,11 @@
LL | foo::<>!();
| ^^
-error: unexpected generic arguments in path
- --> $DIR/macro-ty-params.rs:12:8
- |
-LL | m!(Default<>);
- | ^^^^^^^^^
-
error: generic arguments in macro path
--> $DIR/macro-ty-params.rs:12:15
|
LL | m!(Default<>);
| ^^
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
diff --git a/src/test/ui/tail-typeck.stderr b/src/test/ui/tail-typeck.stderr
index eeeb258..69f8ffa 100644
--- a/src/test/ui/tail-typeck.stderr
+++ b/src/test/ui/tail-typeck.stderr
@@ -5,6 +5,11 @@
| ----- ^^^ expected `isize`, found `usize`
| |
| expected `isize` because of return type
+ |
+help: you can convert an `usize` to `isize` and panic if the converted value wouldn't fit
+ |
+LL | fn f() -> isize { return g().try_into().unwrap(); }
+ | ^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
diff --git a/src/test/ui/wrong-ret-type.stderr b/src/test/ui/wrong-ret-type.stderr
index 440620f..c1274bd 100644
--- a/src/test/ui/wrong-ret-type.stderr
+++ b/src/test/ui/wrong-ret-type.stderr
@@ -5,6 +5,11 @@
| ----- ^ expected `usize`, found `isize`
| |
| expected `usize` because of return type
+ |
+help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit
+ |
+LL | fn mk_int() -> usize { let i: isize = 3; return i.try_into().unwrap(); }
+ | ^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
diff --git a/src/tools/miri b/src/tools/miri
index a0ba079..048af40 160000
--- a/src/tools/miri
+++ b/src/tools/miri
@@ -1 +1 @@
-Subproject commit a0ba079b6af0f8c07c33dd8af72a51c997e58967
+Subproject commit 048af409232fc2d7f8fbe5469080dc8bb702c498