Skip to content

Commit ef81fca

Browse files
authoredJul 27, 2022
Rollup merge of #94247 - saethlin:chunksmut-aliasing, r=the8472
Fix slice::ChunksMut aliasing Fixes #94231, details in that issue. cc `@RalfJung` This isn't done just yet, all the safety comments are placeholders. But otherwise, it seems to work. I don't really like this approach though. There's a lot of unsafe code where there wasn't before, but as far as I can tell the only other way to uphold the aliasing requirement imposed by `__iterator_get_unchecked` is to use raw slices, which I think require the same amount of unsafe code. All that would do is tie the `len` and `ptr` fields together. Oh I just looked and I'm pretty sure that `ChunksExactMut`, `RChunksMut`, and `RChunksExactMut` also need to be patched. Even more reason to put up a draft.
2 parents 2a22093 + 746afe8 commit ef81fca

File tree

2 files changed

+166
-72
lines changed

2 files changed

+166
-72
lines changed
 

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

Lines changed: 122 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1628,14 +1628,21 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for Chunks<'a, T> {
16281628
#[stable(feature = "rust1", since = "1.0.0")]
16291629
#[must_use = "iterators are lazy and do nothing unless consumed"]
16301630
pub struct ChunksMut<'a, T: 'a> {
1631-
v: &'a mut [T],
1631+
/// # Safety
1632+
/// This slice pointer must point at a valid region of `T` with at least length `v.len()`. Normally,
1633+
/// those requirements would mean that we could instead use a `&mut [T]` here, but we cannot
1634+
/// because `__iterator_get_unchecked` needs to return `&mut [T]`, which guarantees certain aliasing
1635+
/// properties that we cannot uphold if we hold on to the full original `&mut [T]`. Wrapping a raw
1636+
/// slice instead lets us hand out non-overlapping `&mut [T]` subslices of the slice we wrap.
1637+
v: *mut [T],
16321638
chunk_size: usize,
1639+
_marker: PhantomData<&'a mut T>,
16331640
}
16341641

16351642
impl<'a, T: 'a> ChunksMut<'a, T> {
16361643
#[inline]
16371644
pub(super) fn new(slice: &'a mut [T], size: usize) -> Self {
1638-
Self { v: slice, chunk_size: size }
1645+
Self { v: slice, chunk_size: size, _marker: PhantomData }
16391646
}
16401647
}
16411648

@@ -1649,10 +1656,11 @@ impl<'a, T> Iterator for ChunksMut<'a, T> {
16491656
None
16501657
} else {
16511658
let sz = cmp::min(self.v.len(), self.chunk_size);
1652-
let tmp = mem::replace(&mut self.v, &mut []);
1653-
let (head, tail) = tmp.split_at_mut(sz);
1659+
// SAFETY: The self.v contract ensures that any split_at_mut is valid.
1660+
let (head, tail) = unsafe { self.v.split_at_mut(sz) };
16541661
self.v = tail;
1655-
Some(head)
1662+
// SAFETY: Nothing else points to or will point to the contents of this slice.
1663+
Some(unsafe { &mut *head })
16561664
}
16571665
}
16581666

@@ -1684,11 +1692,13 @@ impl<'a, T> Iterator for ChunksMut<'a, T> {
16841692
Some(sum) => cmp::min(self.v.len(), sum),
16851693
None => self.v.len(),
16861694
};
1687-
let tmp = mem::replace(&mut self.v, &mut []);
1688-
let (head, tail) = tmp.split_at_mut(end);
1689-
let (_, nth) = head.split_at_mut(start);
1695+
// SAFETY: The self.v contract ensures that any split_at_mut is valid.
1696+
let (head, tail) = unsafe { self.v.split_at_mut(end) };
1697+
// SAFETY: The self.v contract ensures that any split_at_mut is valid.
1698+
let (_, nth) = unsafe { head.split_at_mut(start) };
16901699
self.v = tail;
1691-
Some(nth)
1700+
// SAFETY: Nothing else points to or will point to the contents of this slice.
1701+
Some(unsafe { &mut *nth })
16921702
}
16931703
}
16941704

@@ -1698,13 +1708,14 @@ impl<'a, T> Iterator for ChunksMut<'a, T> {
16981708
None
16991709
} else {
17001710
let start = (self.v.len() - 1) / self.chunk_size * self.chunk_size;
1701-
Some(&mut self.v[start..])
1711+
// SAFETY: Nothing else points to or will point to the contents of this slice.
1712+
Some(unsafe { &mut *self.v.get_unchecked_mut(start..) })
17021713
}
17031714
}
17041715

17051716
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
17061717
let start = idx * self.chunk_size;
1707-
// SAFETY: see comments for `Chunks::__iterator_get_unchecked`.
1718+
// SAFETY: see comments for `Chunks::__iterator_get_unchecked` and `self.v`.
17081719
//
17091720
// Also note that the caller also guarantees that we're never called
17101721
// with the same index again, and that no other methods that will
@@ -1726,12 +1737,12 @@ impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> {
17261737
} else {
17271738
let remainder = self.v.len() % self.chunk_size;
17281739
let sz = if remainder != 0 { remainder } else { self.chunk_size };
1729-
let tmp = mem::replace(&mut self.v, &mut []);
1730-
let tmp_len = tmp.len();
1740+
let len = self.v.len();
17311741
// SAFETY: Similar to `Chunks::next_back`
1732-
let (head, tail) = unsafe { tmp.split_at_mut_unchecked(tmp_len - sz) };
1742+
let (head, tail) = unsafe { self.v.split_at_mut_unchecked(len - sz) };
17331743
self.v = head;
1734-
Some(tail)
1744+
// SAFETY: Nothing else points to or will point to the contents of this slice.
1745+
Some(unsafe { &mut *tail })
17351746
}
17361747
}
17371748

@@ -1747,10 +1758,13 @@ impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> {
17471758
Some(res) => cmp::min(self.v.len(), res),
17481759
None => self.v.len(),
17491760
};
1750-
let (temp, _tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);
1751-
let (head, nth_back) = temp.split_at_mut(start);
1761+
// SAFETY: The self.v contract ensures that any split_at_mut is valid.
1762+
let (temp, _tail) = unsafe { self.v.split_at_mut(end) };
1763+
// SAFETY: The self.v contract ensures that any split_at_mut is valid.
1764+
let (head, nth_back) = unsafe { temp.split_at_mut(start) };
17521765
self.v = head;
1753-
Some(nth_back)
1766+
// SAFETY: Nothing else points to or will point to the contents of this slice.
1767+
Some(unsafe { &mut *nth_back })
17541768
}
17551769
}
17561770
}
@@ -1956,9 +1970,16 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for ChunksExact<'a, T> {
19561970
#[stable(feature = "chunks_exact", since = "1.31.0")]
19571971
#[must_use = "iterators are lazy and do nothing unless consumed"]
19581972
pub struct ChunksExactMut<'a, T: 'a> {
1959-
v: &'a mut [T],
1960-
rem: &'a mut [T],
1973+
/// # Safety
1974+
/// This slice pointer must point at a valid region of `T` with at least length `v.len()`. Normally,
1975+
/// those requirements would mean that we could instead use a `&mut [T]` here, but we cannot
1976+
/// because `__iterator_get_unchecked` needs to return `&mut [T]`, which guarantees certain aliasing
1977+
/// properties that we cannot uphold if we hold on to the full original `&mut [T]`. Wrapping a raw
1978+
/// slice instead lets us hand out non-overlapping `&mut [T]` subslices of the slice we wrap.
1979+
v: *mut [T],
1980+
rem: &'a mut [T], // The iterator never yields from here, so this can be unique
19611981
chunk_size: usize,
1982+
_marker: PhantomData<&'a mut T>,
19621983
}
19631984

19641985
impl<'a, T> ChunksExactMut<'a, T> {
@@ -1968,7 +1989,7 @@ impl<'a, T> ChunksExactMut<'a, T> {
19681989
let fst_len = slice.len() - rem;
19691990
// SAFETY: 0 <= fst_len <= slice.len() by construction above
19701991
let (fst, snd) = unsafe { slice.split_at_mut_unchecked(fst_len) };
1971-
Self { v: fst, rem: snd, chunk_size }
1992+
Self { v: fst, rem: snd, chunk_size, _marker: PhantomData }
19721993
}
19731994

19741995
/// Returns the remainder of the original slice that is not going to be
@@ -1990,10 +2011,11 @@ impl<'a, T> Iterator for ChunksExactMut<'a, T> {
19902011
if self.v.len() < self.chunk_size {
19912012
None
19922013
} else {
1993-
let tmp = mem::replace(&mut self.v, &mut []);
1994-
let (head, tail) = tmp.split_at_mut(self.chunk_size);
2014+
// SAFETY: self.chunk_size is inbounds because we compared above against self.v.len()
2015+
let (head, tail) = unsafe { self.v.split_at_mut(self.chunk_size) };
19952016
self.v = tail;
1996-
Some(head)
2017+
// SAFETY: Nothing else points to or will point to the contents of this slice.
2018+
Some(unsafe { &mut *head })
19972019
}
19982020
}
19992021

@@ -2015,8 +2037,8 @@ impl<'a, T> Iterator for ChunksExactMut<'a, T> {
20152037
self.v = &mut [];
20162038
None
20172039
} else {
2018-
let tmp = mem::replace(&mut self.v, &mut []);
2019-
let (_, snd) = tmp.split_at_mut(start);
2040+
// SAFETY: The self.v contract ensures that any split_at_mut is valid.
2041+
let (_, snd) = unsafe { self.v.split_at_mut(start) };
20202042
self.v = snd;
20212043
self.next()
20222044
}
@@ -2029,7 +2051,7 @@ impl<'a, T> Iterator for ChunksExactMut<'a, T> {
20292051

20302052
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
20312053
let start = idx * self.chunk_size;
2032-
// SAFETY: see comments for `ChunksMut::__iterator_get_unchecked`.
2054+
// SAFETY: see comments for `Chunks::__iterator_get_unchecked` and `self.v`.
20332055
unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) }
20342056
}
20352057
}
@@ -2041,11 +2063,11 @@ impl<'a, T> DoubleEndedIterator for ChunksExactMut<'a, T> {
20412063
if self.v.len() < self.chunk_size {
20422064
None
20432065
} else {
2044-
let tmp = mem::replace(&mut self.v, &mut []);
2045-
let tmp_len = tmp.len();
2046-
let (head, tail) = tmp.split_at_mut(tmp_len - self.chunk_size);
2066+
// SAFETY: This subtraction is inbounds because of the check above
2067+
let (head, tail) = unsafe { self.v.split_at_mut(self.v.len() - self.chunk_size) };
20472068
self.v = head;
2048-
Some(tail)
2069+
// SAFETY: Nothing else points to or will point to the contents of this slice.
2070+
Some(unsafe { &mut *tail })
20492071
}
20502072
}
20512073

@@ -2058,10 +2080,13 @@ impl<'a, T> DoubleEndedIterator for ChunksExactMut<'a, T> {
20582080
} else {
20592081
let start = (len - 1 - n) * self.chunk_size;
20602082
let end = start + self.chunk_size;
2061-
let (temp, _tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);
2062-
let (head, nth_back) = temp.split_at_mut(start);
2083+
// SAFETY: The self.v contract ensures that any split_at_mut is valid.
2084+
let (temp, _tail) = unsafe { mem::replace(&mut self.v, &mut []).split_at_mut(end) };
2085+
// SAFETY: The self.v contract ensures that any split_at_mut is valid.
2086+
let (head, nth_back) = unsafe { temp.split_at_mut(start) };
20632087
self.v = head;
2064-
Some(nth_back)
2088+
// SAFETY: Nothing else points to or will point to the contents of this slice.
2089+
Some(unsafe { &mut *nth_back })
20652090
}
20662091
}
20672092
}
@@ -2645,14 +2670,21 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for RChunks<'a, T> {
26452670
#[stable(feature = "rchunks", since = "1.31.0")]
26462671
#[must_use = "iterators are lazy and do nothing unless consumed"]
26472672
pub struct RChunksMut<'a, T: 'a> {
2648-
v: &'a mut [T],
2673+
/// # Safety
2674+
/// This slice pointer must point at a valid region of `T` with at least length `v.len()`. Normally,
2675+
/// those requirements would mean that we could instead use a `&mut [T]` here, but we cannot
2676+
/// because `__iterator_get_unchecked` needs to return `&mut [T]`, which guarantees certain aliasing
2677+
/// properties that we cannot uphold if we hold on to the full original `&mut [T]`. Wrapping a raw
2678+
/// slice instead lets us hand out non-overlapping `&mut [T]` subslices of the slice we wrap.
2679+
v: *mut [T],
26492680
chunk_size: usize,
2681+
_marker: PhantomData<&'a mut T>,
26502682
}
26512683

26522684
impl<'a, T: 'a> RChunksMut<'a, T> {
26532685
#[inline]
26542686
pub(super) fn new(slice: &'a mut [T], size: usize) -> Self {
2655-
Self { v: slice, chunk_size: size }
2687+
Self { v: slice, chunk_size: size, _marker: PhantomData }
26562688
}
26572689
}
26582690

@@ -2666,16 +2698,16 @@ impl<'a, T> Iterator for RChunksMut<'a, T> {
26662698
None
26672699
} else {
26682700
let sz = cmp::min(self.v.len(), self.chunk_size);
2669-
let tmp = mem::replace(&mut self.v, &mut []);
2670-
let tmp_len = tmp.len();
2701+
let len = self.v.len();
26712702
// SAFETY: split_at_mut_unchecked just requires the argument be less
26722703
// than the length. This could only happen if the expression
2673-
// `tmp_len - sz` overflows. This could only happen if `sz >
2674-
// tmp_len`, which is impossible as we initialize it as the `min` of
2675-
// `self.v.len()` (e.g. `tmp_len`) and `self.chunk_size`.
2676-
let (head, tail) = unsafe { tmp.split_at_mut_unchecked(tmp_len - sz) };
2704+
// `len - sz` overflows. This could only happen if `sz >
2705+
// len`, which is impossible as we initialize it as the `min` of
2706+
// `self.v.len()` (e.g. `len`) and `self.chunk_size`.
2707+
let (head, tail) = unsafe { self.v.split_at_mut_unchecked(len - sz) };
26772708
self.v = head;
2678-
Some(tail)
2709+
// SAFETY: Nothing else points to or will point to the contents of this slice.
2710+
Some(unsafe { &mut *tail })
26792711
}
26802712
}
26812713

@@ -2709,11 +2741,15 @@ impl<'a, T> Iterator for RChunksMut<'a, T> {
27092741
Some(sum) => sum,
27102742
None => 0,
27112743
};
2712-
let tmp = mem::replace(&mut self.v, &mut []);
2713-
let (head, tail) = tmp.split_at_mut(start);
2714-
let (nth, _) = tail.split_at_mut(end - start);
2744+
// SAFETY: This type ensures that self.v is a valid pointer with a correct len.
2745+
// Therefore the bounds check in split_at_mut guarantess the split point is inbounds.
2746+
let (head, tail) = unsafe { self.v.split_at_mut(start) };
2747+
// SAFETY: This type ensures that self.v is a valid pointer with a correct len.
2748+
// Therefore the bounds check in split_at_mut guarantess the split point is inbounds.
2749+
let (nth, _) = unsafe { tail.split_at_mut(end - start) };
27152750
self.v = head;
2716-
Some(nth)
2751+
// SAFETY: Nothing else points to or will point to the contents of this slice.
2752+
Some(unsafe { &mut *nth })
27172753
}
27182754
}
27192755

@@ -2724,7 +2760,8 @@ impl<'a, T> Iterator for RChunksMut<'a, T> {
27242760
} else {
27252761
let rem = self.v.len() % self.chunk_size;
27262762
let end = if rem == 0 { self.chunk_size } else { rem };
2727-
Some(&mut self.v[0..end])
2763+
// SAFETY: Nothing else points to or will point to the contents of this slice.
2764+
Some(unsafe { &mut *self.v.get_unchecked_mut(0..end) })
27282765
}
27292766
}
27302767

@@ -2735,7 +2772,7 @@ impl<'a, T> Iterator for RChunksMut<'a, T> {
27352772
Some(start) => start,
27362773
};
27372774
// SAFETY: see comments for `RChunks::__iterator_get_unchecked` and
2738-
// `ChunksMut::__iterator_get_unchecked`
2775+
// `ChunksMut::__iterator_get_unchecked`, `self.v`.
27392776
unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) }
27402777
}
27412778
}
@@ -2749,11 +2786,11 @@ impl<'a, T> DoubleEndedIterator for RChunksMut<'a, T> {
27492786
} else {
27502787
let remainder = self.v.len() % self.chunk_size;
27512788
let sz = if remainder != 0 { remainder } else { self.chunk_size };
2752-
let tmp = mem::replace(&mut self.v, &mut []);
27532789
// SAFETY: Similar to `Chunks::next_back`
2754-
let (head, tail) = unsafe { tmp.split_at_mut_unchecked(sz) };
2790+
let (head, tail) = unsafe { self.v.split_at_mut_unchecked(sz) };
27552791
self.v = tail;
2756-
Some(head)
2792+
// SAFETY: Nothing else points to or will point to the contents of this slice.
2793+
Some(unsafe { &mut *head })
27572794
}
27582795
}
27592796

@@ -2768,10 +2805,13 @@ impl<'a, T> DoubleEndedIterator for RChunksMut<'a, T> {
27682805
let offset_from_end = (len - 1 - n) * self.chunk_size;
27692806
let end = self.v.len() - offset_from_end;
27702807
let start = end.saturating_sub(self.chunk_size);
2771-
let (tmp, tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);
2772-
let (_, nth_back) = tmp.split_at_mut(start);
2808+
// SAFETY: The self.v contract ensures that any split_at_mut is valid.
2809+
let (tmp, tail) = unsafe { self.v.split_at_mut(end) };
2810+
// SAFETY: The self.v contract ensures that any split_at_mut is valid.
2811+
let (_, nth_back) = unsafe { tmp.split_at_mut(start) };
27732812
self.v = tail;
2774-
Some(nth_back)
2813+
// SAFETY: Nothing else points to or will point to the contents of this slice.
2814+
Some(unsafe { &mut *nth_back })
27752815
}
27762816
}
27772817
}
@@ -2897,8 +2937,7 @@ impl<'a, T> Iterator for RChunksExact<'a, T> {
28972937
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
28982938
let end = self.v.len() - idx * self.chunk_size;
28992939
let start = end - self.chunk_size;
2900-
// SAFETY:
2901-
// SAFETY: mostmy identical to `Chunks::__iterator_get_unchecked`.
2940+
// SAFETY: mostly identical to `Chunks::__iterator_get_unchecked`.
29022941
unsafe { from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) }
29032942
}
29042943
}
@@ -2981,7 +3020,13 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for RChunksExact<'a, T> {
29813020
#[stable(feature = "rchunks", since = "1.31.0")]
29823021
#[must_use = "iterators are lazy and do nothing unless consumed"]
29833022
pub struct RChunksExactMut<'a, T: 'a> {
2984-
v: &'a mut [T],
3023+
/// # Safety
3024+
/// This slice pointer must point at a valid region of `T` with at least length `v.len()`. Normally,
3025+
/// those requirements would mean that we could instead use a `&mut [T]` here, but we cannot
3026+
/// because `__iterator_get_unchecked` needs to return `&mut [T]`, which guarantees certain aliasing
3027+
/// properties that we cannot uphold if we hold on to the full original `&mut [T]`. Wrapping a raw
3028+
/// slice instead lets us hand out non-overlapping `&mut [T]` subslices of the slice we wrap.
3029+
v: *mut [T],
29853030
rem: &'a mut [T],
29863031
chunk_size: usize,
29873032
}
@@ -3014,11 +3059,12 @@ impl<'a, T> Iterator for RChunksExactMut<'a, T> {
30143059
if self.v.len() < self.chunk_size {
30153060
None
30163061
} else {
3017-
let tmp = mem::replace(&mut self.v, &mut []);
3018-
let tmp_len = tmp.len();
3019-
let (head, tail) = tmp.split_at_mut(tmp_len - self.chunk_size);
3062+
let len = self.v.len();
3063+
// SAFETY: The self.v contract ensures that any split_at_mut is valid.
3064+
let (head, tail) = unsafe { self.v.split_at_mut(len - self.chunk_size) };
30203065
self.v = head;
3021-
Some(tail)
3066+
// SAFETY: Nothing else points to or will point to the contents of this slice.
3067+
Some(unsafe { &mut *tail })
30223068
}
30233069
}
30243070

@@ -3040,9 +3086,9 @@ impl<'a, T> Iterator for RChunksExactMut<'a, T> {
30403086
self.v = &mut [];
30413087
None
30423088
} else {
3043-
let tmp = mem::replace(&mut self.v, &mut []);
3044-
let tmp_len = tmp.len();
3045-
let (fst, _) = tmp.split_at_mut(tmp_len - end);
3089+
let len = self.v.len();
3090+
// SAFETY: The self.v contract ensures that any split_at_mut is valid.
3091+
let (fst, _) = unsafe { self.v.split_at_mut(len - end) };
30463092
self.v = fst;
30473093
self.next()
30483094
}
@@ -3056,7 +3102,7 @@ impl<'a, T> Iterator for RChunksExactMut<'a, T> {
30563102
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
30573103
let end = self.v.len() - idx * self.chunk_size;
30583104
let start = end - self.chunk_size;
3059-
// SAFETY: see comments for `RChunksMut::__iterator_get_unchecked`.
3105+
// SAFETY: see comments for `RChunksMut::__iterator_get_unchecked` and `self.v`.
30603106
unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) }
30613107
}
30623108
}
@@ -3068,10 +3114,11 @@ impl<'a, T> DoubleEndedIterator for RChunksExactMut<'a, T> {
30683114
if self.v.len() < self.chunk_size {
30693115
None
30703116
} else {
3071-
let tmp = mem::replace(&mut self.v, &mut []);
3072-
let (head, tail) = tmp.split_at_mut(self.chunk_size);
3117+
// SAFETY: The self.v contract ensures that any split_at_mut is valid.
3118+
let (head, tail) = unsafe { self.v.split_at_mut(self.chunk_size) };
30733119
self.v = tail;
3074-
Some(head)
3120+
// SAFETY: Nothing else points to or will point to the contents of this slice.
3121+
Some(unsafe { &mut *head })
30753122
}
30763123
}
30773124

@@ -3087,10 +3134,13 @@ impl<'a, T> DoubleEndedIterator for RChunksExactMut<'a, T> {
30873134
let offset = (len - n) * self.chunk_size;
30883135
let start = self.v.len() - offset;
30893136
let end = start + self.chunk_size;
3090-
let (tmp, tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);
3091-
let (_, nth_back) = tmp.split_at_mut(start);
3137+
// SAFETY: The self.v contract ensures that any split_at_mut is valid.
3138+
let (tmp, tail) = unsafe { self.v.split_at_mut(end) };
3139+
// SAFETY: The self.v contract ensures that any split_at_mut is valid.
3140+
let (_, nth_back) = unsafe { tmp.split_at_mut(start) };
30923141
self.v = tail;
3093-
Some(nth_back)
3142+
// SAFETY: Nothing else points to or will point to the contents of this slice.
3143+
Some(unsafe { &mut *nth_back })
30943144
}
30953145
}
30963146
}

‎library/core/tests/slice.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,50 @@ fn test_chunks_mut_zip() {
409409
assert_eq!(v1, [13, 14, 19, 20, 14]);
410410
}
411411

412+
#[test]
413+
fn test_chunks_mut_zip_aliasing() {
414+
let v1: &mut [i32] = &mut [0, 1, 2, 3, 4];
415+
let v2: &[i32] = &[6, 7, 8, 9, 10];
416+
417+
let mut it = v1.chunks_mut(2).zip(v2.chunks(2));
418+
let first = it.next().unwrap();
419+
let _ = it.next().unwrap();
420+
assert_eq!(first, (&mut [0, 1][..], &[6, 7][..]));
421+
}
422+
423+
#[test]
424+
fn test_chunks_exact_mut_zip_aliasing() {
425+
let v1: &mut [i32] = &mut [0, 1, 2, 3, 4];
426+
let v2: &[i32] = &[6, 7, 8, 9, 10];
427+
428+
let mut it = v1.chunks_exact_mut(2).zip(v2.chunks(2));
429+
let first = it.next().unwrap();
430+
let _ = it.next().unwrap();
431+
assert_eq!(first, (&mut [0, 1][..], &[6, 7][..]));
432+
}
433+
434+
#[test]
435+
fn test_rchunks_mut_zip_aliasing() {
436+
let v1: &mut [i32] = &mut [0, 1, 2, 3, 4];
437+
let v2: &[i32] = &[6, 7, 8, 9, 10];
438+
439+
let mut it = v1.rchunks_mut(2).zip(v2.chunks(2));
440+
let first = it.next().unwrap();
441+
let _ = it.next().unwrap();
442+
assert_eq!(first, (&mut [3, 4][..], &[6, 7][..]));
443+
}
444+
445+
#[test]
446+
fn test_rchunks_exact_mut_zip_aliasing() {
447+
let v1: &mut [i32] = &mut [0, 1, 2, 3, 4];
448+
let v2: &[i32] = &[6, 7, 8, 9, 10];
449+
450+
let mut it = v1.rchunks_exact_mut(2).zip(v2.chunks(2));
451+
let first = it.next().unwrap();
452+
let _ = it.next().unwrap();
453+
assert_eq!(first, (&mut [3, 4][..], &[6, 7][..]));
454+
}
455+
412456
#[test]
413457
fn test_chunks_exact_count() {
414458
let v: &[i32] = &[0, 1, 2, 3, 4, 5];

0 commit comments

Comments
 (0)
Please sign in to comment.