Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
49044d0
Add support for trait associated items
GuillaumeGomez Jan 20, 2025
f1649a4
Better handling of paths in link to def feature
GuillaumeGomez Jan 26, 2025
1a6d636
Update to last rustc_hir Visitor changes
GuillaumeGomez Jan 26, 2025
d528a49
Fix panic if an item does not have a body
GuillaumeGomez May 4, 2025
25e767b
Ignore impl associated types in jump to def feature
GuillaumeGomez Aug 10, 2025
15f6d2e
rustdoc: Move HTML-specific attr rendering code into HTML rendering mod
fmease Sep 13, 2025
e9b2c4f
avoid violating `slice::from_raw_parts` safety contract in `Vec::extr…
petrosagg May 15, 2025
739e899
Add proper name mangling for pattern types
oli-obk Jun 11, 2025
58c7505
Make `render_example_with_highlighting` return an `impl fmt::Display`
yotamofek Sep 22, 2025
aaff372
Remove `Tooltip::None` variant, use `Option::None`
yotamofek Sep 22, 2025
e697f20
Remove unused param from `write_header`
yotamofek Sep 22, 2025
5673449
feature: Implement vec_try_remove
BenjaminBrienen Sep 24, 2025
137d4ea
BTreeMap: Don't leak allocators when initializing nodes
cammeresi Sep 20, 2025
88e7977
rustdoc: Slightly clean up attr rendering
fmease Sep 13, 2025
d7d7725
rustdoc: Fully escape link section and export name
fmease Sep 13, 2025
85c193a
rustdoc: hide `#[repr(...)]` if it isn't part of the public ABI
fmease May 17, 2025
185ae69
add doc for `NonZero*` const creation
cptpiepmatz Sep 25, 2025
a39d513
Rollup merge of #116882 - fmease:rustdoc-generalized-priv-repr-heuris…
matthiaskrgr Sep 25, 2025
a028b7a
Rollup merge of #135771 - GuillaumeGomez:jump-to-def-perf, r=fmease
matthiaskrgr Sep 25, 2025
e3f7626
Rollup merge of #141032 - petrosagg:extract-if-ub, r=joboet
matthiaskrgr Sep 25, 2025
958d143
Rollup merge of #142401 - oli-obk:pattern-mango, r=petrochenkov
matthiaskrgr Sep 25, 2025
fea9196
Rollup merge of #146293 - BenjaminBrienen:try_remove, r=joboet
matthiaskrgr Sep 25, 2025
83cf8f9
Rollup merge of #146859 - cammeresi:btree-alloc-20250920, r=joboet
matthiaskrgr Sep 25, 2025
781f71a
Rollup merge of #146924 - cptpiepmatz:doc-nonzero-const-creation, r=j…
matthiaskrgr Sep 25, 2025
c6d0059
Rollup merge of #146933 - yotamofek:pr/rustdoc/highlight_no_write_str…
matthiaskrgr Sep 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 6 additions & 8 deletions compiler/rustc_symbol_mangling/src/v0.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,15 +262,16 @@ impl<'tcx> V0SymbolMangler<'tcx> {
fn print_pat(&mut self, pat: ty::Pattern<'tcx>) -> Result<(), std::fmt::Error> {
Ok(match *pat {
ty::PatternKind::Range { start, end } => {
let consts = [start, end];
for ct in consts {
Ty::new_array_with_const_len(self.tcx, self.tcx.types.unit, ct).print(self)?;
}
self.push("R");
self.print_const(start)?;
self.print_const(end)?;
}
ty::PatternKind::Or(patterns) => {
self.push("O");
for pat in patterns {
self.print_pat(pat)?;
}
self.push("E");
}
})
}
Expand Down Expand Up @@ -498,12 +499,9 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> {
}

ty::Pat(ty, pat) => {
// HACK: Represent as tuple until we have something better.
// HACK: constants are used in arrays, even if the types don't match.
self.push("T");
self.push("W");
ty.print(self)?;
self.print_pat(pat)?;
self.push("E");
}

ty::Array(ty, len) => {
Expand Down
3 changes: 3 additions & 0 deletions library/alloc/src/collections/btree/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,9 @@ pub struct BTreeMap<
root: Option<Root<K, V>>,
length: usize,
/// `ManuallyDrop` to control drop order (needs to be dropped after all the nodes).
// Although some of the accessory types store a copy of the allocator, the nodes do not.
// Because allocations will remain live as long as any copy (like this one) of the allocator
// is live, it's unnecessary to store the allocator in each node.
pub(super) alloc: ManuallyDrop<A>,
// For dropck; the `Box` avoids making the `Unpin` impl more strict than before
_marker: PhantomData<crate::boxed::Box<(K, V), A>>,
Expand Down
12 changes: 10 additions & 2 deletions library/alloc/src/collections/btree/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,11 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::Leaf> {
}

fn from_new_leaf<A: Allocator + Clone>(leaf: Box<LeafNode<K, V>, A>) -> Self {
NodeRef { height: 0, node: NonNull::from(Box::leak(leaf)), _marker: PhantomData }
// The allocator must be dropped, not leaked. See also `BTreeMap::alloc`.
let (leaf, _alloc) = Box::into_raw_with_allocator(leaf);
// SAFETY: the node was just allocated.
let node = unsafe { NonNull::new_unchecked(leaf) };
NodeRef { height: 0, node, _marker: PhantomData }
}
}

Expand All @@ -243,7 +247,11 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::Internal> {
height: usize,
) -> Self {
debug_assert!(height > 0);
let node = NonNull::from(Box::leak(internal)).cast();
// The allocator must be dropped, not leaked. See also `BTreeMap::alloc`.
let (internal, _alloc) = Box::into_raw_with_allocator(internal);
// SAFETY: the node was just allocated.
let internal = unsafe { NonNull::new_unchecked(internal) };
let node = internal.cast();
let mut this = NodeRef { height, node, _marker: PhantomData };
this.borrow_mut().correct_all_childrens_parent_links();
this
Expand Down
64 changes: 39 additions & 25 deletions library/alloc/src/vec/extract_if.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,27 +64,37 @@ where
type Item = T;

fn next(&mut self) -> Option<T> {
unsafe {
while self.idx < self.end {
let i = self.idx;
let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len);
let drained = (self.pred)(&mut v[i]);
// Update the index *after* the predicate is called. If the index
// is updated prior and the predicate panics, the element at this
// index would be leaked.
self.idx += 1;
if drained {
self.del += 1;
return Some(ptr::read(&v[i]));
} else if self.del > 0 {
let del = self.del;
let src: *const T = &v[i];
let dst: *mut T = &mut v[i - del];
ptr::copy_nonoverlapping(src, dst, 1);
while self.idx < self.end {
let i = self.idx;
// SAFETY:
// We know that `i < self.end` from the if guard and that `self.end <= self.old_len` from
// the validity of `Self`. Therefore `i` points to an element within `vec`.
//
// Additionally, the i-th element is valid because each element is visited at most once
// and it is the first time we access vec[i].
//
// Note: we can't use `vec.get_unchecked_mut(i)` here since the precondition for that
// function is that i < vec.len(), but we've set vec's length to zero.
let cur = unsafe { &mut *self.vec.as_mut_ptr().add(i) };
let drained = (self.pred)(cur);
// Update the index *after* the predicate is called. If the index
// is updated prior and the predicate panics, the element at this
// index would be leaked.
self.idx += 1;
if drained {
self.del += 1;
// SAFETY: We never touch this element again after returning it.
return Some(unsafe { ptr::read(cur) });
} else if self.del > 0 {
// SAFETY: `self.del` > 0, so the hole slot must not overlap with current element.
// We use copy for move, and never touch this element again.
unsafe {
let hole_slot = self.vec.as_mut_ptr().add(i - self.del);
ptr::copy_nonoverlapping(cur, hole_slot, 1);
}
}
None
}
None
}

fn size_hint(&self) -> (usize, Option<usize>) {
Expand All @@ -95,14 +105,18 @@ where
#[stable(feature = "extract_if", since = "1.87.0")]
impl<T, F, A: Allocator> Drop for ExtractIf<'_, T, F, A> {
fn drop(&mut self) {
unsafe {
if self.idx < self.old_len && self.del > 0 {
let ptr = self.vec.as_mut_ptr();
let src = ptr.add(self.idx);
let dst = src.sub(self.del);
let tail_len = self.old_len - self.idx;
src.copy_to(dst, tail_len);
if self.del > 0 {
// SAFETY: Trailing unchecked items must be valid since we never touch them.
unsafe {
ptr::copy(
self.vec.as_ptr().add(self.idx),
self.vec.as_mut_ptr().add(self.idx - self.del),
self.old_len - self.idx,
);
}
}
// SAFETY: After filling holes, all items are in contiguous memory.
unsafe {
self.vec.set_len(self.old_len - self.del);
}
}
Expand Down
32 changes: 30 additions & 2 deletions library/alloc/src/vec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2173,9 +2173,37 @@ impl<T, A: Allocator> Vec<T, A> {
panic!("removal index (is {index}) should be < len (is {len})");
}

match self.try_remove(index) {
Some(elem) => elem,
None => assert_failed(index, self.len()),
}
}

/// Remove and return the element at position `index` within the vector,
/// shifting all elements after it to the left, or [`None`] if it does not
/// exist.
///
/// Note: Because this shifts over the remaining elements, it has a
/// worst-case performance of *O*(*n*). If you'd like to remove
/// elements from the beginning of the `Vec`, consider using
/// [`VecDeque::pop_front`] instead.
///
/// [`VecDeque::pop_front`]: crate::collections::VecDeque::pop_front
///
/// # Examples
///
/// ```
/// #![feature(vec_try_remove)]
/// let mut v = vec![1, 2, 3];
/// assert_eq!(v.try_remove(0), Some(1));
/// assert_eq!(v.try_remove(2), None);
/// ```
#[unstable(feature = "vec_try_remove", issue = "146954")]
#[rustc_confusables("delete", "take", "remove")]
pub fn try_remove(&mut self, index: usize) -> Option<T> {
let len = self.len();
if index >= len {
assert_failed(index, len);
return None;
}
unsafe {
// infallible
Expand All @@ -2191,7 +2219,7 @@ impl<T, A: Allocator> Vec<T, A> {
ptr::copy(ptr.add(1), ptr, len - index - 1);
}
self.set_len(len - 1);
ret
Some(ret)
}
}

Expand Down
1 change: 1 addition & 0 deletions library/alloctests/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#![feature(unique_rc_arc)]
#![feature(macro_metavar_expr_concat)]
#![feature(vec_peek_mut)]
#![feature(vec_try_remove)]
#![allow(internal_features)]
#![deny(fuzzy_provenance_casts)]
#![deny(unsafe_op_in_unsafe_fn)]
Expand Down
15 changes: 15 additions & 0 deletions library/alloctests/tests/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,21 @@ fn test_swap_remove_empty() {
vec.swap_remove(0);
}

#[test]
fn test_try_remove() {
let mut vec = vec![1, 2, 3];
// We are attempting to remove vec[0] which contains 1
assert_eq!(vec.try_remove(0), Some(1));
// Now `vec` looks like: [2, 3]
// We will now try to remove vec[2] which does not exist
// This should return `None`
assert_eq!(vec.try_remove(2), None);

// We will try the same thing with an empty vector
let mut v: Vec<u8> = vec![];
assert!(v.try_remove(0).is_none());
}

#[test]
fn test_move_items() {
let vec = vec![1, 2, 3];
Expand Down
12 changes: 12 additions & 0 deletions library/core/src/num/nonzero.rs
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,18 @@ macro_rules! nonzero_integer {
#[doc = concat!("assert_eq!(align_of::<", stringify!($Ty), ">(), align_of::<Option<", stringify!($Ty), ">>());")]
/// ```
///
/// # Compile-time creation
///
/// Since both [`Option::unwrap()`] and [`Option::expect()`] are `const`, it is possible to
/// define a new
#[doc = concat!("`", stringify!($Ty), "`")]
/// at compile time via:
/// ```
#[doc = concat!("use std::num::", stringify!($Ty), ";")]
///
#[doc = concat!("const TEN: ", stringify!($Ty), " = ", stringify!($Ty) , r#"::new(10).expect("ten is non-zero");"#)]
/// ```
///
/// [null pointer optimization]: crate::option#representation
#[$stability]
pub type $Ty = NonZero<$Int>;
Expand Down
28 changes: 28 additions & 0 deletions src/doc/rustc/src/symbol-mangling/v0.md
Original file line number Diff line number Diff line change
Expand Up @@ -710,6 +710,7 @@ A *placeholder* may occur in circumstances where a type or const value is not re
[mut-ptr-type]: #mut-ptr-type
[fn-type]: #fn-type
[dyn-trait-type]: #dyn-trait-type
[pattern-type]: #pattern-type

> type → \
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *[basic-type]* \
Expand All @@ -722,6 +723,7 @@ A *placeholder* may occur in circumstances where a type or const value is not re
> &nbsp;&nbsp; | *[mut-ptr-type]* \
> &nbsp;&nbsp; | *[fn-type]* \
> &nbsp;&nbsp; | *[dyn-trait-type]* \
> &nbsp;&nbsp; | *[pattern-type]* \
> &nbsp;&nbsp; | *[path]* \
> &nbsp;&nbsp; | *[backref]*

Expand Down Expand Up @@ -830,6 +832,23 @@ Remaining primitives are encoded as a crate production, e.g. `C4f128`.
[fn-sig]: #fn-sig
[abi]: #abi

* `W` — A [pattern-type][pattern-tpye] `u32 is 0..100`.
> <span id="pattern-type">pattern-type</span> → `W` *[pattern-kind]*
>
> <span id="pattern-kind">pattern-kind</span> → \
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *[range-pattern-kind]* \
> &nbsp;&nbsp; *[or-pattern-kind]*
>
> <span id="range-pattern-kind">range-pattern-kind</span> → `R` *[const]* *[const]*
>
> <span id="or-pattern-kind">or-pattern-kind</span> → `O` *[pattern-kind]* `E`

While or patterns can be nested in theory, in practice this does not happen and they are instead flattened.

Range patterns have a start and end constant that are both included in the range.
The end must be larger than the start (there can be no wraparound). To emulate wraparound,
you need to use an or pattern of the two ranges to the upper limit and from the lower limit.

* `D` — A [trait object][reference-trait-object] `dyn Trait<Assoc=X> + Send + 'a`.

> <span id="dyn-trait-type">dyn-trait-type</span> → `D` *[dyn-bounds]* *[lifetime]*
Expand Down Expand Up @@ -1139,6 +1158,7 @@ The following is a summary of all of the productions of the symbol grammar.
> &nbsp;&nbsp; | *[mut-ptr-type]* \
> &nbsp;&nbsp; | *[fn-type]* \
> &nbsp;&nbsp; | *[dyn-trait-type]* \
> &nbsp;&nbsp; | *[pattern-type]* \
> &nbsp;&nbsp; | *[path]* \
> &nbsp;&nbsp; | *[backref]*
>
Expand All @@ -1152,6 +1172,14 @@ The following is a summary of all of the productions of the symbol grammar.
> [mut-ptr-type] → `O` *[type]* \
> [fn-type] → `F` *[fn-sig]* \
> [dyn-trait-type] → `D` *[dyn-bounds]* *[lifetime]*
> [pattern-type] → `W` *[pattern-kind]*
>
> [pattern-kind] → \
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *[range-pattern-kind]* \
> &nbsp;&nbsp; *[or-pattern-kind]*
>
> [range-pattern-kind] -> `R` *[const]* *[const]* \
> [or-pattern-kind] -> `O` *[pattern-kind]* `E` \
>
> [namespace] → *[lower]* | *[upper]*
>
Expand Down
20 changes: 15 additions & 5 deletions src/doc/rustdoc/src/advanced-features.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,20 +89,30 @@ https://doc.rust-lang.org/stable/std/?search=%s&go_to_first=true
This URL adds the `go_to_first=true` query parameter which can be appended to any `rustdoc` search URL
to automatically go to the first result.

## `#[repr(transparent)]`: Documenting the transparent representation
## `#[repr(...)]`: Documenting the representation of a type

Generally, rustdoc only displays the representation of a given type if none of its variants are
`#[doc(hidden)]` and if all of its fields are public and not `#[doc(hidden)]` since it's likely
not meant to be considered part of the public ABI otherwise.

Note that there's no way to overwrite that heuristic and force rustdoc to show the representation
regardless.

### `#[repr(transparent)]`

You can read more about `#[repr(transparent)]` itself in the [Rust Reference][repr-trans-ref] and
in the [Rustonomicon][repr-trans-nomicon].

Since this representation is only considered part of the public ABI if the single field with non-trivial
size or alignment is public and if the documentation does not state otherwise, Rustdoc helpfully displays
the attribute if and only if the non-1-ZST field is public or at least one field is public in case all
fields are 1-ZST fields. The term *1-ZST* refers to types that are one-aligned and zero-sized.
size or alignment is public and if the documentation does not state otherwise, rustdoc helpfully displays
the attribute if and only if the non-1-ZST field is public and not `#[doc(hidden)]` or
– in case all fields are 1-ZST fields — at least one field is public and not `#[doc(hidden)]`.
The term *1-ZST* refers to types that are one-aligned and zero-sized.

It would seem that one can manually hide the attribute with `#[cfg_attr(not(doc), repr(transparent))]`
if one wishes to declare the representation as private even if the non-1-ZST field is public.
However, due to [current limitations][cross-crate-cfg-doc], this method is not always guaranteed to work.
Therefore, if you would like to do so, you should always write it down in prose independently of whether
Therefore, if you would like to do so, you should always write that down in prose independently of whether
you use `cfg_attr` or not.

[repr-trans-ref]: https://doc.rust-lang.org/reference/type-layout.html#the-transparent-representation
Expand Down
Loading
Loading