Rollup merge of #153380 - pitaj:stabilize-new_range_from_api, r=tgross35

stabilize new RangeFrom type and iterator

```rust
// in core and std
pub mod range;

// in core::range

pub struct RangeFrom<Idx> {
    pub start: Idx,
}

impl<Idx: fmt::Debug> fmt::Debug for RangeFrom<Idx> { /* ... */ }

impl<Idx: PartialOrd<Idx>> RangeFrom<Idx> {
    pub const fn contains<U>(&self, item: &U) -> bool
    where
        Idx: [const] PartialOrd<U>,
        U: ?Sized + [const] PartialOrd<Idx>;
}

impl<Idx: Step> RangeFrom<Idx> {
    pub fn iter(&self) -> RangeFromIter<Idx>;
}

impl<T> const RangeBounds<T> for RangeFrom<T> { /* ... */ }
impl<T> const RangeBounds<T> for RangeFrom<&T> { /* ... */ }

impl<T> const From<RangeFrom<T>> for legacy::RangeFrom<T> { /* ... */ }
impl<T> const From<legacy::RangeFrom<T>> for RangeFrom<T> { /* ... */ }

pub struct RangeFromIter<A>(/* ... */);

// `RangeFromIter::remainder` left unstable

impl<A: Step> Iterator for RangeFromIter<A> {
    type Item = A;
    /* ... */
}

impl<A: Step> FusedIterator for RangeFromIter<A> { }
impl<A: Step> IntoIterator for RangeFrom<A> {
    type Item = A;
    type IntoIter = RangeFromIter<A>;
    /* ... */
}

unsafe impl<T> const SliceIndex<[T]> for range::RangeFrom<usize> {
    type Output = [T];
    /* ... */
}
unsafe impl const SliceIndex<str> for range::RangeFrom<usize> {
    type Output = str;
    /* ... */
}

impl ops::Index<range::RangeFrom<usize>> for CStr {
    type Output = CStr;
    /* ... */
}
```

Tracking issue: https://github.com/rust-lang/rust/issues/125687
This commit is contained in:
Guillaume Gomez
2026-03-29 00:06:49 +01:00
committed by GitHub
12 changed files with 95 additions and 64 deletions
+1 -1
View File
@@ -716,7 +716,7 @@ fn index(&self, index: ops::RangeFrom<usize>) -> &CStr {
}
}
#[unstable(feature = "new_range_api", issue = "125687")]
#[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")]
impl ops::Index<range::RangeFrom<usize>> for CStr {
type Output = CStr;
+18 -23
View File
@@ -24,12 +24,15 @@
#[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 @@ fn from(value: legacy::RangeInclusive<T>) -> Self {
///
/// 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 @@ fn from(value: legacy::RangeInclusive<T>) -> Self {
/// 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 @@ fn from(value: legacy::RangeInclusive<T>) -> Self {
#[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<Idx> {
/// 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<Idx: fmt::Debug> fmt::Debug for RangeFrom<Idx> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
self.start.fmt(fmt)?;
@@ -465,7 +466,6 @@ impl<Idx: Step> RangeFrom<Idx> {
/// # 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<Idx: Step> RangeFrom<Idx> {
/// 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<Idx> {
self.clone().into_iter()
@@ -486,7 +486,6 @@ impl<Idx: PartialOrd<Idx>> RangeFrom<Idx> {
/// # Examples
///
/// ```
/// #![feature(new_range_api)]
/// use core::range::RangeFrom;
///
/// assert!(!RangeFrom::from(3..).contains(&2));
@@ -498,7 +497,7 @@ impl<Idx: PartialOrd<Idx>> RangeFrom<Idx> {
/// 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<U>(&self, item: &U) -> bool
where
@@ -509,7 +508,7 @@ pub const fn contains<U>(&self, item: &U) -> bool
}
}
#[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<T> const RangeBounds<T> for RangeFrom<T> {
fn start_bound(&self) -> Bound<&T> {
@@ -526,7 +525,7 @@ fn end_bound(&self) -> Bound<&T> {
/// 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<T> const RangeBounds<T> for RangeFrom<&T> {
fn start_bound(&self) -> Bound<&T> {
@@ -537,8 +536,7 @@ fn end_bound(&self) -> Bound<&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<T> const IntoBounds<T> for RangeFrom<T> {
fn into_bounds(self) -> (Bound<T>, Bound<T>) {
@@ -547,7 +545,6 @@ fn into_bounds(self) -> (Bound<T>, Bound<T>) {
}
#[unstable(feature = "one_sided_range", issue = "69780")]
// #[unstable(feature = "new_range_api", issue = "125687")]
#[rustc_const_unstable(feature = "const_range", issue = "none")]
impl<T> const OneSidedRange<T> for RangeFrom<T>
where
@@ -558,7 +555,7 @@ fn bound(self) -> (OneSidedRangeBound, T) {
}
}
#[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<T> const From<RangeFrom<T>> for legacy::RangeFrom<T> {
#[inline]
@@ -566,7 +563,7 @@ fn from(value: RangeFrom<T>) -> Self {
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<T> const From<legacy::RangeFrom<T>> for RangeFrom<T> {
#[inline]
@@ -697,7 +694,6 @@ fn end_bound(&self) -> Bound<&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<T> const IntoBounds<T> for RangeToInclusive<T> {
@@ -706,7 +702,6 @@ fn into_bounds(self) -> (Bound<T>, Bound<T>) {
}
}
// #[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<T> const OneSidedRange<T> for RangeToInclusive<T>
+37 -4
View File
@@ -13,6 +13,18 @@
impl<A> RangeIter<A> {
#[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<A> {
Range { start: self.0.start, end: self.0.end }
}
@@ -161,6 +173,17 @@ impl<A: Step> RangeInclusiveIter<A> {
/// 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<RangeInclusive<A>> {
if self.0.is_empty() {
@@ -294,7 +317,7 @@ impl ExactSizeIterator for RangeInclusiveIter<$t> { }
}
/// 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<A> {
start: A,
@@ -305,6 +328,16 @@ pub struct RangeFromIter<A> {
impl<A: Step> RangeFromIter<A> {
/// Returns the remainder of the range being iterated over.
///
/// # Examples
/// ```
/// #![feature(new_range_api)]
/// 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")]
@@ -321,7 +354,7 @@ pub fn remainder(self) -> RangeFrom<A> {
}
}
#[unstable(feature = "new_range_api", issue = "125687")]
#[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")]
impl<A: Step> Iterator for RangeFromIter<A> {
type Item = A;
@@ -392,10 +425,10 @@ fn nth(&mut self, n: usize) -> Option<A> {
#[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<A: TrustedStep> TrustedLen for RangeFromIter<A> {}
#[unstable(feature = "new_range_api", issue = "125687")]
#[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")]
impl<A: Step> FusedIterator for RangeFromIter<A> {}
#[unstable(feature = "new_range_api", issue = "125687")]
#[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")]
impl<A: Step> IntoIterator for RangeFrom<A> {
type Item = A;
type IntoIter = RangeFromIter<A>;
+2 -2
View File
@@ -131,7 +131,7 @@ impl Sealed for range::Range<usize> {}
impl Sealed for range::RangeInclusive<usize> {}
#[stable(feature = "new_range_to_inclusive_api", since = "CURRENT_RUSTC_VERSION")]
impl Sealed for range::RangeToInclusive<usize> {}
#[unstable(feature = "new_range_api", issue = "125687")]
#[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")]
impl Sealed for range::RangeFrom<usize> {}
impl Sealed for ops::IndexRange {}
@@ -588,7 +588,7 @@ fn index_mut(self, slice: &mut [T]) -> &mut [T] {
}
}
#[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<T> const SliceIndex<[T]> for range::RangeFrom<usize> {
type Output = [T];
+1 -1
View File
@@ -555,7 +555,7 @@ fn index_mut(self, slice: &mut str) -> &mut Self::Output {
}
}
#[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<str> for range::RangeFrom<usize> {
type Output = str;
@@ -11,6 +11,7 @@
#![crate_type = "lib"]
#![feature(new_range_api)]
use std::range::RangeFrom;
// CHECK-LABEL: @rangefrom_increments(
@@ -1,7 +1,6 @@
//@ compile-flags: -C overflow-checks=no
#![crate_type = "lib"]
#![feature(new_range_api)]
use std::range::RangeFromIter;
@@ -1,7 +1,6 @@
//@ compile-flags: -C overflow-checks=yes
#![crate_type = "lib"]
#![feature(new_range_api)]
use std::range::RangeFromIter;
-2
View File
@@ -1,8 +1,6 @@
//@ run-pass
//@ compile-flags: -C overflow-checks=yes
#![feature(new_range_api)]
use std::{iter, range};
fn main() {
@@ -7,8 +7,6 @@
// Test that two crates with different overflow-checks have the same results,
// even when the iterator is passed between them.
#![feature(new_range_api)]
extern crate rangefrom_overflow_2crates_ocno;
extern crate rangefrom_overflow_2crates_ocyes;
+21 -3
View File
@@ -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<usize>) {
&[1, 2, 3][r]; // Indexing
@@ -23,15 +29,27 @@ fn range_to_inclusive(mut r: RangeToInclusive<usize>) {
r.contains(&5);
}
fn range_from(mut r: RangeFrom<usize>) {
&[1, 2, 3][r]; // Indexing
r.start;
r.contains(&5);
r.iter();
let mut i = r.into_iter();
i.next();
// Left unstable
i.remainder(); //~ ERROR unstable
}
// 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() {}
+14 -24
View File
@@ -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:48: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 <https://github.com/rust-lang/rust/issues/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:52: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 <https://github.com/rust-lang/rust/issues/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:53:5
|
LL | use std::range::RangeIter;
| ^^^^^^^^^^^^^^^^^^^^^
@@ -48,6 +28,16 @@ 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[E0658]: use of unstable library feature `new_range_api`
--> $DIR/new_range_stability.rs:43:7
|
LL | i.remainder();
| ^^^^^^^^^
|
= note: see issue #125687 <https://github.com/rust-lang/rust/issues/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: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0658`.