From e163707c70dd5490b13b68f1ed111bdea2785f98 Mon Sep 17 00:00:00 2001 From: nxsaken Date: Sun, 9 Nov 2025 21:07:54 +0400 Subject: [PATCH 01/13] Constify `DropGuard` methods --- library/core/src/mem/drop_guard.rs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/library/core/src/mem/drop_guard.rs b/library/core/src/mem/drop_guard.rs index 1301dedf1241a..013134727b7f0 100644 --- a/library/core/src/mem/drop_guard.rs +++ b/library/core/src/mem/drop_guard.rs @@ -1,4 +1,5 @@ use crate::fmt::{self, Debug}; +use crate::marker::Destruct; use crate::mem::ManuallyDrop; use crate::ops::{Deref, DerefMut}; @@ -81,8 +82,12 @@ where /// assert_eq!(guard.dismiss(), "Nori likes chicken"); /// ``` #[unstable(feature = "drop_guard", issue = "144426")] + #[rustc_const_unstable(feature = "const_drop_guard", issue = "none")] #[inline] - pub fn dismiss(self) -> T { + pub const fn dismiss(self) -> T + where + F: [const] Destruct, + { // First we ensure that dropping the guard will not trigger // its destructor let mut this = ManuallyDrop::new(self); @@ -103,7 +108,8 @@ where } #[unstable(feature = "drop_guard", issue = "144426")] -impl Deref for DropGuard +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl const Deref for DropGuard where F: FnOnce(T), { @@ -115,7 +121,8 @@ where } #[unstable(feature = "drop_guard", issue = "144426")] -impl DerefMut for DropGuard +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl const DerefMut for DropGuard where F: FnOnce(T), { @@ -125,9 +132,10 @@ where } #[unstable(feature = "drop_guard", issue = "144426")] -impl Drop for DropGuard +#[rustc_const_unstable(feature = "const_drop_guard", issue = "none")] +impl const Drop for DropGuard where - F: FnOnce(T), + F: [const] FnOnce(T), { fn drop(&mut self) { // SAFETY: `DropGuard` is in the process of being dropped. From e0c09b546a1278ec185ba3d9348223ab11e1f394 Mon Sep 17 00:00:00 2001 From: Eduard Stefes Date: Mon, 8 Dec 2025 15:50:21 +0100 Subject: [PATCH 02/13] fix va_list test by adding a llvmir signext check s390x has no option to directly pass 32bit values therefor i32 parameters need an optional llvmir signext attribute. --- tests/codegen-llvm/cffi/c-variadic-va_list.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/codegen-llvm/cffi/c-variadic-va_list.rs b/tests/codegen-llvm/cffi/c-variadic-va_list.rs index e2652491f421a..b2f5ffc3495b4 100644 --- a/tests/codegen-llvm/cffi/c-variadic-va_list.rs +++ b/tests/codegen-llvm/cffi/c-variadic-va_list.rs @@ -22,15 +22,15 @@ pub unsafe extern "C" fn use_foreign_c_variadic_1_0(ap: VaList) { // CHECK-LABEL: use_foreign_c_variadic_1_1 pub unsafe extern "C" fn use_foreign_c_variadic_1_1(ap: VaList) { - // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap, i32 noundef 42) + // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap, i32 noundef{{( signext)?}} 42) foreign_c_variadic_1(ap, 42i32); } pub unsafe extern "C" fn use_foreign_c_variadic_1_2(ap: VaList) { - // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap, i32 noundef 2, i32 noundef 42) + // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap, i32 noundef{{( signext)?}} 2, i32 noundef{{( signext)?}} 42) foreign_c_variadic_1(ap, 2i32, 42i32); } pub unsafe extern "C" fn use_foreign_c_variadic_1_3(ap: VaList) { - // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap, i32 noundef 2, i32 noundef 42, i32 noundef 0) + // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap, i32 noundef{{( signext)?}} 2, i32 noundef{{( signext)?}} 42, i32 noundef{{( signext)?}} 0) foreign_c_variadic_1(ap, 2i32, 42i32, 0i32); } From 34392a99c0434c93bdaab5c6655f83417303c21c Mon Sep 17 00:00:00 2001 From: DrAsu33 <3537555264@qq.com> Date: Sat, 29 Nov 2025 06:22:41 +0000 Subject: [PATCH 03/13] Fix(alloc): Correctly handle ZST alignment for IntoIter::nth_back This commit consolidates all changes, including the core logic fix for IntoIter::nth_back and the addition of the Miri regression test in `library/alloctests/tests/vec.rs`, to prevent Undefined Behavior (UB) when dealing with highly-aligned Zero-Sized Types. --- library/alloc/src/vec/into_iter.rs | 7 ++++++- library/alloctests/tests/vec.rs | 32 ++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index 358bdeacae790..af1bd53179739 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -411,7 +411,12 @@ impl DoubleEndedIterator for IntoIter { // SAFETY: same as for advance_by() self.end = unsafe { self.end.sub(step_size) }; } - let to_drop = ptr::slice_from_raw_parts_mut(self.end as *mut T, step_size); + let to_drop = if T::IS_ZST { + // ZST may cause unalignment + ptr::slice_from_raw_parts_mut(ptr::NonNull::::dangling().as_ptr(), step_size) + } else { + ptr::slice_from_raw_parts_mut(self.end as *mut T, step_size) + }; // SAFETY: same as for advance_by() unsafe { ptr::drop_in_place(to_drop); diff --git a/library/alloctests/tests/vec.rs b/library/alloctests/tests/vec.rs index dd42230d2e003..cd5b14f6eff37 100644 --- a/library/alloctests/tests/vec.rs +++ b/library/alloctests/tests/vec.rs @@ -2717,3 +2717,35 @@ fn vec_null_ptr_roundtrip() { let new = roundtripped.with_addr(ptr.addr()); unsafe { new.read() }; } + +// Regression test for Undefined Behavior (UB) caused by IntoIter::nth_back (#148682) +// when dealing with high-aligned Zero-Sized Types (ZSTs). +use std::collections::{BTreeMap, BinaryHeap, HashMap, LinkedList, VecDeque}; +#[test] +fn zst_collections_iter_nth_back_regression() { + #[repr(align(8))] + #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] + struct Thing; + let v = vec![Thing, Thing]; + let _ = v.into_iter().nth_back(1); + let mut d = VecDeque::new(); + d.push_back(Thing); + d.push_back(Thing); + let _ = d.into_iter().nth_back(1); + let mut map = BTreeMap::new(); + map.insert(0, Thing); + map.insert(1, Thing); + let _ = map.into_values().nth_back(0); + let mut hash_map = HashMap::new(); + hash_map.insert(1, Thing); + hash_map.insert(2, Thing); + let _ = hash_map.into_values().nth(1); + let mut heap = BinaryHeap::new(); + heap.push(Thing); + heap.push(Thing); + let _ = heap.into_iter().nth_back(1); + let mut list = LinkedList::new(); + list.push_back(Thing); + list.push_back(Thing); + let _ = list.into_iter().nth_back(1); +} From 4e51a8dbc0dfe25791375fe94a395d7cb200ef8a Mon Sep 17 00:00:00 2001 From: Jamie Hill-Daniel Date: Fri, 28 Nov 2025 11:47:27 +0000 Subject: [PATCH 04/13] tidy: Detect outdated workspaces in workspace list --- src/tools/tidy/src/deps.rs | 42 ++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 592ba9c5c7946..5dbb7a4e71b0f 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -1,6 +1,7 @@ //! Checks the licenses of third-party dependencies. use std::collections::{HashMap, HashSet}; +use std::fmt::{Display, Formatter}; use std::fs::{File, read_dir}; use std::io::Write; use std::path::Path; @@ -14,6 +15,25 @@ use crate::diagnostics::{RunningCheck, TidyCtx}; #[path = "../../../bootstrap/src/utils/proc_macro_deps.rs"] mod proc_macro_deps; +#[derive(Clone, Copy)] +struct ListLocation { + path: &'static str, + line: u32, +} + +impl Display for ListLocation { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}:{}", self.path, self.line) + } +} + +/// Creates a [`ListLocation`] for the current location (with an additional offset to the actual list start); +macro_rules! location { + (+ $offset:literal) => { + ListLocation { path: file!(), line: line!() + $offset } + }; +} + /// These are licenses that are allowed for all crates, including the runtime, /// rustc, tools, etc. #[rustfmt::skip] @@ -87,6 +107,8 @@ pub(crate) struct WorkspaceInfo<'a> { pub(crate) submodules: &'a [&'a str], } +const WORKSPACE_LOCATION: ListLocation = location!(+4); + /// The workspaces to check for licensing and optionally permitted dependencies. // FIXME auto detect all cargo workspaces pub(crate) const WORKSPACES: &[WorkspaceInfo<'static>] = &[ @@ -242,19 +264,6 @@ const EXCEPTIONS_BOOTSTRAP: ExceptionList = &[]; const EXCEPTIONS_UEFI_QEMU_TEST: ExceptionList = &[]; -#[derive(Clone, Copy)] -struct ListLocation { - path: &'static str, - line: u32, -} - -/// Creates a [`ListLocation`] for the current location (with an additional offset to the actual list start); -macro_rules! location { - (+ $offset:literal) => { - ListLocation { path: file!(), line: line!() + $offset } - }; -} - const PERMITTED_RUSTC_DEPS_LOCATION: ListLocation = location!(+6); /// Crates rustc is allowed to depend on. Avoid adding to the list if possible. @@ -641,6 +650,13 @@ pub fn check(root: &Path, cargo: &Path, tidy_ctx: TidyCtx) { .other_options(vec!["--locked".to_owned()]); let metadata = t!(cmd.exec()); + // Check for packages which have been moved into a different workspace and not updated + let absolute_root = + if path == "." { root.to_path_buf() } else { t!(std::path::absolute(root.join(path))) }; + let absolute_root_real = t!(std::path::absolute(&metadata.workspace_root)); + if absolute_root_real != absolute_root { + check.error(format!("{path} is part of another workspace ({} != {}), remove from `WORKSPACES` ({WORKSPACE_LOCATION})", absolute_root.display(), absolute_root_real.display())); + } check_license_exceptions(&metadata, path, exceptions, &mut check); if let Some((crates, permitted_deps, location)) = crates_and_deps { let descr = crates.get(0).unwrap_or(&path); From ac5c70ad4d5d8f767237f5b3d28719fbc5d72bc8 Mon Sep 17 00:00:00 2001 From: Clara Engler Date: Tue, 11 Nov 2025 11:46:11 +0100 Subject: [PATCH 05/13] time: Implement SystemTime::{MIN, MAX} This commit introduces two new constants to SystemTime: `MIN` and `MAX`, whose value represent the maximum values for the respective data type, depending upon the platform. Technically, this value is already obtainable during runtime with the following algorithm: Use `SystemTime::UNIX_EPOCH` and call `checked_add` (or `checked_sub`) repeatedly with `Duration::new(0, 1)` on it, until it returns None. Mathematically speaking, this algorithm will terminate after a finite amount of steps, yet it is impractical to run it, as it takes practically forever. Besides, this commit also adds a unit test. Concrete implementation depending upon the platform is done in later commits. In the future, the hope of the authors lies within the creation of a `SystemTime::saturating_add` and `SystemTime::saturating_sub`, similar to the functions already present in `std::time::Duration`. However, for those, these constants are crucially required, thereby this should be seen as the initial step towards this direction. Below are platform specifc notes: # Hermit The HermitOS implementation is more or less identitcal to the Unix one. # sgx The implementation uses a `Duration` to store the Unix time, thereby implying `Duration::ZERO` and `Duration::MAX` as the limits. # solid The implementation uses a `time_t` to store the system time within a single value (i.e. no dual secs/nanosecs handling), thereby implying its `::MIN` and `::MAX` values as the respective boundaries. # UEFI UEFI has a weird way to store times, i.e. a very complicated struct. The standard proclaims "1900-01-01T00:00:00+0000" to be the lowest possible value and `MAX_UEFI_TIME` is already present for the upper limit. # Windows Windows is weird. The Win32 documentation makes no statement on a maximum value here. Next to this, there are two conflicting types: `SYSTEMTIME` and `FILETIME`. Rust's Standard Library uses `FILETIME`, whose limit will (probably) be `i64::MAX` packed into two integers. However, `SYSTEMTIME` has a lower-limit. # xous It is similar to sgx in the sense of using a `Duration`. # unsupported Unsupported platforms store a `SystemTime` in a `Duration`, just like sgx, thereby implying `Duration::ZERO` and `Duration::MAX` as the respective limits. --- library/std/src/sys/pal/hermit/time.rs | 8 +++ library/std/src/sys/pal/sgx/time.rs | 4 ++ library/std/src/sys/pal/solid/time.rs | 4 ++ library/std/src/sys/pal/uefi/time.rs | 17 ++++++ library/std/src/sys/pal/unix/time.rs | 11 ++++ library/std/src/sys/pal/unsupported/time.rs | 4 ++ library/std/src/sys/pal/windows/time.rs | 10 ++++ library/std/src/sys/pal/xous/time.rs | 4 ++ library/std/src/time.rs | 63 +++++++++++++++++++++ library/std/tests/time.rs | 19 +++++++ 10 files changed, 144 insertions(+) diff --git a/library/std/src/sys/pal/hermit/time.rs b/library/std/src/sys/pal/hermit/time.rs index bd6fd5a3de428..53b1f9292b3d4 100644 --- a/library/std/src/sys/pal/hermit/time.rs +++ b/library/std/src/sys/pal/hermit/time.rs @@ -15,6 +15,10 @@ struct Timespec { } impl Timespec { + const MAX: Timespec = Self::new(i64::MAX, 1_000_000_000 - 1); + + const MIN: Timespec = Self::new(i64::MIN, 0); + const fn zero() -> Timespec { Timespec { t: timespec { tv_sec: 0, tv_nsec: 0 } } } @@ -209,6 +213,10 @@ pub struct SystemTime(Timespec); pub const UNIX_EPOCH: SystemTime = SystemTime(Timespec::zero()); impl SystemTime { + pub const MAX: SystemTime = SystemTime { t: Timespec::MAX }; + + pub const MIN: SystemTime = SystemTime { t: Timespec::MIN }; + pub fn new(tv_sec: i64, tv_nsec: i32) -> SystemTime { SystemTime(Timespec::new(tv_sec, tv_nsec)) } diff --git a/library/std/src/sys/pal/sgx/time.rs b/library/std/src/sys/pal/sgx/time.rs index db4cf2804bf13..a9a448226619e 100644 --- a/library/std/src/sys/pal/sgx/time.rs +++ b/library/std/src/sys/pal/sgx/time.rs @@ -28,6 +28,10 @@ impl Instant { } impl SystemTime { + pub const MAX: SystemTime = SystemTime(Duration::MAX); + + pub const MIN: SystemTime = SystemTime(Duration::ZERO); + pub fn now() -> SystemTime { SystemTime(usercalls::insecure_time()) } diff --git a/library/std/src/sys/pal/solid/time.rs b/library/std/src/sys/pal/solid/time.rs index c39d715c6a6f6..d5cf70f94c987 100644 --- a/library/std/src/sys/pal/solid/time.rs +++ b/library/std/src/sys/pal/solid/time.rs @@ -10,6 +10,10 @@ pub struct SystemTime(abi::time_t); pub const UNIX_EPOCH: SystemTime = SystemTime(0); impl SystemTime { + pub const MAX: SystemTime = SystemTime(abi::time_t::MAX); + + pub const MIN: SystemTime = SystemTime(abi::time_t::MIN); + pub fn now() -> SystemTime { let rtc = unsafe { let mut out = MaybeUninit::zeroed(); diff --git a/library/std/src/sys/pal/uefi/time.rs b/library/std/src/sys/pal/uefi/time.rs index 28dacbe3068a7..30df6d93d0eed 100644 --- a/library/std/src/sys/pal/uefi/time.rs +++ b/library/std/src/sys/pal/uefi/time.rs @@ -70,6 +70,23 @@ impl Instant { } impl SystemTime { + pub const MAX: SystemTime = MAX_UEFI_TIME; + + pub const MIN: SystemTime = SystemTime::from_uefi(r_efi::efi::Time { + year: 1900, + month: 1, + day: 1, + hour: 0, + minute: 0, + second: 0, + nanosecond: 0, + timezone: -1440, + daylight: 0, + pad1: 0, + pad2: 0, + }) + .unwrap(); + pub(crate) const fn from_uefi(t: r_efi::efi::Time) -> Option { match system_time_internal::from_uefi(&t) { Some(x) => Some(Self(x)), diff --git a/library/std/src/sys/pal/unix/time.rs b/library/std/src/sys/pal/unix/time.rs index 24f13853b96b3..1b3fbeee4d900 100644 --- a/library/std/src/sys/pal/unix/time.rs +++ b/library/std/src/sys/pal/unix/time.rs @@ -30,6 +30,10 @@ pub(crate) struct Timespec { } impl SystemTime { + pub const MAX: SystemTime = SystemTime { t: Timespec::MAX }; + + pub const MIN: SystemTime = SystemTime { t: Timespec::MIN }; + #[cfg_attr(any(target_os = "horizon", target_os = "hurd"), allow(unused))] pub fn new(tv_sec: i64, tv_nsec: i64) -> Result { Ok(SystemTime { t: Timespec::new(tv_sec, tv_nsec)? }) @@ -62,6 +66,13 @@ impl fmt::Debug for SystemTime { } impl Timespec { + const MAX: Timespec = unsafe { Self::new_unchecked(i64::MAX, 1_000_000_000 - 1) }; + + // As described below, on Apple OS, dates before epoch are represented differently. + // This is not an issue here however, because we are using tv_sec = i64::MIN, + // which will cause the compatibility wrapper to not be executed at all. + const MIN: Timespec = unsafe { Self::new_unchecked(i64::MIN, 0) }; + const unsafe fn new_unchecked(tv_sec: i64, tv_nsec: i64) -> Timespec { Timespec { tv_sec, tv_nsec: unsafe { Nanoseconds::new_unchecked(tv_nsec as u32) } } } diff --git a/library/std/src/sys/pal/unsupported/time.rs b/library/std/src/sys/pal/unsupported/time.rs index 6d67b538a96bf..9bdd57268fd5b 100644 --- a/library/std/src/sys/pal/unsupported/time.rs +++ b/library/std/src/sys/pal/unsupported/time.rs @@ -27,6 +27,10 @@ impl Instant { } impl SystemTime { + pub const MAX: SystemTime = SystemTime(Duration::MAX); + + pub const MIN: SystemTime = SystemTime(Duration::ZERO); + pub fn now() -> SystemTime { panic!("time not implemented on this platform") } diff --git a/library/std/src/sys/pal/windows/time.rs b/library/std/src/sys/pal/windows/time.rs index 0d31b80e56afc..88f4d4cdbd615 100644 --- a/library/std/src/sys/pal/windows/time.rs +++ b/library/std/src/sys/pal/windows/time.rs @@ -64,6 +64,16 @@ impl Instant { } impl SystemTime { + pub const MAX: SystemTime = SystemTime { + t: c::FILETIME { + dwLowDateTime: (i64::MAX & 0xFFFFFFFF) as u32, + dwHighDateTime: (i64::MAX >> 32) as u32, + }, + }; + + pub const MIN: SystemTime = + SystemTime { t: c::FILETIME { dwLowDateTime: 0, dwHighDateTime: 0 } }; + pub fn now() -> SystemTime { unsafe { let mut t: SystemTime = mem::zeroed(); diff --git a/library/std/src/sys/pal/xous/time.rs b/library/std/src/sys/pal/xous/time.rs index ae8be81c0b7c5..1e7e48183e982 100644 --- a/library/std/src/sys/pal/xous/time.rs +++ b/library/std/src/sys/pal/xous/time.rs @@ -35,6 +35,10 @@ impl Instant { } impl SystemTime { + pub const MAX: SystemTime = SystemTime(Duration::MAX); + + pub const MIN: SystemTime = SystemTime(Duration::ZERO); + pub fn now() -> SystemTime { let result = blocking_scalar(systime_server(), GetUtcTimeMs.into()) .expect("failed to request utc time in ms"); diff --git a/library/std/src/time.rs b/library/std/src/time.rs index 87aaf9091f1bc..0bda83af4dfb6 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -511,6 +511,69 @@ impl SystemTime { #[stable(feature = "assoc_unix_epoch", since = "1.28.0")] pub const UNIX_EPOCH: SystemTime = UNIX_EPOCH; + /// Represents the maximum value representable by [`SystemTime`] on this platform. + /// + /// This value differs a lot between platforms, but it is always the case + /// that any positive addition to [`SystemTime::MAX`] will fail. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(time_systemtime_limits)] + /// use std::time::{Duration, SystemTime}; + /// + /// // Adding zero will change nothing. + /// assert_eq!(SystemTime::MAX.checked_add(Duration::ZERO), Some(SystemTime::MAX)); + /// + /// // But adding just 1ns will already fail. + /// assert_eq!(SystemTime::MAX.checked_add(Duration::new(0, 1)), None); + /// + /// // Utilize this for saturating arithmetic to improve error handling. + /// // In this case, we will use a certificate with a timestamp in the + /// // future as a practical example. + /// let configured_offset = Duration::from_secs(60 * 60 * 24); + /// let valid_after = + /// SystemTime::now() + /// .checked_add(configured_offset) + /// .unwrap_or(SystemTime::MAX); + /// ``` + #[unstable(feature = "time_systemtime_limits", issue = "149067")] + pub const MAX: SystemTime = SystemTime(time::SystemTime::MAX); + + /// Represents the minimum value representable by [`SystemTime`] on this platform. + /// + /// This value differs a lot between platforms, but it is always the case + /// that any positive subtraction from [`SystemTime::MIN`] will fail. + /// + /// Depending on the platform, this may be either less than or equal to + /// [`SystemTime::UNIX_EPOCH`], depending on whether the operating system + /// supports the representation of timestamps before the Unix epoch or not. + /// However, it is always guaranteed that a [`SystemTime::UNIX_EPOCH`] fits + /// between a [`SystemTime::MIN`] and [`SystemTime::MAX`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(time_systemtime_limits)] + /// use std::time::{Duration, SystemTime}; + /// + /// // Subtracting zero will change nothing. + /// assert_eq!(SystemTime::MIN.checked_sub(Duration::ZERO), Some(SystemTime::MIN)); + /// + /// // But subtracting just 1ns will already fail. + /// assert_eq!(SystemTime::MIN.checked_sub(Duration::new(0, 1)), None); + /// + /// // Utilize this for saturating arithmetic to improve error handling. + /// // In this case, we will use a cache expiry as a practical example. + /// let configured_expiry = Duration::from_secs(60 * 3); + /// let expiry_threshold = + /// SystemTime::now() + /// .checked_sub(configured_expiry) + /// .unwrap_or(SystemTime::MIN); + /// ``` + #[unstable(feature = "time_systemtime_limits", issue = "149067")] + pub const MIN: SystemTime = SystemTime(time::SystemTime::MIN); + /// Returns the system time corresponding to "now". /// /// # Examples diff --git a/library/std/tests/time.rs b/library/std/tests/time.rs index be1948af91564..31cc7171fe52e 100644 --- a/library/std/tests/time.rs +++ b/library/std/tests/time.rs @@ -1,4 +1,5 @@ #![feature(duration_constants)] +#![feature(time_systemtime_limits)] use std::fmt::Debug; use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; @@ -237,9 +238,27 @@ fn system_time_duration_since_max_range_on_unix() { let min = SystemTime::UNIX_EPOCH - (Duration::new(i64::MAX as u64 + 1, 0)); let max = SystemTime::UNIX_EPOCH + (Duration::new(i64::MAX as u64, 999_999_999)); + assert_eq!(min, SystemTime::MIN); + assert_eq!(max, SystemTime::MAX); + let delta_a = max.duration_since(min).expect("duration_since overflow"); let delta_b = min.duration_since(max).expect_err("duration_since overflow").duration(); assert_eq!(Duration::MAX, delta_a); assert_eq!(Duration::MAX, delta_b); } + +#[test] +fn system_time_max_min() { + // First, test everything with checked_* and Duration::ZERO. + assert_eq!(SystemTime::MAX.checked_add(Duration::ZERO), Some(SystemTime::MAX)); + assert_eq!(SystemTime::MAX.checked_sub(Duration::ZERO), Some(SystemTime::MAX)); + assert_eq!(SystemTime::MIN.checked_add(Duration::ZERO), Some(SystemTime::MIN)); + assert_eq!(SystemTime::MIN.checked_sub(Duration::ZERO), Some(SystemTime::MIN)); + + // Now do the same again with checked_* but try by ± a single nanosecond. + assert!(SystemTime::MAX.checked_add(Duration::new(0, 1)).is_none()); + assert!(SystemTime::MAX.checked_sub(Duration::new(0, 1)).is_some()); + assert!(SystemTime::MIN.checked_add(Duration::new(0, 1)).is_some()); + assert!(SystemTime::MIN.checked_sub(Duration::new(0, 1)).is_none()); +} From 29f688a05ff4306f0a0b322a07b702fe933604f3 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 11 Dec 2025 15:49:36 -0800 Subject: [PATCH 06/13] Update to mdbook 0.5 This updates to mdbook 0.5.2 from mdbook 0.4.52. A primary aspect of this change is that it splits the `mdbook` crate into multiple crates, and various API changes and cleanup. There's full release notes and a migration guide at https://github.com/rust-lang/mdBook/blob/master/CHANGELOG.md#mdbook-050. This also includes submodule updates: ## book 2 commits in 8c0eacd5c4acbb650497454f3a58c9e8083202a4..39aeceaa3aeab845bc4517e7a44e48727d3b9dbe 2025-11-18 10:36:41 -0500 to 2025-12-12 11:02:27 -0500 - Synchronize TrplNote name - Update to mdbook 0.5 ## edition-guide 1 commits in 9cf5443d632673c4d41edad5e8ed8be86eeb3b8f..c3c0f0b3da26610138b7ba7663f60cd2c68cf184 2025-11-15 21:51:11 +0000 to 2025-11-28 18:54:18 +0000 - Update to mdbook 0.5 (rust-lang/edition-guide#381) ## nomicon 2 commits in 0fe83ab28985b99aba36a1f0dbde3e08286fefda..9fe8fa599ad228dda74f240cc32b54bc5c1aa3e6 2025-11-15 00:03:14 +0000 to 2025-12-03 11:54:04 +0000 - Remove references to outdated unsafe code guidelines (rust-lang/nomicon#512) - Update to mdbook 0.5 (rust-lang/nomicon#511) ## reference 5 commits in b14b4e40f53ca468beaf2f5d0dfb4f4c4ba6bc7b..50c5de90487b68d429a30cc9466dc8f5b410128f 2025-12-02 21:17:44 +0000 to 2025-12-09 22:19:05 +0000 - UB: update the extra clause for provenance UB during const evaluation (rust-lang/reference#2091) - Remove `[no-mentions]` handler in our triagebot config (rust-lang/reference#2102) - Clarify that omitting `nostack` is a promise from the compiler to the programmer (rust-lang/reference#1999) - Specify that range patterns must be nonempty. (rust-lang/reference#2093) - Update to mdbook 0.5 (rust-lang/reference#2096) ## rust-by-example 1 commits in 111cfae2f9c3a43f7b0ff8fa68c51cc8f930637c..7d21279e40e8f0e91c2a22c5148dd2d745aef8b6 2025-11-27 17:16:42 -0300 to 2025-12-01 15:02:09 -0300 - Update to mdbook 0.5 (rust-lang/rust-by-example#1977) --- src/doc/book | 2 +- src/doc/edition-guide | 2 +- src/doc/nomicon | 2 +- src/doc/reference | 2 +- src/doc/rust-by-example | 2 +- src/doc/rustc/book.toml | 4 - src/doc/rustc/theme/pagetoc.css | 84 -- src/doc/rustc/theme/pagetoc.js | 104 -- .../src/read-documentation/in-doc-settings.md | 2 +- src/doc/style-guide/book.toml | 4 +- src/doc/unstable-book/book.toml | 1 - src/tools/error_index_generator/Cargo.toml | 3 +- src/tools/error_index_generator/main.rs | 8 +- src/tools/rustbook/Cargo.lock | 899 ++++++------------ src/tools/rustbook/Cargo.toml | 15 +- src/tools/rustbook/src/main.rs | 100 +- src/tools/tidy/src/deps.rs | 12 +- 17 files changed, 398 insertions(+), 848 deletions(-) delete mode 100644 src/doc/rustc/theme/pagetoc.css delete mode 100644 src/doc/rustc/theme/pagetoc.js diff --git a/src/doc/book b/src/doc/book index 8c0eacd5c4acb..39aeceaa3aeab 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 8c0eacd5c4acbb650497454f3a58c9e8083202a4 +Subproject commit 39aeceaa3aeab845bc4517e7a44e48727d3b9dbe diff --git a/src/doc/edition-guide b/src/doc/edition-guide index 9cf5443d63267..c3c0f0b3da266 160000 --- a/src/doc/edition-guide +++ b/src/doc/edition-guide @@ -1 +1 @@ -Subproject commit 9cf5443d632673c4d41edad5e8ed8be86eeb3b8f +Subproject commit c3c0f0b3da26610138b7ba7663f60cd2c68cf184 diff --git a/src/doc/nomicon b/src/doc/nomicon index 0fe83ab28985b..9fe8fa599ad22 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit 0fe83ab28985b99aba36a1f0dbde3e08286fefda +Subproject commit 9fe8fa599ad228dda74f240cc32b54bc5c1aa3e6 diff --git a/src/doc/reference b/src/doc/reference index b14b4e40f53ca..50c5de90487b6 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit b14b4e40f53ca468beaf2f5d0dfb4f4c4ba6bc7b +Subproject commit 50c5de90487b68d429a30cc9466dc8f5b410128f diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 111cfae2f9c3a..7d21279e40e8f 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 111cfae2f9c3a43f7b0ff8fa68c51cc8f930637c +Subproject commit 7d21279e40e8f0e91c2a22c5148dd2d745aef8b6 diff --git a/src/doc/rustc/book.toml b/src/doc/rustc/book.toml index 34c57a63c97bb..9a7c28525f0ec 100644 --- a/src/doc/rustc/book.toml +++ b/src/doc/rustc/book.toml @@ -1,13 +1,9 @@ [book] -multilingual = false -src = "src" title = "The rustc book" [output.html] git-repository-url = "https://github.com/rust-lang/rust/tree/HEAD/src/doc/rustc" edit-url-template = "https://github.com/rust-lang/rust/edit/HEAD/src/doc/rustc/{path}" -additional-css = ["theme/pagetoc.css"] -additional-js = ["theme/pagetoc.js"] [output.html.search] use-boolean-and = true diff --git a/src/doc/rustc/theme/pagetoc.css b/src/doc/rustc/theme/pagetoc.css deleted file mode 100644 index fa709194f3755..0000000000000 --- a/src/doc/rustc/theme/pagetoc.css +++ /dev/null @@ -1,84 +0,0 @@ -/* Inspired by https://github.com/JorelAli/mdBook-pagetoc/tree/98ee241 (under WTFPL) */ - -:root { - --toc-width: 270px; - --center-content-toc-shift: calc(-1 * var(--toc-width) / 2); -} - -.nav-chapters { - /* adjust width of buttons that bring to the previous or the next page */ - min-width: 50px; -} - -@media only screen { - @media (max-width: 1179px) { - .sidebar-hidden #sidetoc { - display: none; - } - } - - @media (max-width: 1439px) { - .sidebar-visible #sidetoc { - display: none; - } - } - - @media (1180px <= width <= 1439px) { - .sidebar-hidden main { - position: relative; - left: var(--center-content-toc-shift); - } - } - - @media (1440px <= width <= 1700px) { - .sidebar-visible main { - position: relative; - left: var(--center-content-toc-shift); - } - } - - #sidetoc { - margin-left: calc(100% + 20px); - } - #pagetoc { - position: fixed; - /* adjust TOC width */ - width: var(--toc-width); - height: calc(100vh - var(--menu-bar-height) - 0.67em * 4); - overflow: auto; - } - #pagetoc a { - border-left: 1px solid var(--sidebar-bg); - color: var(--fg); - display: block; - padding-bottom: 5px; - padding-top: 5px; - padding-left: 10px; - text-align: left; - text-decoration: none; - } - #pagetoc a:hover, - #pagetoc a.active { - background: var(--sidebar-bg); - color: var(--sidebar-active) !important; - } - #pagetoc .active { - background: var(--sidebar-bg); - color: var(--sidebar-active); - } - #pagetoc .pagetoc-H2 { - padding-left: 20px; - } - #pagetoc .pagetoc-H3 { - padding-left: 40px; - } - #pagetoc .pagetoc-H4 { - padding-left: 60px; - } -} - -@media print { - #sidetoc { - display: none; - } -} diff --git a/src/doc/rustc/theme/pagetoc.js b/src/doc/rustc/theme/pagetoc.js deleted file mode 100644 index 927a5b10749b5..0000000000000 --- a/src/doc/rustc/theme/pagetoc.js +++ /dev/null @@ -1,104 +0,0 @@ -// Inspired by https://github.com/JorelAli/mdBook-pagetoc/tree/98ee241 (under WTFPL) - -let activeHref = location.href; -function updatePageToc(elem = undefined) { - let selectedPageTocElem = elem; - const pagetoc = document.getElementById("pagetoc"); - - function getRect(element) { - return element.getBoundingClientRect(); - } - - function overflowTop(container, element) { - return getRect(container).top - getRect(element).top; - } - - function overflowBottom(container, element) { - return getRect(container).bottom - getRect(element).bottom; - } - - // We've not selected a heading to highlight, and the URL needs updating - // so we need to find a heading based on the URL - if (selectedPageTocElem === undefined && location.href !== activeHref) { - activeHref = location.href; - for (const pageTocElement of pagetoc.children) { - if (pageTocElement.href === activeHref) { - selectedPageTocElem = pageTocElement; - } - } - } - - // We still don't have a selected heading, let's try and find the most - // suitable heading based on the scroll position - if (selectedPageTocElem === undefined) { - const margin = window.innerHeight / 3; - - const headers = document.getElementsByClassName("header"); - for (let i = 0; i < headers.length; i++) { - const header = headers[i]; - if (selectedPageTocElem === undefined && getRect(header).top >= 0) { - if (getRect(header).top < margin) { - selectedPageTocElem = header; - } else { - selectedPageTocElem = headers[Math.max(0, i - 1)]; - } - } - // a very long last section's heading is over the screen - if (selectedPageTocElem === undefined && i === headers.length - 1) { - selectedPageTocElem = header; - } - } - } - - // Remove the active flag from all pagetoc elements - for (const pageTocElement of pagetoc.children) { - pageTocElement.classList.remove("active"); - } - - // If we have a selected heading, set it to active and scroll to it - if (selectedPageTocElem !== undefined) { - for (const pageTocElement of pagetoc.children) { - if (selectedPageTocElem.href.localeCompare(pageTocElement.href) === 0) { - pageTocElement.classList.add("active"); - if (overflowTop(pagetoc, pageTocElement) > 0) { - pagetoc.scrollTop = pageTocElement.offsetTop; - } - if (overflowBottom(pagetoc, pageTocElement) < 0) { - pagetoc.scrollTop -= overflowBottom(pagetoc, pageTocElement); - } - } - } - } -} - -if (document.getElementById("sidetoc") === null && - document.getElementsByClassName("header").length > 0) { - // The sidetoc element doesn't exist yet, let's create it - - // Create the empty sidetoc and pagetoc elements - const sidetoc = document.createElement("div"); - const pagetoc = document.createElement("div"); - sidetoc.id = "sidetoc"; - pagetoc.id = "pagetoc"; - sidetoc.appendChild(pagetoc); - - // And append them to the current DOM - const main = document.querySelector('main'); - main.insertBefore(sidetoc, main.firstChild); - - // Populate sidebar on load - window.addEventListener("load", () => { - for (const header of document.getElementsByClassName("header")) { - const link = document.createElement("a"); - link.innerHTML = header.innerHTML; - link.href = header.hash; - link.classList.add("pagetoc-" + header.parentElement.tagName); - document.getElementById("pagetoc").appendChild(link); - link.onclick = () => updatePageToc(link); - } - updatePageToc(); - }); - - // Update page table of contents selected heading on scroll - window.addEventListener("scroll", () => updatePageToc()); -} diff --git a/src/doc/rustdoc/src/read-documentation/in-doc-settings.md b/src/doc/rustdoc/src/read-documentation/in-doc-settings.md index 12928a4f36926..1bcf74e39cd15 100644 --- a/src/doc/rustdoc/src/read-documentation/in-doc-settings.md +++ b/src/doc/rustdoc/src/read-documentation/in-doc-settings.md @@ -4,7 +4,7 @@ Rustdoc's HTML output includes a settings menu, and this chapter describes what each setting in this menu does. It can be accessed by clicking on the gear button -() in the upper right. +() in the upper right. ## Changing displayed theme diff --git a/src/doc/style-guide/book.toml b/src/doc/style-guide/book.toml index 056aec8cdd4f6..1ef0af5fcdbf7 100644 --- a/src/doc/style-guide/book.toml +++ b/src/doc/style-guide/book.toml @@ -1,8 +1,6 @@ [book] title = "The Rust Style Guide" -author = "The Rust Style Team" -multilingual = false -src = "src" +authors = ["The Rust Style Team"] [output.html] git-repository-url = "https://github.com/rust-lang/rust/tree/HEAD/src/doc/style-guide/" diff --git a/src/doc/unstable-book/book.toml b/src/doc/unstable-book/book.toml index 5dbe90cd10ec6..c357949f6c2e9 100644 --- a/src/doc/unstable-book/book.toml +++ b/src/doc/unstable-book/book.toml @@ -1,6 +1,5 @@ [book] title = "The Rust Unstable Book" -author = "The Rust Community" [output.html] git-repository-url = "https://github.com/rust-lang/rust/tree/HEAD/src/doc/unstable-book" diff --git a/src/tools/error_index_generator/Cargo.toml b/src/tools/error_index_generator/Cargo.toml index 54fe7f6eb5a9b..9d0f3b061d476 100644 --- a/src/tools/error_index_generator/Cargo.toml +++ b/src/tools/error_index_generator/Cargo.toml @@ -5,7 +5,8 @@ edition = "2021" workspace = "../rustbook" [dependencies] -mdbook = { version = "0.4", default-features = false, features = ["search"] } +mdbook-driver = { version = "0.5.1", features = ["search"] } +mdbook-summary = "0.5.1" [[bin]] name = "error_index_generator" diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs index 58224aed14879..97ac47918c092 100644 --- a/src/tools/error_index_generator/main.rs +++ b/src/tools/error_index_generator/main.rs @@ -12,8 +12,10 @@ use std::io::Write; use std::path::{Path, PathBuf}; use std::str::FromStr; -use mdbook::book::{BookItem, Chapter, parse_summary}; -use mdbook::{Config, MDBook}; +use mdbook_driver::MDBook; +use mdbook_driver::book::{BookItem, Chapter}; +use mdbook_driver::config::Config; +use mdbook_summary::parse_summary; use rustc_errors::codes::DIAGNOSTICS; enum OutputFormat { @@ -121,7 +123,7 @@ This page lists all the error codes emitted by the Rust compiler. source_path: None, parent_names: Vec::new(), }; - book.book.sections.push(BookItem::Chapter(chapter)); + book.book.items.push(BookItem::Chapter(chapter)); book.build()?; // The error-index used to be generated manually (without mdbook), and the diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock index d5aa7a671636c..e7b04260e4a95 100644 --- a/src/tools/rustbook/Cargo.lock +++ b/src/tools/rustbook/Cargo.lock @@ -17,19 +17,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "ammonia" -version = "4.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17e913097e1a2124b46746c980134e8c954bc17a6a59bb3fde96f088d126dde6" -dependencies = [ - "cssparser", - "html5ever", - "maplit", - "tendril", - "url", -] - [[package]] name = "android_system_properties" version = "0.1.5" @@ -110,6 +97,21 @@ dependencies = [ "serde", ] +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + [[package]] name = "bitflags" version = "2.10.0" @@ -125,17 +127,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "bstr" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" -dependencies = [ - "memchr", - "regex-automata", - "serde", -] - [[package]] name = "bumpalo" version = "3.19.0" @@ -191,16 +182,6 @@ dependencies = [ "anstyle", "clap_lex", "strsim", - "terminal_size", -] - -[[package]] -name = "clap_complete" -version = "4.5.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e602857739c5a4291dfa33b5a298aeac9006185229a700e5810a3ef7272d971" -dependencies = [ - "clap", ] [[package]] @@ -261,29 +242,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "cssparser" -version = "0.35.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e901edd733a1472f944a45116df3f846f54d37e67e68640ac8bb69689aca2aa" -dependencies = [ - "cssparser-macros", - "dtoa-short", - "itoa", - "phf 0.11.3", - "smallvec", -] - -[[package]] -name = "cssparser-macros" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" -dependencies = [ - "quote", - "syn", -] - [[package]] name = "darling" version = "0.20.11" @@ -372,17 +330,6 @@ dependencies = [ "crypto-common", ] -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "doc-comment" version = "0.3.4" @@ -390,19 +337,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "780955b8b195a21ab8e4ac6b60dd1dbdcec1dc6c51c0617964b08c81785e12c9" [[package]] -name = "dtoa" -version = "1.0.10" +name = "ego-tree" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04" - -[[package]] -name = "dtoa-short" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" -dependencies = [ - "dtoa", -] +checksum = "b2972feb8dffe7bc8c5463b1dacda1b0dfbed3710e50f977d965429692d74cd8" [[package]] name = "elasticlunr-rs" @@ -416,29 +354,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "env_filter" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" -dependencies = [ - "log", - "regex", -] - -[[package]] -name = "env_logger" -version = "0.11.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" -dependencies = [ - "anstream", - "anstyle", - "env_filter", - "jiff", - "log", -] - [[package]] name = "equivalent" version = "1.0.2" @@ -459,7 +374,19 @@ dependencies = [ name = "error_index_generator" version = "0.0.0" dependencies = [ - "mdbook", + "mdbook-driver", + "mdbook-summary", +] + +[[package]] +name = "fancy-regex" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "998b056554fbe42e03ae0e152895cd1a7e1002aec800fdc6635d20270260c46f" +dependencies = [ + "bit-set", + "regex-automata", + "regex-syntax", ] [[package]] @@ -491,13 +418,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] -name = "form_urlencoded" -version = "1.2.2" +name = "font-awesome-as-a-crate" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" -dependencies = [ - "percent-encoding", -] +checksum = "932dcfbd51320af5f27f1ba02d2e567dec332cac7d2c221ba45d8e767264c4dc" [[package]] name = "futf" @@ -558,9 +482,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" [[package]] name = "heck" @@ -576,13 +500,12 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "html5ever" -version = "0.35.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55d958c2f74b664487a2035fe1dadb032c48718a03b63f3ab0b8537db8549ed4" +checksum = "6452c4751a24e1b99c3260d505eaeee76a050573e61f30ac2c924ddc7236f01e" dependencies = [ "log", "markup5ever", - "match_token", ] [[package]] @@ -624,119 +547,17 @@ dependencies = [ "cc", ] -[[package]] -name = "icu_collections" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" -dependencies = [ - "displaydoc", - "potential_utf", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locale_core" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_normalizer" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" -dependencies = [ - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" - -[[package]] -name = "icu_properties" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" -dependencies = [ - "icu_collections", - "icu_locale_core", - "icu_properties_data", - "icu_provider", - "zerotrie", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" - -[[package]] -name = "icu_provider" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" -dependencies = [ - "displaydoc", - "icu_locale_core", - "writeable", - "yoke", - "zerofrom", - "zerotrie", - "zerovec", -] - [[package]] name = "ident_case" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" -[[package]] -name = "idna" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - [[package]] name = "indexmap" -version = "2.12.0" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" +checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" dependencies = [ "equivalent", "hashbrown", @@ -754,30 +575,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" -[[package]] -name = "jiff" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49cce2b81f2098e7e3efc35bc2e0a6b7abec9d34128283d7a26fa8f32a6dbb35" -dependencies = [ - "jiff-static", - "log", - "portable-atomic", - "portable-atomic-util", - "serde_core", -] - -[[package]] -name = "jiff-static" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "980af8b43c3ad5d8d349ace167ec8170839f753a42d233ba19e08afe1850fa69" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "js-sys" version = "0.3.82" @@ -815,12 +612,6 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" -[[package]] -name = "litemap" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" - [[package]] name = "lock_api" version = "0.4.14" @@ -842,17 +633,11 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" -[[package]] -name = "maplit" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" - [[package]] name = "markup5ever" -version = "0.35.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "311fe69c934650f8f19652b3946075f0fc41ad8757dbb68f1ca14e7900ecc1c3" +checksum = "6c3294c4d74d0742910f8c7b466f44dda9eb2d5742c1e430138df290a1e8451c" dependencies = [ "log", "tendril", @@ -860,58 +645,91 @@ dependencies = [ ] [[package]] -name = "match_token" -version = "0.35.0" +name = "matchers" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac84fd3f360fcc43dc5f5d186f02a94192761a080e8bc58621ad4d12296a58cf" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" dependencies = [ - "proc-macro2", - "quote", - "syn", + "regex-automata", ] [[package]] -name = "mdbook" -version = "0.4.52" +name = "mdbook-core" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93c284d2855916af7c5919cf9ad897cfc77d3c2db6f55429c7cfb769182030ec" +checksum = "39a3873d4afac65583f1acb56ff058df989d5b4a2464bb02c785549727d307ee" dependencies = [ - "ammonia", "anyhow", - "chrono", - "clap", - "clap_complete", + "regex", + "serde", + "serde_json", + "toml 0.9.8", + "tracing", +] + +[[package]] +name = "mdbook-driver" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a229930b29a9908560883e1f386eae25d8a971d259a80f49916a50627f04a42d" +dependencies = [ + "anyhow", + "indexmap", + "mdbook-core", + "mdbook-html", + "mdbook-markdown", + "mdbook-preprocessor", + "mdbook-renderer", + "mdbook-summary", + "regex", + "serde", + "serde_json", + "shlex", + "tempfile", + "toml 0.9.8", + "topological-sort", + "tracing", +] + +[[package]] +name = "mdbook-html" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dee80c03c65e3212fb528b8c9be5568a6a85cf795d03cf9fd6ba39ad52069ca" +dependencies = [ + "anyhow", + "ego-tree", "elasticlunr-rs", - "env_logger", + "font-awesome-as-a-crate", "handlebars", "hex", - "log", - "memchr", - "opener", - "pulldown-cmark 0.10.3", + "html5ever", + "indexmap", + "mdbook-core", + "mdbook-markdown", + "mdbook-renderer", + "pulldown-cmark 0.13.0", "regex", "serde", "serde_json", "sha2", - "shlex", - "tempfile", - "toml 0.5.11", - "topological-sort", + "tracing", ] [[package]] name = "mdbook-i18n-helpers" -version = "0.3.6" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5644bf29b95683ea60979e30188221c374965c3a1dc0ad2d5c69e867dc0c09dc" +checksum = "82a64b6c27dc99a20968cc85a89dcfe0d36f82e2c9bc3b4342a2ffc55158822f" dependencies = [ "anyhow", "chrono", "dateparser", - "mdbook", + "mdbook-preprocessor", + "mdbook-renderer", "polib", - "pulldown-cmark 0.12.2", - "pulldown-cmark-to-cmark 20.0.1", + "pulldown-cmark 0.13.0", + "pulldown-cmark-to-cmark 21.1.0", "regex", "semver", "serde_json", @@ -919,15 +737,50 @@ dependencies = [ "textwrap", ] +[[package]] +name = "mdbook-markdown" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07c41bf35212f5d8b83e543aa6a4887dc5709c8489c5fb9ed00f1b51ce1a2cc6" +dependencies = [ + "pulldown-cmark 0.13.0", + "regex", + "tracing", +] + +[[package]] +name = "mdbook-preprocessor" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d87bf40be0597f26f0822f939a64f02bf92c4655ba04490aadbf83601a013bb" +dependencies = [ + "anyhow", + "mdbook-core", + "serde", + "serde_json", +] + +[[package]] +name = "mdbook-renderer" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93ed59f225b3ae4283c56bea633db83184627a090d892908bd66990c68e10b43" +dependencies = [ + "anyhow", + "mdbook-core", + "serde", + "serde_json", +] + [[package]] name = "mdbook-spec" version = "0.1.2" dependencies = [ "anyhow", - "mdbook", + "mdbook-markdown", + "mdbook-preprocessor", "once_cell", "pathdiff", - "pulldown-cmark 0.10.3", "railroad", "regex", "semver", @@ -936,6 +789,20 @@ dependencies = [ "walkdir", ] +[[package]] +name = "mdbook-summary" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c00d85b291d67a69c92e939450390fe34d6ea418a868c8f7b42f0b300af35a7b" +dependencies = [ + "anyhow", + "mdbook-core", + "memchr", + "pulldown-cmark 0.13.0", + "serde", + "tracing", +] + [[package]] name = "mdbook-trpl" version = "0.1.0" @@ -943,9 +810,10 @@ dependencies = [ "anyhow", "clap", "html_parser", - "mdbook", + "mdbook-preprocessor", "pulldown-cmark 0.12.2", "pulldown-cmark-to-cmark 19.0.1", + "serde", "serde_json", "thiserror 1.0.69", "toml 0.8.23", @@ -974,10 +842,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" [[package]] -name = "normpath" -version = "1.5.0" +name = "nu-ansi-term" +version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf23ab2b905654b4cb177e30b629937b3868311d4e1cba859f899c041046e69b" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ "windows-sys 0.61.2", ] @@ -1018,39 +886,6 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" -[[package]] -name = "onig" -version = "6.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "336b9c63443aceef14bea841b899035ae3abe89b7c486aaf4c5bd8aafedac3f0" -dependencies = [ - "bitflags", - "libc", - "once_cell", - "onig_sys", -] - -[[package]] -name = "onig_sys" -version = "69.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7f86c6eef3d6df15f23bcfb6af487cbd2fed4e5581d58d5bf1f5f8b7f6727dc" -dependencies = [ - "cc", - "pkg-config", -] - -[[package]] -name = "opener" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb9024962ab91e00c89d2a14352a8d0fc1a64346bf96f1839b45c09149564e47" -dependencies = [ - "bstr", - "normpath", - "windows-sys 0.60.2", -] - [[package]] name = "parking_lot" version = "0.12.5" @@ -1080,12 +915,6 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" -[[package]] -name = "percent-encoding" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" - [[package]] name = "pest" version = "2.8.3" @@ -1129,23 +958,13 @@ dependencies = [ "sha2", ] -[[package]] -name = "phf" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" -dependencies = [ - "phf_macros", - "phf_shared 0.11.3", -] - [[package]] name = "phf" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" dependencies = [ - "phf_shared 0.13.1", + "phf_shared", "serde", ] @@ -1155,18 +974,8 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49aa7f9d80421bca176ca8dbfebe668cc7a2684708594ec9f3c0db0805d5d6e1" dependencies = [ - "phf_generator 0.13.1", - "phf_shared 0.13.1", -] - -[[package]] -name = "phf_generator" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" -dependencies = [ - "phf_shared 0.11.3", - "rand", + "phf_generator", + "phf_shared", ] [[package]] @@ -1176,29 +985,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" dependencies = [ "fastrand", - "phf_shared 0.13.1", -] - -[[package]] -name = "phf_macros" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" -dependencies = [ - "phf_generator 0.11.3", - "phf_shared 0.11.3", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "phf_shared" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" -dependencies = [ - "siphasher", + "phf_shared", ] [[package]] @@ -1211,10 +998,10 @@ dependencies = [ ] [[package]] -name = "pkg-config" -version = "0.3.32" +name = "pin-project-lite" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "polib" @@ -1225,30 +1012,6 @@ dependencies = [ "linereader", ] -[[package]] -name = "portable-atomic" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" - -[[package]] -name = "portable-atomic-util" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" -dependencies = [ - "portable-atomic", -] - -[[package]] -name = "potential_utf" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" -dependencies = [ - "zerovec", -] - [[package]] name = "precomputed-hash" version = "0.1.1" @@ -1266,35 +1029,29 @@ dependencies = [ [[package]] name = "pulldown-cmark" -version = "0.10.3" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76979bea66e7875e7509c4ec5300112b316af87fa7a252ca91c448b32dfe3993" +checksum = "f86ba2052aebccc42cbbb3ed234b8b13ce76f75c3551a303cb2bcffcff12bb14" dependencies = [ "bitflags", + "getopts", "memchr", - "pulldown-cmark-escape 0.10.1", + "pulldown-cmark-escape", "unicase", ] [[package]] name = "pulldown-cmark" -version = "0.12.2" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f86ba2052aebccc42cbbb3ed234b8b13ce76f75c3551a303cb2bcffcff12bb14" +checksum = "1e8bbe1a966bd2f362681a44f6edce3c2310ac21e4d5067a6e7ec396297a6ea0" dependencies = [ "bitflags", - "getopts", "memchr", - "pulldown-cmark-escape 0.11.0", + "pulldown-cmark-escape", "unicase", ] -[[package]] -name = "pulldown-cmark-escape" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd348ff538bc9caeda7ee8cad2d1d48236a1f443c1fa3913c6a02fe0043b1dd3" - [[package]] name = "pulldown-cmark-escape" version = "0.11.0" @@ -1312,11 +1069,11 @@ dependencies = [ [[package]] name = "pulldown-cmark-to-cmark" -version = "20.0.1" +version = "21.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c0f333311d2d8fda65bcf76af35054e9f38e253332a0289746156a59656988b" +checksum = "8246feae3db61428fd0bb94285c690b460e4517d83152377543ca802357785f1" dependencies = [ - "pulldown-cmark 0.12.2", + "pulldown-cmark 0.13.0", ] [[package]] @@ -1343,21 +1100,6 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" - [[package]] name = "redox_syscall" version = "0.5.18" @@ -1401,12 +1143,11 @@ name = "rustbook" version = "0.1.0" dependencies = [ "clap", - "env_logger", - "libc", - "mdbook", + "mdbook-driver", "mdbook-i18n-helpers", "mdbook-spec", "mdbook-trpl", + "tracing-subscriber", ] [[package]] @@ -1507,6 +1248,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e24345aa0fe688594e73770a5f6d1b216508b4f93484c0026d521acd30134392" +dependencies = [ + "serde_core", +] + [[package]] name = "sha2" version = "0.10.9" @@ -1518,6 +1268,15 @@ dependencies = [ "digest", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "shlex" version = "1.3.0" @@ -1542,12 +1301,6 @@ version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" -[[package]] -name = "stable_deref_trait" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" - [[package]] name = "string_cache" version = "0.9.0" @@ -1556,7 +1309,7 @@ checksum = "a18596f8c785a729f2819c0f6a7eae6ebeebdfffbfe4214ae6b087f690e31901" dependencies = [ "new_debug_unreachable", "parking_lot", - "phf_shared 0.13.1", + "phf_shared", "precomputed-hash", "serde", ] @@ -1567,8 +1320,8 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "585635e46db231059f76c5849798146164652513eb9e8ab2685939dd90f29b69" dependencies = [ - "phf_generator 0.13.1", - "phf_shared 0.13.1", + "phf_generator", + "phf_shared", "proc-macro2", "quote", ] @@ -1590,17 +1343,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "synstructure" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "syntect" version = "5.3.0" @@ -1608,10 +1350,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "656b45c05d95a5704399aeef6bd0ddec7b2b3531b7c9e900abbf7c4d2190c925" dependencies = [ "bincode", + "fancy-regex", "flate2", "fnv", "once_cell", - "onig", "regex-syntax", "serde", "serde_derive", @@ -1643,16 +1385,6 @@ dependencies = [ "utf-8", ] -[[package]] -name = "terminal_size" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b8cb979cb11c32ce1603f8137b22262a9d131aaa5c37b5678025f22b8becd0" -dependencies = [ - "rustix", - "windows-sys 0.60.2", -] - [[package]] name = "textwrap" version = "0.16.2" @@ -1700,34 +1432,39 @@ dependencies = [ ] [[package]] -name = "tinystr" -version = "0.8.2" +name = "thread_local" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" dependencies = [ - "displaydoc", - "zerovec", + "cfg-if", ] [[package]] name = "toml" -version = "0.5.11" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", + "toml_edit", ] [[package]] name = "toml" -version = "0.8.23" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8" dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", + "indexmap", + "serde_core", + "serde_spanned 1.0.3", + "toml_datetime 0.7.3", + "toml_parser", + "toml_writer", + "winnow", ] [[package]] @@ -1739,6 +1476,15 @@ dependencies = [ "serde", ] +[[package]] +name = "toml_datetime" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" +dependencies = [ + "serde_core", +] + [[package]] name = "toml_edit" version = "0.22.27" @@ -1747,24 +1493,100 @@ checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap", "serde", - "serde_spanned", - "toml_datetime", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", "toml_write", "winnow", ] +[[package]] +name = "toml_parser" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" +dependencies = [ + "winnow", +] + [[package]] name = "toml_write" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" +[[package]] +name = "toml_writer" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df8b2b54733674ad286d16267dcfc7a71ed5c776e4ac7aa3c3e2561f7c637bf2" + [[package]] name = "topological-sort" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea68304e134ecd095ac6c3574494fc62b909f416c4fca77e440530221e549d3d" +[[package]] +name = "tracing" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d15d90a0b5c19378952d479dc858407149d7bb45a14de0142f6c534b16fc647" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + [[package]] name = "typenum" version = "1.19.0" @@ -1795,36 +1617,24 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" -[[package]] -name = "url" -version = "2.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", - "serde", -] - [[package]] name = "utf-8" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - [[package]] name = "utf8parse" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + [[package]] name = "version_check" version = "0.9.5" @@ -1897,11 +1707,11 @@ dependencies = [ [[package]] name = "web_atoms" -version = "0.1.4" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44b72896d90cfd22c495d0ee4960d3dd20ca64180895cb92cd5342ff7482a579" +checksum = "acd0c322f146d0f8aad130ce6c187953889359584497dac6561204c8e17bb43d" dependencies = [ - "phf 0.13.1", + "phf", "phf_codegen", "string_cache", "string_cache_codegen", @@ -2072,86 +1882,3 @@ name = "wit-bindgen" version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" - -[[package]] -name = "writeable" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" - -[[package]] -name = "yoke" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" -dependencies = [ - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zerofrom" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zerotrie" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", -] - -[[package]] -name = "zerovec" -version = "0.11.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml index 1a5b2c29d20be..2815f09105b1b 100644 --- a/src/tools/rustbook/Cargo.toml +++ b/src/tools/rustbook/Cargo.toml @@ -8,14 +8,9 @@ license = "MIT OR Apache-2.0" edition = "2021" [dependencies] -clap = "4.0.32" -env_logger = "0.11" -libc = "0.2" -mdbook-trpl = { path = "../../doc/book/packages/mdbook-trpl" } -mdbook-i18n-helpers = "0.3.3" +clap = { version = "4.0.32", features = ["cargo"] } +mdbook-driver = { version = "0.5.2", features = ["search"] } +mdbook-i18n-helpers = "0.4.0" mdbook-spec = { path = "../../doc/reference/mdbook-spec" } - -[dependencies.mdbook] -version = "0.4.52" -default-features = false -features = ["search"] +mdbook-trpl = { path = "../../doc/book/packages/mdbook-trpl" } +tracing-subscriber = { version = "0.3.20", features = ["env-filter"] } diff --git a/src/tools/rustbook/src/main.rs b/src/tools/rustbook/src/main.rs index 4b510e308c977..5410524028205 100644 --- a/src/tools/rustbook/src/main.rs +++ b/src/tools/rustbook/src/main.rs @@ -2,15 +2,27 @@ use std::env; use std::path::{Path, PathBuf}; use clap::{ArgMatches, Command, arg, crate_version}; -use mdbook::MDBook; -use mdbook::errors::Result as Result3; +use mdbook_driver::MDBook; +use mdbook_driver::errors::Result as Result3; use mdbook_i18n_helpers::preprocessors::Gettext; use mdbook_spec::Spec; use mdbook_trpl::{Figure, Listing, Note}; fn main() { let crate_version = concat!("v", crate_version!()); - env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("warn")).init(); + let filter = tracing_subscriber::EnvFilter::builder() + .with_env_var("MDBOOK_LOG") + .with_default_directive(tracing_subscriber::filter::LevelFilter::INFO.into()) + .from_env_lossy(); + tracing_subscriber::fmt() + .without_time() + .with_ansi(std::io::IsTerminal::is_terminal(&std::io::stderr())) + .with_writer(std::io::stderr) + .with_env_filter(filter) + .with_target(std::env::var_os("MDBOOK_LOG").is_some()) + .init(); + + // env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init(); let d_arg = arg!(-d --"dest-dir" "The output directory for your book\n(Defaults to ./book when omitted)") .required(false) @@ -82,12 +94,45 @@ fn main() { }; } -// Build command implementation -pub fn build(args: &ArgMatches) -> Result3<()> { +fn build(args: &ArgMatches) -> Result3<()> { let book_dir = get_book_dir(args); - let mut book = load_book(&book_dir)?; + let dest_dir = args.get_one::("dest-dir"); + let lang = args.get_one::("lang"); + let rust_root = args.get_one::("rust-root"); + let book = load_book(&book_dir, dest_dir, lang, rust_root.cloned())?; + book.build() +} + +fn test(args: &ArgMatches) -> Result3<()> { + let book_dir = get_book_dir(args); + let mut book = load_book(&book_dir, None, None, None)?; + let library_paths = args + .try_get_one::>("library-path")? + .map(|v| v.iter().map(|s| s.as_str()).collect::>()) + .unwrap_or_default(); + book.test(library_paths) +} + +fn get_book_dir(args: &ArgMatches) -> PathBuf { + if let Some(p) = args.get_one::("dir") { + // Check if path is relative from current dir, or absolute... + if p.is_relative() { env::current_dir().unwrap().join(p) } else { p.to_path_buf() } + } else { + env::current_dir().unwrap() + } +} + +fn load_book( + book_dir: &Path, + dest_dir: Option<&PathBuf>, + lang: Option<&String>, + rust_root: Option, +) -> Result3 { + let mut book = MDBook::load(book_dir)?; + book.config.set("output.html.input-404", "").unwrap(); + book.config.set("output.html.hash-files", true).unwrap(); - if let Some(lang) = args.get_one::("lang") { + if let Some(lang) = lang { let gettext = Gettext; book.with_preprocessor(gettext); book.config.set("book.language", lang).unwrap(); @@ -96,7 +141,7 @@ pub fn build(args: &ArgMatches) -> Result3<()> { // Set this to allow us to catch bugs in advance. book.config.build.create_missing = false; - if let Some(dest_dir) = args.get_one::("dest-dir") { + if let Some(dest_dir) = dest_dir { book.config.build.build_dir = dest_dir.into(); } @@ -107,51 +152,22 @@ pub fn build(args: &ArgMatches) -> Result3<()> { // This should probably be fixed in mdbook to remove the existing // preprocessor, or this should modify the config and use // MDBook::load_with_config. - if book.config.get_preprocessor("trpl-note").is_some() { + if book.config.contains_key("preprocessor.trpl-note") { book.with_preprocessor(Note); } - if book.config.get_preprocessor("trpl-listing").is_some() { + if book.config.contains_key("preprocessor.trpl-listing") { book.with_preprocessor(Listing); } - if book.config.get_preprocessor("trpl-figure").is_some() { + if book.config.contains_key("preprocessor.trpl-figure") { book.with_preprocessor(Figure); } - if book.config.get_preprocessor("spec").is_some() { - let rust_root = args.get_one::("rust-root").cloned(); + if book.config.contains_key("preprocessor.spec") { book.with_preprocessor(Spec::new(rust_root)?); } - book.build()?; - - Ok(()) -} - -fn test(args: &ArgMatches) -> Result3<()> { - let book_dir = get_book_dir(args); - let library_paths = args - .try_get_one::>("library-path")? - .map(|v| v.iter().map(|s| s.as_str()).collect::>()) - .unwrap_or_default(); - let mut book = load_book(&book_dir)?; - book.test(library_paths) -} - -fn get_book_dir(args: &ArgMatches) -> PathBuf { - if let Some(p) = args.get_one::("dir") { - // Check if path is relative from current dir, or absolute... - if p.is_relative() { env::current_dir().unwrap().join(p) } else { p.to_path_buf() } - } else { - env::current_dir().unwrap() - } -} - -fn load_book(book_dir: &Path) -> Result3 { - let mut book = MDBook::load(book_dir)?; - book.config.set("output.html.input-404", "").unwrap(); - book.config.set("output.html.hash-files", true).unwrap(); Ok(book) } @@ -159,7 +175,7 @@ fn parse_library_paths(input: &str) -> Result, String> { Ok(input.split(",").map(String::from).collect()) } -fn handle_error(error: mdbook::errors::Error) -> ! { +fn handle_error(error: mdbook_driver::errors::Error) -> ! { eprintln!("Error: {}", error); for cause in error.chain().skip(1) { diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 592ba9c5c7946..f374a1e01496c 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -222,10 +222,14 @@ const EXCEPTIONS_RUSTC_PERF: ExceptionList = &[ const EXCEPTIONS_RUSTBOOK: ExceptionList = &[ // tidy-alphabetical-start - ("cssparser", "MPL-2.0"), - ("cssparser-macros", "MPL-2.0"), - ("dtoa-short", "MPL-2.0"), - ("mdbook", "MPL-2.0"), + ("font-awesome-as-a-crate", "CC-BY-4.0 AND MIT"), + ("mdbook-core", "MPL-2.0"), + ("mdbook-driver", "MPL-2.0"), + ("mdbook-html", "MPL-2.0"), + ("mdbook-markdown", "MPL-2.0"), + ("mdbook-preprocessor", "MPL-2.0"), + ("mdbook-renderer", "MPL-2.0"), + ("mdbook-summary", "MPL-2.0"), // tidy-alphabetical-end ]; From e39e127bd0d2baa51b57671f1fa00d0c4e7afbbb Mon Sep 17 00:00:00 2001 From: Oleksii Lozovskyi Date: Sat, 13 Dec 2025 16:19:33 +0900 Subject: [PATCH 07/13] libtest: Stricter XML validation Expect the entire input to be a single XML document, instead of reading it line by line. This detects trailing junk better. --- tests/run-make/libtest-junit/validate_junit.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/run-make/libtest-junit/validate_junit.py b/tests/run-make/libtest-junit/validate_junit.py index f92473751b036..a9cb0a059563d 100755 --- a/tests/run-make/libtest-junit/validate_junit.py +++ b/tests/run-make/libtest-junit/validate_junit.py @@ -13,10 +13,10 @@ import sys import xml.etree.ElementTree as ET -# Try to decode line in order to ensure it is a valid XML document -for line in sys.stdin: - try: - ET.fromstring(line) - except ET.ParseError: - print("Invalid xml: %r" % line) - raise +# Read the entire output and try to decode it as XML. +junit = sys.stdin.read() +try: + ET.fromstring(junit) +except ET.ParseError: + print("Invalid xml: %r" % junit) + raise From 2cc434863c56a925d56e979cbfb1d824040d1cd7 Mon Sep 17 00:00:00 2001 From: Oleksii Lozovskyi Date: Sat, 13 Dec 2025 14:29:44 +0900 Subject: [PATCH 08/13] rustdoc: Test --format=junit Copied validate_junit.py from libtest-junit. JUnit format works well in edition 2021, but is currently broken in edition 2024 by the mergeable doctest report. --- .../run-make/doctests-junit/doctest-2021.xml | 1 + tests/run-make/doctests-junit/doctest.rs | 14 ++++ tests/run-make/doctests-junit/rmake.rs | 72 +++++++++++++++++++ .../run-make/doctests-junit/validate_junit.py | 22 ++++++ 4 files changed, 109 insertions(+) create mode 100644 tests/run-make/doctests-junit/doctest-2021.xml create mode 100644 tests/run-make/doctests-junit/doctest.rs create mode 100644 tests/run-make/doctests-junit/rmake.rs create mode 100755 tests/run-make/doctests-junit/validate_junit.py diff --git a/tests/run-make/doctests-junit/doctest-2021.xml b/tests/run-make/doctests-junit/doctest-2021.xml new file mode 100644 index 0000000000000..5facfb80ce622 --- /dev/null +++ b/tests/run-make/doctests-junit/doctest-2021.xml @@ -0,0 +1 @@ + diff --git a/tests/run-make/doctests-junit/doctest.rs b/tests/run-make/doctests-junit/doctest.rs new file mode 100644 index 0000000000000..1873d63a49c63 --- /dev/null +++ b/tests/run-make/doctests-junit/doctest.rs @@ -0,0 +1,14 @@ +/// ``` +/// assert_eq!(doctest::add(2, 2), 4); +/// ``` +/// +/// ```should_panic +/// assert_eq!(doctest::add(2, 2), 5); +/// ``` +/// +/// ```compile_fail +/// assert_eq!(doctest::add(2, 2), "banana"); +/// ``` +pub fn add(a: i32, b: i32) -> i32 { + a + b +} diff --git a/tests/run-make/doctests-junit/rmake.rs b/tests/run-make/doctests-junit/rmake.rs new file mode 100644 index 0000000000000..40dc541b5d2ce --- /dev/null +++ b/tests/run-make/doctests-junit/rmake.rs @@ -0,0 +1,72 @@ +// Check rustdoc's test JUnit (XML) output against snapshots. + +//@ ignore-cross-compile (running doctests) +//@ needs-unwind (test file contains `should_panic` test) + +use std::path::Path; + +use run_make_support::{cwd, diff, python_command, rustc, rustdoc}; + +fn main() { + let rlib = cwd().join("libdoctest.rlib"); + rustc().input("doctest.rs").crate_type("rlib").output(&rlib).run(); + + run_doctests(&rlib, "2021", "doctest-2021.xml"); + run_doctests_fail(&rlib, "2024"); +} + +#[track_caller] +fn run_doctests(rlib: &Path, edition: &str, expected_xml: &str) { + let rustdoc_out = rustdoc() + .input("doctest.rs") + .args(&[ + "--test", + "--test-args=-Zunstable-options", + "--test-args=--test-threads=1", + "--test-args=--format=junit", + ]) + .edition(edition) + .env("RUST_BACKTRACE", "0") + .extern_("doctest", rlib.display().to_string()) + .run(); + let rustdoc_stdout = &rustdoc_out.stdout_utf8(); + + python_command().arg("validate_junit.py").stdin_buf(rustdoc_stdout).run(); + + diff() + .expected_file(expected_xml) + .actual_text("output", rustdoc_stdout) + .normalize(r#"\btime="[0-9.]+""#, r#"time="$$TIME""#) + .run(); +} + +// FIXME: gone in the next patch +#[track_caller] +fn run_doctests_fail(rlib: &Path, edition: &str) { + let rustdoc_out = rustdoc() + .input("doctest.rs") + .args(&[ + "--test", + "--test-args=-Zunstable-options", + "--test-args=--test-threads=1", + "--test-args=--format=junit", + ]) + .edition(edition) + .env("RUST_BACKTRACE", "0") + .extern_("doctest", rlib.display().to_string()) + .run_fail(); + let rustdoc_stderr = &rustdoc_out.stderr_utf8(); + + diff() + .expected_text( + "expected", + r#" +thread 'main' ($TID) panicked at library/test/src/formatters/junit.rs:22:9: +assertion failed: !s.contains('\n') +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +"#, + ) + .actual_text("actual", rustdoc_stderr) + .normalize(r#"thread 'main' \([0-9]+\)"#, r#"thread 'main' ($$TID)"#) + .run(); +} diff --git a/tests/run-make/doctests-junit/validate_junit.py b/tests/run-make/doctests-junit/validate_junit.py new file mode 100755 index 0000000000000..a9cb0a059563d --- /dev/null +++ b/tests/run-make/doctests-junit/validate_junit.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python + +# Trivial Python script that reads lines from stdin, and checks that each line +# is a well-formed XML document. +# +# This takes advantage of the fact that Python has a built-in XML parser, +# whereas doing the same check in Rust would require us to pull in an XML +# crate just for this relatively-minor test. +# +# If you're trying to remove Python scripts from the test suite, think twice +# before removing this one. You could do so, but it's probably not worth it. + +import sys +import xml.etree.ElementTree as ET + +# Read the entire output and try to decode it as XML. +junit = sys.stdin.read() +try: + ET.fromstring(junit) +except ET.ParseError: + print("Invalid xml: %r" % junit) + raise From 069cf9dfc906452d90d4e2898eac568fb558d25d Mon Sep 17 00:00:00 2001 From: Oleksii Lozovskyi Date: Sat, 29 Nov 2025 09:46:48 +0900 Subject: [PATCH 09/13] rustdoc: Write newline differently Fix the panic in write_message() which expects messages to contain no embedded newlines. We still want a trailing newline at the end of the file though, so write it in different manner. Doctest runner no longer panics, but the output is kinda broken when `compile_fail` doctests are present. This is because they are not mergeable. --- library/test/src/formatters/junit.rs | 6 ++- .../run-make/doctests-junit/doctest-2024.xml | 3 ++ tests/run-make/doctests-junit/rmake.rs | 40 +++---------------- 3 files changed, 13 insertions(+), 36 deletions(-) create mode 100644 tests/run-make/doctests-junit/doctest-2024.xml diff --git a/library/test/src/formatters/junit.rs b/library/test/src/formatters/junit.rs index 1566f1cb1dac6..74d99e0f1270e 100644 --- a/library/test/src/formatters/junit.rs +++ b/library/test/src/formatters/junit.rs @@ -189,8 +189,10 @@ impl OutputFormatter for JunitFormatter { compilation_time: f64, ) -> io::Result<()> { self.write_message(&format!( - "\n", - )) + "", + ))?; + self.out.write_all(b"\n")?; + Ok(()) } } diff --git a/tests/run-make/doctests-junit/doctest-2024.xml b/tests/run-make/doctests-junit/doctest-2024.xml new file mode 100644 index 0000000000000..4f94f01c3e32c --- /dev/null +++ b/tests/run-make/doctests-junit/doctest-2024.xml @@ -0,0 +1,3 @@ + + + diff --git a/tests/run-make/doctests-junit/rmake.rs b/tests/run-make/doctests-junit/rmake.rs index 40dc541b5d2ce..4cc7ac7c31d7f 100644 --- a/tests/run-make/doctests-junit/rmake.rs +++ b/tests/run-make/doctests-junit/rmake.rs @@ -12,7 +12,7 @@ fn main() { rustc().input("doctest.rs").crate_type("rlib").output(&rlib).run(); run_doctests(&rlib, "2021", "doctest-2021.xml"); - run_doctests_fail(&rlib, "2024"); + run_doctests(&rlib, "2024", "doctest-2024.xml"); } #[track_caller] @@ -31,42 +31,14 @@ fn run_doctests(rlib: &Path, edition: &str, expected_xml: &str) { .run(); let rustdoc_stdout = &rustdoc_out.stdout_utf8(); - python_command().arg("validate_junit.py").stdin_buf(rustdoc_stdout).run(); + // FIXME: merged output of compile_fail tests is broken + if edition != "2024" { + python_command().arg("validate_junit.py").stdin_buf(rustdoc_stdout).run(); + } diff() .expected_file(expected_xml) .actual_text("output", rustdoc_stdout) - .normalize(r#"\btime="[0-9.]+""#, r#"time="$$TIME""#) - .run(); -} - -// FIXME: gone in the next patch -#[track_caller] -fn run_doctests_fail(rlib: &Path, edition: &str) { - let rustdoc_out = rustdoc() - .input("doctest.rs") - .args(&[ - "--test", - "--test-args=-Zunstable-options", - "--test-args=--test-threads=1", - "--test-args=--format=junit", - ]) - .edition(edition) - .env("RUST_BACKTRACE", "0") - .extern_("doctest", rlib.display().to_string()) - .run_fail(); - let rustdoc_stderr = &rustdoc_out.stderr_utf8(); - - diff() - .expected_text( - "expected", - r#" -thread 'main' ($TID) panicked at library/test/src/formatters/junit.rs:22:9: -assertion failed: !s.contains('\n') -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -"#, - ) - .actual_text("actual", rustdoc_stderr) - .normalize(r#"thread 'main' \([0-9]+\)"#, r#"thread 'main' ($$TID)"#) + .normalize(r#"\b(time|total_time|compilation_time)="[0-9.]+""#, r#"$1="$$TIME""#) .run(); } From 1b9b4f4dc69302c80925ed910e7e94766d88db63 Mon Sep 17 00:00:00 2001 From: Clara Engler Date: Sat, 13 Dec 2025 10:12:17 +0100 Subject: [PATCH 10/13] time: Test and document time precision edge-case There is a slight edge case when adding and subtracting a `Duration` from a `SystemTime`, namely when the duration itself is finer/smaller than the time precision on the operating systems. On most (if not all non-Windows) operating systems, the precision of `Duration` aligns with the `SystemTime`, both being one nanosecond. However, on Windows, this time precision is 100ns, meaning that adding or subtracting a `Duration` whose value is `< Duration::new(0, 100)` will result in that method behaving like an addition/subtracting of `Duration::ZERO`, due to the `Duration` getting rounded-down to the zero value. --- library/std/src/time.rs | 32 ++++++++++++++++++++++++++------ library/std/tests/time.rs | 17 ++++++++++++----- 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/library/std/src/time.rs b/library/std/src/time.rs index 0bda83af4dfb6..67c144be14f6d 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -514,7 +514,9 @@ impl SystemTime { /// Represents the maximum value representable by [`SystemTime`] on this platform. /// /// This value differs a lot between platforms, but it is always the case - /// that any positive addition to [`SystemTime::MAX`] will fail. + /// that any positive addition of a [`Duration`], whose value is greater + /// than or equal to the time precision of the operating system, to + /// [`SystemTime::MAX`] will fail. /// /// # Examples /// @@ -525,8 +527,13 @@ impl SystemTime { /// // Adding zero will change nothing. /// assert_eq!(SystemTime::MAX.checked_add(Duration::ZERO), Some(SystemTime::MAX)); /// - /// // But adding just 1ns will already fail. - /// assert_eq!(SystemTime::MAX.checked_add(Duration::new(0, 1)), None); + /// // But adding just one second will already fail ... + /// // + /// // Keep in mind that this in fact may succeed, if the Duration is + /// // smaller than the time precision of the operating system, which + /// // happens to be 1ns on most operating systems, with Windows being the + /// // notable exception by using 100ns, hence why this example uses 1s. + /// assert_eq!(SystemTime::MAX.checked_add(Duration::new(1, 0)), None); /// /// // Utilize this for saturating arithmetic to improve error handling. /// // In this case, we will use a certificate with a timestamp in the @@ -543,7 +550,9 @@ impl SystemTime { /// Represents the minimum value representable by [`SystemTime`] on this platform. /// /// This value differs a lot between platforms, but it is always the case - /// that any positive subtraction from [`SystemTime::MIN`] will fail. + /// that any positive subtraction of a [`Duration`] from, whose value is + /// greater than or equal to the time precision of the operating system, to + /// [`SystemTime::MIN`] will fail. /// /// Depending on the platform, this may be either less than or equal to /// [`SystemTime::UNIX_EPOCH`], depending on whether the operating system @@ -560,8 +569,13 @@ impl SystemTime { /// // Subtracting zero will change nothing. /// assert_eq!(SystemTime::MIN.checked_sub(Duration::ZERO), Some(SystemTime::MIN)); /// - /// // But subtracting just 1ns will already fail. - /// assert_eq!(SystemTime::MIN.checked_sub(Duration::new(0, 1)), None); + /// // But subtracting just one second will already fail. + /// // + /// // Keep in mind that this in fact may succeed, if the Duration is + /// // smaller than the time precision of the operating system, which + /// // happens to be 1ns on most operating systems, with Windows being the + /// // notable exception by using 100ns, hence why this example uses 1s. + /// assert_eq!(SystemTime::MIN.checked_sub(Duration::new(1, 0)), None); /// /// // Utilize this for saturating arithmetic to improve error handling. /// // In this case, we will use a cache expiry as a practical example. @@ -651,6 +665,9 @@ impl SystemTime { /// Returns `Some(t)` where `t` is the time `self + duration` if `t` can be represented as /// `SystemTime` (which means it's inside the bounds of the underlying data structure), `None` /// otherwise. + /// + /// In the case that the `duration` is smaller than the time precision of the operating + /// system, `Some(self)` will be returned. #[stable(feature = "time_checked_add", since = "1.34.0")] pub fn checked_add(&self, duration: Duration) -> Option { self.0.checked_add_duration(&duration).map(SystemTime) @@ -659,6 +676,9 @@ impl SystemTime { /// Returns `Some(t)` where `t` is the time `self - duration` if `t` can be represented as /// `SystemTime` (which means it's inside the bounds of the underlying data structure), `None` /// otherwise. + /// + /// In the case that the `duration` is smaller than the time precision of the operating + /// system, `Some(self)` will be returned. #[stable(feature = "time_checked_add", since = "1.34.0")] pub fn checked_sub(&self, duration: Duration) -> Option { self.0.checked_sub_duration(&duration).map(SystemTime) diff --git a/library/std/tests/time.rs b/library/std/tests/time.rs index 31cc7171fe52e..0ef89bb09c637 100644 --- a/library/std/tests/time.rs +++ b/library/std/tests/time.rs @@ -250,15 +250,22 @@ fn system_time_duration_since_max_range_on_unix() { #[test] fn system_time_max_min() { + #[cfg(not(target_os = "windows"))] + /// Most (all?) non-Windows systems have nanosecond precision. + const MIN_INTERVAL: Duration = Duration::new(0, 1); + #[cfg(target_os = "windows")] + /// Windows' time precision is at 100ns. + const MIN_INTERVAL: Duration = Duration::new(0, 100); + // First, test everything with checked_* and Duration::ZERO. assert_eq!(SystemTime::MAX.checked_add(Duration::ZERO), Some(SystemTime::MAX)); assert_eq!(SystemTime::MAX.checked_sub(Duration::ZERO), Some(SystemTime::MAX)); assert_eq!(SystemTime::MIN.checked_add(Duration::ZERO), Some(SystemTime::MIN)); assert_eq!(SystemTime::MIN.checked_sub(Duration::ZERO), Some(SystemTime::MIN)); - // Now do the same again with checked_* but try by ± a single nanosecond. - assert!(SystemTime::MAX.checked_add(Duration::new(0, 1)).is_none()); - assert!(SystemTime::MAX.checked_sub(Duration::new(0, 1)).is_some()); - assert!(SystemTime::MIN.checked_add(Duration::new(0, 1)).is_some()); - assert!(SystemTime::MIN.checked_sub(Duration::new(0, 1)).is_none()); + // Now do the same again with checked_* but try by ± the lowest time precision. + assert!(SystemTime::MAX.checked_add(MIN_INTERVAL).is_none()); + assert!(SystemTime::MAX.checked_sub(MIN_INTERVAL).is_some()); + assert!(SystemTime::MIN.checked_add(MIN_INTERVAL).is_some()); + assert!(SystemTime::MIN.checked_sub(MIN_INTERVAL).is_none()); } From 0ecf91a701b0c4258dba75acde7dadf0586c7ed2 Mon Sep 17 00:00:00 2001 From: nxsaken Date: Sat, 13 Dec 2025 14:00:44 +0400 Subject: [PATCH 11/13] Use an explicit receiver in `DropGuard::dismiss` --- library/core/src/mem/drop_guard.rs | 10 +++++----- library/coretests/tests/mem.rs | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/library/core/src/mem/drop_guard.rs b/library/core/src/mem/drop_guard.rs index 013134727b7f0..74bf353907455 100644 --- a/library/core/src/mem/drop_guard.rs +++ b/library/core/src/mem/drop_guard.rs @@ -79,30 +79,30 @@ where /// /// let value = String::from("Nori likes chicken"); /// let guard = DropGuard::new(value, |s| println!("{s}")); - /// assert_eq!(guard.dismiss(), "Nori likes chicken"); + /// assert_eq!(DropGuard::dismiss(guard), "Nori likes chicken"); /// ``` #[unstable(feature = "drop_guard", issue = "144426")] #[rustc_const_unstable(feature = "const_drop_guard", issue = "none")] #[inline] - pub const fn dismiss(self) -> T + pub const fn dismiss(guard: Self) -> T where F: [const] Destruct, { // First we ensure that dropping the guard will not trigger // its destructor - let mut this = ManuallyDrop::new(self); + let mut guard = ManuallyDrop::new(guard); // Next we manually read the stored value from the guard. // // SAFETY: this is safe because we've taken ownership of the guard. - let value = unsafe { ManuallyDrop::take(&mut this.inner) }; + let value = unsafe { ManuallyDrop::take(&mut guard.inner) }; // Finally we drop the stored closure. We do this *after* having read // the value, so that even if the closure's `drop` function panics, // unwinding still tries to drop the value. // // SAFETY: this is safe because we've taken ownership of the guard. - unsafe { ManuallyDrop::drop(&mut this.f) }; + unsafe { ManuallyDrop::drop(&mut guard.f) }; value } } diff --git a/library/coretests/tests/mem.rs b/library/coretests/tests/mem.rs index 00582109aa2c5..5247e01fba01b 100644 --- a/library/coretests/tests/mem.rs +++ b/library/coretests/tests/mem.rs @@ -815,7 +815,7 @@ fn drop_guard_into_inner() { let dropped = Cell::new(false); let value = DropGuard::new(42, |_| dropped.set(true)); let guard = DropGuard::new(value, |_| dropped.set(true)); - let inner = guard.dismiss(); + let inner = DropGuard::dismiss(guard); assert_eq!(dropped.get(), false); assert_eq!(*inner, 42); } @@ -837,7 +837,7 @@ fn drop_guard_always_drops_value_if_closure_drop_unwinds() { // run the destructor of the value we passed, which we validate. let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { let guard = DropGuard::new(value_with_tracked_destruction, closure_that_panics_on_drop); - guard.dismiss(); + DropGuard::dismiss(guard); })); assert!(value_was_dropped); } From d80348b6c9c72c8d9bd32e764c531958160d6327 Mon Sep 17 00:00:00 2001 From: Clara Engler Date: Sat, 13 Dec 2025 10:09:20 +0100 Subject: [PATCH 12/13] time: Fix Windows' `SystemTime::checked_sub` The Windows implementation of `SystemTime::checked_sub` contains a bug, namely that it does not return `None` on values below 1601. This bug stems from the fact that internally, the time gets converted to an i64, with zero representing the anchor in 1601. Of course, performing checked subtraction on a signed integer generally works fine. However, the resulting value delivers undefined behavior on Windows systems. To mitigate this issue, we try to convert the resulting i64 to an u64 because a negative value should obviously fail there. --- library/std/src/sys/pal/windows/time.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/pal/windows/time.rs b/library/std/src/sys/pal/windows/time.rs index 88f4d4cdbd615..6cccf090a3fcf 100644 --- a/library/std/src/sys/pal/windows/time.rs +++ b/library/std/src/sys/pal/windows/time.rs @@ -111,8 +111,13 @@ impl SystemTime { } pub fn checked_sub_duration(&self, other: &Duration) -> Option { - let intervals = self.intervals().checked_sub(checked_dur2intervals(other)?)?; - Some(SystemTime::from_intervals(intervals)) + // Windows does not support times before 1601, hence why we don't + // support negatives. In order to tackle this, we try to convert the + // resulting value into an u64, which should obviously fail in the case + // that the value is below zero. + let intervals: u64 = + self.intervals().checked_sub(checked_dur2intervals(other)?)?.try_into().ok()?; + Some(SystemTime::from_intervals(intervals as i64)) } } From d484f9361eef9078b729990fd1ba8a40af8bdb6f Mon Sep 17 00:00:00 2001 From: Eli Ozcan <62805599+elijah629@users.noreply.github.com> Date: Sat, 13 Dec 2025 17:12:28 +0000 Subject: [PATCH 13/13] Fix typo in armv7a-vex-v5 documentation --- src/doc/rustc/src/platform-support/armv7a-vex-v5.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support/armv7a-vex-v5.md b/src/doc/rustc/src/platform-support/armv7a-vex-v5.md index 3677f8931dd68..68fbec2ff4b4c 100644 --- a/src/doc/rustc/src/platform-support/armv7a-vex-v5.md +++ b/src/doc/rustc/src/platform-support/armv7a-vex-v5.md @@ -21,7 +21,7 @@ This target is cross-compiled. Dynamic linking is unsupported. `#![no_std]` crates can be built using `build-std` to build `core` and `panic_abort` and optionally `alloc`. Unwinding panics are not yet supported on this target. -`std` has only partial support due platform limitations. Notably: +`std` has only partial support due to platform limitations. Notably: - `std::process` and `std::net` are unimplemented. `std::thread` only supports sleeping and yielding, as this is a single-threaded environment. - `std::time` has full support for `Instant`, but no support for `SystemTime`. - `std::io` has full support for `stdin`/`stdout`/`stderr`. `stdout` and `stderr` both write to to USB channel 1 on this platform and are not differentiated.