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 }`.
This commit is contained in:
parent
9ae1a664f7
commit
00d159095a
3 changed files with 41 additions and 13 deletions
|
@ -2682,12 +2682,8 @@ impl<'a> LoweringContext<'a> {
|
||||||
bounds.iter().map(|bound| self.lower_param_bound(bound, itctx.reborrow())).collect()
|
bounds.iter().map(|bound| self.lower_param_bound(bound, itctx.reborrow())).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_block_with_stmts(
|
fn lower_block(&mut self, b: &Block, targeted_by_break: bool) -> P<hir::Block> {
|
||||||
&mut self,
|
let mut stmts = vec![];
|
||||||
b: &Block,
|
|
||||||
targeted_by_break: bool,
|
|
||||||
mut stmts: Vec<hir::Stmt>,
|
|
||||||
) -> P<hir::Block> {
|
|
||||||
let mut expr = None;
|
let mut expr = None;
|
||||||
|
|
||||||
for (index, stmt) in b.stmts.iter().enumerate() {
|
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> {
|
fn lower_pat(&mut self, p: &Pat) -> P<hir::Pat> {
|
||||||
let node = match p.node {
|
let node = match p.node {
|
||||||
PatKind::Wild => hir::PatKind::Wild,
|
PatKind::Wild => hir::PatKind::Wild,
|
||||||
|
|
|
@ -1310,7 +1310,7 @@ impl LoweringContext<'_> {
|
||||||
/// `{ let _t = $expr; _t }` but should provide better compile-time performance.
|
/// `{ let _t = $expr; _t }` but should provide better compile-time performance.
|
||||||
///
|
///
|
||||||
/// The drop order can be important in e.g. `if expr { .. }`.
|
/// The drop order can be important in e.g. `if expr { .. }`.
|
||||||
fn expr_drop_temps(
|
pub(super) fn expr_drop_temps(
|
||||||
&mut self,
|
&mut self,
|
||||||
span: Span,
|
span: Span,
|
||||||
expr: P<hir::Expr>,
|
expr: P<hir::Expr>,
|
||||||
|
|
|
@ -1219,8 +1219,44 @@ impl LoweringContext<'_> {
|
||||||
let async_expr = this.make_async_expr(
|
let async_expr = this.make_async_expr(
|
||||||
CaptureBy::Value, closure_id, None, body.span,
|
CaptureBy::Value, closure_id, None, body.span,
|
||||||
|this| {
|
|this| {
|
||||||
let body = this.lower_block_with_stmts(body, false, statements);
|
// Create a block from the user's function body:
|
||||||
this.expr_block(body, ThinVec::new())
|
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()))
|
(HirVec::from(parameters), this.expr(body.span, async_expr, ThinVec::new()))
|
||||||
})
|
})
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue