Remove some unsound specializations
This commit is contained in:
parent
212b2c7da8
commit
a81c59f9b8
7 changed files with 168 additions and 57 deletions
|
@ -385,12 +385,14 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> {
|
||||||
}
|
}
|
||||||
Some(Equal) => {
|
Some(Equal) => {
|
||||||
self.is_empty = Some(true);
|
self.is_empty = Some(true);
|
||||||
|
self.start = plus_n.clone();
|
||||||
return Some(plus_n);
|
return Some(plus_n);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.start = self.end.clone();
|
||||||
self.is_empty = Some(true);
|
self.is_empty = Some(true);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -477,12 +479,14 @@ impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> {
|
||||||
}
|
}
|
||||||
Some(Equal) => {
|
Some(Equal) => {
|
||||||
self.is_empty = Some(true);
|
self.is_empty = Some(true);
|
||||||
|
self.end = minus_n.clone();
|
||||||
return Some(minus_n);
|
return Some(minus_n);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.end = self.start.clone();
|
||||||
self.is_empty = Some(true);
|
self.is_empty = Some(true);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
|
@ -343,38 +343,21 @@ pub struct RangeInclusive<Idx> {
|
||||||
pub(crate) is_empty: Option<bool>,
|
pub(crate) is_empty: Option<bool>,
|
||||||
// This field is:
|
// This field is:
|
||||||
// - `None` when next() or next_back() was never called
|
// - `None` when next() or next_back() was never called
|
||||||
// - `Some(false)` when `start <= end` assuming no overflow
|
// - `Some(false)` when `start < end`
|
||||||
// - `Some(true)` otherwise
|
// - `Some(true)` when `end < start`
|
||||||
|
// - `Some(false)` when `start == end` and the range hasn't yet completed iteration
|
||||||
|
// - `Some(true)` when `start == end` and the range has completed iteration
|
||||||
// The field cannot be a simple `bool` because the `..=` constructor can
|
// The field cannot be a simple `bool` because the `..=` constructor can
|
||||||
// accept non-PartialOrd types, also we want the constructor to be const.
|
// accept non-PartialOrd types, also we want the constructor to be const.
|
||||||
}
|
}
|
||||||
|
|
||||||
trait RangeInclusiveEquality: Sized {
|
|
||||||
fn canonicalized_is_empty(range: &RangeInclusive<Self>) -> bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> RangeInclusiveEquality for T {
|
|
||||||
#[inline]
|
|
||||||
default fn canonicalized_is_empty(range: &RangeInclusive<Self>) -> bool {
|
|
||||||
range.is_empty.unwrap_or_default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: PartialOrd> RangeInclusiveEquality for T {
|
|
||||||
#[inline]
|
|
||||||
fn canonicalized_is_empty(range: &RangeInclusive<Self>) -> bool {
|
|
||||||
range.is_empty()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[stable(feature = "inclusive_range", since = "1.26.0")]
|
#[stable(feature = "inclusive_range", since = "1.26.0")]
|
||||||
impl<Idx: PartialEq> PartialEq for RangeInclusive<Idx> {
|
impl<Idx: PartialEq> PartialEq for RangeInclusive<Idx> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.start == other.start
|
self.start == other.start
|
||||||
&& self.end == other.end
|
&& self.end == other.end
|
||||||
&& RangeInclusiveEquality::canonicalized_is_empty(self)
|
&& self.is_exhausted() == other.is_exhausted()
|
||||||
== RangeInclusiveEquality::canonicalized_is_empty(other)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -386,7 +369,8 @@ impl<Idx: Hash> Hash for RangeInclusive<Idx> {
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
self.start.hash(state);
|
self.start.hash(state);
|
||||||
self.end.hash(state);
|
self.end.hash(state);
|
||||||
RangeInclusiveEquality::canonicalized_is_empty(self).hash(state);
|
// Ideally we would hash `is_exhausted` here as well, but there's no
|
||||||
|
// way for us to call it.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -485,6 +469,14 @@ impl<Idx: fmt::Debug> fmt::Debug for RangeInclusive<Idx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<Idx: PartialEq<Idx>> RangeInclusive<Idx> {
|
||||||
|
// Returns true if this is a range that started non-empty, and was iterated
|
||||||
|
// to exhaustion.
|
||||||
|
fn is_exhausted(&self) -> bool {
|
||||||
|
Some(true) == self.is_empty && self.start == self.end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<Idx: PartialOrd<Idx>> RangeInclusive<Idx> {
|
impl<Idx: PartialOrd<Idx>> RangeInclusive<Idx> {
|
||||||
/// Returns `true` if `item` is contained in the range.
|
/// Returns `true` if `item` is contained in the range.
|
||||||
///
|
///
|
||||||
|
|
|
@ -5584,21 +5584,18 @@ where
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
// intermediate trait for specialization of slice's PartialOrd
|
// intermediate trait for specialization of slice's PartialOrd
|
||||||
trait SlicePartialOrd<B> {
|
trait SlicePartialOrd: Sized {
|
||||||
fn partial_compare(&self, other: &[B]) -> Option<Ordering>;
|
fn partial_compare(left: &[Self], right: &[Self]) -> Option<Ordering>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A> SlicePartialOrd<A> for [A]
|
impl<A: PartialOrd> SlicePartialOrd for A {
|
||||||
where
|
default fn partial_compare(left: &[A], right: &[A]) -> Option<Ordering> {
|
||||||
A: PartialOrd,
|
let l = cmp::min(left.len(), right.len());
|
||||||
{
|
|
||||||
default fn partial_compare(&self, other: &[A]) -> Option<Ordering> {
|
|
||||||
let l = cmp::min(self.len(), other.len());
|
|
||||||
|
|
||||||
// Slice to the loop iteration range to enable bound check
|
// Slice to the loop iteration range to enable bound check
|
||||||
// elimination in the compiler
|
// elimination in the compiler
|
||||||
let lhs = &self[..l];
|
let lhs = &left[..l];
|
||||||
let rhs = &other[..l];
|
let rhs = &right[..l];
|
||||||
|
|
||||||
for i in 0..l {
|
for i in 0..l {
|
||||||
match lhs[i].partial_cmp(&rhs[i]) {
|
match lhs[i].partial_cmp(&rhs[i]) {
|
||||||
|
@ -5607,36 +5604,61 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.len().partial_cmp(&other.len())
|
left.len().partial_cmp(&right.len())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A> SlicePartialOrd<A> for [A]
|
// This is the impl that we would like to have. Unfortunately it's not sound.
|
||||||
|
// See `partial_ord_slice.rs`.
|
||||||
|
/*
|
||||||
|
impl<A> SlicePartialOrd for A
|
||||||
where
|
where
|
||||||
A: Ord,
|
A: Ord,
|
||||||
{
|
{
|
||||||
default fn partial_compare(&self, other: &[A]) -> Option<Ordering> {
|
default fn partial_compare(left: &[A], right: &[A]) -> Option<Ordering> {
|
||||||
Some(SliceOrd::compare(self, other))
|
Some(SliceOrd::compare(left, right))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
impl<A: AlwaysApplicableOrd> SlicePartialOrd for A {
|
||||||
|
fn partial_compare(left: &[A], right: &[A]) -> Option<Ordering> {
|
||||||
|
Some(SliceOrd::compare(left, right))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait AlwaysApplicableOrd: SliceOrd + Ord {}
|
||||||
|
|
||||||
|
macro_rules! always_applicable_ord {
|
||||||
|
($([$($p:tt)*] $t:ty,)*) => {
|
||||||
|
$(impl<$($p)*> AlwaysApplicableOrd for $t {})*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
always_applicable_ord! {
|
||||||
|
[] u8, [] u16, [] u32, [] u64, [] u128, [] usize,
|
||||||
|
[] i8, [] i16, [] i32, [] i64, [] i128, [] isize,
|
||||||
|
[] bool, [] char,
|
||||||
|
[T: ?Sized] *const T, [T: ?Sized] *mut T,
|
||||||
|
[T: AlwaysApplicableOrd] &T,
|
||||||
|
[T: AlwaysApplicableOrd] &mut T,
|
||||||
|
[T: AlwaysApplicableOrd] Option<T>,
|
||||||
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
// intermediate trait for specialization of slice's Ord
|
// intermediate trait for specialization of slice's Ord
|
||||||
trait SliceOrd<B> {
|
trait SliceOrd: Sized {
|
||||||
fn compare(&self, other: &[B]) -> Ordering;
|
fn compare(left: &[Self], right: &[Self]) -> Ordering;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A> SliceOrd<A> for [A]
|
impl<A: Ord> SliceOrd for A {
|
||||||
where
|
default fn compare(left: &[Self], right: &[Self]) -> Ordering {
|
||||||
A: Ord,
|
let l = cmp::min(left.len(), right.len());
|
||||||
{
|
|
||||||
default fn compare(&self, other: &[A]) -> Ordering {
|
|
||||||
let l = cmp::min(self.len(), other.len());
|
|
||||||
|
|
||||||
// Slice to the loop iteration range to enable bound check
|
// Slice to the loop iteration range to enable bound check
|
||||||
// elimination in the compiler
|
// elimination in the compiler
|
||||||
let lhs = &self[..l];
|
let lhs = &left[..l];
|
||||||
let rhs = &other[..l];
|
let rhs = &right[..l];
|
||||||
|
|
||||||
for i in 0..l {
|
for i in 0..l {
|
||||||
match lhs[i].cmp(&rhs[i]) {
|
match lhs[i].cmp(&rhs[i]) {
|
||||||
|
@ -5645,19 +5667,19 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.len().cmp(&other.len())
|
left.len().cmp(&right.len())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// memcmp compares a sequence of unsigned bytes lexicographically.
|
// memcmp compares a sequence of unsigned bytes lexicographically.
|
||||||
// this matches the order we want for [u8], but no others (not even [i8]).
|
// this matches the order we want for [u8], but no others (not even [i8]).
|
||||||
impl SliceOrd<u8> for [u8] {
|
impl SliceOrd for u8 {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn compare(&self, other: &[u8]) -> Ordering {
|
fn compare(left: &[Self], right: &[Self]) -> Ordering {
|
||||||
let order =
|
let order =
|
||||||
unsafe { memcmp(self.as_ptr(), other.as_ptr(), cmp::min(self.len(), other.len())) };
|
unsafe { memcmp(left.as_ptr(), right.as_ptr(), cmp::min(left.len(), right.len())) };
|
||||||
if order == 0 {
|
if order == 0 {
|
||||||
self.len().cmp(&other.len())
|
left.len().cmp(&right.len())
|
||||||
} else if order < 0 {
|
} else if order < 0 {
|
||||||
Less
|
Less
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -12,7 +12,7 @@ use self::pattern::{DoubleEndedSearcher, ReverseSearcher, SearchStep, Searcher};
|
||||||
use crate::char;
|
use crate::char;
|
||||||
use crate::fmt::{self, Write};
|
use crate::fmt::{self, Write};
|
||||||
use crate::iter::{Chain, FlatMap, Flatten};
|
use crate::iter::{Chain, FlatMap, Flatten};
|
||||||
use crate::iter::{Cloned, Filter, FusedIterator, Map, TrustedLen, TrustedRandomAccess};
|
use crate::iter::{Copied, Filter, FusedIterator, Map, TrustedLen, TrustedRandomAccess};
|
||||||
use crate::mem;
|
use crate::mem;
|
||||||
use crate::ops::Try;
|
use crate::ops::Try;
|
||||||
use crate::option;
|
use crate::option;
|
||||||
|
@ -750,7 +750,7 @@ impl<'a> CharIndices<'a> {
|
||||||
/// [`str`]: ../../std/primitive.str.html
|
/// [`str`]: ../../std/primitive.str.html
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Bytes<'a>(Cloned<slice::Iter<'a, u8>>);
|
pub struct Bytes<'a>(Copied<slice::Iter<'a, u8>>);
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
impl Iterator for Bytes<'_> {
|
impl Iterator for Bytes<'_> {
|
||||||
|
@ -2778,7 +2778,7 @@ impl str {
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn bytes(&self) -> Bytes<'_> {
|
pub fn bytes(&self) -> Bytes<'_> {
|
||||||
Bytes(self.as_bytes().iter().cloned())
|
Bytes(self.as_bytes().iter().copied())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Splits a string slice by whitespace.
|
/// Splits a string slice by whitespace.
|
||||||
|
@ -3895,7 +3895,7 @@ impl str {
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(
|
||||||
start, 0,
|
start, 0,
|
||||||
"The first search step from Searcher \
|
"The first search step from Searcher \
|
||||||
must include the first character"
|
must include the first character"
|
||||||
);
|
);
|
||||||
// SAFETY: `Searcher` is known to return valid indices.
|
// SAFETY: `Searcher` is known to return valid indices.
|
||||||
unsafe { Some(self.get_unchecked(len..)) }
|
unsafe { Some(self.get_unchecked(len..)) }
|
||||||
|
@ -3934,7 +3934,7 @@ impl str {
|
||||||
end,
|
end,
|
||||||
self.len(),
|
self.len(),
|
||||||
"The first search step from ReverseSearcher \
|
"The first search step from ReverseSearcher \
|
||||||
must include the last character"
|
must include the last character"
|
||||||
);
|
);
|
||||||
// SAFETY: `Searcher` is known to return valid indices.
|
// SAFETY: `Searcher` is known to return valid indices.
|
||||||
unsafe { Some(self.get_unchecked(..start)) }
|
unsafe { Some(self.get_unchecked(..start)) }
|
||||||
|
|
|
@ -1954,11 +1954,19 @@ fn test_range_inclusive_exhaustion() {
|
||||||
assert_eq!(r.next(), None);
|
assert_eq!(r.next(), None);
|
||||||
assert_eq!(r.next(), None);
|
assert_eq!(r.next(), None);
|
||||||
|
|
||||||
|
assert_eq!(*r.start(), 10);
|
||||||
|
assert_eq!(*r.end(), 10);
|
||||||
|
assert_ne!(r, 10..=10);
|
||||||
|
|
||||||
let mut r = 10..=10;
|
let mut r = 10..=10;
|
||||||
assert_eq!(r.next_back(), Some(10));
|
assert_eq!(r.next_back(), Some(10));
|
||||||
assert!(r.is_empty());
|
assert!(r.is_empty());
|
||||||
assert_eq!(r.next_back(), None);
|
assert_eq!(r.next_back(), None);
|
||||||
|
|
||||||
|
assert_eq!(*r.start(), 10);
|
||||||
|
assert_eq!(*r.end(), 10);
|
||||||
|
assert_ne!(r, 10..=10);
|
||||||
|
|
||||||
let mut r = 10..=12;
|
let mut r = 10..=12;
|
||||||
assert_eq!(r.next(), Some(10));
|
assert_eq!(r.next(), Some(10));
|
||||||
assert_eq!(r.next(), Some(11));
|
assert_eq!(r.next(), Some(11));
|
||||||
|
@ -2076,6 +2084,9 @@ fn test_range_inclusive_nth() {
|
||||||
assert_eq!((10..=15).nth(5), Some(15));
|
assert_eq!((10..=15).nth(5), Some(15));
|
||||||
assert_eq!((10..=15).nth(6), None);
|
assert_eq!((10..=15).nth(6), None);
|
||||||
|
|
||||||
|
let mut exhausted_via_next = 10_u8..=20;
|
||||||
|
while exhausted_via_next.next().is_some() {}
|
||||||
|
|
||||||
let mut r = 10_u8..=20;
|
let mut r = 10_u8..=20;
|
||||||
assert_eq!(r.nth(2), Some(12));
|
assert_eq!(r.nth(2), Some(12));
|
||||||
assert_eq!(r, 13..=20);
|
assert_eq!(r, 13..=20);
|
||||||
|
@ -2085,6 +2096,7 @@ fn test_range_inclusive_nth() {
|
||||||
assert_eq!(ExactSizeIterator::is_empty(&r), false);
|
assert_eq!(ExactSizeIterator::is_empty(&r), false);
|
||||||
assert_eq!(r.nth(10), None);
|
assert_eq!(r.nth(10), None);
|
||||||
assert_eq!(r.is_empty(), true);
|
assert_eq!(r.is_empty(), true);
|
||||||
|
assert_eq!(r, exhausted_via_next);
|
||||||
assert_eq!(ExactSizeIterator::is_empty(&r), true);
|
assert_eq!(ExactSizeIterator::is_empty(&r), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2096,6 +2108,9 @@ fn test_range_inclusive_nth_back() {
|
||||||
assert_eq!((10..=15).nth_back(6), None);
|
assert_eq!((10..=15).nth_back(6), None);
|
||||||
assert_eq!((-120..=80_i8).nth_back(200), Some(-120));
|
assert_eq!((-120..=80_i8).nth_back(200), Some(-120));
|
||||||
|
|
||||||
|
let mut exhausted_via_next_back = 10_u8..=20;
|
||||||
|
while exhausted_via_next_back.next_back().is_some() {}
|
||||||
|
|
||||||
let mut r = 10_u8..=20;
|
let mut r = 10_u8..=20;
|
||||||
assert_eq!(r.nth_back(2), Some(18));
|
assert_eq!(r.nth_back(2), Some(18));
|
||||||
assert_eq!(r, 10..=17);
|
assert_eq!(r, 10..=17);
|
||||||
|
@ -2105,6 +2120,7 @@ fn test_range_inclusive_nth_back() {
|
||||||
assert_eq!(ExactSizeIterator::is_empty(&r), false);
|
assert_eq!(ExactSizeIterator::is_empty(&r), false);
|
||||||
assert_eq!(r.nth_back(10), None);
|
assert_eq!(r.nth_back(10), None);
|
||||||
assert_eq!(r.is_empty(), true);
|
assert_eq!(r.is_empty(), true);
|
||||||
|
assert_eq!(r, exhausted_via_next_back);
|
||||||
assert_eq!(ExactSizeIterator::is_empty(&r), true);
|
assert_eq!(ExactSizeIterator::is_empty(&r), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
// run-pass
|
||||||
|
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
|
struct Evil<'a, 'b> {
|
||||||
|
values: RefCell<Vec<&'a str>>,
|
||||||
|
to_insert: &'b String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> PartialEq for Evil<'a, 'b> {
|
||||||
|
fn eq(&self, _other: &Self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> PartialOrd for Evil<'a, 'a> {
|
||||||
|
fn partial_cmp(&self, _other: &Self) -> Option<Ordering> {
|
||||||
|
self.values.borrow_mut().push(self.to_insert);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let e;
|
||||||
|
let values;
|
||||||
|
{
|
||||||
|
let to_insert = String::from("Hello, world!");
|
||||||
|
e = Evil { values: RefCell::new(Vec::new()), to_insert: &to_insert };
|
||||||
|
let range = &e..=&e;
|
||||||
|
let _ = range == range;
|
||||||
|
values = e.values;
|
||||||
|
}
|
||||||
|
assert_eq!(*values.borrow(), Vec::<&str>::new());
|
||||||
|
}
|
42
src/test/ui/specialization/soundness/partial_ord_slice.rs
Normal file
42
src/test/ui/specialization/soundness/partial_ord_slice.rs
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
// Check that we aren't using unsound specialization in slice comparisons.
|
||||||
|
|
||||||
|
// run-pass
|
||||||
|
|
||||||
|
use std::cell::Cell;
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
|
struct Evil<'a, 'b>(Cell<(&'a [i32], &'b [i32])>);
|
||||||
|
|
||||||
|
impl PartialEq for Evil<'_, '_> {
|
||||||
|
fn eq(&self, _other: &Self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for Evil<'_, '_> {}
|
||||||
|
|
||||||
|
impl PartialOrd for Evil<'_, '_> {
|
||||||
|
fn partial_cmp(&self, _other: &Self) -> Option<Ordering> {
|
||||||
|
Some(Ordering::Equal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Ord for Evil<'a, 'a> {
|
||||||
|
fn cmp(&self, _other: &Self) -> Ordering {
|
||||||
|
let (a, b) = self.0.get();
|
||||||
|
self.0.set((b, a));
|
||||||
|
Ordering::Equal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x = &[1, 2, 3, 4];
|
||||||
|
let u = {
|
||||||
|
let a = Box::new([7, 8, 9, 10]);
|
||||||
|
let y = [Evil(Cell::new((x, &*a)))];
|
||||||
|
let _ = &y[..] <= &y[..];
|
||||||
|
let [Evil(c)] = y;
|
||||||
|
c.get().0
|
||||||
|
};
|
||||||
|
assert_eq!(u, &[1, 2, 3, 4]);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue