Auto merge of #154815 - JonathanBrouwer:rollup-sdqRx2J, r=JonathanBrouwer

Rollup of 8 pull requests

Successful merges:

 - rust-lang/rust#149868 (rustc: Stop passing `--allow-undefined` on wasm targets)
 - rust-lang/rust#153555 (Clarified docs in std::sync::RwLock + added test to ensure that max reader count is respected)
 - rust-lang/rust#152851 (Fix SGX delayed host lookup via ToSocketAddr)
 - rust-lang/rust#154051 (use libm for acosh and asinh)
 - rust-lang/rust#154581 (More informative `Debug for vec::ExtractIf`)
 - rust-lang/rust#154461 (Edit the docs new_in() and with_capacity_in())
 - rust-lang/rust#154526 (Panic/return false on overflow in no_threads read/try_read impl)
 - rust-lang/rust#154798 (rustdoc-search: match path components on words)
This commit is contained in:
bors
2026-04-04 17:46:11 +00:00
34 changed files with 444 additions and 138 deletions
@@ -28,16 +28,6 @@ macro_rules! args {
// stack overflow will be guaranteed to trap as it underflows instead of
// corrupting static data.
concat!($prefix, "--stack-first"),
// FIXME we probably shouldn't pass this but instead pass an explicit list
// of symbols we'll allow to be undefined. We don't currently have a
// mechanism of knowing, however, which symbols are intended to be imported
// from the environment and which are intended to be imported from other
// objects linked elsewhere. This is a coarse approximation but is sure to
// hide some bugs and frustrate someone at some point, so we should ideally
// work towards a world where we can explicitly list symbols that are
// supposed to be imported and have all other symbols generate errors if
// they remain undefined.
concat!($prefix, "--allow-undefined"),
// LLD only implements C++-like demangling, which doesn't match our own
// mangling scheme. Tell LLD to not demangle anything and leave it up to
// us to demangle these symbols later. Currently rustc does not perform
+9
View File
@@ -695,6 +695,15 @@ pub fn try_new_zeroed_in(alloc: A) -> Result<Box<mem::MaybeUninit<T>, A>, AllocE
/// does the same as <code>[Box::into_pin]\([Box::new_in]\(x, alloc))</code>. Consider using
/// [`into_pin`](Box::into_pin) if you already have a `Box<T, A>`, or if you want to
/// construct a (pinned) `Box` in a different way than with [`Box::new_in`].
///
/// # Examples
///
/// ```
/// #![feature(allocator_api)]
/// use std::alloc::System;
///
/// let x = Box::pin_in(1, System);
/// ```
#[cfg(not(no_global_oom_handling))]
#[unstable(feature = "allocator_api", issue = "32838")]
#[must_use]
@@ -549,8 +549,8 @@ impl<T, A: Allocator> BinaryHeap<T, A> {
///
/// use std::alloc::System;
/// use std::collections::BinaryHeap;
/// let mut heap = BinaryHeap::new_in(System);
/// heap.push(4);
///
/// let heap : BinaryHeap<i32, System> = BinaryHeap::new_in(System);
/// ```
#[unstable(feature = "allocator_api", issue = "32838")]
#[must_use]
@@ -573,8 +573,8 @@ pub const fn new_in(alloc: A) -> BinaryHeap<T, A> {
///
/// use std::alloc::System;
/// use std::collections::BinaryHeap;
/// let mut heap = BinaryHeap::with_capacity_in(10, System);
/// heap.push(4);
///
/// let heap: BinaryHeap<i32, System> = BinaryHeap::with_capacity_in(10, System);
/// ```
#[unstable(feature = "allocator_api", issue = "32838")]
#[must_use]
+2 -4
View File
@@ -684,13 +684,11 @@ pub fn clear(&mut self) {
/// ```
/// # #![feature(allocator_api)]
/// # #![feature(btreemap_alloc)]
///
/// use std::collections::BTreeMap;
/// use std::alloc::Global;
///
/// let mut map = BTreeMap::new_in(Global);
///
/// // entries can now be inserted into the empty map
/// map.insert(1, "a");
/// let map: BTreeMap<i32, i32> = BTreeMap::new_in(Global);
/// ```
#[unstable(feature = "btreemap_alloc", issue = "32838")]
#[must_use]
+2 -1
View File
@@ -355,10 +355,11 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
/// # #![allow(unused_mut)]
/// # #![feature(allocator_api)]
/// # #![feature(btreemap_alloc)]
///
/// use std::collections::BTreeSet;
/// use std::alloc::Global;
///
/// let mut set: BTreeSet<i32> = BTreeSet::new_in(Global);
/// let set: BTreeSet<i32> = BTreeSet::new_in(Global);
/// ```
#[unstable(feature = "btreemap_alloc", issue = "32838")]
#[must_use]
+1 -1
View File
@@ -509,7 +509,7 @@ impl<T, A: Allocator> LinkedList<T, A> {
/// use std::alloc::System;
/// use std::collections::LinkedList;
///
/// let list: LinkedList<u32, _> = LinkedList::new_in(System);
/// let list: LinkedList<i32, System> = LinkedList::new_in(System);
/// ```
#[inline]
#[unstable(feature = "allocator_api", issue = "32838")]
+11 -5
View File
@@ -790,7 +790,7 @@ pub const fn new() -> VecDeque<T> {
/// ```
/// use std::collections::VecDeque;
///
/// let deque: VecDeque<u32> = VecDeque::with_capacity(10);
/// let deque: VecDeque<i32> = VecDeque::with_capacity(10);
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
@@ -830,9 +830,12 @@ impl<T, A: Allocator> VecDeque<T, A> {
/// # Examples
///
/// ```
/// use std::collections::VecDeque;
/// # #![feature(allocator_api)]
///
/// let deque: VecDeque<u32> = VecDeque::new();
/// use std::collections::VecDeque;
/// use std::alloc::Global;
///
/// let deque: VecDeque<i32> = VecDeque::new_in(Global);
/// ```
#[inline]
#[unstable(feature = "allocator_api", issue = "32838")]
@@ -845,9 +848,12 @@ pub const fn new_in(alloc: A) -> VecDeque<T, A> {
/// # Examples
///
/// ```
/// use std::collections::VecDeque;
/// # #![feature(allocator_api)]
///
/// let deque: VecDeque<u32> = VecDeque::with_capacity(10);
/// use std::collections::VecDeque;
/// use std::alloc::Global;
///
/// let deque: VecDeque<i32> = VecDeque::with_capacity_in(10, Global);
/// ```
#[unstable(feature = "allocator_api", issue = "32838")]
pub fn with_capacity_in(capacity: usize, alloc: A) -> VecDeque<T, A> {
+1
View File
@@ -737,6 +737,7 @@ impl<T, A: Allocator> Rc<T, A> {
///
/// ```
/// #![feature(allocator_api)]
///
/// use std::rc::Rc;
/// use std::alloc::System;
///
+20 -15
View File
@@ -130,20 +130,25 @@ impl<T, F, A> fmt::Debug for ExtractIf<'_, T, F, A>
A: Allocator,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let peek = if self.idx < self.end {
// This has to use pointer arithmetic as `self.vec[self.idx]` or
// `self.vec.get_unchecked(self.idx)` wouldn't work since we
// temporarily set the length of `self.vec` to zero.
//
// SAFETY:
// Since `self.idx` is smaller than `self.end` and `self.end` is
// smaller than `self.old_len`, `idx` is valid for indexing the
// buffer. Also, per the invariant of `self.idx`, this element
// has not been inspected/moved out yet.
Some(unsafe { &*self.vec.as_ptr().add(self.idx) })
} else {
None
};
f.debug_struct("ExtractIf").field("peek", &peek).finish_non_exhaustive()
// We have to use pointer arithmetics here,
// because the length of `self.vec` is temporarily set to 0.
let start = self.vec.as_ptr();
// SAFETY: we always keep first `self.idx - self.del` elements valid.
let retained = unsafe { slice::from_raw_parts(start, self.idx - self.del) };
// SAFETY: we have not yet touched elements starting at `self.idx`.
let valid_tail =
unsafe { slice::from_raw_parts(start.add(self.idx), self.old_len - self.idx) };
// SAFETY: `end - idx <= old_len - idx`, because `end <= old_len`. Also `idx <= end` by invariant.
let (remainder, skipped_tail) =
unsafe { valid_tail.split_at_unchecked(self.end - self.idx) };
f.debug_struct("ExtractIf")
.field("retained", &retained)
.field("remainder", &remainder)
.field("skipped_tail", &skipped_tail)
.finish_non_exhaustive()
}
}
+1 -2
View File
@@ -1062,8 +1062,7 @@ impl<T, A: Allocator> Vec<T, A> {
///
/// use std::alloc::System;
///
/// # #[allow(unused_mut)]
/// let mut vec: Vec<i32, _> = Vec::new_in(System);
/// let vec: Vec<i32, System> = Vec::new_in(System);
/// ```
#[inline]
#[unstable(feature = "allocator_api", issue = "32838")]
+11 -7
View File
@@ -1651,13 +1651,17 @@ fn extract_if_unconsumed() {
#[test]
fn extract_if_debug() {
let mut vec = vec![1, 2];
let mut drain = vec.extract_if(.., |&mut x| x % 2 != 0);
assert!(format!("{drain:?}").contains("Some(1)"));
drain.next();
assert!(format!("{drain:?}").contains("Some(2)"));
drain.next();
assert!(format!("{drain:?}").contains("None"));
let mut vec = vec![1, 2, 3, 4, 5, 6, 7, 8];
let mut drain = vec.extract_if(1..5, |&mut x| x % 2 != 0);
assert_eq!(
format!("{drain:?}"),
"ExtractIf { retained: [1], remainder: [2, 3, 4, 5], skipped_tail: [6, 7, 8], .. }"
);
drain.next().unwrap();
assert_eq!(
format!("{drain:?}"),
"ExtractIf { retained: [1, 2], remainder: [4, 5], skipped_tail: [6, 7, 8], .. }"
);
}
#[test]
+28 -2
View File
@@ -2,6 +2,9 @@
use std::num::FpCategory as Fp;
use std::ops::{Add, Div, Mul, Rem, Sub};
/// i586 has issues with floating point precision.
const I586: bool = cfg!(target_arch = "x86") && cfg!(not(target_feature = "sse2"));
pub(crate) trait TestableFloat: Sized {
const BITS: u32;
/// Unsigned int with the same size, for converting to/from bits.
@@ -59,6 +62,7 @@ pub(crate) trait TestableFloat: Sized {
const NEG_MUL_ADD_RESULT: Self;
/// Reciprocal of the maximum val
const MAX_RECIP: Self;
const ASINH_ACOSH_MAX: Self;
}
impl TestableFloat for f16 {
@@ -103,6 +107,7 @@ impl TestableFloat for f16 {
const MUL_ADD_RESULT: Self = 62.031;
const NEG_MUL_ADD_RESULT: Self = 48.625;
const MAX_RECIP: Self = 1.526624e-5;
const ASINH_ACOSH_MAX: Self = 11.781;
}
impl TestableFloat for f32 {
@@ -120,8 +125,20 @@ impl TestableFloat for f32 {
const LOG_APPROX: Self = if cfg!(miri) { 1e-3 } else { Self::APPROX };
const LOG2_APPROX: Self = if cfg!(miri) { 1e-3 } else { Self::APPROX };
const LOG10_APPROX: Self = if cfg!(miri) { 1e-3 } else { Self::APPROX };
const ASINH_APPROX: Self = if cfg!(miri) { 1e-3 } else { Self::APPROX };
const ACOSH_APPROX: Self = if cfg!(miri) { 1e-3 } else { Self::APPROX };
const ASINH_APPROX: Self = if cfg!(miri) {
1e-3
} else if I586 {
1e-5
} else {
Self::APPROX
};
const ACOSH_APPROX: Self = if cfg!(miri) {
1e-3
} else if I586 {
1e-5
} else {
Self::APPROX
};
const ATANH_APPROX: Self = if cfg!(miri) { 1e-3 } else { Self::APPROX };
const GAMMA_APPROX: Self = if cfg!(miri) { 1e-3 } else { Self::APPROX };
const GAMMA_APPROX_LOOSE: Self = if cfg!(miri) { 1e-2 } else { 1e-4 };
@@ -149,6 +166,7 @@ impl TestableFloat for f32 {
const MUL_ADD_RESULT: Self = 62.05;
const NEG_MUL_ADD_RESULT: Self = 48.65;
const MAX_RECIP: Self = 2.938736e-39;
const ASINH_ACOSH_MAX: Self = 89.4159851;
}
impl TestableFloat for f64 {
@@ -180,6 +198,7 @@ impl TestableFloat for f64 {
const MUL_ADD_RESULT: Self = 62.050000000000004;
const NEG_MUL_ADD_RESULT: Self = 48.650000000000006;
const MAX_RECIP: Self = 5.562684646268003e-309;
const ASINH_ACOSH_MAX: Self = 710.47586007394398;
}
impl TestableFloat for f128 {
@@ -221,6 +240,7 @@ impl TestableFloat for f128 {
const MUL_ADD_RESULT: Self = 62.0500000000000000000000000000000037;
const NEG_MUL_ADD_RESULT: Self = 48.6500000000000000000000000000000049;
const MAX_RECIP: Self = 8.40525785778023376565669454330438228902076605e-4933;
const ASINH_ACOSH_MAX: Self = 11357.216553474703894801348310092223;
}
/// Determine the tolerance for values of the argument type.
@@ -1705,6 +1725,9 @@ fn s_nan() -> Float {
assert_approx_eq!(flt(-200.0).asinh(), -5.991470797049389, Float::ASINH_APPROX);
// issue 153878: large values were rounding to infinity
assert_approx_eq!(Float::MAX.asinh(), Float::ASINH_ACOSH_MAX, Float::ASINH_APPROX);
#[allow(overflowing_literals)]
if Float::MAX > flt(66000.0) {
// regression test for the catastrophic cancellation fixed in 72486
@@ -1733,6 +1756,9 @@ fn s_nan() -> Float {
assert_approx_eq!(flt(2.0).acosh(), 1.31695789692481670862504634730796844, Float::ACOSH_APPROX);
assert_approx_eq!(flt(3.0).acosh(), 1.76274717403908605046521864995958461, Float::ACOSH_APPROX);
// issue 153878: large values were rounding to infinity
assert_approx_eq!(Float::MAX.acosh(), Float::ASINH_ACOSH_MAX, Float::ACOSH_APPROX);
#[allow(overflowing_literals)]
if Float::MAX > flt(66000.0) {
// test for low accuracy from issue 104548
+31 -2
View File
@@ -301,8 +301,11 @@ impl<K, V, A: Allocator> HashMap<K, V, RandomState, A> {
/// # Examples
///
/// ```
/// # #![feature(allocator_api)]
/// use std::collections::HashMap;
/// let mut map: HashMap<&str, i32> = HashMap::new();
/// use std::alloc::Global;
///
/// let map: HashMap<i32, i32> = HashMap::new_in(Global);
/// ```
#[inline]
#[must_use]
@@ -321,8 +324,11 @@ pub fn new_in(alloc: A) -> Self {
/// # Examples
///
/// ```
/// # #![feature(allocator_api)]
/// use std::collections::HashMap;
/// let mut map: HashMap<&str, i32> = HashMap::with_capacity(10);
/// use std::alloc::Global;
///
/// let map: HashMap<i32, i32> = HashMap::with_capacity_in(10, Global);
/// ```
#[inline]
#[must_use]
@@ -410,6 +416,18 @@ impl<K, V, S, A: Allocator> HashMap<K, V, S, A> {
///
/// The `hash_builder` passed should implement the [`BuildHasher`] trait for
/// the `HashMap` to be useful, see its documentation for details.
///
/// # Examples
///
/// ```
/// #![feature(allocator_api)]
/// use std::alloc::Global;
/// use std::collections::HashMap;
/// use std::hash::RandomState;
///
/// let s = RandomState::new();
/// let map: HashMap<i32, i32> = HashMap::with_hasher_in(s, Global);
/// ```
#[inline]
#[must_use]
#[unstable(feature = "allocator_api", issue = "32838")]
@@ -432,6 +450,17 @@ pub fn with_hasher_in(hash_builder: S, alloc: A) -> Self {
/// The `hasher` passed should implement the [`BuildHasher`] trait for
/// the `HashMap` to be useful, see its documentation for details.
///
/// # Examples
///
/// ```
/// #![feature(allocator_api)]
/// use std::alloc::Global;
/// use std::collections::HashMap;
/// use std::hash::RandomState;
///
/// let s = RandomState::new();
/// let map: HashMap<i32, i32> = HashMap::with_capacity_and_hasher_in(10, s, Global);
/// ```
#[inline]
#[must_use]
#[unstable(feature = "allocator_api", issue = "32838")]
+37 -2
View File
@@ -176,6 +176,15 @@ impl<T, A: Allocator> HashSet<T, RandomState, A> {
///
/// The hash set is initially created with a capacity of 0, so it will not allocate until it
/// is first inserted into.
/// # Examples
///
/// ```
/// # #![feature(allocator_api)]
/// use std::alloc::Global;
/// use std::collections::HashSet;
///
/// let set: HashSet<i32> = HashSet::new_in(Global);
/// ```
#[inline]
#[must_use]
#[unstable(feature = "allocator_api", issue = "32838")]
@@ -192,9 +201,11 @@ pub fn new_in(alloc: A) -> HashSet<T, RandomState, A> {
/// # Examples
///
/// ```
/// # #![feature(allocator_api)]
/// use std::collections::HashSet;
/// let set: HashSet<i32> = HashSet::with_capacity(10);
/// assert!(set.capacity() >= 10);
/// use std::alloc::Global;
///
/// let set: HashSet<i32> = HashSet::with_capacity_in(10, Global);
/// ```
#[inline]
#[must_use]
@@ -282,6 +293,18 @@ impl<T, S, A: Allocator> HashSet<T, S, A> {
///
/// The `hash_builder` passed should implement the [`BuildHasher`] trait for
/// the `HashSet` to be useful, see its documentation for details.
///
/// # Examples
///
/// ```
/// # #![feature(allocator_api)]
/// use std::alloc::Global;
/// use std::collections::HashSet;
/// use std::hash::RandomState;
///
/// let s = RandomState::new();
/// let set: HashSet<i32> = HashSet::with_hasher_in(s, Global);
/// ```
#[inline]
#[must_use]
#[unstable(feature = "allocator_api", issue = "32838")]
@@ -303,6 +326,18 @@ pub fn with_hasher_in(hasher: S, alloc: A) -> HashSet<T, S, A> {
///
/// The `hash_builder` passed should implement the [`BuildHasher`] trait for
/// the `HashSet` to be useful, see its documentation for details.
///
/// # Examples
///
/// ```
/// # #![feature(allocator_api)]
/// use std::alloc::Global;
/// use std::collections::HashSet;
/// use std::hash::RandomState;
///
/// let s = RandomState::new();
/// let set: HashSet<i32> = HashSet::with_capacity_and_hasher_in(10, s, Global);
/// ```
#[inline]
#[must_use]
#[unstable(feature = "allocator_api", issue = "32838")]
+3 -16
View File
@@ -189,11 +189,6 @@ fn to_socket_addrs(&self) -> io::Result<option::IntoIter<SocketAddr>> {
}
}
fn lookup_host(host: &str, port: u16) -> io::Result<vec::IntoIter<SocketAddr>> {
let addrs = crate::sys::net::lookup_host(host, port)?;
Ok(Vec::from_iter(addrs).into_iter())
}
#[stable(feature = "rust1", since = "1.0.0")]
impl ToSocketAddrs for (&str, u16) {
type Iter = vec::IntoIter<SocketAddr>;
@@ -207,7 +202,7 @@ fn to_socket_addrs(&self) -> io::Result<vec::IntoIter<SocketAddr>> {
}
// Otherwise, make the system look it up.
lookup_host(host, port)
crate::sys::net::lookup_host(host, port).map(|addrs| Vec::from_iter(addrs).into_iter())
}
}
@@ -229,16 +224,8 @@ fn to_socket_addrs(&self) -> io::Result<vec::IntoIter<SocketAddr>> {
return Ok(vec![addr].into_iter());
}
// Otherwise, split the string by ':' and convert the second part to u16...
let Some((host, port_str)) = self.rsplit_once(':') else {
return Err(io::const_error!(io::ErrorKind::InvalidInput, "invalid socket address"));
};
let Ok(port) = port_str.parse::<u16>() else {
return Err(io::const_error!(io::ErrorKind::InvalidInput, "invalid port value"));
};
// ... and make the system look up the host.
lookup_host(host, port)
// Otherwise, make the system look it up.
crate::sys::net::lookup_host_string(self).map(|addrs| Vec::from_iter(addrs).into_iter())
}
}
+2 -8
View File
@@ -867,9 +867,7 @@ pub fn tanh(self) -> f128 {
#[unstable(feature = "f128", issue = "116909")]
#[must_use = "method returns a new number and does not mutate the original value"]
pub fn asinh(self) -> f128 {
let ax = self.abs();
let ix = 1.0 / ax;
(ax + (ax / (Self::hypot(1.0, ix) + ix))).ln_1p().copysign(self)
cmath::asinhf128(self)
}
/// Inverse hyperbolic cosine function.
@@ -900,11 +898,7 @@ pub fn asinh(self) -> f128 {
#[unstable(feature = "f128", issue = "116909")]
#[must_use = "method returns a new number and does not mutate the original value"]
pub fn acosh(self) -> f128 {
if self < 1.0 {
Self::NAN
} else {
(self + ((self - 1.0).sqrt() * (self + 1.0).sqrt())).ln()
}
cmath::acoshf128(self)
}
/// Inverse hyperbolic tangent function.
+2 -8
View File
@@ -832,9 +832,7 @@ pub fn tanh(self) -> f16 {
#[unstable(feature = "f16", issue = "116909")]
#[must_use = "method returns a new number and does not mutate the original value"]
pub fn asinh(self) -> f16 {
let ax = self.abs();
let ix = 1.0 / ax;
(ax + (ax / (Self::hypot(1.0, ix) + ix))).ln_1p().copysign(self)
cmath::asinhf(self as f32) as f16
}
/// Inverse hyperbolic cosine function.
@@ -865,11 +863,7 @@ pub fn asinh(self) -> f16 {
#[unstable(feature = "f16", issue = "116909")]
#[must_use = "method returns a new number and does not mutate the original value"]
pub fn acosh(self) -> f16 {
if self < 1.0 {
Self::NAN
} else {
(self + ((self - 1.0).sqrt() * (self + 1.0).sqrt())).ln()
}
cmath::acoshf(self as f32) as f16
}
/// Inverse hyperbolic tangent function.
+2 -8
View File
@@ -1091,9 +1091,7 @@ pub fn tanh(self) -> f32 {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn asinh(self) -> f32 {
let ax = self.abs();
let ix = 1.0 / ax;
(ax + (ax / (Self::hypot(1.0, ix) + ix))).ln_1p().copysign(self)
cmath::asinhf(self)
}
/// Inverse hyperbolic cosine function.
@@ -1119,11 +1117,7 @@ pub fn asinh(self) -> f32 {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn acosh(self) -> f32 {
if self < 1.0 {
Self::NAN
} else {
(self + ((self - 1.0).sqrt() * (self + 1.0).sqrt())).ln()
}
cmath::acoshf(self)
}
/// Inverse hyperbolic tangent function.
+2 -8
View File
@@ -1091,9 +1091,7 @@ pub fn tanh(self) -> f64 {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn asinh(self) -> f64 {
let ax = self.abs();
let ix = 1.0 / ax;
(ax + (ax / (Self::hypot(1.0, ix) + ix))).ln_1p().copysign(self)
cmath::asinh(self)
}
/// Inverse hyperbolic cosine function.
@@ -1119,11 +1117,7 @@ pub fn asinh(self) -> f64 {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn acosh(self) -> f64 {
if self < 1.0 {
Self::NAN
} else {
(self + ((self - 1.0).sqrt() * (self + 1.0).sqrt())).ln()
}
cmath::acosh(self)
}
/// Inverse hyperbolic tangent function.
+1 -1
View File
@@ -16,7 +16,7 @@
///
/// In comparison, a [`Mutex`] does not distinguish between readers or writers
/// that acquire the lock, therefore blocking any threads waiting for the lock to
/// become available. An `RwLock` will allow any number of readers to acquire the
/// become available. An `RwLock` will allow multiple readers to acquire the
/// lock as long as a writer is not holding the lock.
///
/// The priority policy of the lock is dependent on the underlying operating
+16
View File
@@ -4,7 +4,9 @@
// or by `compiler-builtins` on unsupported platforms.
unsafe extern "C" {
pub safe fn acos(n: f64) -> f64;
pub safe fn acosh(n: f64) -> f64;
pub safe fn asin(n: f64) -> f64;
pub safe fn asinh(n: f64) -> f64;
pub safe fn atan(n: f64) -> f64;
pub safe fn atan2(a: f64, b: f64) -> f64;
pub safe fn cosh(n: f64) -> f64;
@@ -30,7 +32,9 @@
pub safe fn erfcf(n: f32) -> f32;
pub safe fn acosf128(n: f128) -> f128;
pub safe fn acoshf128(n: f128) -> f128;
pub safe fn asinf128(n: f128) -> f128;
pub safe fn asinhf128(n: f128) -> f128;
pub safe fn atanf128(n: f128) -> f128;
pub safe fn atan2f128(a: f128, b: f128) -> f128;
pub safe fn cbrtf128(n: f128) -> f128;
@@ -57,6 +61,16 @@ pub fn acosf(n: f32) -> f32 {
f64::acos(n as f64) as f32
}
#[inline]
pub fn acoshf(n: f32) -> f32 {
f64::acosh(n as f64) as f32
}
#[inline]
pub fn asinhf(n: f32) -> f32 {
f64::asinh(n as f64) as f32
}
#[inline]
pub fn asinf(n: f32) -> f32 {
f64::asin(n as f64) as f32
@@ -95,7 +109,9 @@ pub fn tanhf(n: f32) -> f32 {
_ => {
unsafe extern "C" {
pub safe fn acosf(n: f32) -> f32;
pub safe fn acoshf(n: f32) -> f32;
pub safe fn asinf(n: f32) -> f32;
pub safe fn asinhf(n: f32) -> f32;
pub safe fn atan2f(a: f32, b: f32) -> f32;
pub safe fn atanf(n: f32) -> f32;
pub safe fn coshf(n: f32) -> f32;
+19
View File
@@ -59,3 +59,22 @@ fn each_addr<A: crate::net::ToSocketAddrs, F, T>(addr: A, mut f: F) -> crate::io
None => Err(Error::NO_ADDRESSES),
}
}
// Default implementation, may be overridden by platform-specific implementations.
#[cfg(not(all(target_vendor = "fortanix", target_env = "sgx")))]
pub(crate) fn lookup_host_string(
addr: &str,
) -> crate::io::Result<impl Iterator<Item = crate::net::SocketAddr>> {
use crate::io;
// Split the string by ':' and convert the second part to u16...
let Some((host, port_str)) = addr.rsplit_once(':') else {
return Err(io::const_error!(io::ErrorKind::InvalidInput, "invalid socket address"));
};
let Ok(port) = port_str.parse::<u16>() else {
return Err(io::const_error!(io::ErrorKind::InvalidInput, "invalid port value"));
};
// ... and make the system look up the host.
crate::sys::net::lookup_host(host, port)
}
+19 -5
View File
@@ -506,9 +506,23 @@ fn next(&mut self) -> Option<SocketAddr> {
}
}
pub fn lookup_host(host: &str, port: u16) -> io::Result<LookupHost> {
Err(io::Error::new(
io::ErrorKind::Uncategorized,
NonIpSockAddr { host: format!("{host}:{port}") },
))
pub(crate) fn lookup_host_string(addr: impl Into<String>) -> io::Result<LookupHost> {
Err(io::Error::new(io::ErrorKind::Uncategorized, NonIpSockAddr { host: addr.into() }))
}
pub fn lookup_host(host: &str, port: u16) -> io::Result<LookupHost> {
lookup_host_string(format!("{host}:{port}"))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn unparseable_sockaddr() {
let addr = "local";
let error = addr.to_socket_addrs().unwrap_err();
let non_ip_addr = error.downcast::<NonIpSockAddr>().unwrap();
assert_eq!(addr, non_ip_addr.host);
}
}
+10 -4
View File
@@ -18,7 +18,7 @@ pub const fn new() -> RwLock {
pub fn read(&self) {
let m = self.mode.get();
if m >= 0 {
self.mode.set(m + 1);
self.mode.set(m.checked_add(1).expect("rwlock overflowed read locks"));
} else {
rtabort!("rwlock locked for writing");
}
@@ -28,6 +28,9 @@ pub fn read(&self) {
pub fn try_read(&self) -> bool {
let m = self.mode.get();
if m >= 0 {
if m == isize::MAX {
return false;
}
self.mode.set(m + 1);
true
} else {
@@ -56,16 +59,19 @@ pub fn try_write(&self) -> bool {
#[inline]
pub unsafe fn read_unlock(&self) {
self.mode.set(self.mode.get() - 1);
assert!(
self.mode.replace(self.mode.get() - 1) > 0,
"rwlock has not been locked for reading"
);
}
#[inline]
pub unsafe fn write_unlock(&self) {
assert_eq!(self.mode.replace(0), -1);
assert_eq!(self.mode.replace(0), -1, "rwlock has not been locked for writing");
}
#[inline]
pub unsafe fn downgrade(&self) {
assert_eq!(self.mode.replace(1), -1);
assert_eq!(self.mode.replace(1), -1, "rwlock has not been locked for writing");
}
}
+64 -1
View File
@@ -7,7 +7,7 @@
Arc, MappedRwLockReadGuard, MappedRwLockWriteGuard, RwLock, RwLockReadGuard, RwLockWriteGuard,
TryLockError,
};
use std::{hint, mem, thread};
use std::{hint, mem, thread, u32};
use rand::Rng;
@@ -883,3 +883,66 @@ fn test_rwlock_with_mut() {
assert_eq!(*rwlock.read(), 5);
assert_eq!(result, 10);
}
// To note: there are (currently) four different implementations of Rwlock:
// - On Windows (but not Win 7), Linux, Android, FreeBSD, OpenBSD, DragonFly,
// Fuchsia, WASM, Hermit, and Motor OSs, it relies on rwlock/futex.rs, which has
// a max reader of 1 << 30 - 2 (or 1073741822). A "too many active reader" error
// is displayed after it exceeds the max number of readers.
// - On Unix, Win 7, Fortranix (target env of sgx), Xous, and TeeOS, it leans
// on rwlock/queue.rs, which uses a linked list under the hood stored on the stack
// to hold a queue of waiters. Assuming no stack overflow, the max number of readers
// that can be queued up at one time is limited to usize::MAX - (1 << 4) as the first
// four bits are reserved for LOCKED, QUEUED, QUEUE_LOCKED, and DOWNGRADED flags. Any
// pending readers after that max count, parks the thread and tries to acquire a read lock
// again when the thread wakes up.
// - On SolidASP3, it leans on rwlock/solid.rs, which utilizes rwl_loc_rdl, so the max
// number of readers depends on the internal implementation of rwl_loc_rdl.
// - Every other platforms utilizes rwlock/no_threads.rs, which has a max reader of
// isize::MAX. An arithmetic overflow error occurs if it exceeds the max reader count.
#[test]
fn test_rwlock_max_readers() {
let mut read_lock_ctr: u32 = 0;
let rwlock: RwLock<i32> = RwLock::new(0);
const MAX_READERS: u32 = cfg_select! {
miri => 100,
any(
all(target_os = "windows", not(target_vendor = "win7")),
target_os = "linux",
target_os = "android",
target_os = "freebsd",
target_os = "openbsd",
target_os = "dragonfly",
target_os = "fuchsia",
all(target_family = "wasm", target_feature = "atomics"),
target_os = "hermit",
target_os = "motor",
) => {
(1 << 30) - 2
},
any(
target_family = "unix",
all(target_os = "windows", target_vendor = "win7"),
all(target_vendor = "fortanix", target_env = "sgx"),
target_os = "xous",
target_os = "teeos",
) => {
u32::MAX
},
target_os = "solid_asp3" => {
(1 << 30)
},
_ => {
u32::MAX
}
};
while read_lock_ctr < MAX_READERS {
let lock = rwlock.read();
mem::forget(lock);
read_lock_ctr += 1;
}
assert_eq!(read_lock_ctr, MAX_READERS);
}
+34 -19
View File
@@ -2799,6 +2799,8 @@ class DocSearch {
result_list.sort((aaa, bbb) => {
const aai = aaa.item;
const bbi = bbb.item;
const ap = aai.modulePath !== undefined ? aai.modulePath : "";
const bp = bbi.modulePath !== undefined ? bbi.modulePath : "";
/** @type {number} */
let a;
/** @type {number} */
@@ -2829,14 +2831,25 @@ class DocSearch {
if (a !== b) {
return a - b;
}
}
// Sort by distance in the path part, if specified
// (less changes required to match means higher rankings)
a = Number(aaa.path_dist);
b = Number(bbb.path_dist);
if (a !== b) {
return a - b;
if (parsedQuery.elems[0] &&
parsedQuery.elems[0].pathWithoutLast.length !== 0
) {
// Sort by distance in the path part, if specified
// (less changes required to match means higher rankings)
a = Number(aaa.path_dist);
b = Number(bbb.path_dist);
if (a !== b) {
return a - b;
}
// sort by path (longer goes later)
a = ap.length + (aai.parent ? aai.parent.name.length + 2 : 0);
b = bp.length + (bbi.parent ? bbi.parent.name.length + 2 : 0);
if (a !== b) {
return a - b;
}
}
}
// (later literal occurrence, if any, goes later)
@@ -2890,8 +2903,8 @@ class DocSearch {
}
// sort by item name (lexicographically larger goes later)
let aw = aai.normalizedName;
let bw = bbi.normalizedName;
const aw = aai.normalizedName;
const bw = bbi.normalizedName;
if (aw !== bw) {
return (aw > bw ? +1 : -1);
}
@@ -2914,12 +2927,8 @@ class DocSearch {
}
// sort by path (lexicographically larger goes later)
const ap = aai.modulePath;
const bp = bbi.modulePath;
aw = ap === undefined ? "" : ap;
bw = bp === undefined ? "" : bp;
if (aw !== bw) {
return (aw > bw ? +1 : -1);
if (ap !== bp) {
return (ap > bp ? +1 : -1);
}
// que sera, sera
@@ -3848,13 +3857,19 @@ class DocSearch {
let dist_total = 0;
for (let x = 0; x < clength; ++x) {
const [p, c] = [path[i + x], contains[x]];
const indexOf = p.indexOf(c);
if (parsedQuery.literalSearch && p !== c) {
continue pathiter;
} else if (Math.floor((p.length - c.length) / 3) <= maxPathEditDistance &&
p.indexOf(c) !== -1
) {
} else if (indexOf !== -1) {
// discount distance on substring match
dist_total += Math.floor((p.length - c.length) / 3);
// if component is surrounded by underscores or edges,
// count the distance as zero
if (
(indexOf !== 0 && p[indexOf - 1] !== "_") ||
(indexOf + c.length !== p.length && p[indexOf + c.length] !== "_")
) {
dist_total += Math.floor((p.length - c.length) / 3);
}
} else {
const dist = editDistance(p, c, maxPathEditDistance);
if (dist > maxPathEditDistance) {
+8
View File
@@ -30,6 +30,8 @@ fn emulate_foreign_item_inner(
| "acosf"
| "asinf"
| "atanf"
| "acoshf"
| "asinhf"
| "log1pf"
| "expm1f"
| "tgammaf"
@@ -52,6 +54,8 @@ fn emulate_foreign_item_inner(
"acosf" => f_host.acos(),
"asinf" => f_host.asin(),
"atanf" => f_host.atan(),
"acoshf" => f_host.acosh(),
"asinhf" => f_host.asinh(),
"log1pf" => f_host.ln_1p(),
"expm1f" => f_host.exp_m1(),
"tgammaf" => f_host.gamma(),
@@ -113,6 +117,8 @@ fn emulate_foreign_item_inner(
| "acos"
| "asin"
| "atan"
| "acosh"
| "asinh"
| "log1p"
| "expm1"
| "tgamma"
@@ -135,6 +141,8 @@ fn emulate_foreign_item_inner(
"acos" => f_host.acos(),
"asin" => f_host.asin(),
"atan" => f_host.atan(),
"acosh" => f_host.acosh(),
"asinh" => f_host.asinh(),
"log1p" => f_host.ln_1p(),
"expm1" => f_host.exp_m1(),
"tgamma" => f_host.gamma(),
+2 -2
View File
@@ -1611,9 +1611,9 @@ fn test_operations_f32(a: f32, b: f32) {
check_nondet(|| 1.0f32.sinh());
check_nondet(|| 1.0f32.cosh());
check_nondet(|| 1.0f32.tanh());
check_nondet(|| 1.0f32.asinh());
check_nondet(|| 2.0f32.acosh());
}
check_nondet(|| 1.0f32.asinh());
check_nondet(|| 2.0f32.acosh());
check_nondet(|| 0.5f32.atanh());
check_nondet(|| 5.0f32.gamma());
check_nondet(|| 5.0f32.ln_gamma());
@@ -1,5 +1,6 @@
#![crate_type = "cdylib"]
#[link(wasm_import_module = "the-world")]
extern "C" {
fn observe(ptr: *const u8, len: usize);
}
@@ -7,6 +8,7 @@
macro_rules! s {
( $( $f:ident -> $t:ty );* $(;)* ) => {
$(
#[link(wasm_import_module = "the-world")]
extern "C" {
fn $f() -> $t;
}
@@ -17,6 +17,11 @@ unsafe fn __rust_alloc(_size: usize, _align: usize) -> *mut u8 {
fn __rust_alloc_error_handler(size: usize, align: usize) -> !;
}
#[rustc_std_internal_symbol]
pub unsafe fn __rdl_alloc_error_handler(_size: usize, _align: usize) -> ! {
loop {}
}
#[used]
static mut BUF: [u8; 1024] = [0; 1024];
+12 -3
View File
@@ -10,15 +10,24 @@ const EXPECTED = [
query: 'vec::iter',
others: [
// std::net::ToSocketAttrs::iter should not show up here
{ 'path': 'std::collections::vec_deque', 'name': 'Iter' },
{ 'path': 'std::collections::VecDeque', 'name': 'iter' },
{ 'path': 'std::collections::vec_deque', 'name': 'IterMut' },
{ 'path': 'std::collections::VecDeque', 'name': 'iter_mut' },
{ 'path': 'std::vec::Vec', 'name': 'from_iter' },
{ 'path': 'std::vec', 'name': 'IntoIter' },
{ 'path': 'std::vec::Vec', 'name': 'from_iter' },
{ 'path': 'std::vec::Vec', 'name': 'into_iter' },
{ 'path': 'std::vec::ExtractIf', 'name': 'into_iter' },
{ 'path': 'std::vec::Drain', 'name': 'into_iter' },
{ 'path': 'std::vec::IntoIter', 'name': 'into_iter' },
{ 'path': 'std::vec::Splice', 'name': 'into_iter' },
{ 'path': 'std::vec::IntoIter', 'name': 'into_iter' },
{ 'path': 'std::vec::ExtractIf', 'name': 'into_iter' },
{ 'path': 'std::collections::vec_deque', 'name': 'IntoIter' },
{ 'path': 'std::collections::vec_deque::Iter', 'name': 'into_iter' },
{ 'path': 'std::collections::vec_deque::Drain', 'name': 'into_iter' },
{ 'path': 'std::collections::vec_deque::Splice', 'name': 'into_iter' },
{ 'path': 'std::collections::vec_deque::IterMut', 'name': 'into_iter' },
{ 'path': 'std::collections::vec_deque::IntoIter', 'name': 'into_iter' },
{ 'path': 'std::collections::vec_deque::ExtractIf', 'name': 'into_iter' },
{ 'path': 'std::collections::VecDeque', 'name': 'from_iter' },
{ 'path': 'std::collections::VecDeque', 'name': 'into_iter' },
],
+75
View File
@@ -0,0 +1,75 @@
// exact-check
// ignore-tidy-linelength
const EXPECTED = [
// should match (substring)
{
'query': 'struct:now::Country',
'others': [
{ 'path': 'x::now_is_the_time_for_all_good_men_to_come_to_the_aid_of_their', 'name': 'Country' },
],
},
{
'query': 'struct:is::Country',
'others': [
{ 'path': 'x::now_is_the_time_for_all_good_men_to_come_to_the_aid_of_their', 'name': 'Country' },
],
},
{
'query': 'struct:is_the::Country',
'others': [
{ 'path': 'x::now_is_the_time_for_all_good_men_to_come_to_the_aid_of_their', 'name': 'Country' },
],
},
{
'query': 'struct:the::Country',
'others': [
{ 'path': 'x::now_is_the_time_for_all_good_men_to_come_to_the_aid_of_their', 'name': 'Country' },
],
},
{
'query': 'struct:their::Country',
'others': [
{ 'path': 'x::now_is_the_time_for_all_good_men_to_come_to_the_aid_of_their', 'name': 'Country' },
],
},
// should not match
{
'query': 'struct:ood::Country',
'others': [],
},
{
'query': 'struct:goo::Country',
'others': [],
},
{
'query': 'struct:he::Country',
'others': [],
},
{
'query': 'struct:heir::Country',
'others': [],
},
{
'query': 'struct:hei::Country',
'others': [],
},
{
'query': 'struct:no::Country',
'others': [],
},
// should match (edit distance)
{
'query': 'struct:nowisthetimeforallgoodmentocometotheaidoftheir::Country',
'others': [
{ 'path': 'x::nowisthetimeforallgoodmentocometotheaidoftheir', 'name': 'Country' },
{ 'path': 'x::now_is_the_time_for_all_good_men_to_come_to_the_aid_of_their', 'name': 'Country' },
],
},
{
'query': 'struct:now_is_the_time_for_all_good_men_to_come_to_the_aid_of_their::Country',
'others': [
{ 'path': 'x::now_is_the_time_for_all_good_men_to_come_to_the_aid_of_their', 'name': 'Country' },
{ 'path': 'x::nowisthetimeforallgoodmentocometotheaidoftheir', 'name': 'Country' },
],
},
];
+7
View File
@@ -0,0 +1,7 @@
#![crate_name = "x"]
pub mod now_is_the_time_for_all_good_men_to_come_to_the_aid_of_their {
pub struct Country;
}
pub mod nowisthetimeforallgoodmentocometotheaidoftheir {
pub struct Country;
}
@@ -1,5 +1,6 @@
//@ run-pass
//@ ignore-windows-gnu: only statics marked with used can be GC-ed on windows-gnu
//@ ignore-wasm: wasm, for better or worse, exports all #[no_mangle]
// Regression test for <https://github.com/rust-lang/rust/issues/139744>.
// Functions in the binary marked with no_mangle should be GC-ed if they