Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove unsound TrustedRandomAccess implementations #85874

Merged
merged 8 commits into from
Jul 29, 2021
15 changes: 8 additions & 7 deletions library/alloc/src/collections/vec_deque/iter.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use core::fmt;
use core::iter::{FusedIterator, TrustedLen, TrustedRandomAccess};
use core::iter::{FusedIterator, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce};
use core::ops::Try;

use super::{count, wrap_index, RingSlices};
Expand Down Expand Up @@ -104,11 +104,8 @@ impl<'a, T> Iterator for Iter<'a, T> {

#[inline]
#[doc(hidden)]
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
where
Self: TrustedRandomAccess,
{
// Safety: The TrustedRandomAccess contract requires that callers only pass an index
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
// Safety: The TrustedRandomAccess contract requires that callers only pass an index
Copy link
Member

Choose a reason for hiding this comment

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

Disclaimer: I'm still unfamiliar with __iterator_get_unchecked and the related specializations so I'm going to be asking some probably silly questions:

Is this comment still relevant?

Also, why doesn't this need a where Self: TrustedRandomAccessNoCoerce bound?

Copy link
Member

Choose a reason for hiding this comment

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

Is this comment still relevant?

It's unsafe code so it should have a SAFETY comment. And it's still correct since this method should only be called by specializing impls relying on TrustedRandomAccess.

Also, why doesn't this need a where Self: TrustedRandomAccessNoCoerce bound?

TrustedRandomAccess is implemented unconditionally for this iterator so the bound would be always true.

But maybe it would still make sense for consistency or in case the trait impls are removed at some point. But I don't think it's needed for safety here.

Copy link
Member

Choose a reason for hiding this comment

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

Aah, I see. I'm assuming that means that all the other __iterator_get_unchecked impls that leave of that bound also have it similarly implied? If that's the case I'd like to see those all have the bound added explicitly though that doesn't need to happen in this PR, but them being left off in some cases and not others seems somewhat confusing and could add to the maintenance burden.

Copy link
Member Author

@steffahn steffahn Jul 27, 2021

Choose a reason for hiding this comment

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

But maybe it would still make sense for consistency

Actually consistency is the reason I removed the bound. Initially I had left the Self: TrustedRandomAccess bounds in place and relied on type errors to point out all the places that needed changing (to Self: TrustedRandomAccessNoCoerce). Afterwards, grepping for and going through all the remaining Self: TrustedRandomAccess occurrences (just to be sure) I came acoss this case (and another one, too IIRC) that didn’t produce an error message: Surprised me as well, I eventually figured out that the bound was entirely useless anyways. Looking at other iterators in std, it seems to have be commonly done without any Self: TrustedRandomAccess bound before when those weren’t necessary. On all kinds of iterators, e.g. all the ones on slices (e.g. also the ones from .chunks(…) and similar). IIRC, with the changes of this PR all the superfluous bounds are consistently gone.

Copy link
Member Author

Choose a reason for hiding this comment

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

If that's the case I'd like to see those all have the bound added explicitly though that doesn't need to happen in this PR, but them being left off in some cases and not others seems somewhat confusing and could add to the maintenance burden.

So as far as I know, after this PR only those implementations that need the bound will have it. Don’t quote me on that, I’d need to double check if this is indeed true. This very PR demonstrated that leaving the bounds off can actually help maintainance in some cases, like it helped me being able to use error messages to find all the places that needed to change, like I described above. The redundant Self: TrustedRandomAccess binding didn’t generate any error messages though, so their existence made the refactor a bit harder (since I needed to grep for things in order to fix those redundant bindings (for now, by removing them instead of changing them to Self: TrustedRandomAccesNoCoerce)).

Copy link
Member Author

Choose a reason for hiding this comment

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

Here’s a “grep” example. Looks like there are about 15 Iterators without the bound on the method (on the branch of this PR, so before this PR there were 13 Iterators without the bound)

~/forks/rust/library   fix_unsound_zip_optimization  rg 'fn __iterator_' -A3
core/src/iter/range.rs
677:    unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
678-    where
679-        Self: TrustedRandomAccessNoCoerce,
680-    {

core/src/str/iter.rs
299:    unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> u8 {
300-        // SAFETY: the caller must uphold the safety contract
301-        // for `Iterator::__iterator_get_unchecked`.
302-        unsafe { self.0.__iterator_get_unchecked(idx) }

core/src/iter/adapters/fuse.rs
119:    unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
120-    where
121-        Self: TrustedRandomAccessNoCoerce,
122-    {

core/src/iter/adapters/enumerate.rs
117:    unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item
118-    where
119-        Self: TrustedRandomAccessNoCoerce,
120-    {

core/src/iter/adapters/map.rs
128:    unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> B
129-    where
130-        Self: TrustedRandomAccessNoCoerce,
131-    {

core/src/iter/adapters/cloned.rs
64:    unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T
65-    where
66-        Self: TrustedRandomAccessNoCoerce,
67-    {

core/src/slice/iter.rs
1268:    unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
1269-        // SAFETY: since the caller guarantees that `i` is in bounds,
1270-        // which means that `i` cannot overflow an `isize`, and the
1271-        // slice created by `from_raw_parts` is a subslice of `self.v`
--
1423:    unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
1424-        let start = idx * self.chunk_size;
1425-        let end = match start.checked_add(self.chunk_size) {
1426-            None => self.v.len(),
--
1588:    unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
1589-        let start = idx * self.chunk_size;
1590-        let end = match start.checked_add(self.chunk_size) {
1591-            None => self.v.len(),
--
1759:    unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
1760-        let start = idx * self.chunk_size;
1761-        // SAFETY: mostly identical to `Chunks::__iterator_get_unchecked`.
1762-        unsafe { from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) }
--
1911:    unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
1912-        let start = idx * self.chunk_size;
1913-        // SAFETY: see comments for `ChunksMut::__iterator_get_unchecked`.
1914-        unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) }
--
2172:    unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> &'a [T; N] {
2173-        // SAFETY: The safety guarantees of `__iterator_get_unchecked` are
2174-        // transferred to the caller.
2175-        unsafe { self.iter.__iterator_get_unchecked(i) }
--
2289:    unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> &'a mut [T; N] {
2290-        // SAFETY: The safety guarantees of `__iterator_get_unchecked` are transferred to
2291-        // the caller.
2292-        unsafe { self.iter.__iterator_get_unchecked(i) }
--
2435:    unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
2436-        let end = self.v.len() - idx * self.chunk_size;
2437-        let start = match end.checked_sub(self.chunk_size) {
2438-            None => 0,
--
2597:    unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
2598-        let end = self.v.len() - idx * self.chunk_size;
2599-        let start = match end.checked_sub(self.chunk_size) {
2600-            None => 0,
--
2761:    unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
2762-        let end = self.v.len() - idx * self.chunk_size;
2763-        let start = end - self.chunk_size;
2764-        // SAFETY:
--
2919:    unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
2920-        let end = self.v.len() - idx * self.chunk_size;
2921-        let start = end - self.chunk_size;
2922-        // SAFETY: see comments for `RChunksMut::__iterator_get_unchecked`.

core/src/iter/adapters/copied.rs
80:    unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T
81-    where
82-        Self: TrustedRandomAccessNoCoerce,
83-    {

core/src/iter/adapters/zip.rs
92:    unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
93-    where
94-        Self: TrustedRandomAccessNoCoerce,
95-    {

core/src/iter/traits/iterator.rs
3492:    unsafe fn __iterator_get_unchecked(&mut self, _idx: usize) -> Self::Item
3493-    where
3494-        Self: TrustedRandomAccessNoCoerce,
3495-    {

core/src/slice/iter/macros.rs
321:            unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
322-                // SAFETY: the caller must guarantee that `i` is in bounds of
323-                // the underlying slice, so `i` cannot overflow an `isize`, and
324-                // the returned references is guaranteed to refer to an element

alloc/src/collections/vec_deque/iter.rs
107:    unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
108-        // Safety: The TrustedRandomAccess contract requires that callers only pass an index
109-        // that is in bounds.
110-        unsafe {

alloc/src/collections/vec_deque/iter_mut.rs
93:    unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
94-        // Safety: The TrustedRandomAccess contract requires that callers only pass an index
95-        // that is in bounds.
96-        unsafe {

alloc/src/vec/into_iter.rs
169:    unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> Self::Item
170-    where
171-        Self: TrustedRandomAccessNoCoerce,
172-    {

// that is in bounds.
unsafe {
let idx = wrap_index(self.tail.wrapping_add(idx), self.ring.len());
Expand Down Expand Up @@ -177,6 +174,10 @@ unsafe impl<T> TrustedLen for Iter<'_, T> {}

#[doc(hidden)]
#[unstable(feature = "trusted_random_access", issue = "none")]
unsafe impl<T> TrustedRandomAccess for Iter<'_, T> {
unsafe impl<T> TrustedRandomAccess for Iter<'_, T> {}

#[doc(hidden)]
#[unstable(feature = "trusted_random_access", issue = "none")]
unsafe impl<T> TrustedRandomAccessNoCoerce for Iter<'_, T> {
const MAY_HAVE_SIDE_EFFECT: bool = false;
}
15 changes: 8 additions & 7 deletions library/alloc/src/collections/vec_deque/iter_mut.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use core::fmt;
use core::iter::{FusedIterator, TrustedLen, TrustedRandomAccess};
use core::iter::{FusedIterator, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce};
use core::marker::PhantomData;

use super::{count, wrap_index, RingSlices};
Expand Down Expand Up @@ -90,11 +90,8 @@ impl<'a, T> Iterator for IterMut<'a, T> {

#[inline]
#[doc(hidden)]
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
where
Self: TrustedRandomAccess,
{
// Safety: The TrustedRandomAccess contract requires that callers only pass an index
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
// Safety: The TrustedRandomAccess contract requires that callers only pass an index
// that is in bounds.
unsafe {
let idx = wrap_index(self.tail.wrapping_add(idx), self.ring.len());
Expand Down Expand Up @@ -146,6 +143,10 @@ unsafe impl<T> TrustedLen for IterMut<'_, T> {}

#[doc(hidden)]
#[unstable(feature = "trusted_random_access", issue = "none")]
unsafe impl<T> TrustedRandomAccess for IterMut<'_, T> {
unsafe impl<T> TrustedRandomAccess for IterMut<'_, T> {}

#[doc(hidden)]
#[unstable(feature = "trusted_random_access", issue = "none")]
unsafe impl<T> TrustedRandomAccessNoCoerce for IterMut<'_, T> {
const MAY_HAVE_SIDE_EFFECT: bool = false;
}
11 changes: 8 additions & 3 deletions library/alloc/src/vec/into_iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ use crate::alloc::{Allocator, Global};
use crate::raw_vec::RawVec;
use core::fmt;
use core::intrinsics::arith_offset;
use core::iter::{FusedIterator, InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccess};
use core::iter::{
FusedIterator, InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccessNoCoerce,
};
use core::marker::PhantomData;
use core::mem::{self};
use core::ptr::{self, NonNull};
Expand Down Expand Up @@ -166,7 +168,7 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
#[doc(hidden)]
unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> Self::Item
where
Self: TrustedRandomAccess,
Self: TrustedRandomAccessNoCoerce,
{
// SAFETY: the caller must guarantee that `i` is in bounds of the
// `Vec<T>`, so `i` cannot overflow an `isize`, and the `self.ptr.add(i)`
Expand Down Expand Up @@ -219,7 +221,10 @@ unsafe impl<T, A: Allocator> TrustedLen for IntoIter<T, A> {}
#[unstable(issue = "none", feature = "std_internals")]
// T: Copy as approximation for !Drop since get_unchecked does not advance self.ptr
// and thus we can't implement drop-handling
unsafe impl<T, A: Allocator> TrustedRandomAccess for IntoIter<T, A>
//
// TrustedRandomAccess (without NoCoerce) must not be implemented because
// subtypes/supertypes of `T` might not be `Copy`
unsafe impl<T, A: Allocator> TrustedRandomAccessNoCoerce for IntoIter<T, A>
where
T: Copy,
{
Expand Down
21 changes: 19 additions & 2 deletions library/alloc/src/vec/source_iter_marker.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use core::iter::{InPlaceIterable, SourceIter, TrustedRandomAccess};
use core::iter::{InPlaceIterable, SourceIter, TrustedRandomAccessNoCoerce};
use core::mem::{self, ManuallyDrop};
use core::ptr::{self};

Expand Down Expand Up @@ -71,6 +71,18 @@ where
// drop any remaining values at the tail of the source
// but prevent drop of the allocation itself once IntoIter goes out of scope
// if the drop panics then we also leak any elements collected into dst_buf
//
// FIXME: Since `SpecInPlaceCollect::collect_in_place` above might use
// `__iterator_get_unchecked` internally, this call might be operating on
// a `vec::IntoIter` with incorrect internal state regarding which elements
// have already been “consumed”. However, the `TrustedRandomIteratorNoCoerce`
// implementation of `vec::IntoIter` is only present if the `Vec` elements
// don’t have a destructor, so it doesn’t matter if elements are “dropped multiple times”
// in this case.
// This argument technically currently lacks justification from the `# Safety` docs for
// `SourceIter`/`InPlaceIterable` and/or `TrustedRandomAccess`, so it might be possible that
// someone could inadvertently create new library unsoundness
// involving this `.forget_allocation_drop_remaining()` call.
src.forget_allocation_drop_remaining();

let vec = unsafe { Vec::from_raw_parts(dst_buf, len, cap) };
Expand Down Expand Up @@ -101,6 +113,11 @@ fn write_in_place_with_drop<T>(
trait SpecInPlaceCollect<T, I>: Iterator<Item = T> {
/// Collects an iterator (`self`) into the destination buffer (`dst`) and returns the number of items
/// collected. `end` is the last writable element of the allocation and used for bounds checks.
///
/// This method is specialized and one of its implementations makes use of
/// `Iterator::__iterator_get_unchecked` calls with a `TrustedRandomAccessNoCoerce` bound
/// on `I` which means the caller of this method must take the safety conditions
/// of that trait into consideration.
fn collect_in_place(&mut self, dst: *mut T, end: *const T) -> usize;
}

Expand All @@ -124,7 +141,7 @@ where

impl<T, I> SpecInPlaceCollect<T, I> for I
where
I: Iterator<Item = T> + TrustedRandomAccess,
I: Iterator<Item = T> + TrustedRandomAccessNoCoerce,
{
#[inline]
fn collect_in_place(&mut self, dst_buf: *mut T, end: *const T) -> usize {
Expand Down
14 changes: 10 additions & 4 deletions library/core/src/iter/adapters/cloned.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use crate::iter::adapters::{zip::try_get_unchecked, TrustedRandomAccess};
use crate::iter::adapters::{
zip::try_get_unchecked, TrustedRandomAccess, TrustedRandomAccessNoCoerce,
};
use crate::iter::{FusedIterator, TrustedLen};
use crate::ops::Try;

Expand Down Expand Up @@ -61,7 +63,7 @@ where
#[doc(hidden)]
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T
where
Self: TrustedRandomAccess,
Self: TrustedRandomAccessNoCoerce,
{
// SAFETY: the caller must uphold the contract for
// `Iterator::__iterator_get_unchecked`.
Expand Down Expand Up @@ -121,9 +123,13 @@ where

#[doc(hidden)]
#[unstable(feature = "trusted_random_access", issue = "none")]
unsafe impl<I> TrustedRandomAccess for Cloned<I>
unsafe impl<I> TrustedRandomAccess for Cloned<I> where I: TrustedRandomAccess {}

#[doc(hidden)]
#[unstable(feature = "trusted_random_access", issue = "none")]
unsafe impl<I> TrustedRandomAccessNoCoerce for Cloned<I>
where
I: TrustedRandomAccess,
I: TrustedRandomAccessNoCoerce,
{
const MAY_HAVE_SIDE_EFFECT: bool = true;
}
Expand Down
14 changes: 10 additions & 4 deletions library/core/src/iter/adapters/copied.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use crate::iter::adapters::{zip::try_get_unchecked, TrustedRandomAccess};
use crate::iter::adapters::{
zip::try_get_unchecked, TrustedRandomAccess, TrustedRandomAccessNoCoerce,
};
use crate::iter::{FusedIterator, TrustedLen};
use crate::ops::Try;

Expand Down Expand Up @@ -77,7 +79,7 @@ where
#[doc(hidden)]
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T
where
Self: TrustedRandomAccess,
Self: TrustedRandomAccessNoCoerce,
{
// SAFETY: the caller must uphold the contract for
// `Iterator::__iterator_get_unchecked`.
Expand Down Expand Up @@ -137,9 +139,13 @@ where

#[doc(hidden)]
#[unstable(feature = "trusted_random_access", issue = "none")]
unsafe impl<I> TrustedRandomAccess for Copied<I>
unsafe impl<I> TrustedRandomAccess for Copied<I> where I: TrustedRandomAccess {}

#[doc(hidden)]
#[unstable(feature = "trusted_random_access", issue = "none")]
unsafe impl<I> TrustedRandomAccessNoCoerce for Copied<I>
where
I: TrustedRandomAccess,
I: TrustedRandomAccessNoCoerce,
{
const MAY_HAVE_SIDE_EFFECT: bool = I::MAY_HAVE_SIDE_EFFECT;
}
Expand Down
14 changes: 10 additions & 4 deletions library/core/src/iter/adapters/enumerate.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use crate::iter::adapters::{zip::try_get_unchecked, SourceIter, TrustedRandomAccess};
use crate::iter::adapters::{
zip::try_get_unchecked, SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce,
};
use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen};
use crate::ops::Try;

Expand Down Expand Up @@ -114,7 +116,7 @@ where
#[doc(hidden)]
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item
where
Self: TrustedRandomAccess,
Self: TrustedRandomAccessNoCoerce,
{
// SAFETY: the caller must uphold the contract for
// `Iterator::__iterator_get_unchecked`.
Expand Down Expand Up @@ -207,9 +209,13 @@ where

#[doc(hidden)]
#[unstable(feature = "trusted_random_access", issue = "none")]
unsafe impl<I> TrustedRandomAccess for Enumerate<I>
unsafe impl<I> TrustedRandomAccess for Enumerate<I> where I: TrustedRandomAccess {}

#[doc(hidden)]
#[unstable(feature = "trusted_random_access", issue = "none")]
unsafe impl<I> TrustedRandomAccessNoCoerce for Enumerate<I>
where
I: TrustedRandomAccess,
I: TrustedRandomAccessNoCoerce,
{
const MAY_HAVE_SIDE_EFFECT: bool = I::MAY_HAVE_SIDE_EFFECT;
}
Expand Down
11 changes: 8 additions & 3 deletions library/core/src/iter/adapters/fuse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::intrinsics;
use crate::iter::adapters::zip::try_get_unchecked;
use crate::iter::{
DoubleEndedIterator, ExactSizeIterator, FusedIterator, TrustedLen, TrustedRandomAccess,
TrustedRandomAccessNoCoerce,
};
use crate::ops::Try;

Expand Down Expand Up @@ -131,7 +132,7 @@ where
#[doc(hidden)]
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
where
Self: TrustedRandomAccess,
Self: TrustedRandomAccessNoCoerce,
{
match self.iter {
// SAFETY: the caller must uphold the contract for
Expand Down Expand Up @@ -221,9 +222,13 @@ unsafe impl<I> TrustedLen for Fuse<I> where I: TrustedLen {}
//
// This is safe to implement as `Fuse` is just forwarding these to the wrapped iterator `I`, which
// preserves these properties.
unsafe impl<I> TrustedRandomAccess for Fuse<I>
unsafe impl<I> TrustedRandomAccess for Fuse<I> where I: TrustedRandomAccess {}

#[doc(hidden)]
#[unstable(feature = "trusted_random_access", issue = "none")]
unsafe impl<I> TrustedRandomAccessNoCoerce for Fuse<I>
where
I: TrustedRandomAccess,
I: TrustedRandomAccessNoCoerce,
{
const MAY_HAVE_SIDE_EFFECT: bool = I::MAY_HAVE_SIDE_EFFECT;
}
Expand Down
14 changes: 10 additions & 4 deletions library/core/src/iter/adapters/map.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use crate::fmt;
use crate::iter::adapters::{zip::try_get_unchecked, SourceIter, TrustedRandomAccess};
use crate::iter::adapters::{
zip::try_get_unchecked, SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce,
};
use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen};
use crate::ops::Try;

Expand Down Expand Up @@ -125,7 +127,7 @@ where
#[doc(hidden)]
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> B
where
Self: TrustedRandomAccess,
Self: TrustedRandomAccessNoCoerce,
{
// SAFETY: the caller must uphold the contract for
// `Iterator::__iterator_get_unchecked`.
Expand Down Expand Up @@ -187,9 +189,13 @@ where

#[doc(hidden)]
#[unstable(feature = "trusted_random_access", issue = "none")]
unsafe impl<I, F> TrustedRandomAccess for Map<I, F>
unsafe impl<I, F> TrustedRandomAccess for Map<I, F> where I: TrustedRandomAccess {}

#[doc(hidden)]
#[unstable(feature = "trusted_random_access", issue = "none")]
unsafe impl<I, F> TrustedRandomAccessNoCoerce for Map<I, F>
where
I: TrustedRandomAccess,
I: TrustedRandomAccessNoCoerce,
{
const MAY_HAVE_SIDE_EFFECT: bool = true;
}
Expand Down
3 changes: 3 additions & 0 deletions library/core/src/iter/adapters/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ pub use self::map_while::MapWhile;
#[unstable(feature = "trusted_random_access", issue = "none")]
pub use self::zip::TrustedRandomAccess;

#[unstable(feature = "trusted_random_access", issue = "none")]
pub use self::zip::TrustedRandomAccessNoCoerce;

#[unstable(feature = "iter_zip", issue = "83574")]
pub use self::zip::zip;

Expand Down
Loading