Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 12 pull requests #72736

Closed
wants to merge 42 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
406852a
Resolve overflow behavior for RangeFrom
CAD97 May 20, 2020
a8ed9aa
impl From<[T; N]> for Box<[T]>
pickfire Apr 13, 2020
96f3879
impl Step for char
CAD97 May 21, 2020
c25b82f
Use Step::forward_unchecked in RangeInclusive::next
CAD97 May 21, 2020
34b5118
Suggest using std::mem::drop function instead of explicit destructor …
stanislav-tkach May 20, 2020
27d1cd8
Add safety annotations in iter::range
CAD97 May 21, 2020
b1d1f25
Add a test for char ranges
CAD97 May 21, 2020
a9199de
Merge spans for the suggestion
stanislav-tkach May 22, 2020
68bab3e
Add total_cmp to f32 and f64, plus tests
golddranks May 22, 2020
b6eec22
Fix typo in src/libcore/num/f32.rs
golddranks May 25, 2020
d6650e0
Fix typo in src/libcore/num/f32.rs
golddranks May 25, 2020
bd68de8
remove unneeded and unidiomatic must_use
golddranks May 25, 2020
6973fd7
Add bit twiddling
golddranks May 25, 2020
8bc31ff
Fix the same typos again orz
golddranks May 25, 2020
c3dc8c4
Rename upvar_list to closure_captures
May 25, 2020
66da735
Add tracing issue for total_cmp
golddranks May 26, 2020
ca722b9
Add test for #56445
JohnTitor May 25, 2020
125f0ab
Add test for #68532
JohnTitor May 25, 2020
4b87f97
Add test for #70121
JohnTitor May 25, 2020
6315d0c
Add test for #71042
JohnTitor May 26, 2020
6ddbef1
Simplify suggestion
stanislav-tkach May 26, 2020
822ad87
Add Peekable::next_if
jyn514 May 18, 2020
709ddba
Allow types (with lifetimes/generics) in impl_lint_pass
flip1995 May 27, 2020
b124892
Add test for {impl,declare}_lint_pass macros
flip1995 May 27, 2020
cd6a8ca
FIx off-by-one in char::steps_between
CAD97 May 28, 2020
52ed89a
from_u32_unchecked: check validity when debug assertions are enabled
RalfJung May 28, 2020
ce81d15
Add test to make sure -Wunused-crate-dependencies works with tests
jsgf May 28, 2020
d5e6bda
Make remote-test-client and remote-test-server compatible with windows
seritools May 27, 2020
2adbfa9
Unify temp path generation for non-android
seritools May 28, 2020
36d6791
Fix `set_permissions` call for non-windows
seritools May 29, 2020
03fe603
Rollup merge of #71095 - pickfire:box-from-array, r=dtolnay
Dylan-DPC May 29, 2020
ee1a4bc
Rollup merge of #72310 - jyn514:peekable-next-if, r=dtolnay
Dylan-DPC May 29, 2020
077383d
Rollup merge of #72368 - CAD97:rangeto, r=dtolnay
Dylan-DPC May 29, 2020
b08978e
Rollup merge of #72383 - DarkEld3r:issue-72322, r=matthewjasper
Dylan-DPC May 29, 2020
b88dc2e
Rollup merge of #72413 - CAD97:char-range, r=dtolnay
Dylan-DPC May 29, 2020
bc61a5f
Rollup merge of #72568 - golddranks:add_total_cmp_to_floats, r=sfackler
Dylan-DPC May 29, 2020
5109c96
Rollup merge of #72572 - JohnTitor:add-tests, r=matthewjasper
Dylan-DPC May 29, 2020
343ea07
Rollup merge of #72591 - sexxi-goose:rename_upvar_list-to-closure_cap…
Dylan-DPC May 29, 2020
a3d1c79
Rollup merge of #72657 - flip1995:impl_lint_pass-ty, r=matthewjasper
Dylan-DPC May 29, 2020
9279a6a
Rollup merge of #72672 - seritools:remote-test-windows, r=Mark-Simula…
Dylan-DPC May 29, 2020
793967b
Rollup merge of #72683 - RalfJung:char-debug-check, r=Mark-Simulacrum
Dylan-DPC May 29, 2020
ebac81e
Rollup merge of #72710 - jsgf:unused-deps-test, r=jsgf
Dylan-DPC May 29, 2020
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
19 changes: 19 additions & 0 deletions src/liballoc/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -865,6 +865,25 @@ impl From<Box<str>> for Box<[u8]> {
}
}

#[stable(feature = "box_from_array", since = "1.45.0")]
impl<T, const N: usize> From<[T; N]> for Box<[T]>
where
[T; N]: LengthAtMost32,
{
/// Converts a `[T; N]` into a `Box<[T]>`
///
/// This conversion moves the array to newly heap-allocated memory.
///
/// # Examples
/// ```rust
/// let boxed: Box<[u8]> = Box::from([4, 2]);
/// println!("{:?}", boxed);
/// ```
fn from(array: [T; N]) -> Box<[T]> {
box array
}
}

#[stable(feature = "boxed_slice_try_from", since = "1.43.0")]
impl<T, const N: usize> TryFrom<Box<[T]>> for Box<[T; N]>
where
Expand Down
4 changes: 2 additions & 2 deletions src/libcore/char/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ pub fn from_u32(i: u32) -> Option<char> {
#[inline]
#[stable(feature = "char_from_unchecked", since = "1.5.0")]
pub unsafe fn from_u32_unchecked(i: u32) -> char {
transmute(i)
if cfg!(debug_assertions) { char::from_u32(i).unwrap() } else { transmute(i) }
}

#[stable(feature = "char_convert", since = "1.13.0")]
Expand Down Expand Up @@ -218,7 +218,7 @@ impl TryFrom<u32> for char {
Err(CharTryFromError(()))
} else {
// SAFETY: checked that it's a legal unicode value
Ok(unsafe { from_u32_unchecked(i) })
Ok(unsafe { transmute(i) })
}
}
}
Expand Down
63 changes: 63 additions & 0 deletions src/libcore/iter/adapters/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1619,6 +1619,69 @@ impl<I: Iterator> Peekable<I> {
let iter = &mut self.iter;
self.peeked.get_or_insert_with(|| iter.next()).as_ref()
}

/// Consume the next value of this iterator if a condition is true.
///
/// If `func` returns `true` for the next value of this iterator, consume and return it.
/// Otherwise, return `None`.
///
/// # Examples
/// Consume a number if it's equal to 0.
/// ```
/// #![feature(peekable_next_if)]
/// let mut iter = (0..5).peekable();
/// // The first item of the iterator is 0; consume it.
/// assert_eq!(iter.next_if(|&x| x == 0), Some(0));
/// // The next item returned is now 1, so `consume` will return `false`.
/// assert_eq!(iter.next_if(|&x| x == 0), None);
/// // `next_if` saves the value of the next item if it was not equal to `expected`.
/// assert_eq!(iter.next(), Some(1));
/// ```
///
/// Consume any number less than 10.
/// ```
/// #![feature(peekable_next_if)]
/// let mut iter = (1..20).peekable();
/// // Consume all numbers less than 10
/// while iter.next_if(|&x| x < 10).is_some() {}
/// // The next value returned will be 10
/// assert_eq!(iter.next(), Some(10));
/// ```
#[unstable(feature = "peekable_next_if", issue = "72480")]
pub fn next_if(&mut self, func: impl FnOnce(&I::Item) -> bool) -> Option<I::Item> {
match self.next() {
Some(matched) if func(&matched) => Some(matched),
other => {
// Since we called `self.next()`, we consumed `self.peeked`.
assert!(self.peeked.is_none());
self.peeked = Some(other);
None
}
}
}

/// Consume the next item if it is equal to `expected`.
///
/// # Example
/// Consume a number if it's equal to 0.
/// ```
/// #![feature(peekable_next_if)]
/// let mut iter = (0..5).peekable();
/// // The first item of the iterator is 0; consume it.
/// assert_eq!(iter.next_if_eq(&0), Some(0));
/// // The next item returned is now 1, so `consume` will return `false`.
/// assert_eq!(iter.next_if_eq(&0), None);
/// // `next_if_eq` saves the value of the next item if it was not equal to `expected`.
/// assert_eq!(iter.next(), Some(1));
/// ```
#[unstable(feature = "peekable_next_if", issue = "72480")]
pub fn next_if_eq<R>(&mut self, expected: &R) -> Option<I::Item>
where
R: ?Sized,
I::Item: PartialEq<R>,
{
self.next_if(|next| next == expected)
}
}

/// An iterator that rejects elements while `predicate` returns `true`.
Expand Down
84 changes: 74 additions & 10 deletions src/libcore/iter/range.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::char;
use crate::convert::TryFrom;
use crate::mem;
use crate::ops::{self, Add, Sub, Try};
Expand Down Expand Up @@ -400,6 +401,73 @@ step_integer_impls! {
wider than usize: [u32 i32], [u64 i64], [u128 i128];
}

#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
unsafe impl Step for char {
#[inline]
fn steps_between(&start: &char, &end: &char) -> Option<usize> {
let start = start as u32;
let end = end as u32;
if start <= end {
let count = end - start;
if start < 0xD800 && 0xE000 <= end {
usize::try_from(count - 0x800).ok()
} else {
usize::try_from(count).ok()
}
} else {
None
}
}

#[inline]
fn forward_checked(start: char, count: usize) -> Option<char> {
let start = start as u32;
let mut res = Step::forward_checked(start, count)?;
if start < 0xD800 && 0xD800 <= res {
res = Step::forward_checked(res, 0x800)?;
}
if res <= char::MAX as u32 {
// SAFETY: res is a valid unicode scalar
// (below 0x110000 and not in 0xD800..0xE000)
Some(unsafe { char::from_u32_unchecked(res) })
} else {
None
}
}

#[inline]
fn backward_checked(start: char, count: usize) -> Option<char> {
let start = start as u32;
let mut res = Step::backward_checked(start, count)?;
if start >= 0xE000 && 0xE000 > res {
res = Step::backward_checked(res, 0x800)?;
}
// SAFETY: res is a valid unicode scalar
// (below 0x110000 and not in 0xD800..0xE000)
Some(unsafe { char::from_u32_unchecked(res) })
}

#[inline]
unsafe fn forward_unchecked(start: char, count: usize) -> char {
let start = start as u32;
let mut res = Step::forward_unchecked(start, count);
if start < 0xD800 && 0xD800 <= res {
res = Step::forward_unchecked(res, 0x800);
}
char::from_u32_unchecked(res)
}

#[inline]
unsafe fn backward_unchecked(start: char, count: usize) -> char {
let start = start as u32;
let mut res = Step::backward_unchecked(start, count);
if start >= 0xE000 && 0xE000 > res {
res = Step::backward_unchecked(res, 0x800);
}
char::from_u32_unchecked(res)
}
}

macro_rules! range_exact_iter_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
Expand Down Expand Up @@ -551,15 +619,7 @@ impl<A: Step> Iterator for ops::RangeFrom<A> {

#[inline]
fn nth(&mut self, n: usize) -> Option<A> {
// If we would jump over the maximum value, panic immediately.
// This is consistent with behavior before the Step redesign,
// even though it's inconsistent with n `next` calls.
// To get consistent behavior, change it to use `forward` instead.
// This change should go through FCP separately to the redesign, so is for now left as a
// FIXME: make this consistent
let plus_n =
Step::forward_checked(self.start.clone(), n).expect("overflow in RangeFrom::nth");
// The final step should always be debug-checked.
let plus_n = Step::forward(self.start.clone(), n);
self.start = Step::forward(plus_n.clone(), 1);
Some(plus_n)
}
Expand All @@ -582,7 +642,11 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> {
}
let is_iterating = self.start < self.end;
Some(if is_iterating {
let n = Step::forward(self.start.clone(), 1);
// SAFETY: just checked precondition
// We use the unchecked version here, because
// otherwise `for _ in '\0'..=char::MAX`
// does not successfully remove panicking code.
let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) };
mem::replace(&mut self.start, n)
} else {
self.exhausted = true;
Expand Down
74 changes: 74 additions & 0 deletions src/libcore/num/f32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -810,4 +810,78 @@ impl f32 {
pub fn from_ne_bytes(bytes: [u8; 4]) -> Self {
Self::from_bits(u32::from_ne_bytes(bytes))
}

/// Returns an ordering between self and other values.
/// Unlike the standard partial comparison between floating point numbers,
/// this comparison always produces an ordering in accordance to
/// the totalOrder predicate as defined in IEEE 754 (2008 revision)
/// floating point standard. The values are ordered in following order:
/// - Negative quiet NaN
/// - Negative signaling NaN
/// - Negative infinity
/// - Negative numbers
/// - Negative subnormal numbers
/// - Negative zero
/// - Positive zero
/// - Positive subnormal numbers
/// - Positive numbers
/// - Positive infinity
/// - Positive signaling NaN
/// - Positive quiet NaN
///
/// # Example
/// ```
/// #![feature(total_cmp)]
/// struct GoodBoy {
/// name: String,
/// weight: f32,
/// }
///
/// let mut bois = vec![
/// GoodBoy { name: "Pucci".to_owned(), weight: 0.1 },
/// GoodBoy { name: "Woofer".to_owned(), weight: 99.0 },
/// GoodBoy { name: "Yapper".to_owned(), weight: 10.0 },
/// GoodBoy { name: "Chonk".to_owned(), weight: f32::INFINITY },
/// GoodBoy { name: "Abs. Unit".to_owned(), weight: f32::NAN },
/// GoodBoy { name: "Floaty".to_owned(), weight: -5.0 },
/// ];
///
/// bois.sort_by(|a, b| a.weight.total_cmp(&b.weight));
/// # assert!(bois.into_iter().map(|b| b.weight)
/// # .zip([-5.0, 0.1, 10.0, 99.0, f32::INFINITY, f32::NAN].iter())
/// # .all(|(a, b)| a.to_bits() == b.to_bits()))
/// ```
#[unstable(feature = "total_cmp", issue = "72599")]
#[inline]
pub fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering {
let mut left = self.to_bits() as i32;
let mut right = other.to_bits() as i32;

// In case of negatives, flip all the bits except the sign
// to achieve a similar layout as two's complement integers
//
// Why does this work? IEEE 754 floats consist of three fields:
// Sign bit, exponent and mantissa. The set of exponent and mantissa
// fields as a whole have the property that their bitwise order is
// equal to the numeric magnitude where the magnitude is defined.
// The magnitude is not normally defined on NaN values, but
// IEEE 754 totalOrder defines the NaN values also to follow the
// bitwise order. This leads to order explained in the doc comment.
// However, the representation of magnitude is the same for negative
// and positive numbers – only the sign bit is different.
// To easily compare the floats as signed integers, we need to
// flip the exponent and mantissa bits in case of negative numbers.
// We effectively convert the numbers to "two's complement" form.
//
// To do the flipping, we construct a mask and XOR against it.
// We branchlessly calculate an "all-ones except for the sign bit"
// mask from negative-signed values: right shifting sign-extends
// the integer, so we "fill" the mask with sign bits, and then
// convert to unsigned to push one more zero bit.
// On positive values, the mask is all zeros, so it's a no-op.
left ^= (((left >> 31) as u32) >> 1) as i32;
right ^= (((right >> 31) as u32) >> 1) as i32;

left.cmp(&right)
}
}
74 changes: 74 additions & 0 deletions src/libcore/num/f64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -824,4 +824,78 @@ impl f64 {
pub fn from_ne_bytes(bytes: [u8; 8]) -> Self {
Self::from_bits(u64::from_ne_bytes(bytes))
}

/// Returns an ordering between self and other values.
/// Unlike the standard partial comparison between floating point numbers,
/// this comparison always produces an ordering in accordance to
/// the totalOrder predicate as defined in IEEE 754 (2008 revision)
/// floating point standard. The values are ordered in following order:
/// - Negative quiet NaN
/// - Negative signaling NaN
/// - Negative infinity
/// - Negative numbers
/// - Negative subnormal numbers
/// - Negative zero
/// - Positive zero
/// - Positive subnormal numbers
/// - Positive numbers
/// - Positive infinity
/// - Positive signaling NaN
/// - Positive quiet NaN
///
/// # Example
/// ```
/// #![feature(total_cmp)]
/// struct GoodBoy {
/// name: String,
/// weight: f64,
/// }
///
/// let mut bois = vec![
/// GoodBoy { name: "Pucci".to_owned(), weight: 0.1 },
/// GoodBoy { name: "Woofer".to_owned(), weight: 99.0 },
/// GoodBoy { name: "Yapper".to_owned(), weight: 10.0 },
/// GoodBoy { name: "Chonk".to_owned(), weight: f64::INFINITY },
/// GoodBoy { name: "Abs. Unit".to_owned(), weight: f64::NAN },
/// GoodBoy { name: "Floaty".to_owned(), weight: -5.0 },
/// ];
///
/// bois.sort_by(|a, b| a.weight.total_cmp(&b.weight));
/// # assert!(bois.into_iter().map(|b| b.weight)
/// # .zip([-5.0, 0.1, 10.0, 99.0, f64::INFINITY, f64::NAN].iter())
/// # .all(|(a, b)| a.to_bits() == b.to_bits()))
/// ```
#[unstable(feature = "total_cmp", issue = "72599")]
#[inline]
pub fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering {
let mut left = self.to_bits() as i64;
let mut right = other.to_bits() as i64;

// In case of negatives, flip all the bits except the sign
// to achieve a similar layout as two's complement integers
//
// Why does this work? IEEE 754 floats consist of three fields:
// Sign bit, exponent and mantissa. The set of exponent and mantissa
// fields as a whole have the property that their bitwise order is
// equal to the numeric magnitude where the magnitude is defined.
// The magnitude is not normally defined on NaN values, but
// IEEE 754 totalOrder defines the NaN values also to follow the
// bitwise order. This leads to order explained in the doc comment.
// However, the representation of magnitude is the same for negative
// and positive numbers – only the sign bit is different.
// To easily compare the floats as signed integers, we need to
// flip the exponent and mantissa bits in case of negative numbers.
// We effectively convert the numbers to "two's complement" form.
//
// To do the flipping, we construct a mask and XOR against it.
// We branchlessly calculate an "all-ones except for the sign bit"
// mask from negative-signed values: right shifting sign-extends
// the integer, so we "fill" the mask with sign bits, and then
// convert to unsigned to push one more zero bit.
// On positive values, the mask is all zeros, so it's a no-op.
left ^= (((left >> 63) as u64) >> 1) as i64;
right ^= (((right >> 63) as u64) >> 1) as i64;

left.cmp(&right)
}
}
Loading