From bc4ceaddcd7b6673edbb0535c70f435bce9d0c67 Mon Sep 17 00:00:00 2001
From: Peter Jaszkowiak
Date: Sat, 7 Feb 2026 09:36:31 -0700
Subject: [PATCH] stabilize new RangeToInclusive type
stabilizes `core::range::RangeToInclusive`
add missing trait impls for new RangeToInclusive
add missing trait impls for new RangeFrom
---
library/core/src/bstr/traits.rs | 1 +
library/core/src/ffi/c_str.rs | 12 ++++-
library/core/src/range.rs | 55 ++++++++++++++++++-----
library/core/src/slice/index.rs | 4 +-
library/core/src/str/traits.rs | 46 +++++++++++++++++++
tests/ui/range/new_range_stability.rs | 11 ++++-
tests/ui/range/new_range_stability.stderr | 10 ++---
7 files changed, 120 insertions(+), 19 deletions(-)
diff --git a/library/core/src/bstr/traits.rs b/library/core/src/bstr/traits.rs
index 7da6c5f13cce1..bcfffd52d7419 100644
--- a/library/core/src/bstr/traits.rs
+++ b/library/core/src/bstr/traits.rs
@@ -268,4 +268,5 @@ impl_slice_index!(range::RangeFrom);
impl_slice_index!(ops::RangeInclusive);
impl_slice_index!(range::RangeInclusive);
impl_slice_index!(ops::RangeToInclusive);
+impl_slice_index!(range::RangeToInclusive);
impl_slice_index!((ops::Bound, ops::Bound));
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index 621277179bb38..5fc97d9a69efd 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -8,7 +8,7 @@ use crate::iter::FusedIterator;
use crate::marker::PhantomData;
use crate::ptr::NonNull;
use crate::slice::memchr;
-use crate::{fmt, ops, slice, str};
+use crate::{fmt, ops, range, slice, str};
// FIXME: because this is doc(inline)d, we *have* to use intra-doc links because the actual link
// depends on where the item is being documented. however, since this is libcore, we can't
@@ -716,6 +716,16 @@ impl ops::Index> for CStr {
}
}
+#[unstable(feature = "new_range_api", issue = "125687")]
+impl ops::Index> for CStr {
+ type Output = CStr;
+
+ #[inline]
+ fn index(&self, index: range::RangeFrom) -> &CStr {
+ ops::Index::index(self, ops::RangeFrom::from(index))
+ }
+}
+
#[stable(feature = "cstring_asref", since = "1.7.0")]
#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
impl const AsRef for CStr {
diff --git a/library/core/src/range.rs b/library/core/src/range.rs
index 0ef0d192a8682..16e6bb6df7da7 100644
--- a/library/core/src/range.rs
+++ b/library/core/src/range.rs
@@ -43,7 +43,7 @@ pub use iter::{RangeFromIter, RangeIter};
// pub use crate::ops::{Bound, IntoBounds, OneSidedRange, RangeBounds, RangeFull, RangeTo};
use crate::iter::Step;
use crate::ops::Bound::{self, Excluded, Included, Unbounded};
-use crate::ops::{IntoBounds, RangeBounds};
+use crate::ops::{IntoBounds, OneSidedRange, OneSidedRangeBound, RangeBounds};
/// A (half-open) range bounded inclusively below and exclusively above
/// (`start..end` in a future edition).
@@ -546,6 +546,18 @@ 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
+ Self: RangeBounds,
+{
+ fn bound(self) -> (OneSidedRangeBound, T) {
+ (OneSidedRangeBound::StartInclusive, self.start)
+ }
+}
+
#[unstable(feature = "new_range_api", issue = "125687")]
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
impl const From> for legacy::RangeFrom {
@@ -573,9 +585,8 @@ impl const From> for RangeFrom {
/// The `..=last` syntax is a `RangeToInclusive`:
///
/// ```
-/// #![feature(new_range_api)]
/// #![feature(new_range)]
-/// assert_eq!((..=5), std::range::RangeToInclusive{ last: 5 });
+/// assert_eq!((..=5), std::range::RangeToInclusive { last: 5 });
/// ```
///
/// It does not have an [`IntoIterator`] implementation, so you can't use it in a
@@ -606,14 +617,14 @@ impl const From> for RangeFrom {
#[lang = "RangeToInclusiveCopy"]
#[doc(alias = "..=")]
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
-#[unstable(feature = "new_range_api", issue = "125687")]
+#[stable(feature = "new_range_to_inclusive_api", since = "CURRENT_RUSTC_VERSION")]
pub struct RangeToInclusive {
/// The upper bound of the range (inclusive)
- #[unstable(feature = "new_range_api", issue = "125687")]
+ #[stable(feature = "new_range_to_inclusive_api", since = "CURRENT_RUSTC_VERSION")]
pub last: Idx,
}
-#[unstable(feature = "new_range_api", issue = "125687")]
+#[stable(feature = "new_range_to_inclusive_api", since = "CURRENT_RUSTC_VERSION")]
impl fmt::Debug for RangeToInclusive {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(fmt, "..=")?;
@@ -637,7 +648,7 @@ impl> RangeToInclusive {
/// assert!(!(..=f32::NAN).contains(&0.5));
/// ```
#[inline]
- #[unstable(feature = "new_range_api", issue = "125687")]
+ #[stable(feature = "new_range_to_inclusive_api", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_unstable(feature = "const_range", issue = "none")]
pub const fn contains(&self, item: &U) -> bool
where
@@ -648,13 +659,13 @@ impl> RangeToInclusive {
}
}
-#[unstable(feature = "new_range_api", issue = "125687")]
+#[stable(feature = "new_range_to_inclusive_api", since = "CURRENT_RUSTC_VERSION")]
impl From> for RangeToInclusive {
fn from(value: legacy::RangeToInclusive) -> Self {
Self { last: value.end }
}
}
-#[unstable(feature = "new_range_api", issue = "125687")]
+#[stable(feature = "new_range_to_inclusive_api", since = "CURRENT_RUSTC_VERSION")]
impl From> for legacy::RangeToInclusive {
fn from(value: RangeToInclusive) -> Self {
Self { end: value.last }
@@ -664,7 +675,7 @@ impl From> for legacy::RangeToInclusive {
// RangeToInclusive cannot impl From>
// because underflow would be possible with (..0).into()
-#[unstable(feature = "new_range_api", issue = "125687")]
+#[stable(feature = "new_range_to_inclusive_api", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_unstable(feature = "const_range", issue = "none")]
impl const RangeBounds for RangeToInclusive {
fn start_bound(&self) -> Bound<&T> {
@@ -675,6 +686,18 @@ impl const RangeBounds for RangeToInclusive {
}
}
+#[stable(feature = "new_range_to_inclusive_api", since = "CURRENT_RUSTC_VERSION")]
+#[rustc_const_unstable(feature = "const_range", issue = "none")]
+impl const RangeBounds for RangeToInclusive<&T> {
+ fn start_bound(&self) -> Bound<&T> {
+ Unbounded
+ }
+ fn end_bound(&self) -> Bound<&T> {
+ Included(self.last)
+ }
+}
+
+// #[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 {
@@ -682,3 +705,15 @@ impl const IntoBounds for RangeToInclusive {
(Unbounded, Included(self.last))
}
}
+
+// #[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
+where
+ Self: RangeBounds,
+{
+ fn bound(self) -> (OneSidedRangeBound, T) {
+ (OneSidedRangeBound::EndInclusive, self.last)
+ }
+}
diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs
index 3a76c098bb530..59239e62916a0 100644
--- a/library/core/src/slice/index.rs
+++ b/library/core/src/slice/index.rs
@@ -129,7 +129,7 @@ mod private_slice_index {
impl Sealed for range::Range {}
#[stable(feature = "new_range_inclusive_api", since = "CURRENT_RUSTC_VERSION")]
impl Sealed for range::RangeInclusive {}
- #[unstable(feature = "new_range_api", issue = "125687")]
+ #[stable(feature = "new_range_to_inclusive_api", since = "CURRENT_RUSTC_VERSION")]
impl Sealed for range::RangeToInclusive {}
#[unstable(feature = "new_range_api", issue = "125687")]
impl Sealed for range::RangeFrom {}
@@ -801,7 +801,7 @@ unsafe impl const SliceIndex<[T]> for ops::RangeToInclusive {
}
/// The methods `index` and `index_mut` panic if the end of the range is out of bounds.
-#[stable(feature = "inclusive_range", since = "1.26.0")]
+#[stable(feature = "new_range_to_inclusive_api", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
unsafe impl const SliceIndex<[T]> for range::RangeToInclusive {
type Output = [T];
diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs
index edf07c0c16f42..03d47cacf5db9 100644
--- a/library/core/src/str/traits.rs
+++ b/library/core/src/str/traits.rs
@@ -763,6 +763,52 @@ unsafe impl const SliceIndex for ops::RangeToInclusive {
}
}
+/// Implements substring slicing with syntax `&self[..= last]` or `&mut
+/// self[..= last]`.
+///
+/// Returns a slice of the given string from the byte range \[0, `last`\].
+/// Equivalent to `&self [0 .. last + 1]`, except if `last` has the maximum
+/// value for `usize`.
+///
+/// This operation is *O*(1).
+///
+/// # Panics
+///
+/// Panics if `last` does not point to the ending byte offset of a character
+/// (`last + 1` is either a starting byte offset as defined by
+/// `is_char_boundary`, or equal to `len`), or if `last >= len`.
+#[stable(feature = "new_range_to_inclusive_api", since = "CURRENT_RUSTC_VERSION")]
+#[rustc_const_unstable(feature = "const_index", issue = "143775")]
+unsafe impl const SliceIndex for range::RangeToInclusive {
+ type Output = str;
+ #[inline]
+ fn get(self, slice: &str) -> Option<&Self::Output> {
+ (0..=self.last).get(slice)
+ }
+ #[inline]
+ fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
+ (0..=self.last).get_mut(slice)
+ }
+ #[inline]
+ unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
+ // SAFETY: the caller must uphold the safety contract for `get_unchecked`.
+ unsafe { (0..=self.last).get_unchecked(slice) }
+ }
+ #[inline]
+ unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
+ // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`.
+ unsafe { (0..=self.last).get_unchecked_mut(slice) }
+ }
+ #[inline]
+ fn index(self, slice: &str) -> &Self::Output {
+ (0..=self.last).index(slice)
+ }
+ #[inline]
+ fn index_mut(self, slice: &mut str) -> &mut Self::Output {
+ (0..=self.last).index_mut(slice)
+ }
+}
+
/// Parse a value from a string
///
/// `FromStr`'s [`from_str`] method is often used implicitly, through
diff --git a/tests/ui/range/new_range_stability.rs b/tests/ui/range/new_range_stability.rs
index 7200e1ac95d27..2d129fb6815f5 100644
--- a/tests/ui/range/new_range_stability.rs
+++ b/tests/ui/range/new_range_stability.rs
@@ -1,8 +1,10 @@
// Stable
-use std::range::{RangeInclusive, RangeInclusiveIter};
+use std::range::{RangeInclusive, RangeInclusiveIter, RangeToInclusive};
fn range_inclusive(mut r: RangeInclusive) {
+ &[1, 2, 3][r]; // Indexing
+
r.start;
r.last;
r.contains(&5);
@@ -14,6 +16,13 @@ fn range_inclusive(mut r: RangeInclusive) {
i.remainder();
}
+fn range_to_inclusive(mut r: RangeToInclusive) {
+ &[1, 2, 3][r]; // Indexing
+
+ r.last;
+ r.contains(&5);
+}
+
// Unstable module
use std::range::legacy; //~ ERROR unstable
diff --git a/tests/ui/range/new_range_stability.stderr b/tests/ui/range/new_range_stability.stderr
index 871d691794ff0..b5a7e06e5f2ea 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:19:5
+ --> $DIR/new_range_stability.rs:28:5
|
LL | use std::range::legacy;
| ^^^^^^^^^^^^^^^^^^
@@ -9,7 +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:23:5
+ --> $DIR/new_range_stability.rs:32:5
|
LL | use std::range::RangeFrom;
| ^^^^^^^^^^^^^^^^^^^^^
@@ -19,7 +19,7 @@ LL | use std::range::RangeFrom;
= 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:24:5
+ --> $DIR/new_range_stability.rs:33:5
|
LL | use std::range::Range;
| ^^^^^^^^^^^^^^^^^
@@ -29,7 +29,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:25:5
+ --> $DIR/new_range_stability.rs:34:5
|
LL | use std::range::RangeFromIter;
| ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -39,7 +39,7 @@ LL | use std::range::RangeFromIter;
= 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:26:5
+ --> $DIR/new_range_stability.rs:35:5
|
LL | use std::range::RangeIter;
| ^^^^^^^^^^^^^^^^^^^^^