From 3a4dd1b7b279435b4289b9b9a45db6647f1d3f9c Mon Sep 17 00:00:00 2001
From: joboet <jonasboettiger@icloud.com>
Date: Sat, 29 Mar 2025 13:08:18 +0100
Subject: [PATCH 1/9] std: make `cmath` functions safe

---
 library/std/src/f128.rs      |  32 +++++-----
 library/std/src/f16.rs       |  32 +++++-----
 library/std/src/f32.rs       |  34 +++++-----
 library/std/src/f64.rs       |  34 +++++-----
 library/std/src/sys/cmath.rs | 118 +++++++++++++++++------------------
 5 files changed, 125 insertions(+), 125 deletions(-)

diff --git a/library/std/src/f128.rs b/library/std/src/f128.rs
index ede2196905118..217528fdf1c10 100644
--- a/library/std/src/f128.rs
+++ b/library/std/src/f128.rs
@@ -666,7 +666,7 @@ impl f128 {
     #[unstable(feature = "f128", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn cbrt(self) -> f128 {
-        unsafe { cmath::cbrtf128(self) }
+        cmath::cbrtf128(self)
     }
 
     /// Compute the distance between the origin and a point (`x`, `y`) on the
@@ -703,7 +703,7 @@ impl f128 {
     #[unstable(feature = "f128", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn hypot(self, other: f128) -> f128 {
-        unsafe { cmath::hypotf128(self, other) }
+        cmath::hypotf128(self, other)
     }
 
     /// Computes the sine of a number (in radians).
@@ -789,7 +789,7 @@ impl f128 {
     #[unstable(feature = "f128", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn tan(self) -> f128 {
-        unsafe { cmath::tanf128(self) }
+        cmath::tanf128(self)
     }
 
     /// Computes the arcsine of a number. Return value is in radians in
@@ -824,7 +824,7 @@ impl f128 {
     #[unstable(feature = "f128", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn asin(self) -> f128 {
-        unsafe { cmath::asinf128(self) }
+        cmath::asinf128(self)
     }
 
     /// Computes the arccosine of a number. Return value is in radians in
@@ -859,7 +859,7 @@ impl f128 {
     #[unstable(feature = "f128", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn acos(self) -> f128 {
-        unsafe { cmath::acosf128(self) }
+        cmath::acosf128(self)
     }
 
     /// Computes the arctangent of a number. Return value is in radians in the
@@ -893,7 +893,7 @@ impl f128 {
     #[unstable(feature = "f128", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn atan(self) -> f128 {
-        unsafe { cmath::atanf128(self) }
+        cmath::atanf128(self)
     }
 
     /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians.
@@ -939,7 +939,7 @@ impl f128 {
     #[unstable(feature = "f128", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn atan2(self, other: f128) -> f128 {
-        unsafe { cmath::atan2f128(self, other) }
+        cmath::atan2f128(self, other)
     }
 
     /// Simultaneously computes the sine and cosine of the number, `x`. Returns
@@ -1008,7 +1008,7 @@ impl f128 {
     #[unstable(feature = "f128", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn exp_m1(self) -> f128 {
-        unsafe { cmath::expm1f128(self) }
+        cmath::expm1f128(self)
     }
 
     /// Returns `ln(1+n)` (natural logarithm) more accurately than if
@@ -1055,7 +1055,7 @@ impl f128 {
     #[rustc_allow_incoherent_impl]
     #[unstable(feature = "f128", issue = "116909")]
     pub fn ln_1p(self) -> f128 {
-        unsafe { cmath::log1pf128(self) }
+        cmath::log1pf128(self)
     }
 
     /// Hyperbolic sine function.
@@ -1090,7 +1090,7 @@ impl f128 {
     #[unstable(feature = "f128", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn sinh(self) -> f128 {
-        unsafe { cmath::sinhf128(self) }
+        cmath::sinhf128(self)
     }
 
     /// Hyperbolic cosine function.
@@ -1125,7 +1125,7 @@ impl f128 {
     #[unstable(feature = "f128", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn cosh(self) -> f128 {
-        unsafe { cmath::coshf128(self) }
+        cmath::coshf128(self)
     }
 
     /// Hyperbolic tangent function.
@@ -1160,7 +1160,7 @@ impl f128 {
     #[unstable(feature = "f128", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn tanh(self) -> f128 {
-        unsafe { cmath::tanhf128(self) }
+        cmath::tanhf128(self)
     }
 
     /// Inverse hyperbolic sine function.
@@ -1289,7 +1289,7 @@ impl f128 {
     // #[unstable(feature = "float_gamma", issue = "99842")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn gamma(self) -> f128 {
-        unsafe { cmath::tgammaf128(self) }
+        cmath::tgammaf128(self)
     }
 
     /// Natural logarithm of the absolute value of the gamma function
@@ -1325,7 +1325,7 @@ impl f128 {
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn ln_gamma(self) -> (f128, i32) {
         let mut signgamp: i32 = 0;
-        let x = unsafe { cmath::lgammaf128_r(self, &mut signgamp) };
+        let x = cmath::lgammaf128_r(self, &mut signgamp);
         (x, signgamp)
     }
 
@@ -1365,7 +1365,7 @@ impl f128 {
     // #[unstable(feature = "float_erf", issue = "136321")]
     #[inline]
     pub fn erf(self) -> f128 {
-        unsafe { cmath::erff128(self) }
+        cmath::erff128(self)
     }
 
     /// Complementary error function.
@@ -1398,6 +1398,6 @@ impl f128 {
     // #[unstable(feature = "float_erf", issue = "136321")]
     #[inline]
     pub fn erfc(self) -> f128 {
-        unsafe { cmath::erfcf128(self) }
+        cmath::erfcf128(self)
     }
 }
diff --git a/library/std/src/f16.rs b/library/std/src/f16.rs
index 286993d736b9c..4dadcbb518556 100644
--- a/library/std/src/f16.rs
+++ b/library/std/src/f16.rs
@@ -665,7 +665,7 @@ impl f16 {
     #[unstable(feature = "f16", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn cbrt(self) -> f16 {
-        (unsafe { cmath::cbrtf(self as f32) }) as f16
+        cmath::cbrtf(self as f32) as f16
     }
 
     /// Compute the distance between the origin and a point (`x`, `y`) on the
@@ -701,7 +701,7 @@ impl f16 {
     #[unstable(feature = "f16", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn hypot(self, other: f16) -> f16 {
-        (unsafe { cmath::hypotf(self as f32, other as f32) }) as f16
+        cmath::hypotf(self as f32, other as f32) as f16
     }
 
     /// Computes the sine of a number (in radians).
@@ -787,7 +787,7 @@ impl f16 {
     #[unstable(feature = "f16", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn tan(self) -> f16 {
-        (unsafe { cmath::tanf(self as f32) }) as f16
+        cmath::tanf(self as f32) as f16
     }
 
     /// Computes the arcsine of a number. Return value is in radians in
@@ -822,7 +822,7 @@ impl f16 {
     #[unstable(feature = "f16", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn asin(self) -> f16 {
-        (unsafe { cmath::asinf(self as f32) }) as f16
+        cmath::asinf(self as f32) as f16
     }
 
     /// Computes the arccosine of a number. Return value is in radians in
@@ -857,7 +857,7 @@ impl f16 {
     #[unstable(feature = "f16", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn acos(self) -> f16 {
-        (unsafe { cmath::acosf(self as f32) }) as f16
+        cmath::acosf(self as f32) as f16
     }
 
     /// Computes the arctangent of a number. Return value is in radians in the
@@ -891,7 +891,7 @@ impl f16 {
     #[unstable(feature = "f16", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn atan(self) -> f16 {
-        (unsafe { cmath::atanf(self as f32) }) as f16
+        cmath::atanf(self as f32) as f16
     }
 
     /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians.
@@ -937,7 +937,7 @@ impl f16 {
     #[unstable(feature = "f16", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn atan2(self, other: f16) -> f16 {
-        (unsafe { cmath::atan2f(self as f32, other as f32) }) as f16
+        cmath::atan2f(self as f32, other as f32) as f16
     }
 
     /// Simultaneously computes the sine and cosine of the number, `x`. Returns
@@ -1006,7 +1006,7 @@ impl f16 {
     #[unstable(feature = "f16", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn exp_m1(self) -> f16 {
-        (unsafe { cmath::expm1f(self as f32) }) as f16
+        cmath::expm1f(self as f32) as f16
     }
 
     /// Returns `ln(1+n)` (natural logarithm) more accurately than if
@@ -1053,7 +1053,7 @@ impl f16 {
     #[unstable(feature = "f16", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn ln_1p(self) -> f16 {
-        (unsafe { cmath::log1pf(self as f32) }) as f16
+        cmath::log1pf(self as f32) as f16
     }
 
     /// Hyperbolic sine function.
@@ -1088,7 +1088,7 @@ impl f16 {
     #[unstable(feature = "f16", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn sinh(self) -> f16 {
-        (unsafe { cmath::sinhf(self as f32) }) as f16
+        cmath::sinhf(self as f32) as f16
     }
 
     /// Hyperbolic cosine function.
@@ -1123,7 +1123,7 @@ impl f16 {
     #[unstable(feature = "f16", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn cosh(self) -> f16 {
-        (unsafe { cmath::coshf(self as f32) }) as f16
+        cmath::coshf(self as f32) as f16
     }
 
     /// Hyperbolic tangent function.
@@ -1158,7 +1158,7 @@ impl f16 {
     #[unstable(feature = "f16", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn tanh(self) -> f16 {
-        (unsafe { cmath::tanhf(self as f32) }) as f16
+        cmath::tanhf(self as f32) as f16
     }
 
     /// Inverse hyperbolic sine function.
@@ -1287,7 +1287,7 @@ impl f16 {
     // #[unstable(feature = "float_gamma", issue = "99842")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn gamma(self) -> f16 {
-        (unsafe { cmath::tgammaf(self as f32) }) as f16
+        cmath::tgammaf(self as f32) as f16
     }
 
     /// Natural logarithm of the absolute value of the gamma function
@@ -1323,7 +1323,7 @@ impl f16 {
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn ln_gamma(self) -> (f16, i32) {
         let mut signgamp: i32 = 0;
-        let x = (unsafe { cmath::lgammaf_r(self as f32, &mut signgamp) }) as f16;
+        let x = cmath::lgammaf_r(self as f32, &mut signgamp) as f16;
         (x, signgamp)
     }
 
@@ -1363,7 +1363,7 @@ impl f16 {
     // #[unstable(feature = "float_erf", issue = "136321")]
     #[inline]
     pub fn erf(self) -> f16 {
-        (unsafe { cmath::erff(self as f32) }) as f16
+        cmath::erff(self as f32) as f16
     }
 
     /// Complementary error function.
@@ -1396,6 +1396,6 @@ impl f16 {
     // #[unstable(feature = "float_erf", issue = "136321")]
     #[inline]
     pub fn erfc(self) -> f16 {
-        (unsafe { cmath::erfcf(self as f32) }) as f16
+        cmath::erfcf(self as f32) as f16
     }
 }
diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs
index 980e7f7793af2..baf7002f3803c 100644
--- a/library/std/src/f32.rs
+++ b/library/std/src/f32.rs
@@ -599,7 +599,7 @@ impl f32 {
                 filing an issue describing your use-case too)."
     )]
     pub fn abs_sub(self, other: f32) -> f32 {
-        unsafe { cmath::fdimf(self, other) }
+        cmath::fdimf(self, other)
     }
 
     /// Returns the cube root of a number.
@@ -626,7 +626,7 @@ impl f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn cbrt(self) -> f32 {
-        unsafe { cmath::cbrtf(self) }
+        cmath::cbrtf(self)
     }
 
     /// Compute the distance between the origin and a point (`x`, `y`) on the
@@ -657,7 +657,7 @@ impl f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn hypot(self, other: f32) -> f32 {
-        unsafe { cmath::hypotf(self, other) }
+        cmath::hypotf(self, other)
     }
 
     /// Computes the sine of a number (in radians).
@@ -730,7 +730,7 @@ impl f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn tan(self) -> f32 {
-        unsafe { cmath::tanf(self) }
+        cmath::tanf(self)
     }
 
     /// Computes the arcsine of a number. Return value is in radians in
@@ -760,7 +760,7 @@ impl f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn asin(self) -> f32 {
-        unsafe { cmath::asinf(self) }
+        cmath::asinf(self)
     }
 
     /// Computes the arccosine of a number. Return value is in radians in
@@ -790,7 +790,7 @@ impl f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn acos(self) -> f32 {
-        unsafe { cmath::acosf(self) }
+        cmath::acosf(self)
     }
 
     /// Computes the arctangent of a number. Return value is in radians in the
@@ -819,7 +819,7 @@ impl f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn atan(self) -> f32 {
-        unsafe { cmath::atanf(self) }
+        cmath::atanf(self)
     }
 
     /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians.
@@ -860,7 +860,7 @@ impl f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn atan2(self, other: f32) -> f32 {
-        unsafe { cmath::atan2f(self, other) }
+        cmath::atan2f(self, other)
     }
 
     /// Simultaneously computes the sine and cosine of the number, `x`. Returns
@@ -919,7 +919,7 @@ impl f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn exp_m1(self) -> f32 {
-        unsafe { cmath::expm1f(self) }
+        cmath::expm1f(self)
     }
 
     /// Returns `ln(1+n)` (natural logarithm) more accurately than if
@@ -957,7 +957,7 @@ impl f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn ln_1p(self) -> f32 {
-        unsafe { cmath::log1pf(self) }
+        cmath::log1pf(self)
     }
 
     /// Hyperbolic sine function.
@@ -987,7 +987,7 @@ impl f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn sinh(self) -> f32 {
-        unsafe { cmath::sinhf(self) }
+        cmath::sinhf(self)
     }
 
     /// Hyperbolic cosine function.
@@ -1017,7 +1017,7 @@ impl f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn cosh(self) -> f32 {
-        unsafe { cmath::coshf(self) }
+        cmath::coshf(self)
     }
 
     /// Hyperbolic tangent function.
@@ -1047,7 +1047,7 @@ impl f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn tanh(self) -> f32 {
-        unsafe { cmath::tanhf(self) }
+        cmath::tanhf(self)
     }
 
     /// Inverse hyperbolic sine function.
@@ -1158,7 +1158,7 @@ impl f32 {
     #[unstable(feature = "float_gamma", issue = "99842")]
     #[inline]
     pub fn gamma(self) -> f32 {
-        unsafe { cmath::tgammaf(self) }
+        cmath::tgammaf(self)
     }
 
     /// Natural logarithm of the absolute value of the gamma function
@@ -1188,7 +1188,7 @@ impl f32 {
     #[inline]
     pub fn ln_gamma(self) -> (f32, i32) {
         let mut signgamp: i32 = 0;
-        let x = unsafe { cmath::lgammaf_r(self, &mut signgamp) };
+        let x = cmath::lgammaf_r(self, &mut signgamp);
         (x, signgamp)
     }
 
@@ -1224,7 +1224,7 @@ impl f32 {
     #[unstable(feature = "float_erf", issue = "136321")]
     #[inline]
     pub fn erf(self) -> f32 {
-        unsafe { cmath::erff(self) }
+        cmath::erff(self)
     }
 
     /// Complementary error function.
@@ -1253,6 +1253,6 @@ impl f32 {
     #[unstable(feature = "float_erf", issue = "136321")]
     #[inline]
     pub fn erfc(self) -> f32 {
-        unsafe { cmath::erfcf(self) }
+        cmath::erfcf(self)
     }
 }
diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs
index 2aaab3ffc8352..84fd9bfb7b680 100644
--- a/library/std/src/f64.rs
+++ b/library/std/src/f64.rs
@@ -599,7 +599,7 @@ impl f64 {
                 filing an issue describing your use-case too)."
     )]
     pub fn abs_sub(self, other: f64) -> f64 {
-        unsafe { cmath::fdim(self, other) }
+        cmath::fdim(self, other)
     }
 
     /// Returns the cube root of a number.
@@ -626,7 +626,7 @@ impl f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn cbrt(self) -> f64 {
-        unsafe { cmath::cbrt(self) }
+        cmath::cbrt(self)
     }
 
     /// Compute the distance between the origin and a point (`x`, `y`) on the
@@ -657,7 +657,7 @@ impl f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn hypot(self, other: f64) -> f64 {
-        unsafe { cmath::hypot(self, other) }
+        cmath::hypot(self, other)
     }
 
     /// Computes the sine of a number (in radians).
@@ -730,7 +730,7 @@ impl f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn tan(self) -> f64 {
-        unsafe { cmath::tan(self) }
+        cmath::tan(self)
     }
 
     /// Computes the arcsine of a number. Return value is in radians in
@@ -760,7 +760,7 @@ impl f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn asin(self) -> f64 {
-        unsafe { cmath::asin(self) }
+        cmath::asin(self)
     }
 
     /// Computes the arccosine of a number. Return value is in radians in
@@ -790,7 +790,7 @@ impl f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn acos(self) -> f64 {
-        unsafe { cmath::acos(self) }
+        cmath::acos(self)
     }
 
     /// Computes the arctangent of a number. Return value is in radians in the
@@ -819,7 +819,7 @@ impl f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn atan(self) -> f64 {
-        unsafe { cmath::atan(self) }
+        cmath::atan(self)
     }
 
     /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians.
@@ -860,7 +860,7 @@ impl f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn atan2(self, other: f64) -> f64 {
-        unsafe { cmath::atan2(self, other) }
+        cmath::atan2(self, other)
     }
 
     /// Simultaneously computes the sine and cosine of the number, `x`. Returns
@@ -919,7 +919,7 @@ impl f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn exp_m1(self) -> f64 {
-        unsafe { cmath::expm1(self) }
+        cmath::expm1(self)
     }
 
     /// Returns `ln(1+n)` (natural logarithm) more accurately than if
@@ -957,7 +957,7 @@ impl f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn ln_1p(self) -> f64 {
-        unsafe { cmath::log1p(self) }
+        cmath::log1p(self)
     }
 
     /// Hyperbolic sine function.
@@ -987,7 +987,7 @@ impl f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn sinh(self) -> f64 {
-        unsafe { cmath::sinh(self) }
+        cmath::sinh(self)
     }
 
     /// Hyperbolic cosine function.
@@ -1017,7 +1017,7 @@ impl f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn cosh(self) -> f64 {
-        unsafe { cmath::cosh(self) }
+        cmath::cosh(self)
     }
 
     /// Hyperbolic tangent function.
@@ -1047,7 +1047,7 @@ impl f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn tanh(self) -> f64 {
-        unsafe { cmath::tanh(self) }
+        cmath::tanh(self)
     }
 
     /// Inverse hyperbolic sine function.
@@ -1158,7 +1158,7 @@ impl f64 {
     #[unstable(feature = "float_gamma", issue = "99842")]
     #[inline]
     pub fn gamma(self) -> f64 {
-        unsafe { cmath::tgamma(self) }
+        cmath::tgamma(self)
     }
 
     /// Natural logarithm of the absolute value of the gamma function
@@ -1188,7 +1188,7 @@ impl f64 {
     #[inline]
     pub fn ln_gamma(self) -> (f64, i32) {
         let mut signgamp: i32 = 0;
-        let x = unsafe { cmath::lgamma_r(self, &mut signgamp) };
+        let x = cmath::lgamma_r(self, &mut signgamp);
         (x, signgamp)
     }
 
@@ -1224,7 +1224,7 @@ impl f64 {
     #[unstable(feature = "float_erf", issue = "136321")]
     #[inline]
     pub fn erf(self) -> f64 {
-        unsafe { cmath::erf(self) }
+        cmath::erf(self)
     }
 
     /// Complementary error function.
@@ -1253,6 +1253,6 @@ impl f64 {
     #[unstable(feature = "float_erf", issue = "136321")]
     #[inline]
     pub fn erfc(self) -> f64 {
-        unsafe { cmath::erfc(self) }
+        cmath::erfc(self)
     }
 }
diff --git a/library/std/src/sys/cmath.rs b/library/std/src/sys/cmath.rs
index c9969b4e376ea..668fd92853400 100644
--- a/library/std/src/sys/cmath.rs
+++ b/library/std/src/sys/cmath.rs
@@ -3,70 +3,70 @@
 // These symbols are all defined by `libm`,
 // or by `compiler-builtins` on unsupported platforms.
 unsafe extern "C" {
-    pub fn acos(n: f64) -> f64;
-    pub fn asin(n: f64) -> f64;
-    pub fn atan(n: f64) -> f64;
-    pub fn atan2(a: f64, b: f64) -> f64;
-    pub fn cbrt(n: f64) -> f64;
-    pub fn cbrtf(n: f32) -> f32;
-    pub fn cosh(n: f64) -> f64;
-    pub fn expm1(n: f64) -> f64;
-    pub fn expm1f(n: f32) -> f32;
-    pub fn fdim(a: f64, b: f64) -> f64;
-    pub fn fdimf(a: f32, b: f32) -> f32;
+    pub safe fn acos(n: f64) -> f64;
+    pub safe fn asin(n: f64) -> f64;
+    pub safe fn atan(n: f64) -> f64;
+    pub safe fn atan2(a: f64, b: f64) -> f64;
+    pub safe fn cbrt(n: f64) -> f64;
+    pub safe fn cbrtf(n: f32) -> f32;
+    pub safe fn cosh(n: f64) -> f64;
+    pub safe fn expm1(n: f64) -> f64;
+    pub safe fn expm1f(n: f32) -> f32;
+    pub safe fn fdim(a: f64, b: f64) -> f64;
+    pub safe fn fdimf(a: f32, b: f32) -> f32;
     #[cfg_attr(target_env = "msvc", link_name = "_hypot")]
-    pub fn hypot(x: f64, y: f64) -> f64;
+    pub safe fn hypot(x: f64, y: f64) -> f64;
     #[cfg_attr(target_env = "msvc", link_name = "_hypotf")]
-    pub fn hypotf(x: f32, y: f32) -> f32;
-    pub fn log1p(n: f64) -> f64;
-    pub fn log1pf(n: f32) -> f32;
-    pub fn sinh(n: f64) -> f64;
-    pub fn tan(n: f64) -> f64;
-    pub fn tanh(n: f64) -> f64;
-    pub fn tgamma(n: f64) -> f64;
-    pub fn tgammaf(n: f32) -> f32;
-    pub fn lgamma_r(n: f64, s: &mut i32) -> f64;
+    pub safe fn hypotf(x: f32, y: f32) -> f32;
+    pub safe fn log1p(n: f64) -> f64;
+    pub safe fn log1pf(n: f32) -> f32;
+    pub safe fn sinh(n: f64) -> f64;
+    pub safe fn tan(n: f64) -> f64;
+    pub safe fn tanh(n: f64) -> f64;
+    pub safe fn tgamma(n: f64) -> f64;
+    pub safe fn tgammaf(n: f32) -> f32;
+    pub safe fn lgamma_r(n: f64, s: &mut i32) -> f64;
     #[cfg(not(target_os = "aix"))]
-    pub fn lgammaf_r(n: f32, s: &mut i32) -> f32;
-    pub fn erf(n: f64) -> f64;
-    pub fn erff(n: f32) -> f32;
-    pub fn erfc(n: f64) -> f64;
-    pub fn erfcf(n: f32) -> f32;
+    pub safe fn lgammaf_r(n: f32, s: &mut i32) -> f32;
+    pub safe fn erf(n: f64) -> f64;
+    pub safe fn erff(n: f32) -> f32;
+    pub safe fn erfc(n: f64) -> f64;
+    pub safe fn erfcf(n: f32) -> f32;
 
-    pub fn acosf128(n: f128) -> f128;
-    pub fn asinf128(n: f128) -> f128;
-    pub fn atanf128(n: f128) -> f128;
-    pub fn atan2f128(a: f128, b: f128) -> f128;
-    pub fn cbrtf128(n: f128) -> f128;
-    pub fn coshf128(n: f128) -> f128;
-    pub fn expm1f128(n: f128) -> f128;
-    pub fn hypotf128(x: f128, y: f128) -> f128;
-    pub fn log1pf128(n: f128) -> f128;
-    pub fn sinhf128(n: f128) -> f128;
-    pub fn tanf128(n: f128) -> f128;
-    pub fn tanhf128(n: f128) -> f128;
-    pub fn tgammaf128(n: f128) -> f128;
-    pub fn lgammaf128_r(n: f128, s: &mut i32) -> f128;
-    pub fn erff128(n: f128) -> f128;
-    pub fn erfcf128(n: f128) -> f128;
+    pub safe fn acosf128(n: f128) -> f128;
+    pub safe fn asinf128(n: f128) -> f128;
+    pub safe fn atanf128(n: f128) -> f128;
+    pub safe fn atan2f128(a: f128, b: f128) -> f128;
+    pub safe fn cbrtf128(n: f128) -> f128;
+    pub safe fn coshf128(n: f128) -> f128;
+    pub safe fn expm1f128(n: f128) -> f128;
+    pub safe fn hypotf128(x: f128, y: f128) -> f128;
+    pub safe fn log1pf128(n: f128) -> f128;
+    pub safe fn sinhf128(n: f128) -> f128;
+    pub safe fn tanf128(n: f128) -> f128;
+    pub safe fn tanhf128(n: f128) -> f128;
+    pub safe fn tgammaf128(n: f128) -> f128;
+    pub safe fn lgammaf128_r(n: f128, s: &mut i32) -> f128;
+    pub safe fn erff128(n: f128) -> f128;
+    pub safe fn erfcf128(n: f128) -> f128;
 
     cfg_if::cfg_if! {
     if #[cfg(not(all(target_os = "windows", target_env = "msvc", target_arch = "x86")))] {
-        pub fn acosf(n: f32) -> f32;
-        pub fn asinf(n: f32) -> f32;
-        pub fn atan2f(a: f32, b: f32) -> f32;
-        pub fn atanf(n: f32) -> f32;
-        pub fn coshf(n: f32) -> f32;
-        pub fn sinhf(n: f32) -> f32;
-        pub fn tanf(n: f32) -> f32;
-        pub fn tanhf(n: f32) -> f32;
+        pub safe fn acosf(n: f32) -> f32;
+        pub safe fn asinf(n: f32) -> f32;
+        pub safe fn atan2f(a: f32, b: f32) -> f32;
+        pub safe fn atanf(n: f32) -> f32;
+        pub safe fn coshf(n: f32) -> f32;
+        pub safe fn sinhf(n: f32) -> f32;
+        pub safe fn tanf(n: f32) -> f32;
+        pub safe fn tanhf(n: f32) -> f32;
     }}
 }
 
 // On AIX, we don't have lgammaf_r only the f64 version, so we can
 // use the f64 version lgamma_r
 #[cfg(target_os = "aix")]
-pub unsafe fn lgammaf_r(n: f32, s: &mut i32) -> f32 {
+pub fn lgammaf_r(n: f32, s: &mut i32) -> f32 {
     lgamma_r(n.into(), s) as f32
 }
 
@@ -76,42 +76,42 @@ pub unsafe fn lgammaf_r(n: f32, s: &mut i32) -> f32 {
 cfg_if::cfg_if! {
 if #[cfg(all(target_os = "windows", target_env = "msvc", target_arch = "x86"))] {
     #[inline]
-    pub unsafe fn acosf(n: f32) -> f32 {
+    pub fn acosf(n: f32) -> f32 {
         f64::acos(n as f64) as f32
     }
 
     #[inline]
-    pub unsafe fn asinf(n: f32) -> f32 {
+    pub fn asinf(n: f32) -> f32 {
         f64::asin(n as f64) as f32
     }
 
     #[inline]
-    pub unsafe fn atan2f(n: f32, b: f32) -> f32 {
+    pub fn atan2f(n: f32, b: f32) -> f32 {
         f64::atan2(n as f64, b as f64) as f32
     }
 
     #[inline]
-    pub unsafe fn atanf(n: f32) -> f32 {
+    pub fn atanf(n: f32) -> f32 {
         f64::atan(n as f64) as f32
     }
 
     #[inline]
-    pub unsafe fn coshf(n: f32) -> f32 {
+    pub fn coshf(n: f32) -> f32 {
         f64::cosh(n as f64) as f32
     }
 
     #[inline]
-    pub unsafe fn sinhf(n: f32) -> f32 {
+    pub fn sinhf(n: f32) -> f32 {
         f64::sinh(n as f64) as f32
     }
 
     #[inline]
-    pub unsafe fn tanf(n: f32) -> f32 {
+    pub fn tanf(n: f32) -> f32 {
         f64::tan(n as f64) as f32
     }
 
     #[inline]
-    pub unsafe fn tanhf(n: f32) -> f32 {
+    pub fn tanhf(n: f32) -> f32 {
         f64::tanh(n as f64) as f32
     }
 }}

From 19648ce5cd12b11889eccacac50c70ca8ac78fee Mon Sep 17 00:00:00 2001
From: Scott McMurray <scottmcm@users.noreply.github.com>
Date: Sun, 23 Mar 2025 18:45:08 -0700
Subject: [PATCH 2/9] codegen test for non-memcmp array comparison

---
 tests/codegen/array-cmp.rs | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/tests/codegen/array-cmp.rs b/tests/codegen/array-cmp.rs
index 2565a385b61b5..f9b7be8988282 100644
--- a/tests/codegen/array-cmp.rs
+++ b/tests/codegen/array-cmp.rs
@@ -17,3 +17,15 @@ pub fn compare() -> bool {
             [0x00, 0x00, 0x48, 0x41]
         }
 }
+
+// CHECK-LABEL: @array_of_tuple_le
+// CHECK: call{{.+}}i8 @llvm.scmp.i8.i16
+// CHECK: call{{.+}}i8 @llvm.ucmp.i8.i16
+// CHECK: call{{.+}}i8 @llvm.scmp.i8.i16
+// CHECK: call{{.+}}i8 @llvm.ucmp.i8.i16
+// CHECK: %[[RET:.+]] = icmp slt i8 {{.+}}, 1
+// CHECK: ret i8 %[[RET]]
+#[no_mangle]
+pub fn array_of_tuple_le(a: &[(i16, u16); 2], b: &[(i16, u16); 2]) -> bool {
+    a <= b
+}

From cf991d9dda411add433565e8759d53413426b131 Mon Sep 17 00:00:00 2001
From: Scott McMurray <scottmcm@users.noreply.github.com>
Date: Sun, 23 Mar 2025 20:45:36 -0700
Subject: [PATCH 3/9] Extend the chaining logic to slices too

---
 library/core/src/cmp.rs       |  32 +++++++
 library/core/src/slice/cmp.rs | 174 ++++++++++++++++++++++++++++------
 library/core/src/tuple.rs     |  29 +++++-
 tests/codegen/array-cmp.rs    |  55 +++++++++--
 4 files changed, 254 insertions(+), 36 deletions(-)

diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index 0dc2cc72e06cc..c315131f4136c 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -2053,6 +2053,22 @@ mod impls {
         fn ge(&self, other: &&B) -> bool {
             PartialOrd::ge(*self, *other)
         }
+        #[inline]
+        fn __chaining_lt(&self, other: &&B) -> ControlFlow<bool> {
+            PartialOrd::__chaining_lt(*self, *other)
+        }
+        #[inline]
+        fn __chaining_le(&self, other: &&B) -> ControlFlow<bool> {
+            PartialOrd::__chaining_le(*self, *other)
+        }
+        #[inline]
+        fn __chaining_gt(&self, other: &&B) -> ControlFlow<bool> {
+            PartialOrd::__chaining_gt(*self, *other)
+        }
+        #[inline]
+        fn __chaining_ge(&self, other: &&B) -> ControlFlow<bool> {
+            PartialOrd::__chaining_ge(*self, *other)
+        }
     }
     #[stable(feature = "rust1", since = "1.0.0")]
     impl<A: ?Sized> Ord for &A
@@ -2108,6 +2124,22 @@ mod impls {
         fn ge(&self, other: &&mut B) -> bool {
             PartialOrd::ge(*self, *other)
         }
+        #[inline]
+        fn __chaining_lt(&self, other: &&mut B) -> ControlFlow<bool> {
+            PartialOrd::__chaining_lt(*self, *other)
+        }
+        #[inline]
+        fn __chaining_le(&self, other: &&mut B) -> ControlFlow<bool> {
+            PartialOrd::__chaining_le(*self, *other)
+        }
+        #[inline]
+        fn __chaining_gt(&self, other: &&mut B) -> ControlFlow<bool> {
+            PartialOrd::__chaining_gt(*self, *other)
+        }
+        #[inline]
+        fn __chaining_ge(&self, other: &&mut B) -> ControlFlow<bool> {
+            PartialOrd::__chaining_ge(*self, *other)
+        }
     }
     #[stable(feature = "rust1", since = "1.0.0")]
     impl<A: ?Sized> Ord for &mut A
diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs
index da85f42926e6b..5ce72b46eee36 100644
--- a/library/core/src/slice/cmp.rs
+++ b/library/core/src/slice/cmp.rs
@@ -5,6 +5,7 @@ use crate::ascii;
 use crate::cmp::{self, BytewiseEq, Ordering};
 use crate::intrinsics::compare_bytes;
 use crate::num::NonZero;
+use crate::ops::ControlFlow;
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T, U> PartialEq<[U]> for [T]
@@ -31,12 +32,64 @@ impl<T: Ord> Ord for [T] {
     }
 }
 
+#[inline]
+fn as_underlying(x: ControlFlow<bool>) -> u8 {
+    // SAFETY: This will only compile if `bool` and `ControlFlow<bool>` have the same
+    // size (which isn't guaranteed but this is libcore). Because they have the same
+    // size, it's a niched implementation, which in one byte means there can't be
+    // any uninitialized memory. The callers then only check for `0` or `1` from this,
+    // which must necessarily match the `Break` variant, and we're fine no matter
+    // what ends up getting picked as the value representing `Continue(())`.
+    unsafe { crate::mem::transmute(x) }
+}
+
 /// Implements comparison of slices [lexicographically](Ord#lexicographical-comparison).
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: PartialOrd> PartialOrd for [T] {
+    #[inline]
     fn partial_cmp(&self, other: &[T]) -> Option<Ordering> {
         SlicePartialOrd::partial_compare(self, other)
     }
+    #[inline]
+    fn lt(&self, other: &Self) -> bool {
+        // This is certainly not the obvious way to implement these methods.
+        // Unfortunately, using anything that looks at the discriminant means that
+        // LLVM sees a check for `2` (aka `ControlFlow<bool>::Continue(())`) and
+        // gets very distracted by that, ending up generating extraneous code.
+        // This should be changed to something simpler once either LLVM is smarter,
+        // see <https://github.com/llvm/llvm-project/issues/132678>, or we generate
+        // niche discriminant checks in a way that doesn't trigger it.
+
+        as_underlying(self.__chaining_lt(other)) == 1
+    }
+    #[inline]
+    fn le(&self, other: &Self) -> bool {
+        as_underlying(self.__chaining_le(other)) != 0
+    }
+    #[inline]
+    fn gt(&self, other: &Self) -> bool {
+        as_underlying(self.__chaining_gt(other)) == 1
+    }
+    #[inline]
+    fn ge(&self, other: &Self) -> bool {
+        as_underlying(self.__chaining_ge(other)) != 0
+    }
+    #[inline]
+    fn __chaining_lt(&self, other: &Self) -> ControlFlow<bool> {
+        SliceChain::chaining_lt(self, other)
+    }
+    #[inline]
+    fn __chaining_le(&self, other: &Self) -> ControlFlow<bool> {
+        SliceChain::chaining_le(self, other)
+    }
+    #[inline]
+    fn __chaining_gt(&self, other: &Self) -> ControlFlow<bool> {
+        SliceChain::chaining_gt(self, other)
+    }
+    #[inline]
+    fn __chaining_ge(&self, other: &Self) -> ControlFlow<bool> {
+        SliceChain::chaining_ge(self, other)
+    }
 }
 
 #[doc(hidden)]
@@ -99,24 +152,63 @@ trait SlicePartialOrd: Sized {
     fn partial_compare(left: &[Self], right: &[Self]) -> Option<Ordering>;
 }
 
+#[doc(hidden)]
+// intermediate trait for specialization of slice's PartialOrd chaining methods
+trait SliceChain: Sized {
+    fn chaining_lt(left: &[Self], right: &[Self]) -> ControlFlow<bool>;
+    fn chaining_le(left: &[Self], right: &[Self]) -> ControlFlow<bool>;
+    fn chaining_gt(left: &[Self], right: &[Self]) -> ControlFlow<bool>;
+    fn chaining_ge(left: &[Self], right: &[Self]) -> ControlFlow<bool>;
+}
+
+type AlwaysBreak<B> = ControlFlow<B, crate::convert::Infallible>;
+
 impl<A: PartialOrd> SlicePartialOrd for A {
     default fn partial_compare(left: &[A], right: &[A]) -> Option<Ordering> {
-        let l = cmp::min(left.len(), right.len());
-
-        // Slice to the loop iteration range to enable bound check
-        // elimination in the compiler
-        let lhs = &left[..l];
-        let rhs = &right[..l];
+        let elem_chain = |a, b| match PartialOrd::partial_cmp(a, b) {
+            Some(Ordering::Equal) => ControlFlow::Continue(()),
+            non_eq => ControlFlow::Break(non_eq),
+        };
+        let len_chain = |a: &_, b: &_| ControlFlow::Break(usize::partial_cmp(a, b));
+        let AlwaysBreak::Break(b) = chaining_impl(left, right, elem_chain, len_chain);
+        b
+    }
+}
 
-        for i in 0..l {
-            match lhs[i].partial_cmp(&rhs[i]) {
-                Some(Ordering::Equal) => (),
-                non_eq => return non_eq,
-            }
-        }
+impl<A: PartialOrd> SliceChain for A {
+    default fn chaining_lt(left: &[Self], right: &[Self]) -> ControlFlow<bool> {
+        chaining_impl(left, right, PartialOrd::__chaining_lt, usize::__chaining_lt)
+    }
+    default fn chaining_le(left: &[Self], right: &[Self]) -> ControlFlow<bool> {
+        chaining_impl(left, right, PartialOrd::__chaining_le, usize::__chaining_le)
+    }
+    default fn chaining_gt(left: &[Self], right: &[Self]) -> ControlFlow<bool> {
+        chaining_impl(left, right, PartialOrd::__chaining_gt, usize::__chaining_gt)
+    }
+    default fn chaining_ge(left: &[Self], right: &[Self]) -> ControlFlow<bool> {
+        chaining_impl(left, right, PartialOrd::__chaining_ge, usize::__chaining_ge)
+    }
+}
 
-        left.len().partial_cmp(&right.len())
+#[inline]
+fn chaining_impl<'l, 'r, A: PartialOrd, B, C>(
+    left: &'l [A],
+    right: &'r [A],
+    elem_chain: impl Fn(&'l A, &'r A) -> ControlFlow<B>,
+    len_chain: impl for<'a> FnOnce(&'a usize, &'a usize) -> ControlFlow<B, C>,
+) -> ControlFlow<B, C> {
+    let l = cmp::min(left.len(), right.len());
+
+    // Slice to the loop iteration range to enable bound check
+    // elimination in the compiler
+    let lhs = &left[..l];
+    let rhs = &right[..l];
+
+    for i in 0..l {
+        elem_chain(&lhs[i], &rhs[i])?;
     }
+
+    len_chain(&left.len(), &right.len())
 }
 
 // This is the impl that we would like to have. Unfortunately it's not sound.
@@ -165,21 +257,13 @@ trait SliceOrd: Sized {
 
 impl<A: Ord> SliceOrd for A {
     default fn compare(left: &[Self], right: &[Self]) -> Ordering {
-        let l = cmp::min(left.len(), right.len());
-
-        // Slice to the loop iteration range to enable bound check
-        // elimination in the compiler
-        let lhs = &left[..l];
-        let rhs = &right[..l];
-
-        for i in 0..l {
-            match lhs[i].cmp(&rhs[i]) {
-                Ordering::Equal => (),
-                non_eq => return non_eq,
-            }
-        }
-
-        left.len().cmp(&right.len())
+        let elem_chain = |a, b| match Ord::cmp(a, b) {
+            Ordering::Equal => ControlFlow::Continue(()),
+            non_eq => ControlFlow::Break(non_eq),
+        };
+        let len_chain = |a: &_, b: &_| ControlFlow::Break(usize::cmp(a, b));
+        let AlwaysBreak::Break(b) = chaining_impl(left, right, elem_chain, len_chain);
+        b
     }
 }
 
@@ -191,7 +275,7 @@ impl<A: Ord> SliceOrd for A {
 /// * For every `x` and `y` of this type, `Ord(x, y)` must return the same
 ///   value as `Ord::cmp(transmute::<_, u8>(x), transmute::<_, u8>(y))`.
 #[rustc_specialization_trait]
-unsafe trait UnsignedBytewiseOrd {}
+unsafe trait UnsignedBytewiseOrd: Ord {}
 
 unsafe impl UnsignedBytewiseOrd for bool {}
 unsafe impl UnsignedBytewiseOrd for u8 {}
@@ -225,6 +309,38 @@ impl<A: Ord + UnsignedBytewiseOrd> SliceOrd for A {
     }
 }
 
+// Don't generate our own chaining loops for `memcmp`-able things either.
+impl<A: PartialOrd + UnsignedBytewiseOrd> SliceChain for A {
+    #[inline]
+    fn chaining_lt(left: &[Self], right: &[Self]) -> ControlFlow<bool> {
+        match SliceOrd::compare(left, right) {
+            Ordering::Equal => ControlFlow::Continue(()),
+            ne => ControlFlow::Break(ne.is_lt()),
+        }
+    }
+    #[inline]
+    fn chaining_le(left: &[Self], right: &[Self]) -> ControlFlow<bool> {
+        match SliceOrd::compare(left, right) {
+            Ordering::Equal => ControlFlow::Continue(()),
+            ne => ControlFlow::Break(ne.is_le()),
+        }
+    }
+    #[inline]
+    fn chaining_gt(left: &[Self], right: &[Self]) -> ControlFlow<bool> {
+        match SliceOrd::compare(left, right) {
+            Ordering::Equal => ControlFlow::Continue(()),
+            ne => ControlFlow::Break(ne.is_gt()),
+        }
+    }
+    #[inline]
+    fn chaining_ge(left: &[Self], right: &[Self]) -> ControlFlow<bool> {
+        match SliceOrd::compare(left, right) {
+            Ordering::Equal => ControlFlow::Continue(()),
+            ne => ControlFlow::Break(ne.is_ge()),
+        }
+    }
+}
+
 pub(super) trait SliceContains: Sized {
     fn slice_contains(&self, x: &[Self]) -> bool;
 }
diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs
index d754bb9034300..02eb805ece121 100644
--- a/library/core/src/tuple.rs
+++ b/library/core/src/tuple.rs
@@ -2,7 +2,7 @@
 
 use crate::cmp::Ordering::{self, *};
 use crate::marker::{ConstParamTy_, StructuralPartialEq, UnsizedConstParamTy};
-use crate::ops::ControlFlow::{Break, Continue};
+use crate::ops::ControlFlow::{self, Break, Continue};
 
 // Recursive macro for implementing n-ary tuple functions and operations
 //
@@ -95,6 +95,22 @@ macro_rules! tuple_impls {
                 fn gt(&self, other: &($($T,)+)) -> bool {
                     lexical_ord!(gt, __chaining_gt, $( ${ignore($T)} self.${index()}, other.${index()} ),+)
                 }
+                #[inline]
+                fn __chaining_lt(&self, other: &($($T,)+)) -> ControlFlow<bool> {
+                    lexical_chain!(__chaining_lt, $( ${ignore($T)} self.${index()}, other.${index()} ),+)
+                }
+                #[inline]
+                fn __chaining_le(&self, other: &($($T,)+)) -> ControlFlow<bool> {
+                    lexical_chain!(__chaining_le, $( ${ignore($T)} self.${index()}, other.${index()} ),+)
+                }
+                #[inline]
+                fn __chaining_gt(&self, other: &($($T,)+)) -> ControlFlow<bool> {
+                    lexical_chain!(__chaining_gt, $( ${ignore($T)} self.${index()}, other.${index()} ),+)
+                }
+                #[inline]
+                fn __chaining_ge(&self, other: &($($T,)+)) -> ControlFlow<bool> {
+                    lexical_chain!(__chaining_ge, $( ${ignore($T)} self.${index()}, other.${index()} ),+)
+                }
             }
         }
 
@@ -187,6 +203,17 @@ macro_rules! lexical_ord {
     };
 }
 
+// Same parameter interleaving as `lexical_ord` above
+macro_rules! lexical_chain {
+    ($chain_rel: ident, $a:expr, $b:expr $(,$rest_a:expr, $rest_b:expr)*) => {{
+        PartialOrd::$chain_rel(&$a, &$b)?;
+        lexical_chain!($chain_rel $(,$rest_a, $rest_b)*)
+    }};
+    ($chain_rel: ident) => {
+        Continue(())
+    };
+}
+
 macro_rules! lexical_partial_cmp {
     ($a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {
         match ($a).partial_cmp(&$b) {
diff --git a/tests/codegen/array-cmp.rs b/tests/codegen/array-cmp.rs
index f9b7be8988282..cd79c3a1ab633 100644
--- a/tests/codegen/array-cmp.rs
+++ b/tests/codegen/array-cmp.rs
@@ -1,6 +1,7 @@
 // Ensure the asm for array comparisons is properly optimized.
 
 //@ compile-flags: -C opt-level=2
+//@ needs-deterministic-layouts (checks depend on tuple layout)
 
 #![crate_type = "lib"]
 
@@ -19,13 +20,55 @@ pub fn compare() -> bool {
 }
 
 // CHECK-LABEL: @array_of_tuple_le
-// CHECK: call{{.+}}i8 @llvm.scmp.i8.i16
-// CHECK: call{{.+}}i8 @llvm.ucmp.i8.i16
-// CHECK: call{{.+}}i8 @llvm.scmp.i8.i16
-// CHECK: call{{.+}}i8 @llvm.ucmp.i8.i16
-// CHECK: %[[RET:.+]] = icmp slt i8 {{.+}}, 1
-// CHECK: ret i8 %[[RET]]
 #[no_mangle]
 pub fn array_of_tuple_le(a: &[(i16, u16); 2], b: &[(i16, u16); 2]) -> bool {
+    // Ensure that, after all the optimizations have run, the happy path just checks
+    // `eq` on each corresponding pair and moves onto the next one if it is.
+    // Then there's a dedup'd comparison for the place that's different.
+    // (As opposed to, say, running a full `[su]cmp` as part of checking equality.)
+
+    // This is written quite specifically because different library code was triggering
+    // <https://github.com/llvm/llvm-project/issues/132678> along the way, so this
+    // has enough checks to make sure that's not happening. It doesn't need to be
+    // *exactly* this IR, but be careful if you ever need to update these checks.
+
+    // CHECK: start:
+    // CHECK: %[[A00:.+]] = load i16, ptr %a
+    // CHECK: %[[B00:.+]] = load i16, ptr %b
+    // CHECK-NOT: cmp
+    // CHECK: %[[EQ00:.+]] = icmp eq i16 %[[A00]], %[[B00]]
+    // CHECK-NEXT: br i1 %[[EQ00]], label %[[L01:.+]], label %[[EXIT_S:.+]]
+
+    // CHECK: [[L01]]:
+    // CHECK: %[[PA01:.+]] = getelementptr{{.+}}i8, ptr %a, i64 2
+    // CHECK: %[[PB01:.+]] = getelementptr{{.+}}i8, ptr %b, i64 2
+    // CHECK: %[[A01:.+]] = load i16, ptr %[[PA01]]
+    // CHECK: %[[B01:.+]] = load i16, ptr %[[PB01]]
+    // CHECK-NOT: cmp
+    // CHECK: %[[EQ01:.+]] = icmp eq i16 %[[A01]], %[[B01]]
+    // CHECK-NEXT: br i1 %[[EQ01]], label %[[L10:.+]], label %[[EXIT_U:.+]]
+
+    // CHECK: [[L10]]:
+    // CHECK: %[[PA10:.+]] = getelementptr{{.+}}i8, ptr %a, i64 4
+    // CHECK: %[[PB10:.+]] = getelementptr{{.+}}i8, ptr %b, i64 4
+    // CHECK: %[[A10:.+]] = load i16, ptr %[[PA10]]
+    // CHECK: %[[B10:.+]] = load i16, ptr %[[PB10]]
+    // CHECK-NOT: cmp
+    // CHECK: %[[EQ10:.+]] = icmp eq i16 %[[A10]], %[[B10]]
+    // CHECK-NEXT: br i1 %[[EQ10]], label %[[L11:.+]], label %[[EXIT_S]]
+
+    // CHECK: [[L11]]:
+    // CHECK: %[[PA11:.+]] = getelementptr{{.+}}i8, ptr %a, i64 6
+    // CHECK: %[[PB11:.+]] = getelementptr{{.+}}i8, ptr %b, i64 6
+    // CHECK: %[[A11:.+]] = load i16, ptr %[[PA11]]
+    // CHECK: %[[B11:.+]] = load i16, ptr %[[PB11]]
+    // CHECK-NOT: cmp
+    // CHECK: %[[EQ11:.+]] = icmp eq i16 %[[A11]], %[[B11]]
+    // CHECK-NEXT: br i1 %[[EQ11]], label %[[DONE:.+]], label %[[EXIT_U]]
+
+    // CHECK: [[DONE]]:
+    // CHECK: %[[RET:.+]] = phi i1 [ %{{.+}}, %[[EXIT_S]] ], [ %{{.+}}, %[[EXIT_U]] ], [ true, %[[L11]] ]
+    // CHECK: ret i1 %[[RET]]
+
     a <= b
 }

From 0acac2cbe306b8db9bc0a7c45f529f1dfa6680c8 Mon Sep 17 00:00:00 2001
From: Thalia Archibald <thalia@archibald.dev>
Date: Wed, 26 Mar 2025 00:38:28 -0700
Subject: [PATCH 4/9] std: Fix build for NuttX targets

Fix std build for all NuttX targets. It is the single largest set of
failures on <https://does-it-build.noratrieb.dev/>. Although, ESP-IDF
also requires these same gates, there are other issues for those
targets.

This can verified be running `x check library/std --target=` for all
NuttX targets.
---
 library/std/src/sys/fd/unix.rs                    | 2 ++
 library/std/src/sys/net/connection/socket/unix.rs | 1 +
 2 files changed, 3 insertions(+)

diff --git a/library/std/src/sys/fd/unix.rs b/library/std/src/sys/fd/unix.rs
index 2042ea2c73d00..13fefb4031d08 100644
--- a/library/std/src/sys/fd/unix.rs
+++ b/library/std/src/sys/fd/unix.rs
@@ -71,9 +71,11 @@ const fn max_iov() -> usize {
     target_os = "android",
     target_os = "dragonfly",
     target_os = "emscripten",
+    target_os = "espidf",
     target_os = "freebsd",
     target_os = "linux",
     target_os = "netbsd",
+    target_os = "nuttx",
     target_os = "nto",
     target_os = "openbsd",
     target_os = "horizon",
diff --git a/library/std/src/sys/net/connection/socket/unix.rs b/library/std/src/sys/net/connection/socket/unix.rs
index bbe1e038dccf5..b35d5d2aa8418 100644
--- a/library/std/src/sys/net/connection/socket/unix.rs
+++ b/library/std/src/sys/net/connection/socket/unix.rs
@@ -1,5 +1,6 @@
 use libc::{MSG_PEEK, c_int, c_void, size_t, sockaddr, socklen_t};
 
+#[cfg(not(any(target_os = "espidf", target_os = "nuttx")))]
 use crate::ffi::CStr;
 use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut};
 use crate::net::{Shutdown, SocketAddr};

From 394610b6d6b0bde38f75b7cc41ec1931bb7f0323 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= <berykubik@gmail.com>
Date: Fri, 11 Apr 2025 21:30:10 +0200
Subject: [PATCH 5/9] Document that `opt-dist` requires metrics to be enabled

---
 src/doc/rustc-dev-guide/src/building/optimized-build.md | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/src/doc/rustc-dev-guide/src/building/optimized-build.md b/src/doc/rustc-dev-guide/src/building/optimized-build.md
index 0849464eab368..62dfaca89d24e 100644
--- a/src/doc/rustc-dev-guide/src/building/optimized-build.md
+++ b/src/doc/rustc-dev-guide/src/building/optimized-build.md
@@ -109,11 +109,16 @@ like Python or LLVM.
 
 Here is an example of how can `opt-dist` be used locally (outside of CI):
 
-1. Build the tool with the following command:
+1. Enable metrics in your `bootstrap.toml` file, because `opt-dist` expects it to be enabled:
+    ```toml
+   [build]
+   metrics = true
+   ```
+2. Build the tool with the following command:
     ```bash
     ./x build tools/opt-dist
     ```
-2. Run the tool with the `local` mode and provide necessary parameters:
+3. Run the tool with the `local` mode and provide necessary parameters:
     ```bash
     ./build/host/stage0-tools-bin/opt-dist local \
       --target-triple <target> \ # select target, e.g. "x86_64-unknown-linux-gnu"

From ddf8237bcb05272a677cba46cffa0296b7477809 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= <berykubik@gmail.com>
Date: Sat, 12 Apr 2025 10:05:50 +0200
Subject: [PATCH 6/9] Fix comment in bootstrap

---
 src/bootstrap/src/core/build_steps/tool.rs | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs
index 1c61f0a56d7b9..ded7220fcedcd 100644
--- a/src/bootstrap/src/core/build_steps/tool.rs
+++ b/src/bootstrap/src/core/build_steps/tool.rs
@@ -150,10 +150,7 @@ impl Step for ToolBuild {
 
         // Rustc tools (miri, clippy, cargo, rustfmt, rust-analyzer)
         // could use the additional optimizations.
-        if self.mode == Mode::ToolRustc &&
-            // rustdoc is performance sensitive, so apply LTO to it.
-            is_lto_stage(&self.compiler)
-        {
+        if self.mode == Mode::ToolRustc && is_lto_stage(&self.compiler) {
             let lto = match builder.config.rust_lto {
                 RustcLto::Off => Some("off"),
                 RustcLto::Thin => Some("thin"),

From 83dd8a2c2a7d948e669adc7170dfc4bf0b76a873 Mon Sep 17 00:00:00 2001
From: Samuel Tardieu <sam@rfc1149.net>
Date: Sat, 12 Apr 2025 11:33:33 +0200
Subject: [PATCH 7/9] Fix name of field in doc comment

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

diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index c9c4936c15640..6455f33b9d153 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1756,7 +1756,7 @@ pub enum PatKind<'hir> {
     Never,
 
     /// A tuple pattern (e.g., `(a, b)`).
-    /// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
+    /// If the `..` pattern fragment is present, then `DotDotPos` denotes its position.
     /// `0 <= position <= subpats.len()`
     Tuple(&'hir [Pat<'hir>], DotDotPos),
 

From 32dd3831f56973881ad2a47d4b4002d18de26c5f Mon Sep 17 00:00:00 2001
From: Tshepang Mbambo <tshepang@gmail.com>
Date: Sat, 12 Apr 2025 11:38:55 +0200
Subject: [PATCH 8/9] bootstrap: fix typo in doc string

---
 src/bootstrap/src/core/download.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs
index 5bd947f6e6360..4e4b948a8fd6a 100644
--- a/src/bootstrap/src/core/download.rs
+++ b/src/bootstrap/src/core/download.rs
@@ -417,7 +417,7 @@ enum DownloadSource {
     Dist,
 }
 
-/// Functions that are only ever called once, but named for clarify and to avoid thousand-line functions.
+/// Functions that are only ever called once, but named for clarity and to avoid thousand-line functions.
 impl Config {
     pub(crate) fn download_clippy(&self) -> PathBuf {
         self.verbose(|| println!("downloading stage0 clippy artifacts"));

From 11256a0fb09b066f2b72f24889f8c02c2ef30098 Mon Sep 17 00:00:00 2001
From: reddevilmidzy <midzy0228@gmail.com>
Date: Wed, 9 Apr 2025 23:22:23 +0900
Subject: [PATCH 9/9] Add regression test for #127424

---
 .../const-generics-closure.rs                 | 13 ++++++++++
 .../const-generics-closure.stderr             | 26 +++++++++++++++++++
 2 files changed, 39 insertions(+)
 create mode 100644 tests/ui/const-generics/generic_const_exprs/const-generics-closure.rs
 create mode 100644 tests/ui/const-generics/generic_const_exprs/const-generics-closure.stderr

diff --git a/tests/ui/const-generics/generic_const_exprs/const-generics-closure.rs b/tests/ui/const-generics/generic_const_exprs/const-generics-closure.rs
new file mode 100644
index 0000000000000..aad8cefe5d62f
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/const-generics-closure.rs
@@ -0,0 +1,13 @@
+// Regression test for issue #127424
+
+fn bar() -> impl Into<
+    [u8; {
+        //~^ ERROR mismatched types [E0308]
+        let _ = for<'a, 'b> |x: &'a &'a Vec<&'b u32>, b: bool| -> &'a Vec<&'b u32> { *x };
+        //~^ ERROR `for<...>` binders for closures are experimental [E0658]
+    }],
+> {
+    [89]
+}
+
+fn main() {}
diff --git a/tests/ui/const-generics/generic_const_exprs/const-generics-closure.stderr b/tests/ui/const-generics/generic_const_exprs/const-generics-closure.stderr
new file mode 100644
index 0000000000000..5410bbdc12536
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/const-generics-closure.stderr
@@ -0,0 +1,26 @@
+error[E0658]: `for<...>` binders for closures are experimental
+  --> $DIR/const-generics-closure.rs:6:17
+   |
+LL |         let _ = for<'a, 'b> |x: &'a &'a Vec<&'b u32>, b: bool| -> &'a Vec<&'b u32> { *x };
+   |                 ^^^^^^^^^^^
+   |
+   = note: see issue #97362 <https://github.com/rust-lang/rust/issues/97362> for more information
+   = help: add `#![feature(closure_lifetime_binder)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = help: consider removing `for<...>`
+
+error[E0308]: mismatched types
+  --> $DIR/const-generics-closure.rs:4:10
+   |
+LL |       [u8; {
+   |  __________^
+LL | |
+LL | |         let _ = for<'a, 'b> |x: &'a &'a Vec<&'b u32>, b: bool| -> &'a Vec<&'b u32> { *x };
+LL | |
+LL | |     }],
+   | |_____^ expected `usize`, found `()`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0308, E0658.
+For more information about an error, try `rustc --explain E0308`.