Skip to content

Commit 16939a5

Browse files
authoredMay 1, 2019
Rollup merge of rust-lang#60437 - davidtwco:issue-60236, r=nikomatsakis
Ensure that drop order of `async fn` matches `fn` and that users cannot refer to generated arguments. Fixes rust-lang#60236 and fixes rust-lang#60438. This PR modifies the lowering of `async fn` arguments so that the drop order matches the equivalent `fn`. Previously, async function arguments were lowered as shown below: async fn foo(<pattern>: <ty>) { async move { } } // <-- dropped as you "exit" the fn // ...becomes... fn foo(__arg0: <ty>) { async move { let <pattern> = __arg0; } // <-- dropped as you "exit" the async block } After this PR, async function arguments will be lowered as: async fn foo(<pattern>: <ty>, <pattern>: <ty>, <pattern>: <ty>) { async move { } } // <-- dropped as you "exit" the fn // ...becomes... fn foo(__arg0: <ty>, __arg1: <ty>, __arg2: <ty>) { async move { let __arg2 = __arg2; let <pattern> = __arg2; let __arg1 = __arg1; let <pattern> = __arg1; let __arg0 = __arg0; let <pattern> = __arg0; } // <-- dropped as you "exit" the async block } If `<pattern>` is a simple ident, then it is lowered to a single `let <pattern> = <pattern>;` statement as an optimization. This PR also stops users from referring to the generated `__argN` identifiers. r? @nikomatsakis
2 parents 12bf981 + 1fedb0a commit 16939a5

13 files changed

+505
-232
lines changed
 

‎src/librustc/hir/lowering.rs

+36-3
Original file line numberDiff line numberDiff line change
@@ -2996,8 +2996,33 @@ impl<'a> LoweringContext<'a> {
29962996
if let IsAsync::Async { closure_id, ref arguments, .. } = asyncness {
29972997
let mut body = body.clone();
29982998

2999+
// Async function arguments are lowered into the closure body so that they are
3000+
// captured and so that the drop order matches the equivalent non-async functions.
3001+
//
3002+
// async fn foo(<pattern>: <ty>, <pattern>: <ty>, <pattern>: <ty>) {
3003+
// async move {
3004+
// }
3005+
// }
3006+
//
3007+
// // ...becomes...
3008+
// fn foo(__arg0: <ty>, __arg1: <ty>, __arg2: <ty>) {
3009+
// async move {
3010+
// let __arg2 = __arg2;
3011+
// let <pattern> = __arg2;
3012+
// let __arg1 = __arg1;
3013+
// let <pattern> = __arg1;
3014+
// let __arg0 = __arg0;
3015+
// let <pattern> = __arg0;
3016+
// }
3017+
// }
3018+
//
3019+
// If `<pattern>` is a simple ident, then it is lowered to a single
3020+
// `let <pattern> = <pattern>;` statement as an optimization.
29993021
for a in arguments.iter().rev() {
3000-
body.stmts.insert(0, a.stmt.clone());
3022+
if let Some(pat_stmt) = a.pat_stmt.clone() {
3023+
body.stmts.insert(0, pat_stmt);
3024+
}
3025+
body.stmts.insert(0, a.move_stmt.clone());
30013026
}
30023027

30033028
let async_expr = this.make_async_expr(
@@ -3093,7 +3118,11 @@ impl<'a> LoweringContext<'a> {
30933118
let mut decl = decl.clone();
30943119
// Replace the arguments of this async function with the generated
30953120
// arguments that will be moved into the closure.
3096-
decl.inputs = arguments.clone().drain(..).map(|a| a.arg).collect();
3121+
for (i, a) in arguments.clone().drain(..).enumerate() {
3122+
if let Some(arg) = a.arg {
3123+
decl.inputs[i] = arg;
3124+
}
3125+
}
30973126
lower_fn(&decl)
30983127
} else {
30993128
lower_fn(decl)
@@ -3590,7 +3619,11 @@ impl<'a> LoweringContext<'a> {
35903619
let mut sig = sig.clone();
35913620
// Replace the arguments of this async function with the generated
35923621
// arguments that will be moved into the closure.
3593-
sig.decl.inputs = arguments.clone().drain(..).map(|a| a.arg).collect();
3622+
for (i, a) in arguments.clone().drain(..).enumerate() {
3623+
if let Some(arg) = a.arg {
3624+
sig.decl.inputs[i] = arg;
3625+
}
3626+
}
35943627
lower_method(&sig)
35953628
} else {
35963629
lower_method(sig)

‎src/librustc/hir/map/def_collector.rs

+9-4
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,9 @@ impl<'a> DefCollector<'a> {
9494
// Walk the generated arguments for the `async fn`.
9595
for a in arguments {
9696
use visit::Visitor;
97-
this.visit_ty(&a.arg.ty);
97+
if let Some(arg) = &a.arg {
98+
this.visit_ty(&arg.ty);
99+
}
98100
}
99101

100102
// We do not invoke `walk_fn_decl` as this will walk the arguments that are being
@@ -105,10 +107,13 @@ impl<'a> DefCollector<'a> {
105107
*closure_id, DefPathData::ClosureExpr, REGULAR_SPACE, span,
106108
);
107109
this.with_parent(closure_def, |this| {
110+
use visit::Visitor;
111+
// Walk each of the generated statements before the regular block body.
108112
for a in arguments {
109-
use visit::Visitor;
110-
// Walk each of the generated statements before the regular block body.
111-
this.visit_stmt(&a.stmt);
113+
this.visit_stmt(&a.move_stmt);
114+
if let Some(pat_stmt) = &a.pat_stmt {
115+
this.visit_stmt(&pat_stmt);
116+
}
112117
}
113118

114119
visit::walk_block(this, &body);

‎src/librustc/lint/context.rs

+10-5
Original file line numberDiff line numberDiff line change
@@ -1334,14 +1334,19 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
13341334
if let ast::IsAsync::Async { ref arguments, .. } = header.asyncness.node {
13351335
for a in arguments {
13361336
// Visit the argument..
1337-
self.visit_pat(&a.arg.pat);
1338-
if let ast::ArgSource::AsyncFn(pat) = &a.arg.source {
1339-
self.visit_pat(pat);
1337+
if let Some(arg) = &a.arg {
1338+
self.visit_pat(&arg.pat);
1339+
if let ast::ArgSource::AsyncFn(pat) = &arg.source {
1340+
self.visit_pat(pat);
1341+
}
1342+
self.visit_ty(&arg.ty);
13401343
}
1341-
self.visit_ty(&a.arg.ty);
13421344

13431345
// ..and the statement.
1344-
self.visit_stmt(&a.stmt);
1346+
self.visit_stmt(&a.move_stmt);
1347+
if let Some(pat_stmt) = &a.pat_stmt {
1348+
self.visit_stmt(&pat_stmt);
1349+
}
13451350
}
13461351
}
13471352
}

‎src/librustc_resolve/lib.rs

+25-13
Original file line numberDiff line numberDiff line change
@@ -862,7 +862,13 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
862862
// Walk the generated async arguments if this is an `async fn`, otherwise walk the
863863
// normal arguments.
864864
if let IsAsync::Async { ref arguments, .. } = asyncness {
865-
for a in arguments { add_argument(&a.arg); }
865+
for (i, a) in arguments.iter().enumerate() {
866+
if let Some(arg) = &a.arg {
867+
add_argument(&arg);
868+
} else {
869+
add_argument(&declaration.inputs[i]);
870+
}
871+
}
866872
} else {
867873
for a in &declaration.inputs { add_argument(a); }
868874
}
@@ -882,8 +888,11 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
882888
let mut body = body.clone();
883889
// Insert the generated statements into the body before attempting to
884890
// resolve names.
885-
for a in arguments {
886-
body.stmts.insert(0, a.stmt.clone());
891+
for a in arguments.iter().rev() {
892+
if let Some(pat_stmt) = a.pat_stmt.clone() {
893+
body.stmts.insert(0, pat_stmt);
894+
}
895+
body.stmts.insert(0, a.move_stmt.clone());
887896
}
888897
self.visit_block(&body);
889898
} else {
@@ -4174,7 +4183,7 @@ impl<'a> Resolver<'a> {
41744183
let add_module_candidates = |module: Module<'_>, names: &mut Vec<TypoSuggestion>| {
41754184
for (&(ident, _), resolution) in module.resolutions.borrow().iter() {
41764185
if let Some(binding) = resolution.borrow().binding {
4177-
if filter_fn(binding.def()) {
4186+
if !ident.name.is_gensymed() && filter_fn(binding.def()) {
41784187
names.push(TypoSuggestion {
41794188
candidate: ident.name,
41804189
article: binding.def().article(),
@@ -4192,7 +4201,7 @@ impl<'a> Resolver<'a> {
41924201
for rib in self.ribs[ns].iter().rev() {
41934202
// Locals and type parameters
41944203
for (ident, def) in &rib.bindings {
4195-
if filter_fn(*def) {
4204+
if !ident.name.is_gensymed() && filter_fn(*def) {
41964205
names.push(TypoSuggestion {
41974206
candidate: ident.name,
41984207
article: def.article(),
@@ -4219,7 +4228,7 @@ impl<'a> Resolver<'a> {
42194228
index: CRATE_DEF_INDEX,
42204229
});
42214230

4222-
if filter_fn(crate_mod) {
4231+
if !ident.name.is_gensymed() && filter_fn(crate_mod) {
42234232
Some(TypoSuggestion {
42244233
candidate: ident.name,
42254234
article: "a",
@@ -4242,13 +4251,16 @@ impl<'a> Resolver<'a> {
42424251
// Add primitive types to the mix
42434252
if filter_fn(Def::PrimTy(Bool)) {
42444253
names.extend(
4245-
self.primitive_type_table.primitive_types.iter().map(|(name, _)| {
4246-
TypoSuggestion {
4247-
candidate: *name,
4248-
article: "a",
4249-
kind: "primitive type",
4250-
}
4251-
})
4254+
self.primitive_type_table.primitive_types
4255+
.iter()
4256+
.filter(|(name, _)| !name.is_gensymed())
4257+
.map(|(name, _)| {
4258+
TypoSuggestion {
4259+
candidate: *name,
4260+
article: "a",
4261+
kind: "primitive type",
4262+
}
4263+
})
42524264
)
42534265
}
42544266
} else {

‎src/libsyntax/ast.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -1865,10 +1865,14 @@ pub enum Unsafety {
18651865
pub struct AsyncArgument {
18661866
/// `__arg0`
18671867
pub ident: Ident,
1868-
/// `__arg0: <ty>` argument to replace existing function argument `<pat>: <ty>`.
1869-
pub arg: Arg,
1870-
/// `let <pat>: <ty> = __arg0;` statement to be inserted at the start of the block.
1871-
pub stmt: Stmt,
1868+
/// `__arg0: <ty>` argument to replace existing function argument `<pat>: <ty>`. Only if
1869+
/// argument is not a simple binding.
1870+
pub arg: Option<Arg>,
1871+
/// `let __arg0 = __arg0;` statement to be inserted at the start of the block.
1872+
pub move_stmt: Stmt,
1873+
/// `let <pat> = __arg0;` statement to be inserted at the start of the block, after matching
1874+
/// move statement. Only if argument is not a simple binding.
1875+
pub pat_stmt: Option<Stmt>,
18721876
}
18731877

18741878
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]

‎src/libsyntax/ext/placeholders.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,10 @@ impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> {
199199

200200
if let ast::IsAsync::Async { ref mut arguments, .. } = a {
201201
for argument in arguments.iter_mut() {
202-
self.next_id(&mut argument.stmt.id);
202+
self.next_id(&mut argument.move_stmt.id);
203+
if let Some(ref mut pat_stmt) = &mut argument.pat_stmt {
204+
self.next_id(&mut pat_stmt.id);
205+
}
203206
}
204207
}
205208
}

‎src/libsyntax/mut_visit.rs

+11-3
Original file line numberDiff line numberDiff line change
@@ -694,13 +694,21 @@ pub fn noop_visit_asyncness<T: MutVisitor>(asyncness: &mut IsAsync, vis: &mut T)
694694
IsAsync::Async { closure_id, return_impl_trait_id, ref mut arguments } => {
695695
vis.visit_id(closure_id);
696696
vis.visit_id(return_impl_trait_id);
697-
for AsyncArgument { ident, arg, stmt } in arguments.iter_mut() {
697+
for AsyncArgument { ident, arg, pat_stmt, move_stmt } in arguments.iter_mut() {
698698
vis.visit_ident(ident);
699-
vis.visit_arg(arg);
700-
visit_clobber(stmt, |stmt| {
699+
if let Some(arg) = arg {
700+
vis.visit_arg(arg);
701+
}
702+
visit_clobber(move_stmt, |stmt| {
701703
vis.flat_map_stmt(stmt)
702704
.expect_one("expected visitor to produce exactly one item")
703705
});
706+
visit_opt(pat_stmt, |stmt| {
707+
visit_clobber(stmt, |stmt| {
708+
vis.flat_map_stmt(stmt)
709+
.expect_one("expected visitor to produce exactly one item")
710+
})
711+
});
704712
}
705713
}
706714
IsAsync::NotAsync => {}

‎src/libsyntax/parse/parser.rs

+49-15
Original file line numberDiff line numberDiff line change
@@ -8720,27 +8720,46 @@ impl<'a> Parser<'a> {
87208720

87218721
// Construct a name for our temporary argument.
87228722
let name = format!("__arg{}", index);
8723-
let ident = Ident::from_str(&name);
8723+
let ident = Ident::from_str(&name).gensym();
8724+
8725+
// Check if this is a ident pattern, if so, we can optimize and avoid adding a
8726+
// `let <pat> = __argN;` statement, instead just adding a `let <pat> = <pat>;`
8727+
// statement.
8728+
let (ident, is_simple_pattern) = match input.pat.node {
8729+
PatKind::Ident(_, ident, _) => (ident, true),
8730+
_ => (ident, false),
8731+
};
87248732

87258733
// Construct an argument representing `__argN: <ty>` to replace the argument of the
8726-
// async function.
8727-
let arg = Arg {
8728-
ty: input.ty.clone(),
8729-
id,
8734+
// async function if it isn't a simple pattern.
8735+
let arg = if is_simple_pattern {
8736+
None
8737+
} else {
8738+
Some(Arg {
8739+
ty: input.ty.clone(),
8740+
id,
8741+
pat: P(Pat {
8742+
id,
8743+
node: PatKind::Ident(
8744+
BindingMode::ByValue(Mutability::Immutable), ident, None,
8745+
),
8746+
span,
8747+
}),
8748+
source: ArgSource::AsyncFn(input.pat.clone()),
8749+
})
8750+
};
8751+
8752+
// Construct a `let __argN = __argN;` statement to insert at the top of the
8753+
// async closure. This makes sure that the argument is captured by the closure and
8754+
// that the drop order is correct.
8755+
let move_local = Local {
87308756
pat: P(Pat {
87318757
id,
87328758
node: PatKind::Ident(
87338759
BindingMode::ByValue(Mutability::Immutable), ident, None,
87348760
),
87358761
span,
87368762
}),
8737-
source: ArgSource::AsyncFn(input.pat.clone()),
8738-
};
8739-
8740-
// Construct a `let <pat> = __argN;` statement to insert at the top of the
8741-
// async closure.
8742-
let local = P(Local {
8743-
pat: input.pat.clone(),
87448763
// We explicitly do not specify the type for this statement. When the user's
87458764
// argument type is `impl Trait` then this would require the
87468765
// `impl_trait_in_bindings` feature to also be present for that same type to
@@ -8760,10 +8779,25 @@ impl<'a> Parser<'a> {
87608779
span,
87618780
attrs: ThinVec::new(),
87628781
source: LocalSource::AsyncFn,
8763-
});
8764-
let stmt = Stmt { id, node: StmtKind::Local(local), span, };
8782+
};
8783+
8784+
// Construct a `let <pat> = __argN;` statement to insert at the top of the
8785+
// async closure if this isn't a simple pattern.
8786+
let pat_stmt = if is_simple_pattern {
8787+
None
8788+
} else {
8789+
Some(Stmt {
8790+
id,
8791+
node: StmtKind::Local(P(Local {
8792+
pat: input.pat.clone(),
8793+
..move_local.clone()
8794+
})),
8795+
span,
8796+
})
8797+
};
87658798

8766-
arguments.push(AsyncArgument { ident, arg, stmt });
8799+
let move_stmt = Stmt { id, node: StmtKind::Local(P(move_local)), span };
8800+
arguments.push(AsyncArgument { ident, arg, pat_stmt, move_stmt });
87678801
}
87688802
}
87698803
}

‎src/test/run-pass/issue-54716.rs

-184
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// edition:2018
2+
3+
use std::sync::Arc;
4+
use std::task::{
5+
Waker, RawWaker, RawWakerVTable,
6+
};
7+
8+
macro_rules! waker_vtable {
9+
($ty:ident) => {
10+
&RawWakerVTable::new(
11+
clone_arc_raw::<$ty>,
12+
wake_arc_raw::<$ty>,
13+
wake_by_ref_arc_raw::<$ty>,
14+
drop_arc_raw::<$ty>,
15+
)
16+
};
17+
}
18+
19+
pub trait ArcWake {
20+
fn wake(self: Arc<Self>);
21+
22+
fn wake_by_ref(arc_self: &Arc<Self>) {
23+
arc_self.clone().wake()
24+
}
25+
26+
fn into_waker(wake: Arc<Self>) -> Waker where Self: Sized
27+
{
28+
let ptr = Arc::into_raw(wake) as *const ();
29+
30+
unsafe {
31+
Waker::from_raw(RawWaker::new(ptr, waker_vtable!(Self)))
32+
}
33+
}
34+
}
35+
36+
unsafe fn increase_refcount<T: ArcWake>(data: *const ()) {
37+
// Retain Arc by creating a copy
38+
let arc: Arc<T> = Arc::from_raw(data as *const T);
39+
let arc_clone = arc.clone();
40+
// Forget the Arcs again, so that the refcount isn't decrased
41+
let _ = Arc::into_raw(arc);
42+
let _ = Arc::into_raw(arc_clone);
43+
}
44+
45+
unsafe fn clone_arc_raw<T: ArcWake>(data: *const ()) -> RawWaker {
46+
increase_refcount::<T>(data);
47+
RawWaker::new(data, waker_vtable!(T))
48+
}
49+
50+
unsafe fn drop_arc_raw<T: ArcWake>(data: *const ()) {
51+
// Drop Arc
52+
let _: Arc<T> = Arc::from_raw(data as *const T);
53+
}
54+
55+
unsafe fn wake_arc_raw<T: ArcWake>(data: *const ()) {
56+
let arc: Arc<T> = Arc::from_raw(data as *const T);
57+
ArcWake::wake(arc);
58+
}
59+
60+
unsafe fn wake_by_ref_arc_raw<T: ArcWake>(data: *const ()) {
61+
let arc: Arc<T> = Arc::from_raw(data as *const T);
62+
ArcWake::wake_by_ref(&arc);
63+
let _ = Arc::into_raw(arc);
64+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
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(x: D, _y: D) {
46+
x.1.borrow_mut().push(DropOrder::Function);
47+
}
48+
49+
fn foo_sync(x: D, _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(x: D, _: D) {
55+
x.1.borrow_mut().push(DropOrder::Function);
56+
}
57+
58+
fn bar_sync(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((x, _): (D, D)) {
65+
x.1.borrow_mut().push(DropOrder::Function);
66+
}
67+
68+
fn baz_sync((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(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
75+
x.1.borrow_mut().push(DropOrder::Function);
76+
}
77+
78+
fn foobar_sync(x: D, (a, _, _c): (D, D, D), _: D, _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(x: D, _y: D) {
87+
x.1.borrow_mut().push(DropOrder::Function);
88+
}
89+
90+
fn foo_sync(x: D, _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(x: D, _: D) {
96+
x.1.borrow_mut().push(DropOrder::Function);
97+
}
98+
99+
fn bar_sync(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((x, _): (D, D)) {
106+
x.1.borrow_mut().push(DropOrder::Function);
107+
}
108+
109+
fn baz_sync((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(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
116+
x.1.borrow_mut().push(DropOrder::Function);
117+
}
118+
119+
fn foobar_sync(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
120+
x.1.borrow_mut().push(DropOrder::Function);
121+
}
122+
}
123+
124+
struct Bar<'a>(PhantomData<&'a ()>);
125+
126+
impl<'a> Bar<'a> {
127+
/// Check that unused bindings are dropped after the method with self is polled.
128+
async fn foo_async(&'a self, x: D, _y: D) {
129+
x.1.borrow_mut().push(DropOrder::Function);
130+
}
131+
132+
fn foo_sync(&'a self, x: D, _y: D) {
133+
x.1.borrow_mut().push(DropOrder::Function);
134+
}
135+
136+
/// Check that underscore patterns are dropped after the method with self is polled.
137+
async fn bar_async(&'a self, x: D, _: D) {
138+
x.1.borrow_mut().push(DropOrder::Function);
139+
}
140+
141+
fn bar_sync(&'a self, x: D, _: D) {
142+
x.1.borrow_mut().push(DropOrder::Function);
143+
}
144+
145+
/// Check that underscore patterns within more complex patterns are dropped after the method
146+
/// with self is polled.
147+
async fn baz_async(&'a self, (x, _): (D, D)) {
148+
x.1.borrow_mut().push(DropOrder::Function);
149+
}
150+
151+
fn baz_sync(&'a self, (x, _): (D, D)) {
152+
x.1.borrow_mut().push(DropOrder::Function);
153+
}
154+
155+
/// Check that underscore and unused bindings within and outwith more complex patterns are
156+
/// dropped after the method with self is polled.
157+
async fn foobar_async(&'a self, x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
158+
x.1.borrow_mut().push(DropOrder::Function);
159+
}
160+
161+
fn foobar_sync(&'a self, x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
162+
x.1.borrow_mut().push(DropOrder::Function);
163+
}
164+
}
165+
166+
fn assert_drop_order_after_poll<Fut: Future<Output = ()>>(
167+
f: impl FnOnce(DropOrderListPtr) -> Fut,
168+
g: impl FnOnce(DropOrderListPtr),
169+
) {
170+
let empty = Arc::new(EmptyWaker);
171+
let waker = ArcWake::into_waker(empty);
172+
let mut cx = Context::from_waker(&waker);
173+
174+
let actual_order = Rc::new(RefCell::new(Vec::new()));
175+
let mut fut = Box::pin(f(actual_order.clone()));
176+
let _ = fut.as_mut().poll(&mut cx);
177+
178+
let expected_order = Rc::new(RefCell::new(Vec::new()));
179+
g(expected_order.clone());
180+
181+
assert_eq!(*actual_order.borrow(), *expected_order.borrow());
182+
}
183+
184+
fn main() {
185+
// Free functions (see doc comment on function for what it tests).
186+
assert_drop_order_after_poll(|l| foo_async(D("x", l.clone()), D("_y", l.clone())),
187+
|l| foo_sync(D("x", l.clone()), D("_y", l.clone())));
188+
assert_drop_order_after_poll(|l| bar_async(D("x", l.clone()), D("_", l.clone())),
189+
|l| bar_sync(D("x", l.clone()), D("_", l.clone())));
190+
assert_drop_order_after_poll(|l| baz_async((D("x", l.clone()), D("_", l.clone()))),
191+
|l| baz_sync((D("x", l.clone()), D("_", l.clone()))));
192+
assert_drop_order_after_poll(
193+
|l| {
194+
foobar_async(
195+
D("x", l.clone()),
196+
(D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
197+
D("_", l.clone()),
198+
D("_y", l.clone()),
199+
)
200+
},
201+
|l| {
202+
foobar_sync(
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+
);
210+
211+
// Methods w/out self (see doc comment on function for what it tests).
212+
assert_drop_order_after_poll(|l| Foo::foo_async(D("x", l.clone()), D("_y", l.clone())),
213+
|l| Foo::foo_sync(D("x", l.clone()), D("_y", l.clone())));
214+
assert_drop_order_after_poll(|l| Foo::bar_async(D("x", l.clone()), D("_", l.clone())),
215+
|l| Foo::bar_sync(D("x", l.clone()), D("_", l.clone())));
216+
assert_drop_order_after_poll(|l| Foo::baz_async((D("x", l.clone()), D("_", l.clone()))),
217+
|l| Foo::baz_sync((D("x", l.clone()), D("_", l.clone()))));
218+
assert_drop_order_after_poll(
219+
|l| {
220+
Foo::foobar_async(
221+
D("x", l.clone()),
222+
(D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
223+
D("_", l.clone()),
224+
D("_y", l.clone()),
225+
)
226+
},
227+
|l| {
228+
Foo::foobar_sync(
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+
);
236+
237+
// Methods (see doc comment on function for what it tests).
238+
let b = Bar(Default::default());
239+
assert_drop_order_after_poll(|l| b.foo_async(D("x", l.clone()), D("_y", l.clone())),
240+
|l| b.foo_sync(D("x", l.clone()), D("_y", l.clone())));
241+
assert_drop_order_after_poll(|l| b.bar_async(D("x", l.clone()), D("_", l.clone())),
242+
|l| b.bar_sync(D("x", l.clone()), D("_", l.clone())));
243+
assert_drop_order_after_poll(|l| b.baz_async((D("x", l.clone()), D("_", l.clone()))),
244+
|l| b.baz_sync((D("x", l.clone()), D("_", l.clone()))));
245+
assert_drop_order_after_poll(
246+
|l| {
247+
b.foobar_async(
248+
D("x", l.clone()),
249+
(D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
250+
D("_", l.clone()),
251+
D("_y", l.clone()),
252+
)
253+
},
254+
|l| {
255+
b.foobar_sync(
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+
);
263+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// edition:2018
2+
3+
#![allow(unused_variables)]
4+
#![feature(async_await)]
5+
6+
async fn foobar_async(x: u32, (a, _, _c): (u32, u32, u32), _: u32, _y: u32) {
7+
assert_eq!(__arg1, (1, 2, 3)); //~ ERROR cannot find value `__arg1` in this scope [E0425]
8+
assert_eq!(__arg2, 4); //~ ERROR cannot find value `__arg2` in this scope [E0425]
9+
}
10+
11+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0425]: cannot find value `__arg1` in this scope
2+
--> $DIR/drop-order-locals-are-hidden.rs:7:16
3+
|
4+
LL | assert_eq!(__arg1, (1, 2, 3));
5+
| ^^^^^^ not found in this scope
6+
7+
error[E0425]: cannot find value `__arg2` in this scope
8+
--> $DIR/drop-order-locals-are-hidden.rs:8:16
9+
|
10+
LL | assert_eq!(__arg2, 4);
11+
| ^^^^^^ not found in this scope
12+
13+
error: aborting due to 2 previous errors
14+
15+
For more information about this error, try `rustc --explain E0425`.

0 commit comments

Comments
 (0)
Please sign in to comment.