Auto merge of #149979 - ChrisDenton:rollup-9rvyn3h, r=ChrisDenton

Rollup of 8 pull requests

Successful merges:

 - rust-lang/rust#148755 (Constify `DropGuard::dismiss` and trait impls)
 - rust-lang/rust#148825 (Add SystemTime::{MIN, MAX})
 - rust-lang/rust#149272 (Fix vec iter zst alignment)
 - rust-lang/rust#149417 (tidy: Detect outdated workspaces in workspace list)
 - rust-lang/rust#149773 (fix va_list test by adding a llvmir signext check)
 - rust-lang/rust#149894 (Update to mdbook 0.5)
 - rust-lang/rust#149955 (Fix typo in armv7a-vex-v5 documentation)
 - rust-lang/rust#149972 (Enable to ping LoongArch group via triagebot)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-12-14 12:32:36 +00:00
commit 0208ee09be
34 changed files with 691 additions and 893 deletions

View file

@ -411,7 +411,12 @@ impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
// 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::<T>::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);

View file

@ -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);
}

View file

@ -1,4 +1,5 @@
use crate::fmt::{self, Debug};
use crate::marker::Destruct;
use crate::mem::ManuallyDrop;
use crate::ops::{Deref, DerefMut};
@ -78,32 +79,37 @@ 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 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
}
}
#[unstable(feature = "drop_guard", issue = "144426")]
impl<T, F> Deref for DropGuard<T, F>
#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
impl<T, F> const Deref for DropGuard<T, F>
where
F: FnOnce(T),
{
@ -115,7 +121,8 @@ where
}
#[unstable(feature = "drop_guard", issue = "144426")]
impl<T, F> DerefMut for DropGuard<T, F>
#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
impl<T, F> const DerefMut for DropGuard<T, F>
where
F: FnOnce(T),
{
@ -125,9 +132,10 @@ where
}
#[unstable(feature = "drop_guard", issue = "144426")]
impl<T, F> Drop for DropGuard<T, F>
#[rustc_const_unstable(feature = "const_drop_guard", issue = "none")]
impl<T, F> const Drop for DropGuard<T, F>
where
F: FnOnce(T),
F: [const] FnOnce(T),
{
fn drop(&mut self) {
// SAFETY: `DropGuard` is in the process of being dropped.

View file

@ -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);
}

View file

@ -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))
}

View file

@ -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())
}

View file

@ -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();

View file

@ -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<Self> {
match system_time_internal::from_uefi(&t) {
Some(x) => Some(Self(x)),

View file

@ -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<SystemTime, io::Error> {
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) } }
}

View file

@ -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")
}

View file

@ -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();
@ -101,8 +111,13 @@ impl SystemTime {
}
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
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))
}
}

View file

@ -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");

View file

@ -511,6 +511,83 @@ 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 of a [`Duration`], whose value is greater
/// than or equal to the time precision of the operating system, 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 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
/// // 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 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
/// 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 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.
/// 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
@ -588,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<SystemTime> {
self.0.checked_add_duration(&duration).map(SystemTime)
@ -596,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<SystemTime> {
self.0.checked_sub_duration(&duration).map(SystemTime)

View file

@ -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,34 @@ 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() {
#[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 ± 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());
}

@ -1 +1 @@
Subproject commit 8c0eacd5c4acbb650497454f3a58c9e8083202a4
Subproject commit 39aeceaa3aeab845bc4517e7a44e48727d3b9dbe

@ -1 +1 @@
Subproject commit 9cf5443d632673c4d41edad5e8ed8be86eeb3b8f
Subproject commit c3c0f0b3da26610138b7ba7663f60cd2c68cf184

@ -1 +1 @@
Subproject commit 0fe83ab28985b99aba36a1f0dbde3e08286fefda
Subproject commit 9fe8fa599ad228dda74f240cc32b54bc5c1aa3e6

@ -1 +1 @@
Subproject commit b14b4e40f53ca468beaf2f5d0dfb4f4c4ba6bc7b
Subproject commit 50c5de90487b68d429a30cc9466dc8f5b410128f

@ -1 +1 @@
Subproject commit 111cfae2f9c3a43f7b0ff8fa68c51cc8f930637c
Subproject commit 7d21279e40e8f0e91c2a22c5148dd2d745aef8b6

View file

@ -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

View file

@ -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.

View file

@ -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;
}
}

View file

@ -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());
}

View file

@ -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
(<i class="fa fa-cog" aria-hidden="true"></i>) in the upper right.
(<i class="fas fa-gear" aria-hidden="true"></i>) in the upper right.
## Changing displayed theme

View file

@ -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/"

View file

@ -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"

View file

@ -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"

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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"] }

View file

@ -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" <DEST_DIR>
"The output directory for your book\n(Defaults to ./book when omitted)")
.required(false)
@ -82,60 +94,22 @@ 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)?;
if let Some(lang) = args.get_one::<String>("lang") {
let gettext = Gettext;
book.with_preprocessor(gettext);
book.config.set("book.language", lang).unwrap();
}
// Set this to allow us to catch bugs in advance.
book.config.build.create_missing = false;
if let Some(dest_dir) = args.get_one::<PathBuf>("dest-dir") {
book.config.build.build_dir = dest_dir.into();
}
// NOTE: Replacing preprocessors using this technique causes error
// messages to be displayed when the original preprocessor doesn't work
// (but it otherwise succeeds).
//
// 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() {
book.with_preprocessor(Note);
}
if book.config.get_preprocessor("trpl-listing").is_some() {
book.with_preprocessor(Listing);
}
if book.config.get_preprocessor("trpl-figure").is_some() {
book.with_preprocessor(Figure);
}
if book.config.get_preprocessor("spec").is_some() {
let rust_root = args.get_one::<PathBuf>("rust-root").cloned();
book.with_preprocessor(Spec::new(rust_root)?);
}
book.build()?;
Ok(())
let dest_dir = args.get_one::<PathBuf>("dest-dir");
let lang = args.get_one::<String>("lang");
let rust_root = args.get_one::<PathBuf>("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::<Vec<String>>("library-path")?
.map(|v| v.iter().map(|s| s.as_str()).collect::<Vec<&str>>())
.unwrap_or_default();
let mut book = load_book(&book_dir)?;
book.test(library_paths)
}
@ -148,10 +122,52 @@ fn get_book_dir(args: &ArgMatches) -> PathBuf {
}
}
fn load_book(book_dir: &Path) -> Result3<MDBook> {
fn load_book(
book_dir: &Path,
dest_dir: Option<&PathBuf>,
lang: Option<&String>,
rust_root: Option<PathBuf>,
) -> Result3<MDBook> {
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) = lang {
let gettext = Gettext;
book.with_preprocessor(gettext);
book.config.set("book.language", lang).unwrap();
}
// Set this to allow us to catch bugs in advance.
book.config.build.create_missing = false;
if let Some(dest_dir) = dest_dir {
book.config.build.build_dir = dest_dir.into();
}
// NOTE: Replacing preprocessors using this technique causes error
// messages to be displayed when the original preprocessor doesn't work
// (but it otherwise succeeds).
//
// 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.contains_key("preprocessor.trpl-note") {
book.with_preprocessor(Note);
}
if book.config.contains_key("preprocessor.trpl-listing") {
book.with_preprocessor(Listing);
}
if book.config.contains_key("preprocessor.trpl-figure") {
book.with_preprocessor(Figure);
}
if book.config.contains_key("preprocessor.spec") {
book.with_preprocessor(Spec::new(rust_root)?);
}
Ok(book)
}
@ -159,7 +175,7 @@ fn parse_library_paths(input: &str) -> Result<Vec<String>, 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) {

View file

@ -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>] = &[
@ -222,10 +244,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
];
@ -242,19 +268,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 +654,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);

View file

@ -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);
}

View file

@ -96,6 +96,17 @@ Thanks! <3
"""
label = "O-ARM"
[ping.loongarch]
message = """\
Hey LoongArch Group! This bug has been identified as a good "LoongArch candidate".
In case it's useful, here are some [instructions] for tackling these sorts of
bugs. Maybe take a look?
Thanks! <3
[instructions]: https://rustc-dev-guide.rust-lang.org/notification-groups/loongarch.html
"""
label = "O-loongarch"
[ping.risc-v]
message = """\
Hey RISC-V Group! This bug has been identified as a good "RISC-V candidate".