Auto merge of #141529 - jhpratt:rollup-8dle839, r=jhpratt

Rollup of 4 pull requests

Successful merges:

 - rust-lang/rust#139831 (rustdoc: on mobile, make the sidebar full width and linewrap)
 - rust-lang/rust#140950 (More option optimization tests)
 - rust-lang/rust#141108 (Docs(lib): Fix `extract_if` docs)
 - rust-lang/rust#141361 (use `cfg_select!` to select the right `VaListImpl` definition)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-05-25 07:37:05 +00:00
commit aa57e46e24
13 changed files with 229 additions and 232 deletions

View File

@ -1398,10 +1398,12 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
}
/// Creates an iterator that visits all elements (key-value pairs) in
/// ascending key order and uses a closure to determine if an element should
/// be removed. If the closure returns `true`, the element is removed from
/// the map and yielded. If the closure returns `false`, or panics, the
/// element remains in the map and will not be yielded.
/// ascending key order and uses a closure to determine if an element
/// should be removed.
///
/// If the closure returns `true`, the element is removed from the map and
/// yielded. If the closure returns `false`, or panics, the element remains
/// in the map and will not be yielded.
///
/// The iterator also lets you mutate the value of each element in the
/// closure, regardless of whether you choose to keep or remove it.

View File

@ -1124,20 +1124,20 @@ impl<T, A: Allocator> LinkedList<T, A> {
/// Creates an iterator which uses a closure to determine if an element should be removed.
///
/// If the closure returns true, then the element is removed and yielded.
/// If the closure returns false, the element will remain in the list and will not be yielded
/// by the iterator.
/// If the closure returns `true`, the element is removed from the list and
/// yielded. If the closure returns `false`, or panics, the element remains
/// in the list and will not be yielded.
///
/// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating
/// or the iteration short-circuits, then the remaining elements will be retained.
/// Use `extract_if().for_each(drop)` if you do not need the returned iterator.
///
/// Note that `extract_if` lets you mutate every element in the filter closure, regardless of
/// whether you choose to keep or remove it.
/// The iterator also lets you mutate the value of each element in the
/// closure, regardless of whether you choose to keep or remove it.
///
/// # Examples
///
/// Splitting a list into evens and odds, reusing the original list:
/// Splitting a list into even and odd values, reusing the original list:
///
/// ```
/// use std::collections::LinkedList;

View File

@ -3648,11 +3648,11 @@ impl<T, A: Allocator> Vec<T, A> {
Splice { drain: self.drain(range), replace_with: replace_with.into_iter() }
}
/// Creates an iterator which uses a closure to determine if element in the range should be removed.
/// Creates an iterator which uses a closure to determine if an element in the range should be removed.
///
/// If the closure returns true, then the element is removed and yielded.
/// If the closure returns false, the element will remain in the vector and will not be yielded
/// by the iterator.
/// If the closure returns `true`, the element is removed from the vector
/// and yielded. If the closure returns `false`, or panics, the element
/// remains in the vector and will not be yielded.
///
/// Only elements that fall in the provided range are considered for extraction, but any elements
/// after the range will still have to be moved if any element has been extracted.
@ -3692,8 +3692,8 @@ impl<T, A: Allocator> Vec<T, A> {
/// But `extract_if` is easier to use. `extract_if` is also more efficient,
/// because it can backshift the elements of the array in bulk.
///
/// Note that `extract_if` also lets you mutate the elements passed to the filter closure,
/// regardless of whether you choose to keep or remove them.
/// The iterator also lets you mutate the value of each element in the
/// closure, regardless of whether you choose to keep or remove it.
///
/// # Panics
///
@ -3701,7 +3701,7 @@ impl<T, A: Allocator> Vec<T, A> {
///
/// # Examples
///
/// Splitting an array into evens and odds, reusing the original allocation:
/// Splitting a vector into even and odd values, reusing the original vector:
///
/// ```
/// let mut numbers = vec![1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15];

View File

@ -5,148 +5,120 @@
use crate::ffi::c_void;
#[allow(unused_imports)]
use crate::fmt;
use crate::marker::PhantomData;
use crate::marker::{PhantomData, PhantomInvariantLifetime};
use crate::ops::{Deref, DerefMut};
/// Basic implementation of a `va_list`.
// The name is WIP, using `VaListImpl` for now.
#[cfg(any(
//
// Most targets explicitly specify the layout of `va_list`, this layout is matched here.
crate::cfg_select! {
all(
not(target_arch = "aarch64"),
not(target_arch = "powerpc"),
not(target_arch = "s390x"),
not(target_arch = "xtensa"),
not(target_arch = "x86_64")
),
all(target_arch = "aarch64", target_vendor = "apple"),
target_family = "wasm",
target_os = "uefi",
windows,
))]
#[repr(transparent)]
#[lang = "va_list"]
pub struct VaListImpl<'f> {
ptr: *mut c_void,
// Invariant over `'f`, so each `VaListImpl<'f>` object is tied to
// the region of the function it's defined in
_marker: PhantomData<&'f mut &'f c_void>,
}
#[cfg(any(
all(
not(target_arch = "aarch64"),
not(target_arch = "powerpc"),
not(target_arch = "s390x"),
not(target_arch = "xtensa"),
not(target_arch = "x86_64")
),
all(target_arch = "aarch64", target_vendor = "apple"),
target_family = "wasm",
target_os = "uefi",
windows,
))]
impl<'f> fmt::Debug for VaListImpl<'f> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "va_list* {:p}", self.ptr)
}
}
/// AArch64 ABI implementation of a `va_list`. See the
/// [AArch64 Procedure Call Standard] for more details.
///
/// [AArch64 Procedure Call Standard]:
/// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf
#[cfg(all(
target_arch = "aarch64",
not(target_vendor = "apple"),
not(target_os = "uefi"),
not(windows),
))]
#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401
#[derive(Debug)]
#[lang = "va_list"]
pub struct VaListImpl<'f> {
) => {
/// AArch64 ABI implementation of a `va_list`. See the
/// [AArch64 Procedure Call Standard] for more details.
///
/// [AArch64 Procedure Call Standard]:
/// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf
#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401
#[derive(Debug)]
#[lang = "va_list"]
pub struct VaListImpl<'f> {
stack: *mut c_void,
gr_top: *mut c_void,
vr_top: *mut c_void,
gr_offs: i32,
vr_offs: i32,
_marker: PhantomData<&'f mut &'f c_void>,
}
/// PowerPC ABI implementation of a `va_list`.
#[cfg(all(target_arch = "powerpc", not(target_os = "uefi"), not(windows)))]
#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401
#[derive(Debug)]
#[lang = "va_list"]
pub struct VaListImpl<'f> {
_marker: PhantomInvariantLifetime<'f>,
}
}
all(target_arch = "powerpc", not(target_os = "uefi"), not(windows)) => {
/// PowerPC ABI implementation of a `va_list`.
#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401
#[derive(Debug)]
#[lang = "va_list"]
pub struct VaListImpl<'f> {
gpr: u8,
fpr: u8,
reserved: u16,
overflow_arg_area: *mut c_void,
reg_save_area: *mut c_void,
_marker: PhantomData<&'f mut &'f c_void>,
}
/// s390x ABI implementation of a `va_list`.
#[cfg(target_arch = "s390x")]
#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401
#[derive(Debug)]
#[lang = "va_list"]
pub struct VaListImpl<'f> {
_marker: PhantomInvariantLifetime<'f>,
}
}
target_arch = "s390x" => {
/// s390x ABI implementation of a `va_list`.
#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401
#[derive(Debug)]
#[lang = "va_list"]
pub struct VaListImpl<'f> {
gpr: i64,
fpr: i64,
overflow_arg_area: *mut c_void,
reg_save_area: *mut c_void,
_marker: PhantomData<&'f mut &'f c_void>,
}
/// x86_64 ABI implementation of a `va_list`.
#[cfg(all(target_arch = "x86_64", not(target_os = "uefi"), not(windows)))]
#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401
#[derive(Debug)]
#[lang = "va_list"]
pub struct VaListImpl<'f> {
_marker: PhantomInvariantLifetime<'f>,
}
}
all(target_arch = "x86_64", not(target_os = "uefi"), not(windows)) => {
/// x86_64 ABI implementation of a `va_list`.
#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401
#[derive(Debug)]
#[lang = "va_list"]
pub struct VaListImpl<'f> {
gp_offset: i32,
fp_offset: i32,
overflow_arg_area: *mut c_void,
reg_save_area: *mut c_void,
_marker: PhantomData<&'f mut &'f c_void>,
}
/// Xtensa ABI implementation of a `va_list`.
#[cfg(target_arch = "xtensa")]
#[repr(C)]
#[derive(Debug)]
#[lang = "va_list"]
pub struct VaListImpl<'f> {
_marker: PhantomInvariantLifetime<'f>,
}
}
target_arch = "xtensa" => {
/// Xtensa ABI implementation of a `va_list`.
#[repr(C)]
#[derive(Debug)]
#[lang = "va_list"]
pub struct VaListImpl<'f> {
stk: *mut i32,
reg: *mut i32,
ndx: i32,
_marker: PhantomData<&'f mut &'f c_void>,
_marker: PhantomInvariantLifetime<'f>,
}
}
// The fallback implementation, used for:
//
// - apple aarch64 (see https://github.com/rust-lang/rust/pull/56599)
// - windows
// - uefi
// - any other target for which we don't specify the `VaListImpl` above
//
// In this implementation the `va_list` type is just an alias for an opaque pointer.
// That pointer is probably just the next variadic argument on the caller's stack.
_ => {
/// Basic implementation of a `va_list`.
#[repr(transparent)]
#[lang = "va_list"]
pub struct VaListImpl<'f> {
ptr: *mut c_void,
// Invariant over `'f`, so each `VaListImpl<'f>` object is tied to
// the region of the function it's defined in
_marker: PhantomInvariantLifetime<'f>,
}
impl<'f> fmt::Debug for VaListImpl<'f> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "va_list* {:p}", self.ptr)
}
}
}
}
/// A wrapper for a `va_list`
#[repr(transparent)]
#[derive(Debug)]
pub struct VaList<'a, 'f: 'a> {
#[cfg(any(
crate::cfg_select! {
all(
not(target_arch = "aarch64"),
not(target_arch = "powerpc"),
not(target_arch = "s390x"),
not(target_arch = "x86_64")
),
target_arch = "xtensa",
all(target_arch = "aarch64", target_vendor = "apple"),
target_family = "wasm",
target_os = "uefi",
windows,
))]
inner: VaListImpl<'f>,
#[cfg(all(
any(
target_arch = "aarch64",
target_arch = "powerpc",
@ -158,52 +130,41 @@ pub struct VaList<'a, 'f: 'a> {
not(target_family = "wasm"),
not(target_os = "uefi"),
not(windows),
))]
) => {
/// A wrapper for a `va_list`
#[repr(transparent)]
#[derive(Debug)]
pub struct VaList<'a, 'f: 'a> {
inner: &'a mut VaListImpl<'f>,
_marker: PhantomData<&'a mut VaListImpl<'f>>,
}
}
#[cfg(any(
all(
not(target_arch = "aarch64"),
not(target_arch = "powerpc"),
not(target_arch = "s390x"),
not(target_arch = "x86_64")
),
target_arch = "xtensa",
all(target_arch = "aarch64", target_vendor = "apple"),
target_family = "wasm",
target_os = "uefi",
windows,
))]
impl<'f> VaListImpl<'f> {
/// Converts a `VaListImpl` into a `VaList` that is binary-compatible with C's `va_list`.
impl<'f> VaListImpl<'f> {
/// Converts a [`VaListImpl`] into a [`VaList`] that is binary-compatible with C's `va_list`.
#[inline]
pub fn as_va_list<'a>(&'a mut self) -> VaList<'a, 'f> {
VaList { inner: self, _marker: PhantomData }
}
}
}
_ => {
/// A wrapper for a `va_list`
#[repr(transparent)]
#[derive(Debug)]
pub struct VaList<'a, 'f: 'a> {
inner: VaListImpl<'f>,
_marker: PhantomData<&'a mut VaListImpl<'f>>,
}
impl<'f> VaListImpl<'f> {
/// Converts a [`VaListImpl`] into a [`VaList`] that is binary-compatible with C's `va_list`.
#[inline]
pub fn as_va_list<'a>(&'a mut self) -> VaList<'a, 'f> {
VaList { inner: VaListImpl { ..*self }, _marker: PhantomData }
}
}
#[cfg(all(
any(
target_arch = "aarch64",
target_arch = "powerpc",
target_arch = "s390x",
target_arch = "xtensa",
target_arch = "x86_64"
),
not(target_arch = "xtensa"),
any(not(target_arch = "aarch64"), not(target_vendor = "apple")),
not(target_family = "wasm"),
not(target_os = "uefi"),
not(windows),
))]
impl<'f> VaListImpl<'f> {
/// Converts a `VaListImpl` into a `VaList` that is binary-compatible with C's `va_list`.
#[inline]
pub fn as_va_list<'a>(&'a mut self) -> VaList<'a, 'f> {
VaList { inner: self, _marker: PhantomData }
}
}
}

View File

@ -648,14 +648,14 @@ impl<K, V, S> HashMap<K, V, S> {
Drain { base: self.base.drain() }
}
/// Creates an iterator which uses a closure to determine if an element should be removed.
/// Creates an iterator which uses a closure to determine if an element (key-value pair) should be removed.
///
/// If the closure returns true, the element is removed from the map and yielded.
/// If the closure returns false, or panics, the element remains in the map and will not be
/// yielded.
/// If the closure returns `true`, the element is removed from the map and
/// yielded. If the closure returns `false`, or panics, the element remains
/// in the map and will not be yielded.
///
/// Note that `extract_if` lets you mutate every value in the filter closure, regardless of
/// whether you choose to keep or remove it.
/// The iterator also lets you mutate the value of each element in the
/// closure, regardless of whether you choose to keep or remove it.
///
/// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating
/// or the iteration short-circuits, then the remaining elements will be retained.

View File

@ -276,11 +276,11 @@ impl<T, S> HashSet<T, S> {
Drain { base: self.base.drain() }
}
/// Creates an iterator which uses a closure to determine if a value should be removed.
/// Creates an iterator which uses a closure to determine if an element should be removed.
///
/// If the closure returns true, then the value is removed and yielded.
/// If the closure returns false, the value will remain in the list and will not be yielded
/// by the iterator.
/// If the closure returns `true`, the element is removed from the set and
/// yielded. If the closure returns `false`, or panics, the element remains
/// in the set and will not be yielded.
///
/// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating
/// or the iteration short-circuits, then the remaining elements will be retained.

View File

@ -2527,9 +2527,12 @@ in src-script.js and main.js
z-index: 11;
/* Reduce height slightly to account for mobile topbar. */
height: calc(100vh - 45px);
width: 200px;
/* resize indicator: hide this when on touch or mobile */
border-right: none;
width: 100%;
}
.sidebar-elems .block li a {
white-space: wrap;
}
/* The source view uses a different design for the sidebar toggle, and doesn't have a topbar,

View File

@ -1,3 +1,4 @@
//@ min-llvm-version: 20
//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled
#![crate_type = "lib"]
@ -24,6 +25,18 @@ pub fn non_zero_signed_eq(l: Option<NonZero<i64>>, r: Option<NonZero<i64>>) -> b
l == r
}
// FIXME(#49892)
// This currently relies on a manual implementation of `PartialOrd`/`Ord` for `Option`
// Once LLVM is better able to optimize this pattern, we can return to using a derive.
// CHECK-LABEL: @non_zero_ord
#[no_mangle]
pub fn non_zero_ord(a: Option<NonZero<u32>>, b: Option<NonZero<u32>>) -> bool {
// CHECK: start:
// CHECK-NEXT: icmp ult i32
// CHECK-NEXT: ret i1
a < b
}
// CHECK-LABEL: @non_null_eq
#[no_mangle]
pub fn non_null_eq(l: Option<NonNull<u8>>, r: Option<NonNull<u8>>) -> bool {
@ -61,13 +74,3 @@ pub fn niche_eq(l: Option<EnumWithNiche>, r: Option<EnumWithNiche>) -> bool {
// CHECK-NEXT: ret i1
l == r
}
// FIXME: This should work too
// // FIXME-CHECK-LABEL: @bool_eq
// #[no_mangle]
// pub fn bool_eq(l: Option<bool>, r: Option<bool>) -> bool {
// // FIXME-CHECK: start:
// // FIXME-CHECK-NEXT: icmp eq i8
// // FIXME-CHECK-NEXT: ret i1
// l == r
// }

View File

@ -0,0 +1,15 @@
//@ should-fail
//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled
//! FIXME(#49892)
//! Tests that LLVM does not fully optimize comparisons of `Option<bool>`.
//! If this starts passing, it can be moved to `tests/codegen/option-niche-eq.rs`
#![crate_type = "lib"]
// CHECK-LABEL: @bool_eq
#[no_mangle]
pub fn bool_eq(l: Option<bool>, r: Option<bool>) -> bool {
// CHECK: start:
// CHECK-NEXT: icmp eq i8
// CHECK-NEXT: ret i1
l == r
}

View File

@ -0,0 +1,24 @@
//@ should-fail
//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled
//! FIXME(#49892)
//! Test that the derived implementation of `PartialEq` for `Option` is not fully
//! optimized by LLVM. If this starts passing, the test and manual impl should
//! be removed.
#![crate_type = "lib"]
use std::num::NonZero;
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum Option<T> {
None,
Some(T),
}
// CHECK-LABEL: @non_zero_eq
#[no_mangle]
pub fn non_zero_eq(l: Option<NonZero<u32>>, r: Option<NonZero<u32>>) -> bool {
// CHECK: start:
// CHECK-NEXT: icmp eq i32
// CHECK-NEXT: ret i1
l == r
}

View File

@ -244,10 +244,6 @@ click: ".sidebar-menu-toggle"
assert: "//*[@class='sidebar shown']"
assert-count: ("//*[@class='tooltip popover']", 0)
assert-false: "#method\.create_an_iterator_from_read .tooltip:focus"
// Clicking a notable trait tooltip popover should close the sidebar.
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
assert-count: ("//*[@class='tooltip popover']", 1)
assert-false: "//*[@class='sidebar shown']"
// Also check the focus handling for the settings button.
set-window-size: (1100, 600)

View File

@ -68,16 +68,3 @@ assert-css: ("#settings-menu .popover", {"display": "block"})
click: ".sidebar-menu-toggle"
assert: "//*[@class='sidebar shown']"
assert-css: ("#settings-menu .popover", {"display": "none"})
// Opening the settings popover should close the sidebar.
click: "#settings-menu a"
assert-css: ("#settings-menu .popover", {"display": "block"})
assert-false: "//*[@class='sidebar shown']"
// Opening the settings popover at start (which async loads stuff) should also close.
reload:
click: ".sidebar-menu-toggle"
assert: "//*[@class='sidebar shown']"
assert-false: "#settings-menu .popover"
click: "#settings-menu a"
assert-false: "//*[@class='sidebar shown']"
wait-for: "#settings-menu .popover"

View File

@ -32,8 +32,8 @@ assert-css: (
{"display": "block"}
)
// Click elsewhere.
click: "body"
// Click the toggle to close it
click: ".sidebar-menu-toggle"
assert-css: (".sidebar", {"display": "block", "left": "-1000px"})
// Open the sidebar menu, and make sure pressing Escape closes it.
@ -57,6 +57,8 @@ scroll-to: ".block.keyword li:nth-child(1)"
compare-elements-position-near: (".block.keyword li:nth-child(1)", ".mobile-topbar", {"y": 544})
// Now checking the background color of the sidebar.
// Close the sidebar menu.
press-key: "Escape"
show-text: true
define-function: (
@ -72,6 +74,10 @@ define-function: (
"background-color": |background|,
"color": |color|,
})
// Make sure the sidebar is full width
compare-elements-size: (".sidebar", "body", ["width"])
// Close the sidebar menu.
press-key: "Escape"
},
)