From 9412a898fa4ed5065a363bd40ad9401469ed3d54 Mon Sep 17 00:00:00 2001
From: Christiaan Dirkx <christiaan@dirkx.email>
Date: Wed, 2 Sep 2020 02:35:14 +0200
Subject: [PATCH 01/34] Stabilize `Poll::is_ready` and `is_pending` as const

Insta-stabilize the methods `is_ready` and `is_pending` of `Poll`.

Possible because of the recent stabilization of const control flow.

Also adds a test for these methods in a const context.
---
 library/core/src/task/poll.rs  |  6 ++++--
 src/test/ui/consts/std/poll.rs | 13 +++++++++++++
 2 files changed, 17 insertions(+), 2 deletions(-)
 create mode 100644 src/test/ui/consts/std/poll.rs

diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs
index 9383e7c45fa55..a789e4e2593ee 100644
--- a/library/core/src/task/poll.rs
+++ b/library/core/src/task/poll.rs
@@ -39,15 +39,17 @@ impl<T> Poll<T> {
 
     /// Returns `true` if this is `Poll::Ready`
     #[inline]
+    #[rustc_const_stable(feature = "const_poll", since = "1.48.0")]
     #[stable(feature = "futures_api", since = "1.36.0")]
-    pub fn is_ready(&self) -> bool {
+    pub const fn is_ready(&self) -> bool {
         matches!(*self, Poll::Ready(_))
     }
 
     /// Returns `true` if this is `Poll::Pending`
     #[inline]
+    #[rustc_const_stable(feature = "const_poll", since = "1.48.0")]
     #[stable(feature = "futures_api", since = "1.36.0")]
-    pub fn is_pending(&self) -> bool {
+    pub const fn is_pending(&self) -> bool {
         !self.is_ready()
     }
 }
diff --git a/src/test/ui/consts/std/poll.rs b/src/test/ui/consts/std/poll.rs
new file mode 100644
index 0000000000000..28f2ace6715fe
--- /dev/null
+++ b/src/test/ui/consts/std/poll.rs
@@ -0,0 +1,13 @@
+// run-pass
+
+use std::task::Poll;
+
+fn main() {
+    const POLL : Poll<usize> = Poll::Pending;
+
+    const IS_READY : bool = POLL.is_ready();
+    assert!(!IS_READY);
+
+    const IS_PENDING : bool = POLL.is_pending();
+    assert!(IS_PENDING);
+}

From ce1d5ed31aff33bbbb116fffabd6107491c464bc Mon Sep 17 00:00:00 2001
From: Christiaan Dirkx <christiaan@dirkx.email>
Date: Fri, 4 Sep 2020 01:04:34 +0200
Subject: [PATCH 02/34] Move const tests for `Poll` to `library\core`

Part of #76268
---
 library/core/tests/lib.rs      |  1 +
 library/core/tests/task.rs     | 14 ++++++++++++++
 src/test/ui/consts/std/poll.rs | 13 -------------
 3 files changed, 15 insertions(+), 13 deletions(-)
 create mode 100644 library/core/tests/task.rs
 delete mode 100644 src/test/ui/consts/std/poll.rs

diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 81e621318e141..2c20259fc5855 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -76,5 +76,6 @@ mod result;
 mod slice;
 mod str;
 mod str_lossy;
+mod task;
 mod time;
 mod tuple;
diff --git a/library/core/tests/task.rs b/library/core/tests/task.rs
new file mode 100644
index 0000000000000..d71fef9e5c87d
--- /dev/null
+++ b/library/core/tests/task.rs
@@ -0,0 +1,14 @@
+use core::task::Poll;
+
+#[test]
+fn poll_const() {
+    // test that the methods of `Poll` are usable in a const context
+
+    const POLL: Poll<usize> = Poll::Pending;
+
+    const IS_READY: bool = POLL.is_ready();
+    assert!(!IS_READY);
+
+    const IS_PENDING: bool = POLL.is_pending();
+    assert!(IS_PENDING);
+}
diff --git a/src/test/ui/consts/std/poll.rs b/src/test/ui/consts/std/poll.rs
deleted file mode 100644
index 28f2ace6715fe..0000000000000
--- a/src/test/ui/consts/std/poll.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-// run-pass
-
-use std::task::Poll;
-
-fn main() {
-    const POLL : Poll<usize> = Poll::Pending;
-
-    const IS_READY : bool = POLL.is_ready();
-    assert!(!IS_READY);
-
-    const IS_PENDING : bool = POLL.is_pending();
-    assert!(IS_PENDING);
-}

From c027844795e427e63ef917ba40c71d0559d88b79 Mon Sep 17 00:00:00 2001
From: Ethan Brierley <ethanboxx@gmail.com>
Date: Tue, 6 Oct 2020 14:06:25 +0100
Subject: [PATCH 03/34] Fill in things needed to stabilize int_error_matching

---
 compiler/rustc_middle/src/lib.rs           |  1 -
 compiler/rustc_middle/src/middle/limits.rs |  8 +--
 library/core/src/num/error.rs              | 33 ++++++------
 library/core/src/num/mod.rs                | 12 ++---
 library/core/tests/lib.rs                  |  1 -
 library/core/tests/nonzero.rs              |  4 +-
 library/core/tests/num/mod.rs              | 63 +++++++++++++---------
 library/std/src/lib.rs                     |  1 -
 library/std/src/num.rs                     |  7 +--
 9 files changed, 66 insertions(+), 64 deletions(-)

diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index fa885ce2e7cdf..37bc1a305b2f8 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -46,7 +46,6 @@
 #![feature(crate_visibility_modifier)]
 #![feature(associated_type_bounds)]
 #![feature(rustc_attrs)]
-#![feature(int_error_matching)]
 #![recursion_limit = "512"]
 
 #[macro_use]
diff --git a/compiler/rustc_middle/src/middle/limits.rs b/compiler/rustc_middle/src/middle/limits.rs
index def9e5ebb527f..6b6df3a303c22 100644
--- a/compiler/rustc_middle/src/middle/limits.rs
+++ b/compiler/rustc_middle/src/middle/limits.rs
@@ -48,10 +48,12 @@ fn update_limit(
                         .unwrap_or(attr.span);
 
                     let error_str = match e.kind() {
-                        IntErrorKind::Overflow => "`limit` is too large",
-                        IntErrorKind::Empty => "`limit` must be a non-negative integer",
+                        IntErrorKind::PosOverflow => "`limit` is too large",
+                        IntErrorKind::Empty | IntErrorKind::OnlySign => {
+                            "`limit` must be a non-negative integer"
+                        }
                         IntErrorKind::InvalidDigit => "not a valid integer",
-                        IntErrorKind::Underflow => bug!("`limit` should never underflow"),
+                        IntErrorKind::NegOverflow => bug!("`limit` should never underflow"),
                         IntErrorKind::Zero => bug!("zero is a valid `limit`"),
                         kind => bug!("unimplemented IntErrorKind variant: {:?}", kind),
                     };
diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs
index aab1715518611..9705226ba243a 100644
--- a/library/core/src/num/error.rs
+++ b/library/core/src/num/error.rs
@@ -77,51 +77,47 @@ pub struct ParseIntError {
 /// # Example
 ///
 /// ```
-/// #![feature(int_error_matching)]
-///
 /// # fn main() {
 /// if let Err(e) = i32::from_str_radix("a12", 10) {
 ///     println!("Failed conversion to i32: {:?}", e.kind());
 /// }
 /// # }
 /// ```
-#[unstable(
-    feature = "int_error_matching",
-    reason = "it can be useful to match errors when making error messages \
-              for integer parsing",
-    issue = "22639"
-)]
+#[stable(feature = "int_error_matching", since = "1.47.0")]
 #[derive(Debug, Clone, PartialEq, Eq)]
 #[non_exhaustive]
 pub enum IntErrorKind {
     /// Value being parsed is empty.
     ///
     /// Among other causes, this variant will be constructed when parsing an empty string.
+    #[stable(feature = "int_error_matching", since = "1.47.0")]
     Empty,
     /// Contains an invalid digit.
     ///
     /// Among other causes, this variant will be constructed when parsing a string that
     /// contains a letter.
+    #[stable(feature = "int_error_matching", since = "1.47.0")]
     InvalidDigit,
     /// Integer is too large to store in target integer type.
-    Overflow,
+    #[stable(feature = "int_error_matching", since = "1.47.0")]
+    PosOverflow,
     /// Integer is too small to store in target integer type.
-    Underflow,
+    #[stable(feature = "int_error_matching", since = "1.47.0")]
+    NegOverflow,
     /// Value was Zero
     ///
     /// This variant will be emitted when the parsing string has a value of zero, which
     /// would be illegal for non-zero types.
+    #[stable(feature = "int_error_matching", since = "1.47.0")]
     Zero,
+    /// The value contains nothing other than signs `+` or `-`.
+    #[stable(feature = "int_error_matching", since = "1.47.0")]
+    OnlySign,
 }
 
 impl ParseIntError {
     /// Outputs the detailed cause of parsing an integer failing.
-    #[unstable(
-        feature = "int_error_matching",
-        reason = "it can be useful to match errors when making error messages \
-                  for integer parsing",
-        issue = "22639"
-    )]
+    #[stable(feature = "int_error_matching", since = "1.47.0")]
     pub fn kind(&self) -> &IntErrorKind {
         &self.kind
     }
@@ -136,9 +132,10 @@ impl ParseIntError {
         match self.kind {
             IntErrorKind::Empty => "cannot parse integer from empty string",
             IntErrorKind::InvalidDigit => "invalid digit found in string",
-            IntErrorKind::Overflow => "number too large to fit in target type",
-            IntErrorKind::Underflow => "number too small to fit in target type",
+            IntErrorKind::PosOverflow => "number too large to fit in target type",
+            IntErrorKind::NegOverflow => "number too small to fit in target type",
             IntErrorKind::Zero => "number would be zero for non-zero type",
+            IntErrorKind::OnlySign => "only signs without digits found in string",
         }
     }
 }
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index 4f64e30ccf84a..67b4b885dd2ec 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -63,7 +63,7 @@ pub use nonzero::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, No
 #[stable(feature = "try_from", since = "1.34.0")]
 pub use error::TryFromIntError;
 
-#[unstable(feature = "int_error_matching", issue = "22639")]
+#[stable(feature = "int_error_matching", since = "1.47.0")]
 pub use error::IntErrorKind;
 
 macro_rules! usize_isize_to_xe_bytes_doc {
@@ -836,7 +836,7 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
     };
 
     if digits.is_empty() {
-        return Err(PIE { kind: Empty });
+        return Err(PIE { kind: OnlySign });
     }
 
     let mut result = T::from_u32(0);
@@ -849,11 +849,11 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
             };
             result = match result.checked_mul(radix) {
                 Some(result) => result,
-                None => return Err(PIE { kind: Overflow }),
+                None => return Err(PIE { kind: PosOverflow }),
             };
             result = match result.checked_add(x) {
                 Some(result) => result,
-                None => return Err(PIE { kind: Overflow }),
+                None => return Err(PIE { kind: PosOverflow }),
             };
         }
     } else {
@@ -865,11 +865,11 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
             };
             result = match result.checked_mul(radix) {
                 Some(result) => result,
-                None => return Err(PIE { kind: Underflow }),
+                None => return Err(PIE { kind: NegOverflow }),
             };
             result = match result.checked_sub(x) {
                 Some(result) => result,
-                None => return Err(PIE { kind: Underflow }),
+                None => return Err(PIE { kind: NegOverflow }),
             };
         }
     }
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index d8b36beb3e085..c128691fa7525 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -37,7 +37,6 @@
 #![feature(try_trait)]
 #![feature(slice_internals)]
 #![feature(slice_partition_dedup)]
-#![feature(int_error_matching)]
 #![feature(array_value_iter)]
 #![feature(iter_partition_in_place)]
 #![feature(iter_is_partitioned)]
diff --git a/library/core/tests/nonzero.rs b/library/core/tests/nonzero.rs
index 825e5e63b59bc..fb1293c99bba9 100644
--- a/library/core/tests/nonzero.rs
+++ b/library/core/tests/nonzero.rs
@@ -135,11 +135,11 @@ fn test_from_str() {
     );
     assert_eq!(
         "-129".parse::<NonZeroI8>().err().map(|e| e.kind().clone()),
-        Some(IntErrorKind::Underflow)
+        Some(IntErrorKind::NegOverflow)
     );
     assert_eq!(
         "257".parse::<NonZeroU8>().err().map(|e| e.kind().clone()),
-        Some(IntErrorKind::Overflow)
+        Some(IntErrorKind::PosOverflow)
     );
 }
 
diff --git a/library/core/tests/num/mod.rs b/library/core/tests/num/mod.rs
index 939f1325c8499..d6f92f25e7846 100644
--- a/library/core/tests/num/mod.rs
+++ b/library/core/tests/num/mod.rs
@@ -2,10 +2,11 @@ use core::cmp::PartialEq;
 use core::convert::{TryFrom, TryInto};
 use core::fmt::Debug;
 use core::marker::Copy;
-use core::num::TryFromIntError;
+use core::num::{IntErrorKind, ParseIntError, TryFromIntError};
 use core::ops::{Add, Div, Mul, Rem, Sub};
 use core::option::Option;
-use core::option::Option::{None, Some};
+use core::option::Option::None;
+use core::str::FromStr;
 
 #[macro_use]
 mod int_macros;
@@ -65,6 +66,14 @@ where
     assert_eq!(ten.rem(two), ten % two);
 }
 
+fn test_parse<T>(num_str: &str, expected: Result<T, IntErrorKind>)
+where
+    T: FromStr<Err = ParseIntError>,
+    Result<T, IntErrorKind>: PartialEq + Debug,
+{
+    assert_eq!(num_str.parse::<T>().map_err(|e| e.kind().clone()), expected)
+}
+
 #[test]
 fn from_str_issue7588() {
     let u: Option<u8> = u8::from_str_radix("1000", 10).ok();
@@ -75,49 +84,51 @@ fn from_str_issue7588() {
 
 #[test]
 fn test_int_from_str_overflow() {
-    assert_eq!("127".parse::<i8>().ok(), Some(127i8));
-    assert_eq!("128".parse::<i8>().ok(), None);
+    test_parse::<i8>("127", Ok(127));
+    test_parse::<i8>("128", Err(IntErrorKind::PosOverflow));
 
-    assert_eq!("-128".parse::<i8>().ok(), Some(-128i8));
-    assert_eq!("-129".parse::<i8>().ok(), None);
+    test_parse::<i8>("-128", Ok(-128));
+    test_parse::<i8>("-129", Err(IntErrorKind::NegOverflow));
 
-    assert_eq!("32767".parse::<i16>().ok(), Some(32_767i16));
-    assert_eq!("32768".parse::<i16>().ok(), None);
+    test_parse::<i16>("32767", Ok(32_767));
+    test_parse::<i16>("32768", Err(IntErrorKind::PosOverflow));
 
-    assert_eq!("-32768".parse::<i16>().ok(), Some(-32_768i16));
-    assert_eq!("-32769".parse::<i16>().ok(), None);
+    test_parse::<i16>("-32768", Ok(-32_768));
+    test_parse::<i16>("-32769", Err(IntErrorKind::NegOverflow));
 
-    assert_eq!("2147483647".parse::<i32>().ok(), Some(2_147_483_647i32));
-    assert_eq!("2147483648".parse::<i32>().ok(), None);
+    test_parse::<i32>("2147483647", Ok(2_147_483_647));
+    test_parse::<i32>("2147483648", Err(IntErrorKind::PosOverflow));
 
-    assert_eq!("-2147483648".parse::<i32>().ok(), Some(-2_147_483_648i32));
-    assert_eq!("-2147483649".parse::<i32>().ok(), None);
+    test_parse::<i32>("-2147483648", Ok(-2_147_483_648));
+    test_parse::<i32>("-2147483649", Err(IntErrorKind::NegOverflow));
 
-    assert_eq!("9223372036854775807".parse::<i64>().ok(), Some(9_223_372_036_854_775_807i64));
-    assert_eq!("9223372036854775808".parse::<i64>().ok(), None);
+    test_parse::<i64>("9223372036854775807", Ok(9_223_372_036_854_775_807));
+    test_parse::<i64>("9223372036854775808", Err(IntErrorKind::PosOverflow));
 
-    assert_eq!("-9223372036854775808".parse::<i64>().ok(), Some(-9_223_372_036_854_775_808i64));
-    assert_eq!("-9223372036854775809".parse::<i64>().ok(), None);
+    test_parse::<i64>("-9223372036854775808", Ok(-9_223_372_036_854_775_808));
+    test_parse::<i64>("-9223372036854775809", Err(IntErrorKind::NegOverflow));
 }
 
 #[test]
 fn test_leading_plus() {
-    assert_eq!("+127".parse::<u8>().ok(), Some(127));
-    assert_eq!("+9223372036854775807".parse::<i64>().ok(), Some(9223372036854775807));
+    test_parse::<u8>("+127", Ok(127));
+    test_parse::<i64>("+9223372036854775807", Ok(9223372036854775807));
 }
 
 #[test]
 fn test_invalid() {
-    assert_eq!("--129".parse::<i8>().ok(), None);
-    assert_eq!("++129".parse::<i8>().ok(), None);
-    assert_eq!("Съешь".parse::<u8>().ok(), None);
+    test_parse::<i8>("--129", Err(IntErrorKind::InvalidDigit));
+    test_parse::<i8>("++129", Err(IntErrorKind::InvalidDigit));
+    test_parse::<u8>("Съешь", Err(IntErrorKind::InvalidDigit));
+    // is this the correct error here. Maybe need a reapeat sign error here
+    test_parse::<i8>("--", Err(IntErrorKind::InvalidDigit));
 }
 
 #[test]
 fn test_empty() {
-    assert_eq!("-".parse::<i8>().ok(), None);
-    assert_eq!("+".parse::<i8>().ok(), None);
-    assert_eq!("".parse::<u8>().ok(), None);
+    test_parse::<i8>("-", Err(IntErrorKind::OnlySign));
+    test_parse::<i8>("+", Err(IntErrorKind::OnlySign));
+    test_parse::<u8>("", Err(IntErrorKind::Empty));
 }
 
 #[test]
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index ac0075ad129c5..fa23229066cf1 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -264,7 +264,6 @@
 #![feature(global_asm)]
 #![feature(hashmap_internals)]
 #![feature(int_error_internals)]
-#![feature(int_error_matching)]
 #![feature(integer_atomics)]
 #![feature(into_future)]
 #![feature(lang_items)]
diff --git a/library/std/src/num.rs b/library/std/src/num.rs
index 0f1c596268594..ac3b055cdb050 100644
--- a/library/std/src/num.rs
+++ b/library/std/src/num.rs
@@ -22,12 +22,7 @@ pub use core::num::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8,
 #[stable(feature = "nonzero", since = "1.28.0")]
 pub use core::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
 
-#[unstable(
-    feature = "int_error_matching",
-    reason = "it can be useful to match errors when making error messages \
-              for integer parsing",
-    issue = "22639"
-)]
+#[stable(feature = "int_error_matching", since = "1.47.0")]
 pub use core::num::IntErrorKind;
 
 #[cfg(test)]

From 83d294f06a8f78f4956333a5285bb2c4f7b8a6a9 Mon Sep 17 00:00:00 2001
From: Ethan Brierley <ethanboxx@gmail.com>
Date: Tue, 6 Oct 2020 19:05:25 +0100
Subject: [PATCH 04/34] Bring char along with InvalidDigit

---
 compiler/rustc_middle/src/middle/limits.rs |  2 +-
 library/core/src/num/error.rs              |  6 +++---
 library/core/src/num/mod.rs                |  4 ++--
 library/core/tests/nonzero.rs              |  2 +-
 library/core/tests/num/mod.rs              | 10 +++++-----
 5 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/compiler/rustc_middle/src/middle/limits.rs b/compiler/rustc_middle/src/middle/limits.rs
index 6b6df3a303c22..f03f439f73b5a 100644
--- a/compiler/rustc_middle/src/middle/limits.rs
+++ b/compiler/rustc_middle/src/middle/limits.rs
@@ -52,7 +52,7 @@ fn update_limit(
                         IntErrorKind::Empty | IntErrorKind::OnlySign => {
                             "`limit` must be a non-negative integer"
                         }
-                        IntErrorKind::InvalidDigit => "not a valid integer",
+                        IntErrorKind::InvalidDigit(_) => "not a valid integer",
                         IntErrorKind::NegOverflow => bug!("`limit` should never underflow"),
                         IntErrorKind::Zero => bug!("zero is a valid `limit`"),
                         kind => bug!("unimplemented IntErrorKind variant: {:?}", kind),
diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs
index 9705226ba243a..ba7c94656ce3f 100644
--- a/library/core/src/num/error.rs
+++ b/library/core/src/num/error.rs
@@ -92,12 +92,12 @@ pub enum IntErrorKind {
     /// Among other causes, this variant will be constructed when parsing an empty string.
     #[stable(feature = "int_error_matching", since = "1.47.0")]
     Empty,
-    /// Contains an invalid digit.
+    /// Contains an digit invalid in its context.
     ///
     /// Among other causes, this variant will be constructed when parsing a string that
     /// contains a letter.
     #[stable(feature = "int_error_matching", since = "1.47.0")]
-    InvalidDigit,
+    InvalidDigit(#[stable(feature = "int_error_matching", since = "1.47.0")] char),
     /// Integer is too large to store in target integer type.
     #[stable(feature = "int_error_matching", since = "1.47.0")]
     PosOverflow,
@@ -131,7 +131,7 @@ impl ParseIntError {
     pub fn __description(&self) -> &str {
         match self.kind {
             IntErrorKind::Empty => "cannot parse integer from empty string",
-            IntErrorKind::InvalidDigit => "invalid digit found in string",
+            IntErrorKind::InvalidDigit(_) => "invalid digit found in string",
             IntErrorKind::PosOverflow => "number too large to fit in target type",
             IntErrorKind::NegOverflow => "number too small to fit in target type",
             IntErrorKind::Zero => "number would be zero for non-zero type",
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index 67b4b885dd2ec..a438f3161a3af 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -845,7 +845,7 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
         for &c in digits {
             let x = match (c as char).to_digit(radix) {
                 Some(x) => x,
-                None => return Err(PIE { kind: InvalidDigit }),
+                None => return Err(PIE { kind: InvalidDigit(c as char) }),
             };
             result = match result.checked_mul(radix) {
                 Some(result) => result,
@@ -861,7 +861,7 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
         for &c in digits {
             let x = match (c as char).to_digit(radix) {
                 Some(x) => x,
-                None => return Err(PIE { kind: InvalidDigit }),
+                None => return Err(PIE { kind: InvalidDigit(c as char) }),
             };
             result = match result.checked_mul(radix) {
                 Some(result) => result,
diff --git a/library/core/tests/nonzero.rs b/library/core/tests/nonzero.rs
index fb1293c99bba9..949d4ea32f064 100644
--- a/library/core/tests/nonzero.rs
+++ b/library/core/tests/nonzero.rs
@@ -131,7 +131,7 @@ fn test_from_str() {
     assert_eq!("0".parse::<NonZeroU8>().err().map(|e| e.kind().clone()), Some(IntErrorKind::Zero));
     assert_eq!(
         "-1".parse::<NonZeroU8>().err().map(|e| e.kind().clone()),
-        Some(IntErrorKind::InvalidDigit)
+        Some(IntErrorKind::InvalidDigit('-'))
     );
     assert_eq!(
         "-129".parse::<NonZeroI8>().err().map(|e| e.kind().clone()),
diff --git a/library/core/tests/num/mod.rs b/library/core/tests/num/mod.rs
index d6f92f25e7846..a93cd38160b58 100644
--- a/library/core/tests/num/mod.rs
+++ b/library/core/tests/num/mod.rs
@@ -117,11 +117,11 @@ fn test_leading_plus() {
 
 #[test]
 fn test_invalid() {
-    test_parse::<i8>("--129", Err(IntErrorKind::InvalidDigit));
-    test_parse::<i8>("++129", Err(IntErrorKind::InvalidDigit));
-    test_parse::<u8>("Съешь", Err(IntErrorKind::InvalidDigit));
-    // is this the correct error here. Maybe need a reapeat sign error here
-    test_parse::<i8>("--", Err(IntErrorKind::InvalidDigit));
+    test_parse::<i8>("--129", Err(IntErrorKind::InvalidDigit('-')));
+    test_parse::<i8>("++129", Err(IntErrorKind::InvalidDigit('+')));
+    test_parse::<u8>("Съешь", Err(IntErrorKind::InvalidDigit('Ð')));
+    test_parse::<u8>("123Hello", Err(IntErrorKind::InvalidDigit('H')));
+    test_parse::<i8>("--", Err(IntErrorKind::InvalidDigit('-')));
 }
 
 #[test]

From 8eaf0de1f45924a0fdbde00d4c7fe0333b377993 Mon Sep 17 00:00:00 2001
From: Ethan Brierley <ethanboxx@gmail.com>
Date: Tue, 6 Oct 2020 21:03:10 +0100
Subject: [PATCH 05/34] Remove incorrect plural

---
 library/core/src/num/error.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs
index ba7c94656ce3f..a8f8a7804fd78 100644
--- a/library/core/src/num/error.rs
+++ b/library/core/src/num/error.rs
@@ -110,7 +110,7 @@ pub enum IntErrorKind {
     /// would be illegal for non-zero types.
     #[stable(feature = "int_error_matching", since = "1.47.0")]
     Zero,
-    /// The value contains nothing other than signs `+` or `-`.
+    /// The value contains nothing other than sign `+` or `-`.
     #[stable(feature = "int_error_matching", since = "1.47.0")]
     OnlySign,
 }
@@ -135,7 +135,7 @@ impl ParseIntError {
             IntErrorKind::PosOverflow => "number too large to fit in target type",
             IntErrorKind::NegOverflow => "number too small to fit in target type",
             IntErrorKind::Zero => "number would be zero for non-zero type",
-            IntErrorKind::OnlySign => "only signs without digits found in string",
+            IntErrorKind::OnlySign => "only sign without digits found in string",
         }
     }
 }

From 1e7e2e40e4992a82b9e5bc7120bd33964bcef355 Mon Sep 17 00:00:00 2001
From: Ethan Brierley <ethanboxx@gmail.com>
Date: Tue, 6 Oct 2020 22:42:33 +0100
Subject: [PATCH 06/34] remove OnlySign in favour of InvalidDigit

---
 compiler/rustc_middle/src/middle/limits.rs | 4 +---
 library/core/src/num/error.rs              | 9 ++++-----
 library/core/src/num/mod.rs                | 7 +++----
 library/core/tests/num/mod.rs              | 5 +++--
 4 files changed, 11 insertions(+), 14 deletions(-)

diff --git a/compiler/rustc_middle/src/middle/limits.rs b/compiler/rustc_middle/src/middle/limits.rs
index f03f439f73b5a..e0d171fa77125 100644
--- a/compiler/rustc_middle/src/middle/limits.rs
+++ b/compiler/rustc_middle/src/middle/limits.rs
@@ -49,9 +49,7 @@ fn update_limit(
 
                     let error_str = match e.kind() {
                         IntErrorKind::PosOverflow => "`limit` is too large",
-                        IntErrorKind::Empty | IntErrorKind::OnlySign => {
-                            "`limit` must be a non-negative integer"
-                        }
+                        IntErrorKind::Empty => "`limit` must be a non-negative integer",
                         IntErrorKind::InvalidDigit(_) => "not a valid integer",
                         IntErrorKind::NegOverflow => bug!("`limit` should never underflow"),
                         IntErrorKind::Zero => bug!("zero is a valid `limit`"),
diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs
index a8f8a7804fd78..401d52eb08481 100644
--- a/library/core/src/num/error.rs
+++ b/library/core/src/num/error.rs
@@ -95,7 +95,10 @@ pub enum IntErrorKind {
     /// Contains an digit invalid in its context.
     ///
     /// Among other causes, this variant will be constructed when parsing a string that
-    /// contains a letter.
+    /// contains a non-asci char.
+    ///
+    /// This variant is also constructed when a `+` or `-` is misplaced within a sting
+    /// either on its own or in the middle of a number.
     #[stable(feature = "int_error_matching", since = "1.47.0")]
     InvalidDigit(#[stable(feature = "int_error_matching", since = "1.47.0")] char),
     /// Integer is too large to store in target integer type.
@@ -110,9 +113,6 @@ pub enum IntErrorKind {
     /// would be illegal for non-zero types.
     #[stable(feature = "int_error_matching", since = "1.47.0")]
     Zero,
-    /// The value contains nothing other than sign `+` or `-`.
-    #[stable(feature = "int_error_matching", since = "1.47.0")]
-    OnlySign,
 }
 
 impl ParseIntError {
@@ -135,7 +135,6 @@ impl ParseIntError {
             IntErrorKind::PosOverflow => "number too large to fit in target type",
             IntErrorKind::NegOverflow => "number too small to fit in target type",
             IntErrorKind::Zero => "number would be zero for non-zero type",
-            IntErrorKind::OnlySign => "only sign without digits found in string",
         }
     }
 }
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index a438f3161a3af..fd00a072d896c 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -830,15 +830,14 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
     let src = src.as_bytes();
 
     let (is_positive, digits) = match src[0] {
+        b'+' | b'-' if src[1..].is_empty() => {
+            return Err(PIE { kind: InvalidDigit(src[0] as char) });
+        }
         b'+' => (true, &src[1..]),
         b'-' if is_signed_ty => (false, &src[1..]),
         _ => (true, src),
     };
 
-    if digits.is_empty() {
-        return Err(PIE { kind: OnlySign });
-    }
-
     let mut result = T::from_u32(0);
     if is_positive {
         // The number is positive
diff --git a/library/core/tests/num/mod.rs b/library/core/tests/num/mod.rs
index a93cd38160b58..4fd9f721b823b 100644
--- a/library/core/tests/num/mod.rs
+++ b/library/core/tests/num/mod.rs
@@ -122,12 +122,13 @@ fn test_invalid() {
     test_parse::<u8>("Съешь", Err(IntErrorKind::InvalidDigit('Ð')));
     test_parse::<u8>("123Hello", Err(IntErrorKind::InvalidDigit('H')));
     test_parse::<i8>("--", Err(IntErrorKind::InvalidDigit('-')));
+    test_parse::<i8>("-", Err(IntErrorKind::InvalidDigit('-')));
+    test_parse::<i8>("+", Err(IntErrorKind::InvalidDigit('+')));
+    test_parse::<u8>("-1", Err(IntErrorKind::InvalidDigit('-')));
 }
 
 #[test]
 fn test_empty() {
-    test_parse::<i8>("-", Err(IntErrorKind::OnlySign));
-    test_parse::<i8>("+", Err(IntErrorKind::OnlySign));
     test_parse::<u8>("", Err(IntErrorKind::Empty));
 }
 

From f233abb9091e3c0999f0cb80ba652d6094e3d5b4 Mon Sep 17 00:00:00 2001
From: Ethan Brierley <ethanboxx@gmail.com>
Date: Wed, 7 Oct 2020 08:02:36 +0100
Subject: [PATCH 07/34] Add comment to helper function

---
 library/core/tests/num/mod.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/library/core/tests/num/mod.rs b/library/core/tests/num/mod.rs
index 4fd9f721b823b..12e52252278c5 100644
--- a/library/core/tests/num/mod.rs
+++ b/library/core/tests/num/mod.rs
@@ -66,6 +66,7 @@ where
     assert_eq!(ten.rem(two), ten % two);
 }
 
+/// Helper function for asserting number parsing returns a specific error
 fn test_parse<T>(num_str: &str, expected: Result<T, IntErrorKind>)
 where
     T: FromStr<Err = ParseIntError>,

From 91a9f83dd1d73cfd451f81306361df3fafad84a5 Mon Sep 17 00:00:00 2001
From: Dan Gohman <dev@sunfishcode.online>
Date: Fri, 16 Oct 2020 09:09:20 -0700
Subject: [PATCH 08/34] Define `fs::hard_link` to not follow symlinks.

POSIX leaves it implementation-defined whether `link` follows symlinks.
In practice, for example, on Linux it does not and on FreeBSD it does.
So, switch to `linkat`, so that we can pick a behavior rather than
depending on OS defaults.

Pick the option to not follow symlinks. This is somewhat arbitrary, but
seems the less surprising choice because hard linking is a very
low-level feature which requires the source and destination to be on
the same mounted filesystem, and following a symbolic link could end
up in a different mounted filesystem.
---
 library/std/src/fs.rs          |  7 +++--
 library/std/src/fs/tests.rs    | 51 ++++++++++++++++++++++++++++++++++
 library/std/src/sys/unix/fs.rs |  5 +++-
 3 files changed, 60 insertions(+), 3 deletions(-)

diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index 161bfe3795c2c..c611bf4d74a49 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -1701,10 +1701,13 @@ pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> {
 /// The `dst` path will be a link pointing to the `src` path. Note that systems
 /// often require these two paths to both be located on the same filesystem.
 ///
+/// If `src` names a symbolic link, it is not followed. The created hard link
+/// points to the symbolic link itself.
+///
 /// # Platform-specific behavior
 ///
-/// This function currently corresponds to the `link` function on Unix
-/// and the `CreateHardLink` function on Windows.
+/// This function currently corresponds to the `linkat` function with no flags
+/// on Unix and the `CreateHardLink` function on Windows.
 /// Note that, this [may change in the future][changes].
 ///
 /// [changes]: io#platform-specific-behavior
diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs
index 65a29076fefa8..8a723d3b4ae22 100644
--- a/library/std/src/fs/tests.rs
+++ b/library/std/src/fs/tests.rs
@@ -1337,3 +1337,54 @@ fn metadata_access_times() {
         }
     }
 }
+
+/// Test creating hard links to symlinks.
+#[test]
+fn symlink_hard_link() {
+    let tmpdir = tmpdir();
+
+    // Create "file", a file.
+    check!(fs::File::create(tmpdir.join("file")));
+
+    // Create "symlink", a symlink to "file".
+    check!(symlink_file("file", tmpdir.join("symlink")));
+
+    // Create "hard_link", a hard link to "symlink".
+    check!(fs::hard_link(tmpdir.join("symlink"), tmpdir.join("hard_link")));
+
+    // "hard_link" should appear as a symlink.
+    assert!(check!(fs::symlink_metadata(tmpdir.join("hard_link"))).file_type().is_symlink());
+
+    // We sould be able to open "file" via any of the above names.
+    let _ = check!(fs::File::open(tmpdir.join("file")));
+    assert!(fs::File::open(tmpdir.join("file.renamed")).is_err());
+    let _ = check!(fs::File::open(tmpdir.join("symlink")));
+    let _ = check!(fs::File::open(tmpdir.join("hard_link")));
+
+    // Rename "file" to "file.renamed".
+    check!(fs::rename(tmpdir.join("file"), tmpdir.join("file.renamed")));
+
+    // Now, the symlink and the hard link should be dangling.
+    assert!(fs::File::open(tmpdir.join("file")).is_err());
+    let _ = check!(fs::File::open(tmpdir.join("file.renamed")));
+    assert!(fs::File::open(tmpdir.join("symlink")).is_err());
+    assert!(fs::File::open(tmpdir.join("hard_link")).is_err());
+
+    // The symlink and the hard link should both still point to "file".
+    assert!(fs::read_link(tmpdir.join("file")).is_err());
+    assert!(fs::read_link(tmpdir.join("file.renamed")).is_err());
+    assert_eq!(check!(fs::read_link(tmpdir.join("symlink"))), Path::new("file"));
+    assert_eq!(check!(fs::read_link(tmpdir.join("hard_link"))), Path::new("file"));
+
+    // Remove "file.renamed".
+    check!(fs::remove_file(tmpdir.join("file.renamed")));
+
+    // Now, we can't open the file by any name.
+    assert!(fs::File::open(tmpdir.join("file")).is_err());
+    assert!(fs::File::open(tmpdir.join("file.renamed")).is_err());
+    assert!(fs::File::open(tmpdir.join("symlink")).is_err());
+    assert!(fs::File::open(tmpdir.join("hard_link")).is_err());
+
+    // "hard_link" should still appear as a symlink.
+    assert!(check!(fs::symlink_metadata(tmpdir.join("hard_link"))).file_type().is_symlink());
+}
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index 819e8ef18415b..88693e4786c0f 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -1067,7 +1067,10 @@ pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> {
 pub fn link(src: &Path, dst: &Path) -> io::Result<()> {
     let src = cstr(src)?;
     let dst = cstr(dst)?;
-    cvt(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) })?;
+    // Use `linkat` with `AT_FDCWD` instead of `link` as `link` leaves it
+    // implmentation-defined whether it follows symlinks. Pass 0 as the
+    // `linkat` flags argument so that we don't follow symlinks.
+    cvt(unsafe { libc::linkat(libc::AT_FDCWD, src.as_ptr(), libc::AT_FDCWD, dst.as_ptr(), 0) })?;
     Ok(())
 }
 

From 5e80c65102f85700e1a449847dfa603e589df950 Mon Sep 17 00:00:00 2001
From: CDirkx <christiaan@dirkx.email>
Date: Fri, 16 Oct 2020 21:29:21 +0200
Subject: [PATCH 09/34] Bump version to 1.49.0

Due to the recent release of 1.47.0, this PR will be stabilized in 1.49.0 instead of 1.48.0.
---
 library/core/src/task/poll.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs
index a789e4e2593ee..dc405465f5d36 100644
--- a/library/core/src/task/poll.rs
+++ b/library/core/src/task/poll.rs
@@ -39,7 +39,7 @@ impl<T> Poll<T> {
 
     /// Returns `true` if this is `Poll::Ready`
     #[inline]
-    #[rustc_const_stable(feature = "const_poll", since = "1.48.0")]
+    #[rustc_const_stable(feature = "const_poll", since = "1.49.0")]
     #[stable(feature = "futures_api", since = "1.36.0")]
     pub const fn is_ready(&self) -> bool {
         matches!(*self, Poll::Ready(_))
@@ -47,7 +47,7 @@ impl<T> Poll<T> {
 
     /// Returns `true` if this is `Poll::Pending`
     #[inline]
-    #[rustc_const_stable(feature = "const_poll", since = "1.48.0")]
+    #[rustc_const_stable(feature = "const_poll", since = "1.49.0")]
     #[stable(feature = "futures_api", since = "1.36.0")]
     pub const fn is_pending(&self) -> bool {
         !self.is_ready()

From 23a5c214150f462043ab411f87ef297309421d71 Mon Sep 17 00:00:00 2001
From: Dan Gohman <dev@sunfishcode.online>
Date: Mon, 19 Oct 2020 07:21:41 -0700
Subject: [PATCH 10/34] Fix a typo in a comment.

---
 library/std/src/sys/unix/fs.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index 88693e4786c0f..69f6b88a3bc56 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -1068,7 +1068,7 @@ pub fn link(src: &Path, dst: &Path) -> io::Result<()> {
     let src = cstr(src)?;
     let dst = cstr(dst)?;
     // Use `linkat` with `AT_FDCWD` instead of `link` as `link` leaves it
-    // implmentation-defined whether it follows symlinks. Pass 0 as the
+    // implementation-defined whether it follows symlinks. Pass 0 as the
     // `linkat` flags argument so that we don't follow symlinks.
     cvt(unsafe { libc::linkat(libc::AT_FDCWD, src.as_ptr(), libc::AT_FDCWD, dst.as_ptr(), 0) })?;
     Ok(())

From ce00b3e2e0c5c0c88fe59fb45a1c25a8ff9e1836 Mon Sep 17 00:00:00 2001
From: Dan Gohman <dev@sunfishcode.online>
Date: Mon, 19 Oct 2020 07:47:32 -0700
Subject: [PATCH 11/34] Use `link` on platforms which lack `linkat`.

---
 library/std/src/sys/unix/fs.rs | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index 69f6b88a3bc56..bf4c941928719 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -1067,10 +1067,20 @@ pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> {
 pub fn link(src: &Path, dst: &Path) -> io::Result<()> {
     let src = cstr(src)?;
     let dst = cstr(dst)?;
-    // Use `linkat` with `AT_FDCWD` instead of `link` as `link` leaves it
-    // implementation-defined whether it follows symlinks. Pass 0 as the
-    // `linkat` flags argument so that we don't follow symlinks.
-    cvt(unsafe { libc::linkat(libc::AT_FDCWD, src.as_ptr(), libc::AT_FDCWD, dst.as_ptr(), 0) })?;
+    cfg_if::cfg_if! {
+        if #[cfg(any(target_os = "vxworks", target_os = "redox"))] {
+            // VxWorks and Redox lack `linkat`, so use `link` instead. POSIX
+            // leaves it implementation-defined whether `link` follows symlinks,
+            // so rely on the `symlink_hard_link` test in
+            // library/std/src/fs/tests.rs to check the behavior.
+            cvt(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) })?;
+        } else {
+            // Use `linkat` with `AT_FDCWD` instead of `link` as `linkat` gives
+            // us a flag to specify how symlinks should be handled. Pass 0 as
+            // the flags argument, meaning don't follow symlinks.
+            cvt(unsafe { libc::linkat(libc::AT_FDCWD, src.as_ptr(), libc::AT_FDCWD, dst.as_ptr(), 0) })?;
+        }
+    }
     Ok(())
 }
 

From 628fb9ff4a36c706789980276c165c4f013780cf Mon Sep 17 00:00:00 2001
From: Tshepang Lekhonkhobe <tshepang@gmail.com>
Date: Wed, 21 Oct 2020 04:44:59 +0200
Subject: [PATCH 12/34] make concurrency helper more pleasant to read

---
 library/test/src/helpers/concurrency.rs | 18 +++++++-----------
 1 file changed, 7 insertions(+), 11 deletions(-)

diff --git a/library/test/src/helpers/concurrency.rs b/library/test/src/helpers/concurrency.rs
index 7e9bd50f5566e..c39a9b0ec0233 100644
--- a/library/test/src/helpers/concurrency.rs
+++ b/library/test/src/helpers/concurrency.rs
@@ -1,18 +1,14 @@
 //! Helper module which helps to determine amount of threads to be used
 //! during tests execution.
-use std::env;
-use std::thread;
+use std::{env, num::NonZeroUsize, thread};
 
-#[allow(deprecated)]
 pub fn get_concurrency() -> usize {
-    match env::var("RUST_TEST_THREADS") {
-        Ok(s) => {
-            let opt_n: Option<usize> = s.parse().ok();
-            match opt_n {
-                Some(n) if n > 0 => n,
-                _ => panic!("RUST_TEST_THREADS is `{}`, should be a positive integer.", s),
-            }
+    if let Ok(value) = env::var("RUST_TEST_THREADS") {
+        match value.parse::<NonZeroUsize>().ok() {
+            Some(n) => n.get(),
+            _ => panic!("RUST_TEST_THREADS is `{}`, should be a positive integer.", value),
         }
-        Err(..) => thread::available_concurrency().map(|n| n.get()).unwrap_or(1),
+    } else {
+        thread::available_concurrency().map(|n| n.get()).unwrap_or(1)
     }
 }

From d0178b4f99c70d2443f9b76421429d0d23dadc45 Mon Sep 17 00:00:00 2001
From: Dan Gohman <dev@sunfishcode.online>
Date: Tue, 20 Oct 2020 16:42:31 -0700
Subject: [PATCH 13/34] Make it platform-specific whether `hard_link` follows
 symlinks.

Also mention that where possible, `hard_link` does not follow symlinks.
---
 library/std/src/fs.rs | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index c611bf4d74a49..c256f556b3c8f 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -1701,8 +1701,9 @@ pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> {
 /// The `dst` path will be a link pointing to the `src` path. Note that systems
 /// often require these two paths to both be located on the same filesystem.
 ///
-/// If `src` names a symbolic link, it is not followed. The created hard link
-/// points to the symbolic link itself.
+/// If `src` names a symbolic link, it is platform-specific whether the symbolic
+/// link is followed. On platforms where it's possible to not follow it, it is
+/// not followed, and the created hard link points to the symbolic link itself.
 ///
 /// # Platform-specific behavior
 ///

From 6249cda78f0cd32b60fb11702b7ffef3e3bab0b2 Mon Sep 17 00:00:00 2001
From: Dan Gohman <dev@sunfishcode.online>
Date: Fri, 23 Oct 2020 15:39:02 -0700
Subject: [PATCH 14/34] Disable use of `linkat` on Android as well.

According to [the bionic status page], `linkat` has only been available
since API level 21. Since Android is based on Linux and Linux's `link`
doesn't follow symlinks, just use `link` on Android.

[the bionic status page]: https://android.googlesource.com/platform/bionic/+/master/docs/status.md
---
 library/std/src/sys/unix/fs.rs | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index bf4c941928719..ec721fccaa622 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -1068,11 +1068,11 @@ pub fn link(src: &Path, dst: &Path) -> io::Result<()> {
     let src = cstr(src)?;
     let dst = cstr(dst)?;
     cfg_if::cfg_if! {
-        if #[cfg(any(target_os = "vxworks", target_os = "redox"))] {
-            // VxWorks and Redox lack `linkat`, so use `link` instead. POSIX
-            // leaves it implementation-defined whether `link` follows symlinks,
-            // so rely on the `symlink_hard_link` test in
-            // library/std/src/fs/tests.rs to check the behavior.
+        if #[cfg(any(target_os = "vxworks", target_os = "redox", target_os = "android"))] {
+            // VxWorks, Redox, and old versions of Android lack `linkat`, so use
+            // `link` instead. POSIX leaves it implementation-defined whether
+            // `link` follows symlinks, so rely on the `symlink_hard_link` test
+            // in library/std/src/fs/tests.rs to check the behavior.
             cvt(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) })?;
         } else {
             // Use `linkat` with `AT_FDCWD` instead of `link` as `linkat` gives

From 199c36115f1daa71458e94db0f37ab213d01eb8a Mon Sep 17 00:00:00 2001
From: Ethan Brierley <ethanboxx@gmail.com>
Date: Mon, 26 Oct 2020 05:50:28 -0500
Subject: [PATCH 15/34] Fix spelling eror

Co-authored-by: Ashley Mannix <kodraus@hey.com>
---
 library/core/src/num/error.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs
index 401d52eb08481..91a24e7740ad4 100644
--- a/library/core/src/num/error.rs
+++ b/library/core/src/num/error.rs
@@ -97,7 +97,7 @@ pub enum IntErrorKind {
     /// Among other causes, this variant will be constructed when parsing a string that
     /// contains a non-asci char.
     ///
-    /// This variant is also constructed when a `+` or `-` is misplaced within a sting
+    /// This variant is also constructed when a `+` or `-` is misplaced within a string
     /// either on its own or in the middle of a number.
     #[stable(feature = "int_error_matching", since = "1.47.0")]
     InvalidDigit(#[stable(feature = "int_error_matching", since = "1.47.0")] char),

From 69c301f0f36696f93a90bb7a6afe9081b0d04233 Mon Sep 17 00:00:00 2001
From: Ethan Brierley <ethanboxx@gmail.com>
Date: Mon, 26 Oct 2020 05:51:07 -0500
Subject: [PATCH 16/34] Small reword

Co-authored-by: Ashley Mannix <kodraus@hey.com>
---
 library/core/src/num/error.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs
index 91a24e7740ad4..d1a65aa35ae25 100644
--- a/library/core/src/num/error.rs
+++ b/library/core/src/num/error.rs
@@ -92,7 +92,7 @@ pub enum IntErrorKind {
     /// Among other causes, this variant will be constructed when parsing an empty string.
     #[stable(feature = "int_error_matching", since = "1.47.0")]
     Empty,
-    /// Contains an digit invalid in its context.
+    /// Contains an invalid digit in its context.
     ///
     /// Among other causes, this variant will be constructed when parsing a string that
     /// contains a non-asci char.

From 75e6deefee8dc68fc35bdfe5effbfdb517b03f9c Mon Sep 17 00:00:00 2001
From: Ethan Brierley <ethanboxx@gmail.com>
Date: Mon, 26 Oct 2020 05:51:22 -0500
Subject: [PATCH 17/34] asci -> ASCII

Co-authored-by: Ashley Mannix <kodraus@hey.com>
---
 library/core/src/num/error.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs
index d1a65aa35ae25..e1684719ab4ec 100644
--- a/library/core/src/num/error.rs
+++ b/library/core/src/num/error.rs
@@ -95,7 +95,7 @@ pub enum IntErrorKind {
     /// Contains an invalid digit in its context.
     ///
     /// Among other causes, this variant will be constructed when parsing a string that
-    /// contains a non-asci char.
+    /// contains a non-ASCII char.
     ///
     /// This variant is also constructed when a `+` or `-` is misplaced within a string
     /// either on its own or in the middle of a number.

From ad2d93da1f051970555a8be0baa8e6277b3a06c1 Mon Sep 17 00:00:00 2001
From: Ethan Brierley <ethanboxx@gmail.com>
Date: Mon, 26 Oct 2020 18:14:12 +0000
Subject: [PATCH 18/34] Apply suggested changes

---
 compiler/rustc_middle/src/lib.rs           |  1 +
 compiler/rustc_middle/src/middle/limits.rs |  6 ++++--
 library/core/src/lib.rs                    |  1 +
 library/core/src/num/error.rs              | 25 ++++++++++++++--------
 library/core/src/num/mod.rs                | 13 +++++++----
 library/core/tests/lib.rs                  |  1 +
 library/core/tests/nonzero.rs              |  2 +-
 library/core/tests/num/mod.rs              | 16 +++++++-------
 library/std/src/lib.rs                     |  1 +
 library/std/src/num.rs                     |  7 +++++-
 10 files changed, 48 insertions(+), 25 deletions(-)

diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index 37bc1a305b2f8..fa885ce2e7cdf 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -46,6 +46,7 @@
 #![feature(crate_visibility_modifier)]
 #![feature(associated_type_bounds)]
 #![feature(rustc_attrs)]
+#![feature(int_error_matching)]
 #![recursion_limit = "512"]
 
 #[macro_use]
diff --git a/compiler/rustc_middle/src/middle/limits.rs b/compiler/rustc_middle/src/middle/limits.rs
index e0d171fa77125..9ff2b7f08fe04 100644
--- a/compiler/rustc_middle/src/middle/limits.rs
+++ b/compiler/rustc_middle/src/middle/limits.rs
@@ -50,8 +50,10 @@ fn update_limit(
                     let error_str = match e.kind() {
                         IntErrorKind::PosOverflow => "`limit` is too large",
                         IntErrorKind::Empty => "`limit` must be a non-negative integer",
-                        IntErrorKind::InvalidDigit(_) => "not a valid integer",
-                        IntErrorKind::NegOverflow => bug!("`limit` should never underflow"),
+                        IntErrorKind::InvalidDigit => "not a valid integer",
+                        IntErrorKind::NegOverflow => {
+                            bug!("`limit` should never negatively underflow")
+                        }
                         IntErrorKind::Zero => bug!("zero is a valid `limit`"),
                         kind => bug!("unimplemented IntErrorKind variant: {:?}", kind),
                     };
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 63ca6e517d214..d67ad30e123f9 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -151,6 +151,7 @@
 #![feature(slice_ptr_get)]
 #![feature(no_niche)] // rust-lang/rust#68303
 #![feature(unsafe_block_in_unsafe_fn)]
+#![feature(int_error_matching)]
 #![deny(unsafe_op_in_unsafe_fn)]
 
 #[prelude_import]
diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs
index e1684719ab4ec..9d8c8c862911c 100644
--- a/library/core/src/num/error.rs
+++ b/library/core/src/num/error.rs
@@ -77,20 +77,26 @@ pub struct ParseIntError {
 /// # Example
 ///
 /// ```
+/// #![feature(int_error_matching)]
+///
 /// # fn main() {
 /// if let Err(e) = i32::from_str_radix("a12", 10) {
 ///     println!("Failed conversion to i32: {:?}", e.kind());
 /// }
 /// # }
 /// ```
-#[stable(feature = "int_error_matching", since = "1.47.0")]
+#[unstable(
+    feature = "int_error_matching",
+    reason = "it can be useful to match errors when making error messages \
+              for integer parsing",
+    issue = "22639"
+)]
 #[derive(Debug, Clone, PartialEq, Eq)]
 #[non_exhaustive]
 pub enum IntErrorKind {
     /// Value being parsed is empty.
     ///
     /// Among other causes, this variant will be constructed when parsing an empty string.
-    #[stable(feature = "int_error_matching", since = "1.47.0")]
     Empty,
     /// Contains an invalid digit in its context.
     ///
@@ -99,25 +105,26 @@ pub enum IntErrorKind {
     ///
     /// This variant is also constructed when a `+` or `-` is misplaced within a string
     /// either on its own or in the middle of a number.
-    #[stable(feature = "int_error_matching", since = "1.47.0")]
-    InvalidDigit(#[stable(feature = "int_error_matching", since = "1.47.0")] char),
+    InvalidDigit,
     /// Integer is too large to store in target integer type.
-    #[stable(feature = "int_error_matching", since = "1.47.0")]
     PosOverflow,
     /// Integer is too small to store in target integer type.
-    #[stable(feature = "int_error_matching", since = "1.47.0")]
     NegOverflow,
     /// Value was Zero
     ///
     /// This variant will be emitted when the parsing string has a value of zero, which
     /// would be illegal for non-zero types.
-    #[stable(feature = "int_error_matching", since = "1.47.0")]
     Zero,
 }
 
 impl ParseIntError {
     /// Outputs the detailed cause of parsing an integer failing.
-    #[stable(feature = "int_error_matching", since = "1.47.0")]
+    #[unstable(
+        feature = "int_error_matching",
+        reason = "it can be useful to match errors when making error messages \
+              for integer parsing",
+        issue = "22639"
+    )]
     pub fn kind(&self) -> &IntErrorKind {
         &self.kind
     }
@@ -131,7 +138,7 @@ impl ParseIntError {
     pub fn __description(&self) -> &str {
         match self.kind {
             IntErrorKind::Empty => "cannot parse integer from empty string",
-            IntErrorKind::InvalidDigit(_) => "invalid digit found in string",
+            IntErrorKind::InvalidDigit => "invalid digit found in string",
             IntErrorKind::PosOverflow => "number too large to fit in target type",
             IntErrorKind::NegOverflow => "number too small to fit in target type",
             IntErrorKind::Zero => "number would be zero for non-zero type",
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index fd00a072d896c..71448a622c09e 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -63,7 +63,12 @@ pub use nonzero::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, No
 #[stable(feature = "try_from", since = "1.34.0")]
 pub use error::TryFromIntError;
 
-#[stable(feature = "int_error_matching", since = "1.47.0")]
+#[unstable(
+    feature = "int_error_matching",
+    reason = "it can be useful to match errors when making error messages \
+              for integer parsing",
+    issue = "22639"
+)]
 pub use error::IntErrorKind;
 
 macro_rules! usize_isize_to_xe_bytes_doc {
@@ -831,7 +836,7 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
 
     let (is_positive, digits) = match src[0] {
         b'+' | b'-' if src[1..].is_empty() => {
-            return Err(PIE { kind: InvalidDigit(src[0] as char) });
+            return Err(PIE { kind: InvalidDigit });
         }
         b'+' => (true, &src[1..]),
         b'-' if is_signed_ty => (false, &src[1..]),
@@ -844,7 +849,7 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
         for &c in digits {
             let x = match (c as char).to_digit(radix) {
                 Some(x) => x,
-                None => return Err(PIE { kind: InvalidDigit(c as char) }),
+                None => return Err(PIE { kind: InvalidDigit }),
             };
             result = match result.checked_mul(radix) {
                 Some(result) => result,
@@ -860,7 +865,7 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
         for &c in digits {
             let x = match (c as char).to_digit(radix) {
                 Some(x) => x,
-                None => return Err(PIE { kind: InvalidDigit(c as char) }),
+                None => return Err(PIE { kind: InvalidDigit }),
             };
             result = match result.checked_mul(radix) {
                 Some(result) => result,
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index c128691fa7525..d8b36beb3e085 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -37,6 +37,7 @@
 #![feature(try_trait)]
 #![feature(slice_internals)]
 #![feature(slice_partition_dedup)]
+#![feature(int_error_matching)]
 #![feature(array_value_iter)]
 #![feature(iter_partition_in_place)]
 #![feature(iter_is_partitioned)]
diff --git a/library/core/tests/nonzero.rs b/library/core/tests/nonzero.rs
index 949d4ea32f064..fb1293c99bba9 100644
--- a/library/core/tests/nonzero.rs
+++ b/library/core/tests/nonzero.rs
@@ -131,7 +131,7 @@ fn test_from_str() {
     assert_eq!("0".parse::<NonZeroU8>().err().map(|e| e.kind().clone()), Some(IntErrorKind::Zero));
     assert_eq!(
         "-1".parse::<NonZeroU8>().err().map(|e| e.kind().clone()),
-        Some(IntErrorKind::InvalidDigit('-'))
+        Some(IntErrorKind::InvalidDigit)
     );
     assert_eq!(
         "-129".parse::<NonZeroI8>().err().map(|e| e.kind().clone()),
diff --git a/library/core/tests/num/mod.rs b/library/core/tests/num/mod.rs
index 12e52252278c5..7c25c32fb40a7 100644
--- a/library/core/tests/num/mod.rs
+++ b/library/core/tests/num/mod.rs
@@ -118,14 +118,14 @@ fn test_leading_plus() {
 
 #[test]
 fn test_invalid() {
-    test_parse::<i8>("--129", Err(IntErrorKind::InvalidDigit('-')));
-    test_parse::<i8>("++129", Err(IntErrorKind::InvalidDigit('+')));
-    test_parse::<u8>("Съешь", Err(IntErrorKind::InvalidDigit('Ð')));
-    test_parse::<u8>("123Hello", Err(IntErrorKind::InvalidDigit('H')));
-    test_parse::<i8>("--", Err(IntErrorKind::InvalidDigit('-')));
-    test_parse::<i8>("-", Err(IntErrorKind::InvalidDigit('-')));
-    test_parse::<i8>("+", Err(IntErrorKind::InvalidDigit('+')));
-    test_parse::<u8>("-1", Err(IntErrorKind::InvalidDigit('-')));
+    test_parse::<i8>("--129", Err(IntErrorKind::InvalidDigit));
+    test_parse::<i8>("++129", Err(IntErrorKind::InvalidDigit));
+    test_parse::<u8>("Съешь", Err(IntErrorKind::InvalidDigit));
+    test_parse::<u8>("123Hello", Err(IntErrorKind::InvalidDigit));
+    test_parse::<i8>("--", Err(IntErrorKind::InvalidDigit));
+    test_parse::<i8>("-", Err(IntErrorKind::InvalidDigit));
+    test_parse::<i8>("+", Err(IntErrorKind::InvalidDigit));
+    test_parse::<u8>("-1", Err(IntErrorKind::InvalidDigit));
 }
 
 #[test]
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index fa23229066cf1..ac0075ad129c5 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -264,6 +264,7 @@
 #![feature(global_asm)]
 #![feature(hashmap_internals)]
 #![feature(int_error_internals)]
+#![feature(int_error_matching)]
 #![feature(integer_atomics)]
 #![feature(into_future)]
 #![feature(lang_items)]
diff --git a/library/std/src/num.rs b/library/std/src/num.rs
index ac3b055cdb050..0f1c596268594 100644
--- a/library/std/src/num.rs
+++ b/library/std/src/num.rs
@@ -22,7 +22,12 @@ pub use core::num::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8,
 #[stable(feature = "nonzero", since = "1.28.0")]
 pub use core::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
 
-#[stable(feature = "int_error_matching", since = "1.47.0")]
+#[unstable(
+    feature = "int_error_matching",
+    reason = "it can be useful to match errors when making error messages \
+              for integer parsing",
+    issue = "22639"
+)]
 pub use core::num::IntErrorKind;
 
 #[cfg(test)]

From e750238404f59f3f6d94142f3e12ffc4c5c0b366 Mon Sep 17 00:00:00 2001
From: Ethan Brierley <ethanboxx@gmail.com>
Date: Mon, 26 Oct 2020 18:16:25 +0000
Subject: [PATCH 19/34] Fix typo

---
 compiler/rustc_middle/src/middle/limits.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compiler/rustc_middle/src/middle/limits.rs b/compiler/rustc_middle/src/middle/limits.rs
index 9ff2b7f08fe04..41342764ba773 100644
--- a/compiler/rustc_middle/src/middle/limits.rs
+++ b/compiler/rustc_middle/src/middle/limits.rs
@@ -52,7 +52,7 @@ fn update_limit(
                         IntErrorKind::Empty => "`limit` must be a non-negative integer",
                         IntErrorKind::InvalidDigit => "not a valid integer",
                         IntErrorKind::NegOverflow => {
-                            bug!("`limit` should never negatively underflow")
+                            bug!("`limit` should never negatively overflow")
                         }
                         IntErrorKind::Zero => bug!("zero is a valid `limit`"),
                         kind => bug!("unimplemented IntErrorKind variant: {:?}", kind),

From e099138eb6274b8450fbbb3c1fec0389337eb992 Mon Sep 17 00:00:00 2001
From: Stein Somers <git@steinsomers.be>
Date: Mon, 26 Oct 2020 23:31:45 +0100
Subject: [PATCH 20/34] BTreeMap: stop mistaking node for an orderly place

---
 .../alloc/src/collections/btree/map/tests.rs  | 26 +++++++++++--
 .../alloc/src/collections/btree/node/tests.rs | 37 -------------------
 2 files changed, 22 insertions(+), 41 deletions(-)

diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs
index adb94972f5bb6..f6921e67636d9 100644
--- a/library/alloc/src/collections/btree/map/tests.rs
+++ b/library/alloc/src/collections/btree/map/tests.rs
@@ -42,7 +42,7 @@ fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator<Item = &'a mut T>
     }
 }
 
-impl<'a, K: 'a, V: 'a> BTreeMap<K, V> {
+impl<K, V> BTreeMap<K, V> {
     /// Panics if the map (or the code navigating it) is corrupted.
     fn check(&self)
     where
@@ -54,14 +54,14 @@ impl<'a, K: 'a, V: 'a> BTreeMap<K, V> {
             assert!(root_node.ascend().is_err());
             root_node.assert_back_pointers();
 
-            let counted = root_node.assert_ascending();
-            assert_eq!(self.length, counted);
             assert_eq!(self.length, root_node.calc_length());
 
             root_node.assert_min_len(if root_node.height() > 0 { 1 } else { 0 });
         } else {
             assert_eq!(self.length, 0);
         }
+
+        self.assert_ascending();
     }
 
     /// Returns the height of the root, if any.
@@ -79,10 +79,28 @@ impl<'a, K: 'a, V: 'a> BTreeMap<K, V> {
             String::from("not yet allocated")
         }
     }
+
+    /// Asserts that the keys are in strictly ascending order.
+    fn assert_ascending(&self)
+    where
+        K: Copy + Debug + Ord,
+    {
+        let mut num_seen = 0;
+        let mut keys = self.keys();
+        if let Some(mut previous) = keys.next() {
+            num_seen = 1;
+            for next in keys {
+                assert!(previous < next, "{:?} >= {:?}", previous, next);
+                previous = next;
+                num_seen += 1;
+            }
+        }
+        assert_eq!(num_seen, self.len());
+    }
 }
 
 impl<'a, K: 'a, V: 'a> NodeRef<marker::Immut<'a>, K, V, marker::LeafOrInternal> {
-    pub fn assert_min_len(self, min_len: usize) {
+    fn assert_min_len(self, min_len: usize) {
         assert!(self.len() >= min_len, "{} < {}", self.len(), min_len);
         if let node::ForceResult::Internal(node) = self.force() {
             for idx in 0..=node.len() {
diff --git a/library/alloc/src/collections/btree/node/tests.rs b/library/alloc/src/collections/btree/node/tests.rs
index d6527057c5d77..38c75de34eeeb 100644
--- a/library/alloc/src/collections/btree/node/tests.rs
+++ b/library/alloc/src/collections/btree/node/tests.rs
@@ -17,43 +17,6 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::Immut<'a>, K, V, marker::LeafOrInternal>
         }
     }
 
-    /// Asserts that the keys are in strictly ascending order.
-    /// Returns how many keys it encountered.
-    pub fn assert_ascending(self) -> usize
-    where
-        K: Copy + Debug + Ord,
-    {
-        struct SeriesChecker<T> {
-            num_seen: usize,
-            previous: Option<T>,
-        }
-        impl<T: Copy + Debug + Ord> SeriesChecker<T> {
-            fn is_ascending(&mut self, next: T) {
-                if let Some(previous) = self.previous {
-                    assert!(previous < next, "{:?} >= {:?}", previous, next);
-                }
-                self.previous = Some(next);
-                self.num_seen += 1;
-            }
-        }
-
-        let mut checker = SeriesChecker { num_seen: 0, previous: None };
-        self.visit_nodes_in_order(|pos| match pos {
-            navigate::Position::Leaf(node) => {
-                for idx in 0..node.len() {
-                    let key = *unsafe { node.key_at(idx) };
-                    checker.is_ascending(key);
-                }
-            }
-            navigate::Position::InternalKV(kv) => {
-                let key = *kv.into_kv().0;
-                checker.is_ascending(key);
-            }
-            navigate::Position::Internal(_) => {}
-        });
-        checker.num_seen
-    }
-
     pub fn dump_keys(self) -> String
     where
         K: Debug,

From b0df3f76dc70eba57d6e0665fa6ccac89b25d3aa Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Wed, 28 Oct 2020 09:05:45 +0100
Subject: [PATCH 21/34] fix some incorrect aliasing in the BTree

---
 library/alloc/src/collections/btree/node.rs | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs
index c8d3de9e5cd5c..433074027e7f7 100644
--- a/library/alloc/src/collections/btree/node.rs
+++ b/library/alloc/src/collections/btree/node.rs
@@ -1608,15 +1608,19 @@ pub mod marker {
 
 unsafe fn slice_insert<T>(slice: &mut [T], idx: usize, val: T) {
     unsafe {
-        ptr::copy(slice.as_ptr().add(idx), slice.as_mut_ptr().add(idx + 1), slice.len() - idx);
-        ptr::write(slice.get_unchecked_mut(idx), val);
+        let len = slice.len();
+        let slice_ptr = slice.as_mut_ptr();
+        ptr::copy(slice_ptr.add(idx), slice_ptr.add(idx + 1), len - idx);
+        ptr::write(slice_ptr.add(idx), val);
     }
 }
 
 unsafe fn slice_remove<T>(slice: &mut [T], idx: usize) -> T {
     unsafe {
-        let ret = ptr::read(slice.get_unchecked(idx));
-        ptr::copy(slice.as_ptr().add(idx + 1), slice.as_mut_ptr().add(idx), slice.len() - idx - 1);
+        let len = slice.len();
+        let slice_ptr = slice.as_mut_ptr();
+        let ret = ptr::read(slice_ptr.add(idx));
+        ptr::copy(slice_ptr.add(idx + 1), slice_ptr.add(idx), len - idx - 1);
         ret
     }
 }

From 39103ced582f1111af41326f904966aedd8bc47f Mon Sep 17 00:00:00 2001
From: bjorn3 <bjorn3@users.noreply.github.com>
Date: Tue, 3 Nov 2020 16:55:33 +0100
Subject: [PATCH 22/34] Fix run-make tests running when LLVM is disabled

---
 src/bootstrap/test.rs | 26 +++++++++++++++-----------
 1 file changed, 15 insertions(+), 11 deletions(-)

diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index 6c2c05ac7197e..97aad8ed646e8 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -1203,17 +1203,6 @@ note: if you're sure you want to do this, please open an issue as to why. In the
             // Only pass correct values for these flags for the `run-make` suite as it
             // requires that a C++ compiler was configured which isn't always the case.
             if !builder.config.dry_run && matches!(suite, "run-make" | "run-make-fulldeps") {
-                cmd.arg("--cc")
-                    .arg(builder.cc(target))
-                    .arg("--cxx")
-                    .arg(builder.cxx(target).unwrap())
-                    .arg("--cflags")
-                    .arg(builder.cflags(target, GitRepo::Rustc).join(" "));
-                copts_passed = true;
-                if let Some(ar) = builder.ar(target) {
-                    cmd.arg("--ar").arg(ar);
-                }
-
                 // The llvm/bin directory contains many useful cross-platform
                 // tools. Pass the path to run-make tests so they can use them.
                 let llvm_bin_path = llvm_config
@@ -1239,6 +1228,21 @@ note: if you're sure you want to do this, please open an issue as to why. In the
             }
         }
 
+        // Only pass correct values for these flags for the `run-make` suite as it
+        // requires that a C++ compiler was configured which isn't always the case.
+        if !builder.config.dry_run && matches!(suite, "run-make" | "run-make-fulldeps") {
+            cmd.arg("--cc")
+                .arg(builder.cc(target))
+                .arg("--cxx")
+                .arg(builder.cxx(target).unwrap())
+                .arg("--cflags")
+                .arg(builder.cflags(target, GitRepo::Rustc).join(" "));
+            copts_passed = true;
+            if let Some(ar) = builder.ar(target) {
+                cmd.arg("--ar").arg(ar);
+            }
+        }
+
         if !llvm_components_passed {
             cmd.arg("--llvm-components").arg("");
         }

From 5fc22f1431e209610040d92ba671966ab2781f0b Mon Sep 17 00:00:00 2001
From: Casey Rodarmor <casey@rodarmor.com>
Date: Sun, 1 Nov 2020 19:43:51 -0800
Subject: [PATCH 23/34] Add a tool to run `x.py` from any subdirectory

This adds a binary called `x` in `src/tools/x`. All it does is check the
current directory and its ancestors for a file called `x.py`, and if it
finds one, runs it.

By installing x, you can easily `x.py` from any subdirectory.

It can be installed globally with `cargo install --path src/tools/x`
---
 .gitignore              |  1 +
 Cargo.toml              |  6 +++
 src/tools/x/Cargo.lock  |  5 +++
 src/tools/x/Cargo.toml  |  7 ++++
 src/tools/x/README.md   |  3 ++
 src/tools/x/src/main.rs | 92 +++++++++++++++++++++++++++++++++++++++++
 6 files changed, 114 insertions(+)
 create mode 100644 src/tools/x/Cargo.lock
 create mode 100644 src/tools/x/Cargo.toml
 create mode 100644 src/tools/x/README.md
 create mode 100644 src/tools/x/src/main.rs

diff --git a/.gitignore b/.gitignore
index 1c50d9b054ddc..5f7135e38d113 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,6 +31,7 @@ __pycache__/
 /inst/
 /llvm/
 /mingw-build/
+/src/tools/x/target
 # Created by default with `src/ci/docker/run.sh`:
 /obj/
 /unicode-downloads
diff --git a/Cargo.toml b/Cargo.toml
index 02794d1028b50..38fd72ace5385 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -29,10 +29,16 @@ members = [
   "src/tools/unicode-table-generator",
   "src/tools/expand-yaml-anchors",
 ]
+
 exclude = [
   "build",
   # HACK(eddyb) This hardcodes the fact that our CI uses `/checkout/obj`.
   "obj",
+  # The `x` binary is a thin wrapper that calls `x.py`, which initializes
+  # submodules, before which workspace members cannot be invoked because
+  # not all `Cargo.toml` files are available, so we exclude the `x` binary,
+  # so it can be invoked before the current checkout is set up.
+  "src/tools/x",
 ]
 
 [profile.release.package.compiler_builtins]
diff --git a/src/tools/x/Cargo.lock b/src/tools/x/Cargo.lock
new file mode 100644
index 0000000000000..723d6cb25ed6a
--- /dev/null
+++ b/src/tools/x/Cargo.lock
@@ -0,0 +1,5 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "x"
+version = "0.1.0"
diff --git a/src/tools/x/Cargo.toml b/src/tools/x/Cargo.toml
new file mode 100644
index 0000000000000..72c4948c617fa
--- /dev/null
+++ b/src/tools/x/Cargo.toml
@@ -0,0 +1,7 @@
+[package]
+name = "x"
+version = "0.1.0"
+description = "Run x.py slightly more conveniently"
+authors = ["Casey Rodarmor <casey@rodarmor.com>"]
+edition = "2018"
+publish = false
diff --git a/src/tools/x/README.md b/src/tools/x/README.md
new file mode 100644
index 0000000000000..3b3cf2847c200
--- /dev/null
+++ b/src/tools/x/README.md
@@ -0,0 +1,3 @@
+# x
+
+`x` invokes `x.py` from any subdirectory.
diff --git a/src/tools/x/src/main.rs b/src/tools/x/src/main.rs
new file mode 100644
index 0000000000000..6c0311433d676
--- /dev/null
+++ b/src/tools/x/src/main.rs
@@ -0,0 +1,92 @@
+//! Run `x.py` from any subdirectory of a rust compiler checkout.
+//!
+//! We prefer `exec`, to avoid adding an extra process in the process tree.
+//! However, since `exec` isn't available on Windows, we indirect through
+//! `exec_or_status`, which will call `exec` on unix and `status` on Windows.
+//!
+//! We use `python`, `python3`, or `python2` as the python interpreter to run
+//! `x.py`, in that order of preference.
+
+use std::{
+    env, io,
+    process::{self, Command, ExitStatus},
+};
+
+const PYTHON: &str = "python";
+const PYTHON2: &str = "python2";
+const PYTHON3: &str = "python3";
+
+fn python() -> &'static str {
+    let val = match env::var_os("PATH") {
+        Some(val) => val,
+        None => return PYTHON,
+    };
+
+    let mut python2 = false;
+    let mut python3 = false;
+
+    for dir in env::split_paths(&val) {
+        if dir.join(PYTHON).exists() {
+            return PYTHON;
+        }
+
+        python2 |= dir.join(PYTHON2).exists();
+        python3 |= dir.join(PYTHON3).exists();
+    }
+
+    if python3 {
+        PYTHON3
+    } else if python2 {
+        PYTHON2
+    } else {
+        PYTHON
+    }
+}
+
+#[cfg(unix)]
+fn exec_or_status(command: &mut Command) -> io::Result<ExitStatus> {
+    use std::os::unix::process::CommandExt;
+    Err(command.exec())
+}
+
+#[cfg(not(unix))]
+fn exec_or_status(command: &mut Command) -> io::Result<ExitStatus> {
+    command.status()
+}
+
+fn main() {
+    let current = match env::current_dir() {
+        Ok(dir) => dir,
+        Err(err) => {
+            eprintln!("Failed to get current directory: {}", err);
+            process::exit(1);
+        }
+    };
+
+    for dir in current.ancestors() {
+        let candidate = dir.join("x.py");
+
+        if candidate.exists() {
+            let mut python = Command::new(python());
+
+            python.arg(&candidate).args(env::args().skip(1)).current_dir(dir);
+
+            let result = exec_or_status(&mut python);
+
+            match result {
+                Err(error) => {
+                    eprintln!("Failed to invoke `{}`: {}", candidate.display(), error);
+                }
+                Ok(status) => {
+                    process::exit(status.code().unwrap_or(1));
+                }
+            }
+        }
+    }
+
+    eprintln!(
+        "x.py not found. Please run inside of a checkout of `https://github.com/rust-lang/rust`."
+    );
+
+    process::exit(1);
+}

From 54a0a98347f739ee3b9cad8760e237fa6cd8db54 Mon Sep 17 00:00:00 2001
From: Pietro Albini <pietro@pietroalbini.org>
Date: Thu, 22 Oct 2020 12:06:12 +0200
Subject: [PATCH 24/34] ci: gate on aarch64-gnu passing tests

---
 .github/workflows/ci.yml     | 115 ++---------------------------------
 src/ci/github-actions/ci.yml |  20 +-----
 2 files changed, 8 insertions(+), 127 deletions(-)

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 91241d2b214f9..90296ec32eeda 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -154,6 +154,11 @@ jobs:
     strategy:
       matrix:
         include:
+          - name: aarch64-gnu
+            os:
+              - self-hosted
+              - ARM64
+              - linux
           - name: arm-android
             os: ubuntu-latest-xl
             env: {}
@@ -509,116 +514,6 @@ jobs:
           AWS_ACCESS_KEY_ID: "${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}"
           AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}"
         if: "success() && !env.SKIP_JOB && (github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1')"
-  auto-fallible:
-    name: auto-fallible
-    env:
-      CI_JOB_NAME: "${{ matrix.name }}"
-      SCCACHE_BUCKET: rust-lang-gha-caches
-      DEPLOY_BUCKET: rust-lang-gha
-      TOOLSTATE_REPO: "https://github.com/pietroalbini/rust-toolstate"
-      TOOLSTATE_ISSUES_API_URL: "https://api.github.com/repos/pietroalbini/rust-toolstate/issues"
-      TOOLSTATE_PUBLISH: 1
-      CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZOMUQATD5
-      ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZH5AYXDVF
-      CACHE_DOMAIN: ci-caches-gha.rust-lang.org
-    if: "github.event_name == 'push' && github.ref == 'refs/heads/auto' && github.repository == 'rust-lang-ci/rust'"
-    strategy:
-      fail-fast: false
-      matrix:
-        include:
-          - name: aarch64-gnu
-            os:
-              - self-hosted
-              - ARM64
-              - linux
-    timeout-minutes: 600
-    runs-on: "${{ matrix.os }}"
-    steps:
-      - name: disable git crlf conversion
-        run: git config --global core.autocrlf false
-      - name: checkout the source code
-        uses: actions/checkout@v2
-        with:
-          fetch-depth: 2
-      - name: configure the PR in which the error message will be posted
-        run: "echo \"[CI_PR_NUMBER=$num]\""
-        env:
-          num: "${{ github.event.number }}"
-        if: "success() && !env.SKIP_JOBS && github.event_name == 'pull_request'"
-      - name: add extra environment variables
-        run: src/ci/scripts/setup-environment.sh
-        env:
-          EXTRA_VARIABLES: "${{ toJson(matrix.env) }}"
-        if: success() && !env.SKIP_JOB
-      - name: decide whether to skip this job
-        run: src/ci/scripts/should-skip-this.sh
-        if: success() && !env.SKIP_JOB
-      - name: configure GitHub Actions to kill the build when outdated
-        uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
-        with:
-          github_token: "${{ secrets.github_token }}"
-        if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
-      - name: collect CPU statistics
-        run: src/ci/scripts/collect-cpu-stats.sh
-        if: success() && !env.SKIP_JOB
-      - name: show the current environment
-        run: src/ci/scripts/dump-environment.sh
-        if: success() && !env.SKIP_JOB
-      - name: install awscli
-        run: src/ci/scripts/install-awscli.sh
-        if: success() && !env.SKIP_JOB
-      - name: install sccache
-        run: src/ci/scripts/install-sccache.sh
-        if: success() && !env.SKIP_JOB
-      - name: select Xcode
-        run: src/ci/scripts/select-xcode.sh
-        if: success() && !env.SKIP_JOB
-      - name: install clang
-        run: src/ci/scripts/install-clang.sh
-        if: success() && !env.SKIP_JOB
-      - name: install WIX
-        run: src/ci/scripts/install-wix.sh
-        if: success() && !env.SKIP_JOB
-      - name: ensure the build happens on a partition with enough space
-        run: src/ci/scripts/symlink-build-dir.sh
-        if: success() && !env.SKIP_JOB
-      - name: disable git crlf conversion
-        run: src/ci/scripts/disable-git-crlf-conversion.sh
-        if: success() && !env.SKIP_JOB
-      - name: install MSYS2
-        run: src/ci/scripts/install-msys2.sh
-        if: success() && !env.SKIP_JOB
-      - name: install MinGW
-        run: src/ci/scripts/install-mingw.sh
-        if: success() && !env.SKIP_JOB
-      - name: install ninja
-        run: src/ci/scripts/install-ninja.sh
-        if: success() && !env.SKIP_JOB
-      - name: enable ipv6 on Docker
-        run: src/ci/scripts/enable-docker-ipv6.sh
-        if: success() && !env.SKIP_JOB
-      - name: disable git crlf conversion
-        run: src/ci/scripts/disable-git-crlf-conversion.sh
-        if: success() && !env.SKIP_JOB
-      - name: checkout submodules
-        run: src/ci/scripts/checkout-submodules.sh
-        if: success() && !env.SKIP_JOB
-      - name: ensure line endings are correct
-        run: src/ci/scripts/verify-line-endings.sh
-        if: success() && !env.SKIP_JOB
-      - name: run the build
-        run: src/ci/scripts/run-build-from-ci.sh
-        env:
-          AWS_ACCESS_KEY_ID: "${{ env.CACHES_AWS_ACCESS_KEY_ID }}"
-          AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}"
-          TOOLSTATE_REPO_ACCESS_TOKEN: "${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }}"
-        if: success() && !env.SKIP_JOB
-      - name: upload artifacts to S3
-        run: src/ci/scripts/upload-artifacts.sh
-        env:
-          AWS_ACCESS_KEY_ID: "${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}"
-          AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}"
-        if: "success() && !env.SKIP_JOB && (github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1')"
   try:
     name: try
     env:
diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml
index 0df191f8f7404..1e28b5a253655 100644
--- a/src/ci/github-actions/ci.yml
+++ b/src/ci/github-actions/ci.yml
@@ -301,6 +301,9 @@ jobs:
           #   Linux/Docker builders   #
           #############################
 
+          - name: aarch64-gnu
+            <<: *job-aarch64-linux
+
           - name: arm-android
             <<: *job-linux-xl
 
@@ -653,23 +656,6 @@ jobs:
               SCRIPT: python x.py dist
             <<: *job-windows-xl
 
-  auto-fallible:
-    <<: *base-ci-job
-    name: auto-fallible
-    env:
-      <<: [*shared-ci-variables, *dummy-variables]
-    if: github.event_name == 'push' && github.ref == 'refs/heads/auto' && github.repository == 'rust-lang-ci/rust'
-    strategy:
-      fail-fast: false
-      matrix:
-        include:
-          #############################
-          #   Linux/Docker builders   #
-          #############################
-
-          - name: aarch64-gnu
-            <<: *job-aarch64-linux
-
   try:
     <<: *base-ci-job
     name: try

From 1274faed1a1379bb1521ae9884bc8ef420971636 Mon Sep 17 00:00:00 2001
From: Pietro Albini <pietro@pietroalbini.org>
Date: Thu, 22 Oct 2020 12:23:18 +0200
Subject: [PATCH 25/34] doc/rustc: promote aarch64-unknown-linux-gnu to tier 1

This also adds a note about missing stack probes support, per the
discussion on RFC 2959.
---
 src/doc/rustc/src/platform-support.md | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 85c6f91f08582..8005a5f3563bf 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -34,6 +34,7 @@ Specifically they will each satisfy the following requirements:
 
 target | std | host | notes
 -------|-----|------|-------
+`aarch64-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (kernel 4.2, glibc 2.17+) [^missing-stack-probes]
 `i686-pc-windows-gnu` | ✓ | ✓ | 32-bit MinGW (Windows 7+)
 `i686-pc-windows-msvc` | ✓ | ✓ | 32-bit MSVC (Windows 7+)
 `i686-unknown-linux-gnu` | ✓ | ✓ | 32-bit Linux (kernel 2.6.32+, glibc 2.11+)
@@ -42,6 +43,12 @@ target | std | host | notes
 `x86_64-pc-windows-msvc` | ✓ | ✓ | 64-bit MSVC (Windows 7+)
 `x86_64-unknown-linux-gnu` | ✓ | ✓ | 64-bit Linux (kernel 2.6.32+, glibc 2.11+)
 
+[^missing-stack-probes]: Stack probes support is missing on
+  `aarch64-unknown-linux-gnu`, but it's planned to be implemented in the near
+  future. The implementation is tracked on [issue #77071][77071].
+
+[77071]: https://github.com/rust-lang/rust/issues/77071
+
 ## Tier 2
 
 Tier 2 platforms can be thought of as "guaranteed to build". Automated tests
@@ -62,7 +69,6 @@ target | std | host | notes
 `aarch64-fuchsia` | ✓ |  | ARM64 Fuchsia
 `aarch64-linux-android` | ✓ |  | ARM64 Android
 `aarch64-pc-windows-msvc` | ✓ | ✓ | ARM64 Windows MSVC
-`aarch64-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (kernel 4.2, glibc 2.17)
 `aarch64-unknown-linux-musl` | ✓ | ✓ | ARM64 Linux with MUSL
 `aarch64-unknown-none` | * |  | Bare ARM64, hardfloat
 `aarch64-unknown-none-softfloat` | * |  | Bare ARM64, softfloat

From 874cbb88e0379a0e7bab5b9db99e2a4c495534fb Mon Sep 17 00:00:00 2001
From: Pietro Albini <pietro@pietroalbini.org>
Date: Thu, 22 Oct 2020 12:31:11 +0200
Subject: [PATCH 26/34] ci: build docs for aarch64-unknown-linux-gnu

---
 src/ci/docker/host-x86_64/dist-aarch64-linux/Dockerfile | 3 +--
 src/tools/build-manifest/src/main.rs                    | 1 +
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/ci/docker/host-x86_64/dist-aarch64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-aarch64-linux/Dockerfile
index df65f9df44127..95c54ca1abc06 100644
--- a/src/ci/docker/host-x86_64/dist-aarch64-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-aarch64-linux/Dockerfile
@@ -35,6 +35,5 @@ ENV HOSTS=aarch64-unknown-linux-gnu
 ENV RUST_CONFIGURE_ARGS \
       --enable-full-tools \
       --enable-profiler \
-      --enable-sanitizers \
-      --disable-docs
+      --enable-sanitizers
 ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index 9a8f2404e4a1a..687354dc6aee2 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -155,6 +155,7 @@ static TARGETS: &[&str] = &[
 ];
 
 static DOCS_TARGETS: &[&str] = &[
+    "aarch64-unknown-linux-gnu",
     "i686-apple-darwin",
     "i686-pc-windows-gnu",
     "i686-pc-windows-msvc",

From eed0cebea3d16d82f5517e17ab498b340001fe01 Mon Sep 17 00:00:00 2001
From: Joshua Nelson <jyn514@gmail.com>
Date: Mon, 19 Oct 2020 14:20:14 -0400
Subject: [PATCH 27/34] Recognize `private_intra_doc_links` as a lint

Previously, trying to allow this would give another error!

```
warning: unknown lint: `private_intra_doc_links`
 --> private.rs:1:10
  |
1 | #![allow(private_intra_doc_links)]
  |          ^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `broken_intra_doc_links`
  |
  = note: `#[warn(unknown_lints)]` on by default

warning: public documentation for `DocMe` links to private item `DontDocMe`
 --> private.rs:2:11
  |
2 | /// docs [DontDocMe]
  |           ^^^^^^^^^ this item is private
  |
  = note: `#[warn(private_intra_doc_links)]` on by default
  = note: this link will resolve properly if you pass `--document-private-items`
```
---
 compiler/rustc_lint_defs/src/builtin.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index a1b7c13e4c0f0..7176a66cdc1bd 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -2790,6 +2790,7 @@ declare_lint_pass! {
         UNSTABLE_NAME_COLLISIONS,
         IRREFUTABLE_LET_PATTERNS,
         BROKEN_INTRA_DOC_LINKS,
+        PRIVATE_INTRA_DOC_LINKS,
         INVALID_CODEBLOCK_ATTRIBUTES,
         MISSING_CRATE_LEVEL_DOCS,
         MISSING_DOC_CODE_EXAMPLES,

From 47b21b84f3ed88cff31fccc78a57a66241a26496 Mon Sep 17 00:00:00 2001
From: Joshua Nelson <jyn514@gmail.com>
Date: Thu, 5 Nov 2020 13:11:50 -0500
Subject: [PATCH 28/34] Add PRIVATE_INTRA_DOC_LINKS to rustdoc special-casing

This is really starting to get out of hand. Rustdoc should instead allow
all lints in the rustdoc lint group.
---
 src/librustdoc/core.rs | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 45a84c4fb30d3..285a3bf8204bb 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -322,7 +322,8 @@ pub fn run_core(
     let cpath = Some(input.clone());
     let input = Input::File(input);
 
-    let intra_link_resolution_failure_name = lint::builtin::BROKEN_INTRA_DOC_LINKS.name;
+    let broken_intra_doc_links = lint::builtin::BROKEN_INTRA_DOC_LINKS.name;
+    let private_intra_doc_links = lint::builtin::PRIVATE_INTRA_DOC_LINKS.name;
     let missing_docs = rustc_lint::builtin::MISSING_DOCS.name;
     let missing_doc_example = rustc_lint::builtin::MISSING_DOC_CODE_EXAMPLES.name;
     let private_doc_tests = rustc_lint::builtin::PRIVATE_DOC_TESTS.name;
@@ -335,7 +336,8 @@ pub fn run_core(
     // In addition to those specific lints, we also need to allow those given through
     // command line, otherwise they'll get ignored and we don't want that.
     let lints_to_show = vec![
-        intra_link_resolution_failure_name.to_owned(),
+        broken_intra_doc_links.to_owned(),
+        private_intra_doc_links.to_owned(),
         missing_docs.to_owned(),
         missing_doc_example.to_owned(),
         private_doc_tests.to_owned(),
@@ -347,9 +349,8 @@ pub fn run_core(
     ];
 
     let (lint_opts, lint_caps) = init_lints(lints_to_show, lint_opts, |lint| {
-        if lint.name == intra_link_resolution_failure_name
-            || lint.name == invalid_codeblock_attributes_name
-        {
+        // FIXME: why is this necessary?
+        if lint.name == broken_intra_doc_links || lint.name == invalid_codeblock_attributes_name {
             None
         } else {
             Some((lint.name_lower(), lint::Allow))

From dd68d0b28d4265fba1b7692f3f4357821e4e8de2 Mon Sep 17 00:00:00 2001
From: Alexis Beingessner <a.beingessner@gmail.com>
Date: Thu, 5 Nov 2020 17:18:14 -0500
Subject: [PATCH 29/34] Vendor libtest's dependencies in the rust-src component

This is the Rust side of https://github.com/rust-lang/wg-cargo-std-aware/issues/23
---
 src/bootstrap/dist.rs | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index bdab12db43502..4534c69d40de9 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -1040,6 +1040,25 @@ impl Step for Src {
             builder.copy(&builder.src.join(file), &dst_src.join(file));
         }
 
+        // libtest includes std and everything else, so vendoring it
+        // creates exactly what's needed for `cargo -Zbuild-std` or any
+        // other analysis of the stdlib's source. Cargo also needs help
+        // finding the lock, so we copy it to libtest temporarily.
+        //
+        // Note that this requires std to only have one version of each
+        // crate. e.g. two versions of getopts won't be patchable.
+        let dst_libtest = dst_src.join("library/test");
+        let dst_vendor = dst_src.join("vendor");
+        let root_lock = dst_src.join("Cargo.lock");
+        let temp_lock = dst_libtest.join("Cargo.lock");
+        builder.copy(&root_lock, &temp_lock);
+
+        let mut cmd = Command::new(&builder.initial_cargo);
+        cmd.arg("vendor").arg(dst_vendor).current_dir(&dst_libtest);
+        builder.run(&mut cmd);
+
+        builder.remove(&temp_lock);
+
         // Create source tarball in rust-installer format
         let mut cmd = rust_installer(builder);
         cmd.arg("generate")

From e8b5be5dffef9ef6a15a085e4b06c4a0471f360d Mon Sep 17 00:00:00 2001
From: Ivan Tham <pickfire@riseup.net>
Date: Sun, 30 Aug 2020 10:35:50 +0800
Subject: [PATCH 30/34] Stabilize hint::spin_loop

Partially fix #55002, deprecate in another release

Co-authored-by: Ashley Mannix <kodraus@hey.com>

Update stable version for stabilize_spin_loop

Co-authored-by: Joshua Nelson <joshua@yottadb.com>

Use better example for spinlock

As suggested by KodrAus

Remove renamed_spin_loop already available in master

Fix spin loop example
---
 library/alloc/src/lib.rs        |  1 -
 library/core/src/hint.rs        | 62 ++++++++++++++++++++++++++++-----
 library/core/src/sync/atomic.rs | 16 ++-------
 library/std/src/lib.rs          |  1 -
 4 files changed, 56 insertions(+), 24 deletions(-)

diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index 0fe15958076c5..ccabc336acc16 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -119,7 +119,6 @@
 #![feature(raw_ref_op)]
 #![feature(rustc_attrs)]
 #![feature(receiver_trait)]
-#![feature(renamed_spin_loop)]
 #![feature(min_specialization)]
 #![feature(slice_ptr_get)]
 #![feature(slice_ptr_len)]
diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs
index 454fb34e77e49..979a5f8cf5075 100644
--- a/library/core/src/hint.rs
+++ b/library/core/src/hint.rs
@@ -1,6 +1,7 @@
 #![stable(feature = "core_hint", since = "1.27.0")]
 
 //! Hints to compiler that affects how code should be emitted or optimized.
+//! Hints may be compile time or runtime.
 
 use crate::intrinsics;
 
@@ -24,7 +25,6 @@ use crate::intrinsics;
 /// Otherwise, consider using the [`unreachable!`] macro, which does not allow
 /// optimizations but will panic when executed.
 ///
-///
 /// # Example
 ///
 /// ```
@@ -51,18 +51,62 @@ pub const unsafe fn unreachable_unchecked() -> ! {
     unsafe { intrinsics::unreachable() }
 }
 
-/// Emits a machine instruction hinting to the processor that it is running in busy-wait
-/// spin-loop ("spin lock").
+/// Emits a machine instruction to signal the processor that it is running in
+/// a busy-wait spin-loop ("spin lock").
+///
+/// Upon receiving the spin-loop signal the processor can optimize its behavior by,
+/// for example, saving power or switching hyper-threads.
+///
+/// This function is different from [`thread::yield_now`] which directly
+/// yields to the system's scheduler, whereas `spin_loop` does not interact
+/// with the operating system.
+///
+/// A common use case for `spin_loop` is implementing bounded optimistic
+/// spinning in a CAS loop in synchronization primitives. To avoid problems
+/// like priority inversion, it is strongly recommended that the spin loop is
+/// terminated after a finite amount of iterations and an appropriate blocking
+/// syscall is made.
+///
+/// **Note**: On platforms that do not support receiving spin-loop hints this
+/// function does not do anything at all.
+///
+/// # Examples
 ///
-/// For a discussion of different locking strategies and their trade-offs, see
-/// [`core::sync::atomic::spin_loop_hint`].
+/// ```
+/// use std::sync::atomic::{AtomicBool, Ordering};
+/// use std::sync::Arc;
+/// use std::{hint, thread};
+///
+/// // A shared atomic value that threads will use to coordinate
+/// let live = Arc::new(AtomicBool::new(false));
+///
+/// // In a background thread we'll eventually set the value
+/// let bg_work = {
+///     let live = live.clone();
+///     thread::spawn(move || {
+///         // Do some work, then make the value live
+///         do_some_work();
+///         live.store(true, Ordering::Release);
+///     })
+/// };
 ///
-/// **Note**: On platforms that do not support receiving spin-loop hints this function does not
-/// do anything at all.
+/// // Back on our current thread, we wait for the value to be set
+/// while live.load(Ordering::Acquire) {
+///     // The spin loop is a hint to the CPU that we're waiting, but probably
+///     // not for very long
+///     hint::spin_loop();
+/// }
+///
+/// // The value is now set
+/// # fn do_some_work() {}
+/// do_some_work();
+/// bg_work.join()?;
+/// # Ok::<(), Box<dyn core::any::Any + Send + 'static>>(())
+/// ```
 ///
-/// [`core::sync::atomic::spin_loop_hint`]: crate::sync::atomic::spin_loop_hint
+/// [`thread::yield_now`]: ../../std/thread/fn.yield_now.html
 #[inline]
-#[unstable(feature = "renamed_spin_loop", issue = "55002")]
+#[stable(feature = "renamed_spin_loop", since = "1.49.0")]
 pub fn spin_loop() {
     #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "sse2"))]
     {
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index 5c9cfe27101f0..5dbea6e71aa4f 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -115,23 +115,13 @@ use crate::hint::spin_loop;
 
 /// Signals the processor that it is inside a busy-wait spin-loop ("spin lock").
 ///
-/// Upon receiving spin-loop signal the processor can optimize its behavior by, for example, saving
-/// power or switching hyper-threads.
-///
-/// This function is different from [`std::thread::yield_now`] which directly yields to the
-/// system's scheduler, whereas `spin_loop_hint` does not interact with the operating system.
-///
-/// A common use case for `spin_loop_hint` is implementing bounded optimistic spinning in a CAS
-/// loop in synchronization primitives. To avoid problems like priority inversion, it is strongly
-/// recommended that the spin loop is terminated after a finite amount of iterations and an
-/// appropriate blocking syscall is made.
+/// This function is expected to be deprecated in favor of
+/// [`hint::spin_loop`].
 ///
 /// **Note**: On platforms that do not support receiving spin-loop hints this function does not
 /// do anything at all.
 ///
-/// [`std::thread::yield_now`]: ../../../std/thread/fn.yield_now.html
-/// [`std::thread::sleep`]: ../../../std/thread/fn.sleep.html
-/// [`std::sync::Mutex`]: ../../../std/sync/struct.Mutex.html
+/// [`hint::spin_loop`]: crate::hint::spin_loop
 #[inline]
 #[stable(feature = "spin_loop_hint", since = "1.24.0")]
 pub fn spin_loop_hint() {
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 96a7755c68821..1636fe5e2575a 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -296,7 +296,6 @@
 #![feature(raw)]
 #![feature(raw_ref_macros)]
 #![feature(ready_macro)]
-#![feature(renamed_spin_loop)]
 #![feature(rustc_attrs)]
 #![feature(rustc_private)]
 #![feature(shrink_to)]

From 020ed653a374d9b8ffa29d191839c1d49a7ce656 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= <matthias.krueger@famsik.de>
Date: Sat, 7 Nov 2020 01:23:02 +0100
Subject: [PATCH 31/34] use single char patterns for split()
 (clippy::single_char_pattern)

---
 compiler/rustc_mir/src/transform/coverage/debug.rs | 8 ++++----
 compiler/rustc_mir/src/util/generic_graphviz.rs    | 2 +-
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/compiler/rustc_mir/src/transform/coverage/debug.rs b/compiler/rustc_mir/src/transform/coverage/debug.rs
index cc697dfd7fe28..ffa795134e257 100644
--- a/compiler/rustc_mir/src/transform/coverage/debug.rs
+++ b/compiler/rustc_mir/src/transform/coverage/debug.rs
@@ -147,8 +147,8 @@ impl DebugOptions {
         let mut counter_format = ExpressionFormat::default();
 
         if let Ok(env_debug_options) = std::env::var(RUSTC_COVERAGE_DEBUG_OPTIONS) {
-            for setting_str in env_debug_options.replace(" ", "").replace("-", "_").split(",") {
-                let mut setting = setting_str.splitn(2, "=");
+            for setting_str in env_debug_options.replace(" ", "").replace("-", "_").split(',') {
+                let mut setting = setting_str.splitn(2, '=');
                 match setting.next() {
                     Some(option) if option == "allow_unused_expressions" => {
                         allow_unused_expressions = bool_option_val(option, setting.next());
@@ -210,7 +210,7 @@ fn bool_option_val(option: &str, some_strval: Option<&str>) -> bool {
 
 fn counter_format_option_val(strval: &str) -> ExpressionFormat {
     let mut counter_format = ExpressionFormat { id: false, block: false, operation: false };
-    let components = strval.splitn(3, "+");
+    let components = strval.splitn(3, '+');
     for component in components {
         match component {
             "id" => counter_format.id = true,
@@ -695,7 +695,7 @@ pub(crate) fn dump_coverage_graphviz(
         let from_bcb_data = &basic_coverage_blocks[from_bcb];
         let from_terminator = from_bcb_data.terminator(mir_body);
         let mut edge_labels = from_terminator.kind.fmt_successor_labels();
-        edge_labels.retain(|label| label.to_string() != "unreachable");
+        edge_labels.retain(|label| label != "unreachable");
         let edge_counters = from_terminator
             .successors()
             .map(|&successor_bb| graphviz_data.get_edge_counter(from_bcb, successor_bb));
diff --git a/compiler/rustc_mir/src/util/generic_graphviz.rs b/compiler/rustc_mir/src/util/generic_graphviz.rs
index 91499bb61c287..8bd4a512bbb05 100644
--- a/compiler/rustc_mir/src/util/generic_graphviz.rs
+++ b/compiler/rustc_mir/src/util/generic_graphviz.rs
@@ -174,7 +174,7 @@ impl<
     where
         W: Write,
     {
-        let lines = label.split("\n").map(|s| dot::escape_html(s)).collect::<Vec<_>>();
+        let lines = label.split('\n').map(|s| dot::escape_html(s)).collect::<Vec<_>>();
         let escaped_label = lines.join(r#"<br align="left"/>"#);
         writeln!(w, r#"    label=<<br/><br/>{}<br align="left"/><br/><br/><br/>>;"#, escaped_label)
     }

From 5c8d25f4035d490063abcca8e71e7b602d467e64 Mon Sep 17 00:00:00 2001
From: Daiki Ihara <sasurau4@gmail.com>
Date: Sat, 7 Nov 2020 21:34:40 +0900
Subject: [PATCH 32/34] remove FIXME comment of #62277 in print_type_sizez ui
 tests

---
 src/test/ui/print_type_sizes/anonymous.rs         | 2 +-
 src/test/ui/print_type_sizes/generics.rs          | 2 +-
 src/test/ui/print_type_sizes/multiple_types.rs    | 2 +-
 src/test/ui/print_type_sizes/niche-filling.rs     | 2 +-
 src/test/ui/print_type_sizes/no_duplicates.rs     | 2 +-
 src/test/ui/print_type_sizes/packed.rs            | 2 +-
 src/test/ui/print_type_sizes/padding.rs           | 2 +-
 src/test/ui/print_type_sizes/repr-align.rs        | 2 +-
 src/test/ui/print_type_sizes/repr_int_c.rs        | 2 +-
 src/test/ui/print_type_sizes/uninhabited.rs       | 2 +-
 src/test/ui/print_type_sizes/variants.rs          | 2 +-
 src/test/ui/print_type_sizes/zero-sized-fields.rs | 2 +-
 12 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/src/test/ui/print_type_sizes/anonymous.rs b/src/test/ui/print_type_sizes/anonymous.rs
index b96348640fa15..2b008ca3b3a9a 100644
--- a/src/test/ui/print_type_sizes/anonymous.rs
+++ b/src/test/ui/print_type_sizes/anonymous.rs
@@ -1,5 +1,5 @@
 // compile-flags: -Z print-type-sizes
-// build-pass (FIXME(62277): could be check-pass?)
+// build-pass
 
 // All of the types that occur in this function are uninteresting, in
 // that one cannot control the sizes of these types with the same sort
diff --git a/src/test/ui/print_type_sizes/generics.rs b/src/test/ui/print_type_sizes/generics.rs
index f165526dffa23..3ef7b60db2cae 100644
--- a/src/test/ui/print_type_sizes/generics.rs
+++ b/src/test/ui/print_type_sizes/generics.rs
@@ -1,5 +1,5 @@
 // compile-flags: -Z print-type-sizes
-// build-pass (FIXME(62277): could be check-pass?)
+// build-pass
 // ignore-pass
 // ^-- needed because `--pass check` does not emit the output needed.
 //     FIXME: consider using an attribute instead of side-effects.
diff --git a/src/test/ui/print_type_sizes/multiple_types.rs b/src/test/ui/print_type_sizes/multiple_types.rs
index 4cb7ae03b5406..f1ad27ec13137 100644
--- a/src/test/ui/print_type_sizes/multiple_types.rs
+++ b/src/test/ui/print_type_sizes/multiple_types.rs
@@ -1,5 +1,5 @@
 // compile-flags: -Z print-type-sizes
-// build-pass (FIXME(62277): could be check-pass?)
+// build-pass
 
 // This file illustrates that when multiple structural types occur in
 // a function, every one of them is included in the output.
diff --git a/src/test/ui/print_type_sizes/niche-filling.rs b/src/test/ui/print_type_sizes/niche-filling.rs
index d9845fd6d70cc..37ac45f7e053c 100644
--- a/src/test/ui/print_type_sizes/niche-filling.rs
+++ b/src/test/ui/print_type_sizes/niche-filling.rs
@@ -1,5 +1,5 @@
 // compile-flags: -Z print-type-sizes
-// build-pass (FIXME(62277): could be check-pass?)
+// build-pass
 // ignore-pass
 // ^-- needed because `--pass check` does not emit the output needed.
 //     FIXME: consider using an attribute instead of side-effects.
diff --git a/src/test/ui/print_type_sizes/no_duplicates.rs b/src/test/ui/print_type_sizes/no_duplicates.rs
index 4495a7770a760..e45e4794a3526 100644
--- a/src/test/ui/print_type_sizes/no_duplicates.rs
+++ b/src/test/ui/print_type_sizes/no_duplicates.rs
@@ -1,5 +1,5 @@
 // compile-flags: -Z print-type-sizes
-// build-pass (FIXME(62277): could be check-pass?)
+// build-pass
 // ignore-pass
 // ^-- needed because `--pass check` does not emit the output needed.
 //     FIXME: consider using an attribute instead of side-effects.
diff --git a/src/test/ui/print_type_sizes/packed.rs b/src/test/ui/print_type_sizes/packed.rs
index dce4a61ef337b..269cc3cc2825f 100644
--- a/src/test/ui/print_type_sizes/packed.rs
+++ b/src/test/ui/print_type_sizes/packed.rs
@@ -1,5 +1,5 @@
 // compile-flags: -Z print-type-sizes
-// build-pass (FIXME(62277): could be check-pass?)
+// build-pass
 // ignore-pass
 // ^-- needed because `--pass check` does not emit the output needed.
 //     FIXME: consider using an attribute instead of side-effects.
diff --git a/src/test/ui/print_type_sizes/padding.rs b/src/test/ui/print_type_sizes/padding.rs
index 1f894c5e252fa..d1acad16d7e1d 100644
--- a/src/test/ui/print_type_sizes/padding.rs
+++ b/src/test/ui/print_type_sizes/padding.rs
@@ -1,5 +1,5 @@
 // compile-flags: -Z print-type-sizes
-// build-pass (FIXME(62277): could be check-pass?)
+// build-pass
 
 // This file illustrates how padding is handled: alignment
 // requirements can lead to the introduction of padding, either before
diff --git a/src/test/ui/print_type_sizes/repr-align.rs b/src/test/ui/print_type_sizes/repr-align.rs
index 1e6f7ccca40f2..07544935b2f82 100644
--- a/src/test/ui/print_type_sizes/repr-align.rs
+++ b/src/test/ui/print_type_sizes/repr-align.rs
@@ -1,5 +1,5 @@
 // compile-flags: -Z print-type-sizes
-// build-pass (FIXME(62277): could be check-pass?)
+// build-pass
 // ignore-pass
 // ^-- needed because `--pass check` does not emit the output needed.
 //     FIXME: consider using an attribute instead of side-effects.
diff --git a/src/test/ui/print_type_sizes/repr_int_c.rs b/src/test/ui/print_type_sizes/repr_int_c.rs
index 7aad2715bc073..b8067c112eef1 100644
--- a/src/test/ui/print_type_sizes/repr_int_c.rs
+++ b/src/test/ui/print_type_sizes/repr_int_c.rs
@@ -1,5 +1,5 @@
 // compile-flags: -Z print-type-sizes
-// build-pass (FIXME(62277): could be check-pass?)
+// build-pass
 
 // This test makes sure that the tag is not grown for `repr(C)` or `repr(u8)`
 // variants (see https://github.com/rust-lang/rust/issues/50098 for the original bug).
diff --git a/src/test/ui/print_type_sizes/uninhabited.rs b/src/test/ui/print_type_sizes/uninhabited.rs
index ae4e492456af9..c234547bd14b1 100644
--- a/src/test/ui/print_type_sizes/uninhabited.rs
+++ b/src/test/ui/print_type_sizes/uninhabited.rs
@@ -1,5 +1,5 @@
 // compile-flags: -Z print-type-sizes
-// build-pass (FIXME(62277): could be check-pass?)
+// build-pass
 // ignore-pass
 // ^-- needed because `--pass check` does not emit the output needed.
 //     FIXME: consider using an attribute instead of side-effects.
diff --git a/src/test/ui/print_type_sizes/variants.rs b/src/test/ui/print_type_sizes/variants.rs
index 77e2b4befba7d..6c8553cc23ded 100644
--- a/src/test/ui/print_type_sizes/variants.rs
+++ b/src/test/ui/print_type_sizes/variants.rs
@@ -1,5 +1,5 @@
 // compile-flags: -Z print-type-sizes
-// build-pass (FIXME(62277): could be check-pass?)
+// build-pass
 
 // This file illustrates two things:
 //
diff --git a/src/test/ui/print_type_sizes/zero-sized-fields.rs b/src/test/ui/print_type_sizes/zero-sized-fields.rs
index 71d091677473a..e02a33109e56a 100644
--- a/src/test/ui/print_type_sizes/zero-sized-fields.rs
+++ b/src/test/ui/print_type_sizes/zero-sized-fields.rs
@@ -1,5 +1,5 @@
 // compile-flags: -Z print-type-sizes
-// build-pass (FIXME(62277): could be check-pass?)
+// build-pass
 // ignore-pass
 
 // At one point, zero-sized fields such as those in this file were causing

From 67d0db6b008f98c1a1ba8ed6c267105433250fc9 Mon Sep 17 00:00:00 2001
From: Joshua Nelson <jyn514@gmail.com>
Date: Wed, 21 Oct 2020 22:00:32 -0400
Subject: [PATCH 33/34] Fix handling of item names for HIR

- Handle variants, fields, macros in `Node::ident()`
- Handle the crate root in `opt_item_name`
- Factor out `item_name_from_def_id` to reduce duplication
- Look at HIR before the DefId for `opt_item_name`

  This gives accurate spans, which are not available from serialized
  metadata.

- Don't panic on the crate root in `opt_item_name`
- Add comments
---
 compiler/rustc_hir/src/hir.rs            |  3 ++
 compiler/rustc_middle/src/hir/map/mod.rs |  2 +-
 compiler/rustc_middle/src/ty/mod.rs      | 65 ++++++++++++++++--------
 3 files changed, 49 insertions(+), 21 deletions(-)

diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index b9ec18688c5f2..3c72937ad3134 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -2677,6 +2677,9 @@ impl<'hir> Node<'hir> {
             Node::TraitItem(TraitItem { ident, .. })
             | Node::ImplItem(ImplItem { ident, .. })
             | Node::ForeignItem(ForeignItem { ident, .. })
+            | Node::Field(StructField { ident, .. })
+            | Node::Variant(Variant { ident, .. })
+            | Node::MacroDef(MacroDef { ident, .. })
             | Node::Item(Item { ident, .. }) => Some(*ident),
             _ => None,
         }
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 106fa8c78fa28..d86e898719557 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -478,7 +478,7 @@ impl<'hir> Map<'hir> {
     }
 
     pub fn get_if_local(&self, id: DefId) -> Option<Node<'hir>> {
-        id.as_local().map(|id| self.get(self.local_def_id_to_hir_id(id)))
+        id.as_local().and_then(|id| self.find(self.local_def_id_to_hir_id(id)))
     }
 
     pub fn get_generics(&self, id: DefId) -> Option<&'hir Generics<'hir>> {
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index aa5a696b09c3b..c69dabda54937 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -2795,10 +2795,52 @@ impl<'tcx> TyCtxt<'tcx> {
             .filter(|item| item.kind == AssocKind::Fn && item.defaultness.has_value())
     }
 
+    fn item_name_from_hir(self, def_id: DefId) -> Option<Ident> {
+        self.hir().get_if_local(def_id).and_then(|node| node.ident())
+    }
+
+    fn item_name_from_def_id(self, def_id: DefId) -> Option<Symbol> {
+        if def_id.index == CRATE_DEF_INDEX {
+            Some(self.original_crate_name(def_id.krate))
+        } else {
+            let def_key = self.def_key(def_id);
+            match def_key.disambiguated_data.data {
+                // The name of a constructor is that of its parent.
+                rustc_hir::definitions::DefPathData::Ctor => self.item_name_from_def_id(DefId {
+                    krate: def_id.krate,
+                    index: def_key.parent.unwrap(),
+                }),
+                _ => def_key.disambiguated_data.data.get_opt_name(),
+            }
+        }
+    }
+
+    /// Look up the name of an item across crates. This does not look at HIR.
+    ///
+    /// When possible, this function should be used for cross-crate lookups over
+    /// [`opt_item_name`] to avoid invalidating the incremental cache. If you
+    /// need to handle items without a name, or HIR items that will not be
+    /// serialized cross-crate, or if you need the span of the item, use
+    /// [`opt_item_name`] instead.
+    ///
+    /// [`opt_item_name`]: Self::opt_item_name
+    pub fn item_name(self, id: DefId) -> Symbol {
+        // Look at cross-crate items first to avoid invalidating the incremental cache
+        // unless we have to.
+        self.item_name_from_def_id(id)
+            .or_else(|| self.item_name_from_hir(id).map(|ident| ident.name))
+            .unwrap_or_else(|| {
+                bug!("item_name: no name for {:?}", self.def_path(id));
+            })
+    }
+
+    /// Look up the name and span of an item or [`Node`].
+    ///
+    /// See [`item_name`][Self::item_name] for more information.
     pub fn opt_item_name(self, def_id: DefId) -> Option<Ident> {
-        def_id
-            .as_local()
-            .and_then(|def_id| self.hir().get(self.hir().local_def_id_to_hir_id(def_id)).ident())
+        // Look at the HIR first so the span will be correct if this is a local item.
+        self.item_name_from_hir(def_id)
+            .or_else(|| self.item_name_from_def_id(def_id).map(Ident::with_dummy_span))
     }
 
     pub fn opt_associated_item(self, def_id: DefId) -> Option<&'tcx AssocItem> {
@@ -2921,23 +2963,6 @@ impl<'tcx> TyCtxt<'tcx> {
         }
     }
 
-    pub fn item_name(self, id: DefId) -> Symbol {
-        if id.index == CRATE_DEF_INDEX {
-            self.original_crate_name(id.krate)
-        } else {
-            let def_key = self.def_key(id);
-            match def_key.disambiguated_data.data {
-                // The name of a constructor is that of its parent.
-                rustc_hir::definitions::DefPathData::Ctor => {
-                    self.item_name(DefId { krate: id.krate, index: def_key.parent.unwrap() })
-                }
-                _ => def_key.disambiguated_data.data.get_opt_name().unwrap_or_else(|| {
-                    bug!("item_name: no name for {:?}", self.def_path(id));
-                }),
-            }
-        }
-    }
-
     /// Returns the possibly-auto-generated MIR of a `(DefId, Subst)` pair.
     pub fn instance_mir(self, instance: ty::InstanceDef<'tcx>) -> &'tcx Body<'tcx> {
         match instance {

From f60fd4963207bd6ac4a1c93c7c2674a7c321ffa8 Mon Sep 17 00:00:00 2001
From: Joshua Nelson <jyn514@gmail.com>
Date: Sat, 7 Nov 2020 10:34:00 -0500
Subject: [PATCH 34/34] Remove unused `from_hir` call

---
 compiler/rustc_middle/src/ty/mod.rs | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index c69dabda54937..0042b4a3a4279 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -2827,11 +2827,9 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn item_name(self, id: DefId) -> Symbol {
         // Look at cross-crate items first to avoid invalidating the incremental cache
         // unless we have to.
-        self.item_name_from_def_id(id)
-            .or_else(|| self.item_name_from_hir(id).map(|ident| ident.name))
-            .unwrap_or_else(|| {
-                bug!("item_name: no name for {:?}", self.def_path(id));
-            })
+        self.item_name_from_def_id(id).unwrap_or_else(|| {
+            bug!("item_name: no name for {:?}", self.def_path(id));
+        })
     }
 
     /// Look up the name and span of an item or [`Node`].