diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index fc13bdff36f5d..489c8d1892657 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -24,6 +24,7 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(array_windows)]
 #![feature(cfg_match)]
+#![feature(core_io_borrowed_buf)]
 #![feature(if_let_guard)]
 #![feature(let_chains)]
 #![feature(min_specialization)]
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index cf52e6726a17c..08208cc60475b 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -2389,12 +2389,21 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                         )
                     });
 
-                let obligation = Obligation::new(
-                    self.tcx(),
-                    cause.clone(),
-                    param_env,
-                    ty::TraitRef::new(self.tcx(), trait_def_id, [normalized_ty]),
-                );
+                let tcx = self.tcx();
+                let trait_ref = if tcx.generics_of(trait_def_id).params.len() == 1 {
+                    ty::TraitRef::new(tcx, trait_def_id, [normalized_ty])
+                } else {
+                    // If this is an ill-formed auto/built-in trait, then synthesize
+                    // new error args for the missing generics.
+                    let err_args = ty::GenericArgs::extend_with_error(
+                        tcx,
+                        trait_def_id,
+                        &[normalized_ty.into()],
+                    );
+                    ty::TraitRef::new(tcx, trait_def_id, err_args)
+                };
+
+                let obligation = Obligation::new(self.tcx(), cause.clone(), param_env, trait_ref);
                 obligations.push(obligation);
                 obligations
             })
diff --git a/library/std/src/io/readbuf.rs b/library/core/src/io/borrowed_buf.rs
similarity index 96%
rename from library/std/src/io/readbuf.rs
rename to library/core/src/io/borrowed_buf.rs
index 95044de2a09e1..fe25cac280fe3 100644
--- a/library/std/src/io/readbuf.rs
+++ b/library/core/src/io/borrowed_buf.rs
@@ -1,10 +1,6 @@
-#![unstable(feature = "read_buf", issue = "78485")]
-
-#[cfg(test)]
-mod tests;
+#![unstable(feature = "core_io_borrowed_buf", issue = "117693")]
 
 use crate::fmt::{self, Debug, Formatter};
-use crate::io::{Result, Write};
 use crate::mem::{self, MaybeUninit};
 use crate::{cmp, ptr};
 
@@ -303,16 +299,3 @@ impl<'a> BorrowedCursor<'a> {
         self.buf.filled += buf.len();
     }
 }
-
-impl<'a> Write for BorrowedCursor<'a> {
-    fn write(&mut self, buf: &[u8]) -> Result<usize> {
-        let amt = cmp::min(buf.len(), self.capacity());
-        self.append(&buf[..amt]);
-        Ok(amt)
-    }
-
-    #[inline]
-    fn flush(&mut self) -> Result<()> {
-        Ok(())
-    }
-}
diff --git a/library/core/src/io/mod.rs b/library/core/src/io/mod.rs
new file mode 100644
index 0000000000000..2f20180cdc9a2
--- /dev/null
+++ b/library/core/src/io/mod.rs
@@ -0,0 +1,6 @@
+//! Traits, helpers, and type definitions for core I/O functionality.
+
+mod borrowed_buf;
+
+#[unstable(feature = "core_io_borrowed_buf", issue = "117693")]
+pub use self::borrowed_buf::{BorrowedBuf, BorrowedCursor};
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index de643fb333efe..5a6d242a7298e 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -369,6 +369,8 @@ pub mod async_iter;
 pub mod cell;
 pub mod char;
 pub mod ffi;
+#[unstable(feature = "core_io_borrowed_buf", issue = "117693")]
+pub mod io;
 pub mod iter;
 pub mod net;
 pub mod option;
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index b5ad3f280e6b1..f83f60857a266 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -4,26 +4,12 @@
 //! threads, and are the building blocks of other concurrent
 //! types.
 //!
-//! Rust atomics currently follow the same rules as [C++20 atomics][cpp], specifically `atomic_ref`.
-//! Basically, creating a *shared reference* to one of the Rust atomic types corresponds to creating
-//! an `atomic_ref` in C++; the `atomic_ref` is destroyed when the lifetime of the shared reference
-//! ends. (A Rust atomic type that is exclusively owned or behind a mutable reference does *not*
-//! correspond to an "atomic object" in C++, since it can be accessed via non-atomic operations.)
-//!
 //! This module defines atomic versions of a select number of primitive
 //! types, including [`AtomicBool`], [`AtomicIsize`], [`AtomicUsize`],
 //! [`AtomicI8`], [`AtomicU16`], etc.
 //! Atomic types present operations that, when used correctly, synchronize
 //! updates between threads.
 //!
-//! Each method takes an [`Ordering`] which represents the strength of
-//! the memory barrier for that operation. These orderings are the
-//! same as the [C++20 atomic orderings][1]. For more information see the [nomicon][2].
-//!
-//! [cpp]: https://en.cppreference.com/w/cpp/atomic
-//! [1]: https://en.cppreference.com/w/cpp/atomic/memory_order
-//! [2]: ../../../nomicon/atomics.html
-//!
 //! Atomic variables are safe to share between threads (they implement [`Sync`])
 //! but they do not themselves provide the mechanism for sharing and follow the
 //! [threading model](../../../std/thread/index.html#the-threading-model) of Rust.
@@ -36,6 +22,75 @@
 //! the constant initializers like [`AtomicBool::new`]. Atomic statics
 //! are often used for lazy global initialization.
 //!
+//! ## Memory model for atomic accesses
+//!
+//! Rust atomics currently follow the same rules as [C++20 atomics][cpp], specifically `atomic_ref`.
+//! Basically, creating a *shared reference* to one of the Rust atomic types corresponds to creating
+//! an `atomic_ref` in C++; the `atomic_ref` is destroyed when the lifetime of the shared reference
+//! ends. (A Rust atomic type that is exclusively owned or behind a mutable reference does *not*
+//! correspond to an "atomic object" in C++, since it can be accessed via non-atomic operations.)
+//!
+//! [cpp]: https://en.cppreference.com/w/cpp/atomic
+//!
+//! Each method takes an [`Ordering`] which represents the strength of
+//! the memory barrier for that operation. These orderings are the
+//! same as the [C++20 atomic orderings][1]. For more information see the [nomicon][2].
+//!
+//! [1]: https://en.cppreference.com/w/cpp/atomic/memory_order
+//! [2]: ../../../nomicon/atomics.html
+//!
+//! Since C++ does not support mixing atomic and non-atomic accesses, or non-synchronized
+//! different-sized accesses to the same data, Rust does not support those operations either.
+//! Note that both of those restrictions only apply if the accesses are non-synchronized.
+//!
+//! ```rust,no_run undefined_behavior
+//! use std::sync::atomic::{AtomicU16, AtomicU8, Ordering};
+//! use std::mem::transmute;
+//! use std::thread;
+//!
+//! let atomic = AtomicU16::new(0);
+//!
+//! thread::scope(|s| {
+//!     // This is UB: mixing atomic and non-atomic accesses
+//!     s.spawn(|| atomic.store(1, Ordering::Relaxed));
+//!     s.spawn(|| unsafe { atomic.as_ptr().write(2) });
+//! });
+//!
+//! thread::scope(|s| {
+//!     // This is UB: even reads are not allowed to be mixed
+//!     s.spawn(|| atomic.load(Ordering::Relaxed));
+//!     s.spawn(|| unsafe { atomic.as_ptr().read() });
+//! });
+//!
+//! thread::scope(|s| {
+//!     // This is fine, `join` synchronizes the code in a way such that atomic
+//!     // and non-atomic accesses can't happen "at the same time"
+//!     let handle = s.spawn(|| atomic.store(1, Ordering::Relaxed));
+//!     handle.join().unwrap();
+//!     s.spawn(|| unsafe { atomic.as_ptr().write(2) });
+//! });
+//!
+//! thread::scope(|s| {
+//!     // This is UB: using different-sized atomic accesses to the same data
+//!     s.spawn(|| atomic.store(1, Ordering::Relaxed));
+//!     s.spawn(|| unsafe {
+//!         let differently_sized = transmute::<&AtomicU16, &AtomicU8>(&atomic);
+//!         differently_sized.store(2, Ordering::Relaxed);
+//!     });
+//! });
+//!
+//! thread::scope(|s| {
+//!     // This is fine, `join` synchronizes the code in a way such that
+//!     // differently-sized accesses can't happen "at the same time"
+//!     let handle = s.spawn(|| atomic.store(1, Ordering::Relaxed));
+//!     handle.join().unwrap();
+//!     s.spawn(|| unsafe {
+//!         let differently_sized = transmute::<&AtomicU16, &AtomicU8>(&atomic);
+//!         differently_sized.store(2, Ordering::Relaxed);
+//!     });
+//! });
+//! ```
+//!
 //! # Portability
 //!
 //! All atomic types in this module are guaranteed to be [lock-free] if they're
@@ -383,16 +438,12 @@ impl AtomicBool {
     /// * `ptr` must be aligned to `align_of::<AtomicBool>()` (note that on some platforms this can
     ///   be bigger than `align_of::<bool>()`).
     /// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`.
-    /// * Non-atomic accesses to the value behind `ptr` must have a happens-before relationship
-    ///   with atomic accesses via the returned value (or vice-versa).
-    ///   * In other words, time periods where the value is accessed atomically may not overlap
-    ///     with periods where the value is accessed non-atomically.
-    ///   * This requirement is trivially satisfied if `ptr` is never used non-atomically for the
-    ///     duration of lifetime `'a`. Most use cases should be able to follow this guideline.
-    ///   * This requirement is also trivially satisfied if all accesses (atomic or not) are done
-    ///     from the same thread.
+    /// * You must adhere to the [Memory model for atomic accesses]. In particular, it is not
+    ///   allowed to mix atomic and non-atomic accesses, or atomic accesses of different sizes,
+    ///   without synchronization.
     ///
     /// [valid]: crate::ptr#safety
+    /// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses
     #[stable(feature = "atomic_from_ptr", since = "CURRENT_RUSTC_VERSION")]
     #[rustc_const_unstable(feature = "const_atomic_from_ptr", issue = "108652")]
     pub const unsafe fn from_ptr<'a>(ptr: *mut bool) -> &'a AtomicBool {
@@ -1185,18 +1236,12 @@ impl<T> AtomicPtr<T> {
     /// * `ptr` must be aligned to `align_of::<AtomicPtr<T>>()` (note that on some platforms this
     ///   can be bigger than `align_of::<*mut T>()`).
     /// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`.
-    /// * Non-atomic accesses to the value behind `ptr` must have a happens-before relationship
-    ///   with atomic accesses via the returned value (or vice-versa).
-    ///   * In other words, time periods where the value is accessed atomically may not overlap
-    ///     with periods where the value is accessed non-atomically.
-    ///   * This requirement is trivially satisfied if `ptr` is never used non-atomically for the
-    ///     duration of lifetime `'a`. Most use cases should be able to follow this guideline.
-    ///   * This requirement is also trivially satisfied if all accesses (atomic or not) are done
-    ///     from the same thread.
-    /// * This method should not be used to create overlapping or mixed-size atomic accesses, as
-    ///   these are not supported by the memory model.
+    /// * You must adhere to the [Memory model for atomic accesses]. In particular, it is not
+    ///   allowed to mix atomic and non-atomic accesses, or atomic accesses of different sizes,
+    ///   without synchronization.
     ///
     /// [valid]: crate::ptr#safety
+    /// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses
     #[stable(feature = "atomic_from_ptr", since = "CURRENT_RUSTC_VERSION")]
     #[rustc_const_unstable(feature = "const_atomic_from_ptr", issue = "108652")]
     pub const unsafe fn from_ptr<'a>(ptr: *mut *mut T) -> &'a AtomicPtr<T> {
@@ -2167,19 +2212,12 @@ macro_rules! atomic_int {
                 `align_of::<", stringify!($atomic_type), ">()` (note that on some platforms this \
                 can be bigger than `align_of::<", stringify!($int_type), ">()`).")]
             /// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`.
-            /// * Non-atomic accesses to the value behind `ptr` must have a happens-before
-            ///   relationship with atomic accesses via the returned value (or vice-versa).
-            ///   * In other words, time periods where the value is accessed atomically may not
-            ///     overlap with periods where the value is accessed non-atomically.
-            ///   * This requirement is trivially satisfied if `ptr` is never used non-atomically
-            ///     for the duration of lifetime `'a`. Most use cases should be able to follow
-            ///     this guideline.
-            ///   * This requirement is also trivially satisfied if all accesses (atomic or not) are
-            ///     done from the same thread.
-            /// * This method should not be used to create overlapping or mixed-size atomic
-            ///   accesses, as these are not supported by the memory model.
+            /// * You must adhere to the [Memory model for atomic accesses]. In particular, it is not
+            ///   allowed to mix atomic and non-atomic accesses, or atomic accesses of different sizes,
+            ///   without synchronization.
             ///
             /// [valid]: crate::ptr#safety
+            /// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses
             #[stable(feature = "atomic_from_ptr", since = "CURRENT_RUSTC_VERSION")]
             #[rustc_const_unstable(feature = "const_atomic_from_ptr", issue = "108652")]
             pub const unsafe fn from_ptr<'a>(ptr: *mut $int_type) -> &'a $atomic_type {
diff --git a/library/std/src/io/readbuf/tests.rs b/library/core/tests/io/borrowed_buf.rs
similarity index 98%
rename from library/std/src/io/readbuf/tests.rs
rename to library/core/tests/io/borrowed_buf.rs
index 89a2f6b2271bd..69511e49acdbc 100644
--- a/library/std/src/io/readbuf/tests.rs
+++ b/library/core/tests/io/borrowed_buf.rs
@@ -1,5 +1,5 @@
-use super::BorrowedBuf;
-use crate::mem::MaybeUninit;
+use core::io::BorrowedBuf;
+use core::mem::MaybeUninit;
 
 /// Test that BorrowedBuf has the correct numbers when created with new
 #[test]
diff --git a/library/core/tests/io/mod.rs b/library/core/tests/io/mod.rs
new file mode 100644
index 0000000000000..a24893a525a9d
--- /dev/null
+++ b/library/core/tests/io/mod.rs
@@ -0,0 +1 @@
+mod borrowed_buf;
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index df7b34ce73b42..168b47dc99cc6 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -23,6 +23,7 @@
 #![feature(const_likely)]
 #![feature(const_location_fields)]
 #![feature(core_intrinsics)]
+#![feature(core_io_borrowed_buf)]
 #![feature(core_private_bignum)]
 #![feature(core_private_diy_float)]
 #![feature(dec2flt)]
@@ -135,6 +136,7 @@ mod fmt;
 mod future;
 mod hash;
 mod intrinsics;
+mod io;
 mod iter;
 mod lazy;
 #[cfg(test)]
diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs
index f438325560f54..256b043a60971 100644
--- a/library/std/src/io/impls.rs
+++ b/library/std/src/io/impls.rs
@@ -528,3 +528,17 @@ impl<A: Allocator> Write for VecDeque<u8, A> {
         Ok(())
     }
 }
+
+#[unstable(feature = "read_buf", issue = "78485")]
+impl<'a> io::Write for core::io::BorrowedCursor<'a> {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        let amt = cmp::min(buf.len(), self.capacity());
+        self.append(&buf[..amt]);
+        Ok(amt)
+    }
+
+    #[inline]
+    fn flush(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+}
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index aa9a2482d2d92..7d70a0bac24fd 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -330,7 +330,7 @@ pub use self::{
 };
 
 #[unstable(feature = "read_buf", issue = "78485")]
-pub use self::readbuf::{BorrowedBuf, BorrowedCursor};
+pub use core::io::{BorrowedBuf, BorrowedCursor};
 pub(crate) use error::const_io_error;
 
 mod buffered;
@@ -339,7 +339,6 @@ mod cursor;
 mod error;
 mod impls;
 pub mod prelude;
-mod readbuf;
 mod stdio;
 mod util;
 
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index f57c8d4e7e282..425890122577f 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -310,6 +310,7 @@
 // tidy-alphabetical-start
 #![feature(char_internals)]
 #![feature(core_intrinsics)]
+#![feature(core_io_borrowed_buf)]
 #![feature(duration_constants)]
 #![feature(error_generic_member_access)]
 #![feature(error_in_core)]
diff --git a/src/bootstrap/src/bin/rustc.rs b/src/bootstrap/src/bin/rustc.rs
index 3041fd37ac80a..e3c010eb49c55 100644
--- a/src/bootstrap/src/bin/rustc.rs
+++ b/src/bootstrap/src/bin/rustc.rs
@@ -32,6 +32,9 @@ fn main() {
     let args = env::args_os().skip(1).collect::<Vec<_>>();
     let arg = |name| args.windows(2).find(|args| args[0] == name).and_then(|args| args[1].to_str());
 
+    // We don't use the stage in this shim, but let's parse it to make sure that we're invoked
+    // by bootstrap, or that we provide a helpful error message if not.
+    bin_helpers::parse_rustc_stage();
     let verbose = bin_helpers::parse_rustc_verbose();
 
     // Detect whether or not we're a build script depending on whether --target
diff --git a/src/bootstrap/src/core/build_steps/clean.rs b/src/bootstrap/src/core/build_steps/clean.rs
index 679770ce0ec78..1f0ca2ac5c882 100644
--- a/src/bootstrap/src/core/build_steps/clean.rs
+++ b/src/bootstrap/src/core/build_steps/clean.rs
@@ -139,7 +139,6 @@ fn clean_specific_stage(build: &Build, stage: u32) {
 fn clean_default(build: &Build) {
     rm_rf(&build.out.join("tmp"));
     rm_rf(&build.out.join("dist"));
-    rm_rf(&build.out.join("bootstrap"));
     rm_rf(&build.out.join("rustfmt.stamp"));
 
     for host in &build.hosts {
diff --git a/src/bootstrap/src/utils/bin_helpers.rs b/src/bootstrap/src/utils/bin_helpers.rs
index b9177c490ac28..ab41a6b960025 100644
--- a/src/bootstrap/src/utils/bin_helpers.rs
+++ b/src/bootstrap/src/utils/bin_helpers.rs
@@ -18,7 +18,6 @@ pub(crate) fn parse_rustc_verbose() -> usize {
 /// Parses the value of the "RUSTC_STAGE" environment variable and returns it as a `String`.
 ///
 /// If "RUSTC_STAGE" was not set, the program will be terminated with 101.
-#[allow(unused)]
 pub(crate) fn parse_rustc_stage() -> String {
     std::env::var("RUSTC_STAGE").unwrap_or_else(|_| {
         // Don't panic here; it's reasonable to try and run these shims directly. Give a helpful error instead.
diff --git a/tests/ui/auto-traits/has-arguments.rs b/tests/ui/auto-traits/has-arguments.rs
new file mode 100644
index 0000000000000..f579eb6772d44
--- /dev/null
+++ b/tests/ui/auto-traits/has-arguments.rs
@@ -0,0 +1,10 @@
+#![feature(auto_traits)]
+
+auto trait Trait1<'outer> {}
+//~^ ERROR auto traits cannot have generic parameters
+
+fn f<'a>(x: impl Trait1<'a>) {}
+
+fn main() {
+    f("");
+}
diff --git a/tests/ui/auto-traits/has-arguments.stderr b/tests/ui/auto-traits/has-arguments.stderr
new file mode 100644
index 0000000000000..3bba74badbce9
--- /dev/null
+++ b/tests/ui/auto-traits/has-arguments.stderr
@@ -0,0 +1,11 @@
+error[E0567]: auto traits cannot have generic parameters
+  --> $DIR/has-arguments.rs:3:18
+   |
+LL | auto trait Trait1<'outer> {}
+   |            ------^^^^^^^^ help: remove the parameters
+   |            |
+   |            auto trait cannot have generic parameters
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0567`.
diff --git a/triagebot.toml b/triagebot.toml
index 69bbbdb03bf43..4c8c1c59beba4 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -579,7 +579,7 @@ Otherwise, you can ignore this comment.
 message = "`src/tools/x` was changed. Bump version of Cargo.toml in `src/tools/x` so tidy will suggest installing the new version."
 
 [mentions."src/tools/tidy/src/deps.rs"]
-message = "Third-party dependency whitelist may have been modified! You must ensure that any new dependencies have compatible licenses before merging."
+message = "The list of allowed third-party dependencies may have been modified! You must ensure that any new dependencies have compatible licenses before merging."
 cc = ["@davidtwco", "@wesleywiser"]
 
 [mentions."src/bootstrap/src/core/config"]