diff options
| author | Niko Matsakis <niko@alum.mit.edu> | 2019-09-16 16:15:20 -0400 |
|---|---|---|
| committer | Niko Matsakis <niko@alum.mit.edu> | 2019-09-16 16:44:18 -0400 |
| commit | 00d159095adbb14c7dfaa6a77177be1b58600dc9 (patch) | |
| tree | 507c54763853fb5d9cc57c1c1bcbe50522b59ccc | |
| parent | 9ae1a664f7b947dadb9e97eea7703831d9cd5d31 (diff) | |
adjust desugaring for async fn to correct drop order
Old desugaring, given a user function body { $stmts; $expr }
```
{
let $param_pattern0 = $raw_param0;
...
let $param_patternN = $raw_paramN;
$stmts;
$expr
}
```
New desugaring:
```
{
let $param_pattern0 = $raw_param0;
...
let $param_patternN = $raw_paramN;
drop-temps {
$stmts;
$expr
}
}
```
The drop-temps is an internal bit of HIR that drops temporaries from
the resulting expression, but it should be equivalent to `return {
$stmts; $expr }`.
| -rw-r--r-- | src/librustc/hir/lowering.rs | 12 | ||||
| -rw-r--r-- | src/librustc/hir/lowering/expr.rs | 2 | ||||
| -rw-r--r-- | src/librustc/hir/lowering/item.rs | 40 |
3 files changed, 41 insertions, 13 deletions
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 58789a10609..492029eed05 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -2682,12 +2682,8 @@ impl<'a> LoweringContext<'a> { bounds.iter().map(|bound| self.lower_param_bound(bound, itctx.reborrow())).collect() } - fn lower_block_with_stmts( - &mut self, - b: &Block, - targeted_by_break: bool, - mut stmts: Vec<hir::Stmt>, - ) -> P<hir::Block> { + fn lower_block(&mut self, b: &Block, targeted_by_break: bool) -> P<hir::Block> { + let mut stmts = vec![]; let mut expr = None; for (index, stmt) in b.stmts.iter().enumerate() { @@ -2712,10 +2708,6 @@ impl<'a> LoweringContext<'a> { }) } - fn lower_block(&mut self, b: &Block, targeted_by_break: bool) -> P<hir::Block> { - self.lower_block_with_stmts(b, targeted_by_break, vec![]) - } - fn lower_pat(&mut self, p: &Pat) -> P<hir::Pat> { let node = match p.node { PatKind::Wild => hir::PatKind::Wild, diff --git a/src/librustc/hir/lowering/expr.rs b/src/librustc/hir/lowering/expr.rs index a46cdabbb51..87462e94f43 100644 --- a/src/librustc/hir/lowering/expr.rs +++ b/src/librustc/hir/lowering/expr.rs @@ -1310,7 +1310,7 @@ impl LoweringContext<'_> { /// `{ let _t = $expr; _t }` but should provide better compile-time performance. /// /// The drop order can be important in e.g. `if expr { .. }`. - fn expr_drop_temps( + pub(super) fn expr_drop_temps( &mut self, span: Span, expr: P<hir::Expr>, diff --git a/src/librustc/hir/lowering/item.rs b/src/librustc/hir/lowering/item.rs index 5f82e42abb3..1e621f7fdae 100644 --- a/src/librustc/hir/lowering/item.rs +++ b/src/librustc/hir/lowering/item.rs @@ -1219,8 +1219,44 @@ impl LoweringContext<'_> { let async_expr = this.make_async_expr( CaptureBy::Value, closure_id, None, body.span, |this| { - let body = this.lower_block_with_stmts(body, false, statements); - this.expr_block(body, ThinVec::new()) + // Create a block from the user's function body: + let user_body = this.lower_block(body, false); + let user_body = this.expr_block(user_body, ThinVec::new()); + + // Transform into `drop-temps { <user-body> }`, an expression: + let desugared_span = this.mark_span_with_reason( + DesugaringKind::Async, + user_body.span, + None, + ); + let user_body = this.expr_drop_temps( + desugared_span, + P(user_body), + ThinVec::new(), + ); + + // Create a block like + // + // ``` + // { + // let $param_pattern = $raw_param; + // ... + // drop-temps { <user-body> } + // } + // ``` + // + // This construction is carefully calibrated to + // get the drop-order correct. In particular, the + // drop-temps ensures that any temporaries in the + // tail expression of `<user-body>` are dropped + // *before* the parameters are dropped (see + // rust-lang/rust#64512). + let body = this.block_all( + desugared_span, + statements.into(), + Some(P(user_body)), + ); + this.expr_block(P(body), ThinVec::new()) }); (HirVec::from(parameters), this.expr(body.span, async_expr, ThinVec::new())) }) |
