From 159e67d44646621f157f07b61f7d78f231c452c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20D=C3=B6nszelmann?= Date: Fri, 11 Oct 2024 00:14:17 +0200 Subject: [PATCH 01/10] rename RcBox to RcInner for consistency --- library/alloc/src/rc.rs | 138 +++++++++++++++++++++------------------- 1 file changed, 71 insertions(+), 67 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 0e2c35845e8f0..e6f27f5363999 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -282,19 +282,19 @@ mod tests; // would interfere with otherwise safe [into|from]_raw() of transmutable // inner types. #[repr(C)] -struct RcBox { +struct RcInner { strong: Cell, weak: Cell, value: T, } -/// Calculate layout for `RcBox` using the inner value's layout +/// Calculate layout for `RcInner` using the inner value's layout fn rcbox_layout_for_value_layout(layout: Layout) -> Layout { // Calculate layout using the given value layout. // Previously, layout was calculated on the expression - // `&*(ptr as *const RcBox)`, but this created a misaligned + // `&*(ptr as *const RcInner)`, but this created a misaligned // reference (see #54908). - Layout::new::>().extend(layout).unwrap().0.pad_to_align() + Layout::new::>().extend(layout).unwrap().0.pad_to_align() } /// A single-threaded reference-counting pointer. 'Rc' stands for 'Reference @@ -314,8 +314,8 @@ pub struct Rc< T: ?Sized, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, > { - ptr: NonNull>, - phantom: PhantomData>, + ptr: NonNull>, + phantom: PhantomData>, alloc: A, } @@ -343,37 +343,37 @@ impl, U: ?Sized> DispatchFromDyn> for Rc {} impl Rc { #[inline] - unsafe fn from_inner(ptr: NonNull>) -> Self { + unsafe fn from_inner(ptr: NonNull>) -> Self { unsafe { Self::from_inner_in(ptr, Global) } } #[inline] - unsafe fn from_ptr(ptr: *mut RcBox) -> Self { + unsafe fn from_ptr(ptr: *mut RcInner) -> Self { unsafe { Self::from_inner(NonNull::new_unchecked(ptr)) } } } impl Rc { #[inline(always)] - fn inner(&self) -> &RcBox { + fn inner(&self) -> &RcInner { // This unsafety is ok because while this Rc is alive we're guaranteed // that the inner pointer is valid. unsafe { self.ptr.as_ref() } } #[inline] - fn into_inner_with_allocator(this: Self) -> (NonNull>, A) { + fn into_inner_with_allocator(this: Self) -> (NonNull>, A) { let this = mem::ManuallyDrop::new(this); (this.ptr, unsafe { ptr::read(&this.alloc) }) } #[inline] - unsafe fn from_inner_in(ptr: NonNull>, alloc: A) -> Self { + unsafe fn from_inner_in(ptr: NonNull>, alloc: A) -> Self { Self { ptr, phantom: PhantomData, alloc } } #[inline] - unsafe fn from_ptr_in(ptr: *mut RcBox, alloc: A) -> Self { + unsafe fn from_ptr_in(ptr: *mut RcInner, alloc: A) -> Self { unsafe { Self::from_inner_in(NonNull::new_unchecked(ptr), alloc) } } } @@ -397,7 +397,7 @@ impl Rc { // if the weak pointer is stored inside the strong one. unsafe { Self::from_inner( - Box::leak(Box::new(RcBox { strong: Cell::new(1), weak: Cell::new(1), value })) + Box::leak(Box::new(RcInner { strong: Cell::new(1), weak: Cell::new(1), value })) .into(), ) } @@ -546,8 +546,12 @@ impl Rc { // if the weak pointer is stored inside the strong one. unsafe { Ok(Self::from_inner( - Box::leak(Box::try_new(RcBox { strong: Cell::new(1), weak: Cell::new(1), value })?) - .into(), + Box::leak(Box::try_new(RcInner { + strong: Cell::new(1), + weak: Cell::new(1), + value, + })?) + .into(), )) } } @@ -646,7 +650,7 @@ impl Rc { // That would make code size bigger. match Self::try_new_in(value, alloc) { Ok(m) => m, - Err(_) => handle_alloc_error(Layout::new::>()), + Err(_) => handle_alloc_error(Layout::new::>()), } } @@ -765,7 +769,7 @@ impl Rc { // Construct the inner in the "uninitialized" state with a single // weak reference. let (uninit_raw_ptr, alloc) = Box::into_raw_with_allocator(Box::new_in( - RcBox { + RcInner { strong: Cell::new(0), weak: Cell::new(1), value: mem::MaybeUninit::::uninit(), @@ -773,7 +777,7 @@ impl Rc { alloc, )); let uninit_ptr: NonNull<_> = (unsafe { &mut *uninit_raw_ptr }).into(); - let init_ptr: NonNull> = uninit_ptr.cast(); + let init_ptr: NonNull> = uninit_ptr.cast(); let weak = Weak { ptr: init_ptr, alloc: alloc }; @@ -826,7 +830,7 @@ impl Rc { // the allocation while the strong destructor is running, even // if the weak pointer is stored inside the strong one. let (ptr, alloc) = Box::into_unique(Box::try_new_in( - RcBox { strong: Cell::new(1), weak: Cell::new(1), value }, + RcInner { strong: Cell::new(1), weak: Cell::new(1), value }, alloc, )?); Ok(unsafe { Self::from_inner_in(ptr.into(), alloc) }) @@ -1059,7 +1063,7 @@ impl Rc<[T]> { |layout| Global.allocate_zeroed(layout), |mem| { ptr::slice_from_raw_parts_mut(mem.cast::(), len) - as *mut RcBox<[mem::MaybeUninit]> + as *mut RcInner<[mem::MaybeUninit]> }, )) } @@ -1132,7 +1136,7 @@ impl Rc<[T], A> { |layout| alloc.allocate_zeroed(layout), |mem| { ptr::slice_from_raw_parts_mut(mem.cast::(), len) - as *mut RcBox<[mem::MaybeUninit]> + as *mut RcInner<[mem::MaybeUninit]> }, ), alloc, @@ -1437,7 +1441,7 @@ impl Rc { #[stable(feature = "weak_into_raw", since = "1.45.0")] #[rustc_never_returns_null_ptr] pub fn as_ptr(this: &Self) -> *const T { - let ptr: *mut RcBox = NonNull::as_ptr(this.ptr); + let ptr: *mut RcInner = NonNull::as_ptr(this.ptr); // SAFETY: This cannot go through Deref::deref or Rc::inner because // this is required to retain raw/mut provenance such that e.g. `get_mut` can @@ -1516,8 +1520,8 @@ impl Rc { pub unsafe fn from_raw_in(ptr: *const T, alloc: A) -> Self { let offset = unsafe { data_offset(ptr) }; - // Reverse the offset to find the original RcBox. - let rc_ptr = unsafe { ptr.byte_sub(offset) as *mut RcBox }; + // Reverse the offset to find the original RcInner. + let rc_ptr = unsafe { ptr.byte_sub(offset) as *mut RcInner }; unsafe { Self::from_ptr_in(rc_ptr, alloc) } } @@ -2002,17 +2006,17 @@ impl Rc { } impl Rc { - /// Allocates an `RcBox` with sufficient space for + /// Allocates an `RcInner` with sufficient space for /// a possibly-unsized inner value where the value has the layout provided. /// /// The function `mem_to_rcbox` is called with the data pointer - /// and must return back a (potentially fat)-pointer for the `RcBox`. + /// and must return back a (potentially fat)-pointer for the `RcInner`. #[cfg(not(no_global_oom_handling))] unsafe fn allocate_for_layout( value_layout: Layout, allocate: impl FnOnce(Layout) -> Result, AllocError>, - mem_to_rcbox: impl FnOnce(*mut u8) -> *mut RcBox, - ) -> *mut RcBox { + mem_to_rcbox: impl FnOnce(*mut u8) -> *mut RcInner, + ) -> *mut RcInner { let layout = rcbox_layout_for_value_layout(value_layout); unsafe { Rc::try_allocate_for_layout(value_layout, allocate, mem_to_rcbox) @@ -2020,24 +2024,24 @@ impl Rc { } } - /// Allocates an `RcBox` with sufficient space for + /// Allocates an `RcInner` with sufficient space for /// a possibly-unsized inner value where the value has the layout provided, /// returning an error if allocation fails. /// /// The function `mem_to_rcbox` is called with the data pointer - /// and must return back a (potentially fat)-pointer for the `RcBox`. + /// and must return back a (potentially fat)-pointer for the `RcInner`. #[inline] unsafe fn try_allocate_for_layout( value_layout: Layout, allocate: impl FnOnce(Layout) -> Result, AllocError>, - mem_to_rcbox: impl FnOnce(*mut u8) -> *mut RcBox, - ) -> Result<*mut RcBox, AllocError> { + mem_to_rcbox: impl FnOnce(*mut u8) -> *mut RcInner, + ) -> Result<*mut RcInner, AllocError> { let layout = rcbox_layout_for_value_layout(value_layout); // Allocate for the layout. let ptr = allocate(layout)?; - // Initialize the RcBox + // Initialize the RcInner let inner = mem_to_rcbox(ptr.as_non_null_ptr().as_ptr()); unsafe { debug_assert_eq!(Layout::for_value_raw(inner), layout); @@ -2051,15 +2055,15 @@ impl Rc { } impl Rc { - /// Allocates an `RcBox` with sufficient space for an unsized inner value + /// Allocates an `RcInner` with sufficient space for an unsized inner value #[cfg(not(no_global_oom_handling))] - unsafe fn allocate_for_ptr_in(ptr: *const T, alloc: &A) -> *mut RcBox { - // Allocate for the `RcBox` using the given value. + unsafe fn allocate_for_ptr_in(ptr: *const T, alloc: &A) -> *mut RcInner { + // Allocate for the `RcInner` using the given value. unsafe { Rc::::allocate_for_layout( Layout::for_value_raw(ptr), |layout| alloc.allocate(layout), - |mem| mem.with_metadata_of(ptr as *const RcBox), + |mem| mem.with_metadata_of(ptr as *const RcInner), ) } } @@ -2088,14 +2092,14 @@ impl Rc { } impl Rc<[T]> { - /// Allocates an `RcBox<[T]>` with the given length. + /// Allocates an `RcInner<[T]>` with the given length. #[cfg(not(no_global_oom_handling))] - unsafe fn allocate_for_slice(len: usize) -> *mut RcBox<[T]> { + unsafe fn allocate_for_slice(len: usize) -> *mut RcInner<[T]> { unsafe { Self::allocate_for_layout( Layout::array::(len).unwrap(), |layout| Global.allocate(layout), - |mem| ptr::slice_from_raw_parts_mut(mem.cast::(), len) as *mut RcBox<[T]>, + |mem| ptr::slice_from_raw_parts_mut(mem.cast::(), len) as *mut RcInner<[T]>, ) } } @@ -2119,7 +2123,7 @@ impl Rc<[T]> { unsafe fn from_iter_exact(iter: impl Iterator, len: usize) -> Rc<[T]> { // Panic guard while cloning T elements. // In the event of a panic, elements that have been written - // into the new RcBox will be dropped, then the memory freed. + // into the new RcInner will be dropped, then the memory freed. struct Guard { mem: NonNull, elems: *mut T, @@ -2154,7 +2158,7 @@ impl Rc<[T]> { guard.n_elems += 1; } - // All clear. Forget the guard so it doesn't free the new RcBox. + // All clear. Forget the guard so it doesn't free the new RcInner. mem::forget(guard); Self::from_ptr(ptr) @@ -2163,15 +2167,15 @@ impl Rc<[T]> { } impl Rc<[T], A> { - /// Allocates an `RcBox<[T]>` with the given length. + /// Allocates an `RcInner<[T]>` with the given length. #[inline] #[cfg(not(no_global_oom_handling))] - unsafe fn allocate_for_slice_in(len: usize, alloc: &A) -> *mut RcBox<[T]> { + unsafe fn allocate_for_slice_in(len: usize, alloc: &A) -> *mut RcInner<[T]> { unsafe { Rc::<[T]>::allocate_for_layout( Layout::array::(len).unwrap(), |layout| alloc.allocate(layout), - |mem| ptr::slice_from_raw_parts_mut(mem.cast::(), len) as *mut RcBox<[T]>, + |mem| ptr::slice_from_raw_parts_mut(mem.cast::(), len) as *mut RcInner<[T]>, ) } } @@ -2901,9 +2905,9 @@ pub struct Weak< // but it is not necessarily a valid pointer. // `Weak::new` sets this to `usize::MAX` so that it doesn’t need // to allocate space on the heap. That's not a value a real pointer - // will ever have because RcBox has alignment at least 2. + // will ever have because RcInner has alignment at least 2. // This is only possible when `T: Sized`; unsized `T` never dangle. - ptr: NonNull>, + ptr: NonNull>, alloc: A, } @@ -2939,7 +2943,7 @@ impl Weak { pub const fn new() -> Weak { Weak { ptr: unsafe { - NonNull::new_unchecked(ptr::without_provenance_mut::>(usize::MAX)) + NonNull::new_unchecked(ptr::without_provenance_mut::>(usize::MAX)) }, alloc: Global, } @@ -2966,7 +2970,7 @@ impl Weak { pub fn new_in(alloc: A) -> Weak { Weak { ptr: unsafe { - NonNull::new_unchecked(ptr::without_provenance_mut::>(usize::MAX)) + NonNull::new_unchecked(ptr::without_provenance_mut::>(usize::MAX)) }, alloc, } @@ -3070,11 +3074,11 @@ impl Weak { #[must_use] #[stable(feature = "rc_as_ptr", since = "1.45.0")] pub fn as_ptr(&self) -> *const T { - let ptr: *mut RcBox = NonNull::as_ptr(self.ptr); + let ptr: *mut RcInner = NonNull::as_ptr(self.ptr); if is_dangling(ptr) { // If the pointer is dangling, we return the sentinel directly. This cannot be - // a valid payload address, as the payload is at least as aligned as RcBox (usize). + // a valid payload address, as the payload is at least as aligned as RcInner (usize). ptr as *const T } else { // SAFETY: if is_dangling returns false, then the pointer is dereferenceable. @@ -3206,14 +3210,14 @@ impl Weak { let ptr = if is_dangling(ptr) { // This is a dangling Weak. - ptr as *mut RcBox + ptr as *mut RcInner } else { // Otherwise, we're guaranteed the pointer came from a nondangling Weak. // SAFETY: data_offset is safe to call, as ptr references a real (potentially dropped) T. let offset = unsafe { data_offset(ptr) }; - // Thus, we reverse the offset to get the whole RcBox. + // Thus, we reverse the offset to get the whole RcInner. // SAFETY: the pointer originated from a Weak, so this offset is safe. - unsafe { ptr.byte_sub(offset) as *mut RcBox } + unsafe { ptr.byte_sub(offset) as *mut RcInner } }; // SAFETY: we now have recovered the original Weak pointer, so can create the Weak. @@ -3288,7 +3292,7 @@ impl Weak { } } - /// Returns `None` when the pointer is dangling and there is no allocated `RcBox`, + /// Returns `None` when the pointer is dangling and there is no allocated `RcInner`, /// (i.e., when this `Weak` was created by `Weak::new`). #[inline] fn inner(&self) -> Option> { @@ -3522,7 +3526,7 @@ trait RcInnerPtr { } } -impl RcInnerPtr for RcBox { +impl RcInnerPtr for RcInner { #[inline(always)] fn weak_ref(&self) -> &Cell { &self.weak @@ -3563,15 +3567,15 @@ impl AsRef for Rc { #[stable(feature = "pin", since = "1.33.0")] impl Unpin for Rc {} -/// Gets the offset within an `RcBox` for the payload behind a pointer. +/// Gets the offset within an `RcInner` for the payload behind a pointer. /// /// # Safety /// /// The pointer must point to (and have valid metadata for) a previously /// valid instance of T, but the T is allowed to be dropped. unsafe fn data_offset(ptr: *const T) -> usize { - // Align the unsized value to the end of the RcBox. - // Because RcBox is repr(C), it will always be the last field in memory. + // Align the unsized value to the end of the RcInner. + // Because RcInner is repr(C), it will always be the last field in memory. // SAFETY: since the only unsized types possible are slices, trait objects, // and extern types, the input safety requirement is currently enough to // satisfy the requirements of align_of_val_raw; this is an implementation @@ -3581,7 +3585,7 @@ unsafe fn data_offset(ptr: *const T) -> usize { #[inline] fn data_offset_align(align: usize) -> usize { - let layout = Layout::new::>(); + let layout = Layout::new::>(); layout.size() + layout.padding_needed_for(align) } @@ -3627,8 +3631,8 @@ pub struct UniqueRc< T: ?Sized, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, > { - ptr: NonNull>, - phantom: PhantomData>, + ptr: NonNull>, + phantom: PhantomData>, alloc: A, } @@ -3664,7 +3668,7 @@ impl UniqueRc { #[unstable(feature = "unique_rc_arc", issue = "112566")] pub fn new_in(value: T, alloc: A) -> Self { let (ptr, alloc) = Box::into_unique(Box::new_in( - RcBox { + RcInner { strong: Cell::new(0), // keep one weak reference so if all the weak pointers that are created are dropped // the UniqueRc still stays valid. @@ -3759,7 +3763,7 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for UniqueRc { } } -/// A unique owning pointer to a [`RcBox`] **that does not imply the contents are initialized,** +/// A unique owning pointer to a [`RcInner`] **that does not imply the contents are initialized,** /// but will deallocate it (without dropping the value) when dropped. /// /// This is a helper for [`Rc::make_mut()`] to ensure correct cleanup on panic. @@ -3767,21 +3771,21 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for UniqueRc { /// which `MaybeUninit` does not. #[cfg(not(no_global_oom_handling))] struct UniqueRcUninit { - ptr: NonNull>, + ptr: NonNull>, layout_for_value: Layout, alloc: Option, } #[cfg(not(no_global_oom_handling))] impl UniqueRcUninit { - /// Allocates a RcBox with layout suitable to contain `for_value` or a clone of it. + /// Allocates a RcInner with layout suitable to contain `for_value` or a clone of it. fn new(for_value: &T, alloc: A) -> UniqueRcUninit { let layout = Layout::for_value(for_value); let ptr = unsafe { Rc::allocate_for_layout( layout, |layout_for_rcbox| alloc.allocate(layout_for_rcbox), - |mem| mem.with_metadata_of(ptr::from_ref(for_value) as *const RcBox), + |mem| mem.with_metadata_of(ptr::from_ref(for_value) as *const RcInner), ) }; Self { ptr: NonNull::new(ptr).unwrap(), layout_for_value: layout, alloc: Some(alloc) } From 0a9c87b1f5d871a3f2cc44c274a7bc72a486e69d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20D=C3=B6nszelmann?= Date: Fri, 11 Oct 2024 00:56:56 +0200 Subject: [PATCH 02/10] rename RcBox in other places too --- compiler/rustc_codegen_ssa/src/mir/block.rs | 4 ++-- compiler/rustc_ty_utils/src/abi.rs | 6 +++--- library/alloc/src/sync.rs | 8 ++++---- library/core/src/cell.rs | 14 +++++++------- src/etc/lldb_providers.py | 4 ++-- src/etc/natvis/liballoc.natvis | 2 +- src/tools/miri/tests/fail/memleak_rc.stderr | 4 ++-- tests/debuginfo/strings-and-strs.rs | 3 +-- tests/ui/abi/compatibility.rs | 6 +++--- 9 files changed, 25 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index be9a6d9a90eed..e3553dc03e106 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -992,10 +992,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { match op.val { Pair(data_ptr, meta) => { // In the case of Rc, we need to explicitly pass a - // *mut RcBox with a Scalar (not ScalarPair) ABI. This is a hack + // *mut RcInner with a Scalar (not ScalarPair) ABI. This is a hack // that is understood elsewhere in the compiler as a method on // `dyn Trait`. - // To get a `*mut RcBox`, we just keep unwrapping newtypes until + // To get a `*mut RcInner`, we just keep unwrapping newtypes until // we get a value of a built-in pointer type. // // This is also relevant for `Pin<&mut Self>`, where we need to peel the diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index deda16b76b587..7354ea5fb6a22 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -822,10 +822,10 @@ fn make_thin_self_ptr<'tcx>( _ => bug!("receiver type has unsupported layout: {:?}", layout), } - // In the case of Rc, we need to explicitly pass a *mut RcBox + // In the case of Rc, we need to explicitly pass a *mut RcInner // with a Scalar (not ScalarPair) ABI. This is a hack that is understood // elsewhere in the compiler as a method on a `dyn Trait`. - // To get the type `*mut RcBox`, we just keep unwrapping newtypes until we + // To get the type `*mut RcInner`, we just keep unwrapping newtypes until we // get a built-in pointer type let mut wide_pointer_layout = layout; while !wide_pointer_layout.ty.is_unsafe_ptr() && !wide_pointer_layout.ty.is_ref() { @@ -838,7 +838,7 @@ fn make_thin_self_ptr<'tcx>( wide_pointer_layout.ty }; - // we now have a type like `*mut RcBox` + // we now have a type like `*mut RcInner` // change its layout to that of `*mut ()`, a thin pointer, but keep the same type // this is understood as a special case elsewhere in the compiler let unit_ptr_ty = Ty::new_mut_ptr(tcx, tcx.types.unit); diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 5d099a49854af..4632f995b82e3 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -319,7 +319,7 @@ pub struct Weak< // but it is not necessarily a valid pointer. // `Weak::new` sets this to `usize::MAX` so that it doesn’t need // to allocate space on the heap. That's not a value a real pointer - // will ever have because RcBox has alignment at least 2. + // will ever have because RcInner has alignment at least 2. // This is only possible when `T: Sized`; unsized `T` never dangle. ptr: NonNull>, alloc: A, @@ -1581,7 +1581,7 @@ impl Arc { pub fn as_ptr(this: &Self) -> *const T { let ptr: *mut ArcInner = NonNull::as_ptr(this.ptr); - // SAFETY: This cannot go through Deref::deref or RcBoxPtr::inner because + // SAFETY: This cannot go through Deref::deref or RcInnerPtr::inner because // this is required to retain raw/mut provenance such that e.g. `get_mut` can // write through the pointer after the Rc is recovered through `from_raw`. unsafe { &raw mut (*ptr).data } @@ -2936,7 +2936,7 @@ impl Weak { // Otherwise, we're guaranteed the pointer came from a nondangling Weak. // SAFETY: data_offset is safe to call, as ptr references a real (potentially dropped) T. let offset = unsafe { data_offset(ptr) }; - // Thus, we reverse the offset to get the whole RcBox. + // Thus, we reverse the offset to get the whole RcInner. // SAFETY: the pointer originated from a Weak, so this offset is safe. unsafe { ptr.byte_sub(offset) as *mut ArcInner } }; @@ -3861,7 +3861,7 @@ impl Unpin for Arc {} /// valid instance of T, but the T is allowed to be dropped. unsafe fn data_offset(ptr: *const T) -> usize { // Align the unsized value to the end of the ArcInner. - // Because RcBox is repr(C), it will always be the last field in memory. + // Because RcInner is repr(C), it will always be the last field in memory. // SAFETY: since the only unsized types possible are slices, trait objects, // and extern types, the input safety requirement is currently enough to // satisfy the requirements of align_of_val_raw; this is an implementation diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 8ccd1a44ff163..513b9cbcefcac 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -193,11 +193,11 @@ //! use std::marker::PhantomData; //! //! struct Rc { -//! ptr: NonNull>, -//! phantom: PhantomData>, +//! ptr: NonNull>, +//! phantom: PhantomData>, //! } //! -//! struct RcBox { +//! struct RcInner { //! strong: Cell, //! refcount: Cell, //! value: T, @@ -213,9 +213,9 @@ //! } //! } //! -//! trait RcBoxPtr { +//! trait RcInnerPtr { //! -//! fn inner(&self) -> &RcBox; +//! fn inner(&self) -> &RcInner; //! //! fn strong(&self) -> usize { //! self.inner().strong.get() @@ -230,8 +230,8 @@ //! } //! } //! -//! impl RcBoxPtr for Rc { -//! fn inner(&self) -> &RcBox { +//! impl RcInnerPtr for Rc { +//! fn inner(&self) -> &RcInner { //! unsafe { //! self.ptr.as_ref() //! } diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py index 8750d7682d136..bace228454ebb 100644 --- a/src/etc/lldb_providers.py +++ b/src/etc/lldb_providers.py @@ -670,11 +670,11 @@ def StdRcSummaryProvider(valobj, dict): class StdRcSyntheticProvider: """Pretty-printer for alloc::rc::Rc and alloc::sync::Arc - struct Rc { ptr: NonNull>, ... } + struct Rc { ptr: NonNull>, ... } rust 1.31.1: struct NonNull { pointer: NonZero<*const T> } rust 1.33.0: struct NonNull { pointer: *const T } struct NonZero(T) - struct RcBox { strong: Cell, weak: Cell, value: T } + struct RcInner { strong: Cell, weak: Cell, value: T } struct Cell { value: UnsafeCell } struct UnsafeCell { value: T } diff --git a/src/etc/natvis/liballoc.natvis b/src/etc/natvis/liballoc.natvis index 49d82dfad820b..1528a8b1226ca 100644 --- a/src/etc/natvis/liballoc.natvis +++ b/src/etc/natvis/liballoc.natvis @@ -95,7 +95,7 @@ ptr.pointer.data_ptr->weak ptr.pointer.length - + ($T1*)(((size_t*)ptr.pointer.data_ptr) + 2) diff --git a/src/tools/miri/tests/fail/memleak_rc.stderr b/src/tools/miri/tests/fail/memleak_rc.stderr index 820e10743bc51..df12eeed6ac64 100644 --- a/src/tools/miri/tests/fail/memleak_rc.stderr +++ b/src/tools/miri/tests/fail/memleak_rc.stderr @@ -1,8 +1,8 @@ error: memory leaked: ALLOC (Rust heap, SIZE, ALIGN), allocated here: --> RUSTLIB/alloc/src/rc.rs:LL:CC | -LL | Box::leak(Box::new(RcBox { strong: Cell::new(1), weak: Cell::new(1), value })) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Box::leak(Box::new(RcInner { strong: Cell::new(1), weak: Cell::new(1), value })) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: BACKTRACE: = note: inside `std::rc::Rc::>>::new` at RUSTLIB/alloc/src/rc.rs:LL:CC diff --git a/tests/debuginfo/strings-and-strs.rs b/tests/debuginfo/strings-and-strs.rs index b7ee3312d1311..3d6589db34b88 100644 --- a/tests/debuginfo/strings-and-strs.rs +++ b/tests/debuginfo/strings-and-strs.rs @@ -19,8 +19,7 @@ // gdb-check:$4 = ("Hello", "World") // gdb-command:print str_in_rc -// gdb-check:$5 = alloc::rc::Rc<&str, alloc::alloc::Global> {ptr: core::ptr::non_null::NonNull> {pointer: 0x[...]}, phantom: core::marker::PhantomData>, alloc: alloc::alloc::Global} - +// gdb-check:$5 = alloc::rc::Rc<&str, alloc::alloc::Global> {ptr: core::ptr::non_null::NonNull> {pointer: 0x[...]}, phantom: core::marker::PhantomData>, alloc: alloc::alloc::Global} // === LLDB TESTS ================================================================================== // lldb-command:run diff --git a/tests/ui/abi/compatibility.rs b/tests/ui/abi/compatibility.rs index b439a4bcf867b..28c8063a92311 100644 --- a/tests/ui/abi/compatibility.rs +++ b/tests/ui/abi/compatibility.rs @@ -160,14 +160,14 @@ mod prelude { pub struct Box(Unique, A); #[repr(C)] - struct RcBox { + struct RcInner { strong: UnsafeCell, weak: UnsafeCell, value: T, } pub struct Rc { - ptr: NonNull>, - phantom: PhantomData>, + ptr: NonNull>, + phantom: PhantomData>, alloc: A, } From 9e0a7b99b5d3677d3c90b11b57ec56a6a2c4f162 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20D=C3=B6nszelmann?= Date: Sun, 13 Oct 2024 21:08:47 +0200 Subject: [PATCH 03/10] rename rcbox in other places as per review comments --- library/alloc/src/rc.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index e6f27f5363999..e98ae7c31ad06 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -289,7 +289,7 @@ struct RcInner { } /// Calculate layout for `RcInner` using the inner value's layout -fn rcbox_layout_for_value_layout(layout: Layout) -> Layout { +fn rc_inner_layout_for_value_layout(layout: Layout) -> Layout { // Calculate layout using the given value layout. // Previously, layout was calculated on the expression // `&*(ptr as *const RcInner)`, but this created a misaligned @@ -2009,17 +2009,17 @@ impl Rc { /// Allocates an `RcInner` with sufficient space for /// a possibly-unsized inner value where the value has the layout provided. /// - /// The function `mem_to_rcbox` is called with the data pointer + /// The function `mem_to_rc_inner` is called with the data pointer /// and must return back a (potentially fat)-pointer for the `RcInner`. #[cfg(not(no_global_oom_handling))] unsafe fn allocate_for_layout( value_layout: Layout, allocate: impl FnOnce(Layout) -> Result, AllocError>, - mem_to_rcbox: impl FnOnce(*mut u8) -> *mut RcInner, + mem_to_rc_inner: impl FnOnce(*mut u8) -> *mut RcInner, ) -> *mut RcInner { - let layout = rcbox_layout_for_value_layout(value_layout); + let layout = rc_inner_layout_for_value_layout(value_layout); unsafe { - Rc::try_allocate_for_layout(value_layout, allocate, mem_to_rcbox) + Rc::try_allocate_for_layout(value_layout, allocate, mem_to_rc_inner) .unwrap_or_else(|_| handle_alloc_error(layout)) } } @@ -2028,21 +2028,21 @@ impl Rc { /// a possibly-unsized inner value where the value has the layout provided, /// returning an error if allocation fails. /// - /// The function `mem_to_rcbox` is called with the data pointer + /// The function `mem_to_rc_inner` is called with the data pointer /// and must return back a (potentially fat)-pointer for the `RcInner`. #[inline] unsafe fn try_allocate_for_layout( value_layout: Layout, allocate: impl FnOnce(Layout) -> Result, AllocError>, - mem_to_rcbox: impl FnOnce(*mut u8) -> *mut RcInner, + mem_to_rc_inner: impl FnOnce(*mut u8) -> *mut RcInner, ) -> Result<*mut RcInner, AllocError> { - let layout = rcbox_layout_for_value_layout(value_layout); + let layout = rc_inner_layout_for_value_layout(value_layout); // Allocate for the layout. let ptr = allocate(layout)?; // Initialize the RcInner - let inner = mem_to_rcbox(ptr.as_non_null_ptr().as_ptr()); + let inner = mem_to_rc_inner(ptr.as_non_null_ptr().as_ptr()); unsafe { debug_assert_eq!(Layout::for_value_raw(inner), layout); @@ -3784,7 +3784,7 @@ impl UniqueRcUninit { let ptr = unsafe { Rc::allocate_for_layout( layout, - |layout_for_rcbox| alloc.allocate(layout_for_rcbox), + |layout_for_rc_inner| alloc.allocate(layout_for_rc_inner), |mem| mem.with_metadata_of(ptr::from_ref(for_value) as *const RcInner), ) }; @@ -3820,10 +3820,10 @@ impl Drop for UniqueRcUninit { // * new() produced a pointer safe to deallocate. // * We own the pointer unless into_rc() was called, which forgets us. unsafe { - self.alloc - .take() - .unwrap() - .deallocate(self.ptr.cast(), rcbox_layout_for_value_layout(self.layout_for_value)); + self.alloc.take().unwrap().deallocate( + self.ptr.cast(), + rc_inner_layout_for_value_layout(self.layout_for_value), + ); } } } From f8ac1c44dba23d425cb630a9e8b334a5781462fb Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Sat, 31 Aug 2024 03:02:30 +0530 Subject: [PATCH 04/10] uefi: Implement getcwd and chdir - Using EFI Shell Protocol. These functions do not make much sense unless a shell is present. - Return the exe dir in case shell protocol is missing. Signed-off-by: Ayush Singh --- library/std/src/sys/pal/uefi/helpers.rs | 24 ++++++---- library/std/src/sys/pal/uefi/os.rs | 63 +++++++++++++++++++++++-- 2 files changed, 73 insertions(+), 14 deletions(-) diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs index bd8a6684b64f9..4ced7065c826d 100644 --- a/library/std/src/sys/pal/uefi/helpers.rs +++ b/library/std/src/sys/pal/uefi/helpers.rs @@ -177,16 +177,8 @@ pub(crate) fn device_path_to_text(path: NonNull) -> io::R ) }; - // SAFETY: `convert_device_path_to_text` returns a pointer to a null-terminated UTF-16 - // string, and that string cannot be deallocated prior to dropping the `WStrUnits`, so - // it's safe for `WStrUnits` to use. - let path_len = unsafe { - WStrUnits::new(path_ptr) - .ok_or(io::const_io_error!(io::ErrorKind::InvalidData, "Invalid path"))? - .count() - }; - - let path = OsString::from_wide(unsafe { slice::from_raw_parts(path_ptr.cast(), path_len) }); + let path = os_string_from_raw(path_ptr) + .ok_or(io::const_io_error!(io::ErrorKind::InvalidData, "Invalid path"))?; if let Some(boot_services) = crate::os::uefi::env::boot_services() { let boot_services: NonNull = boot_services.cast(); @@ -420,3 +412,15 @@ impl Drop for OwnedTable { unsafe { crate::alloc::dealloc(self.ptr as *mut u8, self.layout) }; } } + +/// Create OsString from a pointer to NULL terminated UTF-16 string +pub(crate) fn os_string_from_raw(ptr: *mut r_efi::efi::Char16) -> Option { + let path_len = unsafe { WStrUnits::new(ptr)?.count() }; + Some(OsString::from_wide(unsafe { slice::from_raw_parts(ptr.cast(), path_len) })) +} + +/// Create NULL terminated UTF-16 string +pub(crate) fn os_string_to_raw(s: &OsStr) -> Option> { + let temp = s.encode_wide().chain(Some(0)).collect::>(); + if temp[..temp.len() - 1].contains(&0) { None } else { Some(temp) } +} diff --git a/library/std/src/sys/pal/uefi/os.rs b/library/std/src/sys/pal/uefi/os.rs index 9aee67d622fad..4eb7698b43aa9 100644 --- a/library/std/src/sys/pal/uefi/os.rs +++ b/library/std/src/sys/pal/uefi/os.rs @@ -1,7 +1,7 @@ use r_efi::efi::Status; use r_efi::efi::protocols::{device_path, loaded_image_device_path}; -use super::{RawOsError, helpers, unsupported}; +use super::{RawOsError, helpers, unsupported_err}; use crate::error::Error as StdError; use crate::ffi::{OsStr, OsString}; use crate::marker::PhantomData; @@ -125,11 +125,32 @@ pub fn error_string(errno: RawOsError) -> String { } pub fn getcwd() -> io::Result { - unsupported() + match uefi_shell::open_shell() { + Some(shell) => { + // SAFETY: path_ptr is managed by UEFI shell and should not be deallocated + let path_ptr = unsafe { ((*shell.as_ptr()).get_cur_dir)(crate::ptr::null_mut()) }; + helpers::os_string_from_raw(path_ptr) + .map(PathBuf::from) + .ok_or(io::const_io_error!(io::ErrorKind::InvalidData, "Invalid path")) + } + None => { + let mut t = current_exe()?; + // SAFETY: This should never fail since the disk prefix will be present even for root + // executables + assert!(t.pop()); + Ok(t) + } + } } -pub fn chdir(_: &path::Path) -> io::Result<()> { - unsupported() +pub fn chdir(p: &path::Path) -> io::Result<()> { + let shell = uefi_shell::open_shell().ok_or(unsupported_err())?; + + let mut p = helpers::os_string_to_raw(p.as_os_str()) + .ok_or(io::const_io_error!(io::ErrorKind::InvalidData, "Invalid path"))?; + + let r = unsafe { ((*shell.as_ptr()).set_cur_dir)(crate::ptr::null_mut(), p.as_mut_ptr()) }; + if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) } } pub struct SplitPaths<'a>(!, PhantomData<&'a ()>); @@ -239,3 +260,37 @@ pub fn exit(code: i32) -> ! { pub fn getpid() -> u32 { panic!("no pids on this platform") } + +mod uefi_shell { + use r_efi::protocols::shell; + + use super::super::helpers; + use crate::ptr::NonNull; + use crate::sync::atomic::{AtomicPtr, Ordering}; + + pub fn open_shell() -> Option> { + static LAST_VALID_HANDLE: AtomicPtr = + AtomicPtr::new(crate::ptr::null_mut()); + + if let Some(handle) = NonNull::new(LAST_VALID_HANDLE.load(Ordering::Acquire)) { + if let Ok(protocol) = helpers::open_protocol::( + handle, + r_efi::protocols::shell::PROTOCOL_GUID, + ) { + return Some(protocol); + } + } + + let handles = helpers::locate_handles(shell::PROTOCOL_GUID).ok()?; + for handle in handles { + if let Ok(protocol) = + helpers::open_protocol::(handle, shell::PROTOCOL_GUID) + { + LAST_VALID_HANDLE.store(handle.as_ptr(), Ordering::Release); + return Some(protocol); + } + } + + None + } +} From 5a8405a5fa55526af743a44abf9c57d1452afbaa Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 14 Oct 2024 14:18:13 -0400 Subject: [PATCH 05/10] Don't report on_unimplemented for negative traits --- .../rustc_hir_typeck/src/method/suggest.rs | 2 +- .../traits/fulfillment_errors.rs | 2 +- .../traits/on_unimplemented.rs | 20 +++++++++++-------- .../negative-bounds/on-unimplemented.rs | 12 +++++++++++ .../negative-bounds/on-unimplemented.stderr | 18 +++++++++++++++++ 5 files changed, 44 insertions(+), 10 deletions(-) create mode 100644 tests/ui/traits/negative-bounds/on-unimplemented.rs create mode 100644 tests/ui/traits/negative-bounds/on-unimplemented.stderr diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 4f726f3ed3866..0933e90f8ba2a 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -952,7 +952,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { continue; } unimplemented_traits.entry(p.trait_ref.def_id).or_insert(( - predicate.kind().rebind(p.trait_ref), + predicate.kind().rebind(p), Obligation { cause: cause.clone(), param_env: self.param_env, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 824c25db07d2e..26b0faca2585f 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -202,7 +202,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { notes, parent_label, append_const_msg, - } = self.on_unimplemented_note(main_trait_ref, o, &mut long_ty_file); + } = self.on_unimplemented_note(main_trait_predicate, o, &mut long_ty_file); let have_alt_message = message.is_some() || label.is_some(); let is_try_conversion = self.is_try_conversion(span, main_trait_ref.def_id()); diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs index c3100c48b0aa2..cd41ab9fa6cb0 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs @@ -9,7 +9,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_macros::LintDiagnostic; use rustc_middle::bug; use rustc_middle::ty::print::PrintTraitRefExt as _; -use rustc_middle::ty::{self, GenericArgsRef, GenericParamDefKind, TyCtxt}; +use rustc_middle::ty::{self, GenericArgsRef, GenericParamDefKind, ToPolyTraitRef, TyCtxt}; use rustc_parse_format::{ParseMode, Parser, Piece, Position}; use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES; use rustc_span::Span; @@ -108,14 +108,18 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { pub fn on_unimplemented_note( &self, - trait_ref: ty::PolyTraitRef<'tcx>, + trait_pred: ty::PolyTraitPredicate<'tcx>, obligation: &PredicateObligation<'tcx>, long_ty_file: &mut Option, ) -> OnUnimplementedNote { + if trait_pred.polarity() != ty::PredicatePolarity::Positive { + return OnUnimplementedNote::default(); + } + let (def_id, args) = self - .impl_similar_to(trait_ref, obligation) - .unwrap_or_else(|| (trait_ref.def_id(), trait_ref.skip_binder().args)); - let trait_ref = trait_ref.skip_binder(); + .impl_similar_to(trait_pred.to_poly_trait_ref(), obligation) + .unwrap_or_else(|| (trait_pred.def_id(), trait_pred.skip_binder().trait_ref.args)); + let trait_pred = trait_pred.skip_binder(); let mut flags = vec![]; // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): HIR is not present for RPITITs, @@ -144,13 +148,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { flags.push((sym::cause, Some("MainFunctionType".to_string()))); } - flags.push((sym::Trait, Some(trait_ref.print_trait_sugared().to_string()))); + flags.push((sym::Trait, Some(trait_pred.trait_ref.print_trait_sugared().to_string()))); // Add all types without trimmed paths or visible paths, ensuring they end up with // their "canonical" def path. ty::print::with_no_trimmed_paths!(ty::print::with_no_visible_paths!({ let generics = self.tcx.generics_of(def_id); - let self_ty = trait_ref.self_ty(); + let self_ty = trait_pred.self_ty(); // This is also included through the generics list as `Self`, // but the parser won't allow you to use it flags.push((sym::_Self, Some(self_ty.to_string()))); @@ -266,7 +270,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { })); if let Ok(Some(command)) = OnUnimplementedDirective::of_item(self.tcx, def_id) { - command.evaluate(self.tcx, trait_ref, &flags, long_ty_file) + command.evaluate(self.tcx, trait_pred.trait_ref, &flags, long_ty_file) } else { OnUnimplementedNote::default() } diff --git a/tests/ui/traits/negative-bounds/on-unimplemented.rs b/tests/ui/traits/negative-bounds/on-unimplemented.rs new file mode 100644 index 0000000000000..34582590861fe --- /dev/null +++ b/tests/ui/traits/negative-bounds/on-unimplemented.rs @@ -0,0 +1,12 @@ +#![feature(negative_bounds)] + +#[diagnostic::on_unimplemented(message = "this ain't fooing")] +trait Foo {} +struct NotFoo; + +fn hello() -> impl !Foo { + //~^ ERROR the trait bound `NotFoo: !Foo` is not satisfied + NotFoo +} + +fn main() {} diff --git a/tests/ui/traits/negative-bounds/on-unimplemented.stderr b/tests/ui/traits/negative-bounds/on-unimplemented.stderr new file mode 100644 index 0000000000000..07483e788e5b8 --- /dev/null +++ b/tests/ui/traits/negative-bounds/on-unimplemented.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `NotFoo: !Foo` is not satisfied + --> $DIR/on-unimplemented.rs:7:15 + | +LL | fn hello() -> impl !Foo { + | ^^^^^^^^^ the trait bound `NotFoo: !Foo` is not satisfied +LL | +LL | NotFoo + | ------ return type was inferred to be `NotFoo` here + | +help: this trait has no implementations, consider adding one + --> $DIR/on-unimplemented.rs:4:1 + | +LL | trait Foo {} + | ^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. From b73e613e008fd4a07a52ec7cef7c3af7db716b3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduardo=20S=C3=A1nchez=20Mu=C3=B1oz?= Date: Mon, 14 Oct 2024 20:58:32 +0200 Subject: [PATCH 06/10] De-duplicate and move `adjust_nan` to `InterpCx` --- .../rustc_const_eval/src/interpret/cast.rs | 27 +++++++------------ .../src/interpret/eval_context.rs | 8 ++++++ .../src/interpret/operator.rs | 3 +-- src/tools/miri/src/operator.rs | 4 --- 4 files changed, 19 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 30b5a8d70bc33..1def3d08328ac 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -334,19 +334,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { { use rustc_type_ir::TyKind::*; - fn adjust_nan< - 'tcx, - M: Machine<'tcx>, - F1: rustc_apfloat::Float + FloatConvert, - F2: rustc_apfloat::Float, - >( - ecx: &InterpCx<'tcx, M>, - f1: F1, - f2: F2, - ) -> F2 { - if f2.is_nan() { M::generate_nan(ecx, &[f1]) } else { f2 } - } - match *dest_ty.kind() { // float -> uint Uint(t) => { @@ -367,11 +354,17 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } // float -> float Float(fty) => match fty { - FloatTy::F16 => Scalar::from_f16(adjust_nan(self, f, f.convert(&mut false).value)), - FloatTy::F32 => Scalar::from_f32(adjust_nan(self, f, f.convert(&mut false).value)), - FloatTy::F64 => Scalar::from_f64(adjust_nan(self, f, f.convert(&mut false).value)), + FloatTy::F16 => { + Scalar::from_f16(self.adjust_nan(f.convert(&mut false).value, &[f])) + } + FloatTy::F32 => { + Scalar::from_f32(self.adjust_nan(f.convert(&mut false).value, &[f])) + } + FloatTy::F64 => { + Scalar::from_f64(self.adjust_nan(f.convert(&mut false).value, &[f])) + } FloatTy::F128 => { - Scalar::from_f128(adjust_nan(self, f, f.convert(&mut false).value)) + Scalar::from_f128(self.adjust_nan(f.convert(&mut false).value, &[f])) } }, // That's it. diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 5165f95afd5b7..02dd7821ef667 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -599,6 +599,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { pub fn generate_stacktrace(&self) -> Vec> { Frame::generate_stacktrace_from_stack(self.stack()) } + + pub fn adjust_nan(&self, f: F2, inputs: &[F1]) -> F2 + where + F1: rustc_apfloat::Float + rustc_apfloat::FloatConvert, + F2: rustc_apfloat::Float, + { + if f.is_nan() { M::generate_nan(self, inputs) } else { f } + } } #[doc(hidden)] diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index 52cd9b898bb72..b28ac68ac54ae 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -64,8 +64,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { use rustc_middle::mir::BinOp::*; // Performs appropriate non-deterministic adjustments of NaN results. - let adjust_nan = - |f: F| -> F { if f.is_nan() { M::generate_nan(self, &[l, r]) } else { f } }; + let adjust_nan = |f: F| -> F { self.adjust_nan(f, &[l, r]) }; match bin_op { Eq => ImmTy::from_bool(l == r, *self.tcx), diff --git a/src/tools/miri/src/operator.rs b/src/tools/miri/src/operator.rs index c0911fa717f50..8e06f4258d614 100644 --- a/src/tools/miri/src/operator.rs +++ b/src/tools/miri/src/operator.rs @@ -115,8 +115,4 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { nan } } - - fn adjust_nan, F2: Float>(&self, f: F2, inputs: &[F1]) -> F2 { - if f.is_nan() { self.generate_nan(inputs) } else { f } - } } From c09ed3e767a73d83673790f74c357432fa44d320 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduardo=20S=C3=A1nchez=20Mu=C3=B1oz?= Date: Mon, 14 Oct 2024 21:02:13 +0200 Subject: [PATCH 07/10] Make some float methods unstable `const fn` Some float methods are now `const fn` under the `const_float_methods` feature gate. In order to support `min`, `max`, `abs` and `copysign`, the implementation of some intrinsics had to be moved from Miri to rustc_const_eval. --- .../src/interpret/intrinsics.rs | 80 ++++ library/core/src/intrinsics.rs | 387 +++++++++++------- library/core/src/lib.rs | 1 + library/core/src/num/f128.rs | 42 +- library/core/src/num/f16.rs | 42 +- library/core/src/num/f32.rs | 33 +- library/core/src/num/f64.rs | 33 +- library/std/src/f128.rs | 9 +- library/std/src/f16.rs | 9 +- library/std/src/f32.rs | 9 +- library/std/src/f64.rs | 9 +- library/std/src/lib.rs | 1 + src/tools/miri/src/intrinsics/mod.rs | 39 -- tests/ui/consts/const-eval/float_methods.rs | 47 +++ 14 files changed, 498 insertions(+), 243 deletions(-) create mode 100644 tests/ui/consts/const-eval/float_methods.rs diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 52780cc6a3a6f..540898ec6456c 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -4,6 +4,7 @@ use std::assert_matches::assert_matches; +use rustc_apfloat::ieee::{Double, Half, Quad, Single}; use rustc_hir::def_id::DefId; use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic}; use rustc_middle::ty::layout::{LayoutOf as _, TyAndLayout, ValidityRequirement}; @@ -438,6 +439,26 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.write_scalar(Scalar::from_target_usize(align.bytes(), self), dest)?; } + sym::minnumf16 => self.float_min_intrinsic::(args, dest)?, + sym::minnumf32 => self.float_min_intrinsic::(args, dest)?, + sym::minnumf64 => self.float_min_intrinsic::(args, dest)?, + sym::minnumf128 => self.float_min_intrinsic::(args, dest)?, + + sym::maxnumf16 => self.float_max_intrinsic::(args, dest)?, + sym::maxnumf32 => self.float_max_intrinsic::(args, dest)?, + sym::maxnumf64 => self.float_max_intrinsic::(args, dest)?, + sym::maxnumf128 => self.float_max_intrinsic::(args, dest)?, + + sym::copysignf16 => self.float_copysign_intrinsic::(args, dest)?, + sym::copysignf32 => self.float_copysign_intrinsic::(args, dest)?, + sym::copysignf64 => self.float_copysign_intrinsic::(args, dest)?, + sym::copysignf128 => self.float_copysign_intrinsic::(args, dest)?, + + sym::fabsf16 => self.float_abs_intrinsic::(args, dest)?, + sym::fabsf32 => self.float_abs_intrinsic::(args, dest)?, + sym::fabsf64 => self.float_abs_intrinsic::(args, dest)?, + sym::fabsf128 => self.float_abs_intrinsic::(args, dest)?, + // Unsupported intrinsic: skip the return_to_block below. _ => return interp_ok(false), } @@ -697,4 +718,63 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let rhs_bytes = get_bytes(self, rhs)?; interp_ok(Scalar::from_bool(lhs_bytes == rhs_bytes)) } + + fn float_min_intrinsic( + &mut self, + args: &[OpTy<'tcx, M::Provenance>], + dest: &MPlaceTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, ()> + where + F: rustc_apfloat::Float + rustc_apfloat::FloatConvert + Into>, + { + let a: F = self.read_scalar(&args[0])?.to_float()?; + let b: F = self.read_scalar(&args[1])?.to_float()?; + let res = self.adjust_nan(a.min(b), &[a, b]); + self.write_scalar(res, dest)?; + interp_ok(()) + } + + fn float_max_intrinsic( + &mut self, + args: &[OpTy<'tcx, M::Provenance>], + dest: &MPlaceTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, ()> + where + F: rustc_apfloat::Float + rustc_apfloat::FloatConvert + Into>, + { + let a: F = self.read_scalar(&args[0])?.to_float()?; + let b: F = self.read_scalar(&args[1])?.to_float()?; + let res = self.adjust_nan(a.max(b), &[a, b]); + self.write_scalar(res, dest)?; + interp_ok(()) + } + + fn float_copysign_intrinsic( + &mut self, + args: &[OpTy<'tcx, M::Provenance>], + dest: &MPlaceTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, ()> + where + F: rustc_apfloat::Float + rustc_apfloat::FloatConvert + Into>, + { + let a: F = self.read_scalar(&args[0])?.to_float()?; + let b: F = self.read_scalar(&args[1])?.to_float()?; + // bitwise, no NaN adjustments + self.write_scalar(a.copy_sign(b), dest)?; + interp_ok(()) + } + + fn float_abs_intrinsic( + &mut self, + args: &[OpTy<'tcx, M::Provenance>], + dest: &MPlaceTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, ()> + where + F: rustc_apfloat::Float + rustc_apfloat::FloatConvert + Into>, + { + let x: F = self.read_scalar(&args[0])?.to_float()?; + // bitwise, no NaN adjustments + self.write_scalar(x.abs(), dest)?; + interp_ok(()) + } } diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 061fba9a1f785..3ae729e76e1c7 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1848,154 +1848,6 @@ extern "rust-intrinsic" { #[cfg(not(bootstrap))] pub fn fmuladdf128(a: f128, b: f128, c: f128) -> f128; - /// Returns the absolute value of an `f16`. - /// - /// The stabilized version of this intrinsic is - /// [`f16::abs`](../../std/primitive.f16.html#method.abs) - #[rustc_nounwind] - pub fn fabsf16(x: f16) -> f16; - /// Returns the absolute value of an `f32`. - /// - /// The stabilized version of this intrinsic is - /// [`f32::abs`](../../std/primitive.f32.html#method.abs) - #[rustc_nounwind] - pub fn fabsf32(x: f32) -> f32; - /// Returns the absolute value of an `f64`. - /// - /// The stabilized version of this intrinsic is - /// [`f64::abs`](../../std/primitive.f64.html#method.abs) - #[rustc_nounwind] - pub fn fabsf64(x: f64) -> f64; - /// Returns the absolute value of an `f128`. - /// - /// The stabilized version of this intrinsic is - /// [`f128::abs`](../../std/primitive.f128.html#method.abs) - #[rustc_nounwind] - pub fn fabsf128(x: f128) -> f128; - - /// Returns the minimum of two `f16` values. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized version of this intrinsic is - /// [`f16::min`] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn minnumf16(x: f16, y: f16) -> f16; - /// Returns the minimum of two `f32` values. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized version of this intrinsic is - /// [`f32::min`] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn minnumf32(x: f32, y: f32) -> f32; - /// Returns the minimum of two `f64` values. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized version of this intrinsic is - /// [`f64::min`] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn minnumf64(x: f64, y: f64) -> f64; - /// Returns the minimum of two `f128` values. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized version of this intrinsic is - /// [`f128::min`] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn minnumf128(x: f128, y: f128) -> f128; - - /// Returns the maximum of two `f16` values. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized version of this intrinsic is - /// [`f16::max`] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn maxnumf16(x: f16, y: f16) -> f16; - /// Returns the maximum of two `f32` values. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized version of this intrinsic is - /// [`f32::max`] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn maxnumf32(x: f32, y: f32) -> f32; - /// Returns the maximum of two `f64` values. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized version of this intrinsic is - /// [`f64::max`] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn maxnumf64(x: f64, y: f64) -> f64; - /// Returns the maximum of two `f128` values. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized version of this intrinsic is - /// [`f128::max`] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn maxnumf128(x: f128, y: f128) -> f128; - - /// Copies the sign from `y` to `x` for `f16` values. - /// - /// The stabilized version of this intrinsic is - /// [`f16::copysign`](../../std/primitive.f16.html#method.copysign) - #[rustc_nounwind] - pub fn copysignf16(x: f16, y: f16) -> f16; - /// Copies the sign from `y` to `x` for `f32` values. - /// - /// The stabilized version of this intrinsic is - /// [`f32::copysign`](../../std/primitive.f32.html#method.copysign) - #[rustc_nounwind] - pub fn copysignf32(x: f32, y: f32) -> f32; - /// Copies the sign from `y` to `x` for `f64` values. - /// - /// The stabilized version of this intrinsic is - /// [`f64::copysign`](../../std/primitive.f64.html#method.copysign) - #[rustc_nounwind] - pub fn copysignf64(x: f64, y: f64) -> f64; - /// Copies the sign from `y` to `x` for `f128` values. - /// - /// The stabilized version of this intrinsic is - /// [`f128::copysign`](../../std/primitive.f128.html#method.copysign) - #[rustc_nounwind] - pub fn copysignf128(x: f128, y: f128) -> f128; - /// Returns the largest integer less than or equal to an `f16`. /// /// The stabilized version of this intrinsic is @@ -3550,6 +3402,245 @@ pub const unsafe fn write_bytes(dst: *mut T, val: u8, count: usize) { } } +/// Returns the minimum of two `f16` values. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized version of this intrinsic is +/// [`f16::min`] +#[rustc_nounwind] +// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[rustc_const_unstable(feature = "f16", issue = "116909")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn minnumf16(_x: f16, _y: f16) -> f16 { + unimplemented!(); +} + +/// Returns the minimum of two `f32` values. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized version of this intrinsic is +/// [`f32::min`] +#[rustc_nounwind] +#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn minnumf32(_x: f32, _y: f32) -> f32 { + unimplemented!(); +} + +/// Returns the minimum of two `f64` values. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized version of this intrinsic is +/// [`f64::min`] +#[rustc_nounwind] +#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn minnumf64(_x: f64, _y: f64) -> f64 { + unimplemented!(); +} + +/// Returns the minimum of two `f128` values. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized version of this intrinsic is +/// [`f128::min`] +#[rustc_nounwind] +// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[rustc_const_unstable(feature = "f128", issue = "116909")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn minnumf128(_x: f128, _y: f128) -> f128 { + unimplemented!(); +} + +/// Returns the maximum of two `f16` values. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized version of this intrinsic is +/// [`f16::max`] +#[rustc_nounwind] +// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[rustc_const_unstable(feature = "f16", issue = "116909")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn maxnumf16(_x: f16, _y: f16) -> f16 { + unimplemented!(); +} + +/// Returns the maximum of two `f32` values. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized version of this intrinsic is +/// [`f32::max`] +#[rustc_nounwind] +#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn maxnumf32(_x: f32, _y: f32) -> f32 { + unimplemented!(); +} + +/// Returns the maximum of two `f64` values. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized version of this intrinsic is +/// [`f64::max`] +#[rustc_nounwind] +#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn maxnumf64(_x: f64, _y: f64) -> f64 { + unimplemented!(); +} + +/// Returns the maximum of two `f128` values. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized version of this intrinsic is +/// [`f128::max`] +#[rustc_nounwind] +// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[rustc_const_unstable(feature = "f128", issue = "116909")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn maxnumf128(_x: f128, _y: f128) -> f128 { + unimplemented!(); +} + +/// Returns the absolute value of an `f16`. +/// +/// The stabilized version of this intrinsic is +/// [`f16::abs`](../../std/primitive.f16.html#method.abs) +#[rustc_nounwind] +// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[rustc_const_unstable(feature = "f16", issue = "116909")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn fabsf16(_x: f16) -> f16 { + unimplemented!(); +} + +/// Returns the absolute value of an `f32`. +/// +/// The stabilized version of this intrinsic is +/// [`f32::abs`](../../std/primitive.f32.html#method.abs) +#[rustc_nounwind] +#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn fabsf32(_x: f32) -> f32 { + unimplemented!(); +} + +/// Returns the absolute value of an `f64`. +/// +/// The stabilized version of this intrinsic is +/// [`f64::abs`](../../std/primitive.f64.html#method.abs) +#[rustc_nounwind] +#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn fabsf64(_x: f64) -> f64 { + unimplemented!(); +} + +/// Returns the absolute value of an `f128`. +/// +/// The stabilized version of this intrinsic is +/// [`f128::abs`](../../std/primitive.f128.html#method.abs) +#[rustc_nounwind] +// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[rustc_const_unstable(feature = "f128", issue = "116909")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn fabsf128(_x: f128) -> f128 { + unimplemented!(); +} + +/// Copies the sign from `y` to `x` for `f16` values. +/// +/// The stabilized version of this intrinsic is +/// [`f16::copysign`](../../std/primitive.f16.html#method.copysign) +#[rustc_nounwind] +// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[rustc_const_unstable(feature = "f16", issue = "116909")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn copysignf16(_x: f16, _y: f16) -> f16 { + unimplemented!(); +} + +/// Copies the sign from `y` to `x` for `f32` values. +/// +/// The stabilized version of this intrinsic is +/// [`f32::copysign`](../../std/primitive.f32.html#method.copysign) +#[rustc_nounwind] +#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn copysignf32(_x: f32, _y: f32) -> f32 { + unimplemented!(); +} +/// Copies the sign from `y` to `x` for `f64` values. +/// +/// The stabilized version of this intrinsic is +/// [`f64::copysign`](../../std/primitive.f64.html#method.copysign) +#[rustc_nounwind] +#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn copysignf64(_x: f64, _y: f64) -> f64 { + unimplemented!(); +} + +/// Copies the sign from `y` to `x` for `f128` values. +/// +/// The stabilized version of this intrinsic is +/// [`f128::copysign`](../../std/primitive.f128.html#method.copysign) +#[rustc_nounwind] +// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[rustc_const_unstable(feature = "f128", issue = "116909")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn copysignf128(_x: f128, _y: f128) -> f128 { + unimplemented!(); +} + /// Inform Miri that a given pointer definitely has a certain alignment. #[cfg(miri)] pub(crate) const fn miri_promise_symbolic_alignment(ptr: *const (), align: usize) { diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 7f9a215242650..482e1f30b7e99 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -120,6 +120,7 @@ #![feature(const_char_encode_utf16)] #![feature(const_eval_select)] #![feature(const_exact_div)] +#![feature(const_float_methods)] #![feature(const_fmt_arguments_new)] #![feature(const_hash)] #![feature(const_heap)] diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 764df4fe4b058..5ab2ab50d7c68 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -471,7 +471,7 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - pub fn is_sign_positive(self) -> bool { + pub const fn is_sign_positive(self) -> bool { !self.is_sign_negative() } @@ -497,7 +497,7 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - pub fn is_sign_negative(self) -> bool { + pub const fn is_sign_negative(self) -> bool { // IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus // applies to zeros and NaNs as well. // SAFETY: This is just transmuting to get the sign bit, it's fine. @@ -538,7 +538,7 @@ impl f128 { #[inline] #[unstable(feature = "f128", issue = "116909")] // #[unstable(feature = "float_next_up_down", issue = "91399")] - pub fn next_up(self) -> Self { + pub const fn next_up(self) -> Self { // Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing // denormals to zero. This is in general unsound and unsupported, but here // we do our best to still produce the correct result on such targets. @@ -592,7 +592,7 @@ impl f128 { #[inline] #[unstable(feature = "f128", issue = "116909")] // #[unstable(feature = "float_next_up_down", issue = "91399")] - pub fn next_down(self) -> Self { + pub const fn next_down(self) -> Self { // Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing // denormals to zero. This is in general unsound and unsupported, but here // we do our best to still produce the correct result on such targets. @@ -627,8 +627,9 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[must_use = "this returns the result of the operation, without modifying the original"] - pub fn recip(self) -> Self { + pub const fn recip(self) -> Self { 1.0 / self } @@ -647,8 +648,9 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[must_use = "this returns the result of the operation, without modifying the original"] - pub fn to_degrees(self) -> Self { + pub const fn to_degrees(self) -> Self { // Use a literal for better precision. const PIS_IN_180: f128 = 57.2957795130823208767981548141051703324054724665643215491602_f128; self * PIS_IN_180 @@ -670,8 +672,9 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[must_use = "this returns the result of the operation, without modifying the original"] - pub fn to_radians(self) -> f128 { + pub const fn to_radians(self) -> f128 { // Use a literal for better precision. const RADS_PER_DEG: f128 = 0.0174532925199432957692369076848861271344287188854172545609719_f128; @@ -698,8 +701,9 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[must_use = "this returns the result of the comparison, without modifying either input"] - pub fn max(self, other: f128) -> f128 { + pub const fn max(self, other: f128) -> f128 { intrinsics::maxnumf128(self, other) } @@ -723,8 +727,9 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[must_use = "this returns the result of the comparison, without modifying either input"] - pub fn min(self, other: f128) -> f128 { + pub const fn min(self, other: f128) -> f128 { intrinsics::minnumf128(self, other) } @@ -757,7 +762,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] // #[unstable(feature = "float_minimum_maximum", issue = "91079")] #[must_use = "this returns the result of the comparison, without modifying either input"] - pub fn maximum(self, other: f128) -> f128 { + pub const fn maximum(self, other: f128) -> f128 { if self > other { self } else if other > self { @@ -798,7 +803,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] // #[unstable(feature = "float_minimum_maximum", issue = "91079")] #[must_use = "this returns the result of the comparison, without modifying either input"] - pub fn minimum(self, other: f128) -> f128 { + pub const fn minimum(self, other: f128) -> f128 { if self < other { self } else if other < self { @@ -1269,9 +1274,20 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn clamp(mut self, min: f128, max: f128) -> f128 { - assert!(min <= max, "min > max, or either was NaN. min = {min:?}, max = {max:?}"); + pub const fn clamp(mut self, min: f128, max: f128) -> f128 { + #[inline] // inline to avoid LLVM crash + const fn assert_at_const(min: f128, max: f128) { + // Note that we cannot format in constant expressions. + assert!(min <= max, "min > max, or either was NaN"); + } + #[inline] // inline to avoid codegen regression + fn assert_at_rt(min: f128, max: f128) { + assert!(min <= max, "min > max, or either was NaN. min = {min:?}, max = {max:?}"); + } + // FIXME(const-hack): We would prefer to have streamlined panics when formatters become const-friendly. + intrinsics::const_eval_select((min, max), assert_at_const, assert_at_rt); if self < min { self = min; } diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 897fc8c105d46..60a88496696cf 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -459,7 +459,7 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - pub fn is_sign_positive(self) -> bool { + pub const fn is_sign_positive(self) -> bool { !self.is_sign_negative() } @@ -488,7 +488,7 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - pub fn is_sign_negative(self) -> bool { + pub const fn is_sign_negative(self) -> bool { // IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus // applies to zeros and NaNs as well. // SAFETY: This is just transmuting to get the sign bit, it's fine. @@ -529,7 +529,7 @@ impl f16 { #[inline] #[unstable(feature = "f16", issue = "116909")] // #[unstable(feature = "float_next_up_down", issue = "91399")] - pub fn next_up(self) -> Self { + pub const fn next_up(self) -> Self { // Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing // denormals to zero. This is in general unsound and unsupported, but here // we do our best to still produce the correct result on such targets. @@ -583,7 +583,7 @@ impl f16 { #[inline] #[unstable(feature = "f16", issue = "116909")] // #[unstable(feature = "float_next_up_down", issue = "91399")] - pub fn next_down(self) -> Self { + pub const fn next_down(self) -> Self { // Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing // denormals to zero. This is in general unsound and unsupported, but here // we do our best to still produce the correct result on such targets. @@ -618,8 +618,9 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[must_use = "this returns the result of the operation, without modifying the original"] - pub fn recip(self) -> Self { + pub const fn recip(self) -> Self { 1.0 / self } @@ -638,8 +639,9 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[must_use = "this returns the result of the operation, without modifying the original"] - pub fn to_degrees(self) -> Self { + pub const fn to_degrees(self) -> Self { // Use a literal for better precision. const PIS_IN_180: f16 = 57.2957795130823208767981548141051703_f16; self * PIS_IN_180 @@ -661,8 +663,9 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[must_use = "this returns the result of the operation, without modifying the original"] - pub fn to_radians(self) -> f16 { + pub const fn to_radians(self) -> f16 { // Use a literal for better precision. const RADS_PER_DEG: f16 = 0.017453292519943295769236907684886_f16; self * RADS_PER_DEG @@ -687,8 +690,9 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[must_use = "this returns the result of the comparison, without modifying either input"] - pub fn max(self, other: f16) -> f16 { + pub const fn max(self, other: f16) -> f16 { intrinsics::maxnumf16(self, other) } @@ -711,8 +715,9 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[must_use = "this returns the result of the comparison, without modifying either input"] - pub fn min(self, other: f16) -> f16 { + pub const fn min(self, other: f16) -> f16 { intrinsics::minnumf16(self, other) } @@ -744,7 +749,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] // #[unstable(feature = "float_minimum_maximum", issue = "91079")] #[must_use = "this returns the result of the comparison, without modifying either input"] - pub fn maximum(self, other: f16) -> f16 { + pub const fn maximum(self, other: f16) -> f16 { if self > other { self } else if other > self { @@ -784,7 +789,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] // #[unstable(feature = "float_minimum_maximum", issue = "91079")] #[must_use = "this returns the result of the comparison, without modifying either input"] - pub fn minimum(self, other: f16) -> f16 { + pub const fn minimum(self, other: f16) -> f16 { if self < other { self } else if other < self { @@ -1244,9 +1249,20 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn clamp(mut self, min: f16, max: f16) -> f16 { - assert!(min <= max, "min > max, or either was NaN. min = {min:?}, max = {max:?}"); + pub const fn clamp(mut self, min: f16, max: f16) -> f16 { + #[inline] // inline to avoid LLVM crash + const fn assert_at_const(min: f16, max: f16) { + // Note that we cannot format in constant expressions. + assert!(min <= max, "min > max, or either was NaN"); + } + #[inline] // inline to avoid codegen regression + fn assert_at_rt(min: f16, max: f16) { + assert!(min <= max, "min > max, or either was NaN. min = {min:?}, max = {max:?}"); + } + // FIXME(const-hack): We would prefer to have streamlined panics when formatters become const-friendly. + intrinsics::const_eval_select((min, max), assert_at_const, assert_at_rt); if self < min { self = min; } diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index a9a2595c25c29..05f5a08ad0acf 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -828,8 +828,9 @@ impl f32 { /// ``` #[must_use = "this returns the result of the operation, without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[inline] - pub fn recip(self) -> f32 { + pub const fn recip(self) -> f32 { 1.0 / self } @@ -845,8 +846,9 @@ impl f32 { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "f32_deg_rad_conversions", since = "1.7.0")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[inline] - pub fn to_degrees(self) -> f32 { + pub const fn to_degrees(self) -> f32 { // Use a constant for better precision. const PIS_IN_180: f32 = 57.2957795130823208767981548141051703_f32; self * PIS_IN_180 @@ -864,8 +866,9 @@ impl f32 { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "f32_deg_rad_conversions", since = "1.7.0")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[inline] - pub fn to_radians(self) -> f32 { + pub const fn to_radians(self) -> f32 { const RADS_PER_DEG: f32 = consts::PI / 180.0; self * RADS_PER_DEG } @@ -885,8 +888,9 @@ impl f32 { /// ``` #[must_use = "this returns the result of the comparison, without modifying either input"] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[inline] - pub fn max(self, other: f32) -> f32 { + pub const fn max(self, other: f32) -> f32 { intrinsics::maxnumf32(self, other) } @@ -905,8 +909,9 @@ impl f32 { /// ``` #[must_use = "this returns the result of the comparison, without modifying either input"] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[inline] - pub fn min(self, other: f32) -> f32 { + pub const fn min(self, other: f32) -> f32 { intrinsics::minnumf32(self, other) } @@ -933,7 +938,7 @@ impl f32 { #[must_use = "this returns the result of the comparison, without modifying either input"] #[unstable(feature = "float_minimum_maximum", issue = "91079")] #[inline] - pub fn maximum(self, other: f32) -> f32 { + pub const fn maximum(self, other: f32) -> f32 { if self > other { self } else if other > self { @@ -968,7 +973,7 @@ impl f32 { #[must_use = "this returns the result of the comparison, without modifying either input"] #[unstable(feature = "float_minimum_maximum", issue = "91079")] #[inline] - pub fn minimum(self, other: f32) -> f32 { + pub const fn minimum(self, other: f32) -> f32 { if self < other { self } else if other < self { @@ -1401,9 +1406,19 @@ impl f32 { /// ``` #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "clamp", since = "1.50.0")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[inline] - pub fn clamp(mut self, min: f32, max: f32) -> f32 { - assert!(min <= max, "min > max, or either was NaN. min = {min:?}, max = {max:?}"); + pub const fn clamp(mut self, min: f32, max: f32) -> f32 { + const fn assert_at_const(min: f32, max: f32) { + // Note that we cannot format in constant expressions. + assert!(min <= max, "min > max, or either was NaN"); + } + #[inline] // inline to avoid codegen regression + fn assert_at_rt(min: f32, max: f32) { + assert!(min <= max, "min > max, or either was NaN. min = {min:?}, max = {max:?}"); + } + // FIXME(const-hack): We would prefer to have streamlined panics when formatters become const-friendly. + intrinsics::const_eval_select((min, max), assert_at_const, assert_at_rt); if self < min { self = min; } diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index aa7a54ca65080..89c6726d985e1 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -845,8 +845,9 @@ impl f64 { /// ``` #[must_use = "this returns the result of the operation, without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[inline] - pub fn recip(self) -> f64 { + pub const fn recip(self) -> f64 { 1.0 / self } @@ -862,8 +863,9 @@ impl f64 { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[inline] - pub fn to_degrees(self) -> f64 { + pub const fn to_degrees(self) -> f64 { // The division here is correctly rounded with respect to the true // value of 180/π. (This differs from f32, where a constant must be // used to ensure a correctly rounded result.) @@ -882,8 +884,9 @@ impl f64 { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[inline] - pub fn to_radians(self) -> f64 { + pub const fn to_radians(self) -> f64 { const RADS_PER_DEG: f64 = consts::PI / 180.0; self * RADS_PER_DEG } @@ -903,8 +906,9 @@ impl f64 { /// ``` #[must_use = "this returns the result of the comparison, without modifying either input"] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[inline] - pub fn max(self, other: f64) -> f64 { + pub const fn max(self, other: f64) -> f64 { intrinsics::maxnumf64(self, other) } @@ -923,8 +927,9 @@ impl f64 { /// ``` #[must_use = "this returns the result of the comparison, without modifying either input"] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[inline] - pub fn min(self, other: f64) -> f64 { + pub const fn min(self, other: f64) -> f64 { intrinsics::minnumf64(self, other) } @@ -951,7 +956,7 @@ impl f64 { #[must_use = "this returns the result of the comparison, without modifying either input"] #[unstable(feature = "float_minimum_maximum", issue = "91079")] #[inline] - pub fn maximum(self, other: f64) -> f64 { + pub const fn maximum(self, other: f64) -> f64 { if self > other { self } else if other > self { @@ -986,7 +991,7 @@ impl f64 { #[must_use = "this returns the result of the comparison, without modifying either input"] #[unstable(feature = "float_minimum_maximum", issue = "91079")] #[inline] - pub fn minimum(self, other: f64) -> f64 { + pub const fn minimum(self, other: f64) -> f64 { if self < other { self } else if other < self { @@ -1401,9 +1406,19 @@ impl f64 { /// ``` #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "clamp", since = "1.50.0")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[inline] - pub fn clamp(mut self, min: f64, max: f64) -> f64 { - assert!(min <= max, "min > max, or either was NaN. min = {min:?}, max = {max:?}"); + pub const fn clamp(mut self, min: f64, max: f64) -> f64 { + const fn assert_at_const(min: f64, max: f64) { + // Note that we cannot format in constant expressions. + assert!(min <= max, "min > max, or either was NaN"); + } + #[inline] // inline to avoid codegen regression + fn assert_at_rt(min: f64, max: f64) { + assert!(min <= max, "min > max, or either was NaN. min = {min:?}, max = {max:?}"); + } + // FIXME(const-hack): We would prefer to have streamlined panics when formatters become const-friendly. + intrinsics::const_eval_select((min, max), assert_at_const, assert_at_rt); if self < min { self = min; } diff --git a/library/std/src/f128.rs b/library/std/src/f128.rs index b436fe9929c36..229f979b5b10b 100644 --- a/library/std/src/f128.rs +++ b/library/std/src/f128.rs @@ -210,8 +210,9 @@ impl f128 { #[inline] #[rustc_allow_incoherent_impl] #[unstable(feature = "f128", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn abs(self) -> Self { + pub const fn abs(self) -> Self { // FIXME(f16_f128): replace with `intrinsics::fabsf128` when available // We don't do this now because LLVM has lowering bugs for f128 math. Self::from_bits(self.to_bits() & !(1 << 127)) @@ -240,8 +241,9 @@ impl f128 { #[inline] #[rustc_allow_incoherent_impl] #[unstable(feature = "f128", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn signum(self) -> f128 { + pub const fn signum(self) -> f128 { if self.is_nan() { Self::NAN } else { 1.0_f128.copysign(self) } } @@ -278,8 +280,9 @@ impl f128 { #[inline] #[rustc_allow_incoherent_impl] #[unstable(feature = "f128", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn copysign(self, sign: f128) -> f128 { + pub const fn copysign(self, sign: f128) -> f128 { unsafe { intrinsics::copysignf128(self, sign) } } diff --git a/library/std/src/f16.rs b/library/std/src/f16.rs index b2cd5fae9d04a..bed21cda1cd91 100644 --- a/library/std/src/f16.rs +++ b/library/std/src/f16.rs @@ -210,8 +210,9 @@ impl f16 { #[inline] #[rustc_allow_incoherent_impl] #[unstable(feature = "f16", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn abs(self) -> Self { + pub const fn abs(self) -> Self { // FIXME(f16_f128): replace with `intrinsics::fabsf16` when available Self::from_bits(self.to_bits() & !(1 << 15)) } @@ -239,8 +240,9 @@ impl f16 { #[inline] #[rustc_allow_incoherent_impl] #[unstable(feature = "f16", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn signum(self) -> f16 { + pub const fn signum(self) -> f16 { if self.is_nan() { Self::NAN } else { 1.0_f16.copysign(self) } } @@ -277,8 +279,9 @@ impl f16 { #[inline] #[rustc_allow_incoherent_impl] #[unstable(feature = "f16", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn copysign(self, sign: f16) -> f16 { + pub const fn copysign(self, sign: f16) -> f16 { unsafe { intrinsics::copysignf16(self, sign) } } diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs index fa0b3ef6484f7..30cf4e1f756e0 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -194,8 +194,9 @@ impl f32 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[inline] - pub fn abs(self) -> f32 { + pub const fn abs(self) -> f32 { unsafe { intrinsics::fabsf32(self) } } @@ -218,8 +219,9 @@ impl f32 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[inline] - pub fn signum(self) -> f32 { + pub const fn signum(self) -> f32 { if self.is_nan() { Self::NAN } else { 1.0_f32.copysign(self) } } @@ -253,7 +255,8 @@ impl f32 { #[must_use = "method returns a new number and does not mutate the original value"] #[inline] #[stable(feature = "copysign", since = "1.35.0")] - pub fn copysign(self, sign: f32) -> f32 { + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] + pub const fn copysign(self, sign: f32) -> f32 { unsafe { intrinsics::copysignf32(self, sign) } } diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index 9fa43a6742ea6..51d5476b372d2 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -194,8 +194,9 @@ impl f64 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[inline] - pub fn abs(self) -> f64 { + pub const fn abs(self) -> f64 { unsafe { intrinsics::fabsf64(self) } } @@ -218,8 +219,9 @@ impl f64 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[inline] - pub fn signum(self) -> f64 { + pub const fn signum(self) -> f64 { if self.is_nan() { Self::NAN } else { 1.0_f64.copysign(self) } } @@ -252,8 +254,9 @@ impl f64 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "copysign", since = "1.35.0")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[inline] - pub fn copysign(self, sign: f64) -> f64 { + pub const fn copysign(self, sign: f64) -> f64 { unsafe { intrinsics::copysignf64(self, sign) } } diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 65a9aa66c7cc6..990d83513cfb6 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -288,6 +288,7 @@ #![feature(cfg_target_thread_local)] #![feature(cfi_encoding)] #![feature(concat_idents)] +#![feature(const_float_methods)] #![feature(decl_macro)] #![feature(deprecated_suggestion)] #![feature(doc_cfg)] diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index 9f772cfa982d8..e0d27f21dae9c 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -145,20 +145,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(Scalar::from_bool(branch), dest)?; } - // Floating-point operations - "fabsf32" => { - let [f] = check_arg_count(args)?; - let f = this.read_scalar(f)?.to_f32()?; - // This is a "bitwise" operation, so there's no NaN non-determinism. - this.write_scalar(Scalar::from_f32(f.abs()), dest)?; - } - "fabsf64" => { - let [f] = check_arg_count(args)?; - let f = this.read_scalar(f)?.to_f64()?; - // This is a "bitwise" operation, so there's no NaN non-determinism. - this.write_scalar(Scalar::from_f64(f.abs()), dest)?; - } - "floorf32" | "ceilf32" | "truncf32" | "roundf32" | "rintf32" => { let [f] = check_arg_count(args)?; let f = this.read_scalar(f)?.to_f32()?; @@ -249,31 +235,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(res, dest)?; } - "minnumf32" | "maxnumf32" | "copysignf32" => { - let [a, b] = check_arg_count(args)?; - let a = this.read_scalar(a)?.to_f32()?; - let b = this.read_scalar(b)?.to_f32()?; - let res = match intrinsic_name { - "minnumf32" => this.adjust_nan(a.min(b), &[a, b]), - "maxnumf32" => this.adjust_nan(a.max(b), &[a, b]), - "copysignf32" => a.copy_sign(b), // bitwise, no NaN adjustments - _ => bug!(), - }; - this.write_scalar(Scalar::from_f32(res), dest)?; - } - "minnumf64" | "maxnumf64" | "copysignf64" => { - let [a, b] = check_arg_count(args)?; - let a = this.read_scalar(a)?.to_f64()?; - let b = this.read_scalar(b)?.to_f64()?; - let res = match intrinsic_name { - "minnumf64" => this.adjust_nan(a.min(b), &[a, b]), - "maxnumf64" => this.adjust_nan(a.max(b), &[a, b]), - "copysignf64" => a.copy_sign(b), // bitwise, no NaN adjustments - _ => bug!(), - }; - this.write_scalar(Scalar::from_f64(res), dest)?; - } - "fmaf32" => { let [a, b, c] = check_arg_count(args)?; let a = this.read_scalar(a)?.to_f32()?; diff --git a/tests/ui/consts/const-eval/float_methods.rs b/tests/ui/consts/const-eval/float_methods.rs new file mode 100644 index 0000000000000..49c31f68c5fa2 --- /dev/null +++ b/tests/ui/consts/const-eval/float_methods.rs @@ -0,0 +1,47 @@ +//@ run-pass +//! Tests the float intrinsics: min, max, abs, copysign + +#![feature(const_float_methods)] +#![feature(f16, f128)] + +const F16_MIN: f16 = 1.0_f16.min(0.5_f16); +const F16_MAX: f16 = 1.0_f16.max(0.5_f16); +const F16_ABS: f16 = (-1.0_f16).abs(); +const F16_COPYSIGN: f16 = 1.0_f16.copysign(-2.0_f16); + +const F32_MIN: f32 = 1.0_f32.min(0.5_f32); +const F32_MAX: f32 = 1.0_f32.max(0.5_f32); +const F32_ABS: f32 = (-1.0_f32).abs(); +const F32_COPYSIGN: f32 = 1.0_f32.copysign(-2.0_f32); + +const F64_MIN: f64 = 1.0_f64.min(0.5_f64); +const F64_MAX: f64 = 1.0_f64.max(0.5_f64); +const F64_ABS: f64 = (-1.0_f64).abs(); +const F64_COPYSIGN: f64 = 1.0_f64.copysign(-2.0_f64); + +const F128_MIN: f128 = 1.0_f128.min(0.5_f128); +const F128_MAX: f128 = 1.0_f128.max(0.5_f128); +const F128_ABS: f128 = (-1.0_f128).abs(); +const F128_COPYSIGN: f128 = 1.0_f128.copysign(-2.0_f128); + +fn main() { + assert_eq!(F16_MIN, 0.5); + assert_eq!(F16_MAX, 1.0); + assert_eq!(F16_ABS, 1.0); + assert_eq!(F16_COPYSIGN, -1.0); + + assert_eq!(F32_MIN, 0.5); + assert_eq!(F32_MAX, 1.0); + assert_eq!(F32_ABS, 1.0); + assert_eq!(F32_COPYSIGN, -1.0); + + assert_eq!(F64_MIN, 0.5); + assert_eq!(F64_MAX, 1.0); + assert_eq!(F64_ABS, 1.0); + assert_eq!(F64_COPYSIGN, -1.0); + + assert_eq!(F128_MIN, 0.5); + assert_eq!(F128_MAX, 1.0); + assert_eq!(F128_ABS, 1.0); + assert_eq!(F128_COPYSIGN, -1.0); +} From d3d59055a9f8a7a34d70b581638ef8b56e68d0b4 Mon Sep 17 00:00:00 2001 From: Michal Piotrowski Date: Tue, 15 Oct 2024 13:49:07 +0200 Subject: [PATCH 08/10] Fix uninlined_format_args in stable_mir --- compiler/stable_mir/src/mir/pretty.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/compiler/stable_mir/src/mir/pretty.rs b/compiler/stable_mir/src/mir/pretty.rs index 74081af1d86d0..05d11c71bbbe1 100644 --- a/compiler/stable_mir/src/mir/pretty.rs +++ b/compiler/stable_mir/src/mir/pretty.rs @@ -22,7 +22,7 @@ impl Debug for Place { } pub(crate) fn function_body(writer: &mut W, body: &Body, name: &str) -> io::Result<()> { - write!(writer, "fn {}(", name)?; + write!(writer, "fn {name}(")?; body.arg_locals() .iter() .enumerate() @@ -54,7 +54,7 @@ pub(crate) fn function_body(writer: &mut W, body: &Body, name: &str) - .iter() .enumerate() .map(|(index, block)| -> io::Result<()> { - writeln!(writer, " bb{}: {{", index)?; + writeln!(writer, " bb{index}: {{")?; let _ = block .statements .iter() @@ -75,7 +75,7 @@ pub(crate) fn function_body(writer: &mut W, body: &Body, name: &str) - fn pretty_statement(writer: &mut W, statement: &StatementKind) -> io::Result<()> { match statement { StatementKind::Assign(place, rval) => { - write!(writer, " {:?} = ", place)?; + write!(writer, " {place:?} = ")?; pretty_rvalue(writer, rval)?; writeln!(writer, ";") } @@ -165,7 +165,7 @@ fn pretty_terminator_head(writer: &mut W, terminator: &TerminatorKind) Abort => write!(writer, "{INDENT}abort"), Return => write!(writer, "{INDENT}return"), Unreachable => write!(writer, "{INDENT}unreachable"), - Drop { place, .. } => write!(writer, "{INDENT}drop({:?})", place), + Drop { place, .. } => write!(writer, "{INDENT}drop({place:?})"), Call { func, args, destination, .. } => { write!(writer, "{INDENT}{:?} = {}(", destination, pretty_operand(func))?; let mut args_iter = args.iter(); @@ -304,10 +304,10 @@ fn pretty_assert_message(writer: &mut W, msg: &AssertMessage) -> io::R fn pretty_operand(operand: &Operand) -> String { match operand { Operand::Copy(copy) => { - format!("{:?}", copy) + format!("{copy:?}") } Operand::Move(mv) => { - format!("move {:?}", mv) + format!("move {mv:?}") } Operand::Constant(cnst) => pretty_mir_const(&cnst.const_), } @@ -344,13 +344,13 @@ fn pretty_rvalue(writer: &mut W, rval: &Rvalue) -> io::Result<()> { write!(writer, "Checked{:?}({}, {})", bin, pretty_operand(op1), pretty_operand(op2)) } Rvalue::CopyForDeref(deref) => { - write!(writer, "CopyForDeref({:?})", deref) + write!(writer, "CopyForDeref({deref:?})") } Rvalue::Discriminant(place) => { - write!(writer, "discriminant({:?})", place) + write!(writer, "discriminant({place:?})") } Rvalue::Len(len) => { - write!(writer, "len({:?})", len) + write!(writer, "len({len:?})") } Rvalue::Ref(_, borrowkind, place) => { let kind = match borrowkind { @@ -359,17 +359,17 @@ fn pretty_rvalue(writer: &mut W, rval: &Rvalue) -> io::Result<()> { BorrowKind::Fake(FakeBorrowKind::Shallow) => "&fake shallow ", BorrowKind::Mut { .. } => "&mut ", }; - write!(writer, "{kind}{:?}", place) + write!(writer, "{kind}{place:?}") } Rvalue::Repeat(op, cnst) => { write!(writer, "{} \" \" {}", pretty_operand(op), pretty_ty_const(cnst)) } Rvalue::ShallowInitBox(_, _) => Ok(()), Rvalue::ThreadLocalRef(item) => { - write!(writer, "thread_local_ref{:?}", item) + write!(writer, "thread_local_ref{item:?}") } Rvalue::NullaryOp(nul, ty) => { - write!(writer, "{:?} {} \" \"", nul, ty) + write!(writer, "{nul:?} {ty} \" \"") } Rvalue::UnaryOp(un, op) => { write!(writer, "{} \" \" {:?}", pretty_operand(op), un) From 4e29e454a15cbfff91174332106e09d18a7a7da0 Mon Sep 17 00:00:00 2001 From: Emmanuel Ferdman Date: Tue, 15 Oct 2024 05:12:03 -0700 Subject: [PATCH 09/10] Update arm64e-apple-tvos maintainer Signed-off-by: Emmanuel Ferdman --- src/doc/rustc/src/platform-support/arm64e-apple-tvos.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support/arm64e-apple-tvos.md b/src/doc/rustc/src/platform-support/arm64e-apple-tvos.md index d49383fb853ea..47234809e5f19 100644 --- a/src/doc/rustc/src/platform-support/arm64e-apple-tvos.md +++ b/src/doc/rustc/src/platform-support/arm64e-apple-tvos.md @@ -6,7 +6,7 @@ ARM64e tvOS (10.0+) ## Target maintainers -- Artyom Tetyukhin ([@arttet](https://github.com/https://github.com/arttet)) +- Artyom Tetyukhin ([@arttet](https://github.com/arttet)) ## Requirements From 1d6643c4f69ba31f91a385c51f46d615bd2b0d66 Mon Sep 17 00:00:00 2001 From: Hood Chatham Date: Mon, 14 Oct 2024 21:16:27 +0200 Subject: [PATCH 10/10] Fix most ui tests on emscripten target To fix the linker errors, we need to set the output extension to `.js` instead of `.wasm`. Setting the output to a `.wasm` file puts Emscripten into standalone mode which is effectively a distinct target. We need to set the runner to be `node` as well. This fixes most of the ui tests. I fixed a few more tests with simple problems: - `intrinsics/intrinsic-alignment.rs` and `structs-enums/rec-align-u64.rs` -- Two `#[cfg]` macros match for Emscripten so we got a duplicate definition of `mod m`. - `issues/issue-12699.rs` -- Seems to hang so I disabled it - `process/process-sigpipe.rs` -- Not expected to work on Emscripten so I disabled it --- src/bootstrap/src/core/config/config.rs | 3 +++ src/tools/compiletest/src/runtest.rs | 4 +++- src/tools/tidy/src/issues.txt | 1 - src/tools/tidy/src/ui_tests.rs | 2 +- tests/ui/intrinsics/intrinsic-alignment.rs | 1 - tests/ui/process/process-sigpipe.rs | 8 ++------ .../ui/{issues/issue-12699.rs => std/thread-sleep-ms.rs} | 3 +++ tests/ui/structs-enums/rec-align-u64.rs | 1 - 8 files changed, 12 insertions(+), 11 deletions(-) rename tests/ui/{issues/issue-12699.rs => std/thread-sleep-ms.rs} (59%) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index f768470c4ff0e..eb571f920df2e 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -612,6 +612,9 @@ impl Target { if triple.contains("-none") || triple.contains("nvptx") || triple.contains("switch") { target.no_std = true; } + if triple.contains("emscripten") { + target.runner = Some("node".into()); + } target } } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 29f9925de16a2..69a47fcd0fbea 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1643,7 +1643,9 @@ impl<'test> TestCx<'test> { // double the length. let mut f = self.output_base_dir().join("a"); // FIXME: This is using the host architecture exe suffix, not target! - if self.config.target.starts_with("wasm") { + if self.config.target.contains("emscripten") { + f = f.with_extra_extension("js"); + } else if self.config.target.starts_with("wasm") { f = f.with_extra_extension("wasm"); } else if self.config.target.contains("spirv") { f = f.with_extra_extension("spv"); diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 66c176c6f4424..22126674c156b 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -1520,7 +1520,6 @@ ui/issues/issue-12567.rs ui/issues/issue-12612.rs ui/issues/issue-12660.rs ui/issues/issue-12677.rs -ui/issues/issue-12699.rs ui/issues/issue-12729.rs ui/issues/issue-12744.rs ui/issues/issue-12860.rs diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 41f7778c95272..11f9d5bb03df7 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -17,7 +17,7 @@ use ignore::Walk; const ENTRY_LIMIT: u32 = 901; // FIXME: The following limits should be reduced eventually. -const ISSUES_ENTRY_LIMIT: u32 = 1673; +const ISSUES_ENTRY_LIMIT: u32 = 1672; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files diff --git a/tests/ui/intrinsics/intrinsic-alignment.rs b/tests/ui/intrinsics/intrinsic-alignment.rs index 138273aadd2f1..4cb05f6a8df33 100644 --- a/tests/ui/intrinsics/intrinsic-alignment.rs +++ b/tests/ui/intrinsics/intrinsic-alignment.rs @@ -13,7 +13,6 @@ mod rusti { #[cfg(any( target_os = "android", target_os = "dragonfly", - target_os = "emscripten", target_os = "freebsd", target_os = "fuchsia", target_os = "hurd", diff --git a/tests/ui/process/process-sigpipe.rs b/tests/ui/process/process-sigpipe.rs index 11f363d625f0c..9db130c26bd68 100644 --- a/tests/ui/process/process-sigpipe.rs +++ b/tests/ui/process/process-sigpipe.rs @@ -15,11 +15,12 @@ //@ ignore-vxworks no 'sh' //@ ignore-fuchsia no 'sh' +//@ ignore-emscripten No threads +//@ only-unix SIGPIPE is a unix feature use std::process; use std::thread; -#[cfg(unix)] fn main() { // Just in case `yes` doesn't check for EPIPE... thread::spawn(|| { @@ -34,8 +35,3 @@ fn main() { assert!(output.status.success()); assert!(output.stderr.len() == 0); } - -#[cfg(not(unix))] -fn main() { - // Not worried about signal masks on other platforms -} diff --git a/tests/ui/issues/issue-12699.rs b/tests/ui/std/thread-sleep-ms.rs similarity index 59% rename from tests/ui/issues/issue-12699.rs rename to tests/ui/std/thread-sleep-ms.rs index 4fc93735c3ce3..0a3d0253a20ef 100644 --- a/tests/ui/issues/issue-12699.rs +++ b/tests/ui/std/thread-sleep-ms.rs @@ -1,6 +1,9 @@ //@ run-pass //@ ignore-sgx not supported +//@ ignore-emscripten +// FIXME: test hangs on emscripten #![allow(deprecated)] +#![allow(unused_imports)] use std::thread; diff --git a/tests/ui/structs-enums/rec-align-u64.rs b/tests/ui/structs-enums/rec-align-u64.rs index 8ea72fdf45c88..313ce6d578dff 100644 --- a/tests/ui/structs-enums/rec-align-u64.rs +++ b/tests/ui/structs-enums/rec-align-u64.rs @@ -33,7 +33,6 @@ struct Outer { #[cfg(any( target_os = "android", target_os = "dragonfly", - target_os = "emscripten", target_os = "freebsd", target_os = "fuchsia", target_os = "hurd",