From 709ea7469f5093fb488607fcb966445c63d49a7a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?A=C3=AFssata?= <aimaiga2@gmail.com>
Date: Mon, 11 Jul 2022 13:12:41 +0000
Subject: [PATCH 01/21] Add Read Impl for &Stdin

---
 library/std/src/io/stdio.rs | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs
index 261b570dee74f..e929eaa639696 100644
--- a/library/std/src/io/stdio.rs
+++ b/library/std/src/io/stdio.rs
@@ -445,6 +445,29 @@ impl Read for Stdin {
     }
 }
 
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Read for &Stdin {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        self.lock().read(buf)
+    }
+    fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        self.lock().read_vectored(bufs)
+    }
+    #[inline]
+    fn is_read_vectored(&self) -> bool {
+        self.lock().is_read_vectored()
+    }
+    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        self.lock().read_to_end(buf)
+    }
+    fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
+        self.lock().read_to_string(buf)
+    }
+    fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
+        self.lock().read_exact(buf)
+    }
+}
+
 // only used by platform-dependent io::copy specializations, i.e. unused on some platforms
 #[cfg(any(target_os = "linux", target_os = "android"))]
 impl StdinLock<'_> {

From 1ea6cd715e01f14395ee3f7d944ecc68adf0dde4 Mon Sep 17 00:00:00 2001
From: ltdk <usr@ltdk.xyz>
Date: Sat, 19 Aug 2023 18:46:11 -0400
Subject: [PATCH 02/21] Add std::ffi::c_str modules

---
 library/alloc/src/ffi/c_str.rs |  2 ++
 library/alloc/src/ffi/mod.rs   | 10 +++++++---
 library/core/src/ffi/c_str.rs  | 17 ++++++++++++-----
 library/core/src/ffi/mod.rs    | 14 ++++++++++++--
 library/std/src/ffi/c_str.rs   | 19 +++++++++++++++++++
 library/std/src/ffi/mod.rs     | 32 ++++++++++++++++++++++++++------
 library/std/src/lib.rs         |  1 +
 7 files changed, 79 insertions(+), 16 deletions(-)
 create mode 100644 library/std/src/ffi/c_str.rs

diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs
index 9419b0cfb24fa..35d1f681af605 100644
--- a/library/alloc/src/ffi/c_str.rs
+++ b/library/alloc/src/ffi/c_str.rs
@@ -1,3 +1,5 @@
+//! [`CString`] and its related types.
+
 #[cfg(test)]
 mod tests;
 
diff --git a/library/alloc/src/ffi/mod.rs b/library/alloc/src/ffi/mod.rs
index e8530fbc1f08f..9fc1acc231bff 100644
--- a/library/alloc/src/ffi/mod.rs
+++ b/library/alloc/src/ffi/mod.rs
@@ -80,9 +80,13 @@
 
 #![stable(feature = "alloc_ffi", since = "1.64.0")]
 
+#[doc(no_inline)]
 #[stable(feature = "alloc_c_string", since = "1.64.0")]
-pub use self::c_str::FromVecWithNulError;
+pub use self::c_str::{FromVecWithNulError, IntoStringError, NulError};
+
+#[doc(inline)]
 #[stable(feature = "alloc_c_string", since = "1.64.0")]
-pub use self::c_str::{CString, IntoStringError, NulError};
+pub use self::c_str::CString;
 
-mod c_str;
+#[unstable(feature = "c_str_module", issue = "112134")]
+pub mod c_str;
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index 248943cf02260..cf1427b21bc74 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -1,3 +1,5 @@
+//! [`CStr`] and its related types.
+
 use crate::cmp::Ordering;
 use crate::error::Error;
 use crate::ffi::c_char;
@@ -8,15 +10,20 @@ use crate::slice;
 use crate::slice::memchr;
 use crate::str;
 
+// FIXME: because this is doc(inline)d, we *have* to use intra-doc links because the actual link
+//   depends on where the item is being documented. however, since this is libcore, we can't
+//   actually reference libstd or liballoc in intra-doc links. so, the best we can do is remove the
+//   links to `CString` and `String` for now until a solution is developed
+
 /// Representation of a borrowed C string.
 ///
 /// This type represents a borrowed reference to a nul-terminated
 /// array of bytes. It can be constructed safely from a <code>&[[u8]]</code>
 /// slice, or unsafely from a raw `*const c_char`. It can then be
 /// converted to a Rust <code>&[str]</code> by performing UTF-8 validation, or
-/// into an owned [`CString`].
+/// into an owned `CString`.
 ///
-/// `&CStr` is to [`CString`] as <code>&[str]</code> is to [`String`]: the former
+/// `&CStr` is to `CString` as <code>&[str]</code> is to `String`: the former
 /// in each pair are borrowed references; the latter are owned
 /// strings.
 ///
@@ -25,9 +32,6 @@ use crate::str;
 /// Instead, safe wrappers of FFI functions may leverage the unsafe [`CStr::from_ptr`] constructor
 /// to provide a safe interface to other consumers.
 ///
-/// [`CString`]: ../../std/ffi/struct.CString.html
-/// [`String`]: ../../std/string/struct.String.html
-///
 /// # Examples
 ///
 /// Inspecting a foreign C string:
@@ -124,10 +128,13 @@ enum FromBytesWithNulErrorKind {
     NotNulTerminated,
 }
 
+// FIXME: const stability attributes should not be required here, I think
 impl FromBytesWithNulError {
+    #[rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0")]
     const fn interior_nul(pos: usize) -> FromBytesWithNulError {
         FromBytesWithNulError { kind: FromBytesWithNulErrorKind::InteriorNul(pos) }
     }
+    #[rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0")]
     const fn not_nul_terminated() -> FromBytesWithNulError {
         FromBytesWithNulError { kind: FromBytesWithNulErrorKind::NotNulTerminated }
     }
diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs
index 44200926a32eb..3627e844222ac 100644
--- a/library/core/src/ffi/mod.rs
+++ b/library/core/src/ffi/mod.rs
@@ -13,10 +13,20 @@ use crate::fmt;
 use crate::marker::PhantomData;
 use crate::ops::{Deref, DerefMut};
 
+#[doc(no_inline)]
 #[stable(feature = "core_c_str", since = "1.64.0")]
-pub use self::c_str::{CStr, FromBytesUntilNulError, FromBytesWithNulError};
+pub use self::c_str::FromBytesWithNulError;
 
-mod c_str;
+#[doc(no_inline)]
+#[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")]
+pub use self::c_str::FromBytesUntilNulError;
+
+#[doc(inline)]
+#[stable(feature = "core_c_str", since = "1.64.0")]
+pub use self::c_str::CStr;
+
+#[unstable(feature = "c_str_module", issue = "112134")]
+pub mod c_str;
 
 macro_rules! type_alias {
     {
diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs
new file mode 100644
index 0000000000000..b59b0c5bba65a
--- /dev/null
+++ b/library/std/src/ffi/c_str.rs
@@ -0,0 +1,19 @@
+//! [`CStr`], [`CString`], and related types.
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::ffi::c_str::CStr;
+
+#[stable(feature = "cstr_from_bytes", since = "1.10.0")]
+pub use core::ffi::c_str::FromBytesWithNulError;
+
+#[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")]
+pub use core::ffi::c_str::FromBytesUntilNulError;
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use alloc::ffi::c_str::{CString, NulError};
+
+#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
+pub use alloc::ffi::c_str::FromVecWithNulError;
+
+#[stable(feature = "cstring_into", since = "1.7.0")]
+pub use alloc::ffi::c_str::IntoStringError;
diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs
index 818571ddaaa16..a14a3fe760da0 100644
--- a/library/std/src/ffi/mod.rs
+++ b/library/std/src/ffi/mod.rs
@@ -161,12 +161,32 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-#[stable(feature = "alloc_c_string", since = "1.64.0")]
-pub use alloc::ffi::{CString, FromVecWithNulError, IntoStringError, NulError};
-#[stable(feature = "cstr_from_bytes_until_nul", since = "1.73.0")]
-pub use core::ffi::FromBytesUntilNulError;
-#[stable(feature = "core_c_str", since = "1.64.0")]
-pub use core::ffi::{CStr, FromBytesWithNulError};
+#[unstable(feature = "c_str_module", issue = "112134")]
+pub mod c_str;
+
+#[doc(inline)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::c_str::{CStr, CString};
+
+#[doc(no_inline)]
+#[stable(feature = "cstr_from_bytes", since = "1.10.0")]
+pub use self::c_str::FromBytesWithNulError;
+
+#[doc(no_inline)]
+#[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")]
+pub use self::c_str::FromBytesUntilNulError;
+
+#[doc(no_inline)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::c_str::NulError;
+
+#[doc(no_inline)]
+#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
+pub use self::c_str::FromVecWithNulError;
+
+#[doc(no_inline)]
+#[stable(feature = "cstring_into", since = "1.7.0")]
+pub use self::c_str::IntoStringError;
 
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::os_str::{OsStr, OsString};
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index c6cd2c6786ad6..87d9a0c9185e8 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -314,6 +314,7 @@
 //
 // Library features (core):
 // tidy-alphabetical-start
+#![feature(c_str_module)]
 #![feature(char_internals)]
 #![feature(core_intrinsics)]
 #![feature(core_io_borrowed_buf)]

From b921a34f1738a615c17db513868b6c5219f32893 Mon Sep 17 00:00:00 2001
From: David Tolnay <dtolnay@gmail.com>
Date: Sun, 25 Feb 2024 23:47:10 -0800
Subject: [PATCH 03/21] Fix stable feature name and stabilization version of
 Read for &Stdin

---
 library/std/src/io/stdio.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs
index e929eaa639696..6920281f24bf2 100644
--- a/library/std/src/io/stdio.rs
+++ b/library/std/src/io/stdio.rs
@@ -445,7 +445,7 @@ impl Read for Stdin {
     }
 }
 
-#[stable(feature = "rust1", since = "1.0.0")]
+#[stable(feature = "read_shared_stdin", since = "CURRENT_RUSTC_VERSION")]
 impl Read for &Stdin {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
         self.lock().read(buf)

From b18280f9d5d07ff1a1b5352924c383c1ed3024e9 Mon Sep 17 00:00:00 2001
From: David Tolnay <dtolnay@gmail.com>
Date: Sun, 25 Feb 2024 23:50:00 -0800
Subject: [PATCH 04/21] Fill in Read::read_buf for &Stdin

---
 library/std/src/io/stdio.rs | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs
index 6920281f24bf2..19ed03056a2f9 100644
--- a/library/std/src/io/stdio.rs
+++ b/library/std/src/io/stdio.rs
@@ -450,6 +450,9 @@ impl Read for &Stdin {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
         self.lock().read(buf)
     }
+    fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> {
+        self.lock().read_buf(buf)
+    }
     fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         self.lock().read_vectored(bufs)
     }

From f27a22c24a51ba734e4eb25c499320d819ebe236 Mon Sep 17 00:00:00 2001
From: Kornel <kornel@geekhood.net>
Date: Tue, 30 Jan 2024 15:58:08 +0000
Subject: [PATCH 05/21] try_with_capacity for RawVec

---
 library/alloc/src/raw_vec.rs       | 36 +++++++++++++++++-------------
 library/alloc/src/raw_vec/tests.rs |  7 +++---
 2 files changed, 25 insertions(+), 18 deletions(-)

diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs
index dd8d6f6c7e634..2d86fa377f16d 100644
--- a/library/alloc/src/raw_vec.rs
+++ b/library/alloc/src/raw_vec.rs
@@ -17,7 +17,6 @@ use crate::collections::TryReserveErrorKind::*;
 #[cfg(test)]
 mod tests;
 
-#[cfg(not(no_global_oom_handling))]
 enum AllocInit {
     /// The contents of the new memory are uninitialized.
     Uninitialized,
@@ -93,6 +92,8 @@ impl<T> RawVec<T, Global> {
     /// zero-sized. Note that if `T` is zero-sized this means you will
     /// *not* get a `RawVec` with the requested capacity.
     ///
+    /// Non-fallible version of `try_with_capacity`
+    ///
     /// # Panics
     ///
     /// Panics if the requested capacity exceeds `isize::MAX` bytes.
@@ -104,7 +105,7 @@ impl<T> RawVec<T, Global> {
     #[must_use]
     #[inline]
     pub fn with_capacity(capacity: usize) -> Self {
-        Self::with_capacity_in(capacity, Global)
+        handle_reserve(Self::try_allocate_in(capacity, AllocInit::Uninitialized, Global))
     }
 
     /// Like `with_capacity`, but guarantees the buffer is zeroed.
@@ -142,7 +143,7 @@ impl<T, A: Allocator> RawVec<T, A> {
     #[cfg(not(no_global_oom_handling))]
     #[inline]
     pub fn with_capacity_in(capacity: usize, alloc: A) -> Self {
-        Self::allocate_in(capacity, AllocInit::Uninitialized, alloc)
+        handle_reserve(Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc))
     }
 
     /// Like `with_capacity_zeroed`, but parameterized over the choice
@@ -150,7 +151,7 @@ impl<T, A: Allocator> RawVec<T, A> {
     #[cfg(not(no_global_oom_handling))]
     #[inline]
     pub fn with_capacity_zeroed_in(capacity: usize, alloc: A) -> Self {
-        Self::allocate_in(capacity, AllocInit::Zeroed, alloc)
+        handle_reserve(Self::try_allocate_in(capacity, AllocInit::Zeroed, alloc))
     }
 
     /// Converts the entire buffer into `Box<[MaybeUninit<T>]>` with the specified `len`.
@@ -179,35 +180,40 @@ impl<T, A: Allocator> RawVec<T, A> {
         }
     }
 
-    #[cfg(not(no_global_oom_handling))]
-    fn allocate_in(capacity: usize, init: AllocInit, alloc: A) -> Self {
+    fn try_allocate_in(
+        capacity: usize,
+        init: AllocInit,
+        alloc: A,
+    ) -> Result<Self, TryReserveError> {
         // Don't allocate here because `Drop` will not deallocate when `capacity` is 0.
+
         if T::IS_ZST || capacity == 0 {
-            Self::new_in(alloc)
+            Ok(Self::new_in(alloc))
         } else {
             // We avoid `unwrap_or_else` here because it bloats the amount of
             // LLVM IR generated.
             let layout = match Layout::array::<T>(capacity) {
                 Ok(layout) => layout,
-                Err(_) => capacity_overflow(),
+                Err(_) => return Err(CapacityOverflow.into()),
             };
-            match alloc_guard(layout.size()) {
-                Ok(_) => {}
-                Err(_) => capacity_overflow(),
+
+            if let Err(err) = alloc_guard(layout.size()) {
+                return Err(err);
             }
+
             let result = match init {
                 AllocInit::Uninitialized => alloc.allocate(layout),
                 AllocInit::Zeroed => alloc.allocate_zeroed(layout),
             };
             let ptr = match result {
                 Ok(ptr) => ptr,
-                Err(_) => handle_alloc_error(layout),
+                Err(_) => return Err(AllocError { layout, non_exhaustive: () }.into()),
             };
 
             // Allocators currently return a `NonNull<[u8]>` whose length
             // matches the size requested. If that ever changes, the capacity
             // here should change to `ptr.len() / mem::size_of::<T>()`.
-            Self { ptr: Unique::from(ptr.cast()), cap: unsafe { Cap(capacity) }, alloc }
+            Ok(Self { ptr: Unique::from(ptr.cast()), cap: unsafe { Cap(capacity) }, alloc })
         }
     }
 
@@ -537,11 +543,11 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec<T, A> {
 // Central function for reserve error handling.
 #[cfg(not(no_global_oom_handling))]
 #[inline]
-fn handle_reserve(result: Result<(), TryReserveError>) {
+fn handle_reserve<T>(result: Result<T, TryReserveError>) -> T {
     match result.map_err(|e| e.kind()) {
+        Ok(res) => res,
         Err(CapacityOverflow) => capacity_overflow(),
         Err(AllocError { layout, .. }) => handle_alloc_error(layout),
-        Ok(()) => { /* yay */ }
     }
 }
 
diff --git a/library/alloc/src/raw_vec/tests.rs b/library/alloc/src/raw_vec/tests.rs
index f8cada01c0309..4194be530612d 100644
--- a/library/alloc/src/raw_vec/tests.rs
+++ b/library/alloc/src/raw_vec/tests.rs
@@ -105,13 +105,14 @@ fn zst() {
     let v: RawVec<ZST> = RawVec::with_capacity_in(100, Global);
     zst_sanity(&v);
 
-    let v: RawVec<ZST> = RawVec::allocate_in(0, AllocInit::Uninitialized, Global);
+    let v: RawVec<ZST> = RawVec::try_allocate_in(0, AllocInit::Uninitialized, Global).unwrap();
     zst_sanity(&v);
 
-    let v: RawVec<ZST> = RawVec::allocate_in(100, AllocInit::Uninitialized, Global);
+    let v: RawVec<ZST> = RawVec::try_allocate_in(100, AllocInit::Uninitialized, Global).unwrap();
     zst_sanity(&v);
 
-    let mut v: RawVec<ZST> = RawVec::allocate_in(usize::MAX, AllocInit::Uninitialized, Global);
+    let mut v: RawVec<ZST> =
+        RawVec::try_allocate_in(usize::MAX, AllocInit::Uninitialized, Global).unwrap();
     zst_sanity(&v);
 
     // Check all these operations work as expected with zero-sized elements.

From 78fb977d6b600865b7887245d24f6dca22a0099a Mon Sep 17 00:00:00 2001
From: Kornel <kornel@geekhood.net>
Date: Tue, 30 Jan 2024 16:08:57 +0000
Subject: [PATCH 06/21] try_with_capacity for Vec, VecDeque, String

#91913
---
 .../alloc/src/collections/vec_deque/mod.rs    | 24 +++++++++++++
 library/alloc/src/lib.rs                      |  1 +
 library/alloc/src/raw_vec.rs                  |  9 +++++
 library/alloc/src/string.rs                   | 13 +++++++
 library/alloc/src/vec/mod.rs                  | 34 ++++++++++++++++++
 library/alloc/tests/lib.rs                    |  1 +
 library/alloc/tests/string.rs                 | 11 ++++++
 library/alloc/tests/vec.rs                    | 12 +++++++
 library/alloc/tests/vec_deque.rs              | 11 ++++++
 tests/codegen/vec-with-capacity.rs            | 35 +++++++++++++++++++
 tests/ui/suggestions/deref-path-method.stderr |  4 +--
 tests/ui/ufcs/bad-builder.stderr              |  4 +--
 12 files changed, 155 insertions(+), 4 deletions(-)
 create mode 100644 tests/codegen/vec-with-capacity.rs

diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs
index c35bab5ef6657..41adc2e79dc74 100644
--- a/library/alloc/src/collections/vec_deque/mod.rs
+++ b/library/alloc/src/collections/vec_deque/mod.rs
@@ -559,6 +559,30 @@ impl<T> VecDeque<T> {
     pub fn with_capacity(capacity: usize) -> VecDeque<T> {
         Self::with_capacity_in(capacity, Global)
     }
+
+    /// Creates an empty deque with space for at least `capacity` elements.
+    ///
+    /// # Errors
+    ///
+    /// Returns an error if the capacity exceeds `isize::MAX` _bytes_,
+    /// or if the allocator reports allocation failure.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # #![feature(try_with_capacity)]
+    /// # #[allow(unused)]
+    /// # fn example() -> Result<(), std::collections::TryReserveError> {
+    /// use std::collections::VecDeque;
+    ///
+    /// let deque: VecDeque<u32> = VecDeque::try_with_capacity(10)?;
+    /// # Ok(()) }
+    /// ```
+    #[inline]
+    #[unstable(feature = "try_with_capacity", issue = "91913")]
+    pub fn try_with_capacity(capacity: usize) -> Result<VecDeque<T>, TryReserveError> {
+        Ok(VecDeque { head: 0, len: 0, buf: RawVec::try_with_capacity_in(capacity, Global)? })
+    }
 }
 
 impl<T, A: Allocator> VecDeque<T, A> {
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index 28695ade5bf55..ca504b05a9689 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -163,6 +163,7 @@
 #![feature(trusted_len)]
 #![feature(trusted_random_access)]
 #![feature(try_trait_v2)]
+#![feature(try_with_capacity)]
 #![feature(tuple_trait)]
 #![feature(unchecked_math)]
 #![feature(unicode_internals)]
diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs
index 2d86fa377f16d..c5cf12209d90a 100644
--- a/library/alloc/src/raw_vec.rs
+++ b/library/alloc/src/raw_vec.rs
@@ -20,6 +20,7 @@ mod tests;
 enum AllocInit {
     /// The contents of the new memory are uninitialized.
     Uninitialized,
+    #[cfg(not(no_global_oom_handling))]
     /// The new memory is guaranteed to be zeroed.
     Zeroed,
 }
@@ -146,6 +147,13 @@ impl<T, A: Allocator> RawVec<T, A> {
         handle_reserve(Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc))
     }
 
+    /// Like `try_with_capacity`, but parameterized over the choice of
+    /// allocator for the returned `RawVec`.
+    #[inline]
+    pub fn try_with_capacity_in(capacity: usize, alloc: A) -> Result<Self, TryReserveError> {
+        Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc)
+    }
+
     /// Like `with_capacity_zeroed`, but parameterized over the choice
     /// of allocator for the returned `RawVec`.
     #[cfg(not(no_global_oom_handling))]
@@ -203,6 +211,7 @@ impl<T, A: Allocator> RawVec<T, A> {
 
             let result = match init {
                 AllocInit::Uninitialized => alloc.allocate(layout),
+                #[cfg(not(no_global_oom_handling))]
                 AllocInit::Zeroed => alloc.allocate_zeroed(layout),
             };
             let ptr = match result {
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index 98ded7f6cdf5b..c4dcff1b1c49c 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -492,6 +492,19 @@ impl String {
         String { vec: Vec::with_capacity(capacity) }
     }
 
+    /// Creates a new empty `String` with at least the specified capacity.
+    ///
+    /// # Errors
+    ///
+    /// Returns [`Err`] if the capacity exceeds `isize::MAX` bytes,
+    /// or if the memory allocator reports failure.
+    ///
+    #[inline]
+    #[unstable(feature = "try_with_capacity", issue = "91913")]
+    pub fn try_with_capacity(capacity: usize) -> Result<String, TryReserveError> {
+        Ok(String { vec: Vec::try_with_capacity(capacity)? })
+    }
+
     // HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is
     // required for this method definition, is not available. Since we don't
     // require this method for testing purposes, I'll just stub it
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index 7bd19875584a3..4b8b095c752f7 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -481,6 +481,22 @@ impl<T> Vec<T> {
         Self::with_capacity_in(capacity, Global)
     }
 
+    /// Constructs a new, empty `Vec<T>` with at least the specified capacity.
+    ///
+    /// The vector will be able to hold at least `capacity` elements without
+    /// reallocating. This method is allowed to allocate for more elements than
+    /// `capacity`. If `capacity` is 0, the vector will not allocate.
+    ///
+    /// # Errors
+    ///
+    /// Returns an error if the capacity exceeds `isize::MAX` _bytes_,
+    /// or if the allocator reports allocation failure.
+    #[inline]
+    #[unstable(feature = "try_with_capacity", issue = "91913")]
+    pub fn try_with_capacity(capacity: usize) -> Result<Self, TryReserveError> {
+        Self::try_with_capacity_in(capacity, Global)
+    }
+
     /// Creates a `Vec<T>` directly from a pointer, a length, and a capacity.
     ///
     /// # Safety
@@ -672,6 +688,24 @@ impl<T, A: Allocator> Vec<T, A> {
         Vec { buf: RawVec::with_capacity_in(capacity, alloc), len: 0 }
     }
 
+    /// Constructs a new, empty `Vec<T, A>` with at least the specified capacity
+    /// with the provided allocator.
+    ///
+    /// The vector will be able to hold at least `capacity` elements without
+    /// reallocating. This method is allowed to allocate for more elements than
+    /// `capacity`. If `capacity` is 0, the vector will not allocate.
+    ///
+    /// # Errors
+    ///
+    /// Returns an error if the capacity exceeds `isize::MAX` _bytes_,
+    /// or if the allocator reports allocation failure.
+    #[inline]
+    #[unstable(feature = "allocator_api", issue = "32838")]
+    // #[unstable(feature = "try_with_capacity", issue = "91913")]
+    pub fn try_with_capacity_in(capacity: usize, alloc: A) -> Result<Self, TryReserveError> {
+        Ok(Vec { buf: RawVec::try_with_capacity_in(capacity, alloc)?, len: 0 })
+    }
+
     /// Creates a `Vec<T, A>` directly from a pointer, a length, a capacity,
     /// and an allocator.
     ///
diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs
index c4e89a58a05ac..e4e1a02fd8325 100644
--- a/library/alloc/tests/lib.rs
+++ b/library/alloc/tests/lib.rs
@@ -20,6 +20,7 @@
 #![feature(pattern)]
 #![feature(trusted_len)]
 #![feature(try_reserve_kind)]
+#![feature(try_with_capacity)]
 #![feature(unboxed_closures)]
 #![feature(associated_type_bounds)]
 #![feature(binary_heap_into_iter_sorted)]
diff --git a/library/alloc/tests/string.rs b/library/alloc/tests/string.rs
index 711e4eef2e724..e20ceae87b0d5 100644
--- a/library/alloc/tests/string.rs
+++ b/library/alloc/tests/string.rs
@@ -723,6 +723,17 @@ fn test_reserve_exact() {
     assert!(s.capacity() >= 33)
 }
 
+#[test]
+#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
+#[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc
+fn test_try_with_capacity() {
+    let string = String::try_with_capacity(1000).unwrap();
+    assert_eq!(0, string.len());
+    assert!(string.capacity() >= 1000 && string.capacity() <= isize::MAX as usize);
+
+    assert!(String::try_with_capacity(usize::MAX).is_err());
+}
+
 #[test]
 #[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
 #[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc
diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs
index 15ee4d6520523..aa95b4e977081 100644
--- a/library/alloc/tests/vec.rs
+++ b/library/alloc/tests/vec.rs
@@ -1694,6 +1694,18 @@ fn test_reserve_exact() {
     assert!(v.capacity() >= 33)
 }
 
+#[test]
+#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
+#[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc
+fn test_try_with_capacity() {
+    let mut vec: Vec<u32> = Vec::try_with_capacity(5).unwrap();
+    assert_eq!(0, vec.len());
+    assert!(vec.capacity() >= 5 && vec.capacity() <= isize::MAX as usize / 4);
+    assert!(vec.spare_capacity_mut().len() >= 5);
+
+    assert!(Vec::<u16>::try_with_capacity(isize::MAX as usize + 1).is_err());
+}
+
 #[test]
 #[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
 #[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc
diff --git a/library/alloc/tests/vec_deque.rs b/library/alloc/tests/vec_deque.rs
index eda2f8bb812b5..cea5de4dd5984 100644
--- a/library/alloc/tests/vec_deque.rs
+++ b/library/alloc/tests/vec_deque.rs
@@ -1182,6 +1182,17 @@ fn test_reserve_exact_2() {
     assert!(v.capacity() >= 33)
 }
 
+#[test]
+#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
+#[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc
+fn test_try_with_capacity() {
+    let vec: VecDeque<u32> = VecDeque::try_with_capacity(5).unwrap();
+    assert_eq!(0, vec.len());
+    assert!(vec.capacity() >= 5 && vec.capacity() <= isize::MAX as usize / 4);
+
+    assert!(VecDeque::<u16>::try_with_capacity(isize::MAX as usize + 1).is_err());
+}
+
 #[test]
 #[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
 #[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc
diff --git a/tests/codegen/vec-with-capacity.rs b/tests/codegen/vec-with-capacity.rs
new file mode 100644
index 0000000000000..47051f2eef891
--- /dev/null
+++ b/tests/codegen/vec-with-capacity.rs
@@ -0,0 +1,35 @@
+//@ compile-flags: -O
+//@ ignore-debug
+// (with debug assertions turned on, `assert_unchecked` generates a real assertion)
+
+#![crate_type = "lib"]
+#![feature(try_with_capacity)]
+
+// CHECK-LABEL: @with_capacity_does_not_grow1
+#[no_mangle]
+pub fn with_capacity_does_not_grow1() -> Vec<u32> {
+    let v = Vec::with_capacity(1234);
+    // CHECK: call {{.*}}__rust_alloc(
+    // CHECK-NOT: call {{.*}}__rust_realloc
+    // CHECK-NOT: call {{.*}}capacity_overflow
+    // CHECK-NOT: call {{.*}}finish_grow
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: memcpy
+    // CHECK-NOT: memset
+    v
+}
+
+// CHECK-LABEL: @try_with_capacity_does_not_grow2
+#[no_mangle]
+pub fn try_with_capacity_does_not_grow2() -> Option<Vec<Vec<u8>>> {
+    let v = Vec::try_with_capacity(1234).ok()?;
+    // CHECK: call {{.*}}__rust_alloc(
+    // CHECK-NOT: call {{.*}}__rust_realloc
+    // CHECK-NOT: call {{.*}}capacity_overflow
+    // CHECK-NOT: call {{.*}}finish_grow
+    // CHECK-NOT: call {{.*}}handle_alloc_error
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: memcpy
+    // CHECK-NOT: memset
+    Some(v)
+}
diff --git a/tests/ui/suggestions/deref-path-method.stderr b/tests/ui/suggestions/deref-path-method.stderr
index a2b68fa966fcb..b27d9aef06614 100644
--- a/tests/ui/suggestions/deref-path-method.stderr
+++ b/tests/ui/suggestions/deref-path-method.stderr
@@ -7,9 +7,9 @@ LL |     Vec::contains(&vec, &0);
 note: if you're trying to build a new `Vec<_, _>` consider using one of the following associated functions:
       Vec::<T>::new
       Vec::<T>::with_capacity
+      Vec::<T>::try_with_capacity
       Vec::<T>::from_raw_parts
-      Vec::<T, A>::new_in
-      and 2 others
+      and 4 others
   --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
 help: the function `contains` is implemented on `[_]`
    |
diff --git a/tests/ui/ufcs/bad-builder.stderr b/tests/ui/ufcs/bad-builder.stderr
index e1c5e45b3ebb7..9cfeb7a5d09d6 100644
--- a/tests/ui/ufcs/bad-builder.stderr
+++ b/tests/ui/ufcs/bad-builder.stderr
@@ -7,9 +7,9 @@ LL |     Vec::<Q>::mew()
 note: if you're trying to build a new `Vec<Q>` consider using one of the following associated functions:
       Vec::<T>::new
       Vec::<T>::with_capacity
+      Vec::<T>::try_with_capacity
       Vec::<T>::from_raw_parts
-      Vec::<T, A>::new_in
-      and 2 others
+      and 4 others
   --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
 help: there is an associated function `new` with a similar name
    |

From 784e6a1e080e5ba18e5c246e744e2d20525d1c3d Mon Sep 17 00:00:00 2001
From: Kornel <kornel@geekhood.net>
Date: Wed, 31 Jan 2024 15:23:52 +0000
Subject: [PATCH 07/21] Move capacity_overflow function to make ui tests change
 less

Code changes in raw_vec require blessing UI tests every time
---
 library/alloc/src/raw_vec.rs               | 18 +++++++++---------
 tests/ui/hygiene/panic-location.run.stderr |  2 +-
 2 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs
index c5cf12209d90a..5e37de18c954f 100644
--- a/library/alloc/src/raw_vec.rs
+++ b/library/alloc/src/raw_vec.rs
@@ -17,6 +17,15 @@ use crate::collections::TryReserveErrorKind::*;
 #[cfg(test)]
 mod tests;
 
+// One central function responsible for reporting capacity overflows. This'll
+// ensure that the code generation related to these panics is minimal as there's
+// only one location which panics rather than a bunch throughout the module.
+#[cfg(not(no_global_oom_handling))]
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+fn capacity_overflow() -> ! {
+    panic!("capacity overflow");
+}
+
 enum AllocInit {
     /// The contents of the new memory are uninitialized.
     Uninitialized,
@@ -576,12 +585,3 @@ fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> {
         Ok(())
     }
 }
-
-// One central function responsible for reporting capacity overflows. This'll
-// ensure that the code generation related to these panics is minimal as there's
-// only one location which panics rather than a bunch throughout the module.
-#[cfg(not(no_global_oom_handling))]
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
-fn capacity_overflow() -> ! {
-    panic!("capacity overflow");
-}
diff --git a/tests/ui/hygiene/panic-location.run.stderr b/tests/ui/hygiene/panic-location.run.stderr
index 5c552411da7f3..ec0ce18c3dfa7 100644
--- a/tests/ui/hygiene/panic-location.run.stderr
+++ b/tests/ui/hygiene/panic-location.run.stderr
@@ -1,3 +1,3 @@
-thread 'main' panicked at library/alloc/src/raw_vec.rs:571:5:
+thread 'main' panicked at library/alloc/src/raw_vec.rs:26:5:
 capacity overflow
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

From c3954b358f9e2be96d0dd553a8efaefc49f0bba7 Mon Sep 17 00:00:00 2001
From: r0cky <mu001999@outlook.com>
Date: Sun, 3 Mar 2024 00:57:37 +0800
Subject: [PATCH 08/21] Add a tidy check that checks whether the fluent slugs
 only appear once

---
 src/tools/tidy/src/fluent_alphabetical.rs | 58 ++++++++++++++++++++---
 src/tools/tidy/src/fluent_used.rs         | 43 +++++++++++++++++
 src/tools/tidy/src/lib.rs                 |  1 +
 3 files changed, 96 insertions(+), 6 deletions(-)
 create mode 100644 src/tools/tidy/src/fluent_used.rs

diff --git a/src/tools/tidy/src/fluent_alphabetical.rs b/src/tools/tidy/src/fluent_alphabetical.rs
index 67b745373f019..9803b6eab2db5 100644
--- a/src/tools/tidy/src/fluent_alphabetical.rs
+++ b/src/tools/tidy/src/fluent_alphabetical.rs
@@ -1,6 +1,7 @@
 //! Checks that all Flunt files have messages in alphabetical order
 
 use crate::walk::{filter_dirs, walk};
+use std::collections::HashMap;
 use std::{fs::OpenOptions, io::Write, path::Path};
 
 use regex::Regex;
@@ -13,11 +14,27 @@ fn filter_fluent(path: &Path) -> bool {
     if let Some(ext) = path.extension() { ext.to_str() != Some("ftl") } else { true }
 }
 
-fn check_alphabetic(filename: &str, fluent: &str, bad: &mut bool) {
+fn check_alphabetic(
+    filename: &str,
+    fluent: &str,
+    bad: &mut bool,
+    all_defined_msgs: &mut HashMap<String, String>,
+) {
     let mut matches = MESSAGE.captures_iter(fluent).peekable();
     while let Some(m) = matches.next() {
+        let name = m.get(1).unwrap();
+        if let Some(defined_filename) = all_defined_msgs.get(name.as_str()) {
+            tidy_error!(
+                bad,
+                "{filename}: message `{}` is already defined in {}",
+                name.as_str(),
+                defined_filename,
+            );
+        }
+
+        all_defined_msgs.insert(name.as_str().to_owned(), filename.to_owned());
+
         if let Some(next) = matches.peek() {
-            let name = m.get(1).unwrap();
             let next = next.get(1).unwrap();
             if name.as_str() > next.as_str() {
                 tidy_error!(
@@ -34,13 +51,29 @@ run `./x.py test tidy --bless` to sort the file correctly",
     }
 }
 
-fn sort_messages(fluent: &str) -> String {
+fn sort_messages(
+    filename: &str,
+    fluent: &str,
+    bad: &mut bool,
+    all_defined_msgs: &mut HashMap<String, String>,
+) -> String {
     let mut chunks = vec![];
     let mut cur = String::new();
     for line in fluent.lines() {
-        if MESSAGE.is_match(line) {
+        if let Some(name) = MESSAGE.find(line) {
+            if let Some(defined_filename) = all_defined_msgs.get(name.as_str()) {
+                tidy_error!(
+                    bad,
+                    "{filename}: message `{}` is already defined in {}",
+                    name.as_str(),
+                    defined_filename,
+                );
+            }
+
+            all_defined_msgs.insert(name.as_str().to_owned(), filename.to_owned());
             chunks.push(std::mem::take(&mut cur));
         }
+
         cur += line;
         cur.push('\n');
     }
@@ -53,20 +86,33 @@ fn sort_messages(fluent: &str) -> String {
 }
 
 pub fn check(path: &Path, bless: bool, bad: &mut bool) {
+    let mut all_defined_msgs = HashMap::new();
     walk(
         path,
         |path, is_dir| filter_dirs(path) || (!is_dir && filter_fluent(path)),
         &mut |ent, contents| {
             if bless {
-                let sorted = sort_messages(contents);
+                let sorted = sort_messages(
+                    ent.path().to_str().unwrap(),
+                    contents,
+                    bad,
+                    &mut all_defined_msgs,
+                );
                 if sorted != contents {
                     let mut f =
                         OpenOptions::new().write(true).truncate(true).open(ent.path()).unwrap();
                     f.write(sorted.as_bytes()).unwrap();
                 }
             } else {
-                check_alphabetic(ent.path().to_str().unwrap(), contents, bad);
+                check_alphabetic(
+                    ent.path().to_str().unwrap(),
+                    contents,
+                    bad,
+                    &mut all_defined_msgs,
+                );
             }
         },
     );
+
+    crate::fluent_used::check(path, all_defined_msgs, bad);
 }
diff --git a/src/tools/tidy/src/fluent_used.rs b/src/tools/tidy/src/fluent_used.rs
new file mode 100644
index 0000000000000..b73e79cb38d94
--- /dev/null
+++ b/src/tools/tidy/src/fluent_used.rs
@@ -0,0 +1,43 @@
+//! Checks that all Fluent messages appear at least twice
+
+use crate::walk::{filter_dirs, walk};
+use regex::Regex;
+use std::collections::HashMap;
+use std::path::Path;
+
+lazy_static::lazy_static! {
+    static ref WORD: Regex = Regex::new(r"\w+").unwrap();
+}
+
+fn filter_used_messages(
+    contents: &str,
+    msgs_not_appeared_yet: &mut HashMap<String, String>,
+    msgs_appeared_only_once: &mut HashMap<String, String>,
+) {
+    // we don't just check messages never appear in Rust files,
+    // because messages can be used as parts of other fluent messages in Fluent files,
+    // so we do checking messages appear only once in all Rust and Fluent files.
+    let mut matches = WORD.find_iter(contents);
+    while let Some(name) = matches.next() {
+        if let Some((name, filename)) = msgs_not_appeared_yet.remove_entry(name.as_str()) {
+            // if one msg appears for the first time,
+            // remove it from `msgs_not_appeared_yet` and insert it into `msgs_appeared_only_once`.
+            msgs_appeared_only_once.insert(name, filename);
+        } else {
+            // if one msg appears for the second time,
+            // remove it from `msgs_appeared_only_once`.
+            msgs_appeared_only_once.remove(name.as_str());
+        }
+    }
+}
+
+pub fn check(path: &Path, mut all_defined_msgs: HashMap<String, String>, bad: &mut bool) {
+    let mut msgs_appear_only_once = HashMap::new();
+    walk(path, |path, _| filter_dirs(path), &mut |_, contents| {
+        filter_used_messages(contents, &mut all_defined_msgs, &mut msgs_appear_only_once);
+    });
+
+    for (name, filename) in msgs_appear_only_once {
+        tidy_error!(bad, "{filename}: message `{}` is not used", name,);
+    }
+}
diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs
index 6f3ade0ab58c7..670b7eb2be995 100644
--- a/src/tools/tidy/src/lib.rs
+++ b/src/tools/tidy/src/lib.rs
@@ -65,6 +65,7 @@ pub mod ext_tool_checks;
 pub mod extdeps;
 pub mod features;
 pub mod fluent_alphabetical;
+mod fluent_used;
 pub(crate) mod iter_header;
 pub mod mir_opt_tests;
 pub mod pal;

From d88c7ffc62d0f1ee15abf3e9e65af3eeedc7d003 Mon Sep 17 00:00:00 2001
From: r0cky <mu001999@outlook.com>
Date: Sun, 3 Mar 2024 00:57:45 +0800
Subject: [PATCH 09/21] Remove unused fluent messages

---
 compiler/rustc_const_eval/messages.ftl | 3 ---
 compiler/rustc_infer/messages.ftl      | 8 --------
 compiler/rustc_lint/messages.ftl       | 2 --
 compiler/rustc_parse/messages.ftl      | 4 ----
 compiler/rustc_passes/messages.ftl     | 5 -----
 5 files changed, 22 deletions(-)

diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl
index 2805ca360ad3d..1bad62c4103a3 100644
--- a/compiler/rustc_const_eval/messages.ftl
+++ b/compiler/rustc_const_eval/messages.ftl
@@ -146,9 +146,6 @@ const_eval_intern_kind = {$kind ->
     *[other] {""}
 }
 
-const_eval_invalid_align =
-    align has to be a power of 2
-
 const_eval_invalid_align_details =
     invalid align passed to `{$name}`: {$align} is {$err_kind ->
         [not_power_of_two] not a power of 2
diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl
index 2de87cbe631ac..e44a6ae3b3f2e 100644
--- a/compiler/rustc_infer/messages.ftl
+++ b/compiler/rustc_infer/messages.ftl
@@ -181,14 +181,6 @@ infer_more_targeted = {$has_param_name ->
 
 infer_msl_introduces_static = introduces a `'static` lifetime requirement
 infer_msl_unmet_req = because this has an unmet lifetime requirement
-infer_need_type_info_in_coroutine =
-    type inside {$coroutine_kind ->
-    [async_block] `async` block
-    [async_closure] `async` closure
-    [async_fn] `async fn` body
-    *[coroutine] coroutine
-    } must be known in this context
-
 
 infer_nothing = {""}
 
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 63e2fe47659db..8bf9d0b9d4aac 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -562,8 +562,6 @@ lint_suspicious_double_ref_clone =
 lint_suspicious_double_ref_deref =
     using `.deref()` on a double reference, which returns `{$ty}` instead of dereferencing the inner type
 
-lint_trivial_untranslatable_diag = diagnostic with static strings only
-
 lint_ty_qualified = usage of qualified `ty::{$ty}`
     .suggestion = try importing it and using it unqualified
 
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index 60cc138fd7bc2..a100e2d47bbbb 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -392,9 +392,6 @@ parse_invalid_identifier_with_leading_number = identifiers cannot start with a n
 
 parse_invalid_interpolated_expression = invalid interpolated expression
 
-parse_invalid_literal_suffix = suffixes on {$kind} literals are invalid
-    .label = invalid suffix `{$suffix}`
-
 parse_invalid_literal_suffix_on_tuple_index = suffixes on a tuple index are invalid
     .label = invalid suffix `{$suffix}`
     .tuple_exception_line_1 = `{$suffix}` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases
@@ -609,7 +606,6 @@ parse_nonterminal_expected_item_keyword = expected an item keyword
 parse_nonterminal_expected_lifetime = expected a lifetime, found `{$token}`
 
 parse_nonterminal_expected_statement = expected a statement
-parse_not_supported = not supported
 
 parse_note_edition_guide = for more on editions, read https://doc.rust-lang.org/edition-guide
 
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index c223b8475288b..7fc523ffe0dea 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -302,9 +302,6 @@ passes_export_name =
     attribute should be applied to a free function, impl method or static
     .label = not a free function, impl method or static
 
-passes_expr_not_allowed_in_context =
-    {$expr} is not allowed in a `{$context}`
-
 passes_extern_main =
     the `main` function cannot be declared in an `extern` block
 
@@ -405,8 +402,6 @@ passes_lang_item_on_incorrect_target =
     `{$name}` language item must be applied to a {$expected_target}
     .label = attribute should be applied to a {$expected_target}, not a {$actual_target}
 
-passes_layout =
-    layout error: {$layout_error}
 passes_layout_abi =
     abi: {$abi}
 passes_layout_align =

From 0a0074980fb7802ac621ceac92bf98bdc640bd78 Mon Sep 17 00:00:00 2001
From: Andrew Wock <ajwock@gmail.com>
Date: Sun, 18 Feb 2024 18:06:16 -0500
Subject: [PATCH 10/21] Implement MaybeUninit::fill{,_with,_from}

ACP: rust-lang/libs-team#156

Signed-off-by: Andrew Wock <ajwock@gmail.com>
---
 library/core/src/mem/maybe_uninit.rs | 202 +++++++++++++++++++++++--
 library/core/tests/lib.rs            |   1 +
 library/core/tests/mem.rs            | 217 ++++++++++++++++++++++++++-
 3 files changed, 398 insertions(+), 22 deletions(-)

diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs
index c19b5791562ce..026e21586d403 100644
--- a/library/core/src/mem/maybe_uninit.rs
+++ b/library/core/src/mem/maybe_uninit.rs
@@ -1125,22 +1125,6 @@ impl<T> MaybeUninit<T> {
         // unlike copy_from_slice this does not call clone_from_slice on the slice
         // this is because `MaybeUninit<T: Clone>` does not implement Clone.
 
-        struct Guard<'a, T> {
-            slice: &'a mut [MaybeUninit<T>],
-            initialized: usize,
-        }
-
-        impl<'a, T> Drop for Guard<'a, T> {
-            fn drop(&mut self) {
-                let initialized_part = &mut self.slice[..self.initialized];
-                // SAFETY: this raw slice will contain only initialized objects
-                // that's why, it is allowed to drop it.
-                unsafe {
-                    crate::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(initialized_part));
-                }
-            }
-        }
-
         assert_eq!(this.len(), src.len(), "destination and source slices have different lengths");
         // NOTE: We need to explicitly slice them to the same length
         // for bounds checking to be elided, and the optimizer will
@@ -1162,6 +1146,151 @@ impl<T> MaybeUninit<T> {
         unsafe { MaybeUninit::slice_assume_init_mut(this) }
     }
 
+    /// Fills `this` with elements by cloning `value`, returning a mutable reference to the now
+    /// initialized contents of `this`.
+    /// Any previously initialized elements will not be dropped.
+    ///
+    /// This is similar to [`slice::fill`].
+    ///
+    /// # Panics
+    ///
+    /// This function will panic if any call to `Clone` panics.
+    ///
+    /// If such a panic occurs, any elements previously initialized during this operation will be
+    /// dropped.
+    ///
+    /// # Examples
+    ///
+    /// Fill an uninit vec with 1.
+    /// ```
+    /// #![feature(maybe_uninit_fill)]
+    /// use std::mem::MaybeUninit;
+    ///
+    /// let mut buf = vec![MaybeUninit::uninit(); 10];
+    /// let initialized = MaybeUninit::fill(buf.as_mut_slice(), 1);
+    /// assert_eq!(initialized, &mut [1; 10]);
+    /// ```
+    #[doc(alias = "memset")]
+    #[unstable(feature = "maybe_uninit_fill", issue = "117428")]
+    pub fn fill<'a>(this: &'a mut [MaybeUninit<T>], value: T) -> &'a mut [T]
+    where
+        T: Clone,
+    {
+        SpecFill::spec_fill(this, value);
+        // SAFETY: Valid elements have just been filled into `this` so it is initialized
+        unsafe { MaybeUninit::slice_assume_init_mut(this) }
+    }
+
+    /// Fills `this` with elements returned by calling a closure repeatedly.
+    ///
+    /// This method uses a closure to create new values.  If you'd rather `Clone` a given value, use
+    /// [`MaybeUninit::fill`].  If you want to use the `Default` trait to generate values, you can
+    /// pass [`Default::default`] as the argument.
+    ///
+    /// # Panics
+    ///
+    /// This function will panic if any call to the provided closure panics.
+    ///
+    /// If such a panic occurs, any elements previously initialized during this operation will be
+    /// dropped.
+    ///
+    /// # Examples
+    ///
+    /// Fill an uninit vec with the default value.
+    /// ```
+    /// #![feature(maybe_uninit_fill)]
+    /// use std::mem::MaybeUninit;
+    ///
+    /// let mut buf = vec![MaybeUninit::<i32>::uninit(); 10];
+    /// let initialized = MaybeUninit::fill_with(buf.as_mut_slice(), Default::default);
+    /// assert_eq!(initialized, &mut [0; 10]);
+    /// ```
+    #[unstable(feature = "maybe_uninit_fill", issue = "117428")]
+    pub fn fill_with<'a, F>(this: &'a mut [MaybeUninit<T>], mut f: F) -> &'a mut [T]
+    where
+        F: FnMut() -> T,
+    {
+        let mut guard = Guard { slice: this, initialized: 0 };
+
+        for element in guard.slice.iter_mut() {
+            element.write(f());
+            guard.initialized += 1;
+        }
+
+        super::forget(guard);
+
+        // SAFETY: Valid elements have just been written into `this` so it is initialized
+        unsafe { MaybeUninit::slice_assume_init_mut(this) }
+    }
+
+    /// Fills `this` with elements yielded by an iterator until either all elements have been
+    /// initialized or the iterator is empty.
+    ///
+    /// Returns two slices.  The first slice contains the initialized portion of the original slice.
+    /// The second slice is the still-uninitialized remainder of the original slice.
+    ///
+    /// # Panics
+    ///
+    /// This function panics if the iterator's `next` function panics.
+    ///
+    /// If such a panic occurs, any elements previously initialized during this operation will be
+    /// dropped.
+    ///
+    /// # Examples
+    ///
+    /// Fill an uninit vec with a cycling iterator.
+    /// ```
+    /// #![feature(maybe_uninit_fill)]
+    /// use std::mem::MaybeUninit;
+    ///
+    /// let mut buf = vec![MaybeUninit::uninit(); 5];
+    ///
+    /// let iter = [1, 2, 3].into_iter().cycle();
+    /// let (initialized, remainder) = MaybeUninit::fill_from(&mut buf, iter);
+    ///
+    /// assert_eq!(initialized, &mut [1, 2, 3, 1, 2]);
+    /// assert_eq!(0, remainder.len());
+    /// ```
+    ///
+    /// Fill an uninit vec, but not completely.
+    /// ```
+    /// #![feature(maybe_uninit_fill)]
+    /// use std::mem::MaybeUninit;
+    ///
+    /// let mut buf = vec![MaybeUninit::uninit(); 5];
+    /// let iter = [1, 2];
+    /// let (initialized, remainder) = MaybeUninit::fill_from(&mut buf, iter);
+    ///
+    /// assert_eq!(initialized, &mut [1, 2]);
+    /// assert_eq!(remainder.len(), 3);
+    /// ```
+    #[unstable(feature = "maybe_uninit_fill", issue = "117428")]
+    pub fn fill_from<'a, I>(
+        this: &'a mut [MaybeUninit<T>],
+        it: I,
+    ) -> (&'a mut [T], &'a mut [MaybeUninit<T>])
+    where
+        I: IntoIterator<Item = T>,
+    {
+        let iter = it.into_iter();
+        let mut guard = Guard { slice: this, initialized: 0 };
+
+        for (element, val) in guard.slice.iter_mut().zip(iter) {
+            element.write(val);
+            guard.initialized += 1;
+        }
+
+        let initialized_len = guard.initialized;
+        super::forget(guard);
+
+        // SAFETY: guard.initialized <= this.len()
+        let (initted, remainder) = unsafe { this.split_at_mut_unchecked(initialized_len) };
+
+        // SAFETY: Valid elements have just been written into `init`, so that portion
+        // of `this` is initialized.
+        (unsafe { MaybeUninit::slice_assume_init_mut(initted) }, remainder)
+    }
+
     /// Returns the contents of this `MaybeUninit` as a slice of potentially uninitialized bytes.
     ///
     /// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still
@@ -1315,3 +1444,44 @@ impl<T, const N: usize> [MaybeUninit<T>; N] {
         unsafe { intrinsics::transmute_unchecked(self) }
     }
 }
+
+struct Guard<'a, T> {
+    slice: &'a mut [MaybeUninit<T>],
+    initialized: usize,
+}
+
+impl<'a, T> Drop for Guard<'a, T> {
+    fn drop(&mut self) {
+        let initialized_part = &mut self.slice[..self.initialized];
+        // SAFETY: this raw sub-slice will contain only initialized objects.
+        unsafe {
+            crate::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(initialized_part));
+        }
+    }
+}
+
+trait SpecFill<T> {
+    fn spec_fill(&mut self, value: T);
+}
+
+impl<T: Clone> SpecFill<T> for [MaybeUninit<T>] {
+    default fn spec_fill(&mut self, value: T) {
+        let mut guard = Guard { slice: self, initialized: 0 };
+
+        if let Some((last, elems)) = guard.slice.split_last_mut() {
+            for el in elems {
+                el.write(value.clone());
+                guard.initialized += 1;
+            }
+
+            last.write(value);
+        }
+        super::forget(guard);
+    }
+}
+
+impl<T: Copy> SpecFill<T> for [MaybeUninit<T>] {
+    fn spec_fill(&mut self, value: T) {
+        self.fill(MaybeUninit::new(value));
+    }
+}
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index fa0e9a979d060..c5a7e87c4aa4f 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -54,6 +54,7 @@
 #![feature(slice_from_ptr_range)]
 #![feature(slice_split_once)]
 #![feature(split_as_slice)]
+#![feature(maybe_uninit_fill)]
 #![feature(maybe_uninit_uninit_array)]
 #![feature(maybe_uninit_write_slice)]
 #![feature(maybe_uninit_uninit_array_transpose)]
diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs
index 0f7fde747690a..e388800f400df 100644
--- a/library/core/tests/mem.rs
+++ b/library/core/tests/mem.rs
@@ -308,21 +308,226 @@ fn uninit_write_slice_cloned_mid_panic() {
     }
 }
 
+#[derive(Clone)]
+struct Bomb;
+
+impl Drop for Bomb {
+    fn drop(&mut self) {
+        panic!("dropped a bomb! kaboom!")
+    }
+}
+
 #[test]
 fn uninit_write_slice_cloned_no_drop() {
-    #[derive(Clone)]
-    struct Bomb;
+    let mut dst = [MaybeUninit::uninit()];
+    let src = [Bomb];
+
+    MaybeUninit::clone_from_slice(&mut dst, &src);
+
+    forget(src);
+}
+
+#[test]
+fn uninit_fill() {
+    let mut dst = [MaybeUninit::new(255); 64];
+    let expect = [0; 64];
+
+    assert_eq!(MaybeUninit::fill(&mut dst, 0), &expect);
+}
+
+#[cfg(panic = "unwind")]
+struct CloneUntilPanic {
+    limit: usize,
+    rc: Rc<()>,
+}
 
-    impl Drop for Bomb {
-        fn drop(&mut self) {
-            panic!("dropped a bomb! kaboom")
+#[cfg(panic = "unwind")]
+impl Clone for CloneUntilPanic {
+    fn clone(&self) -> Self {
+        if Rc::strong_count(&self.rc) >= self.limit {
+            panic!("expected panic on clone");
         }
+        Self { limit: self.limit, rc: self.rc.clone() }
     }
+}
+
+#[test]
+#[cfg(panic = "unwind")]
+fn uninit_fill_clone_panic_drop() {
+    use std::panic;
+
+    let rc = Rc::new(());
+
+    let mut dst = [MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit()];
+
+    let src = CloneUntilPanic { limit: 3, rc: rc.clone() };
+    let err = panic::catch_unwind(panic::AssertUnwindSafe(|| {
+        MaybeUninit::fill(&mut dst, src);
+    }));
+
+    match err {
+        Ok(_) => unreachable!(),
+        Err(payload) => {
+            payload
+                .downcast::<&'static str>()
+                .and_then(|s| if *s == "expected panic on clone" { Ok(s) } else { Err(s) })
+                .unwrap_or_else(|p| panic::resume_unwind(p));
+            assert_eq!(Rc::strong_count(&rc), 1)
+        }
+    }
+}
+
+#[test]
+#[cfg(panic = "unwind")]
+fn uninit_fill_clone_no_drop_clones() {
+    let mut dst = [MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit()];
+
+    MaybeUninit::fill(&mut dst, Bomb);
+}
+
+#[test]
+fn uninit_fill_with() {
+    let mut dst = [MaybeUninit::new(255); 64];
+    let expect = [0; 64];
+
+    assert_eq!(MaybeUninit::fill_with(&mut dst, || 0), &expect);
+}
+
+#[test]
+#[cfg(panic = "unwind")]
+fn uninit_fill_with_mid_panic() {
+    use std::panic;
+
+    let rc = Rc::new(());
+
+    let mut dst = [MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit()];
+
+    let src = CloneUntilPanic { limit: 3, rc: rc.clone() };
+    let err = panic::catch_unwind(panic::AssertUnwindSafe(|| {
+        MaybeUninit::fill_with(&mut dst, || src.clone());
+    }));
+
+    drop(src);
+
+    match err {
+        Ok(_) => unreachable!(),
+        Err(payload) => {
+            payload
+                .downcast::<&'static str>()
+                .and_then(|s| if *s == "expected panic on clone" { Ok(s) } else { Err(s) })
+                .unwrap_or_else(|p| panic::resume_unwind(p));
 
+            assert_eq!(Rc::strong_count(&rc), 1)
+        }
+    }
+}
+
+#[test]
+#[cfg(panic = "unwind")]
+fn uninit_fill_with_no_drop() {
+    let mut dst = [MaybeUninit::uninit()];
+    let src = Bomb;
+
+    MaybeUninit::fill_with(&mut dst, || src.clone());
+
+    forget(src);
+}
+
+#[test]
+fn uninit_fill_from() {
+    let mut dst = [MaybeUninit::new(255); 64];
+    let src = [0; 64];
+
+    let (initted, remainder) = MaybeUninit::fill_from(&mut dst, src.into_iter());
+    assert_eq!(initted, &src);
+    assert_eq!(remainder.len(), 0);
+}
+
+#[test]
+fn uninit_fill_from_partial() {
+    let mut dst = [MaybeUninit::new(255); 64];
+    let src = [0; 48];
+
+    let (initted, remainder) = MaybeUninit::fill_from(&mut dst, src.into_iter());
+    assert_eq!(initted, &src);
+    assert_eq!(remainder.len(), 16);
+}
+
+#[test]
+fn uninit_over_fill() {
+    let mut dst = [MaybeUninit::new(255); 64];
+    let src = [0; 72];
+
+    let (initted, remainder) = MaybeUninit::fill_from(&mut dst, src.into_iter());
+    assert_eq!(initted, &src[0..64]);
+    assert_eq!(remainder.len(), 0);
+}
+
+#[test]
+fn uninit_empty_fill() {
+    let mut dst = [MaybeUninit::new(255); 64];
+    let src = [0; 0];
+
+    let (initted, remainder) = MaybeUninit::fill_from(&mut dst, src.into_iter());
+    assert_eq!(initted, &src[0..0]);
+    assert_eq!(remainder.len(), 64);
+}
+
+#[test]
+#[cfg(panic = "unwind")]
+fn uninit_fill_from_mid_panic() {
+    use std::panic;
+
+    struct IterUntilPanic {
+        limit: usize,
+        rc: Rc<()>,
+    }
+
+    impl Iterator for IterUntilPanic {
+        type Item = Rc<()>;
+        fn next(&mut self) -> Option<Self::Item> {
+            if Rc::strong_count(&self.rc) >= self.limit {
+                panic!("expected panic on next");
+            }
+            Some(self.rc.clone())
+        }
+    }
+
+    let rc = Rc::new(());
+
+    let mut dst = [
+        MaybeUninit::uninit(),
+        MaybeUninit::uninit(),
+        MaybeUninit::uninit(),
+        MaybeUninit::uninit(),
+    ];
+
+    let src = IterUntilPanic { limit: 3, rc: rc.clone() };
+
+    let err = panic::catch_unwind(panic::AssertUnwindSafe(|| {
+        MaybeUninit::fill_from(&mut dst, src);
+    }));
+
+    match err {
+        Ok(_) => unreachable!(),
+        Err(payload) => {
+            payload
+                .downcast::<&'static str>()
+                .and_then(|s| if *s == "expected panic on next" { Ok(s) } else { Err(s) })
+                .unwrap_or_else(|p| panic::resume_unwind(p));
+
+            assert_eq!(Rc::strong_count(&rc), 1)
+        }
+    }
+}
+
+#[test]
+#[cfg(panic = "unwind")]
+fn uninit_fill_from_no_drop() {
     let mut dst = [MaybeUninit::uninit()];
     let src = [Bomb];
 
-    MaybeUninit::clone_from_slice(&mut dst, &src);
+    MaybeUninit::fill_from(&mut dst, src.iter());
 
     forget(src);
 }

From 5c87ca2d1f23214d4890c9db88bd39684d6c8852 Mon Sep 17 00:00:00 2001
From: Urgau <urgau@numericable.fr>
Date: Thu, 29 Feb 2024 20:51:24 +0100
Subject: [PATCH 11/21] Add some weird test cases to the non_local_definitions
 lint tests

---
 tests/ui/lint/non_local_definitions.rs     | 20 +++++++++
 tests/ui/lint/non_local_definitions.stderr | 50 ++++++++++++++++------
 2 files changed, 56 insertions(+), 14 deletions(-)

diff --git a/tests/ui/lint/non_local_definitions.rs b/tests/ui/lint/non_local_definitions.rs
index bbcc81898713c..d14312d237a2a 100644
--- a/tests/ui/lint/non_local_definitions.rs
+++ b/tests/ui/lint/non_local_definitions.rs
@@ -245,6 +245,26 @@ fn bad() {
     //~^ WARN non-local `impl` definition
 }
 
+trait Uto9 {}
+trait Uto10 {}
+const _: u32 = {
+    let _a = || {
+        impl Uto9 for Test {}
+        //~^ WARN non-local `impl` definition
+
+        1
+    };
+
+    type A = [u32; {
+        impl Uto10 for Test {}
+        //~^ WARN non-local `impl` definition
+
+        1
+    }];
+
+    1
+};
+
 struct UwU<T>(T);
 
 fn fun() {
diff --git a/tests/ui/lint/non_local_definitions.stderr b/tests/ui/lint/non_local_definitions.stderr
index b9583ae983f34..ef74e262f9dbc 100644
--- a/tests/ui/lint/non_local_definitions.stderr
+++ b/tests/ui/lint/non_local_definitions.stderr
@@ -442,7 +442,29 @@ LL |     impl<T> Uto8 for T {}
    = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
 
 warning: non-local `impl` definition, they should be avoided as they go against expectation
-  --> $DIR/non_local_definitions.rs:253:5
+  --> $DIR/non_local_definitions.rs:252:9
+   |
+LL |         impl Uto9 for Test {}
+   |         ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: move this `impl` block outside the of the current closure `<unnameable>` and up 2 bodies
+   = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block
+   = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type
+   = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
+
+warning: non-local `impl` definition, they should be avoided as they go against expectation
+  --> $DIR/non_local_definitions.rs:259:9
+   |
+LL |         impl Uto10 for Test {}
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: move this `impl` block outside the of the current constant expression `<unnameable>` and up 2 bodies
+   = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block
+   = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type
+   = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
+
+warning: non-local `impl` definition, they should be avoided as they go against expectation
+  --> $DIR/non_local_definitions.rs:273:5
    |
 LL | /     impl Default for UwU<OwO> {
 LL | |
@@ -458,7 +480,7 @@ LL | |     }
    = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
 
 warning: non-local `impl` definition, they should be avoided as they go against expectation
-  --> $DIR/non_local_definitions.rs:264:5
+  --> $DIR/non_local_definitions.rs:284:5
    |
 LL | /     impl From<Cat> for () {
 LL | |
@@ -474,7 +496,7 @@ LL | |     }
    = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
 
 warning: non-local `impl` definition, they should be avoided as they go against expectation
-  --> $DIR/non_local_definitions.rs:273:5
+  --> $DIR/non_local_definitions.rs:293:5
    |
 LL | /     impl AsRef<Cat> for () {
 LL | |
@@ -488,7 +510,7 @@ LL | |     }
    = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
 
 warning: non-local `impl` definition, they should be avoided as they go against expectation
-  --> $DIR/non_local_definitions.rs:284:5
+  --> $DIR/non_local_definitions.rs:304:5
    |
 LL | /     impl PartialEq<B> for G {
 LL | |
@@ -504,7 +526,7 @@ LL | |     }
    = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
 
 warning: non-local `impl` definition, they should be avoided as they go against expectation
-  --> $DIR/non_local_definitions.rs:301:5
+  --> $DIR/non_local_definitions.rs:321:5
    |
 LL | /     impl PartialEq<Dog> for &Dog {
 LL | |
@@ -520,7 +542,7 @@ LL | |     }
    = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
 
 warning: non-local `impl` definition, they should be avoided as they go against expectation
-  --> $DIR/non_local_definitions.rs:308:5
+  --> $DIR/non_local_definitions.rs:328:5
    |
 LL | /     impl PartialEq<()> for Dog {
 LL | |
@@ -536,7 +558,7 @@ LL | |     }
    = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
 
 warning: non-local `impl` definition, they should be avoided as they go against expectation
-  --> $DIR/non_local_definitions.rs:315:5
+  --> $DIR/non_local_definitions.rs:335:5
    |
 LL | /     impl PartialEq<()> for &Dog {
 LL | |
@@ -552,7 +574,7 @@ LL | |     }
    = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
 
 warning: non-local `impl` definition, they should be avoided as they go against expectation
-  --> $DIR/non_local_definitions.rs:322:5
+  --> $DIR/non_local_definitions.rs:342:5
    |
 LL | /     impl PartialEq<Dog> for () {
 LL | |
@@ -568,7 +590,7 @@ LL | |     }
    = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
 
 warning: non-local `impl` definition, they should be avoided as they go against expectation
-  --> $DIR/non_local_definitions.rs:344:5
+  --> $DIR/non_local_definitions.rs:364:5
    |
 LL | /     impl From<Wrap<Wrap<Lion>>> for () {
 LL | |
@@ -584,7 +606,7 @@ LL | |     }
    = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
 
 warning: non-local `impl` definition, they should be avoided as they go against expectation
-  --> $DIR/non_local_definitions.rs:351:5
+  --> $DIR/non_local_definitions.rs:371:5
    |
 LL | /     impl From<()> for Wrap<Lion> {
 LL | |
@@ -600,7 +622,7 @@ LL | |     }
    = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
 
 warning: non-local `impl` definition, they should be avoided as they go against expectation
-  --> $DIR/non_local_definitions.rs:364:13
+  --> $DIR/non_local_definitions.rs:384:13
    |
 LL |             impl MacroTrait for OutsideStruct {}
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -615,7 +637,7 @@ LL | m!();
    = note: this warning originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 warning: non-local `impl` definition, they should be avoided as they go against expectation
-  --> $DIR/non_local_definitions.rs:374:1
+  --> $DIR/non_local_definitions.rs:394:1
    |
 LL | non_local_macro::non_local_impl!(CargoUpdate);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -628,7 +650,7 @@ LL | non_local_macro::non_local_impl!(CargoUpdate);
    = note: this warning originates in the macro `non_local_macro::non_local_impl` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 warning: non-local `macro_rules!` definition, they should be avoided as they go against expectation
-  --> $DIR/non_local_definitions.rs:377:1
+  --> $DIR/non_local_definitions.rs:397:1
    |
 LL | non_local_macro::non_local_macro_rules!(my_macro);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -640,5 +662,5 @@ LL | non_local_macro::non_local_macro_rules!(my_macro);
    = note: the macro `non_local_macro::non_local_macro_rules` may come from an old version of the `non_local_macro` crate, try updating your dependency with `cargo update -p non_local_macro`
    = note: this warning originates in the macro `non_local_macro::non_local_macro_rules` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-warning: 50 warnings emitted
+warning: 52 warnings emitted
 

From 20200f65ca63c4b3cd75aa1ebb9829188c78b388 Mon Sep 17 00:00:00 2001
From: Urgau <urgau@numericable.fr>
Date: Thu, 29 Feb 2024 20:59:09 +0100
Subject: [PATCH 12/21] Remove useless smallvec dependency in
 rustc_lint::non_local_def

---
 Cargo.lock                               |  1 -
 compiler/rustc_lint/Cargo.toml           |  1 -
 compiler/rustc_lint/src/non_local_def.rs | 30 ++++++++++++++----------
 3 files changed, 18 insertions(+), 14 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 635146492b042..81c606849e7e4 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4133,7 +4133,6 @@ dependencies = [
  "rustc_target",
  "rustc_trait_selection",
  "rustc_type_ir",
- "smallvec",
  "tracing",
  "unicode-security",
 ]
diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml
index 2271321b8bf22..fa1133e7780ff 100644
--- a/compiler/rustc_lint/Cargo.toml
+++ b/compiler/rustc_lint/Cargo.toml
@@ -23,7 +23,6 @@ rustc_span = { path = "../rustc_span" }
 rustc_target = { path = "../rustc_target" }
 rustc_trait_selection = { path = "../rustc_trait_selection" }
 rustc_type_ir = { path = "../rustc_type_ir" }
-smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
 tracing = "0.1"
 unicode-security = "0.1.0"
 # tidy-alphabetical-end
diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs
index a4fd5a7c45f97..597010b8925e0 100644
--- a/compiler/rustc_lint/src/non_local_def.rs
+++ b/compiler/rustc_lint/src/non_local_def.rs
@@ -2,8 +2,6 @@ use rustc_hir::{def::DefKind, Body, Item, ItemKind, Node, Path, QPath, TyKind};
 use rustc_span::def_id::{DefId, LOCAL_CRATE};
 use rustc_span::{sym, symbol::kw, ExpnKind, MacroKind};
 
-use smallvec::{smallvec, SmallVec};
-
 use crate::lints::{NonLocalDefinitionsCargoUpdateNote, NonLocalDefinitionsDiag};
 use crate::{LateContext, LateLintPass, LintContext};
 
@@ -114,25 +112,25 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
                 // is using local items and so we don't lint on it.
 
                 // We also ignore anon-const in item by including the anon-const
-                // parent as well; and since it's quite uncommon, we use smallvec
-                // to avoid unnecessary heap allocations.
-                let local_parents: SmallVec<[DefId; 1]> = if parent_def_kind == DefKind::Const
+                // parent as well.
+                let parent_parent = if parent_def_kind == DefKind::Const
                     && parent_opt_item_name == Some(kw::Underscore)
                 {
-                    smallvec![parent, cx.tcx.parent(parent)]
+                    Some(cx.tcx.parent(parent))
                 } else {
-                    smallvec![parent]
+                    None
                 };
 
                 let self_ty_has_local_parent = match impl_.self_ty.kind {
                     TyKind::Path(QPath::Resolved(_, ty_path)) => {
-                        path_has_local_parent(ty_path, cx, &*local_parents)
+                        path_has_local_parent(ty_path, cx, parent, parent_parent)
                     }
                     TyKind::TraitObject([principle_poly_trait_ref, ..], _, _) => {
                         path_has_local_parent(
                             principle_poly_trait_ref.trait_ref.path,
                             cx,
-                            &*local_parents,
+                            parent,
+                            parent_parent,
                         )
                     }
                     TyKind::TraitObject([], _, _)
@@ -154,7 +152,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
 
                 let of_trait_has_local_parent = impl_
                     .of_trait
-                    .map(|of_trait| path_has_local_parent(of_trait.path, cx, &*local_parents))
+                    .map(|of_trait| path_has_local_parent(of_trait.path, cx, parent, parent_parent))
                     .unwrap_or(false);
 
                 // If none of them have a local parent (LOGICAL NOR) this means that
@@ -218,6 +216,14 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
 ///    std::convert::PartialEq<Foo<Bar>>
 ///    ^^^^^^^^^^^^^^^^^^^^^^^
 /// ```
-fn path_has_local_parent(path: &Path<'_>, cx: &LateContext<'_>, local_parents: &[DefId]) -> bool {
-    path.res.opt_def_id().is_some_and(|did| local_parents.contains(&cx.tcx.parent(did)))
+fn path_has_local_parent(
+    path: &Path<'_>,
+    cx: &LateContext<'_>,
+    impl_parent: DefId,
+    impl_parent_parent: Option<DefId>,
+) -> bool {
+    path.res.opt_def_id().is_some_and(|did| {
+        let res_parent = cx.tcx.parent(did);
+        res_parent == impl_parent || Some(res_parent) == impl_parent_parent
+    })
 }

From 6c4eadd74746eaa21c6da1756c440b1fdabf0729 Mon Sep 17 00:00:00 2001
From: Urgau <urgau@numericable.fr>
Date: Thu, 29 Feb 2024 21:00:35 +0100
Subject: [PATCH 13/21] Add early-return when checking if a path is local

---
 compiler/rustc_lint/src/non_local_def.rs | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs
index 597010b8925e0..1ae1c72b6e8f4 100644
--- a/compiler/rustc_lint/src/non_local_def.rs
+++ b/compiler/rustc_lint/src/non_local_def.rs
@@ -223,7 +223,9 @@ fn path_has_local_parent(
     impl_parent_parent: Option<DefId>,
 ) -> bool {
     path.res.opt_def_id().is_some_and(|did| {
-        let res_parent = cx.tcx.parent(did);
-        res_parent == impl_parent || Some(res_parent) == impl_parent_parent
+        did.is_local() && {
+            let res_parent = cx.tcx.parent(did);
+            res_parent == impl_parent || Some(res_parent) == impl_parent_parent
+        }
     })
 }

From 98dbe9abac8e02f9a60393ae2eb2ca448c69e7d4 Mon Sep 17 00:00:00 2001
From: Urgau <urgau@numericable.fr>
Date: Thu, 29 Feb 2024 21:02:47 +0100
Subject: [PATCH 14/21] Use was_invoked_from_cargo method instead of
 hand-written one

---
 compiler/rustc_lint/src/non_local_def.rs | 2 +-
 tests/ui/lint/non_local_definitions.rs   | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs
index 1ae1c72b6e8f4..7c4d92d3ce038 100644
--- a/compiler/rustc_lint/src/non_local_def.rs
+++ b/compiler/rustc_lint/src/non_local_def.rs
@@ -83,7 +83,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
             if let Some(def_id) = oexpn.macro_def_id
                 && let ExpnKind::Macro(macro_kind, macro_name) = oexpn.kind
                 && def_id.krate != LOCAL_CRATE
-                && std::env::var_os("CARGO").is_some()
+                && rustc_session::utils::was_invoked_from_cargo()
             {
                 Some(NonLocalDefinitionsCargoUpdateNote {
                     macro_kind: macro_kind.descr(),
diff --git a/tests/ui/lint/non_local_definitions.rs b/tests/ui/lint/non_local_definitions.rs
index d14312d237a2a..eee582a6f11ba 100644
--- a/tests/ui/lint/non_local_definitions.rs
+++ b/tests/ui/lint/non_local_definitions.rs
@@ -1,7 +1,7 @@
 //@ check-pass
 //@ edition:2021
 //@ aux-build:non_local_macro.rs
-//@ rustc-env:CARGO=/usr/bin/cargo
+//@ rustc-env:CARGO_CRATE_NAME=non_local_def
 
 #![feature(inline_const)]
 #![warn(non_local_definitions)]

From 1195518a5e59e6d37c78db24c637780d2c662f3b Mon Sep 17 00:00:00 2001
From: Kornel <kornel@geekhood.net>
Date: Fri, 1 Mar 2024 13:37:08 +0000
Subject: [PATCH 15/21] Helper function for resolve_path

---
 compiler/rustc_expand/src/base.rs | 25 +++++++++++--------------
 compiler/rustc_span/src/lib.rs    | 11 +++++++++++
 2 files changed, 22 insertions(+), 14 deletions(-)

diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 69dfb48919cdb..a5f54b6b113e7 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -1233,21 +1233,18 @@ pub fn resolve_path(sess: &Session, path: impl Into<PathBuf>, span: Span) -> PRe
     // after macro expansion (that is, they are unhygienic).
     if !path.is_absolute() {
         let callsite = span.source_callsite();
-        let mut result = match sess.source_map().span_to_filename(callsite) {
-            FileName::Real(name) => name
-                .into_local_path()
-                .expect("attempting to resolve a file path in an external file"),
-            FileName::DocTest(path, _) => path,
-            other => {
-                return Err(sess.dcx().create_err(errors::ResolveRelativePath {
-                    span,
-                    path: sess.source_map().filename_for_diagnostics(&other).to_string(),
-                }));
-            }
+        let source_map = sess.source_map();
+        let Some(mut base_path) = source_map.span_to_filename(callsite).into_local_path() else {
+            return Err(sess.dcx().create_err(errors::ResolveRelativePath {
+                span,
+                path: source_map
+                    .filename_for_diagnostics(&source_map.span_to_filename(callsite))
+                    .to_string(),
+            }));
         };
-        result.pop();
-        result.push(path);
-        Ok(result)
+        base_path.pop();
+        base_path.push(path);
+        Ok(base_path)
     } else {
         Ok(path)
     }
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 616a7ccc7c64f..0c974ef4ca3eb 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -427,6 +427,17 @@ impl FileName {
         src.hash(&mut hasher);
         FileName::InlineAsm(hasher.finish())
     }
+
+    /// Returns the path suitable for reading from the file system on the local host,
+    /// if this information exists.
+    /// Avoid embedding this in build artifacts; see `remapped_path_if_available()` for that.
+    pub fn into_local_path(self) -> Option<PathBuf> {
+        match self {
+            FileName::Real(path) => path.into_local_path(),
+            FileName::DocTest(path, _) => Some(path),
+            _ => None,
+        }
+    }
 }
 
 /// Represents a span.

From 25ab1c70734f101596e8703d8c3a4e65da55ec01 Mon Sep 17 00:00:00 2001
From: Kornel <kornel@geekhood.net>
Date: Fri, 1 Mar 2024 02:49:02 +0000
Subject: [PATCH 16/21] Suggest correct path in include_bytes!

---
 .../rustc_builtin_macros/src/source_util.rs   | 150 ++++++++++++++----
 compiler/rustc_expand/src/base.rs             |  16 +-
 tests/ui/include-macros/parent_dir.rs         |  12 ++
 tests/ui/include-macros/parent_dir.stderr     |  50 ++++++
 tests/ui/macros/macros-nonfatal-errors.rs     |   2 +-
 tests/ui/macros/macros-nonfatal-errors.stderr |   4 +-
 6 files changed, 200 insertions(+), 34 deletions(-)
 create mode 100644 tests/ui/include-macros/parent_dir.rs
 create mode 100644 tests/ui/include-macros/parent_dir.stderr

diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs
index 2da9bda19e034..134a6baea6e8b 100644
--- a/compiler/rustc_builtin_macros/src/source_util.rs
+++ b/compiler/rustc_builtin_macros/src/source_util.rs
@@ -3,18 +3,20 @@ use rustc_ast::ptr::P;
 use rustc_ast::token;
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast_pretty::pprust;
+use rustc_data_structures::sync::Lrc;
 use rustc_expand::base::{
-    check_zero_tts, get_single_str_from_tts, parse_expr, resolve_path, DummyResult, ExtCtxt,
-    MacEager, MacResult,
+    check_zero_tts, get_single_str_from_tts, get_single_str_spanned_from_tts, parse_expr,
+    resolve_path, DummyResult, ExtCtxt, MacEager, MacResult,
 };
 use rustc_expand::module::DirOwnership;
 use rustc_parse::new_parser_from_file;
 use rustc_parse::parser::{ForceCollect, Parser};
 use rustc_session::lint::builtin::INCOMPLETE_INCLUDE;
+use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::Symbol;
 use rustc_span::{Pos, Span};
-
 use smallvec::SmallVec;
+use std::path::{Path, PathBuf};
 use std::rc::Rc;
 
 // These macros all relate to the file system; they either return
@@ -180,32 +182,22 @@ pub fn expand_include_str(
     tts: TokenStream,
 ) -> Box<dyn MacResult + 'static> {
     let sp = cx.with_def_site_ctxt(sp);
-    let file = match get_single_str_from_tts(cx, sp, tts, "include_str!") {
-        Ok(file) => file,
+    let (path, path_span) = match get_single_str_spanned_from_tts(cx, sp, tts, "include_str!") {
+        Ok(res) => res,
         Err(guar) => return DummyResult::any(sp, guar),
     };
-    let file = match resolve_path(&cx.sess, file.as_str(), sp) {
-        Ok(f) => f,
-        Err(err) => {
-            let guar = err.emit();
-            return DummyResult::any(sp, guar);
-        }
-    };
-    match cx.source_map().load_binary_file(&file) {
+    match load_binary_file(cx, path.as_str().as_ref(), sp, path_span) {
         Ok(bytes) => match std::str::from_utf8(&bytes) {
             Ok(src) => {
                 let interned_src = Symbol::intern(src);
                 MacEager::expr(cx.expr_str(sp, interned_src))
             }
             Err(_) => {
-                let guar = cx.dcx().span_err(sp, format!("{} wasn't a utf-8 file", file.display()));
+                let guar = cx.dcx().span_err(sp, format!("`{path}` wasn't a utf-8 file"));
                 DummyResult::any(sp, guar)
             }
         },
-        Err(e) => {
-            let guar = cx.dcx().span_err(sp, format!("couldn't read {}: {}", file.display(), e));
-            DummyResult::any(sp, guar)
-        }
+        Err(dummy) => dummy,
     }
 }
 
@@ -215,25 +207,123 @@ pub fn expand_include_bytes(
     tts: TokenStream,
 ) -> Box<dyn MacResult + 'static> {
     let sp = cx.with_def_site_ctxt(sp);
-    let file = match get_single_str_from_tts(cx, sp, tts, "include_bytes!") {
-        Ok(file) => file,
+    let (path, path_span) = match get_single_str_spanned_from_tts(cx, sp, tts, "include_bytes!") {
+        Ok(res) => res,
         Err(guar) => return DummyResult::any(sp, guar),
     };
-    let file = match resolve_path(&cx.sess, file.as_str(), sp) {
-        Ok(f) => f,
+    match load_binary_file(cx, path.as_str().as_ref(), sp, path_span) {
+        Ok(bytes) => {
+            let expr = cx.expr(sp, ast::ExprKind::IncludedBytes(bytes));
+            MacEager::expr(expr)
+        }
+        Err(dummy) => dummy,
+    }
+}
+
+fn load_binary_file(
+    cx: &mut ExtCtxt<'_>,
+    original_path: &Path,
+    macro_span: Span,
+    path_span: Span,
+) -> Result<Lrc<[u8]>, Box<dyn MacResult>> {
+    let resolved_path = match resolve_path(&cx.sess, original_path, macro_span) {
+        Ok(path) => path,
         Err(err) => {
             let guar = err.emit();
-            return DummyResult::any(sp, guar);
+            return Err(DummyResult::any(macro_span, guar));
         }
     };
-    match cx.source_map().load_binary_file(&file) {
-        Ok(bytes) => {
-            let expr = cx.expr(sp, ast::ExprKind::IncludedBytes(bytes));
-            MacEager::expr(expr)
+    match cx.source_map().load_binary_file(&resolved_path) {
+        Ok(data) => Ok(data),
+        Err(io_err) => {
+            let mut err = cx.dcx().struct_span_err(
+                macro_span,
+                format!("couldn't read `{}`: {io_err}", resolved_path.display()),
+            );
+
+            if original_path.is_relative() {
+                let source_map = cx.sess.source_map();
+                let new_path = source_map
+                    .span_to_filename(macro_span.source_callsite())
+                    .into_local_path()
+                    .and_then(|src| find_path_suggestion(source_map, src.parent()?, original_path))
+                    .and_then(|path| path.into_os_string().into_string().ok());
+
+                if let Some(new_path) = new_path {
+                    err.span_suggestion(
+                        path_span,
+                        "there is a file with the same name in a different directory",
+                        format!("\"{}\"", new_path.escape_debug()),
+                        rustc_lint_defs::Applicability::MachineApplicable,
+                    );
+                }
+            }
+            let guar = err.emit();
+            Err(DummyResult::any(macro_span, guar))
         }
-        Err(e) => {
-            let guar = cx.dcx().span_err(sp, format!("couldn't read {}: {}", file.display(), e));
-            DummyResult::any(sp, guar)
+    }
+}
+
+fn find_path_suggestion(
+    source_map: &SourceMap,
+    base_dir: &Path,
+    wanted_path: &Path,
+) -> Option<PathBuf> {
+    // Fix paths that assume they're relative to cargo manifest dir
+    let mut base_c = base_dir.components();
+    let mut wanted_c = wanted_path.components();
+    let mut without_base = None;
+    while let Some(wanted_next) = wanted_c.next() {
+        if wanted_c.as_path().file_name().is_none() {
+            break;
+        }
+        // base_dir may be absolute
+        while let Some(base_next) = base_c.next() {
+            if base_next == wanted_next {
+                without_base = Some(wanted_c.as_path());
+                break;
+            }
+        }
+    }
+    let root_absolute = without_base.into_iter().map(PathBuf::from);
+
+    let base_dir_components = base_dir.components().count();
+    // Avoid going all the way to the root dir
+    let max_parent_components = if base_dir.is_relative() {
+        base_dir_components + 1
+    } else {
+        base_dir_components.saturating_sub(1)
+    };
+
+    // Try with additional leading ../
+    let mut prefix = PathBuf::new();
+    let add = std::iter::from_fn(|| {
+        prefix.push("..");
+        Some(prefix.join(wanted_path))
+    })
+    .take(max_parent_components.min(3));
+
+    // Try without leading directories
+    let mut trimmed_path = wanted_path;
+    let remove = std::iter::from_fn(|| {
+        let mut components = trimmed_path.components();
+        let removed = components.next()?;
+        trimmed_path = components.as_path();
+        let _ = trimmed_path.file_name()?; // ensure there is a file name left
+        Some([
+            Some(trimmed_path.to_path_buf()),
+            (removed != std::path::Component::ParentDir)
+                .then(|| Path::new("..").join(trimmed_path)),
+        ])
+    })
+    .flatten()
+    .flatten()
+    .take(4);
+
+    for new_path in root_absolute.chain(add).chain(remove) {
+        if source_map.file_exists(&base_dir.join(&new_path)) {
+            return Some(new_path);
         }
     }
+    None
 }
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index a5f54b6b113e7..58589ebdca675 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -1341,6 +1341,15 @@ pub fn get_single_str_from_tts(
     tts: TokenStream,
     name: &str,
 ) -> Result<Symbol, ErrorGuaranteed> {
+    get_single_str_spanned_from_tts(cx, span, tts, name).map(|(s, _)| s)
+}
+
+pub fn get_single_str_spanned_from_tts(
+    cx: &mut ExtCtxt<'_>,
+    span: Span,
+    tts: TokenStream,
+    name: &str,
+) -> Result<(Symbol, Span), ErrorGuaranteed> {
     let mut p = cx.new_parser_from_tts(tts);
     if p.token == token::Eof {
         let guar = cx.dcx().emit_err(errors::OnlyOneArgument { span, name });
@@ -1352,7 +1361,12 @@ pub fn get_single_str_from_tts(
     if p.token != token::Eof {
         cx.dcx().emit_err(errors::OnlyOneArgument { span, name });
     }
-    expr_to_string(cx, ret, "argument must be a string literal").map(|(s, _)| s)
+    expr_to_spanned_string(cx, ret, "argument must be a string literal")
+        .map_err(|err| match err {
+            Ok((err, _)) => err.emit(),
+            Err(guar) => guar,
+        })
+        .map(|(symbol, _style, span)| (symbol, span))
 }
 
 /// Extracts comma-separated expressions from `tts`.
diff --git a/tests/ui/include-macros/parent_dir.rs b/tests/ui/include-macros/parent_dir.rs
new file mode 100644
index 0000000000000..321baf77025d2
--- /dev/null
+++ b/tests/ui/include-macros/parent_dir.rs
@@ -0,0 +1,12 @@
+//@ normalize-stderr-test: "`: .*\(os error" -> "`: $$FILE_NOT_FOUND_MSG (os error"
+
+fn main() {
+    let _ = include_str!("include-macros/file.txt");            //~ ERROR couldn't read
+                                                                //~^HELP different directory
+    let _ = include_str!("hello.rs");                           //~ ERROR couldn't read
+                                                                //~^HELP different directory
+    let _ = include_bytes!("../../data.bin");                   //~ ERROR couldn't read
+                                                                //~^HELP different directory
+    let _ = include_str!("tests/ui/include-macros/file.txt");   //~ ERROR couldn't read
+                                                                //~^HELP different directory
+}
diff --git a/tests/ui/include-macros/parent_dir.stderr b/tests/ui/include-macros/parent_dir.stderr
new file mode 100644
index 0000000000000..7610360815b7a
--- /dev/null
+++ b/tests/ui/include-macros/parent_dir.stderr
@@ -0,0 +1,50 @@
+error: couldn't read `$DIR/include-macros/file.txt`: $FILE_NOT_FOUND_MSG (os error 2)
+  --> $DIR/parent_dir.rs:4:13
+   |
+LL |     let _ = include_str!("include-macros/file.txt");
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this error originates in the macro `include_str` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: there is a file with the same name in a different directory
+   |
+LL |     let _ = include_str!("file.txt");
+   |                          ~~~~~~~~~~
+
+error: couldn't read `$DIR/hello.rs`: $FILE_NOT_FOUND_MSG (os error 2)
+  --> $DIR/parent_dir.rs:6:13
+   |
+LL |     let _ = include_str!("hello.rs");
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this error originates in the macro `include_str` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: there is a file with the same name in a different directory
+   |
+LL |     let _ = include_str!("../hello.rs");
+   |                          ~~~~~~~~~~~~~
+
+error: couldn't read `$DIR/../../data.bin`: $FILE_NOT_FOUND_MSG (os error 2)
+  --> $DIR/parent_dir.rs:8:13
+   |
+LL |     let _ = include_bytes!("../../data.bin");
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this error originates in the macro `include_bytes` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: there is a file with the same name in a different directory
+   |
+LL |     let _ = include_bytes!("data.bin");
+   |                            ~~~~~~~~~~
+
+error: couldn't read `$DIR/tests/ui/include-macros/file.txt`: $FILE_NOT_FOUND_MSG (os error 2)
+  --> $DIR/parent_dir.rs:10:13
+   |
+LL |     let _ = include_str!("tests/ui/include-macros/file.txt");
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this error originates in the macro `include_str` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: there is a file with the same name in a different directory
+   |
+LL |     let _ = include_str!("file.txt");
+   |                          ~~~~~~~~~~
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/macros/macros-nonfatal-errors.rs b/tests/ui/macros/macros-nonfatal-errors.rs
index 20e6d70500358..65cb899e0941b 100644
--- a/tests/ui/macros/macros-nonfatal-errors.rs
+++ b/tests/ui/macros/macros-nonfatal-errors.rs
@@ -1,4 +1,4 @@
-//@ normalize-stderr-test: "existed:.*\(" -> "existed: $$FILE_NOT_FOUND_MSG ("
+//@ normalize-stderr-test: "`: .*\(" -> "`: $$FILE_NOT_FOUND_MSG ("
 
 // test that errors in a (selection) of macros don't kill compilation
 // immediately, so that we get more errors listed at a time.
diff --git a/tests/ui/macros/macros-nonfatal-errors.stderr b/tests/ui/macros/macros-nonfatal-errors.stderr
index ca373ea6cd9e4..d02d2399bbadb 100644
--- a/tests/ui/macros/macros-nonfatal-errors.stderr
+++ b/tests/ui/macros/macros-nonfatal-errors.stderr
@@ -200,7 +200,7 @@ error: argument must be a string literal
 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)
+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:113:5
    |
 LL |     include_str!("i'd be quite surprised if a file with this name existed");
@@ -214,7 +214,7 @@ error: argument must be a string literal
 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)
+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:115:5
    |
 LL |     include_bytes!("i'd be quite surprised if a file with this name existed");

From 4663fbb2cb6922c28c4bd4e4947d8213f00382b3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?=
 <jieyouxu@outlook.com>
Date: Thu, 7 Mar 2024 23:03:42 +0000
Subject: [PATCH 17/21] Eagerly translate HelpUseLatestEdition in parser
 diagnostics

---
 .../rustc_parse/src/parser/diagnostics.rs     |  2 +-
 .../ui/parser/help-set-edition-ice-122130.rs  |  5 +++++
 .../parser/help-set-edition-ice-122130.stderr | 21 +++++++++++++++++++
 3 files changed, 27 insertions(+), 1 deletion(-)
 create mode 100644 tests/ui/parser/help-set-edition-ice-122130.rs
 create mode 100644 tests/ui/parser/help-set-edition-ice-122130.stderr

diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 2f7ac7d3a12e5..de088b9364b26 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -667,7 +667,7 @@ impl<'a> Parser<'a> {
         {
             err.note("you may be trying to write a c-string literal");
             err.note("c-string literals require Rust 2021 or later");
-            HelpUseLatestEdition::new().add_to_diagnostic(&mut err);
+            err.subdiagnostic(self.dcx(), HelpUseLatestEdition::new());
         }
 
         // `pub` may be used for an item or `pub(crate)`
diff --git a/tests/ui/parser/help-set-edition-ice-122130.rs b/tests/ui/parser/help-set-edition-ice-122130.rs
new file mode 100644
index 0000000000000..bc5af04ecbc0c
--- /dev/null
+++ b/tests/ui/parser/help-set-edition-ice-122130.rs
@@ -0,0 +1,5 @@
+enum will {
+    s#[c"owned_box"]
+    //~^ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found `#`
+    //~|ERROR expected item, found `"owned_box"`
+}
diff --git a/tests/ui/parser/help-set-edition-ice-122130.stderr b/tests/ui/parser/help-set-edition-ice-122130.stderr
new file mode 100644
index 0000000000000..fe4d212f2db65
--- /dev/null
+++ b/tests/ui/parser/help-set-edition-ice-122130.stderr
@@ -0,0 +1,21 @@
+error: expected one of `(`, `,`, `=`, `{`, or `}`, found `#`
+  --> $DIR/help-set-edition-ice-122130.rs:2:6
+   |
+LL |     s#[c"owned_box"]
+   |      ^ expected one of `(`, `,`, `=`, `{`, or `}`
+   |
+   = note: you may be trying to write a c-string literal
+   = note: c-string literals require Rust 2021 or later
+   = help: pass `--edition 2021` to `rustc`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+
+error: expected item, found `"owned_box"`
+  --> $DIR/help-set-edition-ice-122130.rs:2:9
+   |
+LL |     s#[c"owned_box"]
+   |         ^^^^^^^^^^^ expected item
+   |
+   = note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>
+
+error: aborting due to 2 previous errors
+

From bef1cd80d8f6264b5ed66b5696a758db5d47491b Mon Sep 17 00:00:00 2001
From: Josh Stone <jistone@redhat.com>
Date: Thu, 7 Mar 2024 18:30:04 -0800
Subject: [PATCH 18/21] ci: add a runner for vanilla LLVM 18

---
 .github/workflows/ci.yml                      |  4 ++
 .../host-x86_64/x86_64-gnu-llvm-17/Dockerfile |  4 ++
 .../host-x86_64/x86_64-gnu-llvm-18/Dockerfile | 55 +++++++++++++++++++
 src/ci/github-actions/ci.yml                  |  5 ++
 4 files changed, 68 insertions(+)
 create mode 100644 src/ci/docker/host-x86_64/x86_64-gnu-llvm-18/Dockerfile

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 1d1056de25c10..cd13ce35007b3 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -315,6 +315,10 @@ jobs:
           - name: x86_64-gnu-distcheck
             os: ubuntu-20.04-8core-32gb
             env: {}
+          - name: x86_64-gnu-llvm-18
+            env:
+              RUST_BACKTRACE: 1
+            os: ubuntu-20.04-8core-32gb
           - name: x86_64-gnu-llvm-17
             env:
               RUST_BACKTRACE: 1
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile
index fe30a95344104..1eedfe3f09b4d 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile
@@ -42,6 +42,10 @@ RUN sh /scripts/sccache.sh
 ENV NO_DOWNLOAD_CI_LLVM 1
 ENV EXTERNAL_LLVM 1
 
+# This is not the latest LLVM version, so some components required by tests may
+# be missing.
+ENV IS_NOT_LATEST_LLVM 1
+
 # Using llvm-link-shared due to libffi issues -- see #34486
 ENV RUST_CONFIGURE_ARGS \
       --build=x86_64-unknown-linux-gnu \
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-18/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-18/Dockerfile
new file mode 100644
index 0000000000000..e8383500dfc94
--- /dev/null
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-18/Dockerfile
@@ -0,0 +1,55 @@
+FROM ubuntu:24.04
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+  g++ \
+  gcc-multilib \
+  make \
+  ninja-build \
+  file \
+  curl \
+  ca-certificates \
+  python3 \
+  git \
+  cmake \
+  sudo \
+  gdb \
+  llvm-18-tools \
+  llvm-18-dev \
+  libedit-dev \
+  libssl-dev \
+  pkg-config \
+  zlib1g-dev \
+  xz-utils \
+  nodejs \
+  mingw-w64 \
+  libgccjit-13-dev \
+  && rm -rf /var/lib/apt/lists/*
+
+# Note: libgccjit needs to match the default gcc version for the linker to find it.
+
+# Install powershell (universal package) so we can test x.ps1 on Linux
+# FIXME: need a "universal" version that supports libicu74, but for now it still works to ignore that dep.
+RUN curl -sL "https://github.com/PowerShell/PowerShell/releases/download/v7.3.1/powershell_7.3.1-1.deb_amd64.deb" > powershell.deb && \
+    dpkg --ignore-depends=libicu72 -i powershell.deb && \
+    rm -f powershell.deb
+
+COPY scripts/sccache.sh /scripts/
+RUN sh /scripts/sccache.sh
+
+# We are disabling CI LLVM since this builder is intentionally using a host
+# LLVM, rather than the typical src/llvm-project LLVM.
+ENV NO_DOWNLOAD_CI_LLVM 1
+ENV EXTERNAL_LLVM 1
+
+# Using llvm-link-shared due to libffi issues -- see #34486
+ENV RUST_CONFIGURE_ARGS \
+      --build=x86_64-unknown-linux-gnu \
+      --llvm-root=/usr/lib/llvm-18 \
+      --enable-llvm-link-shared \
+      --set rust.thin-lto-import-instr-limit=10
+
+COPY host-x86_64/x86_64-gnu-llvm-16/script.sh /tmp/
+
+ENV SCRIPT /tmp/script.sh
diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml
index 2ba5d357a1d00..c392ccec3dc2b 100644
--- a/src/ci/github-actions/ci.yml
+++ b/src/ci/github-actions/ci.yml
@@ -510,6 +510,11 @@ jobs:
           - name: x86_64-gnu-distcheck
             <<: *job-linux-8c
 
+          - name: x86_64-gnu-llvm-18
+            env:
+              RUST_BACKTRACE: 1
+            <<: *job-linux-8c
+
           - name: x86_64-gnu-llvm-17
             env:
               RUST_BACKTRACE: 1

From 446708b3422e17264251e656377e354e287a990b Mon Sep 17 00:00:00 2001
From: bjorn3 <bjorn3@users.noreply.github.com>
Date: Sun, 19 Sep 2021 15:18:05 +0200
Subject: [PATCH 19/21] Remove a workaround for a bug

I don't think it is necessary anymore. As I understand it from issue
39504 the original problem was that rustbuild changed a hardlink in the
cargo build dir to point to copy in the sysroot while cargo may have
hardlinked it to the original first. I don't think this happens anymore
and as such this workaround is no longer necessary.
---
 compiler/rustc_metadata/src/locator.rs | 28 --------------------------
 1 file changed, 28 deletions(-)

diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index dcccace12b00a..f957b02b2828c 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -243,7 +243,6 @@ use std::{cmp, fmt};
 pub(crate) struct CrateLocator<'a> {
     // Immutable per-session configuration.
     only_needs_metadata: bool,
-    sysroot: &'a Path,
     metadata_loader: &'a dyn MetadataLoader,
     cfg_version: &'static str,
 
@@ -319,7 +318,6 @@ impl<'a> CrateLocator<'a> {
 
         CrateLocator {
             only_needs_metadata,
-            sysroot: &sess.sysroot,
             metadata_loader,
             cfg_version: sess.cfg_version,
             crate_name,
@@ -610,32 +608,6 @@ impl<'a> CrateLocator<'a> {
                 continue;
             }
 
-            // Ok so at this point we've determined that `(lib, kind)` above is
-            // a candidate crate to load, and that `slot` is either none (this
-            // is the first crate of its kind) or if some the previous path has
-            // the exact same hash (e.g., it's the exact same crate).
-            //
-            // In principle these two candidate crates are exactly the same so
-            // we can choose either of them to link. As a stupidly gross hack,
-            // however, we favor crate in the sysroot.
-            //
-            // You can find more info in rust-lang/rust#39518 and various linked
-            // issues, but the general gist is that during testing libstd the
-            // compilers has two candidates to choose from: one in the sysroot
-            // and one in the deps folder. These two crates are the exact same
-            // crate but if the compiler chooses the one in the deps folder
-            // it'll cause spurious errors on Windows.
-            //
-            // As a result, we favor the sysroot crate here. Note that the
-            // candidates are all canonicalized, so we canonicalize the sysroot
-            // as well.
-            if let Some((prev, _)) = &ret {
-                let sysroot = self.sysroot;
-                let sysroot = try_canonicalize(sysroot).unwrap_or_else(|_| sysroot.to_path_buf());
-                if prev.starts_with(&sysroot) {
-                    continue;
-                }
-            }
             *slot = Some((hash, metadata, lib.clone()));
             ret = Some((lib, kind));
         }

From 87ab9e8c6eac37374475fbc1409b4153dd52e1a0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= <john.kare.alsaker@gmail.com>
Date: Sat, 9 Mar 2024 00:24:14 +0100
Subject: [PATCH 20/21] Some tweaks to the parallel query cycle handler

---
 compiler/rustc_interface/src/util.rs         | 19 ++++++++++++++---
 compiler/rustc_query_system/src/query/job.rs | 22 +++++++-------------
 compiler/rustc_query_system/src/query/mod.rs |  2 +-
 3 files changed, 24 insertions(+), 19 deletions(-)

diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 0d50200133cb2..23bd2dac57e3b 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -101,10 +101,11 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
     threads: usize,
     f: F,
 ) -> R {
-    use rustc_data_structures::{jobserver, sync::FromDyn};
+    use rustc_data_structures::{defer, jobserver, sync::FromDyn};
     use rustc_middle::ty::tls;
     use rustc_query_impl::QueryCtxt;
-    use rustc_query_system::query::{deadlock, QueryContext};
+    use rustc_query_system::query::{break_query_cycles, QueryContext};
+    use std::process;
 
     let registry = sync::Registry::new(std::num::NonZero::new(threads).unwrap());
 
@@ -128,7 +129,19 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
             let query_map =
                 FromDyn::from(tls::with(|tcx| QueryCtxt::new(tcx).collect_active_jobs()));
             let registry = rayon_core::Registry::current();
-            thread::spawn(move || deadlock(query_map.into_inner(), &registry));
+            thread::Builder::new()
+                .name("rustc query cycle handler".to_string())
+                .spawn(move || {
+                    let on_panic = defer(|| {
+                        eprintln!("query cycle handler thread panicked, aborting process");
+                        // We need to abort here as we failed to resolve the deadlock,
+                        // otherwise the compiler could just hang,
+                        process::abort();
+                    });
+                    break_query_cycles(query_map.into_inner(), &registry);
+                    on_panic.disable();
+                })
+                .unwrap();
         });
     if let Some(size) = get_stack_size() {
         builder = builder.stack_size(size);
diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs
index 1a54a2293573b..248a741af9079 100644
--- a/compiler/rustc_query_system/src/query/job.rs
+++ b/compiler/rustc_query_system/src/query/job.rs
@@ -17,10 +17,9 @@ use std::num::NonZero;
 use {
     parking_lot::{Condvar, Mutex},
     rustc_data_structures::fx::FxHashSet,
-    rustc_data_structures::{defer, jobserver},
+    rustc_data_structures::jobserver,
     rustc_span::DUMMY_SP,
     std::iter,
-    std::process,
     std::sync::Arc,
 };
 
@@ -514,12 +513,7 @@ fn remove_cycle(
 /// There may be multiple cycles involved in a deadlock, so this searches
 /// all active queries for cycles before finally resuming all the waiters at once.
 #[cfg(parallel_compiler)]
-pub fn deadlock(query_map: QueryMap, registry: &rayon_core::Registry) {
-    let on_panic = defer(|| {
-        eprintln!("deadlock handler panicked, aborting process");
-        process::abort();
-    });
-
+pub fn break_query_cycles(query_map: QueryMap, registry: &rayon_core::Registry) {
     let mut wakelist = Vec::new();
     let mut jobs: Vec<QueryJobId> = query_map.keys().cloned().collect();
 
@@ -539,19 +533,17 @@ pub fn deadlock(query_map: QueryMap, registry: &rayon_core::Registry) {
     // X to Y due to Rayon waiting and a true dependency from Y to X. The algorithm here
     // only considers the true dependency and won't detect a cycle.
     if !found_cycle {
-        if query_map.len() == 0 {
-            panic!("deadlock detected without any query!")
-        } else {
-            panic!("deadlock detected! current query map:\n{:#?}", query_map);
-        }
+        panic!(
+            "deadlock detected as we're unable to find a query cycle to break\n\
+            current query map:\n{:#?}",
+            query_map
+        );
     }
 
     // FIXME: Ensure this won't cause a deadlock before we return
     for waiter in wakelist.into_iter() {
         waiter.notify(registry);
     }
-
-    on_panic.disable();
 }
 
 #[inline(never)]
diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs
index 0aefe553a3435..01b9d458f1e4f 100644
--- a/compiler/rustc_query_system/src/query/mod.rs
+++ b/compiler/rustc_query_system/src/query/mod.rs
@@ -3,7 +3,7 @@ pub use self::plumbing::*;
 
 mod job;
 #[cfg(parallel_compiler)]
-pub use self::job::deadlock;
+pub use self::job::break_query_cycles;
 pub use self::job::{
     print_query_stack, report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryMap,
 };

From 564837e23d9293edddb3d7a997667a6c6796fb2b Mon Sep 17 00:00:00 2001
From: Jason Newcomb <jsnewcomb@pm.me>
Date: Fri, 8 Mar 2024 23:20:29 -0500
Subject: [PATCH 21/21] Fix typo in `VisitorResult`

---
 compiler/rustc_ast_ir/src/visit.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compiler/rustc_ast_ir/src/visit.rs b/compiler/rustc_ast_ir/src/visit.rs
index dec9f7a47d09d..f6d6bf3a3e309 100644
--- a/compiler/rustc_ast_ir/src/visit.rs
+++ b/compiler/rustc_ast_ir/src/visit.rs
@@ -14,7 +14,7 @@ impl VisitorResult for () {
     type Residual = !;
 
     #[cfg(not(feature = "nightly"))]
-    type Residual = core::ops::Infallible;
+    type Residual = core::convert::Infallible;
 
     fn output() -> Self {}
     fn from_residual(_: Self::Residual) -> Self {}