Skip to content

Commit 1ddb278

Browse files
committed
Auto merge of rust-lang#81905 - Dylan-DPC:rollup-mxpz1j7, r=Dylan-DPC
Rollup of 11 pull requests Successful merges: - rust-lang#72209 (Add checking for no_mangle to unsafe_code lint) - rust-lang#80732 (Allow Trait inheritance with cycles on associated types take 2) - rust-lang#81697 (Add "every" as a doc alias for "all".) - rust-lang#81826 (Prefer match over combinators to make some Box methods inlineable) - rust-lang#81834 (Resolve typedef in HashMap lldb pretty-printer only if possible) - rust-lang#81841 ([rustbuild] Output rustdoc-json-types docs ) - rust-lang#81849 (Expand the docs for ops::ControlFlow a bit) - rust-lang#81876 (parser: Fix panic in 'const impl' recovery) - rust-lang#81882 (:arrow_up: rust-analyzer) - rust-lang#81888 (Fix pretty printer macro_rules with semicolon.) - rust-lang#81896 (Remove outdated comment in windows' mutex.rs) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
2 parents f02fdbe + 08ff93d commit 1ddb278

File tree

7 files changed

+117
-7
lines changed

7 files changed

+117
-7
lines changed

alloc/src/boxed.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,12 @@ impl<T, A: Allocator> Box<T, A> {
390390
// #[unstable(feature = "new_uninit", issue = "63291")]
391391
pub fn new_uninit_in(alloc: A) -> Box<mem::MaybeUninit<T>, A> {
392392
let layout = Layout::new::<mem::MaybeUninit<T>>();
393-
Box::try_new_uninit_in(alloc).unwrap_or_else(|_| handle_alloc_error(layout))
393+
// NOTE: Prefer match over unwrap_or_else since closure sometimes not inlineable.
394+
// That would make code size bigger.
395+
match Box::try_new_uninit_in(alloc) {
396+
Ok(m) => m,
397+
Err(_) => handle_alloc_error(layout),
398+
}
394399
}
395400

396401
/// Constructs a new box with uninitialized contents in the provided allocator,
@@ -447,7 +452,12 @@ impl<T, A: Allocator> Box<T, A> {
447452
// #[unstable(feature = "new_uninit", issue = "63291")]
448453
pub fn new_zeroed_in(alloc: A) -> Box<mem::MaybeUninit<T>, A> {
449454
let layout = Layout::new::<mem::MaybeUninit<T>>();
450-
Box::try_new_zeroed_in(alloc).unwrap_or_else(|_| handle_alloc_error(layout))
455+
// NOTE: Prefer match over unwrap_or_else since closure sometimes not inlineable.
456+
// That would make code size bigger.
457+
match Box::try_new_zeroed_in(alloc) {
458+
Ok(m) => m,
459+
Err(_) => handle_alloc_error(layout),
460+
}
451461
}
452462

453463
/// Constructs a new `Box` with uninitialized contents, with the memory

core/src/iter/traits/iterator.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2205,6 +2205,7 @@ pub trait Iterator {
22052205
/// // we can still use `iter`, as there are more elements.
22062206
/// assert_eq!(iter.next(), Some(&3));
22072207
/// ```
2208+
#[doc(alias = "every")]
22082209
#[inline]
22092210
#[stable(feature = "rust1", since = "1.0.0")]
22102211
fn all<F>(&mut self, f: F) -> bool

core/src/ops/control_flow.rs

Lines changed: 83 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,63 @@
11
use crate::ops::Try;
22

3-
/// Used to make try_fold closures more like normal loops
3+
/// Used to tell an operation whether it should exit early or go on as usual.
4+
///
5+
/// This is used when exposing things (like graph traversals or visitors) where
6+
/// you want the user to be able to choose whether to exit early.
7+
/// Having the enum makes it clearer -- no more wondering "wait, what did `false`
8+
/// mean again?" -- and allows including a value.
9+
///
10+
/// # Examples
11+
///
12+
/// Early-exiting from [`Iterator::try_for_each`]:
13+
/// ```
14+
/// #![feature(control_flow_enum)]
15+
/// use std::ops::ControlFlow;
16+
///
17+
/// let r = (2..100).try_for_each(|x| {
18+
/// if 403 % x == 0 {
19+
/// return ControlFlow::Break(x)
20+
/// }
21+
///
22+
/// ControlFlow::Continue(())
23+
/// });
24+
/// assert_eq!(r, ControlFlow::Break(13));
25+
/// ```
26+
///
27+
/// A basic tree traversal:
28+
/// ```no_run
29+
/// #![feature(control_flow_enum)]
30+
/// use std::ops::ControlFlow;
31+
///
32+
/// pub struct TreeNode<T> {
33+
/// value: T,
34+
/// left: Option<Box<TreeNode<T>>>,
35+
/// right: Option<Box<TreeNode<T>>>,
36+
/// }
37+
///
38+
/// impl<T> TreeNode<T> {
39+
/// pub fn traverse_inorder<B>(&self, mut f: impl FnMut(&T) -> ControlFlow<B>) -> ControlFlow<B> {
40+
/// if let Some(left) = &self.left {
41+
/// left.traverse_inorder(&mut f)?;
42+
/// }
43+
/// f(&self.value)?;
44+
/// if let Some(right) = &self.right {
45+
/// right.traverse_inorder(&mut f)?;
46+
/// }
47+
/// ControlFlow::Continue(())
48+
/// }
49+
/// }
50+
/// ```
451
#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
552
#[derive(Debug, Clone, Copy, PartialEq)]
653
pub enum ControlFlow<B, C = ()> {
7-
/// Continue in the loop, using the given value for the next iteration
54+
/// Move on to the next phase of the operation as normal.
855
Continue(C),
9-
/// Exit the loop, yielding the given value
56+
/// Exit the operation without running subsequent phases.
1057
Break(B),
58+
// Yes, the order of the variants doesn't match the type parameters.
59+
// They're in this order so that `ControlFlow<A, B>` <-> `Result<B, A>`
60+
// is a no-op conversion in the `Try` implementation.
1161
}
1262

1363
#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
@@ -33,13 +83,33 @@ impl<B, C> Try for ControlFlow<B, C> {
3383

3484
impl<B, C> ControlFlow<B, C> {
3585
/// Returns `true` if this is a `Break` variant.
86+
///
87+
/// # Examples
88+
///
89+
/// ```
90+
/// #![feature(control_flow_enum)]
91+
/// use std::ops::ControlFlow;
92+
///
93+
/// assert!(ControlFlow::<i32, String>::Break(3).is_break());
94+
/// assert!(!ControlFlow::<String, i32>::Continue(3).is_break());
95+
/// ```
3696
#[inline]
3797
#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
3898
pub fn is_break(&self) -> bool {
3999
matches!(*self, ControlFlow::Break(_))
40100
}
41101

42102
/// Returns `true` if this is a `Continue` variant.
103+
///
104+
/// # Examples
105+
///
106+
/// ```
107+
/// #![feature(control_flow_enum)]
108+
/// use std::ops::ControlFlow;
109+
///
110+
/// assert!(!ControlFlow::<i32, String>::Break(3).is_continue());
111+
/// assert!(ControlFlow::<String, i32>::Continue(3).is_continue());
112+
/// ```
43113
#[inline]
44114
#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
45115
pub fn is_continue(&self) -> bool {
@@ -48,6 +118,16 @@ impl<B, C> ControlFlow<B, C> {
48118

49119
/// Converts the `ControlFlow` into an `Option` which is `Some` if the
50120
/// `ControlFlow` was `Break` and `None` otherwise.
121+
///
122+
/// # Examples
123+
///
124+
/// ```
125+
/// #![feature(control_flow_enum)]
126+
/// use std::ops::ControlFlow;
127+
///
128+
/// assert_eq!(ControlFlow::<i32, String>::Break(3).break_value(), Some(3));
129+
/// assert_eq!(ControlFlow::<String, i32>::Continue(3).break_value(), None);
130+
/// ```
51131
#[inline]
52132
#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
53133
pub fn break_value(self) -> Option<B> {

core/tests/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#![feature(const_maybe_uninit_assume_init)]
1616
#![feature(const_ptr_read)]
1717
#![feature(const_ptr_offset)]
18+
#![feature(control_flow_enum)]
1819
#![feature(core_intrinsics)]
1920
#![feature(core_private_bignum)]
2021
#![feature(core_private_diy_float)]

core/tests/ops.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
mod control_flow;
2+
13
use core::ops::{Bound, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive};
24
use core::ops::{Deref, DerefMut};
35

core/tests/ops/control_flow.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
use core::intrinsics::discriminant_value;
2+
use core::ops::ControlFlow;
3+
4+
#[test]
5+
fn control_flow_discriminants_match_result() {
6+
// This isn't stable surface area, but helps keep `?` cheap between them,
7+
// even if LLVM can't always take advantage of it right now.
8+
// (Sadly Result and Option are inconsistent, so ControlFlow can't match both.)
9+
10+
assert_eq!(
11+
discriminant_value(&ControlFlow::<i32, i32>::Break(3)),
12+
discriminant_value(&Result::<i32, i32>::Err(3)),
13+
);
14+
assert_eq!(
15+
discriminant_value(&ControlFlow::<i32, i32>::Continue(3)),
16+
discriminant_value(&Result::<i32, i32>::Ok(3)),
17+
);
18+
}

std/src/sys/windows/mutex.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@ pub struct Mutex {
2323
}
2424

2525
// Windows SRW Locks are movable (while not borrowed).
26-
// ReentrantMutexes (in Inner) are not, but those are stored indirectly through
27-
// a Box, so do not move when the Mutex it self is moved.
2826
pub type MovableMutex = Mutex;
2927

3028
unsafe impl Send for Mutex {}

0 commit comments

Comments
 (0)