Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 14 additions & 6 deletions library/core/src/iter/range.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use super::{
FusedIterator, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce, TrustedStep,
};
use crate::ascii::Char as AsciiChar;
use crate::marker::Destruct;
use crate::mem;
use crate::net::{Ipv4Addr, Ipv6Addr};
use crate::num::NonZero;
Expand Down Expand Up @@ -1000,7 +1001,7 @@ macro_rules! range_incl_exact_iter_impl {
}

/// Specialization implementations for `Range`.
trait RangeIteratorImpl {
const trait RangeIteratorImpl {
type Item;

// Iterator
Expand All @@ -1014,7 +1015,8 @@ trait RangeIteratorImpl {
fn spec_advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>>;
}

impl<A: Step> RangeIteratorImpl for ops::Range<A> {
#[rustc_const_unstable(feature = "const_iter", issue = "92476")]
const impl<A: [const] Step + [const] Destruct> RangeIteratorImpl for ops::Range<A> {
type Item = A;

#[inline]
Expand Down Expand Up @@ -1094,7 +1096,8 @@ impl<A: Step> RangeIteratorImpl for ops::Range<A> {
}
}

impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> {
#[rustc_const_unstable(feature = "const_iter", issue = "92476")]
const impl<T: [const] TrustedStep + [const] Destruct> RangeIteratorImpl for ops::Range<T> {
#[inline]
fn spec_next(&mut self) -> Option<T> {
if self.start < self.end {
Expand Down Expand Up @@ -1177,7 +1180,8 @@ impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<A: Step> Iterator for ops::Range<A> {
#[rustc_const_unstable(feature = "const_iter", issue = "92476")]
const impl<A: [const] Step + [const] Destruct> Iterator for ops::Range<A> {
type Item = A;

#[inline]
Expand Down Expand Up @@ -1230,7 +1234,10 @@ impl<A: Step> Iterator for ops::Range<A> {
}

#[inline]
fn is_sorted(self) -> bool {
fn is_sorted(self) -> bool
where
Self: [const] Destruct,
{
true
}

Expand Down Expand Up @@ -1310,7 +1317,8 @@ range_incl_exact_iter_impl! {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<A: Step> DoubleEndedIterator for ops::Range<A> {
#[rustc_const_unstable(feature = "const_iter", issue = "92476")]
const impl<A: [const] Step + [const] Destruct> DoubleEndedIterator for ops::Range<A> {
#[inline]
fn next_back(&mut self) -> Option<A> {
self.spec_next_back()
Expand Down
12 changes: 8 additions & 4 deletions library/core/src/iter/traits/double_ended.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,10 @@ pub const trait DoubleEndedIterator: [const] Iterator {
/// [`Err(k)`]: Err
#[inline]
#[unstable(feature = "iter_advance_by", issue = "77404")]
#[rustc_non_const_trait_method]
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>>
where
Self::Item: [const] Destruct,
{
for i in 0..n {
if self.next_back().is_none() {
// SAFETY: `i` is always less than `n`.
Expand Down Expand Up @@ -239,8 +241,10 @@ pub const trait DoubleEndedIterator: [const] Iterator {
/// ```
#[inline]
#[stable(feature = "iter_nth_back", since = "1.37.0")]
#[rustc_non_const_trait_method]
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
fn nth_back(&mut self, n: usize) -> Option<Self::Item>
where
Self::Item: [const] Destruct,
{
if self.advance_back_by(n).is_err() {
return None;
}
Expand Down
30 changes: 22 additions & 8 deletions library/core/src/iter/traits/iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -306,14 +306,22 @@ pub const trait Iterator {
/// ```
#[inline]
#[unstable(feature = "iter_advance_by", issue = "77404")]
#[rustc_non_const_trait_method]
fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>>
where
Self::Item: [const] Destruct,
{
/// Helper trait to specialize `advance_by` via `try_fold` for `Sized` iterators.
trait SpecAdvanceBy {

#[rustc_const_unstable(feature = "const_iter", issue = "92476")]
const trait SpecAdvanceBy {
fn spec_advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>>;
}

impl<I: Iterator + ?Sized> SpecAdvanceBy for I {
#[rustc_const_unstable(feature = "const_iter", issue = "92476")]
const impl<I: [const] Iterator + ?Sized> SpecAdvanceBy for I
where
I::Item: [const] Destruct,
{
default fn spec_advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
for i in 0..n {
if self.next().is_none() {
Expand All @@ -325,13 +333,17 @@ pub const trait Iterator {
}
}

impl<I: Iterator> SpecAdvanceBy for I {
#[rustc_const_unstable(feature = "const_iter", issue = "92476")]
const impl<I: [const] Iterator> SpecAdvanceBy for I
where
I::Item: [const] Destruct,
{
fn spec_advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
let Some(n) = NonZero::new(n) else {
return Ok(());
};

let res = self.try_fold(n, |n, _| NonZero::new(n.get() - 1));
let res = self.try_fold(n, const |n, _| NonZero::new(n.get() - 1));

match res {
None => Ok(()),
Expand Down Expand Up @@ -384,8 +396,10 @@ pub const trait Iterator {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_non_const_trait_method]
fn nth(&mut self, n: usize) -> Option<Self::Item> {
fn nth(&mut self, n: usize) -> Option<Self::Item>
where
Self::Item: [const] Destruct,
{
self.advance_by(n).ok()?;
self.next()
}
Expand Down
3 changes: 2 additions & 1 deletion library/core/src/iter/traits/marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,4 +115,5 @@ pub unsafe trait InPlaceIterable {
/// for details. Consumers are free to rely on the invariants in unsafe code.
#[unstable(feature = "trusted_step", issue = "85731")]
#[rustc_specialization_trait]
pub unsafe trait TrustedStep: Step + Copy {}
#[rustc_const_unstable(feature = "const_iter", issue = "92476")]
pub const unsafe trait TrustedStep: const Step + Copy {}

@clarfonthey clarfonthey Sep 14, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So unfortunately, due to this, I think we're going to have to block this on the discussion in #148200.

Added T-types label as well and will update the Zulip thread. Hopefully we do resolve that discussion soon, though.

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense. I don't think there is any sensible resolution in which this code is problematic (particularly because we want some version of this PR to work), but better to have working solution first

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, to be clear we want to be able to do stuff like this, but there's been some discussion over making sure it works properly.

10 changes: 2 additions & 8 deletions library/core/src/slice/cmp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,14 +126,11 @@ where
// Implemented as explicit indexing rather
// than zipped iterators for performance reasons.
// See PR https://github.com/rust-lang/rust/pull/116846
// FIXME(const_hack): make this a `for idx in 0..len` loop.
let mut idx = 0;
while idx < len {
for idx in 0..len {
// SAFETY: idx < len, so both are in-bounds and readable
if unsafe { *lhs.add(idx) != *rhs.add(idx) } {
return false;
}
idx += 1;
}

true
Expand Down Expand Up @@ -224,11 +221,8 @@ const fn chaining_impl<'l, 'r, A: PartialOrd, B, C>(
let lhs = &left[..l];
let rhs = &right[..l];

// FIXME(const-hack): revert this to `for i in 0..l` once `impl const Iterator for Range<T>`
let mut i: usize = 0;
while i < l {
for i in 0..l {
elem_chain(&lhs[i], &rhs[i])?;
i += 1;
}

len_chain(&left.len(), &right.len())
Expand Down
7 changes: 2 additions & 5 deletions library/core/src/slice/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5628,11 +5628,8 @@ where
// But since it can't be relied on we also have an explicit specialization for T: Copy.
let len = self.len();
let src = &src[..len];
// FIXME(const_hack): make this a `for idx in 0..self.len()` loop.
let mut idx = 0;
while idx < self.len() {
self[idx].clone_from(&src[idx]);
idx += 1;
for i in 0..len {
self[i].clone_from(&src[i]);
}
}
}
Expand Down
21 changes: 11 additions & 10 deletions tests/codegen-llvm/array-cmp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,16 @@ pub fn array_of_tuple_le(a: &[(i16, u16); 2], b: &[(i16, u16); 2]) -> bool {
// CHECK: %[[EQ00:.+]] = icmp eq i16 %[[A00]], %[[B00]]
// CHECK-NEXT: br i1 %[[EQ00]], label %[[L01:.+]], label %[[EXIT_S:.+]]

// CHECK: [[L01]]:
// CHECK: %[[PA01:.+]] = getelementptr{{.+}}i8, ptr %a, {{i32|i64}} 2
// CHECK: %[[PB01:.+]] = getelementptr{{.+}}i8, ptr %b, {{i32|i64}} 2
// CHECK: %[[A01:.+]] = load i16, ptr %[[PA01]]
// CHECK: %[[B01:.+]] = load i16, ptr %[[PB01]]
// CHECK-NOT: cmp
// CHECK: %[[EQ01:.+]] = icmp eq i16 %[[A01]], %[[B01]]
// CHECK-NEXT: br i1 %[[EQ01]], label %[[L10:.+]], label %[[EXIT_U:.+]]

// CHECK: [[L10]]:
// CHECK: %[[PA10:.+]] = getelementptr{{.+}}i8, ptr %a, {{i32|i64}} 4
// CHECK: %[[PB10:.+]] = getelementptr{{.+}}i8, ptr %b, {{i32|i64}} 4
// CHECK: %[[A10:.+]] = load i16, ptr %[[PA10]]
Expand All @@ -57,16 +67,7 @@ pub fn array_of_tuple_le(a: &[(i16, u16); 2], b: &[(i16, u16); 2]) -> bool {
// CHECK: %[[B11:.+]] = load i16, ptr %[[PB11]]
// CHECK-NOT: cmp
// CHECK: %[[EQ11:.+]] = icmp eq i16 %[[A11]], %[[B11]]
// CHECK-NEXT: br i1 %[[EQ11]], label %[[DONE:.+]], label %[[EXIT_U:.+]]

// CHECK: [[L01]]:
// CHECK: %[[PA01:.+]] = getelementptr{{.+}}i8, ptr %a, {{i32|i64}} 2
// CHECK: %[[PB01:.+]] = getelementptr{{.+}}i8, ptr %b, {{i32|i64}} 2
// CHECK: %[[A01:.+]] = load i16, ptr %[[PA01]]
// CHECK: %[[B01:.+]] = load i16, ptr %[[PB01]]
// CHECK-NOT: cmp
// CHECK: %[[EQ01:.+]] = icmp eq i16 %[[A01]], %[[B01]]
// CHECK-NEXT: br i1 %[[EQ01]], label %{{.+}}, label %[[EXIT_U]]
// CHECK-NEXT: br i1 %[[EQ11]], label %[[DONE:.+]], label %[[EXIT_U]]

// CHECK: [[DONE]]:
// LLVM22: %[[RET:.+]] = phi i1 [ %{{.+}}, %[[EXIT_S]] ], [ %{{.+}}, %[[EXIT_U]] ], [ true, %[[L11]] ]
Expand Down
2 changes: 2 additions & 0 deletions tests/ui/consts/const-for-feature-gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
const _: () = {
for _ in 0..5 {}
//~^ ERROR cannot use `for`
//~| ERROR `IntoIterator` is not yet stable
//~| ERROR cannot use `for`
//~| ERROR `Iterator` is not yet stable
};

fn main() {}
36 changes: 32 additions & 4 deletions tests/ui/consts/const-for-feature-gate.stderr
Original file line number Diff line number Diff line change
@@ -1,20 +1,48 @@
error[E0015]: cannot use `for` loop on `std::ops::Range<i32>` in constants
error[E0658]: cannot use `for` loop on `std::ops::Range<i32>` in constants
--> $DIR/const-for-feature-gate.rs:4:14
|
LL | for _ in 0..5 {}
| ^^^^
|
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
= note: see issue #143874 <https://github.com/rust-lang/rust/issues/143874> for more information
= help: add `#![feature(const_trait_impl)]` 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[E0015]: cannot use `for` loop on `std::ops::Range<i32>` in constants
error: `IntoIterator` is not yet stable as a const trait
--> $DIR/const-for-feature-gate.rs:4:14
|
LL | for _ in 0..5 {}
| ^^^^
|
help: add `#![feature(const_iter)]` to the crate attributes to enable
|
LL + #![feature(const_iter)]
|

error[E0658]: cannot use `for` loop on `std::ops::Range<i32>` in constants
--> $DIR/const-for-feature-gate.rs:4:14
|
LL | for _ in 0..5 {}
| ^^^^
|
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
= note: see issue #143874 <https://github.com/rust-lang/rust/issues/143874> for more information
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error: aborting due to 2 previous errors
error: `Iterator` is not yet stable as a const trait
--> $DIR/const-for-feature-gate.rs:4:14
|
LL | for _ in 0..5 {}
| ^^^^
|
help: add `#![feature(const_iter)]` to the crate attributes to enable
|
LL + #![feature(const_iter)]
|

error: aborting due to 4 previous errors

For more information about this error, try `rustc --explain E0015`.
For more information about this error, try `rustc --explain E0658`.
5 changes: 2 additions & 3 deletions tests/ui/consts/const-for.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
#![feature(const_for)]
//@ check-pass
#![feature(const_trait_impl,const_iter,const_for)]

const _: () = {
for _ in 0..5 {}
//~^ ERROR cannot use `for`

@Randl Randl Sep 13, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this also appears to test specifically for for in const, though it duplicates

View changes since the review

//~| ERROR cannot use `for`
};

fn main() {}
20 changes: 0 additions & 20 deletions tests/ui/consts/const-for.stderr

This file was deleted.

7 changes: 3 additions & 4 deletions tests/ui/consts/control-flow/loop.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
//@ check-pass
#![feature(const_iter,const_trait_impl)]

const _: () = loop { break (); };

static FOO: i32 = loop { break 4; };
Expand Down Expand Up @@ -51,14 +54,10 @@ const _: i32 = {
let mut x = 0;

for i in 0..4 {
//~^ ERROR: cannot use `for`

@Randl Randl Sep 13, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to clearly test loops in const context

View changes since the review

//~| ERROR: cannot use `for`
x += i;
}

for i in 0..4 {
//~^ ERROR: cannot use `for`
//~| ERROR: cannot use `for`
x += i;
}

Expand Down
37 changes: 0 additions & 37 deletions tests/ui/consts/control-flow/loop.stderr

This file was deleted.

Loading
Loading