Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 9a72afa

Browse files
committedMay 30, 2021
Auto merge of #83772 - jhpratt:revamp-step-trait, r=Mark-Simulacrum
Make `Step` trait safe to implement This PR makes a few modifications to the `Step` trait that I believe better position it for stabilization in the short term. In particular, 1. `unsafe trait TrustedStep` is introduced, indicating that the implementation of `Step` for a given type upholds all stated invariants (which have remained unchanged). This is gated behind a new `trusted_step` feature, as stabilization is realistically blocked on min_specialization. 2. The `Step` trait is internally specialized on the `TrustedStep` trait, which avoids a serious performance regression. 3. `TrustedLen` is implemented for `T: TrustedStep` as the latter's invariants subsume the former's. 4. The `Step` trait is no longer `unsafe`, as the invariants must not be relied upon by unsafe code (unless the type implements `TrustedStep`). 5. `TrustedStep` is implemented for all types that implement `Step` in the standard library and compiler. 6. The `step_trait_ext` feature is merged into the `step_trait` feature. I was unable to find any reasoning for the features being split; the `_unchecked` methods need not necessarily be stabilized at the same time, but I think it is useful to have them under the same feature flag. All existing implementations of `Step` will be broken, as it is not possible to `unsafe impl` a safe trait. Given this trait only exists on nightly, I feel this breakage is acceptable. The blanket `impl<T: Step> TrustedLen for T` will likely cause some minor breakage, but this should be covered by the equivalent impl for `TrustedStep`. Hopefully these changes are sufficient to place `Step` in decent position for stabilization, which would allow user-defined types to be used with `a..b` syntax.
2 parents 84b1005 + 741b9a4 commit 9a72afa

File tree

20 files changed

+423
-122
lines changed

20 files changed

+423
-122
lines changed
 

‎compiler/rustc_ast/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
#![feature(iter_zip)]
1818
#![feature(label_break_value)]
1919
#![feature(nll)]
20+
#![feature(min_specialization)]
21+
#![feature(trusted_step)]
2022
#![recursion_limit = "256"]
2123

2224
#[macro_use]

‎compiler/rustc_hir/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
#![cfg_attr(bootstrap, feature(extended_key_value_attributes))]
88
#![feature(in_band_lifetimes)]
99
#![feature(once_cell)]
10+
#![feature(min_specialization)]
11+
#![feature(trusted_step)]
1012
#![recursion_limit = "256"]
1113

1214
#[macro_use]

‎compiler/rustc_index/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#![feature(unboxed_closures)]
77
#![feature(test)]
88
#![feature(fn_traits)]
9+
#![feature(trusted_step)]
910

1011
pub mod bit_set;
1112
pub mod vec;

‎compiler/rustc_index/src/vec.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ impl Idx for u32 {
6565
/// `u32::MAX`. You can also customize things like the `Debug` impl,
6666
/// what traits are derived, and so forth via the macro.
6767
#[macro_export]
68-
#[allow_internal_unstable(step_trait, step_trait_ext, rustc_attrs)]
68+
#[allow_internal_unstable(step_trait, rustc_attrs)]
6969
macro_rules! newtype_index {
7070
// ---- public rules ----
7171

@@ -184,7 +184,7 @@ macro_rules! newtype_index {
184184
}
185185
}
186186

187-
unsafe impl ::std::iter::Step for $type {
187+
impl ::std::iter::Step for $type {
188188
#[inline]
189189
fn steps_between(start: &Self, end: &Self) -> Option<usize> {
190190
<usize as ::std::iter::Step>::steps_between(
@@ -204,6 +204,9 @@ macro_rules! newtype_index {
204204
}
205205
}
206206

207+
// Safety: The implementation of `Step` upholds all invariants.
208+
unsafe impl ::std::iter::TrustedStep for $type {}
209+
207210
impl From<$type> for u32 {
208211
#[inline]
209212
fn from(v: $type) -> u32 {

‎compiler/rustc_infer/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
#![feature(never_type)]
2323
#![feature(in_band_lifetimes)]
2424
#![feature(control_flow_enum)]
25+
#![feature(min_specialization)]
26+
#![feature(trusted_step)]
2527
#![recursion_limit = "512"] // For rustdoc
2628

2729
#[macro_use]

‎compiler/rustc_middle/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
#![feature(associated_type_defaults)]
5151
#![feature(iter_zip)]
5252
#![feature(thread_local_const_init)]
53+
#![feature(trusted_step)]
5354
#![recursion_limit = "512"]
5455

5556
#[macro_use]

‎compiler/rustc_mir/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ Rust MIR: a lowered representation of Rust.
3131
#![feature(option_get_or_insert_default)]
3232
#![feature(once_cell)]
3333
#![feature(control_flow_enum)]
34+
#![feature(trusted_step)]
3435
#![recursion_limit = "256"]
3536

3637
#[macro_use]

‎compiler/rustc_mir_build/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
#![feature(bool_to_option)]
1111
#![feature(iter_zip)]
1212
#![feature(once_cell)]
13+
#![feature(min_specialization)]
14+
#![feature(trusted_step)]
1315
#![recursion_limit = "256"]
1416

1517
#[macro_use]

‎compiler/rustc_passes/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
#![feature(in_band_lifetimes)]
1111
#![feature(iter_zip)]
1212
#![feature(nll)]
13+
#![feature(min_specialization)]
14+
#![feature(trusted_step)]
1315
#![recursion_limit = "256"]
1416

1517
#[macro_use]

‎compiler/rustc_query_system/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#![feature(iter_zip)]
77
#![feature(min_specialization)]
88
#![feature(stmt_expr_attributes)]
9+
#![feature(trusted_step)]
910

1011
#[macro_use]
1112
extern crate tracing;

‎compiler/rustc_span/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#![feature(nll)]
2222
#![feature(min_specialization)]
2323
#![feature(thread_local_const_init)]
24+
#![feature(trusted_step)]
2425

2526
#[macro_use]
2627
extern crate rustc_macros;

‎compiler/rustc_target/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
#![feature(never_type)]
1515
#![feature(associated_type_bounds)]
1616
#![feature(exhaustive_patterns)]
17+
#![feature(min_specialization)]
18+
#![feature(trusted_step)]
1719

1820
use std::path::{Path, PathBuf};
1921

‎compiler/rustc_type_ir/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
#![feature(min_specialization)]
2+
#![feature(trusted_step)]
3+
14
#[macro_use]
25
extern crate bitflags;
36
#[macro_use]

‎library/core/src/iter/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,8 @@ pub use self::traits::FusedIterator;
384384
pub use self::traits::InPlaceIterable;
385385
#[unstable(feature = "trusted_len", issue = "37572")]
386386
pub use self::traits::TrustedLen;
387+
#[unstable(feature = "trusted_step", issue = "85731")]
388+
pub use self::traits::TrustedStep;
387389
#[stable(feature = "rust1", since = "1.0.0")]
388390
pub use self::traits::{
389391
DoubleEndedIterator, ExactSizeIterator, Extend, FromIterator, IntoIterator, Product, Sum,

‎library/core/src/iter/range.rs

Lines changed: 360 additions & 108 deletions
Large diffs are not rendered by default.

‎library/core/src/iter/traits/marker.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use crate::iter::Step;
2+
13
/// An iterator that always continues to yield `None` when exhausted.
24
///
35
/// Calling next on a fused iterator that has returned `None` once is guaranteed
@@ -55,3 +57,18 @@ unsafe impl<I: TrustedLen + ?Sized> TrustedLen for &mut I {}
5557
#[unstable(issue = "none", feature = "inplace_iteration")]
5658
#[doc(hidden)]
5759
pub unsafe trait InPlaceIterable: Iterator {}
60+
61+
/// A type that upholds all invariants of [`Step`].
62+
///
63+
/// The invariants of [`Step::steps_between()`] are a superset of the invariants
64+
/// of [`TrustedLen`]. As such, [`TrustedLen`] is implemented for all range
65+
/// types with the same generic type argument.
66+
///
67+
/// # Safety
68+
///
69+
/// The implementation of [`Step`] for the given type must guarantee all
70+
/// invariants of all methods are upheld. See the [`Step`] trait's documentation
71+
/// for details. Consumers are free to rely on the invariants in unsafe code.
72+
#[unstable(feature = "trusted_step", issue = "85731")]
73+
#[rustc_specialization_trait]
74+
pub unsafe trait TrustedStep: Step {}

‎library/core/src/iter/traits/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,7 @@ pub use self::exact_size::ExactSizeIterator;
1313
pub use self::iterator::Iterator;
1414
#[unstable(issue = "none", feature = "inplace_iteration")]
1515
pub use self::marker::InPlaceIterable;
16+
#[unstable(feature = "trusted_step", issue = "85731")]
17+
pub use self::marker::TrustedStep;
1618
#[stable(feature = "rust1", since = "1.0.0")]
1719
pub use self::marker::{FusedIterator, TrustedLen};

‎library/core/tests/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
#![feature(maybe_uninit_write_slice)]
4141
#![feature(min_specialization)]
4242
#![feature(step_trait)]
43-
#![feature(step_trait_ext)]
4443
#![feature(str_internals)]
4544
#![feature(test)]
4645
#![feature(trusted_len)]

‎src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@
3232
scope 5 {
3333
debug i => _15; // in scope 5 at $DIR/remove_storage_markers.rs:8:9: 8:10
3434
}
35+
scope 7 (inlined iter::range::<impl Iterator for std::ops::Range<i32>>::next) { // at $DIR/remove_storage_markers.rs:8:14: 8:19
36+
debug self => _9; // in scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
37+
let mut _18: &mut std::ops::Range<i32>; // in scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
38+
}
3539
}
3640
}
3741
scope 6 (inlined <std::ops::Range<i32> as IntoIterator>::into_iter) { // at $DIR/remove_storage_markers.rs:8:14: 8:19
@@ -61,19 +65,15 @@
6165
- StorageLive(_10); // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19
6266
_10 = &mut _4; // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19
6367
_9 = &mut (*_10); // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19
64-
_8 = <std::ops::Range<i32> as Iterator>::next(move _9) -> bb2; // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19
68+
- StorageLive(_18); // scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
69+
_18 = &mut (*_9); // scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
70+
_8 = <std::ops::Range<i32> as iter::range::RangeIteratorImpl>::spec_next(move _18) -> bb4; // scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
6571
// mir::Constant
6672
// + span: $DIR/remove_storage_markers.rs:8:14: 8:19
67-
// + literal: Const { ty: for<'r> fn(&'r mut std::ops::Range<i32>) -> std::option::Option<<std::ops::Range<i32> as std::iter::Iterator>::Item> {<std::ops::Range<i32> as std::iter::Iterator>::next}, val: Value(Scalar(<ZST>)) }
73+
// + literal: Const { ty: for<'r> fn(&'r mut std::ops::Range<i32>) -> std::option::Option<<std::ops::Range<i32> as std::iter::range::RangeIteratorImpl>::Item> {<std::ops::Range<i32> as std::iter::range::RangeIteratorImpl>::spec_next}, val: Value(Scalar(<ZST>)) }
6874
}
6975

7076
bb2: {
71-
- StorageDead(_9); // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19
72-
_11 = discriminant(_8); // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
73-
switchInt(move _11) -> [0_isize: bb3, otherwise: bb4]; // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
74-
}
75-
76-
bb3: {
7777
_0 = const (); // scope 3 at $DIR/remove_storage_markers.rs:8:5: 10:6
7878
- StorageDead(_10); // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19
7979
- StorageDead(_8); // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19
@@ -85,7 +85,7 @@
8585
return; // scope 0 at $DIR/remove_storage_markers.rs:11:2: 11:2
8686
}
8787

88-
bb4: {
88+
bb3: {
8989
- StorageLive(_12); // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
9090
_12 = ((_8 as Some).0: i32); // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
9191
- StorageLive(_13); // scope 4 at $DIR/remove_storage_markers.rs:8:9: 8:10
@@ -111,5 +111,12 @@
111111
- StorageDead(_6); // scope 2 at $DIR/remove_storage_markers.rs:10:5: 10:6
112112
goto -> bb1; // scope 2 at $DIR/remove_storage_markers.rs:8:5: 10:6
113113
}
114+
115+
bb4: {
116+
- StorageDead(_18); // scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
117+
- StorageDead(_9); // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19
118+
_11 = discriminant(_8); // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
119+
switchInt(move _11) -> [0_isize: bb2, otherwise: bb3]; // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
120+
}
114121
}
115122

‎src/test/ui/impl-trait/example-calendar.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
#![feature(fn_traits,
55
step_trait,
6-
step_trait_ext,
76
unboxed_closures,
87
)]
98

@@ -157,7 +156,7 @@ impl<'a, 'b> std::ops::Add<&'b NaiveDate> for &'a NaiveDate {
157156
}
158157
}
159158

160-
unsafe impl std::iter::Step for NaiveDate {
159+
impl std::iter::Step for NaiveDate {
161160
fn steps_between(_: &Self, _: &Self) -> Option<usize> {
162161
unimplemented!()
163162
}

0 commit comments

Comments
 (0)
Please sign in to comment.