about summary refs log tree commit diff
path: root/library
diff options
context:
space:
mode:
Diffstat (limited to 'library')
-rw-r--r--library/alloc/benches/lib.rs3
-rw-r--r--library/alloc/tests/string.rs3
-rw-r--r--library/alloc/tests/vec.rs3
-rw-r--r--library/alloc/tests/vec_deque.rs3
m---------library/backtrace0
-rw-r--r--library/core/src/mem/mod.rs2
-rw-r--r--library/core/src/primitive_docs.rs92
-rw-r--r--library/core/tests/num/int_log.rs18
-rw-r--r--library/profiler_builtins/build.rs60
-rw-r--r--library/std/src/io/buffered/bufreader.rs2
-rw-r--r--library/std/src/sys/pal/wasi/thread.rs61
11 files changed, 119 insertions, 128 deletions
diff --git a/library/alloc/benches/lib.rs b/library/alloc/benches/lib.rs
index 0561f49c967..ae9608ec7bd 100644
--- a/library/alloc/benches/lib.rs
+++ b/library/alloc/benches/lib.rs
@@ -1,6 +1,3 @@
-// Disabling on android for the time being
-// See https://github.com/rust-lang/rust/issues/73535#event-3477699747
-#![cfg(not(target_os = "android"))]
 // Disabling in Miri as these would take too long.
 #![cfg(not(miri))]
 #![feature(btree_extract_if)]
diff --git a/library/alloc/tests/string.rs b/library/alloc/tests/string.rs
index c5bc4185a36..dc03c4860e8 100644
--- a/library/alloc/tests/string.rs
+++ b/library/alloc/tests/string.rs
@@ -723,7 +723,6 @@ fn test_reserve_exact() {
 
 #[test]
 #[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
-#[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc
 fn test_try_with_capacity() {
     let string = String::try_with_capacity(1000).unwrap();
     assert_eq!(0, string.len());
@@ -734,7 +733,6 @@ fn test_try_with_capacity() {
 
 #[test]
 #[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
-#[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc
 fn test_try_reserve() {
     // These are the interesting cases:
     // * exactly isize::MAX should never trigger a CapacityOverflow (can be OOM)
@@ -803,7 +801,6 @@ fn test_try_reserve() {
 
 #[test]
 #[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
-#[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc
 fn test_try_reserve_exact() {
     // This is exactly the same as test_try_reserve with the method changed.
     // See that test for comments.
diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs
index fd2ddbf59e4..3722fb06a6a 100644
--- a/library/alloc/tests/vec.rs
+++ b/library/alloc/tests/vec.rs
@@ -1695,7 +1695,6 @@ fn test_reserve_exact() {
 
 #[test]
 #[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
-#[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc
 fn test_try_with_capacity() {
     let mut vec: Vec<u32> = Vec::try_with_capacity(5).unwrap();
     assert_eq!(0, vec.len());
@@ -1707,7 +1706,6 @@ fn test_try_with_capacity() {
 
 #[test]
 #[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
-#[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc
 fn test_try_reserve() {
     // These are the interesting cases:
     // * exactly isize::MAX should never trigger a CapacityOverflow (can be OOM)
@@ -1803,7 +1801,6 @@ fn test_try_reserve() {
 
 #[test]
 #[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
-#[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc
 fn test_try_reserve_exact() {
     // This is exactly the same as test_try_reserve with the method changed.
     // See that test for comments.
diff --git a/library/alloc/tests/vec_deque.rs b/library/alloc/tests/vec_deque.rs
index db972122fef..f32ba8d5aa4 100644
--- a/library/alloc/tests/vec_deque.rs
+++ b/library/alloc/tests/vec_deque.rs
@@ -1185,7 +1185,6 @@ fn test_reserve_exact_2() {
 
 #[test]
 #[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
-#[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc
 fn test_try_with_capacity() {
     let vec: VecDeque<u32> = VecDeque::try_with_capacity(5).unwrap();
     assert_eq!(0, vec.len());
@@ -1196,7 +1195,6 @@ fn test_try_with_capacity() {
 
 #[test]
 #[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
-#[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc
 fn test_try_reserve() {
     // These are the interesting cases:
     // * exactly isize::MAX should never trigger a CapacityOverflow (can be OOM)
@@ -1292,7 +1290,6 @@ fn test_try_reserve() {
 
 #[test]
 #[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
-#[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc
 fn test_try_reserve_exact() {
     // This is exactly the same as test_try_reserve with the method changed.
     // See that test for comments.
diff --git a/library/backtrace b/library/backtrace
-Subproject 72265bea210891ae47bbe6d4f17b493ef060661
+Subproject 230570f2dac80a601f5c0b30da00cc9480bd35e
diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs
index e602b497d17..fed484ae3cd 100644
--- a/library/core/src/mem/mod.rs
+++ b/library/core/src/mem/mod.rs
@@ -612,7 +612,7 @@ pub const fn needs_drop<T: ?Sized>() -> bool {
 ///
 /// There is no guarantee that an all-zero byte-pattern represents a valid value
 /// of some type `T`. For example, the all-zero byte-pattern is not a valid value
-/// for reference types (`&T`, `&mut T`) and functions pointers. Using `zeroed`
+/// for reference types (`&T`, `&mut T`) and function pointers. Using `zeroed`
 /// on such types causes immediate [undefined behavior][ub] because [the Rust
 /// compiler assumes][inv] that there always is a valid value in a variable it
 /// considers initialized.
diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs
index fe6ed7e0cf3..a7037b2a119 100644
--- a/library/core/src/primitive_docs.rs
+++ b/library/core/src/primitive_docs.rs
@@ -1127,7 +1127,7 @@ impl<T> (T,) {}
 
 #[rustc_doc_primitive = "f16"]
 #[doc(alias = "half")]
-/// A 16-bit floating point type (specifically, the "binary16" type defined in IEEE 754-2008).
+/// A 16-bit floating-point type (specifically, the "binary16" type defined in IEEE 754-2008).
 ///
 /// This type is very similar to [`prim@f32`] but has decreased precision because it uses half as many
 /// bits. Please see [the documentation for `f32`](prim@f32) or [Wikipedia on half-precision
@@ -1147,11 +1147,11 @@ mod prim_f16 {}
 
 #[rustc_doc_primitive = "f32"]
 #[doc(alias = "single")]
-/// A 32-bit floating point type (specifically, the "binary32" type defined in IEEE 754-2008).
+/// A 32-bit floating-point type (specifically, the "binary32" type defined in IEEE 754-2008).
 ///
 /// This type can represent a wide range of decimal numbers, like `3.5`, `27`,
 /// `-113.75`, `0.0078125`, `34359738368`, `0`, `-1`. So unlike integer types
-/// (such as `i32`), floating point types can represent non-integer numbers,
+/// (such as `i32`), floating-point types can represent non-integer numbers,
 /// too.
 ///
 /// However, being able to represent this wide range of numbers comes at the
@@ -1165,8 +1165,8 @@ mod prim_f16 {}
 ///
 /// Additionally, `f32` can represent some special values:
 ///
-/// - −0.0: IEEE 754 floating point numbers have a bit that indicates their sign, so −0.0 is a
-///   possible value. For comparison −0.0 = +0.0, but floating point operations can carry
+/// - −0.0: IEEE 754 floating-point numbers have a bit that indicates their sign, so −0.0 is a
+///   possible value. For comparison −0.0 = +0.0, but floating-point operations can carry
 ///   the sign bit through arithmetic operations. This means −0.0 × +0.0 produces −0.0 and
 ///   a negative number rounded to a value smaller than a float can represent also produces −0.0.
 /// - [∞](#associatedconstant.INFINITY) and
@@ -1211,7 +1211,7 @@ mod prim_f16 {}
 ///   both arguments were negative, then it is -0.0. Subtraction `a - b` is
 ///   regarded as a sum `a + (-b)`.
 ///
-/// For more information on floating point numbers, see [Wikipedia][wikipedia].
+/// For more information on floating-point numbers, see [Wikipedia][wikipedia].
 ///
 /// *[See also the `std::f32::consts` module](crate::f32::consts).*
 ///
@@ -1219,39 +1219,43 @@ mod prim_f16 {}
 ///
 /// # NaN bit patterns
 ///
-/// This section defines the possible NaN bit patterns returned by non-"bitwise" floating point
-/// operations. The bitwise operations are unary `-`, `abs`, `copysign`; those are guaranteed to
-/// exactly preserve the bit pattern of their input except for possibly changing the sign bit.
+/// This section defines the possible NaN bit patterns returned by floating-point operations.
 ///
-/// A floating-point NaN value consists of:
-/// - a sign bit
-/// - a quiet/signaling bit
+/// The bit pattern of a floating-point NaN value is defined by:
+/// - a sign bit.
+/// - a quiet/signaling bit. Rust assumes that the quiet/signaling bit being set to `1` indicates a
+///   quiet NaN (QNaN), and a value of `0` indicates a signaling NaN (SNaN). In the following we
+///   will hence just call it the "quiet bit".
 /// - a payload, which makes up the rest of the significand (i.e., the mantissa) except for the
-///   quiet/signaling bit.
-///
-/// Rust assumes that the quiet/signaling bit being set to `1` indicates a quiet NaN (QNaN), and a
-/// value of `0` indicates a signaling NaN (SNaN). In the following we will hence just call it the
-/// "quiet bit".
-///
-/// The following rules apply when a NaN value is returned: the result has a non-deterministic sign.
-/// The quiet bit and payload are non-deterministically chosen from the following set of options:
-///
-/// - **Preferred NaN**: The quiet bit is set and the payload is all-zero.
-/// - **Quieting NaN propagation**: The quiet bit is set and the payload is copied from any input
-///   operand that is a NaN. If the inputs and outputs do not have the same payload size (i.e., for
-///   `as` casts), then
-///   - If the output is smaller than the input, low-order bits of the payload get dropped.
-///   - If the output is larger than the input, the payload gets filled up with 0s in the low-order
-///     bits.
-/// - **Unchanged NaN propagation**: The quiet bit and payload are copied from any input operand
-///   that is a NaN. If the inputs and outputs do not have the same size (i.e., for `as` casts), the
-///   same rules as for "quieting NaN propagation" apply, with one caveat: if the output is smaller
-///   than the input, droppig the low-order bits may result in a payload of 0; a payload of 0 is not
-///   possible with a signaling NaN (the all-0 significand encodes an infinity) so unchanged NaN
-///   propagation cannot occur with some inputs.
-/// - **Target-specific NaN**: The quiet bit is set and the payload is picked from a target-specific
-///   set of "extra" possible NaN payloads. The set can depend on the input operand values.
-///   See the table below for the concrete NaNs this set contains on various targets.
+///   quiet bit.
+///
+/// The rules for NaN values differ between *arithmetic* and *non-arithmetic* (or "bitwise")
+/// operations. The non-arithmetic operations are unary `-`, `abs`, `copysign`, `signum`,
+/// `{to,from}_bits`, `{to,from}_{be,le,ne}_bytes` and `is_sign_{positive,negative}`. These
+/// operations are guaranteed to exactly preserve the bit pattern of their input except for possibly
+/// changing the sign bit.
+///
+/// The following rules apply when a NaN value is returned from an arithmetic operation:
+/// - The result has a non-deterministic sign.
+/// - The quiet bit and payload are non-deterministically chosen from
+///   the following set of options:
+///
+///   - **Preferred NaN**: The quiet bit is set and the payload is all-zero.
+///   - **Quieting NaN propagation**: The quiet bit is set and the payload is copied from any input
+///     operand that is a NaN. If the inputs and outputs do not have the same payload size (i.e., for
+///     `as` casts), then
+///     - If the output is smaller than the input, low-order bits of the payload get dropped.
+///     - If the output is larger than the input, the payload gets filled up with 0s in the low-order
+///       bits.
+///   - **Unchanged NaN propagation**: The quiet bit and payload are copied from any input operand
+///     that is a NaN. If the inputs and outputs do not have the same size (i.e., for `as` casts), the
+///     same rules as for "quieting NaN propagation" apply, with one caveat: if the output is smaller
+///     than the input, droppig the low-order bits may result in a payload of 0; a payload of 0 is not
+///     possible with a signaling NaN (the all-0 significand encodes an infinity) so unchanged NaN
+///     propagation cannot occur with some inputs.
+///   - **Target-specific NaN**: The quiet bit is set and the payload is picked from a target-specific
+///     set of "extra" possible NaN payloads. The set can depend on the input operand values.
+///     See the table below for the concrete NaNs this set contains on various targets.
 ///
 /// In particular, if all input NaNs are quiet (or if there are no input NaNs), then the output NaN
 /// is definitely quiet. Signaling NaN outputs can only occur if they are provided as an input
@@ -1259,7 +1263,7 @@ mod prim_f16 {}
 /// does not have any "extra" NaN payloads, then the output NaN is guaranteed to be preferred.
 ///
 /// The non-deterministic choice happens when the operation is executed; i.e., the result of a
-/// NaN-producing floating point operation is a stable bit pattern (looking at these bits multiple
+/// NaN-producing floating-point operation is a stable bit pattern (looking at these bits multiple
 /// times will yield consistent results), but running the same operation twice with the same inputs
 /// can produce different results.
 ///
@@ -1273,10 +1277,10 @@ mod prim_f16 {}
 /// (e.g. `min`, `minimum`, `max`, `maximum`); other aspects of their semantics and which IEEE 754
 /// operation they correspond to are documented with the respective functions.
 ///
-/// When a floating-point operation is executed in `const` context, the same rules apply: no
-/// guarantee is made about which of the NaN bit patterns described above will be returned. The
-/// result does not have to match what happens when executing the same code at runtime, and the
-/// result can vary depending on factors such as compiler version and flags.
+/// When an arithmetic floating-point operation is executed in `const` context, the same rules
+/// apply: no guarantee is made about which of the NaN bit patterns described above will be
+/// returned. The result does not have to match what happens when executing the same code at
+/// runtime, and the result can vary depending on factors such as compiler version and flags.
 ///
 /// ### Target-specific "extra" NaN values
 // FIXME: Is there a better place to put this?
@@ -1294,7 +1298,7 @@ mod prim_f32 {}
 
 #[rustc_doc_primitive = "f64"]
 #[doc(alias = "double")]
-/// A 64-bit floating point type (specifically, the "binary64" type defined in IEEE 754-2008).
+/// A 64-bit floating-point type (specifically, the "binary64" type defined in IEEE 754-2008).
 ///
 /// This type is very similar to [`prim@f32`], but has increased precision by using twice as many
 /// bits. Please see [the documentation for `f32`](prim@f32) or [Wikipedia on double-precision
@@ -1308,7 +1312,7 @@ mod prim_f64 {}
 
 #[rustc_doc_primitive = "f128"]
 #[doc(alias = "quad")]
-/// A 128-bit floating point type (specifically, the "binary128" type defined in IEEE 754-2008).
+/// A 128-bit floating-point type (specifically, the "binary128" type defined in IEEE 754-2008).
 ///
 /// This type is very similar to [`prim@f32`] and [`prim@f64`], but has increased precision by using twice
 /// as many bits as `f64`. Please see [the documentation for `f32`](prim@f32) or [Wikipedia on
diff --git a/library/core/tests/num/int_log.rs b/library/core/tests/num/int_log.rs
index 2320a7acc35..60902752dab 100644
--- a/library/core/tests/num/int_log.rs
+++ b/library/core/tests/num/int_log.rs
@@ -1,7 +1,4 @@
-//! This tests the `Integer::{ilog,log2,log10}` methods. These tests are in a
-//! separate file because there's both a large number of them, and not all tests
-//! can be run on Android. This is because in Android `ilog2` uses an imprecise
-//! approximation:https://github.com/rust-lang/rust/blob/4825e12fc9c79954aa0fe18f5521efa6c19c7539/src/libstd/sys/unix/android.rs#L27-L53
+//! Tests for the `Integer::{ilog,log2,log10}` methods.
 
 #[test]
 fn checked_ilog() {
@@ -48,6 +45,10 @@ fn checked_ilog2() {
     assert_eq!(0i8.checked_ilog2(), None);
     assert_eq!(0i16.checked_ilog2(), None);
 
+    assert_eq!(8192u16.checked_ilog2(), Some((8192f32).log2() as u32));
+    assert_eq!(32768u16.checked_ilog2(), Some((32768f32).log2() as u32));
+    assert_eq!(8192i16.checked_ilog2(), Some((8192f32).log2() as u32));
+
     for i in 1..=u8::MAX {
         assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32), "checking {i}");
     }
@@ -77,15 +78,6 @@ fn checked_ilog2() {
     }
 }
 
-// Validate cases that fail on Android's imprecise float ilog2 implementation.
-#[test]
-#[cfg(not(target_os = "android"))]
-fn checked_ilog2_not_android() {
-    assert_eq!(8192u16.checked_ilog2(), Some((8192f32).log2() as u32));
-    assert_eq!(32768u16.checked_ilog2(), Some((32768f32).log2() as u32));
-    assert_eq!(8192i16.checked_ilog2(), Some((8192f32).log2() as u32));
-}
-
 #[test]
 fn checked_ilog10() {
     assert_eq!(0u8.checked_ilog10(), None);
diff --git a/library/profiler_builtins/build.rs b/library/profiler_builtins/build.rs
index c1e0e5c1c89..dd85239fa8c 100644
--- a/library/profiler_builtins/build.rs
+++ b/library/profiler_builtins/build.rs
@@ -1,14 +1,15 @@
 //! Compiles the profiler part of the `compiler-rt` library.
 //!
-//! See the build.rs for libcompiler_builtins crate for details.
+//! Loosely based on:
+//! - LLVM's `compiler-rt/lib/profile/CMakeLists.txt`
+//! - <https://github.com/rust-lang/compiler-builtins/blob/master/build.rs>.
 
 use std::env;
 use std::path::PathBuf;
 
 fn main() {
-    println!("cargo:rerun-if-env-changed=LLVM_PROFILER_RT_LIB");
-    if let Ok(rt) = env::var("LLVM_PROFILER_RT_LIB") {
-        println!("cargo:rustc-link-lib=static:+verbatim={rt}");
+    if let Ok(rt) = tracked_env_var("LLVM_PROFILER_RT_LIB") {
+        println!("cargo::rustc-link-lib=static:+verbatim={rt}");
         return;
     }
 
@@ -16,13 +17,13 @@ fn main() {
     let target_env = env::var("CARGO_CFG_TARGET_ENV").expect("CARGO_CFG_TARGET_ENV was not set");
     let cfg = &mut cc::Build::new();
 
-    // FIXME: `rerun-if-changed` directives are not currently emitted and the build script
-    // will not rerun on changes in these source files or headers included into them.
-    let mut profile_sources = vec![
+    let profile_sources = vec![
+        // tidy-alphabetical-start
         "GCDAProfiling.c",
         "InstrProfiling.c",
         "InstrProfilingBuffer.c",
         "InstrProfilingFile.c",
+        "InstrProfilingInternal.c",
         "InstrProfilingMerge.c",
         "InstrProfilingMergeFile.c",
         "InstrProfilingNameVar.c",
@@ -37,15 +38,13 @@ fn main() {
         "InstrProfilingValue.c",
         "InstrProfilingVersionVar.c",
         "InstrProfilingWriter.c",
-        // These files were added in LLVM 11.
-        "InstrProfilingInternal.c",
-        "InstrProfilingBiasVar.c",
+        "WindowsMMap.c",
+        // tidy-alphabetical-end
     ];
 
     if target_env == "msvc" {
         // Don't pull in extra libraries on MSVC
         cfg.flag("/Zl");
-        profile_sources.push("WindowsMMap.c");
         cfg.define("strdup", Some("_strdup"));
         cfg.define("open", Some("_open"));
         cfg.define("fdopen", Some("_fdopen"));
@@ -60,8 +59,6 @@ fn main() {
         if target_os != "windows" {
             cfg.flag("-fvisibility=hidden");
             cfg.define("COMPILER_RT_HAS_UNAME", Some("1"));
-        } else {
-            profile_sources.push("WindowsMMap.c");
         }
     }
 
@@ -80,26 +77,33 @@ fn main() {
     }
 
     // Get the LLVM `compiler-rt` directory from bootstrap.
-    println!("cargo:rerun-if-env-changed=RUST_COMPILER_RT_FOR_PROFILER");
-    let root = PathBuf::from(env::var("RUST_COMPILER_RT_FOR_PROFILER").unwrap_or_else(|_| {
-        let path = "../../src/llvm-project/compiler-rt";
-        println!("RUST_COMPILER_RT_FOR_PROFILER was not set; falling back to {path:?}");
-        path.to_owned()
-    }));
+    let root = PathBuf::from(tracked_env_var_or_fallback(
+        "RUST_COMPILER_RT_FOR_PROFILER",
+        "../../src/llvm-project/compiler-rt",
+    ));
 
     let src_root = root.join("lib").join("profile");
     assert!(src_root.exists(), "profiler runtime source directory not found: {src_root:?}");
-    let mut n_sources_found = 0u32;
-    for src in profile_sources {
-        let path = src_root.join(src);
-        if path.exists() {
-            cfg.file(path);
-            n_sources_found += 1;
-        }
+    println!("cargo::rerun-if-changed={}", src_root.display());
+    for file in profile_sources {
+        cfg.file(src_root.join(file));
     }
-    assert!(n_sources_found > 0, "couldn't find any profiler runtime source files in {src_root:?}");
 
-    cfg.include(root.join("include"));
+    let include = root.join("include");
+    println!("cargo::rerun-if-changed={}", include.display());
+    cfg.include(include);
+
     cfg.warnings(false);
     cfg.compile("profiler-rt");
 }
+
+fn tracked_env_var(key: &str) -> Result<String, env::VarError> {
+    println!("cargo::rerun-if-env-changed={key}");
+    env::var(key)
+}
+fn tracked_env_var_or_fallback(key: &str, fallback: &str) -> String {
+    tracked_env_var(key).unwrap_or_else(|_| {
+        println!("cargo::warning={key} was not set; falling back to {fallback:?}");
+        fallback.to_owned()
+    })
+}
diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs
index 0b12e5777c8..cf226bd28d0 100644
--- a/library/std/src/io/buffered/bufreader.rs
+++ b/library/std/src/io/buffered/bufreader.rs
@@ -94,7 +94,9 @@ impl<R: Read> BufReader<R> {
     pub fn with_capacity(capacity: usize, inner: R) -> BufReader<R> {
         BufReader { inner, buf: Buffer::with_capacity(capacity) }
     }
+}
 
+impl<R: Read + ?Sized> BufReader<R> {
     /// Attempt to look ahead `n` bytes.
     ///
     /// `n` must be less than `capacity`.
diff --git a/library/std/src/sys/pal/wasi/thread.rs b/library/std/src/sys/pal/wasi/thread.rs
index 31c9cbd4699..4b83870fdea 100644
--- a/library/std/src/sys/pal/wasi/thread.rs
+++ b/library/std/src/sys/pal/wasi/thread.rs
@@ -136,36 +136,37 @@ impl Thread {
     }
 
     pub fn sleep(dur: Duration) {
-        let nanos = dur.as_nanos();
-        assert!(nanos <= u64::MAX as u128);
-
-        const USERDATA: wasi::Userdata = 0x0123_45678;
-
-        let clock = wasi::SubscriptionClock {
-            id: wasi::CLOCKID_MONOTONIC,
-            timeout: nanos as u64,
-            precision: 0,
-            flags: 0,
-        };
-
-        let in_ = wasi::Subscription {
-            userdata: USERDATA,
-            u: wasi::SubscriptionU { tag: 0, u: wasi::SubscriptionUU { clock } },
-        };
-        unsafe {
-            let mut event: wasi::Event = mem::zeroed();
-            let res = wasi::poll_oneoff(&in_, &mut event, 1);
-            match (res, event) {
-                (
-                    Ok(1),
-                    wasi::Event {
-                        userdata: USERDATA,
-                        error: wasi::ERRNO_SUCCESS,
-                        type_: wasi::EVENTTYPE_CLOCK,
-                        ..
-                    },
-                ) => {}
-                _ => panic!("thread::sleep(): unexpected result of poll_oneoff"),
+        let mut nanos = dur.as_nanos();
+        while nanos > 0 {
+            const USERDATA: wasi::Userdata = 0x0123_45678;
+
+            let clock = wasi::SubscriptionClock {
+                id: wasi::CLOCKID_MONOTONIC,
+                timeout: u64::try_from(nanos).unwrap_or(u64::MAX),
+                precision: 0,
+                flags: 0,
+            };
+            nanos -= u128::from(clock.timeout);
+
+            let in_ = wasi::Subscription {
+                userdata: USERDATA,
+                u: wasi::SubscriptionU { tag: 0, u: wasi::SubscriptionUU { clock } },
+            };
+            unsafe {
+                let mut event: wasi::Event = mem::zeroed();
+                let res = wasi::poll_oneoff(&in_, &mut event, 1);
+                match (res, event) {
+                    (
+                        Ok(1),
+                        wasi::Event {
+                            userdata: USERDATA,
+                            error: wasi::ERRNO_SUCCESS,
+                            type_: wasi::EVENTTYPE_CLOCK,
+                            ..
+                        },
+                    ) => {}
+                    _ => panic!("thread::sleep(): unexpected result of poll_oneoff"),
+                }
             }
         }
     }