Skip to content

Commit 535db2f

Browse files
authored
Rollup merge of rust-lang#60535 - taiki-e:async-fn-arguments, r=cramertj
Correct handling of arguments in async fn Fixes rust-lang#60509 Fixes rust-lang#60566 r? @cramertj or @davidtwco
2 parents 4e23358 + 57ec63c commit 535db2f

6 files changed

+341
-22
lines changed

src/libsyntax/parse/parser.rs

+22-11
Original file line numberDiff line numberDiff line change
@@ -1576,7 +1576,7 @@ impl<'a> Parser<'a> {
15761576
let ident = self.parse_ident()?;
15771577
let mut generics = self.parse_generics()?;
15781578

1579-
let d = self.parse_fn_decl_with_self(|p: &mut Parser<'a>| {
1579+
let mut decl = self.parse_fn_decl_with_self(|p: &mut Parser<'a>| {
15801580
// This is somewhat dubious; We don't want to allow
15811581
// argument names to be left off if there is a
15821582
// definition...
@@ -1585,7 +1585,7 @@ impl<'a> Parser<'a> {
15851585
p.parse_arg_general(p.span.rust_2018(), true, false)
15861586
})?;
15871587
generics.where_clause = self.parse_where_clause()?;
1588-
self.construct_async_arguments(&mut asyncness, &d);
1588+
self.construct_async_arguments(&mut asyncness, &mut decl);
15891589

15901590
let sig = ast::MethodSig {
15911591
header: FnHeader {
@@ -1594,7 +1594,7 @@ impl<'a> Parser<'a> {
15941594
abi,
15951595
asyncness,
15961596
},
1597-
decl: d,
1597+
decl,
15981598
};
15991599

16001600
let body = match self.token {
@@ -6475,10 +6475,10 @@ impl<'a> Parser<'a> {
64756475
-> PResult<'a, ItemInfo> {
64766476
let (ident, mut generics) = self.parse_fn_header()?;
64776477
let allow_c_variadic = abi == Abi::C && unsafety == Unsafety::Unsafe;
6478-
let decl = self.parse_fn_decl(allow_c_variadic)?;
6478+
let mut decl = self.parse_fn_decl(allow_c_variadic)?;
64796479
generics.where_clause = self.parse_where_clause()?;
64806480
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
6481-
self.construct_async_arguments(&mut asyncness, &decl);
6481+
self.construct_async_arguments(&mut asyncness, &mut decl);
64826482
let header = FnHeader { unsafety, asyncness, constness, abi };
64836483
Ok((ident, ItemKind::Fn(decl, header, generics, body), Some(inner_attrs)))
64846484
}
@@ -6662,9 +6662,9 @@ impl<'a> Parser<'a> {
66626662
let (constness, unsafety, mut asyncness, abi) = self.parse_fn_front_matter()?;
66636663
let ident = self.parse_ident()?;
66646664
let mut generics = self.parse_generics()?;
6665-
let decl = self.parse_fn_decl_with_self(|p| p.parse_arg())?;
6665+
let mut decl = self.parse_fn_decl_with_self(|p| p.parse_arg())?;
66666666
generics.where_clause = self.parse_where_clause()?;
6667-
self.construct_async_arguments(&mut asyncness, &decl);
6667+
self.construct_async_arguments(&mut asyncness, &mut decl);
66686668
*at_end = true;
66696669
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
66706670
let header = ast::FnHeader { abi, unsafety, constness, asyncness };
@@ -8710,9 +8710,9 @@ impl<'a> Parser<'a> {
87108710
///
87118711
/// The arguments of the function are replaced in HIR lowering with the arguments created by
87128712
/// this function and the statements created here are inserted at the top of the closure body.
8713-
fn construct_async_arguments(&mut self, asyncness: &mut Spanned<IsAsync>, decl: &FnDecl) {
8713+
fn construct_async_arguments(&mut self, asyncness: &mut Spanned<IsAsync>, decl: &mut FnDecl) {
87148714
if let IsAsync::Async { ref mut arguments, .. } = asyncness.node {
8715-
for (index, input) in decl.inputs.iter().enumerate() {
8715+
for (index, input) in decl.inputs.iter_mut().enumerate() {
87168716
let id = ast::DUMMY_NODE_ID;
87178717
let span = input.pat.span;
87188718

@@ -8724,8 +8724,10 @@ impl<'a> Parser<'a> {
87248724
// `let <pat> = __argN;` statement, instead just adding a `let <pat> = <pat>;`
87258725
// statement.
87268726
let (binding_mode, ident, is_simple_pattern) = match input.pat.node {
8727-
PatKind::Ident(binding_mode, ident, _) => (binding_mode, ident, true),
8728-
_ => (BindingMode::ByValue(Mutability::Immutable), ident, false),
8727+
PatKind::Ident(binding_mode @ BindingMode::ByValue(_), ident, _) => {
8728+
(binding_mode, ident, true)
8729+
}
8730+
_ => (BindingMode::ByValue(Mutability::Mutable), ident, false),
87298731
};
87308732

87318733
// Construct an argument representing `__argN: <ty>` to replace the argument of the
@@ -8792,6 +8794,15 @@ impl<'a> Parser<'a> {
87928794
})
87938795
};
87948796

8797+
// Remove mutability from arguments. If this is not a simple pattern,
8798+
// those arguments are replaced by `__argN`, so there is no need to do this.
8799+
if let PatKind::Ident(BindingMode::ByValue(mutability @ Mutability::Mutable), ..) =
8800+
&mut input.pat.node
8801+
{
8802+
assert!(is_simple_pattern);
8803+
*mutability = Mutability::Immutable;
8804+
}
8805+
87958806
let move_stmt = Stmt { id, node: StmtKind::Local(P(move_local)), span };
87968807
arguments.push(AsyncArgument { ident, arg, pat_stmt, move_stmt });
87978808
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// edition:2018
2+
// run-pass
3+
4+
#![allow(unused_variables)]
5+
#![deny(unused_mut)]
6+
#![feature(async_await)]
7+
8+
type A = Vec<u32>;
9+
10+
async fn a(n: u32, mut vec: A) {
11+
vec.push(n);
12+
}
13+
14+
async fn b(n: u32, ref mut vec: A) {
15+
vec.push(n);
16+
}
17+
18+
async fn c(ref vec: A) {
19+
vec.contains(&0);
20+
}
21+
22+
async fn d((a, mut b): (A, A)) {
23+
b.push(1);
24+
}
25+
26+
async fn f((ref mut a, ref b): (A, A)) {}
27+
28+
async fn g(((ref a, ref mut b), (ref mut c, ref d)): ((A, A), (A, A))) {}
29+
30+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
// aux-build:arc_wake.rs
2+
// edition:2018
3+
// run-pass
4+
5+
#![allow(unused_variables)]
6+
#![feature(async_await, await_macro)]
7+
8+
// Test that the drop order for parameters in a fn and async fn matches up. Also test that
9+
// parameters (used or unused) are not dropped until the async fn completes execution.
10+
// See also #54716.
11+
12+
extern crate arc_wake;
13+
14+
use arc_wake::ArcWake;
15+
use std::cell::RefCell;
16+
use std::future::Future;
17+
use std::marker::PhantomData;
18+
use std::sync::Arc;
19+
use std::rc::Rc;
20+
use std::task::Context;
21+
22+
struct EmptyWaker;
23+
24+
impl ArcWake for EmptyWaker {
25+
fn wake(self: Arc<Self>) {}
26+
}
27+
28+
#[derive(Debug, Eq, PartialEq)]
29+
enum DropOrder {
30+
Function,
31+
Val(&'static str),
32+
}
33+
34+
type DropOrderListPtr = Rc<RefCell<Vec<DropOrder>>>;
35+
36+
struct D(&'static str, DropOrderListPtr);
37+
38+
impl Drop for D {
39+
fn drop(&mut self) {
40+
self.1.borrow_mut().push(DropOrder::Val(self.0));
41+
}
42+
}
43+
44+
/// Check that unused bindings are dropped after the function is polled.
45+
async fn foo_async(ref mut x: D, ref mut _y: D) {
46+
x.1.borrow_mut().push(DropOrder::Function);
47+
}
48+
49+
fn foo_sync(ref mut x: D, ref mut _y: D) {
50+
x.1.borrow_mut().push(DropOrder::Function);
51+
}
52+
53+
/// Check that underscore patterns are dropped after the function is polled.
54+
async fn bar_async(ref mut x: D, _: D) {
55+
x.1.borrow_mut().push(DropOrder::Function);
56+
}
57+
58+
fn bar_sync(ref mut x: D, _: D) {
59+
x.1.borrow_mut().push(DropOrder::Function);
60+
}
61+
62+
/// Check that underscore patterns within more complex patterns are dropped after the function
63+
/// is polled.
64+
async fn baz_async((ref mut x, _): (D, D)) {
65+
x.1.borrow_mut().push(DropOrder::Function);
66+
}
67+
68+
fn baz_sync((ref mut x, _): (D, D)) {
69+
x.1.borrow_mut().push(DropOrder::Function);
70+
}
71+
72+
/// Check that underscore and unused bindings within and outwith more complex patterns are dropped
73+
/// after the function is polled.
74+
async fn foobar_async(ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D) {
75+
x.1.borrow_mut().push(DropOrder::Function);
76+
}
77+
78+
fn foobar_sync(ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D) {
79+
x.1.borrow_mut().push(DropOrder::Function);
80+
}
81+
82+
struct Foo;
83+
84+
impl Foo {
85+
/// Check that unused bindings are dropped after the method is polled.
86+
async fn foo_async(ref mut x: D, ref mut _y: D) {
87+
x.1.borrow_mut().push(DropOrder::Function);
88+
}
89+
90+
fn foo_sync(ref mut x: D, ref mut _y: D) {
91+
x.1.borrow_mut().push(DropOrder::Function);
92+
}
93+
94+
/// Check that underscore patterns are dropped after the method is polled.
95+
async fn bar_async(ref mut x: D, _: D) {
96+
x.1.borrow_mut().push(DropOrder::Function);
97+
}
98+
99+
fn bar_sync(ref mut x: D, _: D) {
100+
x.1.borrow_mut().push(DropOrder::Function);
101+
}
102+
103+
/// Check that underscore patterns within more complex patterns are dropped after the method
104+
/// is polled.
105+
async fn baz_async((ref mut x, _): (D, D)) {
106+
x.1.borrow_mut().push(DropOrder::Function);
107+
}
108+
109+
fn baz_sync((ref mut x, _): (D, D)) {
110+
x.1.borrow_mut().push(DropOrder::Function);
111+
}
112+
113+
/// Check that underscore and unused bindings within and outwith more complex patterns are
114+
/// dropped after the method is polled.
115+
async fn foobar_async(
116+
ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D,
117+
) {
118+
x.1.borrow_mut().push(DropOrder::Function);
119+
}
120+
121+
fn foobar_sync(
122+
ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D,
123+
) {
124+
x.1.borrow_mut().push(DropOrder::Function);
125+
}
126+
}
127+
128+
struct Bar<'a>(PhantomData<&'a ()>);
129+
130+
impl<'a> Bar<'a> {
131+
/// Check that unused bindings are dropped after the method with self is polled.
132+
async fn foo_async(&'a self, ref mut x: D, ref mut _y: D) {
133+
x.1.borrow_mut().push(DropOrder::Function);
134+
}
135+
136+
fn foo_sync(&'a self, ref mut x: D, ref mut _y: D) {
137+
x.1.borrow_mut().push(DropOrder::Function);
138+
}
139+
140+
/// Check that underscore patterns are dropped after the method with self is polled.
141+
async fn bar_async(&'a self, ref mut x: D, _: D) {
142+
x.1.borrow_mut().push(DropOrder::Function);
143+
}
144+
145+
fn bar_sync(&'a self, ref mut x: D, _: D) {
146+
x.1.borrow_mut().push(DropOrder::Function);
147+
}
148+
149+
/// Check that underscore patterns within more complex patterns are dropped after the method
150+
/// with self is polled.
151+
async fn baz_async(&'a self, (ref mut x, _): (D, D)) {
152+
x.1.borrow_mut().push(DropOrder::Function);
153+
}
154+
155+
fn baz_sync(&'a self, (ref mut x, _): (D, D)) {
156+
x.1.borrow_mut().push(DropOrder::Function);
157+
}
158+
159+
/// Check that underscore and unused bindings within and outwith more complex patterns are
160+
/// dropped after the method with self is polled.
161+
async fn foobar_async(
162+
&'a self, ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D,
163+
) {
164+
x.1.borrow_mut().push(DropOrder::Function);
165+
}
166+
167+
fn foobar_sync(
168+
&'a self, ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D,
169+
) {
170+
x.1.borrow_mut().push(DropOrder::Function);
171+
}
172+
}
173+
174+
fn assert_drop_order_after_poll<Fut: Future<Output = ()>>(
175+
f: impl FnOnce(DropOrderListPtr) -> Fut,
176+
g: impl FnOnce(DropOrderListPtr),
177+
) {
178+
let empty = Arc::new(EmptyWaker);
179+
let waker = ArcWake::into_waker(empty);
180+
let mut cx = Context::from_waker(&waker);
181+
182+
let actual_order = Rc::new(RefCell::new(Vec::new()));
183+
let mut fut = Box::pin(f(actual_order.clone()));
184+
let _ = fut.as_mut().poll(&mut cx);
185+
186+
let expected_order = Rc::new(RefCell::new(Vec::new()));
187+
g(expected_order.clone());
188+
189+
assert_eq!(*actual_order.borrow(), *expected_order.borrow());
190+
}
191+
192+
fn main() {
193+
// Free functions (see doc comment on function for what it tests).
194+
assert_drop_order_after_poll(|l| foo_async(D("x", l.clone()), D("_y", l.clone())),
195+
|l| foo_sync(D("x", l.clone()), D("_y", l.clone())));
196+
assert_drop_order_after_poll(|l| bar_async(D("x", l.clone()), D("_", l.clone())),
197+
|l| bar_sync(D("x", l.clone()), D("_", l.clone())));
198+
assert_drop_order_after_poll(|l| baz_async((D("x", l.clone()), D("_", l.clone()))),
199+
|l| baz_sync((D("x", l.clone()), D("_", l.clone()))));
200+
assert_drop_order_after_poll(
201+
|l| {
202+
foobar_async(
203+
D("x", l.clone()),
204+
(D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
205+
D("_", l.clone()),
206+
D("_y", l.clone()),
207+
)
208+
},
209+
|l| {
210+
foobar_sync(
211+
D("x", l.clone()),
212+
(D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
213+
D("_", l.clone()),
214+
D("_y", l.clone()),
215+
)
216+
},
217+
);
218+
219+
// Methods w/out self (see doc comment on function for what it tests).
220+
assert_drop_order_after_poll(|l| Foo::foo_async(D("x", l.clone()), D("_y", l.clone())),
221+
|l| Foo::foo_sync(D("x", l.clone()), D("_y", l.clone())));
222+
assert_drop_order_after_poll(|l| Foo::bar_async(D("x", l.clone()), D("_", l.clone())),
223+
|l| Foo::bar_sync(D("x", l.clone()), D("_", l.clone())));
224+
assert_drop_order_after_poll(|l| Foo::baz_async((D("x", l.clone()), D("_", l.clone()))),
225+
|l| Foo::baz_sync((D("x", l.clone()), D("_", l.clone()))));
226+
assert_drop_order_after_poll(
227+
|l| {
228+
Foo::foobar_async(
229+
D("x", l.clone()),
230+
(D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
231+
D("_", l.clone()),
232+
D("_y", l.clone()),
233+
)
234+
},
235+
|l| {
236+
Foo::foobar_sync(
237+
D("x", l.clone()),
238+
(D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
239+
D("_", l.clone()),
240+
D("_y", l.clone()),
241+
)
242+
},
243+
);
244+
245+
// Methods (see doc comment on function for what it tests).
246+
let b = Bar(Default::default());
247+
assert_drop_order_after_poll(|l| b.foo_async(D("x", l.clone()), D("_y", l.clone())),
248+
|l| b.foo_sync(D("x", l.clone()), D("_y", l.clone())));
249+
assert_drop_order_after_poll(|l| b.bar_async(D("x", l.clone()), D("_", l.clone())),
250+
|l| b.bar_sync(D("x", l.clone()), D("_", l.clone())));
251+
assert_drop_order_after_poll(|l| b.baz_async((D("x", l.clone()), D("_", l.clone()))),
252+
|l| b.baz_sync((D("x", l.clone()), D("_", l.clone()))));
253+
assert_drop_order_after_poll(
254+
|l| {
255+
b.foobar_async(
256+
D("x", l.clone()),
257+
(D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
258+
D("_", l.clone()),
259+
D("_y", l.clone()),
260+
)
261+
},
262+
|l| {
263+
b.foobar_sync(
264+
D("x", l.clone()),
265+
(D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
266+
D("_", l.clone()),
267+
D("_y", l.clone()),
268+
)
269+
},
270+
);
271+
}

0 commit comments

Comments
 (0)