From 73c3905de7b2a7cc14594080a72d4cd58391ebc7 Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Thu, 18 Sep 2025 08:07:51 +0800 Subject: [PATCH 1/8] Add `is_ascii` function optimized for LoongArch64 for [u8] Similar to x86_64, on LoongArch64 we use the `vmskltz.b` instruction to test the high bit in a lane. For longer input cases, the performance improvement is significant. For unaligned cases close to 32 bytes in length, there's some regression, but it seems acceptable. | core benches (MB/s) | Before | After | % | |--------------------------------------------------------|--------|--------|---------| | ascii::is_ascii::short::case00_libcore | 1000 | 1000 | 0.00 | | ascii::is_ascii::medium::case00_libcore | 8000 | 8000 | 0.00 | | ascii::is_ascii::long::case00_libcore | 183947 | 436875 | +137.50 | | ascii::is_ascii::unaligned_head_medium::case00_libcore | 7750 | 2818 | -63.64 | | ascii::is_ascii::unaligned_head_long::case00_libcore | 317681 | 436812 | +37.50 | | ascii::is_ascii::unaligned_tail_medium::case00_libcore | 7750 | 3444 | -55.56 | | ascii::is_ascii::unaligned_tail_long::case00_libcore | 155311 | 436812 | +181.25 | | ascii::is_ascii::unaligned_both_medium::case00_libcore | 7500 | 3333 | -55.56 | | ascii::is_ascii::unaligned_both_long::case00_libcore | 174700 | 436750 | +150.00 | --- library/core/src/slice/ascii.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs index e17a2e03d2dc4..d02be440f5bfb 100644 --- a/library/core/src/slice/ascii.rs +++ b/library/core/src/slice/ascii.rs @@ -3,7 +3,10 @@ use core::ascii::EscapeDefault; use crate::fmt::{self, Write}; -#[cfg(not(all(target_arch = "x86_64", target_feature = "sse2")))] +#[cfg(not(any( + all(target_arch = "x86_64", target_feature = "sse2"), + all(target_arch = "loongarch64", target_feature = "lsx") +)))] use crate::intrinsics::const_eval_select; use crate::{ascii, iter, ops}; @@ -357,7 +360,10 @@ pub const fn is_ascii_simple(mut bytes: &[u8]) -> bool { /// /// If any of these loads produces something for which `contains_nonascii` /// (above) returns true, then we know the answer is false. -#[cfg(not(all(target_arch = "x86_64", target_feature = "sse2")))] +#[cfg(not(any( + all(target_arch = "x86_64", target_feature = "sse2"), + all(target_arch = "loongarch64", target_feature = "lsx") +)))] #[inline] #[rustc_allow_const_fn_unstable(const_eval_select)] // fallback impl has same behavior const fn is_ascii(s: &[u8]) -> bool { @@ -455,12 +461,15 @@ const fn is_ascii(s: &[u8]) -> bool { ) } -/// ASCII test optimized to use the `pmovmskb` instruction available on `x86-64` -/// platforms. +/// ASCII test optimized to use the `pmovmskb` instruction on `x86-64` and the +/// `vmskltz.b` instruction on `loongarch64`. /// /// Other platforms are not likely to benefit from this code structure, so they /// use SWAR techniques to test for ASCII in `usize`-sized chunks. -#[cfg(all(target_arch = "x86_64", target_feature = "sse2"))] +#[cfg(any( + all(target_arch = "x86_64", target_feature = "sse2"), + all(target_arch = "loongarch64", target_feature = "lsx") +))] #[inline] const fn is_ascii(bytes: &[u8]) -> bool { // Process chunks of 32 bytes at a time in the fast path to enable From 4ee19d9e865ad619bbf790c01762cb66277016b6 Mon Sep 17 00:00:00 2001 From: Evgenii Zheltonozhskii Date: Tue, 21 Oct 2025 13:21:06 +0300 Subject: [PATCH 2/8] Constify Range functions --- library/core/src/ops/index_range.rs | 9 +- library/core/src/ops/range.rs | 168 ++++++++++++++++++---------- library/core/src/range.rs | 73 +++++++----- library/core/src/slice/index.rs | 11 +- 4 files changed, 171 insertions(+), 90 deletions(-) diff --git a/library/core/src/ops/index_range.rs b/library/core/src/ops/index_range.rs index 507fa9460bea6..84395ddadf2b7 100644 --- a/library/core/src/ops/index_range.rs +++ b/library/core/src/ops/index_range.rs @@ -9,7 +9,8 @@ use crate::ub_checks; /// /// (Normal `Range` code needs to handle degenerate ranges like `10..0`, /// which takes extra checks compared to only handling the canonical form.) -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Debug)] +#[derive_const(Clone, Eq, PartialEq)] pub(crate) struct IndexRange { start: usize, end: usize, @@ -54,7 +55,7 @@ impl IndexRange { /// # Safety /// - Can only be called when `start < end`, aka when `len > 0`. #[inline] - unsafe fn next_unchecked(&mut self) -> usize { + const unsafe fn next_unchecked(&mut self) -> usize { debug_assert!(self.start < self.end); let value = self.start; @@ -66,7 +67,7 @@ impl IndexRange { /// # Safety /// - Can only be called when `start < end`, aka when `len > 0`. #[inline] - unsafe fn next_back_unchecked(&mut self) -> usize { + const unsafe fn next_back_unchecked(&mut self) -> usize { debug_assert!(self.start < self.end); // SAFETY: The range isn't empty, so this cannot overflow @@ -116,7 +117,7 @@ impl IndexRange { } #[inline] - fn assume_range(&self) { + const fn assume_range(&self) { // SAFETY: This is the type invariant unsafe { crate::hint::assert_unchecked(self.start <= self.end) } } diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index 58a9431bd845d..d781f3f7ace4a 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -1,6 +1,6 @@ use crate::fmt; use crate::hash::Hash; - +use crate::marker::Destruct; /// An unbounded range (`..`). /// /// `RangeFull` is primarily used as a [slicing index], its shorthand is `..`. @@ -38,7 +38,8 @@ use crate::hash::Hash; /// [slicing index]: crate::slice::SliceIndex #[lang = "RangeFull"] #[doc(alias = "..")] -#[derive(Copy, Clone, Default, PartialEq, Eq, Hash)] +#[derive(Copy, Hash)] +#[derive_const(Clone, Default, Eq, PartialEq)] #[stable(feature = "rust1", since = "1.0.0")] pub struct RangeFull; @@ -75,7 +76,8 @@ impl fmt::Debug for RangeFull { /// ``` #[lang = "Range"] #[doc(alias = "..")] -#[derive(Clone, Default, PartialEq, Eq, Hash)] // not Copy -- see #27186 +#[derive(Eq, Hash)] +#[derive_const(Clone, Default, PartialEq)] // not Copy -- see #27186 #[stable(feature = "rust1", since = "1.0.0")] pub struct Range { /// The lower bound of the range (inclusive). @@ -117,10 +119,11 @@ impl> Range { /// ``` #[inline] #[stable(feature = "range_contains", since = "1.35.0")] - pub fn contains(&self, item: &U) -> bool + #[rustc_const_unstable(feature = "const_range", issue = "none")] + pub const fn contains(&self, item: &U) -> bool where - Idx: PartialOrd, - U: ?Sized + PartialOrd, + Idx: [const] PartialOrd, + U: ?Sized + [const] PartialOrd, { >::contains(self, item) } @@ -144,7 +147,11 @@ impl> Range { /// ``` #[inline] #[stable(feature = "range_is_empty", since = "1.47.0")] - pub fn is_empty(&self) -> bool { + #[rustc_const_unstable(feature = "const_range", issue = "none")] + pub const fn is_empty(&self) -> bool + where + Idx: [const] PartialOrd, + { !(self.start < self.end) } } @@ -184,7 +191,8 @@ impl> Range { /// ``` #[lang = "RangeFrom"] #[doc(alias = "..")] -#[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 +#[derive(Eq, Hash)] +#[derive_const(Clone, PartialEq)] // not Copy -- see #27186 #[stable(feature = "rust1", since = "1.0.0")] pub struct RangeFrom { /// The lower bound of the range (inclusive). @@ -217,10 +225,11 @@ impl> RangeFrom { /// ``` #[inline] #[stable(feature = "range_contains", since = "1.35.0")] - pub fn contains(&self, item: &U) -> bool + #[rustc_const_unstable(feature = "const_range", issue = "none")] + pub const fn contains(&self, item: &U) -> bool where - Idx: PartialOrd, - U: ?Sized + PartialOrd, + Idx: [const] PartialOrd, + U: ?Sized + [const] PartialOrd, { >::contains(self, item) } @@ -266,7 +275,8 @@ impl> RangeFrom { /// [slicing index]: crate::slice::SliceIndex #[lang = "RangeTo"] #[doc(alias = "..")] -#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Copy, Eq, Hash)] +#[derive_const(Clone, PartialEq)] #[stable(feature = "rust1", since = "1.0.0")] pub struct RangeTo { /// The upper bound of the range (exclusive). @@ -299,10 +309,11 @@ impl> RangeTo { /// ``` #[inline] #[stable(feature = "range_contains", since = "1.35.0")] - pub fn contains(&self, item: &U) -> bool + #[rustc_const_unstable(feature = "const_range", issue = "none")] + pub const fn contains(&self, item: &U) -> bool where - Idx: PartialOrd, - U: ?Sized + PartialOrd, + Idx: [const] PartialOrd, + U: ?Sized + [const] PartialOrd, { >::contains(self, item) } @@ -340,7 +351,8 @@ impl> RangeTo { /// ``` #[lang = "RangeInclusive"] #[doc(alias = "..=")] -#[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 +#[derive(Clone, Hash)] +#[derive_const(Eq, PartialEq)] // not Copy -- see #27186 #[stable(feature = "inclusive_range", since = "1.26.0")] pub struct RangeInclusive { // Note that the fields here are not public to allow changing the @@ -506,10 +518,11 @@ impl> RangeInclusive { /// ``` #[inline] #[stable(feature = "range_contains", since = "1.35.0")] - pub fn contains(&self, item: &U) -> bool + #[rustc_const_unstable(feature = "const_range", issue = "none")] + pub const fn contains(&self, item: &U) -> bool where - Idx: PartialOrd, - U: ?Sized + PartialOrd, + Idx: [const] PartialOrd, + U: ?Sized + [const] PartialOrd, { >::contains(self, item) } @@ -542,7 +555,11 @@ impl> RangeInclusive { /// ``` #[stable(feature = "range_is_empty", since = "1.47.0")] #[inline] - pub fn is_empty(&self) -> bool { + #[rustc_const_unstable(feature = "const_range", issue = "none")] + pub const fn is_empty(&self) -> bool + where + Idx: [const] PartialOrd, + { self.exhausted || !(self.start <= self.end) } } @@ -587,7 +604,8 @@ impl> RangeInclusive { /// [slicing index]: crate::slice::SliceIndex #[lang = "RangeToInclusive"] #[doc(alias = "..=")] -#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Copy, Hash)] +#[derive(Clone, PartialEq, Eq)] #[stable(feature = "inclusive_range", since = "1.26.0")] pub struct RangeToInclusive { /// The upper bound of the range (inclusive) @@ -620,10 +638,11 @@ impl> RangeToInclusive { /// ``` #[inline] #[stable(feature = "range_contains", since = "1.35.0")] - pub fn contains(&self, item: &U) -> bool + #[rustc_const_unstable(feature = "const_range", issue = "none")] + pub const fn contains(&self, item: &U) -> bool where - Idx: PartialOrd, - U: ?Sized + PartialOrd, + Idx: [const] PartialOrd, + U: ?Sized + [const] PartialOrd, { >::contains(self, item) } @@ -668,7 +687,8 @@ impl> RangeToInclusive { /// /// [`BTreeMap::range`]: ../../std/collections/btree_map/struct.BTreeMap.html#method.range #[stable(feature = "collections_bound", since = "1.17.0")] -#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] +#[derive(Copy, Debug, Hash)] +#[derive_const(Clone, Eq, PartialEq)] pub enum Bound { /// An inclusive bound. #[stable(feature = "collections_bound", since = "1.17.0")] @@ -685,7 +705,8 @@ impl Bound { /// Converts from `&Bound` to `Bound<&T>`. #[inline] #[stable(feature = "bound_as_ref_shared", since = "1.65.0")] - pub fn as_ref(&self) -> Bound<&T> { + #[rustc_const_unstable(feature = "const_range", issue = "none")] + pub const fn as_ref(&self) -> Bound<&T> { match *self { Included(ref x) => Included(x), Excluded(ref x) => Excluded(x), @@ -696,7 +717,7 @@ impl Bound { /// Converts from `&mut Bound` to `Bound<&mut T>`. #[inline] #[unstable(feature = "bound_as_ref", issue = "80996")] - pub fn as_mut(&mut self) -> Bound<&mut T> { + pub const fn as_mut(&mut self) -> Bound<&mut T> { match *self { Included(ref mut x) => Included(x), Excluded(ref mut x) => Excluded(x), @@ -778,7 +799,11 @@ impl Bound<&T> { /// ``` #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "bound_cloned", since = "1.55.0")] - pub fn cloned(self) -> Bound { + #[rustc_const_unstable(feature = "const_range", issue = "none")] + pub const fn cloned(self) -> Bound + where + T: [const] Clone, + { match self { Bound::Unbounded => Bound::Unbounded, Bound::Included(x) => Bound::Included(x.clone()), @@ -791,6 +816,8 @@ impl Bound<&T> { /// by range syntax like `..`, `a..`, `..b`, `..=c`, `d..e`, or `f..=g`. #[stable(feature = "collections_range", since = "1.28.0")] #[rustc_diagnostic_item = "RangeBounds"] +#[const_trait] +#[rustc_const_unstable(feature = "const_range", issue = "none")] pub trait RangeBounds { /// Start index bound. /// @@ -841,8 +868,8 @@ pub trait RangeBounds { #[stable(feature = "range_contains", since = "1.35.0")] fn contains(&self, item: &U) -> bool where - T: PartialOrd, - U: ?Sized + PartialOrd, + T: [const] PartialOrd, + U: ?Sized + [const] PartialOrd, { (match self.start_bound() { Included(start) => start <= item, @@ -909,7 +936,7 @@ pub trait RangeBounds { #[unstable(feature = "range_bounds_is_empty", issue = "137300")] fn is_empty(&self) -> bool where - T: PartialOrd, + T: [const] PartialOrd, { !match (self.start_bound(), self.end_bound()) { (Unbounded, _) | (_, Unbounded) => true, @@ -927,7 +954,9 @@ pub trait RangeBounds { /// `IntoBounds` is implemented by Rust’s built-in range types, produced /// by range syntax like `..`, `a..`, `..b`, `..=c`, `d..e`, or `f..=g`. #[unstable(feature = "range_into_bounds", issue = "136903")] -pub trait IntoBounds: RangeBounds { +#[const_trait] +#[rustc_const_unstable(feature = "const_range", issue = "none")] +pub trait IntoBounds: [const] RangeBounds { /// Convert this range into the start and end bounds. /// Returns `(start_bound, end_bound)`. /// @@ -973,8 +1002,8 @@ pub trait IntoBounds: RangeBounds { fn intersect(self, other: R) -> (Bound, Bound) where Self: Sized, - T: Ord, - R: Sized + IntoBounds, + T: [const] Ord + [const] Destruct, + R: Sized + [const] IntoBounds, { let (self_start, self_end) = IntoBounds::into_bounds(self); let (other_start, other_end) = IntoBounds::into_bounds(other); @@ -1017,7 +1046,8 @@ pub trait IntoBounds: RangeBounds { use self::Bound::{Excluded, Included, Unbounded}; #[stable(feature = "collections_range", since = "1.28.0")] -impl RangeBounds for RangeFull { +#[rustc_const_unstable(feature = "const_range", issue = "none")] +impl const RangeBounds for RangeFull { fn start_bound(&self) -> Bound<&T> { Unbounded } @@ -1027,14 +1057,16 @@ impl RangeBounds for RangeFull { } #[unstable(feature = "range_into_bounds", issue = "136903")] -impl IntoBounds for RangeFull { +#[rustc_const_unstable(feature = "const_range", issue = "none")] +impl const IntoBounds for RangeFull { fn into_bounds(self) -> (Bound, Bound) { (Unbounded, Unbounded) } } #[stable(feature = "collections_range", since = "1.28.0")] -impl RangeBounds for RangeFrom { +#[rustc_const_unstable(feature = "const_range", issue = "none")] +impl const RangeBounds for RangeFrom { fn start_bound(&self) -> Bound<&T> { Included(&self.start) } @@ -1044,14 +1076,16 @@ impl RangeBounds for RangeFrom { } #[unstable(feature = "range_into_bounds", issue = "136903")] -impl IntoBounds for RangeFrom { +#[rustc_const_unstable(feature = "const_range", issue = "none")] +impl const IntoBounds for RangeFrom { fn into_bounds(self) -> (Bound, Bound) { (Included(self.start), Unbounded) } } #[stable(feature = "collections_range", since = "1.28.0")] -impl RangeBounds for RangeTo { +#[rustc_const_unstable(feature = "const_range", issue = "none")] +impl const RangeBounds for RangeTo { fn start_bound(&self) -> Bound<&T> { Unbounded } @@ -1061,14 +1095,16 @@ impl RangeBounds for RangeTo { } #[unstable(feature = "range_into_bounds", issue = "136903")] -impl IntoBounds for RangeTo { +#[rustc_const_unstable(feature = "const_range", issue = "none")] +impl const IntoBounds for RangeTo { fn into_bounds(self) -> (Bound, Bound) { (Unbounded, Excluded(self.end)) } } #[stable(feature = "collections_range", since = "1.28.0")] -impl RangeBounds for Range { +#[rustc_const_unstable(feature = "const_range", issue = "none")] +impl const RangeBounds for Range { fn start_bound(&self) -> Bound<&T> { Included(&self.start) } @@ -1078,14 +1114,16 @@ impl RangeBounds for Range { } #[unstable(feature = "range_into_bounds", issue = "136903")] -impl IntoBounds for Range { +#[rustc_const_unstable(feature = "const_range", issue = "none")] +impl const IntoBounds for Range { fn into_bounds(self) -> (Bound, Bound) { (Included(self.start), Excluded(self.end)) } } #[stable(feature = "collections_range", since = "1.28.0")] -impl RangeBounds for RangeInclusive { +#[rustc_const_unstable(feature = "const_range", issue = "none")] +impl const RangeBounds for RangeInclusive { fn start_bound(&self) -> Bound<&T> { Included(&self.start) } @@ -1101,7 +1139,8 @@ impl RangeBounds for RangeInclusive { } #[unstable(feature = "range_into_bounds", issue = "136903")] -impl IntoBounds for RangeInclusive { +#[rustc_const_unstable(feature = "const_range", issue = "none")] +impl const IntoBounds for RangeInclusive { fn into_bounds(self) -> (Bound, Bound) { ( Included(self.start), @@ -1117,7 +1156,8 @@ impl IntoBounds for RangeInclusive { } #[stable(feature = "collections_range", since = "1.28.0")] -impl RangeBounds for RangeToInclusive { +#[rustc_const_unstable(feature = "const_range", issue = "none")] +impl const RangeBounds for RangeToInclusive { fn start_bound(&self) -> Bound<&T> { Unbounded } @@ -1127,14 +1167,16 @@ impl RangeBounds for RangeToInclusive { } #[unstable(feature = "range_into_bounds", issue = "136903")] -impl IntoBounds for RangeToInclusive { +#[rustc_const_unstable(feature = "const_range", issue = "none")] +impl const IntoBounds for RangeToInclusive { fn into_bounds(self) -> (Bound, Bound) { (Unbounded, Included(self.end)) } } #[stable(feature = "collections_range", since = "1.28.0")] -impl RangeBounds for (Bound, Bound) { +#[rustc_const_unstable(feature = "const_range", issue = "none")] +impl const RangeBounds for (Bound, Bound) { fn start_bound(&self) -> Bound<&T> { match *self { (Included(ref start), _) => Included(start), @@ -1153,14 +1195,16 @@ impl RangeBounds for (Bound, Bound) { } #[unstable(feature = "range_into_bounds", issue = "136903")] -impl IntoBounds for (Bound, Bound) { +#[rustc_const_unstable(feature = "const_range", issue = "none")] +impl const IntoBounds for (Bound, Bound) { fn into_bounds(self) -> (Bound, Bound) { self } } #[stable(feature = "collections_range", since = "1.28.0")] -impl<'a, T: ?Sized + 'a> RangeBounds for (Bound<&'a T>, Bound<&'a T>) { +#[rustc_const_unstable(feature = "const_range", issue = "none")] +impl<'a, T: ?Sized + 'a> const RangeBounds for (Bound<&'a T>, Bound<&'a T>) { fn start_bound(&self) -> Bound<&T> { self.0 } @@ -1177,7 +1221,8 @@ impl<'a, T: ?Sized + 'a> RangeBounds for (Bound<&'a T>, Bound<&'a T>) { /// consider using the `RangeBounds` impl for a 2-tuple of [`Bound<&T>`][Bound], /// i.e. replace `start..` with `(Bound::Included(start), Bound::Unbounded)`. #[stable(feature = "collections_range", since = "1.28.0")] -impl RangeBounds for RangeFrom<&T> { +#[rustc_const_unstable(feature = "const_range", issue = "none")] +impl const RangeBounds for RangeFrom<&T> { fn start_bound(&self) -> Bound<&T> { Included(self.start) } @@ -1193,7 +1238,8 @@ impl RangeBounds for RangeFrom<&T> { /// consider using the `RangeBounds` impl for a 2-tuple of [`Bound<&T>`][Bound], /// i.e. replace `..end` with `(Bound::Unbounded, Bound::Excluded(end))`. #[stable(feature = "collections_range", since = "1.28.0")] -impl RangeBounds for RangeTo<&T> { +#[rustc_const_unstable(feature = "const_range", issue = "none")] +impl const RangeBounds for RangeTo<&T> { fn start_bound(&self) -> Bound<&T> { Unbounded } @@ -1209,7 +1255,8 @@ impl RangeBounds for RangeTo<&T> { /// consider using the `RangeBounds` impl for a 2-tuple of [`Bound<&T>`][Bound], /// i.e. replace `start..end` with `(Bound::Included(start), Bound::Excluded(end))`. #[stable(feature = "collections_range", since = "1.28.0")] -impl RangeBounds for Range<&T> { +#[rustc_const_unstable(feature = "const_range", issue = "none")] +impl const RangeBounds for Range<&T> { fn start_bound(&self) -> Bound<&T> { Included(self.start) } @@ -1225,7 +1272,8 @@ impl RangeBounds for Range<&T> { /// consider using the `RangeBounds` impl for a 2-tuple of [`Bound<&T>`][Bound], /// i.e. replace `start..=end` with `(Bound::Included(start), Bound::Included(end))`. #[stable(feature = "collections_range", since = "1.28.0")] -impl RangeBounds for RangeInclusive<&T> { +#[rustc_const_unstable(feature = "const_range", issue = "none")] +impl const RangeBounds for RangeInclusive<&T> { fn start_bound(&self) -> Bound<&T> { Included(self.start) } @@ -1241,7 +1289,8 @@ impl RangeBounds for RangeInclusive<&T> { /// consider using the `RangeBounds` impl for a 2-tuple of [`Bound<&T>`][Bound], /// i.e. replace `..=end` with `(Bound::Unbounded, Bound::Included(end))`. #[stable(feature = "collections_range", since = "1.28.0")] -impl RangeBounds for RangeToInclusive<&T> { +#[rustc_const_unstable(feature = "const_range", issue = "none")] +impl const RangeBounds for RangeToInclusive<&T> { fn start_bound(&self) -> Bound<&T> { Unbounded } @@ -1270,6 +1319,8 @@ pub enum OneSidedRangeBound { /// Types that implement `OneSidedRange` must return `Bound::Unbounded` /// from one of `RangeBounds::start_bound` or `RangeBounds::end_bound`. #[unstable(feature = "one_sided_range", issue = "69780")] +#[const_trait] +#[rustc_const_unstable(feature = "const_range", issue = "none")] pub trait OneSidedRange: RangeBounds { /// An internal-only helper function for `split_off` and /// `split_off_mut` that returns the bound of the one-sided range. @@ -1277,7 +1328,8 @@ pub trait OneSidedRange: RangeBounds { } #[unstable(feature = "one_sided_range", issue = "69780")] -impl OneSidedRange for RangeTo +#[rustc_const_unstable(feature = "const_range", issue = "none")] +impl const OneSidedRange for RangeTo where Self: RangeBounds, { @@ -1287,7 +1339,8 @@ where } #[unstable(feature = "one_sided_range", issue = "69780")] -impl OneSidedRange for RangeFrom +#[rustc_const_unstable(feature = "const_range", issue = "none")] +impl const OneSidedRange for RangeFrom where Self: RangeBounds, { @@ -1297,7 +1350,8 @@ where } #[unstable(feature = "one_sided_range", issue = "69780")] -impl OneSidedRange for RangeToInclusive +#[rustc_const_unstable(feature = "const_range", issue = "none")] +impl const OneSidedRange for RangeToInclusive where Self: RangeBounds, { diff --git a/library/core/src/range.rs b/library/core/src/range.rs index a096a8ceafc87..96c56e96b3ebe 100644 --- a/library/core/src/range.rs +++ b/library/core/src/range.rs @@ -118,10 +118,11 @@ impl> Range { /// ``` #[inline] #[unstable(feature = "new_range_api", issue = "125687")] - pub fn contains(&self, item: &U) -> bool + #[rustc_const_unstable(feature = "const_range", issue = "none")] + pub const fn contains(&self, item: &U) -> bool where - Idx: PartialOrd, - U: ?Sized + PartialOrd, + Idx: [const] PartialOrd, + U: ?Sized + [const] PartialOrd, { >::contains(self, item) } @@ -151,13 +152,18 @@ impl> Range { /// ``` #[inline] #[unstable(feature = "new_range_api", issue = "125687")] - pub fn is_empty(&self) -> bool { + #[rustc_const_unstable(feature = "const_range", issue = "none")] + pub const fn is_empty(&self) -> bool + where + Idx: [const] PartialOrd, + { !(self.start < self.end) } } #[unstable(feature = "new_range_api", issue = "125687")] -impl RangeBounds for Range { +#[rustc_const_unstable(feature = "const_range", issue = "none")] +impl const RangeBounds for Range { fn start_bound(&self) -> Bound<&T> { Included(&self.start) } @@ -173,7 +179,8 @@ impl RangeBounds for Range { /// consider using the `RangeBounds` impl for a 2-tuple of [`Bound<&T>`][Bound], /// i.e. replace `start..end` with `(Bound::Included(start), Bound::Excluded(end))`. #[unstable(feature = "new_range_api", issue = "125687")] -impl RangeBounds for Range<&T> { +#[rustc_const_unstable(feature = "const_range", issue = "none")] +impl const RangeBounds for Range<&T> { fn start_bound(&self) -> Bound<&T> { Included(self.start) } @@ -184,7 +191,8 @@ impl RangeBounds for Range<&T> { // #[unstable(feature = "range_into_bounds", issue = "136903")] #[unstable(feature = "new_range_api", issue = "125687")] -impl IntoBounds for Range { +#[rustc_const_unstable(feature = "const_range", issue = "none")] +impl const IntoBounds for Range { fn into_bounds(self) -> (Bound, Bound) { (Included(self.start), Excluded(self.end)) } @@ -271,10 +279,11 @@ impl> RangeInclusive { /// ``` #[inline] #[unstable(feature = "new_range_api", issue = "125687")] - pub fn contains(&self, item: &U) -> bool + #[rustc_const_unstable(feature = "const_range", issue = "none")] + pub const fn contains(&self, item: &U) -> bool where - Idx: PartialOrd, - U: ?Sized + PartialOrd, + Idx: [const] PartialOrd, + U: ?Sized + [const] PartialOrd, { >::contains(self, item) } @@ -304,7 +313,11 @@ impl> RangeInclusive { /// ``` #[unstable(feature = "new_range_api", issue = "125687")] #[inline] - pub fn is_empty(&self) -> bool { + #[rustc_const_unstable(feature = "const_range", issue = "none")] + pub const fn is_empty(&self) -> bool + where + Idx: [const] PartialOrd, + { !(self.start <= self.last) } } @@ -342,7 +355,8 @@ impl RangeInclusive { } #[unstable(feature = "new_range_api", issue = "125687")] -impl RangeBounds for RangeInclusive { +#[rustc_const_unstable(feature = "const_range", issue = "none")] +impl const RangeBounds for RangeInclusive { fn start_bound(&self) -> Bound<&T> { Included(&self.start) } @@ -358,7 +372,8 @@ impl RangeBounds for RangeInclusive { /// consider using the `RangeBounds` impl for a 2-tuple of [`Bound<&T>`][Bound], /// i.e. replace `start..=end` with `(Bound::Included(start), Bound::Included(end))`. #[unstable(feature = "new_range_api", issue = "125687")] -impl RangeBounds for RangeInclusive<&T> { +#[rustc_const_unstable(feature = "const_range", issue = "none")] +impl const RangeBounds for RangeInclusive<&T> { fn start_bound(&self) -> Bound<&T> { Included(self.start) } @@ -369,7 +384,8 @@ impl RangeBounds for RangeInclusive<&T> { // #[unstable(feature = "range_into_bounds", issue = "136903")] #[unstable(feature = "new_range_api", issue = "125687")] -impl IntoBounds for RangeInclusive { +#[rustc_const_unstable(feature = "const_range", issue = "none")] +impl const IntoBounds for RangeInclusive { fn into_bounds(self) -> (Bound, Bound) { (Included(self.start), Included(self.last)) } @@ -485,17 +501,19 @@ impl> RangeFrom { /// ``` #[inline] #[unstable(feature = "new_range_api", issue = "125687")] - pub fn contains(&self, item: &U) -> bool + #[rustc_const_unstable(feature = "const_range", issue = "none")] + pub const fn contains(&self, item: &U) -> bool where - Idx: PartialOrd, - U: ?Sized + PartialOrd, + Idx: [const] PartialOrd, + U: ?Sized + [const] PartialOrd, { >::contains(self, item) } } #[unstable(feature = "new_range_api", issue = "125687")] -impl RangeBounds for RangeFrom { +#[rustc_const_unstable(feature = "const_range", issue = "none")] +impl const RangeBounds for RangeFrom { fn start_bound(&self) -> Bound<&T> { Included(&self.start) } @@ -511,7 +529,8 @@ impl RangeBounds for RangeFrom { /// consider using the `RangeBounds` impl for a 2-tuple of [`Bound<&T>`][Bound], /// i.e. replace `start..` with `(Bound::Included(start), Bound::Unbounded)`. #[unstable(feature = "new_range_api", issue = "125687")] -impl RangeBounds for RangeFrom<&T> { +#[rustc_const_unstable(feature = "const_range", issue = "none")] +impl const RangeBounds for RangeFrom<&T> { fn start_bound(&self) -> Bound<&T> { Included(self.start) } @@ -522,7 +541,8 @@ impl RangeBounds for RangeFrom<&T> { // #[unstable(feature = "range_into_bounds", issue = "136903")] #[unstable(feature = "new_range_api", issue = "125687")] -impl IntoBounds for RangeFrom { +#[rustc_const_unstable(feature = "const_range", issue = "none")] +impl const IntoBounds for RangeFrom { fn into_bounds(self) -> (Bound, Bound) { (Included(self.start), Unbounded) } @@ -620,10 +640,11 @@ impl> RangeToInclusive { /// ``` #[inline] #[unstable(feature = "new_range_api", issue = "125687")] - pub fn contains(&self, item: &U) -> bool + #[rustc_const_unstable(feature = "const_range", issue = "none")] + pub const fn contains(&self, item: &U) -> bool where - Idx: PartialOrd, - U: ?Sized + PartialOrd, + Idx: [const] PartialOrd, + U: ?Sized + [const] PartialOrd, { >::contains(self, item) } @@ -633,7 +654,8 @@ impl> RangeToInclusive { // because underflow would be possible with (..0).into() #[unstable(feature = "new_range_api", issue = "125687")] -impl RangeBounds for RangeToInclusive { +#[rustc_const_unstable(feature = "const_range", issue = "none")] +impl const RangeBounds for RangeToInclusive { fn start_bound(&self) -> Bound<&T> { Unbounded } @@ -643,7 +665,8 @@ impl RangeBounds for RangeToInclusive { } #[unstable(feature = "range_into_bounds", issue = "136903")] -impl IntoBounds for RangeToInclusive { +#[rustc_const_unstable(feature = "const_range", issue = "none")] +impl const IntoBounds for RangeToInclusive { fn into_bounds(self) -> (Bound, Bound) { (Unbounded, Included(self.last)) } diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index a9806060d3d81..aad046a7e5a94 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -1,6 +1,7 @@ //! Indexing implementations for `[T]`. use crate::intrinsics::slice_get_unchecked; +use crate::marker::Destruct; use crate::panic::const_panic; use crate::ub_checks::assert_unsafe_precondition; use crate::{ops, range}; @@ -899,9 +900,10 @@ unsafe impl const SliceIndex<[T]> for range::RangeToInclusive { #[track_caller] #[unstable(feature = "slice_range", issue = "76393")] #[must_use] -pub fn range(range: R, bounds: ops::RangeTo) -> ops::Range +#[rustc_const_unstable(feature = "const_range", issue = "none")] +pub const fn range(range: R, bounds: ops::RangeTo) -> ops::Range where - R: ops::RangeBounds, + R: [const] ops::RangeBounds + [const] Destruct, { let len = bounds.end; @@ -984,7 +986,7 @@ where /// Converts a pair of `ops::Bound`s into `ops::Range` without performing any /// bounds checking or (in debug) overflow checking. -pub(crate) fn into_range_unchecked( +pub(crate) const fn into_range_unchecked( len: usize, (start, end): (ops::Bound, ops::Bound), ) -> ops::Range { @@ -1004,7 +1006,8 @@ pub(crate) fn into_range_unchecked( /// Converts pair of `ops::Bound`s into `ops::Range`. /// Returns `None` on overflowing indices. -pub(crate) fn into_range( +#[rustc_const_unstable(feature = "const_range", issue = "none")] +pub(crate) const fn into_range( len: usize, (start, end): (ops::Bound, ops::Bound), ) -> Option> { From a7f08dec439f24f52de20b2e856c9ab8fb2ff89a Mon Sep 17 00:00:00 2001 From: joboet Date: Thu, 23 Oct 2025 14:25:31 +0200 Subject: [PATCH 3/8] std: don't leak the thread closure if destroying the thread attributes fails --- library/std/src/sys/thread/unix.rs | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/library/std/src/sys/thread/unix.rs b/library/std/src/sys/thread/unix.rs index 2a3e3a9715f80..9b26262bc80dc 100644 --- a/library/std/src/sys/thread/unix.rs +++ b/library/std/src/sys/thread/unix.rs @@ -7,7 +7,7 @@ target_os = "aix", )))] use crate::ffi::CStr; -use crate::mem::{self, ManuallyDrop}; +use crate::mem::{self, DropGuard, ManuallyDrop}; use crate::num::NonZero; #[cfg(all(target_os = "linux", target_env = "gnu"))] use crate::sys::weak::dlsym; @@ -52,10 +52,13 @@ impl Thread { name: Option<&str>, f: Box, ) -> io::Result { - let data = Box::into_raw(Box::new(ThreadData { name: name.map(Box::from), f })); - let mut native: libc::pthread_t = mem::zeroed(); + let data = Box::new(ThreadData { name: name.map(Box::from), f }); + let mut attr: mem::MaybeUninit = mem::MaybeUninit::uninit(); assert_eq!(libc::pthread_attr_init(attr.as_mut_ptr()), 0); + let mut attr = DropGuard::new(&mut attr, |attr| { + assert_eq!(libc::pthread_attr_destroy(attr.as_mut_ptr()), 0) + }); #[cfg(any(target_os = "espidf", target_os = "nuttx"))] if stack > 0 { @@ -90,8 +93,6 @@ impl Thread { // on the stack size, in which case we can only gracefully return // an error here. if libc::pthread_attr_setstacksize(attr.as_mut_ptr(), stack_size) != 0 { - assert_eq!(libc::pthread_attr_destroy(attr.as_mut_ptr()), 0); - drop(Box::from_raw(data)); return Err(io::const_error!( io::ErrorKind::InvalidInput, "invalid stack size" @@ -101,19 +102,16 @@ impl Thread { }; } + let data = Box::into_raw(data); + let mut native: libc::pthread_t = mem::zeroed(); let ret = libc::pthread_create(&mut native, attr.as_ptr(), thread_start, data as *mut _); - // Note: if the thread creation fails and this assert fails, then p will - // be leaked. However, an alternative design could cause double-free - // which is clearly worse. - assert_eq!(libc::pthread_attr_destroy(attr.as_mut_ptr()), 0); - - return if ret != 0 { - // The thread failed to start and as a result p was not consumed. Therefore, it is - // safe to reconstruct the box so that it gets deallocated. + return if ret == 0 { + Ok(Thread { id: native }) + } else { + // The thread failed to start and as a result `data` was not consumed. + // Therefore, it is safe to reconstruct the box so that it gets deallocated. drop(Box::from_raw(data)); Err(io::Error::from_raw_os_error(ret)) - } else { - Ok(Thread { id: native }) }; extern "C" fn thread_start(data: *mut libc::c_void) -> *mut libc::c_void { From ff138802a0a7bb5ef4dd96ab80407cfea20cca12 Mon Sep 17 00:00:00 2001 From: hax0kartik Date: Sun, 26 Oct 2025 15:45:24 +0530 Subject: [PATCH 4/8] Ignore unix socket related tests on VxWorks --- library/std/src/os/unix/net/tests.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/library/std/src/os/unix/net/tests.rs b/library/std/src/os/unix/net/tests.rs index 4666b5e3c6c18..d88c97113efeb 100644 --- a/library/std/src/os/unix/net/tests.rs +++ b/library/std/src/os/unix/net/tests.rs @@ -24,6 +24,7 @@ macro_rules! or_panic { #[test] #[cfg_attr(target_os = "android", ignore)] // Android SELinux rules prevent creating Unix sockets +#[cfg_attr(target_os = "vxworks", ignore = "Unix sockets are not implemented in VxWorks")] fn basic() { let dir = tmpdir(); let socket_path = dir.path().join("sock"); @@ -51,6 +52,7 @@ fn basic() { } #[test] +#[cfg_attr(target_os = "vxworks", ignore = "Unix sockets are not implemented in VxWorks")] fn vectored() { let (mut s1, mut s2) = or_panic!(UnixStream::pair()); @@ -71,6 +73,7 @@ fn vectored() { } #[test] +#[cfg_attr(target_os = "vxworks", ignore = "Unix sockets are not implemented in VxWorks")] fn pair() { let msg1 = b"hello"; let msg2 = b"world!"; @@ -95,6 +98,7 @@ fn pair() { #[test] #[cfg_attr(target_os = "android", ignore)] // Android SELinux rules prevent creating Unix sockets +#[cfg_attr(target_os = "vxworks", ignore = "Unix sockets are not implemented in VxWorks")] fn try_clone() { let dir = tmpdir(); let socket_path = dir.path().join("sock"); @@ -122,6 +126,7 @@ fn try_clone() { #[test] #[cfg_attr(target_os = "android", ignore)] // Android SELinux rules prevent creating Unix sockets +#[cfg_attr(target_os = "vxworks", ignore = "Unix sockets are not implemented in VxWorks")] fn iter() { let dir = tmpdir(); let socket_path = dir.path().join("sock"); @@ -144,6 +149,7 @@ fn iter() { } #[test] +#[cfg_attr(target_os = "vxworks", ignore = "Unix sockets are not implemented in VxWorks")] fn long_path() { let dir = tmpdir(); let socket_path = dir.path().join( @@ -173,6 +179,7 @@ fn long_path() { #[cfg(not(target_os = "nto"))] #[cfg_attr(target_os = "android", ignore)] // Android SELinux rules prevent creating Unix sockets #[cfg_attr(target_os = "cygwin", ignore)] // Cygwin connect needs handshake +#[cfg_attr(target_os = "vxworks", ignore = "Unix sockets are not implemented in VxWorks")] fn timeouts() { let dir = tmpdir(); let socket_path = dir.path().join("sock"); @@ -202,6 +209,7 @@ fn timeouts() { #[test] #[cfg_attr(target_os = "android", ignore)] // Android SELinux rules prevent creating Unix sockets #[cfg_attr(target_os = "cygwin", ignore)] // Cygwin connect needs handshake +#[cfg_attr(target_os = "vxworks", ignore = "Unix sockets are not implemented in VxWorks")] fn test_read_timeout() { let dir = tmpdir(); let socket_path = dir.path().join("sock"); @@ -223,6 +231,7 @@ fn test_read_timeout() { #[test] #[cfg_attr(target_os = "android", ignore)] // Android SELinux rules prevent creating Unix sockets #[cfg_attr(target_os = "cygwin", ignore)] // Cygwin connect needs handshake +#[cfg_attr(target_os = "vxworks", ignore = "Unix sockets are not implemented in VxWorks")] fn test_read_with_timeout() { let dir = tmpdir(); let socket_path = dir.path().join("sock"); @@ -252,6 +261,7 @@ fn test_read_with_timeout() { #[test] #[cfg_attr(target_os = "android", ignore)] // Android SELinux rules prevent creating Unix sockets #[cfg_attr(target_os = "cygwin", ignore)] // Cygwin connect needs handshake +#[cfg_attr(target_os = "vxworks", ignore = "Unix sockets are not implemented in VxWorks")] fn test_unix_stream_timeout_zero_duration() { let dir = tmpdir(); let socket_path = dir.path().join("sock"); @@ -272,6 +282,7 @@ fn test_unix_stream_timeout_zero_duration() { #[test] #[cfg_attr(target_os = "android", ignore)] // Android SELinux rules prevent creating Unix sockets +#[cfg_attr(target_os = "vxworks", ignore = "Unix sockets are not implemented in VxWorks")] fn test_unix_datagram() { let dir = tmpdir(); let path1 = dir.path().join("sock1"); @@ -290,6 +301,7 @@ fn test_unix_datagram() { #[test] #[cfg_attr(target_os = "android", ignore)] // Android SELinux rules prevent creating Unix sockets #[cfg_attr(target_os = "cygwin", ignore)] // Cygwin autobinds an address +#[cfg_attr(target_os = "vxworks", ignore = "Unix sockets are not implemented in VxWorks")] fn test_unnamed_unix_datagram() { let dir = tmpdir(); let path1 = dir.path().join("sock1"); @@ -308,6 +320,7 @@ fn test_unnamed_unix_datagram() { #[test] #[cfg_attr(target_os = "android", ignore)] // Android SELinux rules prevent creating Unix sockets +#[cfg_attr(target_os = "vxworks", ignore = "Unix sockets are not implemented in VxWorks")] fn test_unix_datagram_connect_to_recv_addr() { let dir = tmpdir(); let path1 = dir.path().join("sock1"); @@ -334,6 +347,7 @@ fn test_unix_datagram_connect_to_recv_addr() { #[test] #[cfg_attr(target_os = "android", ignore)] // Android SELinux rules prevent creating Unix sockets #[cfg_attr(target_os = "cygwin", ignore)] // Cygwin autobinds an address +#[cfg_attr(target_os = "vxworks", ignore = "Unix sockets are not implemented in VxWorks")] fn test_connect_unix_datagram() { let dir = tmpdir(); let path1 = dir.path().join("sock1"); @@ -361,6 +375,7 @@ fn test_connect_unix_datagram() { #[test] #[cfg_attr(target_os = "android", ignore)] // Android SELinux rules prevent creating Unix sockets +#[cfg_attr(target_os = "vxworks", ignore = "Unix sockets are not implemented in VxWorks")] fn test_unix_datagram_recv() { let dir = tmpdir(); let path1 = dir.path().join("sock1"); @@ -378,6 +393,7 @@ fn test_unix_datagram_recv() { } #[test] +#[cfg_attr(target_os = "vxworks", ignore = "Unix sockets are not implemented in VxWorks")] fn datagram_pair() { let msg1 = b"hello"; let msg2 = b"world!"; @@ -404,6 +420,7 @@ fn datagram_pair() { // when passed zero Durations #[test] #[cfg_attr(target_os = "android", ignore)] // Android SELinux rules prevent creating Unix sockets +#[cfg_attr(target_os = "vxworks", ignore = "Unix sockets are not implemented in VxWorks")] fn test_unix_datagram_timeout_zero_duration() { let dir = tmpdir(); let path = dir.path().join("sock"); @@ -562,6 +579,7 @@ fn test_abstract_no_pathname_and_not_unnamed() { #[test] #[cfg_attr(target_os = "android", ignore)] // Android SELinux rules prevent creating Unix sockets +#[cfg_attr(target_os = "vxworks", ignore = "Unix sockets are not implemented in VxWorks")] fn test_unix_stream_peek() { let (txdone, rxdone) = crate::sync::mpsc::channel(); @@ -595,6 +613,7 @@ fn test_unix_stream_peek() { #[test] #[cfg_attr(target_os = "android", ignore)] // Android SELinux rules prevent creating Unix sockets +#[cfg_attr(target_os = "vxworks", ignore = "Unix sockets are not implemented in VxWorks")] fn test_unix_datagram_peek() { let dir = tmpdir(); let path1 = dir.path().join("sock"); @@ -620,6 +639,7 @@ fn test_unix_datagram_peek() { #[test] #[cfg_attr(target_os = "android", ignore)] // Android SELinux rules prevent creating Unix sockets +#[cfg_attr(target_os = "vxworks", ignore = "Unix sockets are not implemented in VxWorks")] fn test_unix_datagram_peek_from() { let dir = tmpdir(); let path1 = dir.path().join("sock"); From 9e4ec2acc782dea54c71430b5de5281cc77eb4ad Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Tue, 28 Oct 2025 13:27:21 +0000 Subject: [PATCH 5/8] clippy fixes and code simplification --- .../src/fn_ctxt/adjust_fulfillment_errors.rs | 34 +++++++++--------- .../src/fn_ctxt/arg_matrix.rs | 36 +++++++------------ .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 21 ++++------- .../src/fn_ctxt/suggestions.rs | 12 +++---- .../rustc_hir_typeck/src/gather_locals.rs | 2 +- compiler/rustc_hir_typeck/src/loops.rs | 17 ++++----- compiler/rustc_index/src/bit_set.rs | 2 +- .../src/impossible_predicates.rs | 8 ++--- compiler/rustc_mir_transform/src/inline.rs | 2 +- 9 files changed, 55 insertions(+), 79 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs index 837328e379ca3..854202c312705 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs @@ -94,20 +94,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let find_param_matching = |matches: &dyn Fn(ParamTerm) -> bool| { predicate_args.iter().find_map(|arg| { - arg.walk().find_map(|arg| { - if let ty::GenericArgKind::Type(ty) = arg.kind() - && let ty::Param(param_ty) = *ty.kind() - && matches(ParamTerm::Ty(param_ty)) - { - Some(arg) - } else if let ty::GenericArgKind::Const(ct) = arg.kind() - && let ty::ConstKind::Param(param_ct) = ct.kind() - && matches(ParamTerm::Const(param_ct)) + arg.walk().find(|arg| match arg.kind() { + ty::GenericArgKind::Type(ty) if let ty::Param(param_ty) = ty.kind() => { + matches(ParamTerm::Ty(*param_ty)) + } + ty::GenericArgKind::Const(ct) + if let ty::ConstKind::Param(param_ct) = ct.kind() => { - Some(arg) - } else { - None + matches(ParamTerm::Const(param_ct)) } + _ => false, }) }) }; @@ -162,7 +158,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .into_iter() .flatten() { - if self.point_at_path_if_possible(error, def_id, param, &qpath) { + if self.point_at_path_if_possible(error, def_id, param, qpath) { return true; } } @@ -194,7 +190,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { args, ) => { if let Some(param) = predicate_self_type_to_point_at - && self.point_at_path_if_possible(error, callee_def_id, param, &qpath) + && self.point_at_path_if_possible(error, callee_def_id, param, qpath) { return true; } @@ -225,7 +221,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .into_iter() .flatten() { - if self.point_at_path_if_possible(error, callee_def_id, param, &qpath) { + if self.point_at_path_if_possible(error, callee_def_id, param, qpath) { return true; } } @@ -543,10 +539,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /// - `blame_specific_*` means that the function will recursively traverse the expression, - /// looking for the most-specific-possible span to blame. + /// looking for the most-specific-possible span to blame. /// /// - `point_at_*` means that the function will only go "one level", pointing at the specific - /// expression mentioned. + /// expression mentioned. /// /// `blame_specific_arg_if_possible` will find the most-specific expression anywhere inside /// the provided function call expression, and mark it as responsible for the fulfillment @@ -609,6 +605,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { * - want `Vec: Copy` * - because `Option>: Copy` needs `Vec: Copy` because `impl Copy for Option` * - because `(Option, bool)` needs `Option>: Copy` because `impl Copy for (A, B)` + * * then if you pass in `(Some(vec![1, 2, 3]), false)`, this helper `point_at_specific_expr_if_possible` * will find the expression `vec![1, 2, 3]` as the "most blameable" reason for this missing constraint. * @@ -749,6 +746,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// - expr: `(Some(vec![1, 2, 3]), false)` /// - param: `T` /// - in_ty: `(Option, bool)` + /// /// we would drill until we arrive at `vec![1, 2, 3]`. /// /// If successful, we return `Ok(refined_expr)`. If unsuccessful, we return `Err(partially_refined_expr`), @@ -1016,7 +1014,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .variant_with_id(variant_def_id) .fields .iter() - .map(|field| field.ty(self.tcx, *in_ty_adt_generic_args)) + .map(|field| field.ty(self.tcx, in_ty_adt_generic_args)) .enumerate() .filter(|(_index, field_type)| find_param_in_ty((*field_type).into(), param)), ) else { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs index f6298adf2ebb7..16f0a7dbc6f33 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs @@ -174,7 +174,7 @@ impl<'tcx> ArgMatrix<'tcx> { return Some(Issue::Missing(next_unmatched_idx)); } // If we eliminate the last column, any left-over inputs are extra - if mat[i].len() == 0 { + if mat[i].is_empty() { return Some(Issue::Extra(next_unmatched_idx)); } @@ -187,28 +187,18 @@ impl<'tcx> ArgMatrix<'tcx> { continue; } - let mut useless = true; - let mut unsatisfiable = true; - if is_arg { - for j in 0..ii.len() { - // If we find at least one input this argument could satisfy - // this argument isn't unsatisfiable - if matches!(mat[j][i], Compatibility::Compatible) { - unsatisfiable = false; - break; - } - } - } - if is_input { - for j in 0..ai.len() { - // If we find at least one argument that could satisfy this input - // this input isn't useless - if matches!(mat[i][j], Compatibility::Compatible) { - useless = false; - break; - } - } - } + // If this argument can satisfy some input, then this argument is satisfiable + let unsatisfiable = if is_arg { + !mat.iter().take(ii.len()).any(|c| matches!(c[i], Compatibility::Compatible)) + } else { + true + }; + // If this input can be satisfied by some argument, then this input is useful + let useless = if is_input { + !mat[i].iter().take(ai.len()).any(|c| matches!(c, Compatibility::Compatible)) + } else { + true + }; match (is_input, is_arg, useless, unsatisfiable) { // If an argument is unsatisfied, and the input in its position is useless diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 0cbdd86768a67..127f2c676391d 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -777,10 +777,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } _ => bug!("unexpected type: {:?}", ty.normalized), }, - Res::Def( - DefKind::Struct | DefKind::Union | DefKind::TyAlias { .. } | DefKind::AssocTy, - _, - ) + Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } => match ty.normalized.ty_adt_def() { Some(adt) if !adt.is_enum() => { @@ -868,7 +865,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let decl_ty = self.local_ty(decl.span, decl.hir_id); // Type check the initializer. - if let Some(ref init) = decl.init { + if let Some(init) = decl.init { let init_ty = self.check_decl_initializer(decl.hir_id, decl.pat, init); self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, init_ty); } @@ -932,7 +929,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // Ignore for now. hir::StmtKind::Item(_) => {} - hir::StmtKind::Expr(ref expr) => { + hir::StmtKind::Expr(expr) => { // Check with expected type of `()`. self.check_expr_has_type_or_error(expr, self.tcx.types.unit, |err| { if self.is_next_stmt_expr_continuation(stmt.hir_id) @@ -1766,10 +1763,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let params = params.get(is_method as usize..params.len() - sig.decl.c_variadic as usize)?; debug_assert_eq!(params.len(), fn_inputs.len()); - Some(( - fn_inputs.zip(params.iter().map(|param| FnParam::Param(param))).collect(), - generics, - )) + Some((fn_inputs.zip(params.iter().map(FnParam::Param)).collect(), generics)) } (None, Some(params)) => { let params = @@ -2632,7 +2626,7 @@ impl<'a, 'b, 'tcx> FnCallDiagCtxt<'a, 'b, 'tcx> { suggestions: Vec<(Span, String)>, suggestion_text: SuggestionText, ) -> Option { - let suggestion_text = match suggestion_text { + match suggestion_text { SuggestionText::None => None, SuggestionText::Provide(plural) => { Some(format!("provide the argument{}", if plural { "s" } else { "" })) @@ -2648,8 +2642,7 @@ impl<'a, 'b, 'tcx> FnCallDiagCtxt<'a, 'b, 'tcx> { SuggestionText::Swap => Some("swap these arguments".to_string()), SuggestionText::Reorder => Some("reorder these arguments".to_string()), SuggestionText::DidYouMean => Some("did you mean".to_string()), - }; - suggestion_text + } } fn arguments_formatting(&self, suggestion_span: Span) -> ArgumentsFormatting { @@ -2947,7 +2940,7 @@ impl<'a, 'b, 'tcx> ArgsCtxt<'a, 'b, 'tcx> { .fn_ctxt .typeck_results .borrow() - .expr_ty_adjusted_opt(*expr) + .expr_ty_adjusted_opt(expr) .unwrap_or_else(|| Ty::new_misc_error(self.call_ctxt.fn_ctxt.tcx)); ( self.call_ctxt.fn_ctxt.resolve_vars_if_possible(ty), diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 28bd3e7e8d5bb..1d16c3af7fb75 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1132,7 +1132,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) .collect::>(); - if all_matching_bounds_strs.len() == 0 { + if all_matching_bounds_strs.is_empty() { return; } @@ -1336,7 +1336,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected_ty = *inner_expected_ty; } (hir::ExprKind::Block(blk, _), _, _) => { - self.suggest_block_to_brackets(diag, *blk, expr_ty, expected_ty); + self.suggest_block_to_brackets(diag, blk, expr_ty, expected_ty); break true; } _ => break false, @@ -1463,7 +1463,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let span = expr .span - .find_ancestor_not_from_extern_macro(&self.tcx.sess.source_map()) + .find_ancestor_not_from_extern_macro(self.tcx.sess.source_map()) .unwrap_or(expr.span); let mut sugg = if self.precedence(expr) >= ExprPrecedence::Unambiguous { @@ -2144,7 +2144,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let span = expr .span - .find_ancestor_not_from_extern_macro(&self.tcx.sess.source_map()) + .find_ancestor_not_from_extern_macro(self.tcx.sess.source_map()) .unwrap_or(expr.span); err.span_suggestion_verbose(span.shrink_to_hi(), msg, sugg, Applicability::HasPlaceholders); true @@ -2257,7 +2257,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let src_map = tcx.sess.source_map(); let suggestion = if src_map.is_multiline(expr.span) { - let indentation = src_map.indentation_before(span).unwrap_or_else(String::new); + let indentation = src_map.indentation_before(span).unwrap_or_default(); format!("\n{indentation}/* {suggestion} */") } else { // If the entire expr is on a single line @@ -2289,7 +2289,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Check if `expr` is contained in array of two elements if let hir::Node::Expr(array_expr) = self.tcx.parent_hir_node(expr.hir_id) && let hir::ExprKind::Array(elements) = array_expr.kind - && let [first, second] = &elements[..] + && let [first, second] = elements && second.hir_id == expr.hir_id { // Span between the two elements of the array diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs index f1d6476a0f363..85c8400f227bd 100644 --- a/compiler/rustc_hir_typeck/src/gather_locals.rs +++ b/compiler/rustc_hir_typeck/src/gather_locals.rs @@ -135,7 +135,7 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> { /// again during type checking by querying [`FnCtxt::local_ty`] for the same hir_id. fn declare(&mut self, decl: Declaration<'tcx>) { let local_ty = match decl.ty { - Some(ref ty) => { + Some(ty) => { let o_ty = self.fcx.lower_ty(ty); let c_ty = self.fcx.infcx.canonicalize_user_type_annotation( diff --git a/compiler/rustc_hir_typeck/src/loops.rs b/compiler/rustc_hir_typeck/src/loops.rs index acfa5c473aacc..799e82ec13b80 100644 --- a/compiler/rustc_hir_typeck/src/loops.rs +++ b/compiler/rustc_hir_typeck/src/loops.rs @@ -147,7 +147,7 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> { } } } - hir::ExprKind::Loop(ref b, _, source, _) => { + hir::ExprKind::Loop(b, _, source, _) => { let cx = match self.is_loop_match(e, b) { Some(labeled_block) => LoopMatch { labeled_block }, None => Loop(source), @@ -155,9 +155,7 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> { self.with_context(cx, |v| v.visit_block(b)); } - hir::ExprKind::Closure(&hir::Closure { - ref fn_decl, body, fn_decl_span, kind, .. - }) => { + hir::ExprKind::Closure(&hir::Closure { fn_decl, body, fn_decl_span, kind, .. }) => { let cx = match kind { hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(kind, source)) => { Coroutine { coroutine_span: fn_decl_span, kind, source } @@ -167,16 +165,16 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> { self.visit_fn_decl(fn_decl); self.with_context(cx, |v| v.visit_nested_body(body)); } - hir::ExprKind::Block(ref b, Some(_label)) => { + hir::ExprKind::Block(b, Some(_label)) => { self.with_context(LabeledBlock, |v| v.visit_block(b)); } - hir::ExprKind::Block(ref b, None) + hir::ExprKind::Block(b, None) if matches!(self.cx_stack.last(), Some(&Fn) | Some(&ConstBlock)) => { self.with_context(Normal, |v| v.visit_block(b)); } hir::ExprKind::Block( - ref b @ hir::Block { rules: hir::BlockCheckMode::DefaultBlock, .. }, + b @ hir::Block { rules: hir::BlockCheckMode::DefaultBlock, .. }, None, ) if matches!( self.cx_stack.last(), @@ -431,10 +429,7 @@ impl<'hir> CheckLoopVisitor<'hir> { // Accept either `state = expr` or `state = expr;`. let loop_body_expr = match body.stmts { - [] => match body.expr { - Some(expr) => expr, - None => return None, - }, + [] => body.expr?, [single] if body.expr.is_none() => match single.kind { hir::StmtKind::Expr(expr) | hir::StmtKind::Semi(expr) => expr, _ => return None, diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index 96e85fdb10a6e..a9bdf597e128f 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -1409,7 +1409,7 @@ impl BitMatrix { BitMatrix { num_rows, num_columns, - words: iter::repeat(&row.words).take(num_rows).flatten().cloned().collect(), + words: iter::repeat_n(&row.words, num_rows).flatten().cloned().collect(), marker: PhantomData, } } diff --git a/compiler/rustc_mir_transform/src/impossible_predicates.rs b/compiler/rustc_mir_transform/src/impossible_predicates.rs index 883ee32bdec91..71e4d5581ddc2 100644 --- a/compiler/rustc_mir_transform/src/impossible_predicates.rs +++ b/compiler/rustc_mir_transform/src/impossible_predicates.rs @@ -20,11 +20,11 @@ //! parameters, so this filtering serves two purposes: //! //! 1. We skip evaluating any predicates that we would -//! never be able prove are unsatisfiable (e.g. `` +//! never be able prove are unsatisfiable (e.g. `` //! 2. We avoid trying to normalize predicates involving generic -//! parameters (e.g. `::MyItem`). This can confuse -//! the normalization code (leading to cycle errors), since -//! it's usually never invoked in this way. +//! parameters (e.g. `::MyItem`). This can confuse +//! the normalization code (leading to cycle errors), since +//! it's usually never invoked in this way. use rustc_middle::mir::{Body, START_BLOCK, TerminatorKind}; use rustc_middle::ty::{TyCtxt, TypeFlags, TypeVisitableExt}; diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index dc6088849bf5e..7e1dd76f903d4 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -635,7 +635,7 @@ fn try_inlining<'tcx, I: Inliner<'tcx>>( // Normally, this shouldn't be required, but trait normalization failure can create a // validation ICE. - if !validate_types(tcx, inliner.typing_env(), &callee_body, &caller_body).is_empty() { + if !validate_types(tcx, inliner.typing_env(), &callee_body, caller_body).is_empty() { debug!("failed to validate callee body"); return Err("implementation limitation -- callee body failed validation"); } From d3473f0741a8b5c8a60b5f54a6b0a898bec27d29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sun, 2 Nov 2025 11:03:31 +0100 Subject: [PATCH 6/8] Generalize branch references to HEAD --- .github/ISSUE_TEMPLATE/tracking_issue.md | 2 +- .github/workflows/ci.yml | 2 +- .github/workflows/post-merge.yml | 2 +- compiler/rustc_codegen_llvm/src/llvm_util.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 2 +- library/core/src/intrinsics/mod.rs | 10 ++-- src/bootstrap/src/lib.rs | 2 +- src/ci/github-actions/jobs.yml | 2 +- src/ci/run.sh | 2 +- .../src/appendix/code-index.md | 2 +- .../rustc-dev-guide/src/appendix/humorust.md | 2 +- src/doc/rustc-dev-guide/src/attributes.md | 2 +- .../src/backend/updating-llvm.md | 2 +- .../src/borrow_check/region_inference.md | 2 +- .../bootstrapping/how-bootstrap-does-it.md | 10 ++-- .../bootstrapping/what-bootstrapping-does.md | 10 ++-- .../src/building/prerequisites.md | 2 +- .../rustc-dev-guide/src/building/suggested.md | 12 ++-- .../rustc-dev-guide/src/compiler-debugging.md | 4 +- src/doc/rustc-dev-guide/src/compiler-src.md | 58 +++++++++---------- src/doc/rustc-dev-guide/src/compiler-team.md | 2 +- .../src/const-eval/interpret.md | 6 +- src/doc/rustc-dev-guide/src/contributing.md | 6 +- src/doc/rustc-dev-guide/src/external-repos.md | 2 +- .../rustc-dev-guide/src/getting-started.md | 2 +- src/doc/rustc-dev-guide/src/git.md | 2 +- .../rustc-dev-guide/src/guides/editions.md | 4 +- .../rustc-dev-guide/src/incrcomp-debugging.md | 2 +- src/doc/rustc-dev-guide/src/licenses.md | 4 +- .../src/llvm-coverage-instrumentation.md | 10 ++-- .../rustc-dev-guide/src/macro-expansion.md | 2 +- .../src/mir/drop-elaboration.md | 6 +- .../rustc-dev-guide/src/mir/optimizations.md | 4 +- .../src/notification-groups/about.md | 2 +- src/doc/rustc-dev-guide/src/overview.md | 10 ++-- .../src/panic-implementation.md | 2 +- .../src/profile-guided-optimization.md | 4 +- .../rustc-dev-guide/src/rustdoc-internals.md | 22 +++---- .../rustdoc-gui-test-suite.md | 2 +- .../rustdoc-json-test-suite.md | 6 +- .../rustdoc-internals/rustdoc-test-suite.md | 2 +- .../src/rustdoc-internals/search.md | 2 +- src/doc/rustc-dev-guide/src/rustdoc.md | 4 +- src/doc/rustc-dev-guide/src/sanitizers.md | 4 +- src/doc/rustc-dev-guide/src/serialization.md | 4 +- .../rustc-dev-guide/src/solve/opaque-types.md | 2 +- .../src/solve/significant-changes.md | 2 +- .../src/stabilization_guide.md | 8 +-- .../src/test-implementation.md | 2 +- src/doc/rustc-dev-guide/src/tests/adding.md | 2 +- src/doc/rustc-dev-guide/src/tests/ci.md | 10 ++-- .../rustc-dev-guide/src/tests/compiletest.md | 32 +++++----- .../rustc-dev-guide/src/tests/directives.md | 10 ++-- src/doc/rustc-dev-guide/src/tests/docker.md | 8 +-- src/doc/rustc-dev-guide/src/tests/intro.md | 8 +-- src/doc/rustc-dev-guide/src/tests/minicore.md | 2 +- src/doc/rustc-dev-guide/src/tests/running.md | 12 ++-- src/doc/rustc-dev-guide/src/tests/ui.md | 10 ++-- src/doc/rustc-dev-guide/src/tracing.md | 2 +- src/doc/rustc-dev-guide/src/traits/chalk.md | 2 +- .../src/traits/goals-and-clauses.md | 2 +- src/doc/rustc-dev-guide/src/ty-fold.md | 2 +- .../rustc-dev-guide/src/unsafety-checking.md | 2 +- src/doc/rustc-dev-guide/src/walkthrough.md | 2 +- src/doc/rustc/book.toml | 4 +- src/doc/rustc/src/codegen-options/index.md | 2 +- src/doc/rustc/src/contributing.md | 2 +- src/doc/rustc/src/exploit-mitigations.md | 2 +- .../armeb-unknown-linux-gnueabi.md | 2 +- src/doc/rustc/src/target-tier-policy.md | 6 +- src/doc/rustdoc/book.toml | 2 +- .../write-documentation/what-to-include.md | 2 +- src/doc/unstable-book/book.toml | 4 +- .../src/compiler-flags/codegen-backend.md | 2 +- .../src/language-features/lang-items.md | 4 +- src/etc/lldb_providers.py | 2 +- src/etc/natvis/libstd.natvis | 4 +- src/librustdoc/lib.rs | 4 +- .../rustc-std-workspace-alloc/Cargo.toml | 2 +- .../rustc-std-workspace-core/Cargo.toml | 2 +- .../rustc-std-workspace-std/Cargo.toml | 2 +- .../infrastructure/changelog_update.md | 2 +- .../src/disallowed_script_idents.rs | 2 +- src/tools/clippy/src/driver.rs | 4 +- src/tools/miri/src/shims/io_error.rs | 4 +- src/tools/nix-dev-shell/x/default.nix | 2 +- .../macro_expansion_tests/mbe/meta_syntax.rs | 2 +- .../crates/ide-db/src/generated/lints.rs | 4 +- .../docs/book/src/non_cargo_based_projects.md | 2 +- src/tools/rustfmt/Configurations.md | 2 +- src/tools/rustfmt/Contributing.md | 2 +- src/tools/rustfmt/src/closures.rs | 2 +- 92 files changed, 222 insertions(+), 222 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/tracking_issue.md b/.github/ISSUE_TEMPLATE/tracking_issue.md index aedc15a54c274..6def803b269e9 100644 --- a/.github/ISSUE_TEMPLATE/tracking_issue.md +++ b/.github/ISSUE_TEMPLATE/tracking_issue.md @@ -50,7 +50,7 @@ for larger features an implementation could be broken up into multiple PRs. [stabilization-guide]: https://rustc-dev-guide.rust-lang.org/stabilization_guide.html#stabilization-pr [doc-guide]: https://rustc-dev-guide.rust-lang.org/stabilization_guide.html#documentation-prs [nightly-style-procedure]: https://github.com/rust-lang/style-team/blob/main/nightly-style-procedure.md -[Style Guide]: https://github.com/rust-lang/rust/tree/master/src/doc/style-guide +[Style Guide]: https://github.com/rust-lang/rust/tree/HEAD/src/doc/style-guide ### Unresolved Questions $DIR/missing-param-but-has-colon-144215.rs:4:14 + | +LL | struct S(&'static T); + | ^^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the reference type `&'static T` does not outlive the data it points at + | +help: consider adding an explicit lifetime bound + | +LL | struct S(&'static T); + | +++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0310`.