Skip to content

Commit 7ac0330

Browse files
committed
Auto merge of #147037 - matthiaskrgr:rollup-xtgqzuu, r=matthiaskrgr
Rollup of 8 pull requests Successful merges: - #116882 (rustdoc: hide `#[repr]` if it isn't part of the public ABI) - #135771 ([rustdoc] Add support for associated items in "jump to def" feature) - #141032 (avoid violating `slice::from_raw_parts` safety contract in `Vec::extract_if`) - #142401 (Add proper name mangling for pattern types) - #146293 (feat: non-panicking `Vec::try_remove`) - #146859 (BTreeMap: Don't leak allocators when initializing nodes) - #146924 (Add doc for `NonZero*` const creation) - #146933 (Make `render_example_with_highlighting` return an `impl fmt::Display`) r? `@ghost` `@rustbot` modify labels: rollup
2 parents eabf390 + c6d0059 commit 7ac0330

File tree

36 files changed

+848
-536
lines changed

36 files changed

+848
-536
lines changed

compiler/rustc_symbol_mangling/src/v0.rs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -262,15 +262,16 @@ impl<'tcx> V0SymbolMangler<'tcx> {
262262
fn print_pat(&mut self, pat: ty::Pattern<'tcx>) -> Result<(), std::fmt::Error> {
263263
Ok(match *pat {
264264
ty::PatternKind::Range { start, end } => {
265-
let consts = [start, end];
266-
for ct in consts {
267-
Ty::new_array_with_const_len(self.tcx, self.tcx.types.unit, ct).print(self)?;
268-
}
265+
self.push("R");
266+
self.print_const(start)?;
267+
self.print_const(end)?;
269268
}
270269
ty::PatternKind::Or(patterns) => {
270+
self.push("O");
271271
for pat in patterns {
272272
self.print_pat(pat)?;
273273
}
274+
self.push("E");
274275
}
275276
})
276277
}
@@ -498,12 +499,9 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> {
498499
}
499500

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

509507
ty::Array(ty, len) => {

library/alloc/src/collections/btree/map.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,9 @@ pub struct BTreeMap<
194194
root: Option<Root<K, V>>,
195195
length: usize,
196196
/// `ManuallyDrop` to control drop order (needs to be dropped after all the nodes).
197+
// Although some of the accessory types store a copy of the allocator, the nodes do not.
198+
// Because allocations will remain live as long as any copy (like this one) of the allocator
199+
// is live, it's unnecessary to store the allocator in each node.
197200
pub(super) alloc: ManuallyDrop<A>,
198201
// For dropck; the `Box` avoids making the `Unpin` impl more strict than before
199202
_marker: PhantomData<crate::boxed::Box<(K, V), A>>,

library/alloc/src/collections/btree/node.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,11 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::Leaf> {
225225
}
226226

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

@@ -243,7 +247,11 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::Internal> {
243247
height: usize,
244248
) -> Self {
245249
debug_assert!(height > 0);
246-
let node = NonNull::from(Box::leak(internal)).cast();
250+
// The allocator must be dropped, not leaked. See also `BTreeMap::alloc`.
251+
let (internal, _alloc) = Box::into_raw_with_allocator(internal);
252+
// SAFETY: the node was just allocated.
253+
let internal = unsafe { NonNull::new_unchecked(internal) };
254+
let node = internal.cast();
247255
let mut this = NodeRef { height, node, _marker: PhantomData };
248256
this.borrow_mut().correct_all_childrens_parent_links();
249257
this

library/alloc/src/vec/extract_if.rs

Lines changed: 39 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -64,27 +64,37 @@ where
6464
type Item = T;
6565

6666
fn next(&mut self) -> Option<T> {
67-
unsafe {
68-
while self.idx < self.end {
69-
let i = self.idx;
70-
let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len);
71-
let drained = (self.pred)(&mut v[i]);
72-
// Update the index *after* the predicate is called. If the index
73-
// is updated prior and the predicate panics, the element at this
74-
// index would be leaked.
75-
self.idx += 1;
76-
if drained {
77-
self.del += 1;
78-
return Some(ptr::read(&v[i]));
79-
} else if self.del > 0 {
80-
let del = self.del;
81-
let src: *const T = &v[i];
82-
let dst: *mut T = &mut v[i - del];
83-
ptr::copy_nonoverlapping(src, dst, 1);
67+
while self.idx < self.end {
68+
let i = self.idx;
69+
// SAFETY:
70+
// We know that `i < self.end` from the if guard and that `self.end <= self.old_len` from
71+
// the validity of `Self`. Therefore `i` points to an element within `vec`.
72+
//
73+
// Additionally, the i-th element is valid because each element is visited at most once
74+
// and it is the first time we access vec[i].
75+
//
76+
// Note: we can't use `vec.get_unchecked_mut(i)` here since the precondition for that
77+
// function is that i < vec.len(), but we've set vec's length to zero.
78+
let cur = unsafe { &mut *self.vec.as_mut_ptr().add(i) };
79+
let drained = (self.pred)(cur);
80+
// Update the index *after* the predicate is called. If the index
81+
// is updated prior and the predicate panics, the element at this
82+
// index would be leaked.
83+
self.idx += 1;
84+
if drained {
85+
self.del += 1;
86+
// SAFETY: We never touch this element again after returning it.
87+
return Some(unsafe { ptr::read(cur) });
88+
} else if self.del > 0 {
89+
// SAFETY: `self.del` > 0, so the hole slot must not overlap with current element.
90+
// We use copy for move, and never touch this element again.
91+
unsafe {
92+
let hole_slot = self.vec.as_mut_ptr().add(i - self.del);
93+
ptr::copy_nonoverlapping(cur, hole_slot, 1);
8494
}
8595
}
86-
None
8796
}
97+
None
8898
}
8999

90100
fn size_hint(&self) -> (usize, Option<usize>) {
@@ -95,14 +105,18 @@ where
95105
#[stable(feature = "extract_if", since = "1.87.0")]
96106
impl<T, F, A: Allocator> Drop for ExtractIf<'_, T, F, A> {
97107
fn drop(&mut self) {
98-
unsafe {
99-
if self.idx < self.old_len && self.del > 0 {
100-
let ptr = self.vec.as_mut_ptr();
101-
let src = ptr.add(self.idx);
102-
let dst = src.sub(self.del);
103-
let tail_len = self.old_len - self.idx;
104-
src.copy_to(dst, tail_len);
108+
if self.del > 0 {
109+
// SAFETY: Trailing unchecked items must be valid since we never touch them.
110+
unsafe {
111+
ptr::copy(
112+
self.vec.as_ptr().add(self.idx),
113+
self.vec.as_mut_ptr().add(self.idx - self.del),
114+
self.old_len - self.idx,
115+
);
105116
}
117+
}
118+
// SAFETY: After filling holes, all items are in contiguous memory.
119+
unsafe {
106120
self.vec.set_len(self.old_len - self.del);
107121
}
108122
}

library/alloc/src/vec/mod.rs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2173,9 +2173,37 @@ impl<T, A: Allocator> Vec<T, A> {
21732173
panic!("removal index (is {index}) should be < len (is {len})");
21742174
}
21752175

2176+
match self.try_remove(index) {
2177+
Some(elem) => elem,
2178+
None => assert_failed(index, self.len()),
2179+
}
2180+
}
2181+
2182+
/// Remove and return the element at position `index` within the vector,
2183+
/// shifting all elements after it to the left, or [`None`] if it does not
2184+
/// exist.
2185+
///
2186+
/// Note: Because this shifts over the remaining elements, it has a
2187+
/// worst-case performance of *O*(*n*). If you'd like to remove
2188+
/// elements from the beginning of the `Vec`, consider using
2189+
/// [`VecDeque::pop_front`] instead.
2190+
///
2191+
/// [`VecDeque::pop_front`]: crate::collections::VecDeque::pop_front
2192+
///
2193+
/// # Examples
2194+
///
2195+
/// ```
2196+
/// #![feature(vec_try_remove)]
2197+
/// let mut v = vec![1, 2, 3];
2198+
/// assert_eq!(v.try_remove(0), Some(1));
2199+
/// assert_eq!(v.try_remove(2), None);
2200+
/// ```
2201+
#[unstable(feature = "vec_try_remove", issue = "146954")]
2202+
#[rustc_confusables("delete", "take", "remove")]
2203+
pub fn try_remove(&mut self, index: usize) -> Option<T> {
21762204
let len = self.len();
21772205
if index >= len {
2178-
assert_failed(index, len);
2206+
return None;
21792207
}
21802208
unsafe {
21812209
// infallible
@@ -2191,7 +2219,7 @@ impl<T, A: Allocator> Vec<T, A> {
21912219
ptr::copy(ptr.add(1), ptr, len - index - 1);
21922220
}
21932221
self.set_len(len - 1);
2194-
ret
2222+
Some(ret)
21952223
}
21962224
}
21972225

library/alloctests/tests/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#![feature(unique_rc_arc)]
4242
#![feature(macro_metavar_expr_concat)]
4343
#![feature(vec_peek_mut)]
44+
#![feature(vec_try_remove)]
4445
#![allow(internal_features)]
4546
#![deny(fuzzy_provenance_casts)]
4647
#![deny(unsafe_op_in_unsafe_fn)]

library/alloctests/tests/vec.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,21 @@ fn test_swap_remove_empty() {
630630
vec.swap_remove(0);
631631
}
632632

633+
#[test]
634+
fn test_try_remove() {
635+
let mut vec = vec![1, 2, 3];
636+
// We are attempting to remove vec[0] which contains 1
637+
assert_eq!(vec.try_remove(0), Some(1));
638+
// Now `vec` looks like: [2, 3]
639+
// We will now try to remove vec[2] which does not exist
640+
// This should return `None`
641+
assert_eq!(vec.try_remove(2), None);
642+
643+
// We will try the same thing with an empty vector
644+
let mut v: Vec<u8> = vec![];
645+
assert!(v.try_remove(0).is_none());
646+
}
647+
633648
#[test]
634649
fn test_move_items() {
635650
let vec = vec![1, 2, 3];

library/core/src/num/nonzero.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,18 @@ macro_rules! nonzero_integer {
548548
#[doc = concat!("assert_eq!(align_of::<", stringify!($Ty), ">(), align_of::<Option<", stringify!($Ty), ">>());")]
549549
/// ```
550550
///
551+
/// # Compile-time creation
552+
///
553+
/// Since both [`Option::unwrap()`] and [`Option::expect()`] are `const`, it is possible to
554+
/// define a new
555+
#[doc = concat!("`", stringify!($Ty), "`")]
556+
/// at compile time via:
557+
/// ```
558+
#[doc = concat!("use std::num::", stringify!($Ty), ";")]
559+
///
560+
#[doc = concat!("const TEN: ", stringify!($Ty), " = ", stringify!($Ty) , r#"::new(10).expect("ten is non-zero");"#)]
561+
/// ```
562+
///
551563
/// [null pointer optimization]: crate::option#representation
552564
#[$stability]
553565
pub type $Ty = NonZero<$Int>;

src/doc/rustc/src/symbol-mangling/v0.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -710,6 +710,7 @@ A *placeholder* may occur in circumstances where a type or const value is not re
710710
[mut-ptr-type]: #mut-ptr-type
711711
[fn-type]: #fn-type
712712
[dyn-trait-type]: #dyn-trait-type
713+
[pattern-type]: #pattern-type
713714
714715
> type → \
715716
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *[basic-type]* \
@@ -722,6 +723,7 @@ A *placeholder* may occur in circumstances where a type or const value is not re
722723
> &nbsp;&nbsp; | *[mut-ptr-type]* \
723724
> &nbsp;&nbsp; | *[fn-type]* \
724725
> &nbsp;&nbsp; | *[dyn-trait-type]* \
726+
> &nbsp;&nbsp; | *[pattern-type]* \
725727
> &nbsp;&nbsp; | *[path]* \
726728
> &nbsp;&nbsp; | *[backref]*
727729
@@ -830,6 +832,23 @@ Remaining primitives are encoded as a crate production, e.g. `C4f128`.
830832
[fn-sig]: #fn-sig
831833
[abi]: #abi
832834
835+
* `W` — A [pattern-type][pattern-tpye] `u32 is 0..100`.
836+
> <span id="pattern-type">pattern-type</span> → `W` *[pattern-kind]*
837+
>
838+
> <span id="pattern-kind">pattern-kind</span> → \
839+
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *[range-pattern-kind]* \
840+
> &nbsp;&nbsp; *[or-pattern-kind]*
841+
>
842+
> <span id="range-pattern-kind">range-pattern-kind</span> → `R` *[const]* *[const]*
843+
>
844+
> <span id="or-pattern-kind">or-pattern-kind</span> → `O` *[pattern-kind]* `E`
845+
846+
While or patterns can be nested in theory, in practice this does not happen and they are instead flattened.
847+
848+
Range patterns have a start and end constant that are both included in the range.
849+
The end must be larger than the start (there can be no wraparound). To emulate wraparound,
850+
you need to use an or pattern of the two ranges to the upper limit and from the lower limit.
851+
833852
* `D` — A [trait object][reference-trait-object] `dyn Trait<Assoc=X> + Send + 'a`.
834853
835854
> <span id="dyn-trait-type">dyn-trait-type</span> → `D` *[dyn-bounds]* *[lifetime]*
@@ -1139,6 +1158,7 @@ The following is a summary of all of the productions of the symbol grammar.
11391158
> &nbsp;&nbsp; | *[mut-ptr-type]* \
11401159
> &nbsp;&nbsp; | *[fn-type]* \
11411160
> &nbsp;&nbsp; | *[dyn-trait-type]* \
1161+
> &nbsp;&nbsp; | *[pattern-type]* \
11421162
> &nbsp;&nbsp; | *[path]* \
11431163
> &nbsp;&nbsp; | *[backref]*
11441164
>
@@ -1152,6 +1172,14 @@ The following is a summary of all of the productions of the symbol grammar.
11521172
> [mut-ptr-type] → `O` *[type]* \
11531173
> [fn-type] → `F` *[fn-sig]* \
11541174
> [dyn-trait-type] → `D` *[dyn-bounds]* *[lifetime]*
1175+
> [pattern-type] → `W` *[pattern-kind]*
1176+
>
1177+
> [pattern-kind] → \
1178+
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *[range-pattern-kind]* \
1179+
> &nbsp;&nbsp; *[or-pattern-kind]*
1180+
>
1181+
> [range-pattern-kind] -> `R` *[const]* *[const]* \
1182+
> [or-pattern-kind] -> `O` *[pattern-kind]* `E` \
11551183
>
11561184
> [namespace] → *[lower]* | *[upper]*
11571185
>

src/doc/rustdoc/src/advanced-features.md

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,20 +89,30 @@ https://doc.rust-lang.org/stable/std/?search=%s&go_to_first=true
8989
This URL adds the `go_to_first=true` query parameter which can be appended to any `rustdoc` search URL
9090
to automatically go to the first result.
9191

92-
## `#[repr(transparent)]`: Documenting the transparent representation
92+
## `#[repr(...)]`: Documenting the representation of a type
93+
94+
Generally, rustdoc only displays the representation of a given type if none of its variants are
95+
`#[doc(hidden)]` and if all of its fields are public and not `#[doc(hidden)]` since it's likely
96+
not meant to be considered part of the public ABI otherwise.
97+
98+
Note that there's no way to overwrite that heuristic and force rustdoc to show the representation
99+
regardless.
100+
101+
### `#[repr(transparent)]`
93102

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

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

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

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

0 commit comments

Comments
 (0)