Change:
See:
for future reference: is referencing my PR which changed the r-value temporary rules with respect to the temporaries in the of
Even beside the part the loop desugaring is so complex. It would be nice to document what every employed trick changes compared to the naive desugaring.
PR itself was motivated (or at least spawned off of) PR . I'm actually trying to find out what the actual motivation for the described change was. The change, as described, was that the temporaries within would previously live until the end of the enclosing block. So if you consider the following code (): which, when it is accepted by the compiler (as written it requires NLL), it should print this: notably, we drop all of {, , } immediately after the for-statement, but before the at the end of the block. The breakage I would be concerned about, if we made for-loops no longer a terminating scope for their , is that all of the temps would live until the end of the block, and thus the drops of {, , } would happen after the "end of enclosing block", which would be an observable change. has relayed to me in private conversation that they tried examples like this under variants of their desugaring and did not witness any change in behavior. Our best guess as to why this is, is because the desugaring is, in the end, turning into a which is itself a terminating scope for the temporaries in the -input, and so you don't need to recreate such an effect by other means.
Note: it is nonetheless possible that the distinction here is more subtle and my above example isn't quite right. in particular, I'm a little worried that there may have been a reason that the example from PR puts the for-expression in the tail expression of a block, and that examples that don't take similar care might fail to pick up on a relevant distinction here...

Discussion:
}) } <ins> fn lower_exprs(&mut self, exprs: &[AstP<Expr>]) -> HirVec<hir::Expr> { exprs.iter().map(|x| self.lower_expr(x)).collect() } </ins> fn lower_expr(&mut self, e: &Expr) -> hir::Expr { let kind = match e.node { ExprKind::Box(ref inner) => hir::ExprKind::Box(P(self.lower_expr(inner))), <del> ExprKind::Array(ref exprs) => { hir::ExprKind::Array(exprs.iter().map(|x| self.lower_expr(x)).collect()) } </del> <ins> ExprKind::Array(ref exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), </ins> ExprKind::Repeat(ref expr, ref count) => { let expr = P(self.lower_expr(expr)); let count = self.lower_anon_const(count); hir::ExprKind::Repeat(expr, count) } <del> ExprKind::Tup(ref elts) => { hir::ExprKind::Tup(elts.iter().map(|x| self.lower_expr(x)).collect()) } </del> <ins> ExprKind::Tup(ref elts) => hir::ExprKind::Tup(self.lower_exprs(elts)), </ins> ExprKind::Call(ref f, ref args) => { let f = P(self.lower_expr(f)); <del> hir::ExprKind::Call(f, args.iter().map(|x| self.lower_expr(x)).collect()) </del> <ins> hir::ExprKind::Call(f, self.lower_exprs(args)) </ins> } ExprKind::MethodCall(ref seg, ref args) => { let hir_seg = P(self.lower_path_segment(

ImplTraitContext::disallowed(), None, )); <del> let args = args.iter().map(|x| self.lower_expr(x)).collect(); </del> <ins> let args = self.lower_exprs(args); </ins> hir::ExprKind::MethodCall(hir_seg, seg.ident.span, args) } ExprKind::Binary(binop, ref lhs, ref rhs) => {

)); let arms = hir_vec![pat_arm, break_arm]; <del> P(self.expr( head_sp, hir::ExprKind::Match( next_expr, arms, hir::MatchSource::ForLoopDesugar ), ThinVec::new(), )) </del> <ins> self.expr_match(head_sp, next_expr, arms, hir::MatchSource::ForLoopDesugar) </ins> }; <del> let match_stmt = self.stmt(head_sp, hir::StmtKind::Expr(match_expr)); </del> <ins> let match_stmt = self.stmt_expr(head_sp, match_expr); </ins> let next_expr = P(self.expr_ident(head_sp, next_ident, next_pat_hid));

); let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false)); <del> let body_expr = P(self.expr_block(body_block, ThinVec::new())); let body_stmt = self.stmt(body.span, hir::StmtKind::Expr(body_expr)); </del> <ins> let body_expr = self.expr_block(body_block, ThinVec::new()); let body_stmt = self.stmt_expr(body.span, body_expr); </ins> let loop_block = P(self.block_all( e.span,

)); // This is effectively `{ let _result = ...; _result }`. <del> // The construct was introduced in #21984. // FIXME(60253): Is this still necessary? </del> <ins> // The construct was introduced in #21984 and is necessary to make sure that // temporaries in the `head` expression are dropped and do not leak to the // surrounding scope of the `match` since the `match` is not a terminating scope. // </ins> // Also, add the attributes to the outer returned expr node. return self.expr_drop_temps(head_sp, match_expr, e.attrs.clone()) }

} fn lower_stmt(&mut self, s: &Stmt) -> SmallVec<[hir::Stmt; 1]> { <del> smallvec![match s.node { </del> <ins> let node = match s.node { </ins> StmtKind::Local(ref l) => { let (l, item_ids) = self.lower_local(l); let mut ids: SmallVec<[hir::Stmt; 1]> = item_ids

}) .collect(); } <del> StmtKind::Expr(ref e) => { hir::Stmt { hir_id: self.lower_node_id(s.id), node: hir::StmtKind::Expr(P(self.lower_expr(e))), span: s.span, } }, StmtKind::Semi(ref e) => { hir::Stmt { hir_id: self.lower_node_id(s.id), node: hir::StmtKind::Semi(P(self.lower_expr(e))), span: s.span, } }, </del> <ins> StmtKind::Expr(ref e) => hir::StmtKind::Expr(P(self.lower_expr(e))), StmtKind::Semi(ref e) => hir::StmtKind::Semi(P(self.lower_expr(e))), </ins> StmtKind::Mac(..) => panic!("Shouldn't exist here"), <ins> }; smallvec![hir::Stmt { hir_id: self.lower_node_id(s.id), node, span: s.span, </ins> }] }

hir::Stmt { span, node, hir_id: self.next_id() } } <ins> fn stmt_expr(&mut self, span: Span, expr: hir::Expr) -> hir::Stmt { self.stmt(span, hir::StmtKind::Expr(P(expr))) } </ins> fn stmt_let_pat( &mut self, attrs: ThinVec<Attribute>,

}; let match_stmt = { <del> let match_expr = P(self.expr_match( </del> <ins> let match_expr = self.expr_match( </ins> span, poll_expr, hir_vec![ready_arm, pending_arm], hir::MatchSource::AwaitDesugar, <del> )); self.stmt(span, hir::StmtKind::Expr(match_expr)) </del> <ins> ); self.stmt_expr(span, match_expr) </ins> }; let yield_stmt = { let unit = self.expr_unit(span); <del> let yield_expr = P(self.expr( </del> <ins> let yield_expr = self.expr( </ins> span, hir::ExprKind::Yield(P(unit), hir::YieldSource::Await), ThinVec::new(), <del> )); self.stmt(span, hir::StmtKind::Expr(yield_expr)) </del> <ins> ); self.stmt_expr(span, yield_expr) </ins> }; let loop_block = P(self.block_all(