From f310d0e5003cde10959eba46dd969f37b8089382 Mon Sep 17 00:00:00 2001 From: ltdk Date: Tue, 1 Jun 2021 22:50:42 -0400 Subject: [PATCH 01/10] Add lerp method --- library/std/src/f32.rs | 28 ++++++++++++++++++++++++++++ library/std/src/f64.rs | 28 ++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs index c16d27fa1f58c..32a4d415362a6 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -876,4 +876,32 @@ impl f32 { pub fn atanh(self) -> f32 { 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() } + + /// Linear interpolation between `start` and `end`. + /// + /// This enables the calculation of a "smooth" transition between `start` and `end`, + /// where start is represented by `self == 0.0` and `end` is represented by `self == 1.0`. + /// + /// Values below 0.0 or above 1.0 are allowed, and in general this function closely + /// resembles the value of `start + self * (end - start)`, plus additional guarantees. + /// + /// Those guarantees are, assuming that all values are [`finite`]: + /// + /// * The value at 0.0 is always `start` and the value at 1.0 is always `end` (exactness) + /// * If `start == end`, the value at any point will always be `start == end` (consistency) + /// * The values will always move in the direction from `start` to `end` (monotonicity) + /// + /// [`finite`]: #method.is_finite + #[must_use = "method returns a new number and does not mutate the original value"] + #[unstable(feature = "float_interpolation", issue = "71015")] + pub fn lerp(self, start: f32, end: f32) -> f32 { + // consistent + if start == end { + start + + // exact/monotonic + } else { + self.mul_add(end, (-self).mul_add(start, start)) + } + } } diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index 4c95df5ffe04a..39c3e587e1f6f 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -879,6 +879,34 @@ impl f64 { 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() } + /// Linear interpolation between `start` and `end`. + /// + /// This enables the calculation of a "smooth" transition between `start` and `end`, + /// where start is represented by `self == 0.0` and `end` is represented by `self == 1.0`. + /// + /// Values below 0.0 or above 1.0 are allowed, and in general this function closely + /// resembles the value of `start + self * (end - start)`, plus additional guarantees. + /// + /// Those guarantees are, assuming that all values are [`finite`]: + /// + /// * The value at 0.0 is always `start` and the value at 1.0 is always `end` (exactness) + /// * If `start == end`, the value at any point will always be `start == end` (consistency) + /// * The values will always move in the direction from `start` to `end` (monotonicity) + /// + /// [`finite`]: #method.is_finite + #[must_use = "method returns a new number and does not mutate the original value"] + #[unstable(feature = "float_interpolation", issue = "71015")] + pub fn lerp(self, start: f64, end: f64) -> f64 { + // consistent + if start == end { + start + + // exact/monotonic + } else { + self.mul_add(end, (-self).mul_add(start, start)) + } + } + // Solaris/Illumos requires a wrapper around log, log2, and log10 functions // because of their non-standard behavior (e.g., log(-n) returns -Inf instead // of expected NaN). From 0865acd22b9f0fa2d2ac0bcec61b479e4b3613d9 Mon Sep 17 00:00:00 2001 From: ltdk Date: Sun, 6 Jun 2021 22:42:53 -0400 Subject: [PATCH 02/10] A few lerp tests --- library/std/src/f32/tests.rs | 21 +++++++++++++++++++++ library/std/src/f64/tests.rs | 21 +++++++++++++++++++++ library/std/src/lib.rs | 1 + 3 files changed, 43 insertions(+) diff --git a/library/std/src/f32/tests.rs b/library/std/src/f32/tests.rs index 0d4b865f3392a..7b54bc2335450 100644 --- a/library/std/src/f32/tests.rs +++ b/library/std/src/f32/tests.rs @@ -757,3 +757,24 @@ fn test_total_cmp() { assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::INFINITY)); assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan())); } + +#[test] +fn test_lerp_exact() { + assert_eq!(f32::lerp(0.0, 2.0, 4.0), 2.0); + assert_eq!(f32::lerp(1.0, 2.0, 4.0), 4.0); + assert_eq!(f32::lerp(0.0, f32::MIN, f32::MAX), f32::MIN); + assert_eq!(f32::lerp(1.0, f32::MIN, f32::MAX), f32::MAX); +} + +#[test] +fn test_lerp_consistent() { + assert_eq!(f32::lerp(f32::MAX, f32::MIN, f32::MIN), f32::MIN); + assert_eq!(f32::lerp(f32::MIN, f32::MAX, f32::MAX), f32::MAX); +} + +#[test] +fn test_lerp_values() { + assert_eq!(f32::lerp(0.25, 1.0, 2.0), 1.25); + assert_eq!(f32::lerp(0.50, 1.0, 2.0), 1.50); + assert_eq!(f32::lerp(0.75, 1.0, 2.0), 1.75); +} diff --git a/library/std/src/f64/tests.rs b/library/std/src/f64/tests.rs index 5c163cfe90e0b..3efb2e9d3236c 100644 --- a/library/std/src/f64/tests.rs +++ b/library/std/src/f64/tests.rs @@ -753,3 +753,24 @@ fn test_total_cmp() { assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::INFINITY)); assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan())); } + +#[test] +fn test_lerp_exact() { + assert_eq!(f64::lerp(0.0, 2.0, 4.0), 2.0); + assert_eq!(f64::lerp(1.0, 2.0, 4.0), 4.0); + assert_eq!(f64::lerp(0.0, f64::MIN, f64::MAX), f64::MIN); + assert_eq!(f64::lerp(1.0, f64::MIN, f64::MAX), f64::MAX); +} + +#[test] +fn test_lerp_consistent() { + assert_eq!(f64::lerp(f64::MAX, f64::MIN, f64::MIN), f64::MIN); + assert_eq!(f64::lerp(f64::MIN, f64::MAX, f64::MAX), f64::MAX); +} + +#[test] +fn test_lerp_values() { + assert_eq!(f64::lerp(0.25, 1.0, 2.0), 1.25); + assert_eq!(f64::lerp(0.50, 1.0, 2.0), 1.50); + assert_eq!(f64::lerp(0.75, 1.0, 2.0), 1.75); +} diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 8e4c63762fd38..a0f7b41b8a0f5 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -268,6 +268,7 @@ #![feature(exhaustive_patterns)] #![feature(extend_one)] #![cfg_attr(bootstrap, feature(extended_key_value_attributes))] +#![feature(float_interpolation)] #![feature(fn_traits)] #![feature(format_args_nl)] #![feature(gen_future)] From 2cbd5d1df54400b8bd718b7e0dadc4c38c6f9932 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?= Date: Thu, 10 Jun 2021 19:09:04 +0200 Subject: [PATCH 03/10] Specialize `io::Bytes::size_hint` for more types --- library/std/src/io/buffered/bufreader.rs | 8 +++- library/std/src/io/mod.rs | 58 +++++++++++++++++++++++- library/std/src/io/tests.rs | 20 +++++++- library/std/src/io/util.rs | 13 ++++++ 4 files changed, 96 insertions(+), 3 deletions(-) diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs index d8021d3e99a70..32d194d961652 100644 --- a/library/std/src/io/buffered/bufreader.rs +++ b/library/std/src/io/buffered/bufreader.rs @@ -438,7 +438,13 @@ impl Seek for BufReader { } impl SizeHint for BufReader { + #[inline] fn lower_bound(&self) -> usize { - self.buffer().len() + SizeHint::lower_bound(self.get_ref()) + self.buffer().len() + } + + #[inline] + fn upper_bound(&self) -> Option { + SizeHint::upper_bound(self.get_ref()).and_then(|up| self.buffer().len().checked_add(up)) } } diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 4c154dbe01a5a..95aef0bd0fc42 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -252,6 +252,7 @@ mod tests; use crate::cmp; +use crate::convert::TryInto; use crate::fmt; use crate::ops::{Deref, DerefMut}; use crate::ptr; @@ -2291,13 +2292,15 @@ impl BufRead for Chain { } impl SizeHint for Chain { + #[inline] fn lower_bound(&self) -> usize { SizeHint::lower_bound(&self.first) + SizeHint::lower_bound(&self.second) } + #[inline] fn upper_bound(&self) -> Option { match (SizeHint::upper_bound(&self.first), SizeHint::upper_bound(&self.second)) { - (Some(first), Some(second)) => Some(first + second), + (Some(first), Some(second)) => first.checked_add(second), _ => None, } } @@ -2502,6 +2505,21 @@ impl BufRead for Take { } } +impl SizeHint for Take { + #[inline] + fn lower_bound(&self) -> usize { + cmp::min(SizeHint::lower_bound(&self.inner) as u64, self.limit) as usize + } + + #[inline] + fn upper_bound(&self) -> Option { + match SizeHint::upper_bound(&self.inner) { + Some(upper_bound) => Some(cmp::min(upper_bound as u64, self.limit) as usize), + None => self.limit.try_into().ok(), + } + } +} + /// An iterator over `u8` values of a reader. /// /// This struct is generally created by calling [`bytes`] on a reader. @@ -2546,15 +2564,53 @@ trait SizeHint { } impl SizeHint for T { + #[inline] default fn lower_bound(&self) -> usize { 0 } + #[inline] default fn upper_bound(&self) -> Option { None } } +impl SizeHint for &mut T { + #[inline] + fn lower_bound(&self) -> usize { + SizeHint::lower_bound(*self) + } + + #[inline] + fn upper_bound(&self) -> Option { + SizeHint::upper_bound(*self) + } +} + +impl SizeHint for Box { + #[inline] + fn lower_bound(&self) -> usize { + SizeHint::lower_bound(&**self) + } + + #[inline] + fn upper_bound(&self) -> Option { + SizeHint::upper_bound(&**self) + } +} + +impl SizeHint for &[u8] { + #[inline] + fn lower_bound(&self) -> usize { + self.len() + } + + #[inline] + fn upper_bound(&self) -> Option { + Some(self.len()) + } +} + /// An iterator over the contents of an instance of `BufRead` split on a /// particular byte. /// diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs index 2b14e16150317..a483847fb26c8 100644 --- a/library/std/src/io/tests.rs +++ b/library/std/src/io/tests.rs @@ -224,6 +224,24 @@ fn empty_size_hint() { assert_eq!(size_hint, (0, Some(0))); } +#[test] +fn slice_size_hint() { + let size_hint = (&[1, 2, 3]).bytes().size_hint(); + assert_eq!(size_hint, (3, Some(3))); +} + +#[test] +fn take_size_hint() { + let size_hint = (&[1, 2, 3]).take(2).bytes().size_hint(); + assert_eq!(size_hint, (2, Some(2))); + + let size_hint = (&[1, 2, 3]).take(4).bytes().size_hint(); + assert_eq!(size_hint, (3, Some(3))); + + let size_hint = io::repeat(0).take(3).bytes().size_hint(); + assert_eq!(size_hint, (3, Some(3))); +} + #[test] fn chain_empty_size_hint() { let chain = io::empty().chain(io::empty()); @@ -242,7 +260,7 @@ fn chain_size_hint() { let chain = buf_reader_1.chain(buf_reader_2); let size_hint = chain.bytes().size_hint(); - assert_eq!(size_hint, (testdata.len(), None)); + assert_eq!(size_hint, (testdata.len(), Some(testdata.len()))); } #[test] diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs index 73f2f3eb3f5dc..f3bff391fb3ea 100644 --- a/library/std/src/io/util.rs +++ b/library/std/src/io/util.rs @@ -83,6 +83,7 @@ impl fmt::Debug for Empty { } impl SizeHint for Empty { + #[inline] fn upper_bound(&self) -> Option { Some(0) } @@ -147,6 +148,18 @@ impl Read for Repeat { } } +impl SizeHint for Repeat { + #[inline] + fn lower_bound(&self) -> usize { + usize::MAX + } + + #[inline] + fn upper_bound(&self) -> Option { + None + } +} + #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Repeat { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { From d8e247e38c9ce6746a595d374cf260b46ac54f27 Mon Sep 17 00:00:00 2001 From: ltdk Date: Sun, 13 Jun 2021 14:00:15 -0400 Subject: [PATCH 04/10] More lerp tests, altering lerp docs --- library/std/src/f32.rs | 34 ++++++++++++++++++----------- library/std/src/f32/tests.rs | 42 ++++++++++++++++++++++++++++++++++++ library/std/src/f64.rs | 34 ++++++++++++++++++----------- library/std/src/f64/tests.rs | 34 +++++++++++++++++++++++++++++ 4 files changed, 118 insertions(+), 26 deletions(-) diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs index 32a4d415362a6..00cab72564f94 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -879,19 +879,27 @@ impl f32 { /// Linear interpolation between `start` and `end`. /// - /// This enables the calculation of a "smooth" transition between `start` and `end`, - /// where start is represented by `self == 0.0` and `end` is represented by `self == 1.0`. - /// - /// Values below 0.0 or above 1.0 are allowed, and in general this function closely - /// resembles the value of `start + self * (end - start)`, plus additional guarantees. - /// - /// Those guarantees are, assuming that all values are [`finite`]: - /// - /// * The value at 0.0 is always `start` and the value at 1.0 is always `end` (exactness) - /// * If `start == end`, the value at any point will always be `start == end` (consistency) - /// * The values will always move in the direction from `start` to `end` (monotonicity) - /// - /// [`finite`]: #method.is_finite + /// This enables linear interpolation between `start` and `end`, where start is represented by + /// `self == 0.0` and `end` is represented by `self == 1.0`. This is the basis of all + /// "transition", "easing", or "step" functions; if you change `self` from 0.0 to 1.0 + /// at a given rate, the result will change from `start` to `end` at a similar rate. + /// + /// Values below 0.0 or above 1.0 are allowed, allowing you to extrapolate values outside the + /// range from `start` to `end`. This also is useful for transition functions which might + /// move slightly past the end or start for a desired effect. Mathematically, the values + /// returned are equivalent to `start + self * (end - start)`, although we make a few specific + /// guarantees that are useful specifically to linear interpolation. + /// + /// These guarantees are: + /// + /// * If `start` and `end` are [finite], the value at 0.0 is always `start` and the + /// value at 1.0 is always `end`. (exactness) + /// * If `start` and `end` are [finite], the values will always move in the direction from + /// `start` to `end` (monotonicity) + /// * If `self` is [finite] and `start == end`, the value at any point will always be + /// `start == end`. (consistency) + /// + /// [finite]: #method.is_finite #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "float_interpolation", issue = "71015")] pub fn lerp(self, start: f32, end: f32) -> f32 { diff --git a/library/std/src/f32/tests.rs b/library/std/src/f32/tests.rs index 7b54bc2335450..fe66a73afd63a 100644 --- a/library/std/src/f32/tests.rs +++ b/library/std/src/f32/tests.rs @@ -760,8 +760,11 @@ fn test_total_cmp() { #[test] fn test_lerp_exact() { + // simple values assert_eq!(f32::lerp(0.0, 2.0, 4.0), 2.0); assert_eq!(f32::lerp(1.0, 2.0, 4.0), 4.0); + + // boundary values assert_eq!(f32::lerp(0.0, f32::MIN, f32::MAX), f32::MIN); assert_eq!(f32::lerp(1.0, f32::MIN, f32::MAX), f32::MAX); } @@ -770,11 +773,50 @@ fn test_lerp_exact() { fn test_lerp_consistent() { assert_eq!(f32::lerp(f32::MAX, f32::MIN, f32::MIN), f32::MIN); assert_eq!(f32::lerp(f32::MIN, f32::MAX, f32::MAX), f32::MAX); + + // as long as t is finite, a/b can be infinite + assert_eq!(f32::lerp(f32::MAX, f32::NEG_INFINITY, f32::NEG_INFINITY), f32::NEG_INFINITY); + assert_eq!(f32::lerp(f32::MIN, f32::INFINITY, f32::INFINITY), f32::INFINITY); +} + +#[test] +fn test_lerp_nan_infinite() { + // non-finite t is not NaN if a/b different + assert!(!f32::lerp(f32::INFINITY, f32::MIN, f32::MAX).is_nan()); + assert!(!f32::lerp(f32::NEG_INFINITY, f32::MIN, f32::MAX).is_nan()); } #[test] fn test_lerp_values() { + // just a few basic values assert_eq!(f32::lerp(0.25, 1.0, 2.0), 1.25); assert_eq!(f32::lerp(0.50, 1.0, 2.0), 1.50); assert_eq!(f32::lerp(0.75, 1.0, 2.0), 1.75); } + +#[test] +fn test_lerp_monotonic() { + // near 0 + let below_zero = f32::lerp(-f32::EPSILON, f32::MIN, f32::MAX); + let zero = f32::lerp(0.0, f32::MIN, f32::MAX); + let above_zero = f32::lerp(f32::EPSILON, f32::MIN, f32::MAX); + assert!(below_zero <= zero); + assert!(zero <= above_zero); + assert!(below_zero <= above_zero); + + // near 0.5 + let below_half = f32::lerp(0.5 - f32::EPSILON, f32::MIN, f32::MAX); + let half = f32::lerp(0.5, f32::MIN, f32::MAX); + let above_half = f32::lerp(0.5 + f32::EPSILON, f32::MIN, f32::MAX); + assert!(below_half <= half); + assert!(half <= above_half); + assert!(below_half <= above_half); + + // near 1 + let below_one = f32::lerp(1.0 - f32::EPSILON, f32::MIN, f32::MAX); + let one = f32::lerp(1.0, f32::MIN, f32::MAX); + let above_one = f32::lerp(1.0 + f32::EPSILON, f32::MIN, f32::MAX); + assert!(below_one <= one); + assert!(one <= above_one); + assert!(below_one <= above_one); +} diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index 39c3e587e1f6f..ff41f999dd565 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -881,19 +881,27 @@ impl f64 { /// Linear interpolation between `start` and `end`. /// - /// This enables the calculation of a "smooth" transition between `start` and `end`, - /// where start is represented by `self == 0.0` and `end` is represented by `self == 1.0`. - /// - /// Values below 0.0 or above 1.0 are allowed, and in general this function closely - /// resembles the value of `start + self * (end - start)`, plus additional guarantees. - /// - /// Those guarantees are, assuming that all values are [`finite`]: - /// - /// * The value at 0.0 is always `start` and the value at 1.0 is always `end` (exactness) - /// * If `start == end`, the value at any point will always be `start == end` (consistency) - /// * The values will always move in the direction from `start` to `end` (monotonicity) - /// - /// [`finite`]: #method.is_finite + /// This enables linear interpolation between `start` and `end`, where start is represented by + /// `self == 0.0` and `end` is represented by `self == 1.0`. This is the basis of all + /// "transition", "easing", or "step" functions; if you change `self` from 0.0 to 1.0 + /// at a given rate, the result will change from `start` to `end` at a similar rate. + /// + /// Values below 0.0 or above 1.0 are allowed, allowing you to extrapolate values outside the + /// range from `start` to `end`. This also is useful for transition functions which might + /// move slightly past the end or start for a desired effect. Mathematically, the values + /// returned are equivalent to `start + self * (end - start)`, although we make a few specific + /// guarantees that are useful specifically to linear interpolation. + /// + /// These guarantees are: + /// + /// * If `start` and `end` are [finite], the value at 0.0 is always `start` and the + /// value at 1.0 is always `end`. (exactness) + /// * If `start` and `end` are [finite], the values will always move in the direction from + /// `start` to `end` (monotonicity) + /// * If `self` is [finite] and `start == end`, the value at any point will always be + /// `start == end`. (consistency) + /// + /// [finite]: #method.is_finite #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "float_interpolation", issue = "71015")] pub fn lerp(self, start: f64, end: f64) -> f64 { diff --git a/library/std/src/f64/tests.rs b/library/std/src/f64/tests.rs index 3efb2e9d3236c..04cb0109261a4 100644 --- a/library/std/src/f64/tests.rs +++ b/library/std/src/f64/tests.rs @@ -756,8 +756,11 @@ fn test_total_cmp() { #[test] fn test_lerp_exact() { + // simple values assert_eq!(f64::lerp(0.0, 2.0, 4.0), 2.0); assert_eq!(f64::lerp(1.0, 2.0, 4.0), 4.0); + + // boundary values assert_eq!(f64::lerp(0.0, f64::MIN, f64::MAX), f64::MIN); assert_eq!(f64::lerp(1.0, f64::MIN, f64::MAX), f64::MAX); } @@ -766,11 +769,42 @@ fn test_lerp_exact() { fn test_lerp_consistent() { assert_eq!(f64::lerp(f64::MAX, f64::MIN, f64::MIN), f64::MIN); assert_eq!(f64::lerp(f64::MIN, f64::MAX, f64::MAX), f64::MAX); + + // as long as t is finite, a/b can be infinite + assert_eq!(f64::lerp(f64::MAX, f64::NEG_INFINITY, f64::NEG_INFINITY), f64::NEG_INFINITY); + assert_eq!(f64::lerp(f64::MIN, f64::INFINITY, f64::INFINITY), f64::INFINITY); +} + +#[test] +fn test_lerp_nan_infinite() { + // non-finite t is not NaN if a/b different + assert!(!f64::lerp(f64::INFINITY, f64::MIN, f64::MAX).is_nan()); + assert!(!f64::lerp(f64::NEG_INFINITY, f64::MIN, f64::MAX).is_nan()); } #[test] fn test_lerp_values() { + // just a few basic values assert_eq!(f64::lerp(0.25, 1.0, 2.0), 1.25); assert_eq!(f64::lerp(0.50, 1.0, 2.0), 1.50); assert_eq!(f64::lerp(0.75, 1.0, 2.0), 1.75); } + +#[test] +fn test_lerp_monotonic() { + // near 0 + let below_zero = f64::lerp(-f64::EPSILON, f64::MIN, f64::MAX); + let zero = f64::lerp(0.0, f64::MIN, f64::MAX); + let above_zero = f64::lerp(f64::EPSILON, f64::MIN, f64::MAX); + assert!(below_zero <= zero); + assert!(zero <= above_zero); + assert!(below_zero <= above_zero); + + // near 1 + let below_one = f64::lerp(1.0 - f64::EPSILON, f64::MIN, f64::MAX); + let one = f64::lerp(1.0, f64::MIN, f64::MAX); + let above_one = f64::lerp(1.0 + f64::EPSILON, f64::MIN, f64::MAX); + assert!(below_one <= one); + assert!(one <= above_one); + assert!(below_one <= above_one); +} From 525d76026fe855f6a9de4604d9fee50d974994a3 Mon Sep 17 00:00:00 2001 From: ltdk Date: Sun, 13 Jun 2021 14:04:43 -0400 Subject: [PATCH 05/10] Change tracking issue --- library/std/src/f32.rs | 2 +- library/std/src/f64.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs index 00cab72564f94..21bd79611a5e5 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -901,7 +901,7 @@ impl f32 { /// /// [finite]: #method.is_finite #[must_use = "method returns a new number and does not mutate the original value"] - #[unstable(feature = "float_interpolation", issue = "71015")] + #[unstable(feature = "float_interpolation", issue = "86269")] pub fn lerp(self, start: f32, end: f32) -> f32 { // consistent if start == end { diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index ff41f999dd565..8c8cf73741b51 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -903,7 +903,7 @@ impl f64 { /// /// [finite]: #method.is_finite #[must_use = "method returns a new number and does not mutate the original value"] - #[unstable(feature = "float_interpolation", issue = "71015")] + #[unstable(feature = "float_interpolation", issue = "86269")] pub fn lerp(self, start: f64, end: f64) -> f64 { // consistent if start == end { From 34f38bf76006b0dfdc2784d76e3e1775cee024a4 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Thu, 17 Jun 2021 09:45:19 +0900 Subject: [PATCH 06/10] Make `s` pre-interned --- compiler/rustc_builtin_macros/src/deriving/encodable.rs | 7 +------ compiler/rustc_span/src/symbol.rs | 1 + 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/deriving/encodable.rs b/compiler/rustc_builtin_macros/src/deriving/encodable.rs index 01a57bea14e3b..c5f3a9d3379a7 100644 --- a/compiler/rustc_builtin_macros/src/deriving/encodable.rs +++ b/compiler/rustc_builtin_macros/src/deriving/encodable.rs @@ -124,12 +124,7 @@ pub fn expand_deriving_rustc_encodable( explicit_self: borrowed_explicit_self(), args: vec![( Ptr(Box::new(Literal(Path::new_local(typaram))), Borrowed(None, Mutability::Mut)), - // FIXME: we could use `sym::s` here, but making `s` a static - // symbol changes the symbol index ordering in a way that makes - // ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.rs - // fail. The linting code should be fixed so that its output - // does not depend on the symbol index ordering. - Symbol::intern("s"), + sym::s, )], ret_ty: Literal(Path::new_( pathvec_std!(result::Result), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index a96d37c652d12..862bde3f6a3e8 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1062,6 +1062,7 @@ symbols! { rustdoc, rustfmt, rvalue_static_promotion, + s, sanitize, sanitizer_runtime, saturating_add, From 259bf5f47a7247c3ecf7100845953859d02562b4 Mon Sep 17 00:00:00 2001 From: Maarten de Vries Date: Wed, 16 Jun 2021 12:37:00 +0200 Subject: [PATCH 07/10] Rely on libc for correct integer types in os/unix/net/ancillary.rs. --- library/std/src/os/unix/net/ancillary.rs | 110 +++-------------------- 1 file changed, 10 insertions(+), 100 deletions(-) diff --git a/library/std/src/os/unix/net/ancillary.rs b/library/std/src/os/unix/net/ancillary.rs index 15ce7056fea34..cd429d1426937 100644 --- a/library/std/src/os/unix/net/ancillary.rs +++ b/library/std/src/os/unix/net/ancillary.rs @@ -32,23 +32,8 @@ pub(super) fn recv_vectored_with_ancillary_from( msg.msg_name = &mut msg_name as *mut _ as *mut _; msg.msg_namelen = size_of::() as libc::socklen_t; msg.msg_iov = bufs.as_mut_ptr().cast(); - cfg_if::cfg_if! { - if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] { - msg.msg_iovlen = bufs.len() as libc::size_t; - msg.msg_controllen = ancillary.buffer.len() as libc::size_t; - } else if #[cfg(any( - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - all(target_os = "linux", target_env = "musl",), - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - ))] { - msg.msg_iovlen = bufs.len() as libc::c_int; - msg.msg_controllen = ancillary.buffer.len() as libc::socklen_t; - } - } + msg.msg_iovlen = bufs.len() as _; + msg.msg_controllen = ancillary.buffer.len() as _; // macos requires that the control pointer is null when the len is 0. if msg.msg_controllen > 0 { msg.msg_control = ancillary.buffer.as_mut_ptr().cast(); @@ -80,23 +65,8 @@ pub(super) fn send_vectored_with_ancillary_to( msg.msg_name = &mut msg_name as *mut _ as *mut _; msg.msg_namelen = msg_namelen; msg.msg_iov = bufs.as_ptr() as *mut _; - cfg_if::cfg_if! { - if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] { - msg.msg_iovlen = bufs.len() as libc::size_t; - msg.msg_controllen = ancillary.length as libc::size_t; - } else if #[cfg(any( - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - all(target_os = "linux", target_env = "musl",), - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - ))] { - msg.msg_iovlen = bufs.len() as libc::c_int; - msg.msg_controllen = ancillary.length as libc::socklen_t; - } - } + msg.msg_iovlen = bufs.len() as _; + msg.msg_controllen = ancillary.length as _; // macos requires that the control pointer is null when the len is 0. if msg.msg_controllen > 0 { msg.msg_control = ancillary.buffer.as_mut_ptr().cast(); @@ -144,21 +114,7 @@ fn add_to_ancillary_data( let mut msg: libc::msghdr = zeroed(); msg.msg_control = buffer.as_mut_ptr().cast(); - cfg_if::cfg_if! { - if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] { - msg.msg_controllen = *length as libc::size_t; - } else if #[cfg(any( - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - all(target_os = "linux", target_env = "musl",), - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - ))] { - msg.msg_controllen = *length as libc::socklen_t; - } - } + msg.msg_controllen = *length as _; let mut cmsg = libc::CMSG_FIRSTHDR(&msg); let mut previous_cmsg = cmsg; @@ -180,21 +136,7 @@ fn add_to_ancillary_data( (*previous_cmsg).cmsg_level = cmsg_level; (*previous_cmsg).cmsg_type = cmsg_type; - cfg_if::cfg_if! { - if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] { - (*previous_cmsg).cmsg_len = libc::CMSG_LEN(source_len) as libc::size_t; - } else if #[cfg(any( - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - all(target_os = "linux", target_env = "musl",), - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - ))] { - (*previous_cmsg).cmsg_len = libc::CMSG_LEN(source_len) as libc::socklen_t; - } - } + (*previous_cmsg).cmsg_len = libc::CMSG_LEN(source_len) as _; let data = libc::CMSG_DATA(previous_cmsg).cast(); @@ -364,28 +306,10 @@ impl<'a> AncillaryData<'a> { fn try_from_cmsghdr(cmsg: &'a libc::cmsghdr) -> Result { unsafe { - cfg_if::cfg_if! { - if #[cfg(any( - target_os = "android", - all(target_os = "linux", target_env = "gnu"), - all(target_os = "linux", target_env = "uclibc"), - ))] { - let cmsg_len_zero = libc::CMSG_LEN(0) as libc::size_t; - } else if #[cfg(any( - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - all(target_os = "linux", target_env = "musl",), - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - ))] { - let cmsg_len_zero = libc::CMSG_LEN(0) as libc::socklen_t; - } - } - let data_len = (*cmsg).cmsg_len - cmsg_len_zero; + let cmsg_len_zero = libc::CMSG_LEN(0) as usize; + let data_len = (*cmsg).cmsg_len as usize - cmsg_len_zero; let data = libc::CMSG_DATA(cmsg).cast(); - let data = from_raw_parts(data, data_len as usize); + let data = from_raw_parts(data, data_len); match (*cmsg).cmsg_level { libc::SOL_SOCKET => match (*cmsg).cmsg_type { @@ -419,21 +343,7 @@ impl<'a> Iterator for Messages<'a> { unsafe { let mut msg: libc::msghdr = zeroed(); msg.msg_control = self.buffer.as_ptr() as *mut _; - cfg_if::cfg_if! { - if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] { - msg.msg_controllen = self.buffer.len() as libc::size_t; - } else if #[cfg(any( - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - all(target_os = "linux", target_env = "musl",), - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - ))] { - msg.msg_controllen = self.buffer.len() as libc::socklen_t; - } - } + msg.msg_controllen = self.buffer.len() as _; let cmsg = if let Some(current) = self.current { libc::CMSG_NXTHDR(&msg, current) From 2cedd86b1c25db321e7e023f6a429e23425a7e00 Mon Sep 17 00:00:00 2001 From: Fabian Wolff Date: Thu, 17 Jun 2021 16:45:26 +0200 Subject: [PATCH 08/10] Fix ICE when using `#[doc(keyword = "...")]` on non-items --- compiler/rustc_passes/src/check_attr.rs | 7 +++++-- src/test/ui/rustdoc/issue-83512.rs | 10 ++++++++++ src/test/ui/rustdoc/issue-83512.stderr | 8 ++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/rustdoc/issue-83512.rs create mode 100644 src/test/ui/rustdoc/issue-83512.stderr diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index eca84c791fb3f..e85392cf0bda5 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -525,8 +525,11 @@ impl CheckAttrVisitor<'tcx> { self.doc_attr_str_error(meta, "keyword"); return false; } - match self.tcx.hir().expect_item(hir_id).kind { - ItemKind::Mod(ref module) => { + match self.tcx.hir().find(hir_id).and_then(|node| match node { + hir::Node::Item(item) => Some(&item.kind), + _ => None, + }) { + Some(ItemKind::Mod(ref module)) => { if !module.item_ids.is_empty() { self.tcx .sess diff --git a/src/test/ui/rustdoc/issue-83512.rs b/src/test/ui/rustdoc/issue-83512.rs new file mode 100644 index 0000000000000..378f685ed30aa --- /dev/null +++ b/src/test/ui/rustdoc/issue-83512.rs @@ -0,0 +1,10 @@ +// Regression test for the ICE described in #83512. + +#![feature(doc_keyword)] +#![crate_type="lib"] + +trait Foo { + #[doc(keyword = "match")] + //~^ ERROR: `#[doc(keyword = "...")]` can only be used on modules + fn quux() {} +} diff --git a/src/test/ui/rustdoc/issue-83512.stderr b/src/test/ui/rustdoc/issue-83512.stderr new file mode 100644 index 0000000000000..da7e480c63e37 --- /dev/null +++ b/src/test/ui/rustdoc/issue-83512.stderr @@ -0,0 +1,8 @@ +error: `#[doc(keyword = "...")]` can only be used on modules + --> $DIR/issue-83512.rs:7:11 + | +LL | #[doc(keyword = "match")] + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + From e9e844f44cf21bfa9ff8931b9256da57a2dec79f Mon Sep 17 00:00:00 2001 From: Fabian Wolff Date: Thu, 17 Jun 2021 17:28:55 +0200 Subject: [PATCH 09/10] Move regression test for #83512 into doc_keyword.rs --- src/test/ui/rustdoc/doc_keyword.rs | 8 ++++++++ src/test/ui/rustdoc/doc_keyword.stderr | 8 +++++++- src/test/ui/rustdoc/issue-83512.rs | 10 ---------- src/test/ui/rustdoc/issue-83512.stderr | 8 -------- 4 files changed, 15 insertions(+), 19 deletions(-) delete mode 100644 src/test/ui/rustdoc/issue-83512.rs delete mode 100644 src/test/ui/rustdoc/issue-83512.stderr diff --git a/src/test/ui/rustdoc/doc_keyword.rs b/src/test/ui/rustdoc/doc_keyword.rs index 4c72e7e96842c..4518f77ef933d 100644 --- a/src/test/ui/rustdoc/doc_keyword.rs +++ b/src/test/ui/rustdoc/doc_keyword.rs @@ -10,3 +10,11 @@ mod foo { #[doc(keyword = "hall")] //~ ERROR fn foo() {} + + +// Regression test for the ICE described in #83512. +trait Foo { + #[doc(keyword = "match")] + //~^ ERROR: `#[doc(keyword = "...")]` can only be used on modules + fn quux() {} +} diff --git a/src/test/ui/rustdoc/doc_keyword.stderr b/src/test/ui/rustdoc/doc_keyword.stderr index 0679bb8c5a7a6..6ba7034d54122 100644 --- a/src/test/ui/rustdoc/doc_keyword.stderr +++ b/src/test/ui/rustdoc/doc_keyword.stderr @@ -10,11 +10,17 @@ error: `#[doc(keyword = "...")]` can only be used on modules LL | #[doc(keyword = "hall")] | ^^^^^^^^^^^^^^^^ +error: `#[doc(keyword = "...")]` can only be used on modules + --> $DIR/doc_keyword.rs:17:11 + | +LL | #[doc(keyword = "match")] + | ^^^^^^^^^^^^^^^^^ + error: `#![doc(keyword = "...")]` isn't allowed as a crate-level attribute --> $DIR/doc_keyword.rs:4:8 | LL | #![doc(keyword = "hello")] | ^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors diff --git a/src/test/ui/rustdoc/issue-83512.rs b/src/test/ui/rustdoc/issue-83512.rs deleted file mode 100644 index 378f685ed30aa..0000000000000 --- a/src/test/ui/rustdoc/issue-83512.rs +++ /dev/null @@ -1,10 +0,0 @@ -// Regression test for the ICE described in #83512. - -#![feature(doc_keyword)] -#![crate_type="lib"] - -trait Foo { - #[doc(keyword = "match")] - //~^ ERROR: `#[doc(keyword = "...")]` can only be used on modules - fn quux() {} -} diff --git a/src/test/ui/rustdoc/issue-83512.stderr b/src/test/ui/rustdoc/issue-83512.stderr deleted file mode 100644 index da7e480c63e37..0000000000000 --- a/src/test/ui/rustdoc/issue-83512.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: `#[doc(keyword = "...")]` can only be used on modules - --> $DIR/issue-83512.rs:7:11 - | -LL | #[doc(keyword = "match")] - | ^^^^^^^^^^^^^^^^^ - -error: aborting due to previous error - From 3fbac90c4d3b8db48d1f4e5634135b0d22723f16 Mon Sep 17 00:00:00 2001 From: Felix S Klock II Date: Thu, 17 Jun 2021 12:45:50 -0400 Subject: [PATCH 10/10] Update RELEASES.md --- RELEASES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASES.md b/RELEASES.md index 9001f9c4b00f0..4b753a2b32fff 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -113,6 +113,7 @@ Compatibility Notes In particular, this was known to be a problem in the `lexical-core` crate, but they have published fixes for semantic versions 0.4 through 0.7. To update this dependency alone, use `cargo update -p lexical-core`. +- Incremental compilation remains off by default, unless one uses the `RUSTC_FORCE_INCREMENTAL=1` environment variable added in 1.52.1. Internal Only -------------