From d404c58aa88b12a9c8180878e6e78f0500a18974 Mon Sep 17 00:00:00 2001 From: Peter Jaszkowiak Date: Mon, 2 Mar 2026 21:01:30 -0700 Subject: [PATCH] stabilize new RangeFrom type and iterator stabilizes `core::range::RangeFrom` stabilizes `core::range::RangeFromIter` add examples for `remainder` method on range iterators --- library/core/src/ffi/c_str.rs | 2 +- library/core/src/range.rs | 41 ++++++++---------- library/core/src/range/iter.rs | 42 ++++++++++++++++--- library/core/src/slice/index.rs | 4 +- library/core/src/str/traits.rs | 2 +- .../fromrangeiter-overflow-checks.rs | 1 - tests/ui/iterators/fromrangeiter.rs | 2 - .../ui/iterators/rangefrom-overflow-debug.rs | 2 - .../ui/iterators/rangefrom-overflow-ndebug.rs | 2 - .../rangefrom-overflow-overflow-checks.rs | 2 - tests/ui/range/new_range_stability.rs | 22 ++++++++-- tests/ui/range/new_range_stability.stderr | 28 ++----------- 12 files changed, 82 insertions(+), 68 deletions(-) diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 5fc97d9a69efd..62b3d75d7a779 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -716,7 +716,7 @@ impl ops::Index> for CStr { } } -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")] impl ops::Index> for CStr { type Output = CStr; diff --git a/library/core/src/range.rs b/library/core/src/range.rs index 3c2c40d492005..2007533e68e54 100644 --- a/library/core/src/range.rs +++ b/library/core/src/range.rs @@ -24,12 +24,15 @@ mod iter; #[unstable(feature = "new_range_api", issue = "125687")] pub mod legacy; +#[doc(inline)] +#[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")] +pub use iter::RangeFromIter; #[doc(inline)] #[stable(feature = "new_range_inclusive_api", since = "1.95.0")] pub use iter::RangeInclusiveIter; #[doc(inline)] #[unstable(feature = "new_range_api", issue = "125687")] -pub use iter::{RangeFromIter, RangeIter}; +pub use iter::RangeIter; // FIXME(#125687): re-exports temporarily removed // Because re-exports of stable items (Bound, RangeBounds, RangeFull, RangeTo) @@ -416,14 +419,13 @@ impl const From> for RangeInclusive { /// /// The `RangeFrom` `start..` contains all values with `x >= start`. /// -/// *Note*: Overflow in the [`Iterator`] implementation (when the contained +/// *Note*: Overflow in the [`IntoIterator`] implementation (when the contained /// data type reaches its numerical limit) is allowed to panic, wrap, or /// saturate. This behavior is defined by the implementation of the [`Step`] /// trait. For primitive integers, this follows the normal rules, and respects -/// the overflow checks profile (panic in debug, wrap in release). Note also -/// that overflow happens earlier than you might assume: the overflow happens -/// in the call to `next` that yields the maximum value, as the range must be -/// set to a state to yield the next value. +/// the overflow checks profile (panic in debug, wrap in release). Unlike +/// its legacy counterpart, the iterator will only panic after yielding the +/// maximum value when overflow checks are enabled. /// /// [`Step`]: crate::iter::Step /// @@ -432,7 +434,6 @@ impl const From> for RangeInclusive { /// The `start..` syntax is a `RangeFrom`: /// /// ``` -/// #![feature(new_range_api)] /// use core::range::RangeFrom; /// /// assert_eq!(RangeFrom::from(2..), core::range::RangeFrom { start: 2 }); @@ -441,14 +442,14 @@ impl const From> for RangeInclusive { #[lang = "RangeFromCopy"] #[derive(Copy, Hash)] #[derive_const(Clone, PartialEq, Eq)] -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")] pub struct RangeFrom { /// The lower bound of the range (inclusive). - #[unstable(feature = "new_range_api", issue = "125687")] + #[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")] pub start: Idx, } -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")] impl fmt::Debug for RangeFrom { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { self.start.fmt(fmt)?; @@ -465,7 +466,6 @@ impl RangeFrom { /// # Examples /// /// ``` - /// #![feature(new_range_api)] /// use core::range::RangeFrom; /// /// let mut i = RangeFrom::from(3..).iter().map(|n| n*n); @@ -473,7 +473,7 @@ impl RangeFrom { /// assert_eq!(i.next(), Some(16)); /// assert_eq!(i.next(), Some(25)); /// ``` - #[unstable(feature = "new_range_api", issue = "125687")] + #[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")] #[inline] pub fn iter(&self) -> RangeFromIter { self.clone().into_iter() @@ -486,7 +486,6 @@ impl> RangeFrom { /// # Examples /// /// ``` - /// #![feature(new_range_api)] /// use core::range::RangeFrom; /// /// assert!(!RangeFrom::from(3..).contains(&2)); @@ -498,7 +497,7 @@ impl> RangeFrom { /// assert!(!RangeFrom::from(f32::NAN..).contains(&0.5)); /// ``` #[inline] - #[unstable(feature = "new_range_api", issue = "125687")] + #[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_range", issue = "none")] pub const fn contains(&self, item: &U) -> bool where @@ -509,7 +508,7 @@ impl> RangeFrom { } } -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_range", issue = "none")] impl const RangeBounds for RangeFrom { fn start_bound(&self) -> Bound<&T> { @@ -526,7 +525,7 @@ impl const RangeBounds for RangeFrom { /// If you need to use this implementation where `T` is unsized, /// 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")] +#[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_range", issue = "none")] impl const RangeBounds for RangeFrom<&T> { fn start_bound(&self) -> Bound<&T> { @@ -537,8 +536,7 @@ impl const RangeBounds for RangeFrom<&T> { } } -// #[unstable(feature = "range_into_bounds", issue = "136903")] -#[unstable(feature = "new_range_api", issue = "125687")] +#[unstable(feature = "range_into_bounds", issue = "136903")] #[rustc_const_unstable(feature = "const_range", issue = "none")] impl const IntoBounds for RangeFrom { fn into_bounds(self) -> (Bound, Bound) { @@ -547,7 +545,6 @@ impl const IntoBounds for RangeFrom { } #[unstable(feature = "one_sided_range", issue = "69780")] -// #[unstable(feature = "new_range_api", issue = "125687")] #[rustc_const_unstable(feature = "const_range", issue = "none")] impl const OneSidedRange for RangeFrom where @@ -558,7 +555,7 @@ where } } -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_index", issue = "143775")] impl const From> for legacy::RangeFrom { #[inline] @@ -566,7 +563,7 @@ impl const From> for legacy::RangeFrom { Self { start: value.start } } } -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_index", issue = "143775")] impl const From> for RangeFrom { #[inline] @@ -697,7 +694,6 @@ impl const RangeBounds for RangeToInclusive<&T> { } } -// #[stable(feature = "new_range_to_inclusive_api", since = "CURRENT_RUSTC_VERSION")] #[unstable(feature = "range_into_bounds", issue = "136903")] #[rustc_const_unstable(feature = "const_range", issue = "none")] impl const IntoBounds for RangeToInclusive { @@ -706,7 +702,6 @@ impl const IntoBounds for RangeToInclusive { } } -// #[stable(feature = "new_range_to_inclusive_api", since = "CURRENT_RUSTC_VERSION")] #[unstable(feature = "one_sided_range", issue = "69780")] #[rustc_const_unstable(feature = "const_range", issue = "none")] impl const OneSidedRange for RangeToInclusive diff --git a/library/core/src/range/iter.rs b/library/core/src/range/iter.rs index c1d4fbbd23ad4..4d75c4683b1c9 100644 --- a/library/core/src/range/iter.rs +++ b/library/core/src/range/iter.rs @@ -13,6 +13,18 @@ pub struct RangeIter(legacy::Range); impl RangeIter { #[unstable(feature = "new_range_api", issue = "125687")] /// Returns the remainder of the range being iterated over. + /// + /// # Examples + /// ``` + /// #![feature(new_range_api)] + /// let range = core::range::Range::from(3..11); + /// let mut iter = range.into_iter(); + /// assert_eq!(iter.clone().remainder(), range); + /// iter.next(); + /// assert_eq!(iter.clone().remainder(), core::range::Range::from(4..11)); + /// iter.by_ref().for_each(drop); + /// assert!(iter.remainder().is_empty()); + /// ``` pub fn remainder(self) -> Range { Range { start: self.0.start, end: self.0.end } } @@ -161,6 +173,17 @@ impl RangeInclusiveIter { /// Returns the remainder of the range being iterated over. /// /// If the iterator is exhausted or empty, returns `None`. + /// + /// # Examples + /// ``` + /// let range = core::range::RangeInclusive::from(3..=11); + /// let mut iter = range.into_iter(); + /// assert_eq!(iter.clone().remainder().unwrap(), range); + /// iter.next(); + /// assert_eq!(iter.clone().remainder().unwrap(), core::range::RangeInclusive::from(4..=11)); + /// iter.by_ref().for_each(drop); + /// assert!(iter.remainder().is_none()); + /// ``` #[stable(feature = "new_range_inclusive_api", since = "1.95.0")] pub fn remainder(self) -> Option> { if self.0.is_empty() { @@ -294,7 +317,7 @@ range_incl_exact_iter_impl! { } /// By-value [`RangeFrom`] iterator. -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")] #[derive(Debug, Clone)] pub struct RangeFromIter { start: A, @@ -305,9 +328,18 @@ pub struct RangeFromIter { impl RangeFromIter { /// Returns the remainder of the range being iterated over. + /// + /// # Examples + /// ``` + /// let range = core::range::RangeFrom::from(3..); + /// let mut iter = range.into_iter(); + /// assert_eq!(iter.clone().remainder(), range); + /// iter.next(); + /// assert_eq!(iter.remainder(), core::range::RangeFrom::from(4..)); + /// ``` #[inline] #[rustc_inherit_overflow_checks] - #[unstable(feature = "new_range_api", issue = "125687")] + #[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")] pub fn remainder(self) -> RangeFrom { if intrinsics::overflow_checks() { if !self.first { @@ -319,7 +351,7 @@ impl RangeFromIter { } } -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")] impl Iterator for RangeFromIter { type Item = A; @@ -371,10 +403,10 @@ impl Iterator for RangeFromIter { #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl TrustedLen for RangeFromIter {} -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")] impl FusedIterator for RangeFromIter {} -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")] impl IntoIterator for RangeFrom { type Item = A; type IntoIter = RangeFromIter; diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index 1709bc7c09843..b30f82a5783ad 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -131,7 +131,7 @@ mod private_slice_index { impl Sealed for range::RangeInclusive {} #[stable(feature = "new_range_to_inclusive_api", since = "CURRENT_RUSTC_VERSION")] impl Sealed for range::RangeToInclusive {} - #[unstable(feature = "new_range_api", issue = "125687")] + #[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")] impl Sealed for range::RangeFrom {} impl Sealed for ops::IndexRange {} @@ -588,7 +588,7 @@ unsafe impl const SliceIndex<[T]> for ops::RangeFrom { } } -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_index", issue = "143775")] unsafe impl const SliceIndex<[T]> for range::RangeFrom { type Output = [T]; diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs index 88a8a9764cbc5..336f074883d25 100644 --- a/library/core/src/str/traits.rs +++ b/library/core/src/str/traits.rs @@ -555,7 +555,7 @@ unsafe impl const SliceIndex for ops::RangeFrom { } } -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_index", issue = "143775")] unsafe impl const SliceIndex for range::RangeFrom { type Output = str; diff --git a/tests/codegen-llvm/fromrangeiter-overflow-checks.rs b/tests/codegen-llvm/fromrangeiter-overflow-checks.rs index 4d27f118ddd37..ec2d6d0c3164f 100644 --- a/tests/codegen-llvm/fromrangeiter-overflow-checks.rs +++ b/tests/codegen-llvm/fromrangeiter-overflow-checks.rs @@ -10,7 +10,6 @@ //@ [NOCHECKS] compile-flags: -Coverflow-checks=no #![crate_type = "lib"] -#![feature(new_range_api)] use std::range::{RangeFrom, RangeFromIter}; // CHECK-LABEL: @iterrangefrom_remainder( diff --git a/tests/ui/iterators/fromrangeiter.rs b/tests/ui/iterators/fromrangeiter.rs index 54d8f522a2c88..c672f1348437c 100644 --- a/tests/ui/iterators/fromrangeiter.rs +++ b/tests/ui/iterators/fromrangeiter.rs @@ -1,8 +1,6 @@ //@ run-pass //@ compile-flags: -C overflow-checks=yes -#![feature(new_range_api)] - use std::{iter, range}; fn main() { diff --git a/tests/ui/iterators/rangefrom-overflow-debug.rs b/tests/ui/iterators/rangefrom-overflow-debug.rs index 9a1bc6910a044..83cb07e9fa12b 100644 --- a/tests/ui/iterators/rangefrom-overflow-debug.rs +++ b/tests/ui/iterators/rangefrom-overflow-debug.rs @@ -2,8 +2,6 @@ //@ needs-unwind //@ compile-flags: -O -C debug_assertions=yes -#![feature(new_range_api)] - use std::panic; fn main() { diff --git a/tests/ui/iterators/rangefrom-overflow-ndebug.rs b/tests/ui/iterators/rangefrom-overflow-ndebug.rs index 4ce9b0636383c..e7059a4010ca7 100644 --- a/tests/ui/iterators/rangefrom-overflow-ndebug.rs +++ b/tests/ui/iterators/rangefrom-overflow-ndebug.rs @@ -1,8 +1,6 @@ //@ run-pass //@ compile-flags: -O -C debug_assertions=no -#![feature(new_range_api)] - fn main() { let mut it = core::range::RangeFrom::from(u8::MAX..).into_iter(); assert_eq!(it.next().unwrap(), 255); diff --git a/tests/ui/iterators/rangefrom-overflow-overflow-checks.rs b/tests/ui/iterators/rangefrom-overflow-overflow-checks.rs index 7e3b0fc308405..13c4fe56ccf03 100644 --- a/tests/ui/iterators/rangefrom-overflow-overflow-checks.rs +++ b/tests/ui/iterators/rangefrom-overflow-overflow-checks.rs @@ -2,8 +2,6 @@ //@ needs-unwind //@ compile-flags: -O -C overflow-checks=yes -#![feature(new_range_api)] - use std::panic; fn main() { diff --git a/tests/ui/range/new_range_stability.rs b/tests/ui/range/new_range_stability.rs index 2d129fb6815f5..a160e469281fe 100644 --- a/tests/ui/range/new_range_stability.rs +++ b/tests/ui/range/new_range_stability.rs @@ -1,6 +1,12 @@ // Stable -use std::range::{RangeInclusive, RangeInclusiveIter, RangeToInclusive}; +use std::range::{ + RangeInclusive, + RangeInclusiveIter, + RangeToInclusive, + RangeFrom, + RangeFromIter, +}; fn range_inclusive(mut r: RangeInclusive) { &[1, 2, 3][r]; // Indexing @@ -23,15 +29,25 @@ fn range_to_inclusive(mut r: RangeToInclusive) { r.contains(&5); } +fn range_from(mut r: RangeFrom) { + &[1, 2, 3][r]; // Indexing + + r.start; + r.contains(&5); + r.iter(); + + let mut i = r.into_iter(); + i.next(); + i.remainder(); +} + // Unstable module use std::range::legacy; //~ ERROR unstable // Unstable types -use std::range::RangeFrom; //~ ERROR unstable use std::range::Range; //~ ERROR unstable -use std::range::RangeFromIter; //~ ERROR unstable use std::range::RangeIter; //~ ERROR unstable fn main() {} diff --git a/tests/ui/range/new_range_stability.stderr b/tests/ui/range/new_range_stability.stderr index b5a7e06e5f2ea..ca87f5884d5ce 100644 --- a/tests/ui/range/new_range_stability.stderr +++ b/tests/ui/range/new_range_stability.stderr @@ -1,5 +1,5 @@ error[E0658]: use of unstable library feature `new_range_api` - --> $DIR/new_range_stability.rs:28:5 + --> $DIR/new_range_stability.rs:46:5 | LL | use std::range::legacy; | ^^^^^^^^^^^^^^^^^^ @@ -9,17 +9,7 @@ LL | use std::range::legacy; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: use of unstable library feature `new_range_api` - --> $DIR/new_range_stability.rs:32:5 - | -LL | use std::range::RangeFrom; - | ^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #125687 for more information - = help: add `#![feature(new_range_api)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: use of unstable library feature `new_range_api` - --> $DIR/new_range_stability.rs:33:5 + --> $DIR/new_range_stability.rs:50:5 | LL | use std::range::Range; | ^^^^^^^^^^^^^^^^^ @@ -29,17 +19,7 @@ LL | use std::range::Range; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: use of unstable library feature `new_range_api` - --> $DIR/new_range_stability.rs:34:5 - | -LL | use std::range::RangeFromIter; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #125687 for more information - = help: add `#![feature(new_range_api)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: use of unstable library feature `new_range_api` - --> $DIR/new_range_stability.rs:35:5 + --> $DIR/new_range_stability.rs:51:5 | LL | use std::range::RangeIter; | ^^^^^^^^^^^^^^^^^^^^^ @@ -48,6 +28,6 @@ LL | use std::range::RangeIter; = help: add `#![feature(new_range_api)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0658`.