Skip to content

Commit

Permalink
Rollup merge of rust-lang#90009 - woppopo:const_from_more, r=dtolnay
Browse files Browse the repository at this point in the history
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: rust-lang#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>
  • Loading branch information
GuillaumeGomez committed Oct 19, 2021
2 parents 21de245 + 7936ecf commit d6af6c9
Show file tree
Hide file tree
Showing 19 changed files with 103 additions and 27 deletions.
3 changes: 2 additions & 1 deletion library/core/src/array/mod.rs
Expand Up @@ -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 {}
}
Expand Down
9 changes: 6 additions & 3 deletions library/core/src/cell.rs
Expand Up @@ -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)
}
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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)
}
Expand Down
12 changes: 8 additions & 4 deletions library/core/src/char/convert.rs
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
9 changes: 6 additions & 3 deletions library/core/src/convert/mod.rs
Expand Up @@ -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
}
Expand All @@ -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
}
Expand Down Expand Up @@ -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
}
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/lazy.rs
Expand Up @@ -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)) }
}
Expand Down
5 changes: 3 additions & 2 deletions library/core/src/num/error.rs
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion library/core/src/num/nonzero.rs
Expand Up @@ -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 {
Expand Down
11 changes: 7 additions & 4 deletions library/core/src/option.rs
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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 {
Expand Down
9 changes: 6 additions & 3 deletions library/core/src/ptr/non_null.rs
Expand Up @@ -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
Expand All @@ -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.
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/ptr/unique.rs
Expand Up @@ -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
Expand Down
9 changes: 6 additions & 3 deletions library/core/src/sync/atomic.rs
Expand Up @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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) }
Expand Down
3 changes: 2 additions & 1 deletion library/core/src/task/poll.rs
Expand Up @@ -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
Expand Down
7 changes: 7 additions & 0 deletions library/core/tests/atomic.rs
Expand Up @@ -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());
}
9 changes: 9 additions & 0 deletions library/core/tests/cell.rs
Expand Up @@ -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();
}
12 changes: 12 additions & 0 deletions library/core/tests/char.rs
Expand Up @@ -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}');
Expand All @@ -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');
Expand Down
6 changes: 6 additions & 0 deletions library/core/tests/lazy.rs
Expand Up @@ -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();
Expand Down
1 change: 1 addition & 0 deletions library/core/tests/lib.rs
Expand Up @@ -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)]
Expand Down
3 changes: 3 additions & 0 deletions library/core/tests/nonzero.rs
Expand Up @@ -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]
Expand Down
15 changes: 15 additions & 0 deletions library/core/tests/option.rs
Expand Up @@ -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);

Expand All @@ -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]
Expand Down

0 comments on commit d6af6c9

Please sign in to comment.