From 61273b7e642979ee25b669fd7dea05051ed6520d Mon Sep 17 00:00:00 2001
From: Dan Gohman <dev@sunfishcode.online>
Date: Sun, 27 Mar 2022 15:41:13 -0700
Subject: [PATCH 01/14] Define a dedicated error type for `HandleOrNull` and
 `HandleOrInvalid`.

Define a `NotHandle` type, that implements `std::error::Error`, and use
it as the error type in `HandleOrNull` and `HandleOrInvalid`.
---
 library/std/src/error.rs                |  4 ++++
 library/std/src/os/windows/io/handle.rs | 26 +++++++++++++++++++------
 2 files changed, 24 insertions(+), 6 deletions(-)

diff --git a/library/std/src/error.rs b/library/std/src/error.rs
index c3cb71a5dee63..5e51dbf87549b 100644
--- a/library/std/src/error.rs
+++ b/library/std/src/error.rs
@@ -604,6 +604,10 @@ impl Error for alloc::collections::TryReserveError {}
 #[unstable(feature = "duration_checked_float", issue = "83400")]
 impl Error for time::FromFloatSecsError {}
 
+#[cfg(windows)]
+#[unstable(feature = "io_safety", issue = "87074")]
+impl Error for crate::os::windows::io::NotHandle {}
+
 // Copied from `any.rs`.
 impl dyn Error + 'static {
     /// Returns `true` if the inner type is the same as `T`.
diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs
index 120af9f99dd9b..4003f04731f7d 100644
--- a/library/std/src/os/windows/io/handle.rs
+++ b/library/std/src/os/windows/io/handle.rs
@@ -142,17 +142,17 @@ impl BorrowedHandle<'_> {
 }
 
 impl TryFrom<HandleOrNull> for OwnedHandle {
-    type Error = ();
+    type Error = NotHandle;
 
     #[inline]
-    fn try_from(handle_or_null: HandleOrNull) -> Result<Self, ()> {
+    fn try_from(handle_or_null: HandleOrNull) -> Result<Self, NotHandle> {
         let owned_handle = handle_or_null.0;
         if owned_handle.handle.is_null() {
             // Don't call `CloseHandle`; it'd be harmless, except that it could
             // overwrite the `GetLastError` error.
             forget(owned_handle);
 
-            Err(())
+            Err(NotHandle(()))
         } else {
             Ok(owned_handle)
         }
@@ -200,23 +200,37 @@ impl OwnedHandle {
 }
 
 impl TryFrom<HandleOrInvalid> for OwnedHandle {
-    type Error = ();
+    type Error = NotHandle;
 
     #[inline]
-    fn try_from(handle_or_invalid: HandleOrInvalid) -> Result<Self, ()> {
+    fn try_from(handle_or_invalid: HandleOrInvalid) -> Result<Self, NotHandle> {
         let owned_handle = handle_or_invalid.0;
         if owned_handle.handle == c::INVALID_HANDLE_VALUE {
             // Don't call `CloseHandle`; it'd be harmless, except that it could
             // overwrite the `GetLastError` error.
             forget(owned_handle);
 
-            Err(())
+            Err(NotHandle(()))
         } else {
             Ok(owned_handle)
         }
     }
 }
 
+/// This is the error type used by [`HandleOrInvalid`] and
+/// [`HandleOrNull`] when attempting to convert into a handle,
+/// to indicate that the value is not a handle.
+#[unstable(feature = "io_safety", issue = "87074")]
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub struct NotHandle(());
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl fmt::Display for NotHandle {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        "the return value of a Windows API call indicated an error".fmt(fmt)
+    }
+}
+
 impl AsRawHandle for BorrowedHandle<'_> {
     #[inline]
     fn as_raw_handle(&self) -> RawHandle {

From c7e0ef5cabbdf42e54b69ec1760835ad2d611c02 Mon Sep 17 00:00:00 2001
From: Dan Gohman <dev@sunfishcode.online>
Date: Sun, 27 Mar 2022 16:53:56 -0700
Subject: [PATCH 02/14] Fix an incorrect word in a comment.

---
 library/std/src/os/windows/io/handle.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs
index 4003f04731f7d..f27ea785586fa 100644
--- a/library/std/src/os/windows/io/handle.rs
+++ b/library/std/src/os/windows/io/handle.rs
@@ -75,7 +75,7 @@ pub struct OwnedHandle {
 /// `NULL`. This ensures that such FFI calls cannot start using the handle without
 /// checking for `NULL` first.
 ///
-/// This type concerns any value other than `NULL` to be valid, including `INVALID_HANDLE_VALUE`.
+/// This type considers any value other than `NULL` to be valid, including `INVALID_HANDLE_VALUE`.
 /// This is because APIs that use `NULL` as their sentry value don't treat `INVALID_HANDLE_VALUE`
 /// as special.
 ///
@@ -95,7 +95,7 @@ pub struct HandleOrNull(OwnedHandle);
 /// `INVALID_HANDLE_VALUE`. This ensures that such FFI calls cannot start using the handle without
 /// checking for `INVALID_HANDLE_VALUE` first.
 ///
-/// This type concerns any value other than `INVALID_HANDLE_VALUE` to be valid, including `NULL`.
+/// This type considers any value other than `INVALID_HANDLE_VALUE` to be valid, including `NULL`.
 /// This is because APIs that use `INVALID_HANDLE_VALUE` as their sentry value may return `NULL`
 /// under `windows_subsystem = "windows"` or other situations where I/O devices are detached.
 ///

From fc3b8b34ea5f68180dc1d776df99357c00fe135b Mon Sep 17 00:00:00 2001
From: Dan Gohman <dev@sunfishcode.online>
Date: Sun, 27 Mar 2022 16:54:58 -0700
Subject: [PATCH 03/14] Move the `Error` impl for `NotHandle` out of
 platform-independent code.

---
 library/std/src/error.rs                | 4 ----
 library/std/src/os/windows/io/handle.rs | 3 +++
 2 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/library/std/src/error.rs b/library/std/src/error.rs
index 5e51dbf87549b..c3cb71a5dee63 100644
--- a/library/std/src/error.rs
+++ b/library/std/src/error.rs
@@ -604,10 +604,6 @@ impl Error for alloc::collections::TryReserveError {}
 #[unstable(feature = "duration_checked_float", issue = "83400")]
 impl Error for time::FromFloatSecsError {}
 
-#[cfg(windows)]
-#[unstable(feature = "io_safety", issue = "87074")]
-impl Error for crate::os::windows::io::NotHandle {}
-
 // Copied from `any.rs`.
 impl dyn Error + 'static {
     /// Returns `true` if the inner type is the same as `T`.
diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs
index f27ea785586fa..32e454cee7edc 100644
--- a/library/std/src/os/windows/io/handle.rs
+++ b/library/std/src/os/windows/io/handle.rs
@@ -231,6 +231,9 @@ impl fmt::Display for NotHandle {
     }
 }
 
+#[unstable(feature = "io_safety", issue = "87074")]
+impl crate::error::Error for NotHandle {}
+
 impl AsRawHandle for BorrowedHandle<'_> {
     #[inline]
     fn as_raw_handle(&self) -> RawHandle {

From 0efbd34c7e0c5064e7df977189c9950b1074706b Mon Sep 17 00:00:00 2001
From: Dan Gohman <dev@sunfishcode.online>
Date: Mon, 28 Mar 2022 10:56:00 -0700
Subject: [PATCH 04/14] Split `NotHandle` into `NullHandleError` and
 `InvalidHandleError`.

Also, make the display messages more specific, and remove the `Copy`
implementation.
---
 library/std/src/os/windows/io/handle.rs | 45 +++++++++++++++++--------
 1 file changed, 31 insertions(+), 14 deletions(-)

diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs
index 32e454cee7edc..707b8a301727c 100644
--- a/library/std/src/os/windows/io/handle.rs
+++ b/library/std/src/os/windows/io/handle.rs
@@ -142,17 +142,17 @@ impl BorrowedHandle<'_> {
 }
 
 impl TryFrom<HandleOrNull> for OwnedHandle {
-    type Error = NotHandle;
+    type Error = NullHandleError;
 
     #[inline]
-    fn try_from(handle_or_null: HandleOrNull) -> Result<Self, NotHandle> {
+    fn try_from(handle_or_null: HandleOrNull) -> Result<Self, NullHandleError> {
         let owned_handle = handle_or_null.0;
         if owned_handle.handle.is_null() {
             // Don't call `CloseHandle`; it'd be harmless, except that it could
             // overwrite the `GetLastError` error.
             forget(owned_handle);
 
-            Err(NotHandle(()))
+            Err(NullHandleError(()))
         } else {
             Ok(owned_handle)
         }
@@ -200,39 +200,56 @@ impl OwnedHandle {
 }
 
 impl TryFrom<HandleOrInvalid> for OwnedHandle {
-    type Error = NotHandle;
+    type Error = InvalidHandleError;
 
     #[inline]
-    fn try_from(handle_or_invalid: HandleOrInvalid) -> Result<Self, NotHandle> {
+    fn try_from(handle_or_invalid: HandleOrInvalid) -> Result<Self, InvalidHandleError> {
         let owned_handle = handle_or_invalid.0;
         if owned_handle.handle == c::INVALID_HANDLE_VALUE {
             // Don't call `CloseHandle`; it'd be harmless, except that it could
             // overwrite the `GetLastError` error.
             forget(owned_handle);
 
-            Err(NotHandle(()))
+            Err(InvalidHandleError(()))
         } else {
             Ok(owned_handle)
         }
     }
 }
 
-/// This is the error type used by [`HandleOrInvalid`] and
-/// [`HandleOrNull`] when attempting to convert into a handle,
-/// to indicate that the value is not a handle.
+/// This is the error type used by [`HandleOrNull`] when attempting to convert
+/// into a handle, to indicate that the value is null.
 #[unstable(feature = "io_safety", issue = "87074")]
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub struct NotHandle(());
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct NullHandleError(());
 
 #[unstable(feature = "io_safety", issue = "87074")]
-impl fmt::Display for NotHandle {
+impl fmt::Display for NullHandleError {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        "the return value of a Windows API call indicated an error".fmt(fmt)
+        "A HandleOrNull could not be converted to a handle because it was null".fmt(fmt)
     }
 }
 
 #[unstable(feature = "io_safety", issue = "87074")]
-impl crate::error::Error for NotHandle {}
+impl crate::error::Error for NullHandleError {}
+
+/// This is the error type used by [`HandleOrInvalid`] when attempting to
+/// convert into a handle, to indicate that the value is
+/// `INVALID_HANDLE_VALUE`.
+#[unstable(feature = "io_safety", issue = "87074")]
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct InvalidHandleError(());
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl fmt::Display for InvalidHandleError {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        "A HandleOrInvalid could not be converted to a handle because it was INVALID_HANDLE_VALUE"
+            .fmt(fmt)
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl crate::error::Error for InvalidHandleError {}
 
 impl AsRawHandle for BorrowedHandle<'_> {
     #[inline]

From 6b75406f5a7b006f7c724c08c6a00d7696a3620d Mon Sep 17 00:00:00 2001
From: Jacob Pratt <jacob@jhpratt.dev>
Date: Mon, 28 Feb 2022 18:13:24 -0500
Subject: [PATCH 05/14] Create 2024 edition

---
 compiler/rustc_ast/src/token.rs               |  2 +-
 .../src/standard_library_imports.rs           |  1 +
 compiler/rustc_expand/src/mbe/macro_rules.rs  |  2 +-
 compiler/rustc_session/src/session.rs         |  5 ++++
 compiler/rustc_span/src/edition.rs            | 30 +++++++++++++++++--
 compiler/rustc_span/src/lib.rs                |  5 ++++
 compiler/rustc_span/src/symbol.rs             |  2 ++
 library/core/src/prelude/mod.rs               | 10 +++++++
 library/std/src/lib.rs                        |  1 +
 library/std/src/prelude/mod.rs                | 14 +++++++++
 src/test/ui/hello.rs                          | 11 +++++--
 src/test/ui/hello2021.rs                      |  6 ----
 src/tools/rustfmt/src/bin/main.rs             |  1 +
 src/tools/rustfmt/src/config/options.rs       |  5 ++++
 14 files changed, 83 insertions(+), 12 deletions(-)
 delete mode 100644 src/test/ui/hello2021.rs

diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index 2132cdfc001b6..3e274107e7fb6 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -722,7 +722,7 @@ impl NonterminalKind {
                 Edition::Edition2015 | Edition::Edition2018 => {
                     NonterminalKind::PatParam { inferred: true }
                 }
-                Edition::Edition2021 => NonterminalKind::PatWithOr,
+                Edition::Edition2021 | Edition::Edition2024 => NonterminalKind::PatWithOr,
             },
             sym::pat_param => NonterminalKind::PatParam { inferred: false },
             sym::expr => NonterminalKind::Expr,
diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs
index 3571517d2b258..09ad5f9b3eaa9 100644
--- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs
+++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs
@@ -70,6 +70,7 @@ pub fn inject(
             Edition2015 => sym::rust_2015,
             Edition2018 => sym::rust_2018,
             Edition2021 => sym::rust_2021,
+            Edition2024 => sym::rust_2024,
         }])
         .map(|&symbol| Ident::new(symbol, span))
         .collect();
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 10b2b9f07e2a5..058b03530a39f 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -1033,7 +1033,7 @@ fn check_matcher_core(
                             err.span_label(sp, format!("not allowed after `{}` fragments", kind));
 
                             if kind == NonterminalKind::PatWithOr
-                                && sess.edition == Edition::Edition2021
+                                && sess.edition.rust_2021()
                                 && next_token.is_token(&BinOp(token::BinOpToken::Or))
                             {
                                 let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl(
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index eed0f1e09fffe..8ba859bed4d08 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -945,6 +945,11 @@ impl Session {
         self.opts.edition >= Edition::Edition2021
     }
 
+    /// Are we allowed to use features from the Rust 2024 edition?
+    pub fn rust_2024(&self) -> bool {
+        self.opts.edition >= Edition::Edition2024
+    }
+
     pub fn edition(&self) -> Edition {
         self.opts.edition
     }
diff --git a/compiler/rustc_span/src/edition.rs b/compiler/rustc_span/src/edition.rs
index 511c2e8662697..065d3660e5008 100644
--- a/compiler/rustc_span/src/edition.rs
+++ b/compiler/rustc_span/src/edition.rs
@@ -22,13 +22,15 @@ pub enum Edition {
     Edition2018,
     /// The 2021 edition
     Edition2021,
+    /// The 2024 edition
+    Edition2024,
 }
 
 // Must be in order from oldest to newest.
 pub const ALL_EDITIONS: &[Edition] =
-    &[Edition::Edition2015, Edition::Edition2018, Edition::Edition2021];
+    &[Edition::Edition2015, Edition::Edition2018, Edition::Edition2021, Edition::Edition2024];
 
-pub const EDITION_NAME_LIST: &str = "2015|2018|2021";
+pub const EDITION_NAME_LIST: &str = "2015|2018|2021|2024";
 
 pub const DEFAULT_EDITION: Edition = Edition::Edition2015;
 
@@ -40,6 +42,7 @@ impl fmt::Display for Edition {
             Edition::Edition2015 => "2015",
             Edition::Edition2018 => "2018",
             Edition::Edition2021 => "2021",
+            Edition::Edition2024 => "2024",
         };
         write!(f, "{}", s)
     }
@@ -51,6 +54,7 @@ impl Edition {
             Edition::Edition2015 => "rust_2015_compatibility",
             Edition::Edition2018 => "rust_2018_compatibility",
             Edition::Edition2021 => "rust_2021_compatibility",
+            Edition::Edition2024 => "rust_2024_compatibility",
         }
     }
 
@@ -59,6 +63,7 @@ impl Edition {
             Edition::Edition2015 => sym::rust_2015_preview,
             Edition::Edition2018 => sym::rust_2018_preview,
             Edition::Edition2021 => sym::rust_2021_preview,
+            Edition::Edition2024 => sym::rust_2024_preview,
         }
     }
 
@@ -67,8 +72,28 @@ impl Edition {
             Edition::Edition2015 => true,
             Edition::Edition2018 => true,
             Edition::Edition2021 => true,
+            Edition::Edition2024 => false,
         }
     }
+
+    pub fn rust_2015(&self) -> bool {
+        *self == Edition::Edition2015
+    }
+
+    /// Are we allowed to use features from the Rust 2018 edition?
+    pub fn rust_2018(&self) -> bool {
+        *self >= Edition::Edition2018
+    }
+
+    /// Are we allowed to use features from the Rust 2021 edition?
+    pub fn rust_2021(&self) -> bool {
+        *self >= Edition::Edition2021
+    }
+
+    /// Are we allowed to use features from the Rust 2024 edition?
+    pub fn rust_2024(&self) -> bool {
+        *self >= Edition::Edition2024
+    }
 }
 
 impl FromStr for Edition {
@@ -78,6 +103,7 @@ impl FromStr for Edition {
             "2015" => Ok(Edition::Edition2015),
             "2018" => Ok(Edition::Edition2018),
             "2021" => Ok(Edition::Edition2021),
+            "2024" => Ok(Edition::Edition2024),
             _ => Err(()),
         }
     }
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 6d7377927c291..9ae366a5fe811 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -698,6 +698,11 @@ impl Span {
         self.edition() >= edition::Edition::Edition2021
     }
 
+    #[inline]
+    pub fn rust_2024(self) -> bool {
+        self.edition() >= edition::Edition::Edition2024
+    }
+
     /// Returns the source callee.
     ///
     /// Returns `None` if the supplied span has no expansion trace,
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 2737c26708bc4..443f0a6db89ce 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1145,6 +1145,8 @@ symbols! {
         rust_2018_preview,
         rust_2021,
         rust_2021_preview,
+        rust_2024,
+        rust_2024_preview,
         rust_begin_unwind,
         rust_eh_catch_typeinfo,
         rust_eh_personality,
diff --git a/library/core/src/prelude/mod.rs b/library/core/src/prelude/mod.rs
index ccd36a428e296..3cd3a3b780e9c 100644
--- a/library/core/src/prelude/mod.rs
+++ b/library/core/src/prelude/mod.rs
@@ -45,3 +45,13 @@ pub mod rust_2021 {
     #[doc(no_inline)]
     pub use crate::convert::{TryFrom, TryInto};
 }
+
+/// The 2024 edition of the core prelude.
+///
+/// See the [module-level documentation](self) for more.
+#[unstable(feature = "prelude_2024", issue = "none")]
+pub mod rust_2024 {
+    #[unstable(feature = "prelude_2024", issue = "none")]
+    #[doc(no_inline)]
+    pub use super::rust_2021::*;
+}
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 819ec10a4b4b6..a5cdc89c5b60e 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -279,6 +279,7 @@
 #![feature(panic_info_message)]
 #![feature(panic_internals)]
 #![feature(portable_simd)]
+#![feature(prelude_2024)]
 #![feature(ptr_as_uninit)]
 #![feature(raw_os_nonzero)]
 #![feature(slice_internals)]
diff --git a/library/std/src/prelude/mod.rs b/library/std/src/prelude/mod.rs
index d4bf6aeefee57..c314bbbb68e57 100644
--- a/library/std/src/prelude/mod.rs
+++ b/library/std/src/prelude/mod.rs
@@ -132,3 +132,17 @@ pub mod rust_2021 {
     #[doc(no_inline)]
     pub use core::prelude::rust_2021::*;
 }
+
+/// The 2024 version of the prelude of The Rust Standard Library.
+///
+/// See the [module-level documentation](self) for more.
+#[unstable(feature = "prelude_2024", issue = "none")]
+pub mod rust_2024 {
+    #[unstable(feature = "prelude_2024", issue = "none")]
+    #[doc(no_inline)]
+    pub use super::v1::*;
+
+    #[unstable(feature = "prelude_2024", issue = "none")]
+    #[doc(no_inline)]
+    pub use core::prelude::rust_2024::*;
+}
diff --git a/src/test/ui/hello.rs b/src/test/ui/hello.rs
index c207c25545eca..c66b7c60fb4ea 100644
--- a/src/test/ui/hello.rs
+++ b/src/test/ui/hello.rs
@@ -1,5 +1,12 @@
 // run-pass
+// revisions: e2015 e2018 e2021 e2024
 
-pub fn main() {
-    println!("hello, world");
+//[e2018] edition:2018
+//[e2021] edition:2021
+//[e2024] edition:2024
+
+//[e2024] compile-flags: -Zunstable-options
+
+fn main() {
+    println!("hello");
 }
diff --git a/src/test/ui/hello2021.rs b/src/test/ui/hello2021.rs
deleted file mode 100644
index 134d8af5bfb8a..0000000000000
--- a/src/test/ui/hello2021.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-// run-pass
-// edition:2021
-
-fn main() {
-    println!("hello, 2021");
-}
diff --git a/src/tools/rustfmt/src/bin/main.rs b/src/tools/rustfmt/src/bin/main.rs
index ad10b9ede608f..8e871e61f2683 100644
--- a/src/tools/rustfmt/src/bin/main.rs
+++ b/src/tools/rustfmt/src/bin/main.rs
@@ -693,6 +693,7 @@ fn edition_from_edition_str(edition_str: &str) -> Result<Edition> {
         "2015" => Ok(Edition::Edition2015),
         "2018" => Ok(Edition::Edition2018),
         "2021" => Ok(Edition::Edition2021),
+        "2024" => Ok(Edition::Edition2024),
         _ => Err(format_err!("Invalid value for `--edition`")),
     }
 }
diff --git a/src/tools/rustfmt/src/config/options.rs b/src/tools/rustfmt/src/config/options.rs
index d857c29be29c6..257a17b2703a9 100644
--- a/src/tools/rustfmt/src/config/options.rs
+++ b/src/tools/rustfmt/src/config/options.rs
@@ -423,6 +423,10 @@ pub enum Edition {
     #[doc_hint = "2021"]
     /// Edition 2021.
     Edition2021,
+    #[value = "2024"]
+    #[doc_hint = "2024"]
+    /// Edition 2024.
+    Edition2024,
 }
 
 impl Default for Edition {
@@ -437,6 +441,7 @@ impl From<Edition> for rustc_span::edition::Edition {
             Edition::Edition2015 => Self::Edition2015,
             Edition::Edition2018 => Self::Edition2018,
             Edition::Edition2021 => Self::Edition2021,
+            Edition::Edition2024 => Self::Edition2024,
         }
     }
 }

From abf2b4c04d4d6a0a2c49562fde33ae1d46e6ead7 Mon Sep 17 00:00:00 2001
From: Jacob Pratt <jacob@jhpratt.dev>
Date: Mon, 28 Feb 2022 15:33:50 -0500
Subject: [PATCH 06/14] Stabilize `derive_default_enum`

---
 .../src/deriving/default.rs                   | 13 +----
 compiler/rustc_feature/src/accepted.rs        |  2 +
 compiler/rustc_feature/src/active.rs          |  2 -
 compiler/rustc_feature/src/lib.rs             |  2 +-
 compiler/rustc_infer/src/lib.rs               |  2 +-
 compiler/rustc_middle/src/lib.rs              |  2 +-
 compiler/rustc_session/src/lib.rs             |  2 +-
 compiler/rustc_trait_selection/src/lib.rs     |  2 +-
 library/core/src/lib.rs                       |  2 +-
 src/test/ui/deriving/deriving-default-enum.rs |  2 -
 src/test/ui/deriving/deriving-with-helper.rs  |  1 -
 .../feature-gate-derive_default_enum.rs       |  7 ---
 .../feature-gate-derive_default_enum.stderr   | 13 -----
 src/test/ui/macros/macros-nonfatal-errors.rs  |  1 -
 .../ui/macros/macros-nonfatal-errors.stderr   | 58 +++++++++----------
 15 files changed, 38 insertions(+), 73 deletions(-)
 delete mode 100644 src/test/ui/feature-gates/feature-gate-derive_default_enum.rs
 delete mode 100644 src/test/ui/feature-gates/feature-gate-derive_default_enum.stderr

diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs
index ca83941f600ca..2c5260616c7da 100644
--- a/compiler/rustc_builtin_macros/src/deriving/default.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/default.rs
@@ -46,18 +46,7 @@ pub fn expand_deriving_default(
                     StaticStruct(_, fields) => {
                         default_struct_substructure(cx, trait_span, substr, fields)
                     }
-                    StaticEnum(enum_def, _) => {
-                        if !cx.sess.features_untracked().derive_default_enum {
-                            rustc_session::parse::feature_err(
-                                cx.parse_sess(),
-                                sym::derive_default_enum,
-                                span,
-                                "deriving `Default` on enums is experimental",
-                            )
-                            .emit();
-                        }
-                        default_enum_substructure(cx, trait_span, enum_def)
-                    }
+                    StaticEnum(enum_def, _) => default_enum_substructure(cx, trait_span, enum_def),
                     _ => cx.span_bug(trait_span, "method in `derive(Default)`"),
                 }
             })),
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index e37251c9c2439..048039343a7a2 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -126,6 +126,8 @@ declare_features! (
     (accepted, default_type_params, "1.0.0", None, None),
     /// Allows `#[deprecated]` attribute.
     (accepted, deprecated, "1.9.0", Some(29935), None),
+    /// Allows `#[derive(Default)]` and `#[default]` on enums.
+    (accepted, derive_default_enum, "1.62.0", Some(86985), None),
     /// Allows the use of destructuring assignments.
     (accepted, destructuring_assignment, "1.59.0", Some(71126), None),
     /// Allows `#[doc(alias = "...")]`.
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 28466315c8687..81863162df318 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -368,8 +368,6 @@ declare_features! (
     (active, deprecated_safe, "1.61.0", Some(94978), None),
     /// Allows having using `suggestion` in the `#[deprecated]` attribute.
     (active, deprecated_suggestion, "1.61.0", Some(94785), None),
-    /// Allows `#[derive(Default)]` and `#[default]` on enums.
-    (active, derive_default_enum, "1.56.0", Some(86985), None),
     /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`.
     (active, doc_auto_cfg, "1.58.0", Some(43781), None),
     /// Allows `#[doc(cfg(...))]`.
diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs
index bfc537cfae2cb..940c4ecdcc23a 100644
--- a/compiler/rustc_feature/src/lib.rs
+++ b/compiler/rustc_feature/src/lib.rs
@@ -11,7 +11,7 @@
 //! even if it is stabilized or removed, *do not remove it*. Instead, move the
 //! symbol to the `accepted` or `removed` modules respectively.
 
-#![feature(derive_default_enum)]
+#![cfg_attr(bootstrap, feature(derive_default_enum))]
 #![feature(once_cell)]
 
 mod accepted;
diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs
index 08e005364ce64..e859bcaec1206 100644
--- a/compiler/rustc_infer/src/lib.rs
+++ b/compiler/rustc_infer/src/lib.rs
@@ -17,7 +17,7 @@
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
 #![feature(control_flow_enum)]
-#![feature(derive_default_enum)]
+#![cfg_attr(bootstrap, feature(derive_default_enum))]
 #![feature(extend_one)]
 #![feature(label_break_value)]
 #![feature(let_chains)]
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index fa2dad5ce25f0..cffcd6699b6e4 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -30,7 +30,7 @@
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
 #![feature(core_intrinsics)]
-#![feature(derive_default_enum)]
+#![cfg_attr(bootstrap, feature(derive_default_enum))]
 #![feature(discriminant_kind)]
 #![feature(exhaustive_patterns)]
 #![feature(get_mut_unchecked)]
diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs
index 3151b025ffff7..054b18b6b633a 100644
--- a/compiler/rustc_session/src/lib.rs
+++ b/compiler/rustc_session/src/lib.rs
@@ -1,7 +1,7 @@
 #![feature(crate_visibility_modifier)]
-#![feature(derive_default_enum)]
 #![feature(if_let_guard)]
 #![feature(let_chains)]
+#![cfg_attr(bootstrap, feature(derive_default_enum))]
 #![feature(let_else)]
 #![feature(min_specialization)]
 #![feature(never_type)]
diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs
index 7523b8441013a..2ae7f34a91e00 100644
--- a/compiler/rustc_trait_selection/src/lib.rs
+++ b/compiler/rustc_trait_selection/src/lib.rs
@@ -16,7 +16,7 @@
 #![feature(box_patterns)]
 #![feature(control_flow_enum)]
 #![feature(crate_visibility_modifier)]
-#![feature(derive_default_enum)]
+#![cfg_attr(bootstrap, feature(derive_default_enum))]
 #![feature(drain_filter)]
 #![feature(hash_drain_filter)]
 #![feature(label_break_value)]
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 660f6d92fe184..dc6bec246b9fe 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -167,7 +167,7 @@
 #![feature(const_precise_live_drops)]
 #![feature(const_refs_to_cell)]
 #![feature(decl_macro)]
-#![feature(derive_default_enum)]
+#![cfg_attr(bootstrap, feature(derive_default_enum))]
 #![feature(deprecated_suggestion)]
 #![feature(doc_cfg)]
 #![feature(doc_notable_trait)]
diff --git a/src/test/ui/deriving/deriving-default-enum.rs b/src/test/ui/deriving/deriving-default-enum.rs
index 931ff1a5847d4..d1a81c72c2fdc 100644
--- a/src/test/ui/deriving/deriving-default-enum.rs
+++ b/src/test/ui/deriving/deriving-default-enum.rs
@@ -1,7 +1,5 @@
 // run-pass
 
-#![feature(derive_default_enum)]
-
 // nb: does not impl Default
 #[derive(Debug, PartialEq)]
 struct NotDefault;
diff --git a/src/test/ui/deriving/deriving-with-helper.rs b/src/test/ui/deriving/deriving-with-helper.rs
index d8f0b27a2e5f6..1c30b0b6fba75 100644
--- a/src/test/ui/deriving/deriving-with-helper.rs
+++ b/src/test/ui/deriving/deriving-with-helper.rs
@@ -5,7 +5,6 @@
 #![feature(lang_items)]
 #![feature(no_core)]
 #![feature(rustc_attrs)]
-#![feature(derive_default_enum)]
 
 #![no_core]
 
diff --git a/src/test/ui/feature-gates/feature-gate-derive_default_enum.rs b/src/test/ui/feature-gates/feature-gate-derive_default_enum.rs
deleted file mode 100644
index 05a5d4e14223a..0000000000000
--- a/src/test/ui/feature-gates/feature-gate-derive_default_enum.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-#[derive(Default)] //~ ERROR deriving `Default` on enums is experimental
-enum Foo {
-    #[default]
-    Alpha,
-}
-
-fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-derive_default_enum.stderr b/src/test/ui/feature-gates/feature-gate-derive_default_enum.stderr
deleted file mode 100644
index 58dd4d508a709..0000000000000
--- a/src/test/ui/feature-gates/feature-gate-derive_default_enum.stderr
+++ /dev/null
@@ -1,13 +0,0 @@
-error[E0658]: deriving `Default` on enums is experimental
-  --> $DIR/feature-gate-derive_default_enum.rs:1:10
-   |
-LL | #[derive(Default)]
-   |          ^^^^^^^
-   |
-   = note: see issue #86985 <https://github.com/rust-lang/rust/issues/86985> for more information
-   = help: add `#![feature(derive_default_enum)]` to the crate attributes to enable
-   = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/macros/macros-nonfatal-errors.rs b/src/test/ui/macros/macros-nonfatal-errors.rs
index 98f64aa6f8025..e7a01f105de0b 100644
--- a/src/test/ui/macros/macros-nonfatal-errors.rs
+++ b/src/test/ui/macros/macros-nonfatal-errors.rs
@@ -5,7 +5,6 @@
 
 #![feature(trace_macros, concat_idents)]
 #![feature(stmt_expr_attributes, arbitrary_enum_discriminant)]
-#![feature(derive_default_enum)]
 
 use std::arch::asm;
 
diff --git a/src/test/ui/macros/macros-nonfatal-errors.stderr b/src/test/ui/macros/macros-nonfatal-errors.stderr
index 79e8db9c1d429..b3c6d07f96763 100644
--- a/src/test/ui/macros/macros-nonfatal-errors.stderr
+++ b/src/test/ui/macros/macros-nonfatal-errors.stderr
@@ -1,41 +1,41 @@
 error: the `#[default]` attribute may only be used on unit enum variants
-  --> $DIR/macros-nonfatal-errors.rs:14:5
+  --> $DIR/macros-nonfatal-errors.rs:13:5
    |
 LL |     #[default]
    |     ^^^^^^^^^^
 
 error: the `#[default]` attribute may only be used on unit enum variants
-  --> $DIR/macros-nonfatal-errors.rs:19:36
+  --> $DIR/macros-nonfatal-errors.rs:18:36
    |
 LL | struct DefaultInnerAttrTupleStruct(#[default] ());
    |                                    ^^^^^^^^^^
 
 error: the `#[default]` attribute may only be used on unit enum variants
-  --> $DIR/macros-nonfatal-errors.rs:23:1
+  --> $DIR/macros-nonfatal-errors.rs:22:1
    |
 LL | #[default]
    | ^^^^^^^^^^
 
 error: the `#[default]` attribute may only be used on unit enum variants
-  --> $DIR/macros-nonfatal-errors.rs:27:1
+  --> $DIR/macros-nonfatal-errors.rs:26:1
    |
 LL | #[default]
    | ^^^^^^^^^^
 
 error: the `#[default]` attribute may only be used on unit enum variants
-  --> $DIR/macros-nonfatal-errors.rs:37:11
+  --> $DIR/macros-nonfatal-errors.rs:36:11
    |
 LL |     Foo = #[default] 0,
    |           ^^^^^^^^^^
 
 error: the `#[default]` attribute may only be used on unit enum variants
-  --> $DIR/macros-nonfatal-errors.rs:38:14
+  --> $DIR/macros-nonfatal-errors.rs:37:14
    |
 LL |     Bar([u8; #[default] 1]),
    |              ^^^^^^^^^^
 
 error: no default declared
-  --> $DIR/macros-nonfatal-errors.rs:43:10
+  --> $DIR/macros-nonfatal-errors.rs:42:10
    |
 LL | #[derive(Default)]
    |          ^^^^^^^
@@ -44,7 +44,7 @@ LL | #[derive(Default)]
    = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: multiple declared defaults
-  --> $DIR/macros-nonfatal-errors.rs:49:10
+  --> $DIR/macros-nonfatal-errors.rs:48:10
    |
 LL | #[derive(Default)]
    |          ^^^^^^^
@@ -62,7 +62,7 @@ LL |     Baz,
    = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: `#[default]` attribute does not accept a value
-  --> $DIR/macros-nonfatal-errors.rs:61:5
+  --> $DIR/macros-nonfatal-errors.rs:60:5
    |
 LL |     #[default = 1]
    |     ^^^^^^^^^^^^^^
@@ -70,7 +70,7 @@ LL |     #[default = 1]
    = help: try using `#[default]`
 
 error: multiple `#[default]` attributes
-  --> $DIR/macros-nonfatal-errors.rs:69:5
+  --> $DIR/macros-nonfatal-errors.rs:68:5
    |
 LL |     #[default]
    |     ---------- `#[default]` used here
@@ -81,13 +81,13 @@ LL |     Foo,
    |
    = note: only one `#[default]` attribute is needed
 help: try removing this
-  --> $DIR/macros-nonfatal-errors.rs:68:5
+  --> $DIR/macros-nonfatal-errors.rs:67:5
    |
 LL |     #[default]
    |     ^^^^^^^^^^
 
 error: multiple `#[default]` attributes
-  --> $DIR/macros-nonfatal-errors.rs:79:5
+  --> $DIR/macros-nonfatal-errors.rs:78:5
    |
 LL |     #[default]
    |     ---------- `#[default]` used here
@@ -99,7 +99,7 @@ LL |     Foo,
    |
    = note: only one `#[default]` attribute is needed
 help: try removing these
-  --> $DIR/macros-nonfatal-errors.rs:76:5
+  --> $DIR/macros-nonfatal-errors.rs:75:5
    |
 LL |     #[default]
    |     ^^^^^^^^^^
@@ -109,7 +109,7 @@ LL |     #[default]
    |     ^^^^^^^^^^
 
 error: the `#[default]` attribute may only be used on unit enum variants
-  --> $DIR/macros-nonfatal-errors.rs:86:5
+  --> $DIR/macros-nonfatal-errors.rs:85:5
    |
 LL |     Foo {},
    |     ^^^
@@ -117,7 +117,7 @@ LL |     Foo {},
    = help: consider a manual implementation of `Default`
 
 error: default variant must be exhaustive
-  --> $DIR/macros-nonfatal-errors.rs:94:5
+  --> $DIR/macros-nonfatal-errors.rs:93:5
    |
 LL |     #[non_exhaustive]
    |     ----------------- declared `#[non_exhaustive]` here
@@ -127,37 +127,37 @@ LL |     Foo,
    = help: consider a manual implementation of `Default`
 
 error: asm template must be a string literal
-  --> $DIR/macros-nonfatal-errors.rs:99:10
+  --> $DIR/macros-nonfatal-errors.rs:98:10
    |
 LL |     asm!(invalid);
    |          ^^^^^^^
 
 error: concat_idents! requires ident args
-  --> $DIR/macros-nonfatal-errors.rs:102:5
+  --> $DIR/macros-nonfatal-errors.rs:101:5
    |
 LL |     concat_idents!("not", "idents");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: argument must be a string literal
-  --> $DIR/macros-nonfatal-errors.rs:104:17
+  --> $DIR/macros-nonfatal-errors.rs:103:17
    |
 LL |     option_env!(invalid);
    |                 ^^^^^^^
 
 error: expected string literal
-  --> $DIR/macros-nonfatal-errors.rs:105:10
+  --> $DIR/macros-nonfatal-errors.rs:104:10
    |
 LL |     env!(invalid);
    |          ^^^^^^^
 
 error: expected string literal
-  --> $DIR/macros-nonfatal-errors.rs:106:10
+  --> $DIR/macros-nonfatal-errors.rs:105:10
    |
 LL |     env!(foo, abr, baz);
    |          ^^^
 
 error: environment variable `RUST_HOPEFULLY_THIS_DOESNT_EXIST` not defined
-  --> $DIR/macros-nonfatal-errors.rs:107:5
+  --> $DIR/macros-nonfatal-errors.rs:106:5
    |
 LL |     env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -165,7 +165,7 @@ LL |     env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST");
    = note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: format argument must be a string literal
-  --> $DIR/macros-nonfatal-errors.rs:109:13
+  --> $DIR/macros-nonfatal-errors.rs:108:13
    |
 LL |     format!(invalid);
    |             ^^^^^^^
@@ -176,19 +176,19 @@ LL |     format!("{}", invalid);
    |             +++++
 
 error: argument must be a string literal
-  --> $DIR/macros-nonfatal-errors.rs:111:14
+  --> $DIR/macros-nonfatal-errors.rs:110:14
    |
 LL |     include!(invalid);
    |              ^^^^^^^
 
 error: argument must be a string literal
-  --> $DIR/macros-nonfatal-errors.rs:113:18
+  --> $DIR/macros-nonfatal-errors.rs:112:18
    |
 LL |     include_str!(invalid);
    |                  ^^^^^^^
 
 error: couldn't read $DIR/i'd be quite surprised if a file with this name existed: $FILE_NOT_FOUND_MSG (os error 2)
-  --> $DIR/macros-nonfatal-errors.rs:114:5
+  --> $DIR/macros-nonfatal-errors.rs:113:5
    |
 LL |     include_str!("i'd be quite surprised if a file with this name existed");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -196,13 +196,13 @@ LL |     include_str!("i'd be quite surprised if a file with this name existed")
    = note: this error originates in the macro `include_str` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: argument must be a string literal
-  --> $DIR/macros-nonfatal-errors.rs:115:20
+  --> $DIR/macros-nonfatal-errors.rs:114:20
    |
 LL |     include_bytes!(invalid);
    |                    ^^^^^^^
 
 error: couldn't read $DIR/i'd be quite surprised if a file with this name existed: $FILE_NOT_FOUND_MSG (os error 2)
-  --> $DIR/macros-nonfatal-errors.rs:116:5
+  --> $DIR/macros-nonfatal-errors.rs:115:5
    |
 LL |     include_bytes!("i'd be quite surprised if a file with this name existed");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -210,13 +210,13 @@ LL |     include_bytes!("i'd be quite surprised if a file with this name existed
    = note: this error originates in the macro `include_bytes` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: trace_macros! accepts only `true` or `false`
-  --> $DIR/macros-nonfatal-errors.rs:118:5
+  --> $DIR/macros-nonfatal-errors.rs:117:5
    |
 LL |     trace_macros!(invalid);
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: cannot find macro `llvm_asm` in this scope
-  --> $DIR/macros-nonfatal-errors.rs:100:5
+  --> $DIR/macros-nonfatal-errors.rs:99:5
    |
 LL |     llvm_asm!(invalid);
    |     ^^^^^^^^

From a3dd654ae9f9002d3ff47e45a9a9b6afcb484d2f Mon Sep 17 00:00:00 2001
From: Jacob Pratt <jacob@jhpratt.dev>
Date: Tue, 8 Mar 2022 15:44:52 -0500
Subject: [PATCH 07/14] Add documentation

---
 library/core/src/default.rs | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/library/core/src/default.rs b/library/core/src/default.rs
index fb862f7df947b..1ce00828bf344 100644
--- a/library/core/src/default.rs
+++ b/library/core/src/default.rs
@@ -52,6 +52,23 @@
 /// This trait can be used with `#[derive]` if all of the type's fields implement
 /// `Default`. When `derive`d, it will use the default value for each field's type.
 ///
+/// ### `enum`s
+///
+/// When using `#[derive(Default)]` on an `enum`, you need to choose which unit variant will be
+/// default. You do this by placing the `#[default]` attribute on the variant.
+///
+/// ```
+/// #[derive(Default)]
+/// enum Kind {
+///     #[default]
+///     A,
+///     B,
+///     C,
+/// }
+/// ```
+///
+/// You cannot use the `#[default]` attribute on non-unit or non-exhaustive variants.
+///
 /// ## How can I implement `Default`?
 ///
 /// Provide an implementation for the `default()` method that returns the value of

From edeb826d0a6c157f389f94b8525794b52362e174 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Sun, 10 Apr 2022 12:23:42 -0700
Subject: [PATCH 08/14] Inline shallow_resolve_ty into ShallowResolver

---
 compiler/rustc_infer/src/infer/mod.rs | 83 +++++++++++++--------------
 1 file changed, 39 insertions(+), 44 deletions(-)

diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 2524bd78355a1..e1cad1a4f6cef 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -1659,49 +1659,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         self.tcx.const_eval_resolve(param_env_erased, unevaluated, span)
     }
 
-    /// If `typ` is a type variable of some kind, resolve it one level
-    /// (but do not resolve types found in the result). If `typ` is
-    /// not a type variable, just return it unmodified.
-    // FIXME(eddyb) inline into `ShallowResolver::visit_ty`.
-    fn shallow_resolve_ty(&self, typ: Ty<'tcx>) -> Ty<'tcx> {
-        match *typ.kind() {
-            ty::Infer(ty::TyVar(v)) => {
-                // Not entirely obvious: if `typ` is a type variable,
-                // it can be resolved to an int/float variable, which
-                // can then be recursively resolved, hence the
-                // recursion. Note though that we prevent type
-                // variables from unifying to other type variables
-                // directly (though they may be embedded
-                // structurally), and we prevent cycles in any case,
-                // so this recursion should always be of very limited
-                // depth.
-                //
-                // Note: if these two lines are combined into one we get
-                // dynamic borrow errors on `self.inner`.
-                let known = self.inner.borrow_mut().type_variables().probe(v).known();
-                known.map_or(typ, |t| self.shallow_resolve_ty(t))
-            }
-
-            ty::Infer(ty::IntVar(v)) => self
-                .inner
-                .borrow_mut()
-                .int_unification_table()
-                .probe_value(v)
-                .map(|v| v.to_type(self.tcx))
-                .unwrap_or(typ),
-
-            ty::Infer(ty::FloatVar(v)) => self
-                .inner
-                .borrow_mut()
-                .float_unification_table()
-                .probe_value(v)
-                .map(|v| v.to_type(self.tcx))
-                .unwrap_or(typ),
-
-            _ => typ,
-        }
-    }
-
     /// `ty_or_const_infer_var_changed` is equivalent to one of these two:
     ///   * `shallow_resolve(ty) != ty` (where `ty.kind = ty::Infer(_)`)
     ///   * `shallow_resolve(ct) != ct` (where `ct.kind = ty::ConstKind::Infer(_)`)
@@ -1831,8 +1788,46 @@ impl<'a, 'tcx> TypeFolder<'tcx> for ShallowResolver<'a, 'tcx> {
         self.infcx.tcx
     }
 
+    /// If `ty` is a type variable of some kind, resolve it one level
+    /// (but do not resolve types found in the result). If `typ` is
+    /// not a type variable, just return it unmodified.
     fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        self.infcx.shallow_resolve_ty(ty)
+        match *ty.kind() {
+            ty::Infer(ty::TyVar(v)) => {
+                // Not entirely obvious: if `typ` is a type variable,
+                // it can be resolved to an int/float variable, which
+                // can then be recursively resolved, hence the
+                // recursion. Note though that we prevent type
+                // variables from unifying to other type variables
+                // directly (though they may be embedded
+                // structurally), and we prevent cycles in any case,
+                // so this recursion should always be of very limited
+                // depth.
+                //
+                // Note: if these two lines are combined into one we get
+                // dynamic borrow errors on `self.inner`.
+                let known = self.infcx.inner.borrow_mut().type_variables().probe(v).known();
+                known.map_or(ty, |t| self.fold_ty(t))
+            }
+
+            ty::Infer(ty::IntVar(v)) => self
+                .infcx
+                .inner
+                .borrow_mut()
+                .int_unification_table()
+                .probe_value(v)
+                .map_or(ty, |v| v.to_type(self.infcx.tcx)),
+
+            ty::Infer(ty::FloatVar(v)) => self
+                .infcx
+                .inner
+                .borrow_mut()
+                .float_unification_table()
+                .probe_value(v)
+                .map_or(ty, |v| v.to_type(self.infcx.tcx)),
+
+            _ => ty,
+        }
     }
 
     fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {

From 4a0f8d517529cdaca6750966536052b5104b05be Mon Sep 17 00:00:00 2001
From: rainy-me <github@yue.coffee>
Date: Thu, 14 Apr 2022 03:22:02 +0900
Subject: [PATCH 09/14] improve diagnostics for unterminated nested block
 comment

---
 compiler/rustc_parse/src/lexer/mod.rs         | 63 ++++++++++++++++---
 src/test/ui/unterminated-nested-comment.rs    |  4 ++
 .../ui/unterminated-nested-comment.stderr     | 21 +++++++
 3 files changed, 78 insertions(+), 10 deletions(-)
 create mode 100644 src/test/ui/unterminated-nested-comment.rs
 create mode 100644 src/test/ui/unterminated-nested-comment.stderr

diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index 5ab412dc777de..96513958eb06b 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -182,16 +182,7 @@ impl<'a> StringReader<'a> {
             }
             rustc_lexer::TokenKind::BlockComment { doc_style, terminated } => {
                 if !terminated {
-                    let msg = match doc_style {
-                        Some(_) => "unterminated block doc-comment",
-                        None => "unterminated block comment",
-                    };
-                    let last_bpos = self.pos;
-                    self.sess.span_diagnostic.span_fatal_with_code(
-                        self.mk_sp(start, last_bpos),
-                        msg,
-                        error_code!(E0758),
-                    );
+                    self.report_unterminated_block_comment(start, doc_style);
                 }
 
                 // Skip non-doc comments
@@ -553,6 +544,58 @@ impl<'a> StringReader<'a> {
         err.emit()
     }
 
+    fn report_unterminated_block_comment(&self, start: BytePos, doc_style: Option<DocStyle>) {
+        let msg = match doc_style {
+            Some(_) => "unterminated block doc-comment",
+            None => "unterminated block comment",
+        };
+        let last_bpos = self.pos;
+        let mut err = self.sess.span_diagnostic.struct_span_fatal_with_code(
+            self.mk_sp(start, last_bpos),
+            msg,
+            error_code!(E0758),
+        );
+        let mut nested_block_comment_open_idxs = vec![];
+        let mut last_nested_block_comment_idxs = None;
+        let mut content_chars = self.str_from(start).char_indices();
+
+        if let Some((_, mut last_char)) = content_chars.next() {
+            while let Some((idx, c)) = content_chars.next() {
+                match c {
+                    '*' if last_char == '/' => {
+                        nested_block_comment_open_idxs.push(idx);
+                    }
+                    '/' if last_char == '*' => {
+                        last_nested_block_comment_idxs =
+                            nested_block_comment_open_idxs.pop().map(|open_idx| (open_idx, idx));
+                    }
+                    _ => {}
+                };
+                last_char = c;
+            }
+        }
+
+        if let Some((nested_open_idx, nested_close_idx)) = last_nested_block_comment_idxs {
+            err.span_label(self.mk_sp(start, start + BytePos(2)), msg)
+                .span_label(
+                    self.mk_sp(
+                        start + BytePos(nested_open_idx as u32 - 1),
+                        start + BytePos(nested_open_idx as u32 + 1),
+                    ),
+                    "...as last nested comment starts here, maybe you want to close this instead?",
+                )
+                .span_label(
+                    self.mk_sp(
+                        start + BytePos(nested_close_idx as u32 - 1),
+                        start + BytePos(nested_close_idx as u32 + 1),
+                    ),
+                    "...and last nested comment terminates here",
+                );
+        }
+
+        err.emit();
+    }
+
     // RFC 3101 introduced the idea of (reserved) prefixes. As of Rust 2021,
     // using a (unknown) prefix is an error. In earlier editions, however, they
     // only result in a (allowed by default) lint, and are treated as regular
diff --git a/src/test/ui/unterminated-nested-comment.rs b/src/test/ui/unterminated-nested-comment.rs
new file mode 100644
index 0000000000000..db5f2f3ba1358
--- /dev/null
+++ b/src/test/ui/unterminated-nested-comment.rs
@@ -0,0 +1,4 @@
+/* //~ ERROR E0758
+/* */
+/*
+*/
diff --git a/src/test/ui/unterminated-nested-comment.stderr b/src/test/ui/unterminated-nested-comment.stderr
new file mode 100644
index 0000000000000..eda8f2dcd2469
--- /dev/null
+++ b/src/test/ui/unterminated-nested-comment.stderr
@@ -0,0 +1,21 @@
+error[E0758]: unterminated block comment
+  --> $DIR/unterminated-nested-comment.rs:1:1
+   |
+LL |   /*
+   |   ^-
+   |   |
+   |  _unterminated block comment
+   | |
+LL | | /* */
+LL | | /*
+   | | --
+   | | |
+   | | ...as last nested comment starts here, maybe you want to close this instead?
+LL | | */
+   | |_--^
+   |   |
+   |   ...and last nested comment terminates here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0758`.

From 733ef089d9f59234e93f84dbe94472f0f9f2a34b Mon Sep 17 00:00:00 2001
From: Dan Gohman <dev@sunfishcode.online>
Date: Wed, 13 Apr 2022 14:32:17 -0700
Subject: [PATCH 10/14] Add a comment explaining the `(())` idiom for empty
 structs.

---
 library/std/src/os/windows/io/handle.rs | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs
index 707b8a301727c..1408b2e83f87a 100644
--- a/library/std/src/os/windows/io/handle.rs
+++ b/library/std/src/os/windows/io/handle.rs
@@ -219,6 +219,7 @@ impl TryFrom<HandleOrInvalid> for OwnedHandle {
 
 /// This is the error type used by [`HandleOrNull`] when attempting to convert
 /// into a handle, to indicate that the value is null.
+// The empty field prevents constructing this, and allows extending it in the future.
 #[unstable(feature = "io_safety", issue = "87074")]
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct NullHandleError(());
@@ -236,6 +237,7 @@ impl crate::error::Error for NullHandleError {}
 /// This is the error type used by [`HandleOrInvalid`] when attempting to
 /// convert into a handle, to indicate that the value is
 /// `INVALID_HANDLE_VALUE`.
+// The empty field prevents constructing this, and allows extending it in the future.
 #[unstable(feature = "io_safety", issue = "87074")]
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct InvalidHandleError(());

From 849ede1cee9cca22683f9061f466cee82b738a36 Mon Sep 17 00:00:00 2001
From: Eric Huss <eric@huss.org>
Date: Wed, 13 Apr 2022 18:28:57 -0700
Subject: [PATCH 11/14] Update books

---
 src/doc/book            | 2 +-
 src/doc/nomicon         | 2 +-
 src/doc/reference       | 2 +-
 src/doc/rust-by-example | 2 +-
 src/doc/rustc-dev-guide | 2 +-
 5 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/doc/book b/src/doc/book
index ea90bbaf53ba6..765318b844569 160000
--- a/src/doc/book
+++ b/src/doc/book
@@ -1 +1 @@
-Subproject commit ea90bbaf53ba64ef4e2da9ac2352b298aec6bec8
+Subproject commit 765318b844569a642ceef7bf1adab9639cbf6af3
diff --git a/src/doc/nomicon b/src/doc/nomicon
index 11f1165e8a2f5..c7d8467ca9158 160000
--- a/src/doc/nomicon
+++ b/src/doc/nomicon
@@ -1 +1 @@
-Subproject commit 11f1165e8a2f5840467e748c8108dc53c948ee9a
+Subproject commit c7d8467ca9158da58ef295ae65dbf00a308752d9
diff --git a/src/doc/reference b/src/doc/reference
index c97d14fa6fed0..b5f6c2362baf9 160000
--- a/src/doc/reference
+++ b/src/doc/reference
@@ -1 +1 @@
-Subproject commit c97d14fa6fed0baa9255432b8a93cb70614f80e3
+Subproject commit b5f6c2362baf932db9440fbfcb509b309237ee85
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
index ec954f35eedf5..c2a98d9fc5d29 160000
--- a/src/doc/rust-by-example
+++ b/src/doc/rust-by-example
@@ -1 +1 @@
-Subproject commit ec954f35eedf592cd173b21c05a7f80a65b61d8a
+Subproject commit c2a98d9fc5d29c481d42052fbeccfde15ed03116
diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide
index 155126b1d2e2c..eeb5a83c15b6a 160000
--- a/src/doc/rustc-dev-guide
+++ b/src/doc/rustc-dev-guide
@@ -1 +1 @@
-Subproject commit 155126b1d2e2cb01ddb1d7ba9489b90d7cd173ad
+Subproject commit eeb5a83c15b6ae60df3e4f19207376b22c6fbc4c

From f6d957701f8113d8c05e6a2397b93ad6fc450400 Mon Sep 17 00:00:00 2001
From: Boyd Kane <33420535+beyarkay@users.noreply.github.com>
Date: Thu, 14 Apr 2022 09:51:47 +0200
Subject: [PATCH 12/14] docs: add link from zip to unzip

The docs for `Iterator::unzip` explain that it is kind of an inverse operation to `Iterator::zip` and guide the reader to the `zip` docs, but the `zip` docs don't let the user know that they can undo the `zip` operation with `unzip`. This change modifies the docs to help the user find `unzip`.
---
 library/core/src/iter/traits/iterator.rs | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index 53fbe4cbc42f5..eae29278f5572 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -469,6 +469,10 @@ pub trait Iterator {
     /// If the zipped iterator has no more elements to return then each further attempt to advance
     /// it will first try to advance the first iterator at most one time and if it still yielded an item
     /// try to advance the second iterator at most one time.
+    ///    
+    /// To 'undo' the result of zipping up two iterators, see [`unzip`].
+    ///
+    /// [`unzip`]: Iterator::unzip
     ///
     /// # Examples
     ///

From d73e32867f45690720c17422b83c8abc8ceff645 Mon Sep 17 00:00:00 2001
From: Boyd Kane <33420535+beyarkay@users.noreply.github.com>
Date: Thu, 14 Apr 2022 11:19:49 +0200
Subject: [PATCH 13/14] Remove trailing whitespace

Co-authored-by: Mara Bos <m-ou.se@m-ou.se>
---
 library/core/src/iter/traits/iterator.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index eae29278f5572..69f06fb06ef5d 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -469,7 +469,7 @@ pub trait Iterator {
     /// If the zipped iterator has no more elements to return then each further attempt to advance
     /// it will first try to advance the first iterator at most one time and if it still yielded an item
     /// try to advance the second iterator at most one time.
-    ///    
+    ///
     /// To 'undo' the result of zipping up two iterators, see [`unzip`].
     ///
     /// [`unzip`]: Iterator::unzip

From 1b7008dc77e25049b04e5c3e31aecf4de00803e7 Mon Sep 17 00:00:00 2001
From: rainy-me <github@yue.coffee>
Date: Thu, 14 Apr 2022 21:18:27 +0900
Subject: [PATCH 14/14] refactor: change to use peekable

---
 compiler/rustc_parse/src/lexer/mod.rs         | 37 +++++++++----------
 .../ui/unterminated-nested-comment.stderr     |  2 +-
 2 files changed, 18 insertions(+), 21 deletions(-)

diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index 96513958eb06b..e5ee1d5dab92e 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -557,39 +557,36 @@ impl<'a> StringReader<'a> {
         );
         let mut nested_block_comment_open_idxs = vec![];
         let mut last_nested_block_comment_idxs = None;
-        let mut content_chars = self.str_from(start).char_indices();
+        let mut content_chars = self.str_from(start).char_indices().peekable();
 
-        if let Some((_, mut last_char)) = content_chars.next() {
-            while let Some((idx, c)) = content_chars.next() {
-                match c {
-                    '*' if last_char == '/' => {
-                        nested_block_comment_open_idxs.push(idx);
-                    }
-                    '/' if last_char == '*' => {
-                        last_nested_block_comment_idxs =
-                            nested_block_comment_open_idxs.pop().map(|open_idx| (open_idx, idx));
-                    }
-                    _ => {}
-                };
-                last_char = c;
-            }
+        while let Some((idx, current_char)) = content_chars.next() {
+            match content_chars.peek() {
+                Some((_, '*')) if current_char == '/' => {
+                    nested_block_comment_open_idxs.push(idx);
+                }
+                Some((_, '/')) if current_char == '*' => {
+                    last_nested_block_comment_idxs =
+                        nested_block_comment_open_idxs.pop().map(|open_idx| (open_idx, idx));
+                }
+                _ => {}
+            };
         }
 
         if let Some((nested_open_idx, nested_close_idx)) = last_nested_block_comment_idxs {
             err.span_label(self.mk_sp(start, start + BytePos(2)), msg)
                 .span_label(
                     self.mk_sp(
-                        start + BytePos(nested_open_idx as u32 - 1),
-                        start + BytePos(nested_open_idx as u32 + 1),
+                        start + BytePos(nested_open_idx as u32),
+                        start + BytePos(nested_open_idx as u32 + 2),
                     ),
                     "...as last nested comment starts here, maybe you want to close this instead?",
                 )
                 .span_label(
                     self.mk_sp(
-                        start + BytePos(nested_close_idx as u32 - 1),
-                        start + BytePos(nested_close_idx as u32 + 1),
+                        start + BytePos(nested_close_idx as u32),
+                        start + BytePos(nested_close_idx as u32 + 2),
                     ),
-                    "...and last nested comment terminates here",
+                    "...and last nested comment terminates here.",
                 );
         }
 
diff --git a/src/test/ui/unterminated-nested-comment.stderr b/src/test/ui/unterminated-nested-comment.stderr
index eda8f2dcd2469..3653e76c9cbda 100644
--- a/src/test/ui/unterminated-nested-comment.stderr
+++ b/src/test/ui/unterminated-nested-comment.stderr
@@ -14,7 +14,7 @@ LL | | /*
 LL | | */
    | |_--^
    |   |
-   |   ...and last nested comment terminates here
+   |   ...and last nested comment terminates here.
 
 error: aborting due to previous error