Skip to content

Commit 27d42bd

Browse files
committed
Auto merge of rust-lang#91799 - matthiaskrgr:rollup-b38xx6i, r=matthiaskrgr
Rollup of 6 pull requests Successful merges: - rust-lang#83174 (Suggest using a temporary variable to fix borrowck errors) - rust-lang#89734 (Point at capture points for non-`'static` reference crossing a `yield` point) - rust-lang#90270 (Make `Borrow` and `BorrowMut` impls `const`) - rust-lang#90741 (Const `Option::cloned`) - rust-lang#91548 (Add spin_loop hint for RISC-V architecture) - rust-lang#91721 (Minor improvements to `future::join!`'s implementation) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
2 parents 989b8d6 + 440afa8 commit 27d42bd

File tree

8 files changed

+174
-66
lines changed

8 files changed

+174
-66
lines changed

core/src/array/mod.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,14 +162,16 @@ impl<T, const N: usize> AsMut<[T]> for [T; N] {
162162
}
163163

164164
#[stable(feature = "array_borrow", since = "1.4.0")]
165-
impl<T, const N: usize> Borrow<[T]> for [T; N] {
165+
#[rustc_const_unstable(feature = "const_borrow", issue = "91522")]
166+
impl<T, const N: usize> const Borrow<[T]> for [T; N] {
166167
fn borrow(&self) -> &[T] {
167168
self
168169
}
169170
}
170171

171172
#[stable(feature = "array_borrow", since = "1.4.0")]
172-
impl<T, const N: usize> BorrowMut<[T]> for [T; N] {
173+
#[rustc_const_unstable(feature = "const_borrow", issue = "91522")]
174+
impl<T, const N: usize> const BorrowMut<[T]> for [T; N] {
173175
fn borrow_mut(&mut self) -> &mut [T] {
174176
self
175177
}

core/src/borrow.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -205,36 +205,41 @@ pub trait BorrowMut<Borrowed: ?Sized>: Borrow<Borrowed> {
205205
}
206206

207207
#[stable(feature = "rust1", since = "1.0.0")]
208-
impl<T: ?Sized> Borrow<T> for T {
208+
#[rustc_const_unstable(feature = "const_borrow", issue = "91522")]
209+
impl<T: ?Sized> const Borrow<T> for T {
209210
#[rustc_diagnostic_item = "noop_method_borrow"]
210211
fn borrow(&self) -> &T {
211212
self
212213
}
213214
}
214215

215216
#[stable(feature = "rust1", since = "1.0.0")]
216-
impl<T: ?Sized> BorrowMut<T> for T {
217+
#[rustc_const_unstable(feature = "const_borrow", issue = "91522")]
218+
impl<T: ?Sized> const BorrowMut<T> for T {
217219
fn borrow_mut(&mut self) -> &mut T {
218220
self
219221
}
220222
}
221223

222224
#[stable(feature = "rust1", since = "1.0.0")]
223-
impl<T: ?Sized> Borrow<T> for &T {
225+
#[rustc_const_unstable(feature = "const_borrow", issue = "91522")]
226+
impl<T: ?Sized> const Borrow<T> for &T {
224227
fn borrow(&self) -> &T {
225228
&**self
226229
}
227230
}
228231

229232
#[stable(feature = "rust1", since = "1.0.0")]
230-
impl<T: ?Sized> Borrow<T> for &mut T {
233+
#[rustc_const_unstable(feature = "const_borrow", issue = "91522")]
234+
impl<T: ?Sized> const Borrow<T> for &mut T {
231235
fn borrow(&self) -> &T {
232236
&**self
233237
}
234238
}
235239

236240
#[stable(feature = "rust1", since = "1.0.0")]
237-
impl<T: ?Sized> BorrowMut<T> for &mut T {
241+
#[rustc_const_unstable(feature = "const_borrow", issue = "91522")]
242+
impl<T: ?Sized> const BorrowMut<T> for &mut T {
238243
fn borrow_mut(&mut self) -> &mut T {
239244
&mut **self
240245
}

core/src/future/join.rs

Lines changed: 100 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#![allow(unused_imports)] // items are used by the macro
1+
#![allow(unused_imports, unused_macros)] // items are used by the macro
22

33
use crate::cell::UnsafeCell;
44
use crate::future::{poll_fn, Future};
@@ -45,59 +45,104 @@ use crate::task::{Context, Poll};
4545
/// # };
4646
/// ```
4747
#[unstable(feature = "future_join", issue = "91642")]
48-
pub macro join {
49-
( $($fut:expr),* $(,)?) => {
50-
join! { @count: (), @futures: {}, @rest: ($($fut,)*) }
51-
},
52-
// Recurse until we have the position of each future in the tuple
48+
pub macro join( $($fut:expr),+ $(,)? ) {
49+
// Funnel through an internal macro not to leak implementation details.
50+
join_internal! {
51+
current_position: []
52+
futures_and_positions: []
53+
munching: [ $($fut)+ ]
54+
}
55+
}
56+
57+
// FIXME(danielhenrymantilla): a private macro should need no stability guarantee.
58+
#[unstable(feature = "future_join", issue = "91642")]
59+
/// To be able to *name* the i-th future in the tuple (say we want the .4-th),
60+
/// the following trick will be used: `let (_, _, _, _, it, ..) = tuple;`
61+
/// In order to do that, we need to generate a `i`-long repetition of `_`,
62+
/// for each i-th fut. Hence the recursive muncher approach.
63+
macro join_internal {
64+
// Recursion step: map each future with its "position" (underscore count).
5365
(
54-
// A token for each future that has been expanded: "_ _ _"
55-
@count: ($($count:tt)*),
56-
// Futures and their positions in the tuple: "{ a => (_), b => (_ _)) }"
57-
@futures: { $($fut:tt)* },
58-
// Take a future from @rest to expand
59-
@rest: ($current:expr, $($rest:tt)*)
60-
) => {
61-
join! {
62-
@count: ($($count)* _),
63-
@futures: { $($fut)* $current => ($($count)*), },
64-
@rest: ($($rest)*)
66+
// Accumulate a token for each future that has been expanded: "_ _ _".
67+
current_position: [
68+
$($underscores:tt)*
69+
]
70+
// Accumulate Futures and their positions in the tuple: `_0th () _1st ( _ ) …`.
71+
futures_and_positions: [
72+
$($acc:tt)*
73+
]
74+
// Munch one future.
75+
munching: [
76+
$current:tt
77+
$($rest:tt)*
78+
]
79+
) => (
80+
join_internal! {
81+
current_position: [
82+
$($underscores)*
83+
_
84+
]
85+
futures_and_positions: [
86+
$($acc)*
87+
$current ( $($underscores)* )
88+
]
89+
munching: [
90+
$($rest)*
91+
]
6592
}
66-
},
67-
// Now generate the output future
68-
(
69-
@count: ($($count:tt)*),
70-
@futures: {
71-
$( $(@$f:tt)? $fut:expr => ( $($pos:tt)* ), )*
72-
},
73-
@rest: ()
74-
) => {
75-
async move {
76-
let mut futures = ( $( MaybeDone::Future($fut), )* );
93+
),
7794

95+
// End of recursion: generate the output future.
96+
(
97+
current_position: $_:tt
98+
futures_and_positions: [
99+
$(
100+
$fut_expr:tt ( $($pos:tt)* )
101+
)*
102+
]
103+
// Nothing left to munch.
104+
munching: []
105+
) => (
106+
match ( $( MaybeDone::Future($fut_expr), )* ) { futures => async {
107+
let mut futures = futures;
108+
// SAFETY: this is `pin_mut!`.
109+
let mut futures = unsafe { Pin::new_unchecked(&mut futures) };
78110
poll_fn(move |cx| {
79111
let mut done = true;
80-
112+
// For each `fut`, pin-project to it, and poll it.
81113
$(
82-
let ( $($pos,)* fut, .. ) = &mut futures;
83-
84-
// SAFETY: The futures are never moved
85-
done &= unsafe { Pin::new_unchecked(fut).poll(cx).is_ready() };
114+
// SAFETY: pinning projection
115+
let fut = unsafe {
116+
futures.as_mut().map_unchecked_mut(|it| {
117+
let ( $($pos,)* fut, .. ) = it;
118+
fut
119+
})
120+
};
121+
// Despite how tempting it may be to `let () = fut.poll(cx).ready()?;`
122+
// doing so would defeat the point of `join!`: to start polling eagerly all
123+
// of the futures, to allow parallelizing the waits.
124+
done &= fut.poll(cx).is_ready();
86125
)*
87-
88-
if done {
89-
// Extract all the outputs
90-
Poll::Ready(($({
91-
let ( $($pos,)* fut, .. ) = &mut futures;
92-
93-
fut.take_output().unwrap()
94-
}),*))
95-
} else {
96-
Poll::Pending
126+
if !done {
127+
return Poll::Pending;
97128
}
129+
// All ready; time to extract all the outputs.
130+
131+
// SAFETY: `.take_output()` does not break the `Pin` invariants for that `fut`.
132+
let futures = unsafe {
133+
futures.as_mut().get_unchecked_mut()
134+
};
135+
Poll::Ready(
136+
($(
137+
{
138+
let ( $($pos,)* fut, .. ) = &mut *futures;
139+
fut.take_output().unwrap()
140+
}
141+
),*) // <- no trailing comma since we don't want 1-tuples.
142+
)
98143
}).await
99-
}
100-
}
144+
}}
145+
),
101146
}
102147

103148
/// Future used by `join!` that stores it's output to
@@ -109,14 +154,14 @@ pub macro join {
109154
pub enum MaybeDone<F: Future> {
110155
Future(F),
111156
Done(F::Output),
112-
Took,
157+
Taken,
113158
}
114159

115160
#[unstable(feature = "future_join", issue = "91642")]
116161
impl<F: Future> MaybeDone<F> {
117162
pub fn take_output(&mut self) -> Option<F::Output> {
118-
match &*self {
119-
MaybeDone::Done(_) => match mem::replace(self, Self::Took) {
163+
match *self {
164+
MaybeDone::Done(_) => match mem::replace(self, Self::Taken) {
120165
MaybeDone::Done(val) => Some(val),
121166
_ => unreachable!(),
122167
},
@@ -132,13 +177,14 @@ impl<F: Future> Future for MaybeDone<F> {
132177
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
133178
// SAFETY: pinning in structural for `f`
134179
unsafe {
135-
match self.as_mut().get_unchecked_mut() {
136-
MaybeDone::Future(f) => match Pin::new_unchecked(f).poll(cx) {
137-
Poll::Ready(val) => self.set(Self::Done(val)),
138-
Poll::Pending => return Poll::Pending,
139-
},
180+
// Do not mix match ergonomics with unsafe.
181+
match *self.as_mut().get_unchecked_mut() {
182+
MaybeDone::Future(ref mut f) => {
183+
let val = Pin::new_unchecked(f).poll(cx).ready()?;
184+
self.set(Self::Done(val));
185+
}
140186
MaybeDone::Done(_) => {}
141-
MaybeDone::Took => unreachable!(),
187+
MaybeDone::Taken => unreachable!(),
142188
}
143189
}
144190

core/src/hint.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,11 @@ pub fn spin_loop() {
137137
unsafe { crate::arch::arm::__yield() };
138138
}
139139
}
140+
141+
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
142+
{
143+
crate::arch::riscv::pause();
144+
}
140145
}
141146

142147
/// An identity function that *__hints__* to the compiler to be maximally pessimistic about what

core/src/option.rs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1523,8 +1523,15 @@ impl<T: Clone> Option<&T> {
15231523
/// ```
15241524
#[must_use = "`self` will be dropped if the result is not used"]
15251525
#[stable(feature = "rust1", since = "1.0.0")]
1526-
pub fn cloned(self) -> Option<T> {
1527-
self.map(|t| t.clone())
1526+
#[rustc_const_unstable(feature = "const_option_cloned", issue = "91582")]
1527+
pub const fn cloned(self) -> Option<T>
1528+
where
1529+
T: ~const Clone,
1530+
{
1531+
match self {
1532+
Some(t) => Some(t.clone()),
1533+
None => None,
1534+
}
15281535
}
15291536
}
15301537

@@ -1541,9 +1548,17 @@ impl<T: Clone> Option<&mut T> {
15411548
/// let cloned = opt_x.cloned();
15421549
/// assert_eq!(cloned, Some(12));
15431550
/// ```
1551+
#[must_use = "`self` will be dropped if the result is not used"]
15441552
#[stable(since = "1.26.0", feature = "option_ref_mut_cloned")]
1545-
pub fn cloned(self) -> Option<T> {
1546-
self.map(|t| t.clone())
1553+
#[rustc_const_unstable(feature = "const_option_cloned", issue = "91582")]
1554+
pub const fn cloned(self) -> Option<T>
1555+
where
1556+
T: ~const Clone,
1557+
{
1558+
match self {
1559+
Some(t) => Some(t.clone()),
1560+
None => None,
1561+
}
15471562
}
15481563
}
15491564

core/tests/future.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,40 @@ fn test_join() {
6464
});
6565
}
6666

67+
/// Tests that `join!(…)` behaves "like a function": evaluating its arguments
68+
/// before applying any of its own logic.
69+
///
70+
/// _e.g._, `join!(async_fn(&borrowed), …)` does not consume `borrowed`;
71+
/// and `join!(opt_fut?, …)` does let that `?` refer to the callsite scope.
72+
mod test_join_function_like_value_arg_semantics {
73+
use super::*;
74+
75+
async fn async_fn(_: impl Sized) {}
76+
77+
// no need to _run_ this test, just to compile it.
78+
fn _join_does_not_unnecessarily_move_mentioned_bindings() {
79+
let not_copy = vec![()];
80+
let _ = join!(async_fn(&not_copy)); // should not move `not_copy`
81+
let _ = &not_copy; // OK
82+
}
83+
84+
#[test]
85+
fn join_lets_control_flow_effects_such_as_try_flow_through() {
86+
let maybe_fut = None;
87+
if false {
88+
*&mut { maybe_fut } = Some(async {});
89+
loop {}
90+
}
91+
assert!(Option::is_none(&try { join!(maybe_fut?, async { unreachable!() }) }));
92+
}
93+
94+
#[test]
95+
fn join_is_able_to_handle_temporaries() {
96+
let _ = join!(async_fn(&String::from("temporary")));
97+
let () = block_on(join!(async_fn(&String::from("temporary"))));
98+
}
99+
}
100+
67101
fn block_on(fut: impl Future) {
68102
struct Waker;
69103
impl Wake for Waker {

core/tests/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
#![feature(str_internals)]
5050
#![feature(test)]
5151
#![feature(trusted_len)]
52+
#![feature(try_blocks)]
5253
#![feature(try_trait_v2)]
5354
#![feature(slice_internals)]
5455
#![feature(slice_partition_dedup)]

stdarch

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Subproject commit cfba59fccd90b3b52a614120834320f764ab08d1
1+
Subproject commit b70ae88ef2a6c83acad0a1e83d5bd78f9655fd05

0 commit comments

Comments
 (0)