Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion library/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,13 @@
#![feature(core_intrinsics)]
#![feature(coverage_attribute)]
#![feature(disjoint_bitor)]
#![feature(funnel_shifts)]
#![feature(io_const_error)]
#![feature(offset_of_enum)]
#![feature(panic_internals)]
#![feature(pattern_type_macro)]
#![feature(ub_checks)]
#![feature(wrapping_funnel_shifts)]
// tidy-alphabetical-end
//
// Language features:
Expand Down Expand Up @@ -131,7 +133,6 @@
#![feature(final_associated_functions)]
#![feature(freeze_impls)]
#![feature(fundamental)]
#![feature(funnel_shifts)]
#![feature(impl_restriction)]
#![feature(intra_doc_pointers)]
#![feature(intrinsics)]
Expand Down
148 changes: 138 additions & 10 deletions library/core/src/num/uint_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -568,11 +568,8 @@ macro_rules! uint_impl {
if intrinsics::overflow_checks() {
assert!(n < Self::BITS, "attempt to funnel shift left with overflow");
}
// SAFETY: `n` is wrapped to within range
unsafe {
let n = n & (Self::BITS - 1);
self.unchecked_funnel_shl(right, n)
}

self.wrapping_funnel_shl(right, n)
}

/// Performs a right funnel shift.
Expand Down Expand Up @@ -639,10 +636,141 @@ macro_rules! uint_impl {
if intrinsics::overflow_checks() {
assert!(n < Self::BITS, "attempt to funnel shift right with overflow");
}

self.wrapping_funnel_shr(right, n)
}

/// Performs a left funnel shift.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of the summary lines say "Performs a left/right funnel shift." Please update these to be a bit more similar to the {checked,wrapping,strict,unbounded}_{shl,shr}.

///
/// This function will return `None` if `n` is greater than or equal to the number of
/// bits in `self`, i.e., when [`funnel_shl`](Self::funnel_shl) might panic or wrap.
Comment on lines +644 to +646

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add examples

Comment on lines +645 to +646

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use "would" rather than "might" because we guarantee it would do one of those two things.

#[rustc_const_unstable(feature = "wrapping_funnel_shifts", issue = "161798")]
#[unstable(feature = "wrapping_funnel_shifts", issue = "161798")]
#[must_use = "this returns the result of the operation, without modifying the original"]
#[inline(always)]
pub const fn checked_funnel_shl(self, right: Self, n: u32) -> Option<Self> {
if n < Self::BITS {
// SAFETY: just checked that `n` is in-range
Some(unsafe { self.unchecked_funnel_shl(right, n) })
} else {
None
}
}

/// Performs a right funnel shift.
///
/// This function will return `None` if `n` is greater than or equal to the number of
/// bits in `self`, i.e., when [`funnel_shr`](Self::funnel_shr) might panic or wrap.
#[rustc_const_unstable(feature = "wrapping_funnel_shifts", issue = "161798")]
#[unstable(feature = "wrapping_funnel_shifts", issue = "161798")]
#[must_use = "this returns the result of the operation, without modifying the original"]
#[inline(always)]
pub const fn checked_funnel_shr(self, right: Self, n: u32) -> Option<Self> {
if n < Self::BITS {
// SAFETY: just checked that `n` is in-range
Some(unsafe { self.unchecked_funnel_shr(right, n) })
} else {
None
}
}

/// Performs a left funnel shift.
///
/// This function shifts by `mask(n)`, where `mask` removes any high-order bits of `n`
/// that would cause the shift to exceed the bitwidth of the type. As a result, this
/// function never panics, unlike [`funnel_shl`](Self::funnel_shl).
#[rustc_const_unstable(feature = "wrapping_funnel_shifts", issue = "161798")]
#[unstable(feature = "wrapping_funnel_shifts", issue = "161798")]
#[must_use = "this returns the result of the operation, without modifying the original"]
#[inline(always)]
pub const fn wrapping_funnel_shl(self, right: Self, n: u32) -> Self {
Comment on lines +677 to +686

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Include the "Beware that, unlike most other wrapping_* methods on integer" from wrapping_shl, adapted to funnel shifts. The result can be extra unintuitive because of the reason mentioned at rust-lang/libs-team#642 (comment), try to capture that in an example.

(same for wrapping_funnel_shr)

let n = n & (Self::BITS - 1);
// SAFETY: `n` is wrapped to within range
unsafe {
let n = n & (Self::BITS - 1);
self.unchecked_funnel_shr(right, n)
unsafe { self.unchecked_funnel_shl(right, n) }
}

/// Performs a right funnel shift.
///
/// This function shifts by `mask(n)`, where `mask` removes any high-order bits of `n`
/// that would cause the shift to exceed the bitwidth of the type. As a result, this
/// function never panics, unlike [`funnel_shr`](Self::funnel_shr).
#[rustc_const_unstable(feature = "wrapping_funnel_shifts", issue = "161798")]
#[unstable(feature = "wrapping_funnel_shifts", issue = "161798")]
#[must_use = "this returns the result of the operation, without modifying the original"]
#[inline(always)]
pub const fn wrapping_funnel_shr(self, right: Self, n: u32) -> Self {
let n = n & (Self::BITS - 1);
// SAFETY: `n` is wrapped to within range
unsafe { self.unchecked_funnel_shr(right, n) }
}

/// Performs a left funnel shift.
///
/// # Panics
///
/// This function will always panic if `n` is greater than or equal to the number of
/// bits in `self`, i.e., when [`funnel_shr`](Self::funnel_shr) might panic or wrap.
#[rustc_const_unstable(feature = "wrapping_funnel_shifts", issue = "161798")]
#[unstable(feature = "wrapping_funnel_shifts", issue = "161798")]
#[must_use = "this returns the result of the operation, without modifying the original"]
#[inline(always)]
pub const fn strict_funnel_shl(self, right: Self, n: u32) -> Self {
assert!(n < Self::BITS, "attempt to funnel shift left with overflow");
// SAFETY: `n` is checked to be within range
unsafe { self.unchecked_funnel_shl(right, n) }
}

/// Performs a right funnel shift.
///
/// # Panics
///
/// This function will always panic if `n` is greater than or equal to the number of
/// bits in `self`, i.e., when [`funnel_shr`](Self::funnel_shr) might panic or wrap.
#[rustc_const_unstable(feature = "wrapping_funnel_shifts", issue = "161798")]
#[unstable(feature = "wrapping_funnel_shifts", issue = "161798")]
#[must_use = "this returns the result of the operation, without modifying the original"]
#[inline(always)]
pub const fn strict_funnel_shr(self, right: Self, n: u32) -> Self {
Comment on lines +725 to +733

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The strict_* methods have a subsection "overflow behavior". I don't love that, but this should be consistent

https://doc.rust-lang.org/nightly/std/primitive.u32.html#method.strict_shl

assert!(n < Self::BITS, "attempt to funnel shift right with overflow");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These should probably go in the overflow_panic module like the other strict_* functions to be consistent. Though I'm not really sure why that module exists.

// SAFETY: `n` is checked to be within range
unsafe { self.unchecked_funnel_shr(right, n) }
}

/// Performs a left funnel shift.
///
/// This function will act like [`unbounded_shl`](Self::unbounded_shl) on a type with
/// twice the bitwidth of `Self` where the high-order half comes from `self` and the
/// low-order half comes from `right`, regardless of whether such a type exists, and
/// will return the high-order half of the result.
#[rustc_const_unstable(feature = "wrapping_funnel_shifts", issue = "161798")]
#[unstable(feature = "wrapping_funnel_shifts", issue = "161798")]
#[must_use = "this returns the result of the operation, without modifying the original"]
#[inline(always)]
pub const fn unbounded_funnel_shl(self, right: Self, n: u32) -> Self {
if let Some(r) = self.checked_funnel_shl(right, n) {
r
} else {
// This subtraction will never underflow.
right.unbounded_shl(n - Self::BITS)
}
}

/// Performs a right funnel shift.
///
/// This function will act like [`unbounded_shr`](Self::unbounded_shr) on a type with
/// twice the bitwidth of `Self` where the high-order half comes from `self` and the
/// low-order half comes from `right`, regardless of whether such a type exists, and
/// will return the low-order half of the result.
#[rustc_const_unstable(feature = "wrapping_funnel_shifts", issue = "161798")]
#[unstable(feature = "wrapping_funnel_shifts", issue = "161798")]
#[must_use = "this returns the result of the operation, without modifying the original"]
#[inline(always)]
pub const fn unbounded_funnel_shr(self, right: Self, n: u32) -> Self {
if let Some(r) = self.checked_funnel_shr(right, n) {
r
} else {
// This subtraction will never underflow.
self.unbounded_shr(n - Self::BITS)
}
}

Expand All @@ -652,7 +780,7 @@ macro_rules! uint_impl {
///
/// This results in undefined behavior if `n` is greater than or equal to
#[doc = concat!("`", stringify!($SelfT) , "::BITS`,")]
/// i.e. when [`funnel_shl`](Self::funnel_shl) would panic.
/// i.e. when [`funnel_shl`](Self::funnel_shl) might panic or wrap.
///
#[rustc_const_unstable(feature = "funnel_shifts", issue = "145686")]
#[unstable(feature = "funnel_shifts", issue = "145686")]
Expand All @@ -678,7 +806,7 @@ macro_rules! uint_impl {
///
/// This results in undefined behavior if `n` is greater than or equal to
#[doc = concat!("`", stringify!($SelfT) , "::BITS`,")]
/// i.e. when [`funnel_shr`](Self::funnel_shr) would panic.
/// i.e. when [`funnel_shr`](Self::funnel_shr) might panic or wrap.
///
#[rustc_const_unstable(feature = "funnel_shifts", issue = "145686")]
#[unstable(feature = "funnel_shifts", issue = "145686")]
Expand Down
1 change: 1 addition & 0 deletions library/coretests/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@
#![feature(unicode_internals)]
#![feature(unsize)]
#![feature(unwrap_infallible)]
#![feature(wrapping_funnel_shifts)]
// tidy-alphabetical-end
#![allow(internal_features)]
#![deny(implicit_provenance_casts)]
Expand Down
22 changes: 22 additions & 0 deletions library/coretests/tests/num/uint_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,28 @@ macro_rules! uint_module {
let _ = <$T>::funnel_shr(A, B, $T::BITS);
}

#[test]
#[should_panic = "attempt to funnel shift left with overflow"]
fn test_strict_funnel_shl_overflow() {
let _ = <$T>::strict_funnel_shl(A, B, $T::BITS);
}

#[test]
#[should_panic = "attempt to funnel shift right with overflow"]
fn test_strict_funnel_shr_overflow() {
let _ = <$T>::strict_funnel_shr(A, B, $T::BITS);
}

#[test]
fn test_wrapping_funnel_shl_overflow() {
let _ = <$T>::wrapping_funnel_shl(A, B, $T::BITS);
}

#[test]
fn test_wrapping_funnel_shr_overflow() {
let _ = <$T>::wrapping_funnel_shr(A, B, $T::BITS);
}

Comment on lines +256 to +265

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These aren't actually testing anything other than the fact that we don't panic?

These methods should be tested in test_funnel_shifts_runtime and test_funnel_shift

#[test]
fn test_funnel_shifts_runtime() {
for i in 0..$T::BITS - 1 {
Expand Down
1 change: 1 addition & 0 deletions library/std/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,7 @@
#![feature(ub_checks)]
#![feature(uint_carryless_mul)]
#![feature(used_with_arg)]
#![feature(wrapping_funnel_shifts)]
#![feature(write_all_vectored)]
// tidy-alphabetical-end
//
Expand Down
Loading