about summary refs log tree commit diff
path: root/library
diff options
context:
space:
mode:
authorThe Miri Cronjob Bot <miri@cron.bot>2025-09-05 05:00:55 +0000
committerThe Miri Cronjob Bot <miri@cron.bot>2025-09-05 05:00:55 +0000
commit7c5fdb072e3d07674ba88153a4cac4f792c20fdc (patch)
tree78897a875065b81c78004b1cd0f83e78254fb11d /library
parent9a1eb85394e3612213e829ed871eb281079a2364 (diff)
parentb6f8824315367f73e43efe08f6e5a88cc3f117ce (diff)
downloadrust-7c5fdb072e3d07674ba88153a4cac4f792c20fdc.tar.gz
rust-7c5fdb072e3d07674ba88153a4cac4f792c20fdc.zip
Merge ref 'b3cfb8faf84c' from rust-lang/rust
Pull recent changes from https://github.com/rust-lang/rust via Josh.

Upstream ref: b3cfb8faf84c5f3b7909479a9f9b6a3290d5f4d7
Filtered ref: 8995aa7743caf019203bc853f27af6006705ae30
Upstream diff: https://github.com/rust-lang/rust/compare/9385c64c95d971329e62917adc4349c8ccdbafe0...b3cfb8faf84c5f3b7909479a9f9b6a3290d5f4d7

This merge was created using https://github.com/rust-lang/josh-sync.
Diffstat (limited to 'library')
-rw-r--r--library/alloc/src/raw_vec/mod.rs27
-rw-r--r--library/core/src/array/mod.rs1
-rw-r--r--library/core/src/intrinsics/fallback.rs73
-rw-r--r--library/core/src/intrinsics/mod.rs55
-rw-r--r--library/core/src/iter/adapters/chain.rs1
-rw-r--r--library/core/src/iter/adapters/peekable.rs102
-rw-r--r--library/core/src/lib.rs1
-rw-r--r--library/core/src/num/int_macros.rs2
-rw-r--r--library/core/src/num/mod.rs24
-rw-r--r--library/core/src/num/uint_macros.rs75
-rw-r--r--library/core/src/ops/range.rs1
-rw-r--r--library/core/src/ptr/mut_ptr.rs1
-rw-r--r--library/coretests/tests/iter/adapters/peekable.rs86
-rw-r--r--library/coretests/tests/lib.rs2
-rw-r--r--library/coretests/tests/num/uint_macros.rs36
-rw-r--r--library/portable-simd/crates/core_simd/src/simd/num/int.rs1
-rw-r--r--library/portable-simd/crates/core_simd/src/simd/num/uint.rs1
-rw-r--r--library/std/src/fs/tests.rs112
-rw-r--r--library/std/src/lib.rs1
-rw-r--r--library/std/src/os/unix/fs.rs89
-rw-r--r--library/std/src/os/windows/fs.rs43
-rw-r--r--library/std/src/path.rs10
-rw-r--r--library/std/src/sys/fd/unix.rs65
-rw-r--r--library/std/src/sys/fs/unix.rs4
-rw-r--r--library/std/src/sys/fs/windows.rs4
-rw-r--r--library/std/src/sys/pal/windows/handle.rs13
-rw-r--r--library/std/tests/path.rs8
27 files changed, 780 insertions, 58 deletions
diff --git a/library/alloc/src/raw_vec/mod.rs b/library/alloc/src/raw_vec/mod.rs
index fd05f9ca464..b0027e964e4 100644
--- a/library/alloc/src/raw_vec/mod.rs
+++ b/library/alloc/src/raw_vec/mod.rs
@@ -468,10 +468,6 @@ impl<A: Allocator> RawVecInner<A> {
             return Ok(Self::new_in(alloc, elem_layout.alignment()));
         }
 
-        if let Err(err) = alloc_guard(layout.size()) {
-            return Err(err);
-        }
-
         let result = match init {
             AllocInit::Uninitialized => alloc.allocate(layout),
             #[cfg(not(no_global_oom_handling))]
@@ -662,7 +658,7 @@ impl<A: Allocator> RawVecInner<A> {
         let new_layout = layout_array(cap, elem_layout)?;
 
         let ptr = finish_grow(new_layout, self.current_memory(elem_layout), &mut self.alloc)?;
-        // SAFETY: finish_grow would have resulted in a capacity overflow if we tried to allocate more than `isize::MAX` items
+        // SAFETY: layout_array would have resulted in a capacity overflow if we tried to allocate more than `isize::MAX` items
 
         unsafe { self.set_ptr_and_cap(ptr, cap) };
         Ok(())
@@ -684,7 +680,7 @@ impl<A: Allocator> RawVecInner<A> {
         let new_layout = layout_array(cap, elem_layout)?;
 
         let ptr = finish_grow(new_layout, self.current_memory(elem_layout), &mut self.alloc)?;
-        // SAFETY: finish_grow would have resulted in a capacity overflow if we tried to allocate more than `isize::MAX` items
+        // SAFETY: layout_array would have resulted in a capacity overflow if we tried to allocate more than `isize::MAX` items
         unsafe {
             self.set_ptr_and_cap(ptr, cap);
         }
@@ -771,8 +767,6 @@ fn finish_grow<A>(
 where
     A: Allocator,
 {
-    alloc_guard(new_layout.size())?;
-
     let memory = if let Some((ptr, old_layout)) = current_memory {
         debug_assert_eq!(old_layout.align(), new_layout.align());
         unsafe {
@@ -799,23 +793,6 @@ fn handle_error(e: TryReserveError) -> ! {
     }
 }
 
-// We need to guarantee the following:
-// * We don't ever allocate `> isize::MAX` byte-size objects.
-// * We don't overflow `usize::MAX` and actually allocate too little.
-//
-// On 64-bit we just need to check for overflow since trying to allocate
-// `> isize::MAX` bytes will surely fail. On 32-bit and 16-bit we need to add
-// an extra guard for this in case we're running on a platform which can use
-// all 4GB in user-space, e.g., PAE or x32.
-#[inline]
-fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> {
-    if usize::BITS < 64 && alloc_size > isize::MAX as usize {
-        Err(CapacityOverflow.into())
-    } else {
-        Ok(())
-    }
-}
-
 #[inline]
 fn layout_array(cap: usize, elem_layout: Layout) -> Result<Layout, TryReserveError> {
     elem_layout.repeat(cap).map(|(layout, _pad)| layout).map_err(|_| CapacityOverflow.into())
diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs
index 4cdc046f71e..d14419a23a1 100644
--- a/library/core/src/array/mod.rs
+++ b/library/core/src/array/mod.rs
@@ -48,6 +48,7 @@ pub use iter::IntoIter;
 /// assert_eq!(strings, ["Hello there!", "Hello there!"]);
 /// ```
 #[inline]
+#[must_use = "cloning is often expensive and is not expected to have side effects"]
 #[stable(feature = "array_repeat", since = "CURRENT_RUSTC_VERSION")]
 pub fn repeat<T: Clone, const N: usize>(val: T) -> [T; N] {
     from_trusted_iterator(repeat_n(val, N))
diff --git a/library/core/src/intrinsics/fallback.rs b/library/core/src/intrinsics/fallback.rs
index eec5c4d646d..96928325328 100644
--- a/library/core/src/intrinsics/fallback.rs
+++ b/library/core/src/intrinsics/fallback.rs
@@ -148,3 +148,76 @@ impl_disjoint_bitor! {
     u8, u16, u32, u64, u128, usize,
     i8, i16, i32, i64, i128, isize,
 }
+
+#[const_trait]
+#[rustc_const_unstable(feature = "core_intrinsics_fallbacks", issue = "none")]
+pub trait FunnelShift: Copy + 'static {
+    /// See [`super::unchecked_funnel_shl`]; we just need the trait indirection to handle
+    /// different types since calling intrinsics with generics doesn't work.
+    unsafe fn unchecked_funnel_shl(self, rhs: Self, shift: u32) -> Self;
+
+    /// See [`super::unchecked_funnel_shr`]; we just need the trait indirection to handle
+    /// different types since calling intrinsics with generics doesn't work.
+    unsafe fn unchecked_funnel_shr(self, rhs: Self, shift: u32) -> Self;
+}
+
+macro_rules! impl_funnel_shifts {
+    ($($type:ident),*) => {$(
+        #[rustc_const_unstable(feature = "core_intrinsics_fallbacks", issue = "none")]
+        impl const FunnelShift for $type {
+            #[cfg_attr(miri, track_caller)]
+            #[inline]
+            unsafe fn unchecked_funnel_shl(self, rhs: Self, shift: u32) -> Self {
+                // This implementation is also used by Miri so we have to check the precondition.
+                // SAFETY: this is guaranteed by the caller
+                unsafe { super::assume(shift < $type::BITS) };
+                if shift == 0 {
+                    self
+                } else {
+                    // SAFETY:
+                    //  - `shift < T::BITS`, which satisfies `unchecked_shl`
+                    //  - this also ensures that `T::BITS - shift < T::BITS` (shift = 0 is checked
+                    //    above), which satisfies `unchecked_shr`
+                    //  - because the types are unsigned, the combination are disjoint bits (this is
+                    //    not true if they're signed, since SHR will fill in the empty space with a
+                    //    sign bit, not zero)
+                    unsafe {
+                        super::disjoint_bitor(
+                            super::unchecked_shl(self, shift),
+                            super::unchecked_shr(rhs, $type::BITS - shift),
+                        )
+                    }
+                }
+            }
+
+            #[cfg_attr(miri, track_caller)]
+            #[inline]
+            unsafe fn unchecked_funnel_shr(self, rhs: Self, shift: u32) -> Self {
+                // This implementation is also used by Miri so we have to check the precondition.
+                // SAFETY: this is guaranteed by the caller
+                unsafe { super::assume(shift < $type::BITS) };
+                if shift == 0 {
+                    rhs
+                } else {
+                    // SAFETY:
+                    //  - `shift < T::BITS`, which satisfies `unchecked_shr`
+                    //  - this also ensures that `T::BITS - shift < T::BITS` (shift = 0 is checked
+                    //    above), which satisfies `unchecked_shl`
+                    //  - because the types are unsigned, the combination are disjoint bits (this is
+                    //    not true if they're signed, since SHR will fill in the empty space with a
+                    //    sign bit, not zero)
+                    unsafe {
+                        super::disjoint_bitor(
+                            super::unchecked_shl(self, $type::BITS - shift),
+                            super::unchecked_shr(rhs, shift),
+                        )
+                    }
+                }
+            }
+        }
+    )*};
+}
+
+impl_funnel_shifts! {
+    u8, u16, u32, u64, u128, usize
+}
diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs
index 904aa52c784..bffffbc29c1 100644
--- a/library/core/src/intrinsics/mod.rs
+++ b/library/core/src/intrinsics/mod.rs
@@ -2102,6 +2102,61 @@ pub const fn saturating_add<T: Copy>(a: T, b: T) -> T;
 #[rustc_intrinsic]
 pub const fn saturating_sub<T: Copy>(a: T, b: T) -> T;
 
+/// Funnel Shift left.
+///
+/// Concatenates `a` and `b` (with `a` in the most significant half),
+/// creating an integer twice as wide. Then shift this integer left
+/// by `shift`), and extract the most significant half. If `a` and `b`
+/// are the same, this is equivalent to a rotate left operation.
+///
+/// It is undefined behavior if `shift` is greater than or equal to the
+/// bit size of `T`.
+///
+/// Safe versions of this intrinsic are available on the integer primitives
+/// via the `funnel_shl` method. For example, [`u32::funnel_shl`].
+#[rustc_intrinsic]
+#[rustc_nounwind]
+#[rustc_const_unstable(feature = "funnel_shifts", issue = "145686")]
+#[unstable(feature = "funnel_shifts", issue = "145686")]
+#[track_caller]
+#[miri::intrinsic_fallback_is_spec]
+pub const unsafe fn unchecked_funnel_shl<T: [const] fallback::FunnelShift>(
+    a: T,
+    b: T,
+    shift: u32,
+) -> T {
+    // SAFETY: caller ensures that `shift` is in-range
+    unsafe { a.unchecked_funnel_shl(b, shift) }
+}
+
+/// Funnel Shift right.
+///
+/// Concatenates `a` and `b` (with `a` in the most significant half),
+/// creating an integer twice as wide. Then shift this integer right
+/// by `shift` (taken modulo the bit size of `T`), and extract the
+/// least significant half. If `a` and `b` are the same, this is equivalent
+/// to a rotate right operation.
+///
+/// It is undefined behavior if `shift` is greater than or equal to the
+/// bit size of `T`.
+///
+/// Safer versions of this intrinsic are available on the integer primitives
+/// via the `funnel_shr` method. For example, [`u32::funnel_shr`]
+#[rustc_intrinsic]
+#[rustc_nounwind]
+#[rustc_const_unstable(feature = "funnel_shifts", issue = "145686")]
+#[unstable(feature = "funnel_shifts", issue = "145686")]
+#[track_caller]
+#[miri::intrinsic_fallback_is_spec]
+pub const unsafe fn unchecked_funnel_shr<T: [const] fallback::FunnelShift>(
+    a: T,
+    b: T,
+    shift: u32,
+) -> T {
+    // SAFETY: caller ensures that `shift` is in-range
+    unsafe { a.unchecked_funnel_shr(b, shift) }
+}
+
 /// This is an implementation detail of [`crate::ptr::read`] and should
 /// not be used anywhere else.  See its comments for why this exists.
 ///
diff --git a/library/core/src/iter/adapters/chain.rs b/library/core/src/iter/adapters/chain.rs
index 943b88e2330..3ebdf7b4727 100644
--- a/library/core/src/iter/adapters/chain.rs
+++ b/library/core/src/iter/adapters/chain.rs
@@ -321,6 +321,7 @@ impl<A: Default, B: Default> Default for Chain<A, B> {
     ///
     /// // take requires `Default`
     /// let _: Chain<_, _> = mem::take(&mut foo.0);
+    /// ```
     fn default() -> Self {
         Chain::new(Default::default(), Default::default())
     }
diff --git a/library/core/src/iter/adapters/peekable.rs b/library/core/src/iter/adapters/peekable.rs
index a6522659620..a55de75d56c 100644
--- a/library/core/src/iter/adapters/peekable.rs
+++ b/library/core/src/iter/adapters/peekable.rs
@@ -317,6 +317,108 @@ impl<I: Iterator> Peekable<I> {
     {
         self.next_if(|next| next == expected)
     }
+
+    /// Consumes the next value of this iterator and applies a function `f` on it,
+    /// returning the result if the closure returns `Ok`.
+    ///
+    /// Otherwise if the closure returns `Err` the value is put back for the next iteration.
+    ///
+    /// The content of the `Err` variant is typically the original value of the closure,
+    /// but this is not required. If a different value is returned,
+    /// the next `peek()` or `next()` call will result in this new value.
+    /// This is similar to modifying the output of `peek_mut()`.
+    ///
+    /// If the closure panics, the next value will always be consumed and dropped
+    /// even if the panic is caught, because the closure never returned an `Err` value to put back.
+    ///
+    /// # Examples
+    ///
+    /// Parse the leading decimal number from an iterator of characters.
+    /// ```
+    /// #![feature(peekable_next_if_map)]
+    /// let mut iter = "125 GOTO 10".chars().peekable();
+    /// let mut line_num = 0_u32;
+    /// while let Some(digit) = iter.next_if_map(|c| c.to_digit(10).ok_or(c)) {
+    ///     line_num = line_num * 10 + digit;
+    /// }
+    /// assert_eq!(line_num, 125);
+    /// assert_eq!(iter.collect::<String>(), " GOTO 10");
+    /// ```
+    ///
+    /// Matching custom types.
+    /// ```
+    /// #![feature(peekable_next_if_map)]
+    ///
+    /// #[derive(Debug, PartialEq, Eq)]
+    /// enum Node {
+    ///     Comment(String),
+    ///     Red(String),
+    ///     Green(String),
+    ///     Blue(String),
+    /// }
+    ///
+    /// /// Combines all consecutive `Comment` nodes into a single one.
+    /// fn combine_comments(nodes: Vec<Node>) -> Vec<Node> {
+    ///     let mut result = Vec::with_capacity(nodes.len());
+    ///     let mut iter = nodes.into_iter().peekable();
+    ///     let mut comment_text = None::<String>;
+    ///     loop {
+    ///         // Typically the closure in .next_if_map() matches on the input,
+    ///         //  extracts the desired pattern into an `Ok`,
+    ///         //  and puts the rest into an `Err`.
+    ///         while let Some(text) = iter.next_if_map(|node| match node {
+    ///             Node::Comment(text) => Ok(text),
+    ///             other => Err(other),
+    ///         }) {
+    ///             comment_text.get_or_insert_default().push_str(&text);
+    ///         }
+    ///
+    ///         if let Some(text) = comment_text.take() {
+    ///             result.push(Node::Comment(text));
+    ///         }
+    ///         if let Some(node) = iter.next() {
+    ///             result.push(node);
+    ///         } else {
+    ///             break;
+    ///         }
+    ///     }
+    ///     result
+    /// }
+    ///# assert_eq!( // hiding the test to avoid cluttering the documentation.
+    ///#     combine_comments(vec![
+    ///#         Node::Comment("The".to_owned()),
+    ///#         Node::Comment("Quick".to_owned()),
+    ///#         Node::Comment("Brown".to_owned()),
+    ///#         Node::Red("Fox".to_owned()),
+    ///#         Node::Green("Jumped".to_owned()),
+    ///#         Node::Comment("Over".to_owned()),
+    ///#         Node::Blue("The".to_owned()),
+    ///#         Node::Comment("Lazy".to_owned()),
+    ///#         Node::Comment("Dog".to_owned()),
+    ///#     ]),
+    ///#     vec![
+    ///#         Node::Comment("TheQuickBrown".to_owned()),
+    ///#         Node::Red("Fox".to_owned()),
+    ///#         Node::Green("Jumped".to_owned()),
+    ///#         Node::Comment("Over".to_owned()),
+    ///#         Node::Blue("The".to_owned()),
+    ///#         Node::Comment("LazyDog".to_owned()),
+    ///#     ],
+    ///# )
+    /// ```
+    #[unstable(feature = "peekable_next_if_map", issue = "143702")]
+    pub fn next_if_map<R>(&mut self, f: impl FnOnce(I::Item) -> Result<R, I::Item>) -> Option<R> {
+        let unpeek = if let Some(item) = self.next() {
+            match f(item) {
+                Ok(result) => return Some(result),
+                Err(item) => Some(item),
+            }
+        } else {
+            None
+        };
+        self.peeked = Some(unpeek);
+        None
+    }
 }
 
 #[unstable(feature = "trusted_len", issue = "37572")]
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 82506379cac..c306011bdda 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -156,6 +156,7 @@
 #![feature(f128)]
 #![feature(freeze_impls)]
 #![feature(fundamental)]
+#![feature(funnel_shifts)]
 #![feature(if_let_guard)]
 #![feature(intra_doc_pointers)]
 #![feature(intrinsics)]
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index 25864db5fea..db70fb65d44 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -1285,7 +1285,7 @@ macro_rules! int_impl {
         ///
         /// ```should_panic
         #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_neg();")]
-        ///
+        /// ```
         #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")]
         #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index 69c6a7dbd89..54d5a63633c 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -454,6 +454,9 @@ impl u8 {
         rot = 2,
         rot_op = "0x82",
         rot_result = "0xa",
+        fsh_op = "0x36",
+        fshl_result = "0x8",
+        fshr_result = "0x8d",
         swap_op = "0x12",
         swapped = "0x12",
         reversed = "0x48",
@@ -1088,6 +1091,9 @@ impl u16 {
         rot = 4,
         rot_op = "0xa003",
         rot_result = "0x3a",
+        fsh_op = "0x2de",
+        fshl_result = "0x30",
+        fshr_result = "0x302d",
         swap_op = "0x1234",
         swapped = "0x3412",
         reversed = "0x2c48",
@@ -1135,6 +1141,9 @@ impl u32 {
         rot = 8,
         rot_op = "0x10000b3",
         rot_result = "0xb301",
+        fsh_op = "0x2fe78e45",
+        fshl_result = "0xb32f",
+        fshr_result = "0xb32fe78e",
         swap_op = "0x12345678",
         swapped = "0x78563412",
         reversed = "0x1e6a2c48",
@@ -1158,6 +1167,9 @@ impl u64 {
         rot = 12,
         rot_op = "0xaa00000000006e1",
         rot_result = "0x6e10aa",
+        fsh_op = "0x2fe78e45983acd98",
+        fshl_result = "0x6e12fe",
+        fshr_result = "0x6e12fe78e45983ac",
         swap_op = "0x1234567890123456",
         swapped = "0x5634129078563412",
         reversed = "0x6a2c48091e6a2c48",
@@ -1181,6 +1193,9 @@ impl u128 {
         rot = 16,
         rot_op = "0x13f40000000000000000000000004f76",
         rot_result = "0x4f7613f4",
+        fsh_op = "0x2fe78e45983acd98039000008736273",
+        fshl_result = "0x4f7602fe",
+        fshr_result = "0x4f7602fe78e45983acd9803900000873",
         swap_op = "0x12345678901234567890123456789012",
         swapped = "0x12907856341290785634129078563412",
         reversed = "0x48091e6a2c48091e6a2c48091e6a2c48",
@@ -1207,6 +1222,9 @@ impl usize {
         rot = 4,
         rot_op = "0xa003",
         rot_result = "0x3a",
+        fsh_op = "0x2fe78e45983acd98039000008736273",
+        fshl_result = "0x4f7602fe",
+        fshr_result = "0x4f7602fe78e45983acd9803900000873",
         swap_op = "0x1234",
         swapped = "0x3412",
         reversed = "0x2c48",
@@ -1231,6 +1249,9 @@ impl usize {
         rot = 8,
         rot_op = "0x10000b3",
         rot_result = "0xb301",
+        fsh_op = "0x2fe78e45",
+        fshl_result = "0xb32f",
+        fshr_result = "0xb32fe78e",
         swap_op = "0x12345678",
         swapped = "0x78563412",
         reversed = "0x1e6a2c48",
@@ -1255,6 +1276,9 @@ impl usize {
         rot = 12,
         rot_op = "0xaa00000000006e1",
         rot_result = "0x6e10aa",
+        fsh_op = "0x2fe78e45983acd98",
+        fshl_result = "0x6e12fe",
+        fshr_result = "0x6e12fe78e45983ac",
         swap_op = "0x1234567890123456",
         swapped = "0x5634129078563412",
         reversed = "0x6a2c48091e6a2c48",
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index c1e656fdea2..0ce9c259c40 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -14,6 +14,9 @@ macro_rules! uint_impl {
         rot = $rot:literal,
         rot_op = $rot_op:literal,
         rot_result = $rot_result:literal,
+        fsh_op = $fsh_op:literal,
+        fshl_result = $fshl_result:literal,
+        fshr_result = $fshr_result:literal,
         swap_op = $swap_op:literal,
         swapped = $swapped:literal,
         reversed = $reversed:literal,
@@ -375,6 +378,76 @@ macro_rules! uint_impl {
             return intrinsics::rotate_right(self, n);
         }
 
+        /// Performs a left funnel shift (concatenates `self` with `rhs`, with `self`
+        /// making up the most significant half, then shifts the combined value left
+        /// by `n`, and most significant half is extracted to produce the result).
+        ///
+        /// Please note this isn't the same operation as the `<<` shifting operator or
+        /// [`rotate_left`](Self::rotate_left), although `a.funnel_shl(a, n)` is *equivalent*
+        /// to `a.rotate_left(n)`.
+        ///
+        /// # Panics
+        ///
+        /// If `n` is greater than or equal to the number of bits in `self`
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// #![feature(funnel_shifts)]
+        #[doc = concat!("let a = ", $rot_op, stringify!($SelfT), ";")]
+        #[doc = concat!("let b = ", $fsh_op, stringify!($SelfT), ";")]
+        #[doc = concat!("let m = ", $fshl_result, ";")]
+        ///
+        #[doc = concat!("assert_eq!(a.funnel_shl(b, ", $rot, "), m);")]
+        /// ```
+        #[rustc_const_unstable(feature = "funnel_shifts", issue = "145686")]
+        #[unstable(feature = "funnel_shifts", issue = "145686")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline(always)]
+        pub const fn funnel_shl(self, rhs: Self, n: u32) -> Self {
+            assert!(n < Self::BITS, "attempt to funnel shift left with overflow");
+            // SAFETY: just checked that `shift` is in-range
+            unsafe { intrinsics::unchecked_funnel_shl(self, rhs, n) }
+        }
+
+        /// Performs a right funnel shift (concatenates `self` and `rhs`, with `self`
+        /// making up the most significant half, then shifts the combined value right
+        /// by `n`, and least significant half is extracted to produce the result).
+        ///
+        /// Please note this isn't the same operation as the `>>` shifting operator or
+        /// [`rotate_right`](Self::rotate_right), although `a.funnel_shr(a, n)` is *equivalent*
+        /// to `a.rotate_right(n)`.
+        ///
+        /// # Panics
+        ///
+        /// If `n` is greater than or equal to the number of bits in `self`
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// #![feature(funnel_shifts)]
+        #[doc = concat!("let a = ", $rot_op, stringify!($SelfT), ";")]
+        #[doc = concat!("let b = ", $fsh_op, stringify!($SelfT), ";")]
+        #[doc = concat!("let m = ", $fshr_result, ";")]
+        ///
+        #[doc = concat!("assert_eq!(a.funnel_shr(b, ", $rot, "), m);")]
+        /// ```
+        #[rustc_const_unstable(feature = "funnel_shifts", issue = "145686")]
+        #[unstable(feature = "funnel_shifts", issue = "145686")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline(always)]
+        pub const fn funnel_shr(self, rhs: Self, n: u32) -> Self {
+            assert!(n < Self::BITS, "attempt to funnel shift right with overflow");
+            // SAFETY: just checked that `shift` is in-range
+            unsafe { intrinsics::unchecked_funnel_shr(self, rhs, n) }
+        }
+
         /// Reverses the byte order of the integer.
         ///
         /// # Examples
@@ -1620,7 +1693,7 @@ macro_rules! uint_impl {
         ///
         /// ```should_panic
         #[doc = concat!("let _ = 1", stringify!($SelfT), ".strict_neg();")]
-        ///
+        /// ```
         #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")]
         #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs
index c0a27775694..58a9431bd84 100644
--- a/library/core/src/ops/range.rs
+++ b/library/core/src/ops/range.rs
@@ -836,6 +836,7 @@ pub trait RangeBounds<T: ?Sized> {
     /// assert!(!(0.0..1.0).contains(&f32::NAN));
     /// assert!(!(0.0..f32::NAN).contains(&0.5));
     /// assert!(!(f32::NAN..1.0).contains(&0.5));
+    /// ```
     #[inline]
     #[stable(feature = "range_contains", since = "1.35.0")]
     fn contains<U>(&self, item: &U) -> bool
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 3fe4b08d459..ce6eee4f911 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -106,6 +106,7 @@ impl<T: PointeeSized> *mut T {
     ///
     /// // This dereference is UB. The pointer only has provenance for `x` but points to `y`.
     /// println!("{:?}", unsafe { &*bad });
+    /// ```
     #[unstable(feature = "set_ptr_value", issue = "75091")]
     #[must_use = "returns a new pointer rather than modifying its argument"]
     #[inline]
diff --git a/library/coretests/tests/iter/adapters/peekable.rs b/library/coretests/tests/iter/adapters/peekable.rs
index 7f4341b8902..f0549e8d6c2 100644
--- a/library/coretests/tests/iter/adapters/peekable.rs
+++ b/library/coretests/tests/iter/adapters/peekable.rs
@@ -271,3 +271,89 @@ fn test_peekable_non_fused() {
     assert_eq!(iter.peek(), None);
     assert_eq!(iter.next_back(), None);
 }
+
+#[test]
+fn test_peekable_next_if_map_mutation() {
+    fn collatz((mut num, mut len): (u64, u32)) -> Result<u32, (u64, u32)> {
+        let jump = num.trailing_zeros();
+        num >>= jump;
+        len += jump;
+        if num == 1 { Ok(len) } else { Err((3 * num + 1, len + 1)) }
+    }
+
+    let mut iter = once((3, 0)).peekable();
+    assert_eq!(iter.peek(), Some(&(3, 0)));
+    assert_eq!(iter.next_if_map(collatz), None);
+    assert_eq!(iter.peek(), Some(&(10, 1)));
+    assert_eq!(iter.next_if_map(collatz), None);
+    assert_eq!(iter.peek(), Some(&(16, 3)));
+    assert_eq!(iter.next_if_map(collatz), Some(7));
+    assert_eq!(iter.peek(), None);
+    assert_eq!(iter.next_if_map(collatz), None);
+}
+
+#[test]
+#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
+fn test_peekable_next_if_map_panic() {
+    use core::cell::Cell;
+    use std::panic::{AssertUnwindSafe, catch_unwind};
+
+    struct BitsetOnDrop<'a> {
+        value: u32,
+        cell: &'a Cell<u32>,
+    }
+    impl<'a> Drop for BitsetOnDrop<'a> {
+        fn drop(&mut self) {
+            self.cell.update(|v| v | self.value);
+        }
+    }
+
+    let cell = &Cell::new(0);
+    let mut it = [
+        BitsetOnDrop { value: 1, cell },
+        BitsetOnDrop { value: 2, cell },
+        BitsetOnDrop { value: 4, cell },
+        BitsetOnDrop { value: 8, cell },
+    ]
+    .into_iter()
+    .peekable();
+
+    // sanity check, .peek() won't consume the value, .next() will transfer ownership.
+    let item = it.peek().unwrap();
+    assert_eq!(item.value, 1);
+    assert_eq!(cell.get(), 0);
+    let item = it.next().unwrap();
+    assert_eq!(item.value, 1);
+    assert_eq!(cell.get(), 0);
+    drop(item);
+    assert_eq!(cell.get(), 1);
+
+    // next_if_map returning Ok should transfer the value out.
+    let item = it.next_if_map(Ok).unwrap();
+    assert_eq!(item.value, 2);
+    assert_eq!(cell.get(), 1);
+    drop(item);
+    assert_eq!(cell.get(), 3);
+
+    // next_if_map returning Err should not drop anything.
+    assert_eq!(it.next_if_map::<()>(Err), None);
+    assert_eq!(cell.get(), 3);
+    assert_eq!(it.peek().unwrap().value, 4);
+    assert_eq!(cell.get(), 3);
+
+    // next_if_map panicking should consume and drop the item.
+    let result = catch_unwind({
+        let mut it = AssertUnwindSafe(&mut it);
+        move || it.next_if_map::<()>(|_| panic!())
+    });
+    assert!(result.is_err());
+    assert_eq!(cell.get(), 7);
+    assert_eq!(it.next().unwrap().value, 8);
+    assert_eq!(cell.get(), 15);
+    assert!(it.peek().is_none());
+
+    // next_if_map should *not* execute the closure if the iterator is exhausted.
+    assert!(it.next_if_map::<()>(|_| panic!()).is_none());
+    assert!(it.peek().is_none());
+    assert_eq!(cell.get(), 15);
+}
diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs
index ffb96b5a7cf..b5658a9970f 100644
--- a/library/coretests/tests/lib.rs
+++ b/library/coretests/tests/lib.rs
@@ -50,6 +50,7 @@
 #![feature(fmt_internals)]
 #![feature(formatting_options)]
 #![feature(freeze)]
+#![feature(funnel_shifts)]
 #![feature(future_join)]
 #![feature(generic_assert_internals)]
 #![feature(hasher_prefixfree_extras)]
@@ -82,6 +83,7 @@
 #![feature(numfmt)]
 #![feature(option_reduce)]
 #![feature(pattern)]
+#![feature(peekable_next_if_map)]
 #![feature(pointer_is_aligned_to)]
 #![feature(portable_simd)]
 #![feature(ptr_metadata)]
diff --git a/library/coretests/tests/num/uint_macros.rs b/library/coretests/tests/num/uint_macros.rs
index c7d10ea4d88..63be8a45b5c 100644
--- a/library/coretests/tests/num/uint_macros.rs
+++ b/library/coretests/tests/num/uint_macros.rs
@@ -104,6 +104,19 @@ macro_rules! uint_module {
                 assert_eq_const_safe!($T: C.rotate_left(128), C);
             }
 
+            fn test_funnel_shift() {
+                // Shifting by 0 should have no effect
+                assert_eq_const_safe!($T: <$T>::funnel_shl(A, B, 0), A);
+                assert_eq_const_safe!($T: <$T>::funnel_shr(A, B, 0), B);
+
+                assert_eq_const_safe!($T: <$T>::funnel_shl(_0, _1, 4), 0b1111);
+                assert_eq_const_safe!($T: <$T>::funnel_shr(_0, _1, 4), _1 >> 4);
+                assert_eq_const_safe!($T: <$T>::funnel_shl(_1, _0, 4), _1 << 4);
+
+                assert_eq_const_safe!($T: <$T>::funnel_shl(_1, _1, 4), <$T>::rotate_left(_1, 4));
+                assert_eq_const_safe!($T: <$T>::funnel_shr(_1, _1, 4), <$T>::rotate_right(_1, 4));
+            }
+
             fn test_swap_bytes() {
                 assert_eq_const_safe!($T: A.swap_bytes().swap_bytes(), A);
                 assert_eq_const_safe!($T: B.swap_bytes().swap_bytes(), B);
@@ -151,6 +164,29 @@ macro_rules! uint_module {
         }
 
         #[test]
+        #[should_panic = "attempt to funnel shift left with overflow"]
+        fn test_funnel_shl_overflow() {
+            let _ = <$T>::funnel_shl(A, B, $T::BITS);
+        }
+
+        #[test]
+        #[should_panic = "attempt to funnel shift right with overflow"]
+        fn test_funnel_shr_overflow() {
+            let _ = <$T>::funnel_shr(A, B, $T::BITS);
+        }
+
+        #[test]
+        fn test_funnel_shifts_runtime() {
+            for i in 0..$T::BITS - 1 {
+                assert_eq!(<$T>::funnel_shl(A, 0, i), A << i);
+                assert_eq!(<$T>::funnel_shl(A, A, i), A.rotate_left(i));
+
+                assert_eq!(<$T>::funnel_shr(0, A, i), A >> i);
+                assert_eq!(<$T>::funnel_shr(A, A, i), A.rotate_right(i));
+            }
+        }
+
+        #[test]
         fn test_isolate_highest_one() {
             const BITS: $T = <$T>::MAX;
             const MOST_SIG_ONE: $T = 1 << (<$T>::BITS - 1);
diff --git a/library/portable-simd/crates/core_simd/src/simd/num/int.rs b/library/portable-simd/crates/core_simd/src/simd/num/int.rs
index d25050c3e4b..e7253313f03 100644
--- a/library/portable-simd/crates/core_simd/src/simd/num/int.rs
+++ b/library/portable-simd/crates/core_simd/src/simd/num/int.rs
@@ -58,6 +58,7 @@ pub trait SimdInt: Copy + Sealed {
     /// let sat = x.saturating_sub(max);
     /// assert_eq!(unsat, Simd::from_array([1, MAX, MIN, 0]));
     /// assert_eq!(sat, Simd::from_array([MIN, MIN, MIN, 0]));
+    /// ```
     fn saturating_sub(self, second: Self) -> Self;
 
     /// Lanewise absolute value, implemented in Rust.
diff --git a/library/portable-simd/crates/core_simd/src/simd/num/uint.rs b/library/portable-simd/crates/core_simd/src/simd/num/uint.rs
index 45d978068b6..e3ba8658bd8 100644
--- a/library/portable-simd/crates/core_simd/src/simd/num/uint.rs
+++ b/library/portable-simd/crates/core_simd/src/simd/num/uint.rs
@@ -55,6 +55,7 @@ pub trait SimdUint: Copy + Sealed {
     /// let sat = x.saturating_sub(max);
     /// assert_eq!(unsat, Simd::from_array([3, 2, 1, 0]));
     /// assert_eq!(sat, Simd::splat(0));
+    /// ```
     fn saturating_sub(self, second: Self) -> Self;
 
     /// Lanewise absolute difference.
diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs
index 5e51d5e5211..f4431cedd18 100644
--- a/library/std/src/fs/tests.rs
+++ b/library/std/src/fs/tests.rs
@@ -492,6 +492,85 @@ fn file_test_io_read_write_at() {
 
 #[test]
 #[cfg(unix)]
+fn test_read_buf_at() {
+    use crate::os::unix::fs::FileExt;
+
+    let tmpdir = tmpdir();
+    let filename = tmpdir.join("file_rt_io_file_test_read_buf_at.txt");
+    {
+        let oo = OpenOptions::new().create_new(true).write(true).read(true).clone();
+        let mut file = check!(oo.open(&filename));
+        check!(file.write_all(b"0123456789"));
+    }
+    {
+        let mut file = check!(File::open(&filename));
+        let mut buf: [MaybeUninit<u8>; 5] = [MaybeUninit::uninit(); 5];
+        let mut buf = BorrowedBuf::from(buf.as_mut_slice());
+
+        // Fill entire buffer with potentially short reads
+        while buf.unfilled().capacity() > 0 {
+            let len = buf.len();
+            check!(file.read_buf_at(buf.unfilled(), 2 + len as u64));
+            assert!(!buf.filled().is_empty());
+            assert!(b"23456".starts_with(buf.filled()));
+            assert_eq!(check!(file.stream_position()), 0);
+        }
+        assert_eq!(buf.filled(), b"23456");
+
+        // Already full
+        check!(file.read_buf_at(buf.unfilled(), 3));
+        check!(file.read_buf_at(buf.unfilled(), 10));
+        assert_eq!(buf.filled(), b"23456");
+        assert_eq!(check!(file.stream_position()), 0);
+
+        // Read past eof is noop
+        check!(file.read_buf_at(buf.clear().unfilled(), 10));
+        assert_eq!(buf.filled(), b"");
+        check!(file.read_buf_at(buf.clear().unfilled(), 11));
+        assert_eq!(buf.filled(), b"");
+        assert_eq!(check!(file.stream_position()), 0);
+    }
+    check!(fs::remove_file(&filename));
+}
+
+#[test]
+#[cfg(unix)]
+fn test_read_buf_exact_at() {
+    use crate::os::unix::fs::FileExt;
+
+    let tmpdir = tmpdir();
+    let filename = tmpdir.join("file_rt_io_file_test_read_buf_exact_at.txt");
+    {
+        let oo = OpenOptions::new().create_new(true).write(true).read(true).clone();
+        let mut file = check!(oo.open(&filename));
+        check!(file.write_all(b"0123456789"));
+    }
+    {
+        let mut file = check!(File::open(&filename));
+        let mut buf: [MaybeUninit<u8>; 5] = [MaybeUninit::uninit(); 5];
+        let mut buf = BorrowedBuf::from(buf.as_mut_slice());
+
+        // Exact read
+        check!(file.read_buf_exact_at(buf.unfilled(), 2));
+        assert_eq!(buf.filled(), b"23456");
+        assert_eq!(check!(file.stream_position()), 0);
+
+        // Already full
+        check!(file.read_buf_exact_at(buf.unfilled(), 3));
+        check!(file.read_buf_exact_at(buf.unfilled(), 10));
+        assert_eq!(buf.filled(), b"23456");
+        assert_eq!(check!(file.stream_position()), 0);
+
+        // Non-empty exact read past eof fails
+        let err = file.read_buf_exact_at(buf.clear().unfilled(), 6).unwrap_err();
+        assert_eq!(err.kind(), ErrorKind::UnexpectedEof);
+        assert_eq!(check!(file.stream_position()), 0);
+    }
+    check!(fs::remove_file(&filename));
+}
+
+#[test]
+#[cfg(unix)]
 fn set_get_unix_permissions() {
     use crate::os::unix::fs::PermissionsExt;
 
@@ -567,6 +646,39 @@ fn file_test_io_seek_read_write() {
 }
 
 #[test]
+#[cfg(windows)]
+fn test_seek_read_buf() {
+    use crate::os::windows::fs::FileExt;
+
+    let tmpdir = tmpdir();
+    let filename = tmpdir.join("file_rt_io_file_test_seek_read_buf.txt");
+    {
+        let oo = OpenOptions::new().create_new(true).write(true).read(true).clone();
+        let mut file = check!(oo.open(&filename));
+        check!(file.write_all(b"0123456789"));
+    }
+    {
+        let mut file = check!(File::open(&filename));
+        let mut buf: [MaybeUninit<u8>; 1] = [MaybeUninit::uninit()];
+        let mut buf = BorrowedBuf::from(buf.as_mut_slice());
+
+        // Seek read
+        check!(file.seek_read_buf(buf.unfilled(), 8));
+        assert_eq!(buf.filled(), b"8");
+        assert_eq!(check!(file.stream_position()), 9);
+
+        // Empty seek read
+        check!(file.seek_read_buf(buf.unfilled(), 0));
+        assert_eq!(buf.filled(), b"8");
+
+        // Seek read past eof
+        check!(file.seek_read_buf(buf.clear().unfilled(), 10));
+        assert_eq!(buf.filled(), b"");
+    }
+    check!(fs::remove_file(&filename));
+}
+
+#[test]
 fn file_test_read_buf() {
     let tmpdir = tmpdir();
     let filename = &tmpdir.join("test");
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index a4b63462053..99b380c4793 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -294,6 +294,7 @@
 #![feature(f128)]
 #![feature(ffi_const)]
 #![feature(formatting_options)]
+#![feature(funnel_shifts)]
 #![feature(hash_map_internals)]
 #![feature(hash_map_macro)]
 #![feature(if_let_guard)]
diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs
index b776df3dde1..1d1a138b302 100644
--- a/library/std/src/os/unix/fs.rs
+++ b/library/std/src/os/unix/fs.rs
@@ -11,6 +11,7 @@ use super::platform::fs::MetadataExt as _;
 // Used for `File::read` on intra-doc links
 use crate::ffi::OsStr;
 use crate::fs::{self, OpenOptions, Permissions};
+use crate::io::BorrowedCursor;
 use crate::os::unix::io::{AsFd, AsRawFd};
 use crate::path::Path;
 use crate::sealed::Sealed;
@@ -130,6 +131,91 @@ pub trait FileExt {
         if !buf.is_empty() { Err(io::Error::READ_EXACT_EOF) } else { Ok(()) }
     }
 
+    /// Reads some bytes starting from a given offset into the buffer.
+    ///
+    /// This equivalent to the [`read_at`](FileExt::read_at) method, except that it is passed a
+    /// [`BorrowedCursor`] rather than `&mut [u8]` to allow use with uninitialized buffers. The new
+    /// data will be appended to any existing contents of `buf`.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(core_io_borrowed_buf)]
+    /// #![feature(read_buf_at)]
+    ///
+    /// use std::io;
+    /// use std::io::BorrowedBuf;
+    /// use std::fs::File;
+    /// use std::mem::MaybeUninit;
+    /// use std::os::unix::prelude::*;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let mut file = File::open("pi.txt")?;
+    ///
+    ///     // Read some bytes starting from offset 2
+    ///     let mut buf: [MaybeUninit<u8>; 10] = [MaybeUninit::uninit(); 10];
+    ///     let mut buf = BorrowedBuf::from(buf.as_mut_slice());
+    ///     file.read_buf_at(buf.unfilled(), 2)?;
+    ///
+    ///     assert!(buf.filled().starts_with(b"1"));
+    ///
+    ///     Ok(())
+    /// }
+    /// ```
+    #[unstable(feature = "read_buf_at", issue = "140771")]
+    fn read_buf_at(&self, buf: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
+        io::default_read_buf(|b| self.read_at(b, offset), buf)
+    }
+
+    /// Reads the exact number of bytes required to fill the buffer from a given offset.
+    ///
+    /// This is equivalent to the [`read_exact_at`](FileExt::read_exact_at) method, except that it
+    /// is passed a [`BorrowedCursor`] rather than `&mut [u8]` to allow use with uninitialized
+    /// buffers. The new data will be appended to any existing contents of `buf`.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(core_io_borrowed_buf)]
+    /// #![feature(read_buf_at)]
+    ///
+    /// use std::io;
+    /// use std::io::BorrowedBuf;
+    /// use std::fs::File;
+    /// use std::mem::MaybeUninit;
+    /// use std::os::unix::prelude::*;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let mut file = File::open("pi.txt")?;
+    ///
+    ///     // Read exactly 10 bytes starting from offset 2
+    ///     let mut buf: [MaybeUninit<u8>; 10] = [MaybeUninit::uninit(); 10];
+    ///     let mut buf = BorrowedBuf::from(buf.as_mut_slice());
+    ///     file.read_buf_exact_at(buf.unfilled(), 2)?;
+    ///
+    ///     assert_eq!(buf.filled(), b"1415926535");
+    ///
+    ///     Ok(())
+    /// }
+    /// ```
+    #[unstable(feature = "read_buf_at", issue = "140771")]
+    fn read_buf_exact_at(&self, mut buf: BorrowedCursor<'_>, mut offset: u64) -> io::Result<()> {
+        while buf.capacity() > 0 {
+            let prev_written = buf.written();
+            match self.read_buf_at(buf.reborrow(), offset) {
+                Ok(()) => {}
+                Err(e) if e.is_interrupted() => {}
+                Err(e) => return Err(e),
+            }
+            let n = buf.written() - prev_written;
+            offset += n as u64;
+            if n == 0 {
+                return Err(io::Error::READ_EXACT_EOF);
+            }
+        }
+        Ok(())
+    }
+
     /// Writes a number of bytes starting from a given offset.
     ///
     /// Returns the number of bytes written.
@@ -264,6 +350,9 @@ impl FileExt for fs::File {
     fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
         self.as_inner().read_at(buf, offset)
     }
+    fn read_buf_at(&self, buf: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
+        self.as_inner().read_buf_at(buf, offset)
+    }
     fn read_vectored_at(&self, bufs: &mut [io::IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
         self.as_inner().read_vectored_at(bufs, offset)
     }
diff --git a/library/std/src/os/windows/fs.rs b/library/std/src/os/windows/fs.rs
index ddb8dbd8fee..b445f368aeb 100644
--- a/library/std/src/os/windows/fs.rs
+++ b/library/std/src/os/windows/fs.rs
@@ -5,6 +5,7 @@
 #![stable(feature = "rust1", since = "1.0.0")]
 
 use crate::fs::{self, Metadata, OpenOptions};
+use crate::io::BorrowedCursor;
 use crate::path::Path;
 use crate::sealed::Sealed;
 use crate::sys_common::{AsInner, AsInnerMut, IntoInner};
@@ -49,6 +50,44 @@ pub trait FileExt {
     #[stable(feature = "file_offset", since = "1.15.0")]
     fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
 
+    /// Seeks to a given position and reads some bytes into the buffer.
+    ///
+    /// This is equivalent to the [`seek_read`](FileExt::seek_read) method, except that it is passed
+    /// a [`BorrowedCursor`] rather than `&mut [u8]` to allow use with uninitialized buffers. The
+    /// new data will be appended to any existing contents of `buf`.
+    ///
+    /// Reading beyond the end of the file will always succeed without reading any bytes.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(core_io_borrowed_buf)]
+    /// #![feature(read_buf_at)]
+    ///
+    /// use std::io;
+    /// use std::io::BorrowedBuf;
+    /// use std::fs::File;
+    /// use std::mem::MaybeUninit;
+    /// use std::os::windows::prelude::*;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let mut file = File::open("pi.txt")?;
+    ///
+    ///     // Read some bytes starting from offset 2
+    ///     let mut buf: [MaybeUninit<u8>; 10] = [MaybeUninit::uninit(); 10];
+    ///     let mut buf = BorrowedBuf::from(buf.as_mut_slice());
+    ///     file.seek_read_buf(buf.unfilled(), 2)?;
+    ///
+    ///     assert!(buf.filled().starts_with(b"1"));
+    ///
+    ///     Ok(())
+    /// }
+    /// ```
+    #[unstable(feature = "read_buf_at", issue = "140771")]
+    fn seek_read_buf(&self, buf: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
+        io::default_read_buf(|b| self.seek_read(b, offset), buf)
+    }
+
     /// Seeks to a given position and writes a number of bytes.
     ///
     /// Returns the number of bytes written.
@@ -89,6 +128,10 @@ impl FileExt for fs::File {
         self.as_inner().read_at(buf, offset)
     }
 
+    fn seek_read_buf(&self, buf: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
+        self.as_inner().read_buf_at(buf, offset)
+    }
+
     fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
         self.as_inner().write_at(buf, offset)
     }
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index 5ccea1c972c..19663e4a9df 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -1575,8 +1575,6 @@ impl PathBuf {
     /// # Examples
     ///
     /// ```
-    /// #![feature(path_add_extension)]
-    ///
     /// use std::path::{Path, PathBuf};
     ///
     /// let mut p = PathBuf::from("/feel/the");
@@ -1596,7 +1594,7 @@ impl PathBuf {
     /// p.add_extension("");
     /// assert_eq!(Path::new("/feel/the.formatted.dark"), p.as_path());
     /// ```
-    #[unstable(feature = "path_add_extension", issue = "127292")]
+    #[stable(feature = "path_add_extension", since = "CURRENT_RUSTC_VERSION")]
     pub fn add_extension<S: AsRef<OsStr>>(&mut self, extension: S) -> bool {
         self._add_extension(extension.as_ref())
     }
@@ -2109,7 +2107,7 @@ impl PartialEq for PathBuf {
 impl cmp::PartialEq<str> for PathBuf {
     #[inline]
     fn eq(&self, other: &str) -> bool {
-        &*self == other
+        Path::eq(self, other)
     }
 }
 
@@ -2880,8 +2878,6 @@ impl Path {
     /// # Examples
     ///
     /// ```
-    /// #![feature(path_add_extension)]
-    ///
     /// use std::path::{Path, PathBuf};
     ///
     /// let path = Path::new("foo.rs");
@@ -2892,7 +2888,7 @@ impl Path {
     /// assert_eq!(path.with_added_extension("xz"), PathBuf::from("foo.tar.gz.xz"));
     /// assert_eq!(path.with_added_extension("").with_added_extension("txt"), PathBuf::from("foo.tar.gz.txt"));
     /// ```
-    #[unstable(feature = "path_add_extension", issue = "127292")]
+    #[stable(feature = "path_add_extension", since = "CURRENT_RUSTC_VERSION")]
     pub fn with_added_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf {
         let mut new_path = self.to_path_buf();
         new_path.add_extension(extension);
diff --git a/library/std/src/sys/fd/unix.rs b/library/std/src/sys/fd/unix.rs
index a12f692e754..2b2dfe48e89 100644
--- a/library/std/src/sys/fd/unix.rs
+++ b/library/std/src/sys/fd/unix.rs
@@ -18,6 +18,21 @@ use libc::off_t as off64_t;
 ))]
 use libc::off64_t;
 
+cfg_select! {
+    any(
+        all(target_os = "linux", not(target_env = "musl")),
+        target_os = "android",
+        target_os = "hurd",
+    ) => {
+        // Prefer explicit pread64 for 64-bit offset independently of libc
+        // #[cfg(gnu_file_offset_bits64)].
+        use libc::pread64;
+    }
+    _ => {
+        use libc::pread as pread64;
+    }
+}
+
 use crate::cmp;
 use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read};
 use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
@@ -146,42 +161,47 @@ impl FileDesc {
         (&mut me).read_to_end(buf)
     }
 
-    #[cfg_attr(target_os = "vxworks", allow(unused_unsafe))]
     pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
-        #[cfg(not(any(
-            all(target_os = "linux", not(target_env = "musl")),
-            target_os = "android",
-            target_os = "hurd"
-        )))]
-        use libc::pread as pread64;
-        #[cfg(any(
-            all(target_os = "linux", not(target_env = "musl")),
-            target_os = "android",
-            target_os = "hurd"
-        ))]
-        use libc::pread64;
-
-        unsafe {
-            cvt(pread64(
+        cvt(unsafe {
+            pread64(
                 self.as_raw_fd(),
                 buf.as_mut_ptr() as *mut libc::c_void,
                 cmp::min(buf.len(), READ_LIMIT),
-                offset as off64_t,
-            ))
-            .map(|n| n as usize)
-        }
+                offset as off64_t, // EINVAL if offset + count overflows
+            )
+        })
+        .map(|n| n as usize)
     }
 
     pub fn read_buf(&self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
+        // SAFETY: `cursor.as_mut()` starts with `cursor.capacity()` writable bytes
         let ret = cvt(unsafe {
             libc::read(
                 self.as_raw_fd(),
-                cursor.as_mut().as_mut_ptr() as *mut libc::c_void,
+                cursor.as_mut().as_mut_ptr().cast::<libc::c_void>(),
+                cmp::min(cursor.capacity(), READ_LIMIT),
+            )
+        })?;
+
+        // SAFETY: `ret` bytes were written to the initialized portion of the buffer
+        unsafe {
+            cursor.advance_unchecked(ret as usize);
+        }
+        Ok(())
+    }
+
+    pub fn read_buf_at(&self, mut cursor: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
+        // SAFETY: `cursor.as_mut()` starts with `cursor.capacity()` writable bytes
+        let ret = cvt(unsafe {
+            pread64(
+                self.as_raw_fd(),
+                cursor.as_mut().as_mut_ptr().cast::<libc::c_void>(),
                 cmp::min(cursor.capacity(), READ_LIMIT),
+                offset as off64_t, // EINVAL if offset + count overflows
             )
         })?;
 
-        // Safety: `ret` bytes were written to the initialized portion of the buffer
+        // SAFETY: `ret` bytes were written to the initialized portion of the buffer
         unsafe {
             cursor.advance_unchecked(ret as usize);
         }
@@ -369,7 +389,6 @@ impl FileDesc {
         )))
     }
 
-    #[cfg_attr(target_os = "vxworks", allow(unused_unsafe))]
     pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
         #[cfg(not(any(
             all(target_os = "linux", not(target_env = "musl")),
diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs
index a89c3bbacfb..3b525406223 100644
--- a/library/std/src/sys/fs/unix.rs
+++ b/library/std/src/sys/fs/unix.rs
@@ -1463,6 +1463,10 @@ impl File {
         self.0.read_buf(cursor)
     }
 
+    pub fn read_buf_at(&self, cursor: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
+        self.0.read_buf_at(cursor, offset)
+    }
+
     pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
         self.0.read_vectored_at(bufs, offset)
     }
diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs
index bac278f7c8f..ccfe410627f 100644
--- a/library/std/src/sys/fs/windows.rs
+++ b/library/std/src/sys/fs/windows.rs
@@ -605,6 +605,10 @@ impl File {
         self.handle.read_buf(cursor)
     }
 
+    pub fn read_buf_at(&self, cursor: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
+        self.handle.read_buf_at(cursor, offset)
+    }
+
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         self.handle.write(buf)
     }
diff --git a/library/std/src/sys/pal/windows/handle.rs b/library/std/src/sys/pal/windows/handle.rs
index 82a880faf5f..76c8aa939d3 100644
--- a/library/std/src/sys/pal/windows/handle.rs
+++ b/library/std/src/sys/pal/windows/handle.rs
@@ -136,6 +136,19 @@ impl Handle {
         }
     }
 
+    pub fn read_buf_at(&self, mut cursor: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
+        // SAFETY: `cursor.as_mut()` starts with `cursor.capacity()` writable bytes
+        let read = unsafe {
+            self.synchronous_read(cursor.as_mut().as_mut_ptr(), cursor.capacity(), Some(offset))
+        }?;
+
+        // SAFETY: `read` bytes were written to the initialized portion of the buffer
+        unsafe {
+            cursor.advance_unchecked(read);
+        }
+        Ok(())
+    }
+
     pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
         let mut me = self;
 
diff --git a/library/std/tests/path.rs b/library/std/tests/path.rs
index e1576a0d423..fa76c50597b 100644
--- a/library/std/tests/path.rs
+++ b/library/std/tests/path.rs
@@ -1,4 +1,4 @@
-#![feature(clone_to_uninit, path_add_extension, maybe_uninit_slice, normalize_lexically)]
+#![feature(clone_to_uninit, maybe_uninit_slice, normalize_lexically)]
 
 use std::clone::CloneToUninit;
 use std::ffi::OsStr;
@@ -2526,3 +2526,9 @@ fn normalize_lexically() {
         check_err(r"\\?\UNC\server\share\a\..\..");
     }
 }
+
+#[test]
+/// See issue#146183
+fn compare_path_to_str() {
+    assert!(&PathBuf::from("x") == "x");
+}