From bc2f0fb5a9783ab2d70aa2831b7ffd056f5a16e9 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Fri, 2 Apr 2021 00:58:45 -0400 Subject: [PATCH] Specialize implementations Implementations in stdlib are now optimized as they were before. --- compiler/rustc_ast/src/lib.rs | 2 + compiler/rustc_hir/src/lib.rs | 2 + compiler/rustc_index/src/lib.rs | 1 + compiler/rustc_index/src/vec.rs | 3 + compiler/rustc_infer/src/lib.rs | 2 + compiler/rustc_middle/src/lib.rs | 1 + compiler/rustc_mir/src/lib.rs | 1 + compiler/rustc_mir_build/src/lib.rs | 2 + compiler/rustc_passes/src/lib.rs | 2 + compiler/rustc_query_system/src/lib.rs | 1 + compiler/rustc_span/src/lib.rs | 1 + compiler/rustc_target/src/lib.rs | 2 + compiler/rustc_type_ir/src/lib.rs | 3 + library/core/src/iter/mod.rs | 2 + library/core/src/iter/range.rs | 468 +++++++++++++++++++------ library/core/src/iter/traits/marker.rs | 17 + library/core/src/iter/traits/mod.rs | 2 + 17 files changed, 403 insertions(+), 109 deletions(-) diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 0f6e0fb8825..14ecf27813d 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -17,6 +17,8 @@ #![feature(iter_zip)] #![feature(label_break_value)] #![feature(nll)] +#![feature(min_specialization)] +#![feature(trusted_step)] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index 6a12c917436..7f3c410b1ec 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -7,6 +7,8 @@ #![cfg_attr(bootstrap, feature(extended_key_value_attributes))] #![feature(in_band_lifetimes)] #![feature(once_cell)] +#![feature(min_specialization)] +#![feature(trusted_step)] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs index 4c73b7bf612..04d62391c02 100644 --- a/compiler/rustc_index/src/lib.rs +++ b/compiler/rustc_index/src/lib.rs @@ -6,6 +6,7 @@ #![feature(unboxed_closures)] #![feature(test)] #![feature(fn_traits)] +#![feature(trusted_step)] pub mod bit_set; pub mod vec; diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 9cf6756a090..440e0943d6e 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -204,6 +204,9 @@ fn backward_checked(start: Self, u: usize) -> Option { } } + // Safety: The implementation of `Step` upholds all invariants. + unsafe impl ::std::iter::TrustedStep for $type {} + impl From<$type> for u32 { #[inline] fn from(v: $type) -> u32 { diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index f3e5830c198..6b452bca8e7 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -22,6 +22,8 @@ #![feature(never_type)] #![feature(in_band_lifetimes)] #![feature(control_flow_enum)] +#![feature(min_specialization)] +#![feature(trusted_step)] #![recursion_limit = "512"] // For rustdoc #[macro_use] diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 7e85f5d5de2..6f97716e2e0 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -50,6 +50,7 @@ #![feature(associated_type_defaults)] #![feature(iter_zip)] #![feature(thread_local_const_init)] +#![feature(trusted_step)] #![recursion_limit = "512"] #[macro_use] diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs index 010da247b2e..647c368d2bb 100644 --- a/compiler/rustc_mir/src/lib.rs +++ b/compiler/rustc_mir/src/lib.rs @@ -31,6 +31,7 @@ #![feature(option_get_or_insert_default)] #![feature(once_cell)] #![feature(control_flow_enum)] +#![feature(trusted_step)] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index e4a71b52b78..99b854ff066 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -10,6 +10,8 @@ #![feature(bool_to_option)] #![feature(iter_zip)] #![feature(once_cell)] +#![feature(min_specialization)] +#![feature(trusted_step)] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index fdcb2293a41..4803148eba9 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -10,6 +10,8 @@ #![feature(in_band_lifetimes)] #![feature(iter_zip)] #![feature(nll)] +#![feature(min_specialization)] +#![feature(trusted_step)] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs index be72baefb9e..7df3804c986 100644 --- a/compiler/rustc_query_system/src/lib.rs +++ b/compiler/rustc_query_system/src/lib.rs @@ -6,6 +6,7 @@ #![feature(iter_zip)] #![feature(min_specialization)] #![feature(stmt_expr_attributes)] +#![feature(trusted_step)] #[macro_use] extern crate tracing; diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 0301b364591..39b7b36b853 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -21,6 +21,7 @@ #![feature(nll)] #![feature(min_specialization)] #![feature(thread_local_const_init)] +#![feature(trusted_step)] #[macro_use] extern crate rustc_macros; diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index 48ace9b65b6..a40de5ef18e 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -14,6 +14,8 @@ #![feature(never_type)] #![feature(associated_type_bounds)] #![feature(exhaustive_patterns)] +#![feature(min_specialization)] +#![feature(trusted_step)] use std::path::{Path, PathBuf}; diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 0dbcd483c45..3f4c8a72f1d 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -1,3 +1,6 @@ +#![feature(min_specialization)] +#![feature(trusted_step)] + #[macro_use] extern crate bitflags; #[macro_use] diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index 2a179f0b1d7..bfb27da505e 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -384,6 +384,8 @@ pub use self::traits::InPlaceIterable; #[unstable(feature = "trusted_len", issue = "37572")] pub use self::traits::TrustedLen; +#[unstable(feature = "trusted_step", issue = "85731")] +pub use self::traits::TrustedStep; #[stable(feature = "rust1", since = "1.0.0")] pub use self::traits::{ DoubleEndedIterator, ExactSizeIterator, Extend, FromIterator, IntoIterator, Product, Sum, diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index 63e6181cae2..bb7d3d04806 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -3,7 +3,16 @@ use crate::mem; use crate::ops::{self, Try}; -use super::{FusedIterator, TrustedLen, TrustedRandomAccess}; +use super::{FusedIterator, TrustedLen, TrustedRandomAccess, TrustedStep}; + +// Safety: All invariants are upheld. +macro_rules! unsafe_impl_trusted_step { + ($($type:ty)*) => {$( + #[unstable(feature = "trusted_step", issue = "85731")] + unsafe impl TrustedStep for $type {} + )*}; +} +unsafe_impl_trusted_step![char i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize]; /// Objects that have a notion of *successor* and *predecessor* operations. /// @@ -505,12 +514,24 @@ impl ExactSizeIterator for ops::RangeInclusive<$t> { } )*) } -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for ops::Range { +/// Specialization implementations for `Range`. +trait RangeIteratorImpl { + type Item; + + // Iterator + fn spec_next(&mut self) -> Option; + fn spec_nth(&mut self, n: usize) -> Option; + + // DoubleEndedIterator + fn spec_next_back(&mut self) -> Option; + fn spec_nth_back(&mut self, n: usize) -> Option; +} + +impl RangeIteratorImpl for ops::Range { type Item = A; #[inline] - fn next(&mut self) -> Option { + default fn spec_next(&mut self) -> Option { if self.start < self.end { let n = Step::forward_checked(self.start.clone(), 1).expect("`Step` invariants not upheld"); @@ -520,6 +541,107 @@ fn next(&mut self) -> Option { } } + #[inline] + default fn spec_nth(&mut self, n: usize) -> Option { + if let Some(plus_n) = Step::forward_checked(self.start.clone(), n) { + if plus_n < self.end { + self.start = + Step::forward_checked(plus_n.clone(), 1).expect("`Step` invariants not upheld"); + return Some(plus_n); + } + } + + self.start = self.end.clone(); + None + } + + #[inline] + default fn spec_next_back(&mut self) -> Option { + if self.start < self.end { + self.end = + Step::backward_checked(self.end.clone(), 1).expect("`Step` invariants not upheld"); + Some(self.end.clone()) + } else { + None + } + } + + #[inline] + default fn spec_nth_back(&mut self, n: usize) -> Option { + if let Some(minus_n) = Step::backward_checked(self.end.clone(), n) { + if minus_n > self.start { + self.end = + Step::backward_checked(minus_n, 1).expect("`Step` invariants not upheld"); + return Some(self.end.clone()); + } + } + + self.end = self.start.clone(); + None + } +} + +impl RangeIteratorImpl for ops::Range { + #[inline] + fn spec_next(&mut self) -> Option { + if self.start < self.end { + // SAFETY: just checked precondition + let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) }; + Some(mem::replace(&mut self.start, n)) + } else { + None + } + } + + #[inline] + fn spec_nth(&mut self, n: usize) -> Option { + if let Some(plus_n) = Step::forward_checked(self.start.clone(), n) { + if plus_n < self.end { + // SAFETY: just checked precondition + self.start = unsafe { Step::forward_unchecked(plus_n.clone(), 1) }; + return Some(plus_n); + } + } + + self.start = self.end.clone(); + None + } + + #[inline] + fn spec_next_back(&mut self) -> Option { + if self.start < self.end { + // SAFETY: just checked precondition + self.end = unsafe { Step::backward_unchecked(self.end.clone(), 1) }; + Some(self.end.clone()) + } else { + None + } + } + + #[inline] + fn spec_nth_back(&mut self, n: usize) -> Option { + if let Some(minus_n) = Step::backward_checked(self.end.clone(), n) { + if minus_n > self.start { + // SAFETY: just checked precondition + self.end = unsafe { Step::backward_unchecked(minus_n, 1) }; + return Some(self.end.clone()); + } + } + + self.end = self.start.clone(); + None + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for ops::Range { + type Item = A; + + #[inline] + fn next(&mut self) -> Option { + self.spec_next() + } + #[inline] fn size_hint(&self) -> (usize, Option) { if self.start < self.end { @@ -532,16 +654,7 @@ fn size_hint(&self) -> (usize, Option) { #[inline] fn nth(&mut self, n: usize) -> Option { - if let Some(plus_n) = Step::forward_checked(self.start.clone(), n) { - if plus_n < self.end { - self.start = - Step::forward_checked(plus_n.clone(), 1).expect("`Step` invariants not upheld"); - return Some(plus_n); - } - } - - self.start = self.end.clone(); - None + self.spec_nth(n) } #[inline] @@ -624,37 +737,36 @@ unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item impl DoubleEndedIterator for ops::Range { #[inline] fn next_back(&mut self) -> Option { - if self.start < self.end { - self.end = - Step::backward_checked(self.end.clone(), 1).expect("`Step` invariants not upheld"); - Some(self.end.clone()) - } else { - None - } + self.spec_next_back() } #[inline] fn nth_back(&mut self, n: usize) -> Option { - if let Some(minus_n) = Step::backward_checked(self.end.clone(), n) { - if minus_n > self.start { - self.end = - Step::backward_checked(minus_n, 1).expect("`Step` invariants not upheld"); - return Some(self.end.clone()); - } - } - - self.end = self.start.clone(); - None + self.spec_nth_back(n) } } -macro_rules! impl_trusted_len_for_range { - ($($type:ty)*) => {$( - #[unstable(feature = "trusted_len", issue = "37572")] - unsafe impl TrustedLen for ops::Range<$type> {} - )*} -} -impl_trusted_len_for_range![char i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize]; +// Safety: +// The following invariants for `Step::steps_between` exist: +// +// > * `steps_between(&a, &b) == Some(n)` only if `a <= b` +// > * Note that `a <= b` does _not_ imply `steps_between(&a, &b) != None`; +// > this is the case when it would require more than `usize::MAX` steps to +// > get to `b` +// > * `steps_between(&a, &b) == None` if `a > b` +// +// The first invariant is what is generally required for `TrustedLen` to be +// sound. The note addendum satisfies an additional `TrustedLen` invariant. +// +// > The upper bound must only be `None` if the actual iterator length is larger +// > than `usize::MAX` +// +// The second invariant logically follows the first so long as the `PartialOrd` +// implementation is correct; regardless it is explicitly stated. If `a < b` +// then `(0, Some(0))` is returned by `ops::Range::size_hint`. As such +// the second invariant is upheld. +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for ops::Range {} #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for ops::Range {} @@ -682,23 +794,38 @@ fn nth(&mut self, n: usize) -> Option { } } +// Safety: See above implementation for `ops::Range` +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for ops::RangeFrom {} + #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for ops::RangeFrom {} -macro_rules! impl_trusted_len_for_range_from { - ($($type:ty)*) => {$( - #[unstable(feature = "trusted_len", issue = "37572")] - unsafe impl TrustedLen for ops::RangeFrom<$type> {} - )*} -} -impl_trusted_len_for_range_from![char i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize]; +trait RangeInclusiveIteratorImpl { + type Item; -#[stable(feature = "inclusive_range", since = "1.26.0")] -impl Iterator for ops::RangeInclusive { + // Iterator + fn spec_next(&mut self) -> Option; + fn spec_try_fold(&mut self, init: B, f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try; + + // DoubleEndedIterator + fn spec_next_back(&mut self) -> Option; + fn spec_try_rfold(&mut self, init: B, f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try; +} + +impl RangeInclusiveIteratorImpl for ops::RangeInclusive { type Item = A; #[inline] - fn next(&mut self) -> Option { + default fn spec_next(&mut self) -> Option { if self.is_empty() { return None; } @@ -713,6 +840,182 @@ fn next(&mut self) -> Option { }) } + #[inline] + default fn spec_try_fold(&mut self, init: B, mut f: F) -> R + where + Self: Sized, + F: FnMut(B, A) -> R, + R: Try, + { + if self.is_empty() { + return try { init }; + } + + let mut accum = init; + + while self.start < self.end { + let n = + Step::forward_checked(self.start.clone(), 1).expect("`Step` invariants not upheld"); + let n = mem::replace(&mut self.start, n); + accum = f(accum, n)?; + } + + self.exhausted = true; + + if self.start == self.end { + accum = f(accum, self.start.clone())?; + } + + try { accum } + } + + #[inline] + default fn spec_next_back(&mut self) -> Option { + if self.is_empty() { + return None; + } + let is_iterating = self.start < self.end; + Some(if is_iterating { + let n = + Step::backward_checked(self.end.clone(), 1).expect("`Step` invariants not upheld"); + mem::replace(&mut self.end, n) + } else { + self.exhausted = true; + self.end.clone() + }) + } + + #[inline] + default fn spec_try_rfold(&mut self, init: B, mut f: F) -> R + where + Self: Sized, + F: FnMut(B, A) -> R, + R: Try, + { + if self.is_empty() { + return try { init }; + } + + let mut accum = init; + + while self.start < self.end { + let n = + Step::backward_checked(self.end.clone(), 1).expect("`Step` invariants not upheld"); + let n = mem::replace(&mut self.end, n); + accum = f(accum, n)?; + } + + self.exhausted = true; + + if self.start == self.end { + accum = f(accum, self.start.clone())?; + } + + try { accum } + } +} + +impl RangeInclusiveIteratorImpl for ops::RangeInclusive { + #[inline] + fn spec_next(&mut self) -> Option { + if self.is_empty() { + return None; + } + let is_iterating = self.start < self.end; + Some(if is_iterating { + // SAFETY: just checked precondition + let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) }; + mem::replace(&mut self.start, n) + } else { + self.exhausted = true; + self.start.clone() + }) + } + + #[inline] + fn spec_try_fold(&mut self, init: B, mut f: F) -> R + where + Self: Sized, + F: FnMut(B, T) -> R, + R: Try, + { + if self.is_empty() { + return try { init }; + } + + let mut accum = init; + + while self.start < self.end { + // SAFETY: just checked precondition + let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) }; + let n = mem::replace(&mut self.start, n); + accum = f(accum, n)?; + } + + self.exhausted = true; + + if self.start == self.end { + accum = f(accum, self.start.clone())?; + } + + try { accum } + } + + #[inline] + fn spec_next_back(&mut self) -> Option { + if self.is_empty() { + return None; + } + let is_iterating = self.start < self.end; + Some(if is_iterating { + // SAFETY: just checked precondition + let n = unsafe { Step::backward_unchecked(self.end.clone(), 1) }; + mem::replace(&mut self.end, n) + } else { + self.exhausted = true; + self.end.clone() + }) + } + + #[inline] + fn spec_try_rfold(&mut self, init: B, mut f: F) -> R + where + Self: Sized, + F: FnMut(B, T) -> R, + R: Try, + { + if self.is_empty() { + return try { init }; + } + + let mut accum = init; + + while self.start < self.end { + // SAFETY: just checked precondition + let n = unsafe { Step::backward_unchecked(self.end.clone(), 1) }; + let n = mem::replace(&mut self.end, n); + accum = f(accum, n)?; + } + + self.exhausted = true; + + if self.start == self.end { + accum = f(accum, self.start.clone())?; + } + + try { accum } + } +} + +#[stable(feature = "inclusive_range", since = "1.26.0")] +impl Iterator for ops::RangeInclusive { + type Item = A; + + #[inline] + fn next(&mut self) -> Option { + self.spec_next() + } + #[inline] fn size_hint(&self) -> (usize, Option) { if self.is_empty() { @@ -754,32 +1057,13 @@ fn nth(&mut self, n: usize) -> Option { } #[inline] - fn try_fold(&mut self, init: B, mut f: F) -> R + fn try_fold(&mut self, init: B, f: F) -> R where Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try, { - if self.is_empty() { - return try { init }; - } - - let mut accum = init; - - while self.start < self.end { - let n = - Step::forward_checked(self.start.clone(), 1).expect("`Step` invariants not upheld"); - let n = mem::replace(&mut self.start, n); - accum = f(accum, n)?; - } - - self.exhausted = true; - - if self.start == self.end { - accum = f(accum, self.start.clone())?; - } - - try { accum } + self.spec_try_fold(init, f) } #[inline] @@ -816,18 +1100,7 @@ fn max(mut self) -> Option { impl DoubleEndedIterator for ops::RangeInclusive { #[inline] fn next_back(&mut self) -> Option { - if self.is_empty() { - return None; - } - let is_iterating = self.start < self.end; - Some(if is_iterating { - let n = - Step::backward_checked(self.end.clone(), 1).expect("`Step` invariants not upheld"); - mem::replace(&mut self.end, n) - } else { - self.exhausted = true; - self.end.clone() - }) + self.spec_next_back() } #[inline] @@ -859,32 +1132,13 @@ fn nth_back(&mut self, n: usize) -> Option { } #[inline] - fn try_rfold(&mut self, init: B, mut f: F) -> R + fn try_rfold(&mut self, init: B, f: F) -> R where Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try, { - if self.is_empty() { - return try { init }; - } - - let mut accum = init; - - while self.start < self.end { - let n = - Step::backward_checked(self.end.clone(), 1).expect("`Step` invariants not upheld"); - let n = mem::replace(&mut self.end, n); - accum = f(accum, n)?; - } - - self.exhausted = true; - - if self.start == self.end { - accum = f(accum, self.start.clone())?; - } - - try { accum } + self.spec_try_rfold(init, f) } #[inline] @@ -902,13 +1156,9 @@ fn ok(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result { } } -macro_rules! impl_trusted_len_for_range_inclusive { - ($($type:ty)*) => {$( - #[unstable(feature = "trusted_len", issue = "37572")] - unsafe impl TrustedLen for ops::RangeInclusive<$type> {} - )*} -} -impl_trusted_len_for_range_inclusive![char i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize]; +// Safety: See above implementation for `ops::Range` +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for ops::RangeInclusive {} #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for ops::RangeInclusive {} diff --git a/library/core/src/iter/traits/marker.rs b/library/core/src/iter/traits/marker.rs index 22b5ffdf886..ebf37f97bc6 100644 --- a/library/core/src/iter/traits/marker.rs +++ b/library/core/src/iter/traits/marker.rs @@ -1,3 +1,5 @@ +use crate::iter::Step; + /// An iterator that always continues to yield `None` when exhausted. /// /// Calling next on a fused iterator that has returned `None` once is guaranteed @@ -55,3 +57,18 @@ unsafe impl TrustedLen for &mut I {} #[unstable(issue = "none", feature = "inplace_iteration")] #[doc(hidden)] pub unsafe trait InPlaceIterable: Iterator {} + +/// A type that upholds all invariants of [`Step`]. +/// +/// The invariants of [`Step::steps_between()`] are a superset of the invariants +/// of [`TrustedLen`]. As such, [`TrustedLen`] is implemented for all range +/// types with the same generic type argument. +/// +/// # Safety +/// +/// The implementation of [`Step`] for the given type must guarantee all +/// invariants of all methods are upheld. See the [`Step`] trait's documentation +/// 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 {} diff --git a/library/core/src/iter/traits/mod.rs b/library/core/src/iter/traits/mod.rs index 880f8d831fd..ffd745a46b1 100644 --- a/library/core/src/iter/traits/mod.rs +++ b/library/core/src/iter/traits/mod.rs @@ -13,5 +13,7 @@ pub use self::iterator::Iterator; #[unstable(issue = "none", feature = "inplace_iteration")] pub use self::marker::InPlaceIterable; +#[unstable(feature = "trusted_step", issue = "85731")] +pub use self::marker::TrustedStep; #[stable(feature = "rust1", since = "1.0.0")] pub use self::marker::{FusedIterator, TrustedLen};