diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index be11cd0fd2de3..4513cf55ed83d 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -916,7 +916,7 @@ where /// /// To minimize indirection fields are still pub but callers should at least use /// `push_unchecked` to signal that something unsafe is going on. -pub(crate) struct Guard<'a, T, const N: usize> { +pub(crate) struct Guard<'a, T: ~const Destruct, const N: usize> { /// The array to be initialized. pub array_mut: &'a mut [MaybeUninit; N], /// The number of items that have been initialized so far. @@ -930,7 +930,7 @@ impl Guard<'_, T, N> { /// /// No more than N elements must be initialized. #[inline] - pub unsafe fn push_unchecked(&mut self, item: T) { + pub const unsafe fn push_unchecked(&mut self, item: T) { // SAFETY: If `initialized` was correct before and the caller does not // invoke this method more than N times then writes will be in-bounds // and slots will not be initialized more than once. @@ -941,15 +941,33 @@ impl Guard<'_, T, N> { } } -impl Drop for Guard<'_, T, N> { +impl const Drop for Guard<'_, T, N> { fn drop(&mut self) { debug_assert!(self.initialized <= N); + #[inline] + const fn drop_ct(x: &mut [T]) { + let mut i = 0; + while i < x.len() { + // SAFETY: dropping the value, contains initialized objects + unsafe { + crate::ptr::read(&mut x[i]); + } + i += 1; + } + } + #[inline] + fn drop_rt(x: &mut [T]) { + // SAFETY: slice contains initialized objects + unsafe { crate::ptr::drop_in_place(x) } + } + // SAFETY: this slice will contain only initialized objects. unsafe { - crate::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut( - &mut self.array_mut.get_unchecked_mut(..self.initialized), - )); + let to_drop = MaybeUninit::slice_assume_init_mut( + self.array_mut.get_unchecked_mut(..self.initialized), + ); + crate::intrinsics::const_eval_select((to_drop,), drop_ct, drop_rt); } } } diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 6da9f745399e1..aa198cbbd1c63 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -1223,7 +1223,7 @@ pub const fn min(v1: T, v2: T) -> T { #[stable(feature = "cmp_min_max_by", since = "1.53.0")] #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] pub const fn min_by Ordering>(v1: T, v2: T, compare: F) -> T -where +where T: ~const Destruct, { match compare(&v1, &v2) { @@ -1309,6 +1309,7 @@ pub const fn max(v1: T, v2: T) -> T { pub const fn max_by Ordering>(v1: T, v2: T, compare: F) -> T where T: ~const Destruct, +{ match compare(&v1, &v2) { Ordering::Less | Ordering::Equal => v2, Ordering::Greater => v1, diff --git a/library/core/src/const_closure.rs b/library/core/src/const_closure.rs index 151c8e6d8986a..541198624f1a3 100644 --- a/library/core/src/const_closure.rs +++ b/library/core/src/const_closure.rs @@ -25,6 +25,7 @@ pub(crate) struct ConstFnMutClosure { /// The Function of the Closure, must be: Fn(CapturedData, ClosureArgs) -> ClosureReturn pub func: Function, } + impl<'a, CapturedData: ?Sized, Function> ConstFnMutClosure<&'a mut CapturedData, Function> { /// Function for creating a new closure. /// diff --git a/library/core/src/iter/adapters/map.rs b/library/core/src/iter/adapters/map.rs index 9a99cf274645f..8e06d332cdef1 100644 --- a/library/core/src/iter/adapters/map.rs +++ b/library/core/src/iter/adapters/map.rs @@ -1,3 +1,4 @@ +use crate::const_closure::ConstFnMutClosure; use crate::fmt; use crate::iter::adapters::{ zip::try_get_unchecked, SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce, diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index 0c20b35613835..a707d96eae464 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -1,3 +1,4 @@ +use crate::const_closure::ConstFnMutClosure; use crate::iter::{InPlaceIterable, Iterator}; use crate::marker::Destruct; use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try}; diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs index 6bcd2eea57e01..2a6faf4df9257 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs @@ -171,8 +171,9 @@ macro_rules! zip_impl_general_defaults { #[inline] #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_try, const_for))] default fn next(&mut self) -> Option<(A::Item, B::Item)> { - let x = self.a.next()?; - let y = self.b.next()?; + // FIXME(const_trait_impl): revert to `?` when we can + let Some(x) = self.a.next() else { return None }; + let Some(y) = self.b.next() else { return None }; Some((x, y)) } @@ -586,11 +587,12 @@ pub unsafe trait TrustedRandomAccess: ~const TrustedRandomAccessNoCoerce {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] #[rustc_specialization_trait] +#[const_trait] pub unsafe trait TrustedRandomAccessNoCoerce: Sized { // Convenience method. fn size(&self) -> usize where - Self: Iterator, + Self: ~const Iterator, { self.size_hint().0 } diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index bb35d50b4bfda..84b6712d7c1ab 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -364,7 +364,8 @@ macro_rules! impl_fold_via_try_fold { #[inline] fn $fold(mut self, init: AAA, mut fold: FFF) -> AAA where - FFF: FnMut(AAA, Self::Item) -> AAA, + FFF: ~const FnMut(AAA, Self::Item) -> AAA + ~const crate::marker::Destruct, + Self: ~const crate::marker::Destruct, { use crate::const_closure::ConstFnMutClosure; use crate::ops::NeverShortCircuit; diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index ac7b389b15b4d..a52753f5753eb 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -21,6 +21,7 @@ unsafe_impl_trusted_step![char i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usi /// The *successor* operation moves towards values that compare greater. /// The *predecessor* operation moves towards values that compare lesser. #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] +#[const_trait] pub trait Step: Clone + PartialOrd + Sized { /// Returns the number of *successor* steps required to get from `start` to `end`. /// diff --git a/library/core/src/iter/traits/accum.rs b/library/core/src/iter/traits/accum.rs index 84d83ee39699f..9d71ae02837fc 100644 --- a/library/core/src/iter/traits/accum.rs +++ b/library/core/src/iter/traits/accum.rs @@ -10,6 +10,7 @@ use crate::num::Wrapping; /// [`sum()`]: Iterator::sum /// [`FromIterator`]: iter::FromIterator #[stable(feature = "iter_arith_traits", since = "1.12.0")] +#[const_trait] pub trait Sum: Sized { /// Method which takes an iterator and generates `Self` from the elements by /// "summing up" the items. @@ -27,6 +28,7 @@ pub trait Sum: Sized { /// [`product()`]: Iterator::product /// [`FromIterator`]: iter::FromIterator #[stable(feature = "iter_arith_traits", since = "1.12.0")] +#[const_trait] pub trait Product: Sized { /// Method which takes an iterator and generates `Self` from the elements by /// multiplying the items. diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs index 3b7c06f238b4d..10331c0c301f5 100644 --- a/library/core/src/iter/traits/collect.rs +++ b/library/core/src/iter/traits/collect.rs @@ -122,6 +122,7 @@ use crate::marker::Destruct; label = "value of type `{Self}` cannot be built from `std::iter::Iterator`" )] #[rustc_diagnostic_item = "FromIterator"] +#[const_trait] pub trait FromIterator: Sized { /// Creates a value from an iterator. /// @@ -267,7 +268,7 @@ pub trait IntoIterator { #[rustc_const_unstable(feature = "const_intoiterator_identity", issue = "90603")] #[stable(feature = "rust1", since = "1.0.0")] -impl const IntoIterator for I { +impl const IntoIterator for I { type Item = I::Item; type IntoIter = I; diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs index bdf94c792c27c..3f2d9a5733bfc 100644 --- a/library/core/src/iter/traits/double_ended.rs +++ b/library/core/src/iter/traits/double_ended.rs @@ -1,3 +1,5 @@ +use crate::const_closure::ConstFnMutClosure; +use crate::marker::Destruct; use crate::ops::{ControlFlow, Try}; /// An iterator able to yield elements from both ends. @@ -37,6 +39,7 @@ use crate::ops::{ControlFlow, Try}; /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "DoubleEndedIterator")] +#[const_trait] pub trait DoubleEndedIterator: Iterator { /// Removes and returns an element from the end of the iterator. /// @@ -131,9 +134,15 @@ pub trait DoubleEndedIterator: Iterator { /// [`Err(k)`]: Err #[inline] #[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")] - fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { - for i in 0..n { + fn advance_back_by(&mut self, n: usize) -> Result<(), usize> + where + Self::Item: ~const Destruct, + { + // FIXME(const_trait_impl): revert back to for loop + let mut i = 0; + while i < n { self.next_back().ok_or(i)?; + i += 1; } Ok(()) } @@ -181,7 +190,10 @@ pub trait DoubleEndedIterator: Iterator { /// ``` #[inline] #[stable(feature = "iter_nth_back", since = "1.37.0")] - fn nth_back(&mut self, n: usize) -> Option { + fn nth_back(&mut self, n: usize) -> Option + where + Self::Item: ~const Destruct, + { self.advance_back_by(n).ok()?; self.next_back() } @@ -221,8 +233,9 @@ pub trait DoubleEndedIterator: Iterator { fn try_rfold(&mut self, init: B, mut f: F) -> R where Self: Sized, - F: FnMut(B, Self::Item) -> R, - R: Try, + F: ~const FnMut(B, Self::Item) -> R + ~const Destruct, + R: ~const Try, + Self::Item: ~const Destruct, { let mut accum = init; while let Some(x) = self.next_back() { @@ -291,8 +304,9 @@ pub trait DoubleEndedIterator: Iterator { #[stable(feature = "iter_rfold", since = "1.27.0")] fn rfold(mut self, init: B, mut f: F) -> B where - Self: Sized, - F: FnMut(B, Self::Item) -> B, + Self: Sized + ~const Destruct, + F: ~const FnMut(B, Self::Item) -> B + ~const Destruct, + Self::Item: ~const Destruct, { let mut accum = init; while let Some(x) = self.next_back() { @@ -344,19 +358,21 @@ pub trait DoubleEndedIterator: Iterator { /// ``` #[inline] #[stable(feature = "iter_rfind", since = "1.27.0")] - fn rfind

(&mut self, predicate: P) -> Option + fn rfind

(&mut self, mut predicate: P) -> Option where Self: Sized, - P: FnMut(&Self::Item) -> bool, + P: ~const FnMut(&Self::Item) -> bool + ~const Destruct, + Self::Item: ~const Destruct, { #[inline] - fn check(mut predicate: impl FnMut(&T) -> bool) -> impl FnMut((), T) -> ControlFlow { - move |(), x| { - if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::CONTINUE } - } + const fn check bool>( + predicate: &mut F, + ((), x): ((), T), + ) -> ControlFlow { + if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::CONTINUE } } - self.try_rfold((), check(predicate)).break_value() + self.try_rfold((), ConstFnMutClosure::new(&mut predicate, check)).break_value() } } diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 193e3294be98d..84c6ce2565a6b 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -3540,7 +3540,7 @@ pub trait Iterator { /// assert_eq!(xs.iter().cmp_by(&ys, |&x, &y| (2 * x).cmp(&y)), Ordering::Greater); /// ``` #[unstable(feature = "iter_order_by", issue = "64295")] - fn cmp_by(self, other: I, cmp: F) -> Ordering + fn cmp_by(self, other: I, mut cmp: F) -> Ordering where Self: Sized, I: ~const IntoIterator, @@ -3551,17 +3551,17 @@ pub trait Iterator { Self: ~const Destruct, { #[inline] - fn compare(mut cmp: F) -> impl FnMut(X, Y) -> ControlFlow + const fn compare(cmp: &mut F, (x, y): (X, Y)) -> ControlFlow where - F: FnMut(X, Y) -> Ordering, + F: ~const FnMut(X, Y) -> Ordering, { - move |x, y| match cmp(x, y) { + match cmp(x, y) { Ordering::Equal => ControlFlow::CONTINUE, non_eq => ControlFlow::Break(non_eq), } } - match iter_compare(self, other.into_iter(), compare(cmp)) { + match iter_compare(self, other.into_iter(), ConstFnMutClosure::new(&mut cmp, compare)) { ControlFlow::Continue(ord) => ord, ControlFlow::Break(ord) => ord, } @@ -3628,7 +3628,7 @@ pub trait Iterator { /// ); /// ``` #[unstable(feature = "iter_order_by", issue = "64295")] - fn partial_cmp_by(self, other: I, partial_cmp: F) -> Option + fn partial_cmp_by(self, other: I, mut partial_cmp: F) -> Option where Self: Sized, I: ~const IntoIterator, @@ -3639,17 +3639,24 @@ pub trait Iterator { Self: ~const Destruct, { #[inline] - fn compare(mut partial_cmp: F) -> impl FnMut(X, Y) -> ControlFlow> + const fn compare( + partial_cmp: &mut F, + (x, y): (X, Y), + ) -> ControlFlow> where - F: FnMut(X, Y) -> Option, + F: ~const FnMut(X, Y) -> Option, { - move |x, y| match partial_cmp(x, y) { + match partial_cmp(x, y) { Some(Ordering::Equal) => ControlFlow::CONTINUE, non_eq => ControlFlow::Break(non_eq), } } - match iter_compare(self, other.into_iter(), compare(partial_cmp)) { + match iter_compare( + self, + other.into_iter(), + ConstFnMutClosure::new(&mut partial_cmp, compare), + ) { ControlFlow::Continue(ord) => Some(ord), ControlFlow::Break(ord) => ord, } @@ -3700,7 +3707,7 @@ pub trait Iterator { /// assert!(xs.iter().eq_by(&ys, |&x, &y| x * x == y)); /// ``` #[unstable(feature = "iter_order_by", issue = "64295")] - fn eq_by(self, other: I, eq: F) -> bool + fn eq_by(self, other: I, mut eq: F) -> bool where Self: Sized, I: ~const IntoIterator, @@ -3711,16 +3718,14 @@ pub trait Iterator { Self: ~const Destruct, { #[inline] - fn compare(mut eq: F) -> impl FnMut(X, Y) -> ControlFlow<()> + const fn compare(eq: &mut F, (x, y): (X, Y)) -> ControlFlow<()> where - F: FnMut(X, Y) -> bool, + F: ~const FnMut(X, Y) -> bool, { - move |x, y| { - if eq(x, y) { ControlFlow::CONTINUE } else { ControlFlow::BREAK } - } + if eq(x, y) { ControlFlow::CONTINUE } else { ControlFlow::BREAK } } - match iter_compare(self, other.into_iter(), compare(eq)) { + match iter_compare(self, other.into_iter(), ConstFnMutClosure::new(&mut eq, compare)) { ControlFlow::Continue(ord) => ord == Ordering::Equal, ControlFlow::Break(()) => false, } @@ -3981,28 +3986,38 @@ pub trait Iterator { /// Isolates the logic shared by ['cmp_by'](Iterator::cmp_by), /// ['partial_cmp_by'](Iterator::partial_cmp_by), and ['eq_by'](Iterator::eq_by). #[inline] -fn iter_compare(mut a: A, mut b: B, f: F) -> ControlFlow +const fn iter_compare(mut a: A, b: B, f: F) -> ControlFlow where - A: Iterator, - B: Iterator, - F: FnMut(A::Item, B::Item) -> ControlFlow, + A: ~const Iterator + ~const Destruct, + B: ~const Iterator + ~const Destruct, + A::Item: ~const Destruct, + B::Item: ~const Destruct, + F: ~const FnMut(A::Item, B::Item) -> ControlFlow + ~const Destruct, { #[inline] - fn compare<'a, B, X, T>( - b: &'a mut B, - mut f: impl FnMut(X, B::Item) -> ControlFlow + 'a, - ) -> impl FnMut(X) -> ControlFlow> + 'a + const fn compare<'a, B, F, X, T>( + (b, f): &'a mut (B, F), + (x,): (X,), + ) -> ControlFlow> where - B: Iterator, + B: ~const Iterator, + F: ~const FnMut(X, B::Item) -> ControlFlow, + X: ~const Destruct, { - move |x| match b.next() { + match b.next() { None => ControlFlow::Break(ControlFlow::Continue(Ordering::Greater)), - Some(y) => f(x, y).map_break(ControlFlow::Break), + Some(y) => match f(x, y) { + ControlFlow::Break(x) => ControlFlow::Break(ControlFlow::Break(x)), + ControlFlow::Continue(x) => ControlFlow::Continue(x), + }, } } - match a.try_for_each(compare(&mut b, f)) { - ControlFlow::Continue(()) => ControlFlow::Continue(match b.next() { + let mut tuple = (b, f); + let mut f = ConstFnMutClosure::new(&mut tuple, compare); + + match a.try_for_each(&mut f) { + ControlFlow::Continue(()) => ControlFlow::Continue(match f.data.0.next() { None => Ordering::Equal, Some(_) => Ordering::Less, }), diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 727aed856c3b5..75858e2e2ec09 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -123,6 +123,7 @@ #![feature(const_index_range_slice_index)] #![feature(const_inherent_unchecked_arith)] #![feature(const_int_unchecked_arith)] +#![feature(const_intoiterator_identity)] #![feature(const_intrinsic_forget)] #![feature(const_likely)] #![feature(const_maybe_uninit_array_assume_init)] diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs index 28275798f751e..b0889ed2284d9 100644 --- a/library/core/src/tuple.rs +++ b/library/core/src/tuple.rs @@ -41,7 +41,8 @@ macro_rules! tuple_impls { maybe_tuple_doc! { $($T)+ @ #[stable(feature = "rust1", since = "1.0.0")] - impl<$($T: Eq),+> Eq for ($($T,)+) + #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] + impl<$($T: ~const Eq),+> const Eq for ($($T,)+) where last_type!($($T,)+): ?Sized {} diff --git a/src/test/ui/consts/const-fn-error.stderr b/src/test/ui/consts/const-fn-error.stderr index 02960b363e78f..e36324f0b3eea 100644 --- a/src/test/ui/consts/const-fn-error.stderr +++ b/src/test/ui/consts/const-fn-error.stderr @@ -22,8 +22,8 @@ LL | for i in 0..x { note: impl defined here, but it is not `const` --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL | -LL | impl const IntoIterator for I { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl const IntoIterator for I { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error[E0658]: mutable references are not allowed in constant functions diff --git a/src/test/ui/consts/const-for.stderr b/src/test/ui/consts/const-for.stderr index 11e4ae309c01f..f2e1c8a4991a3 100644 --- a/src/test/ui/consts/const-for.stderr +++ b/src/test/ui/consts/const-for.stderr @@ -7,8 +7,8 @@ LL | for _ in 0..5 {} note: impl defined here, but it is not `const` --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL | -LL | impl const IntoIterator for I { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl const IntoIterator for I { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: calls in constants are limited to constant functions, tuple structs and tuple variants error[E0015]: cannot call non-const fn ` as Iterator>::next` in constants diff --git a/src/test/ui/never_type/issue-52443.stderr b/src/test/ui/never_type/issue-52443.stderr index 0910e9ad77a84..3c0daa4c55f01 100644 --- a/src/test/ui/never_type/issue-52443.stderr +++ b/src/test/ui/never_type/issue-52443.stderr @@ -47,8 +47,8 @@ LL | [(); { for _ in 0usize.. {}; 0}]; note: impl defined here, but it is not `const` --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL | -LL | impl const IntoIterator for I { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl const IntoIterator for I { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: calls in constants are limited to constant functions, tuple structs and tuple variants error[E0658]: mutable references are not allowed in constants