Rollup merge of #90009 - woppopo:const_from_more, r=dtolnay

Make more `From` impls `const` (libcore)

Adding `const` to `From` implementations in the core. `rustc_const_unstable` attribute is not added to unstable implementations.

Tracking issue: #88674

<details>
<summary>Done</summary><div>

- `T` from `T`
- `T` from `!`
- `Option<T>` from `T`
- `Option<&T>` from `&Option<T>`
- `Option<&mut T>` from `&mut Option<T>`
- `Cell<T>` from `T`
- `RefCell<T>` from `T`
- `UnsafeCell<T>` from `T`
- `OnceCell<T>` from `T`
- `Poll<T>` from `T`
- `u32` from `char`
- `u64` from `char`
- `u128` from `char`
- `char` from `u8`
- `AtomicBool` from `bool`
- `AtomicPtr<T>` from `*mut T`
- `AtomicI(bits)` from `i(bits)`
- `AtomicU(bits)` from `u(bits)`
- `i(bits)` from `NonZeroI(bits)`
- `u(bits)` from `NonZeroU(bits)`
- `NonNull<T>` from `Unique<T>`
- `NonNull<T>` from `&T`
- `NonNull<T>` from `&mut T`
- `Unique<T>` from `&mut T`
- `Infallible` from `!`
- `TryIntError` from `!`
- `TryIntError` from `Infallible`
- `TryFromSliceError` from `Infallible`
- `FromResidual for Option<T>`
</div></details>

<details>
<summary>Remaining</summary><dev>

- `NonZero` from `NonZero`
These can't be made const at this time because these use Into::into.
https://github.com/rust-lang/rust/blob/master/library/core/src/convert/num.rs#L393

- `std`, `alloc`
There may still be many implementations that can be made `const`.
</div></details>
This commit is contained in:
Yuki Okushi 2021-10-20 04:35:15 +09:00 committed by GitHub
commit 9f2ad0a061
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 103 additions and 27 deletions

View File

@ -125,7 +125,8 @@ impl TryFromSliceError {
}
#[stable(feature = "try_from_slice_error", since = "1.36.0")]
impl From<Infallible> for TryFromSliceError {
#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl const From<Infallible> for TryFromSliceError {
fn from(x: Infallible) -> TryFromSliceError {
match x {}
}

View File

@ -308,7 +308,8 @@ impl<T: Ord + Copy> Ord for Cell<T> {
}
#[stable(feature = "cell_from", since = "1.12.0")]
impl<T> From<T> for Cell<T> {
#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl<T> const From<T> for Cell<T> {
fn from(t: T) -> Cell<T> {
Cell::new(t)
}
@ -1236,7 +1237,8 @@ impl<T: ?Sized + Ord> Ord for RefCell<T> {
}
#[stable(feature = "cell_from", since = "1.12.0")]
impl<T> From<T> for RefCell<T> {
#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl<T> const From<T> for RefCell<T> {
fn from(t: T) -> RefCell<T> {
RefCell::new(t)
}
@ -1976,7 +1978,8 @@ impl<T: Default> Default for UnsafeCell<T> {
}
#[stable(feature = "cell_from", since = "1.12.0")]
impl<T> From<T> for UnsafeCell<T> {
#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl<T> const From<T> for UnsafeCell<T> {
fn from(t: T) -> UnsafeCell<T> {
UnsafeCell::new(t)
}

View File

@ -97,7 +97,8 @@ pub unsafe fn from_u32_unchecked(i: u32) -> char {
}
#[stable(feature = "char_convert", since = "1.13.0")]
impl From<char> for u32 {
#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl const From<char> for u32 {
/// Converts a [`char`] into a [`u32`].
///
/// # Examples
@ -116,7 +117,8 @@ impl From<char> for u32 {
}
#[stable(feature = "more_char_conversions", since = "1.51.0")]
impl From<char> for u64 {
#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl const From<char> for u64 {
/// Converts a [`char`] into a [`u64`].
///
/// # Examples
@ -137,7 +139,8 @@ impl From<char> for u64 {
}
#[stable(feature = "more_char_conversions", since = "1.51.0")]
impl From<char> for u128 {
#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl const From<char> for u128 {
/// Converts a [`char`] into a [`u128`].
///
/// # Examples
@ -176,7 +179,8 @@ impl From<char> for u128 {
/// for a superset of Windows-1252 that fills the remaining blanks with corresponding
/// C0 and C1 control codes.
#[stable(feature = "char_convert", since = "1.13.0")]
impl From<u8> for char {
#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl const From<u8> for char {
/// Converts a [`u8`] into a [`char`].
///
/// # Examples

View File

@ -545,7 +545,8 @@ where
// From (and thus Into) is reflexive
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> From<T> for T {
#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl<T> const From<T> for T {
fn from(t: T) -> T {
t
}
@ -560,7 +561,8 @@ impl<T> From<T> for T {
#[allow(unused_attributes)] // FIXME(#58633): do a principled fix instead.
#[rustc_reservation_impl = "permitting this impl would forbid us from adding \
`impl<T> From<!> for T` later; see rust-lang/rust#64715 for details"]
impl<T> From<!> for T {
#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl<T> const From<!> for T {
fn from(t: !) -> T {
t
}
@ -726,7 +728,8 @@ impl Ord for Infallible {
}
#[stable(feature = "convert_infallible", since = "1.34.0")]
impl From<!> for Infallible {
#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl const From<!> for Infallible {
fn from(x: !) -> Self {
x
}

View File

@ -74,7 +74,7 @@ impl<T: PartialEq> PartialEq for OnceCell<T> {
impl<T: Eq> Eq for OnceCell<T> {}
#[unstable(feature = "once_cell", issue = "74465")]
impl<T> From<T> for OnceCell<T> {
impl<T> const From<T> for OnceCell<T> {
fn from(value: T) -> Self {
OnceCell { inner: UnsafeCell::new(Some(value)) }
}

View File

@ -29,14 +29,15 @@ impl fmt::Display for TryFromIntError {
}
#[stable(feature = "try_from", since = "1.34.0")]
impl From<Infallible> for TryFromIntError {
#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl const From<Infallible> for TryFromIntError {
fn from(x: Infallible) -> TryFromIntError {
match x {}
}
}
#[unstable(feature = "never_type", issue = "35121")]
impl From<!> for TryFromIntError {
impl const From<!> for TryFromIntError {
fn from(never: !) -> TryFromIntError {
// Match rather than coerce to make sure that code like
// `From<Infallible> for TryFromIntError` above will keep working

View File

@ -82,7 +82,8 @@ macro_rules! nonzero_integers {
}
#[stable(feature = "from_nonzero", since = "1.31.0")]
impl From<$Ty> for $Int {
#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl const From<$Ty> for $Int {
#[doc = concat!("Converts a `", stringify!($Ty), "` into an `", stringify!($Int), "`")]
#[inline]
fn from(nonzero: $Ty) -> Self {

View File

@ -1723,7 +1723,8 @@ impl<'a, T> IntoIterator for &'a mut Option<T> {
}
#[stable(since = "1.12.0", feature = "option_from")]
impl<T> From<T> for Option<T> {
#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl<T> const From<T> for Option<T> {
/// Moves `val` into a new [`Some`].
///
/// # Examples
@ -1739,7 +1740,8 @@ impl<T> From<T> for Option<T> {
}
#[stable(feature = "option_ref_from_ref_option", since = "1.30.0")]
impl<'a, T> From<&'a Option<T>> for Option<&'a T> {
#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl<'a, T> const From<&'a Option<T>> for Option<&'a T> {
/// Converts from `&Option<T>` to `Option<&T>`.
///
/// # Examples
@ -1766,7 +1768,8 @@ impl<'a, T> From<&'a Option<T>> for Option<&'a T> {
}
#[stable(feature = "option_ref_from_ref_option", since = "1.30.0")]
impl<'a, T> From<&'a mut Option<T>> for Option<&'a mut T> {
#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl<'a, T> const From<&'a mut Option<T>> for Option<&'a mut T> {
/// Converts from `&mut Option<T>` to `Option<&mut T>`
///
/// # Examples
@ -2052,7 +2055,7 @@ impl<T> ops::Try for Option<T> {
}
#[unstable(feature = "try_trait_v2", issue = "84277")]
impl<T> ops::FromResidual for Option<T> {
impl<T> const ops::FromResidual for Option<T> {
#[inline]
fn from_residual(residual: Option<convert::Infallible>) -> Self {
match residual {

View File

@ -698,7 +698,8 @@ impl<T: ?Sized> hash::Hash for NonNull<T> {
}
#[unstable(feature = "ptr_internals", issue = "none")]
impl<T: ?Sized> From<Unique<T>> for NonNull<T> {
#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl<T: ?Sized> const From<Unique<T>> for NonNull<T> {
#[inline]
fn from(unique: Unique<T>) -> Self {
// SAFETY: A Unique pointer cannot be null, so the conditions for
@ -708,7 +709,8 @@ impl<T: ?Sized> From<Unique<T>> for NonNull<T> {
}
#[stable(feature = "nonnull", since = "1.25.0")]
impl<T: ?Sized> From<&mut T> for NonNull<T> {
#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl<T: ?Sized> const From<&mut T> for NonNull<T> {
#[inline]
fn from(reference: &mut T) -> Self {
// SAFETY: A mutable reference cannot be null.
@ -717,7 +719,8 @@ impl<T: ?Sized> From<&mut T> for NonNull<T> {
}
#[stable(feature = "nonnull", since = "1.25.0")]
impl<T: ?Sized> From<&T> for NonNull<T> {
#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl<T: ?Sized> const From<&T> for NonNull<T> {
#[inline]
fn from(reference: &T) -> Self {
// SAFETY: A reference cannot be null, so the conditions for

View File

@ -176,7 +176,7 @@ impl<T: ?Sized> fmt::Pointer for Unique<T> {
}
#[unstable(feature = "ptr_internals", issue = "none")]
impl<T: ?Sized> From<&mut T> for Unique<T> {
impl<T: ?Sized> const From<&mut T> for Unique<T> {
#[inline]
fn from(reference: &mut T) -> Self {
// SAFETY: A mutable reference cannot be null

View File

@ -1273,7 +1273,8 @@ impl<T> AtomicPtr<T> {
#[cfg(target_has_atomic_load_store = "8")]
#[stable(feature = "atomic_bool_from", since = "1.24.0")]
impl From<bool> for AtomicBool {
#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl const From<bool> for AtomicBool {
/// Converts a `bool` into an `AtomicBool`.
///
/// # Examples
@ -1291,7 +1292,8 @@ impl From<bool> for AtomicBool {
#[cfg(target_has_atomic_load_store = "ptr")]
#[stable(feature = "atomic_from", since = "1.23.0")]
impl<T> From<*mut T> for AtomicPtr<T> {
#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl<T> const From<*mut T> for AtomicPtr<T> {
#[inline]
fn from(p: *mut T) -> Self {
Self::new(p)
@ -1363,7 +1365,8 @@ macro_rules! atomic_int {
}
#[$stable_from]
impl From<$int_type> for $atomic_type {
#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl const From<$int_type> for $atomic_type {
#[doc = concat!("Converts an `", stringify!($int_type), "` into an `", stringify!($atomic_type), "`.")]
#[inline]
fn from(v: $int_type) -> Self { Self::new(v) }

View File

@ -241,7 +241,8 @@ impl<T, E> Poll<Option<Result<T, E>>> {
}
#[stable(feature = "futures_api", since = "1.36.0")]
impl<T> From<T> for Poll<T> {
#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl<T> const From<T> for Poll<T> {
/// Convert to a `Ready` variant.
///
/// # Example

View File

@ -220,3 +220,10 @@ fn atomic_compare_exchange() {
ATOMIC.compare_exchange_weak(0, 1, SeqCst, Acquire).ok();
ATOMIC.compare_exchange_weak(0, 1, SeqCst, SeqCst).ok();
}
#[test]
fn atomic_const_from() {
const _ATOMIC_U8: AtomicU8 = AtomicU8::from(1);
const _ATOMIC_BOOL: AtomicBool = AtomicBool::from(true);
const _ATOMIC_PTR: AtomicPtr<u32> = AtomicPtr::from(core::ptr::null_mut());
}

View File

@ -465,4 +465,13 @@ fn const_cells() {
const CELL: Cell<i32> = Cell::new(3);
const _: i32 = CELL.into_inner();
const UNSAFE_CELL_FROM: UnsafeCell<i32> = UnsafeCell::from(3);
const _: i32 = UNSAFE_CELL.into_inner();
const REF_CELL_FROM: RefCell<i32> = RefCell::from(3);
const _: i32 = REF_CELL.into_inner();
const CELL_FROM: Cell<i32> = Cell::from(3);
const _: i32 = CELL.into_inner();
}

View File

@ -5,6 +5,8 @@ use std::{char, str};
#[test]
fn test_convert() {
assert_eq!(u32::from('a'), 0x61);
assert_eq!(u64::from('b'), 0x62);
assert_eq!(u128::from('c'), 0x63);
assert_eq!(char::from(b'\0'), '\0');
assert_eq!(char::from(b'a'), 'a');
assert_eq!(char::from(b'\xFF'), '\u{FF}');
@ -19,6 +21,16 @@ fn test_convert() {
assert!(char::try_from(0xFFFF_FFFF_u32).is_err());
}
#[test]
const fn test_convert_const() {
assert!(u32::from('a') == 0x61);
assert!(u64::from('b') == 0x62);
assert!(u128::from('c') == 0x63);
assert!(char::from(b'\0') == '\0');
assert!(char::from(b'a') == 'a');
assert!(char::from(b'\xFF') == '\u{FF}');
}
#[test]
fn test_from_str() {
assert_eq!(char::from_str("a").unwrap(), 'a');

View File

@ -47,6 +47,12 @@ fn unsync_once_cell_drop_empty() {
drop(x);
}
#[test]
const fn once_cell_const() {
let _once_cell: OnceCell<u32> = OnceCell::new();
let _once_cell: OnceCell<u32> = OnceCell::from(32);
}
#[test]
fn clone() {
let s = OnceCell::new();

View File

@ -9,6 +9,7 @@
#![feature(cfg_target_has_atomic)]
#![feature(const_assume)]
#![feature(const_cell_into_inner)]
#![feature(const_convert)]
#![feature(const_maybe_uninit_assume_init)]
#![cfg_attr(bootstrap, feature(const_panic))]
#![feature(const_ptr_read)]

View File

@ -214,6 +214,9 @@ fn nonzero_const() {
const ONE: Option<NonZeroU8> = NonZeroU8::new(1);
assert!(ONE.is_some());
const FROM_NONZERO: u8 = u8::from(NONZERO);
assert_eq!(FROM_NONZERO, 5);
}
#[test]

View File

@ -358,10 +358,17 @@ fn option_const() {
// test that the methods of `Option` are usable in a const context
const OPTION: Option<usize> = Some(32);
assert_eq!(OPTION, Some(32));
const OPTION_FROM: Option<usize> = Option::from(32);
assert_eq!(OPTION_FROM, Some(32));
const REF: Option<&usize> = OPTION.as_ref();
assert_eq!(REF, Some(&32));
const REF_FROM: Option<&usize> = Option::from(&OPTION);
assert_eq!(REF_FROM, Some(&32));
const IS_SOME: bool = OPTION.is_some();
assert!(IS_SOME);
@ -388,6 +395,14 @@ const fn option_const_mut() {
None => unreachable!(),
}
}
{
let as_mut: Option<&mut usize> = Option::from(&mut option);
match as_mut {
Some(v) => *v = 42,
None => unreachable!(),
}
}
}
#[test]