@@ -1082,194 +1082,217 @@ impl<'hir> LoweringContext<'_, 'hir> {
10821082 let ( Some ( coroutine_kind) , Some ( body) ) = ( coroutine_kind, body) else {
10831083 return self . lower_fn_body_block ( span, decl, body) ;
10841084 } ;
1085- let closure_id = coroutine_kind. closure_id ( ) ;
1086-
10871085 self . lower_body ( |this| {
1088- let mut parameters: Vec < hir:: Param < ' _ > > = Vec :: new ( ) ;
1089- let mut statements: Vec < hir:: Stmt < ' _ > > = Vec :: new ( ) ;
1090-
1091- // Async function parameters are lowered into the closure body so that they are
1092- // captured and so that the drop order matches the equivalent non-async functions.
1093- //
1094- // from:
1095- //
1096- // async fn foo(<pattern>: <ty>, <pattern>: <ty>, <pattern>: <ty>) {
1097- // <body>
1098- // }
1099- //
1100- // into:
1101- //
1102- // fn foo(__arg0: <ty>, __arg1: <ty>, __arg2: <ty>) {
1103- // async move {
1104- // let __arg2 = __arg2;
1105- // let <pattern> = __arg2;
1106- // let __arg1 = __arg1;
1107- // let <pattern> = __arg1;
1108- // let __arg0 = __arg0;
1109- // let <pattern> = __arg0;
1110- // drop-temps { <body> } // see comments later in fn for details
1111- // }
1112- // }
1113- //
1114- // If `<pattern>` is a simple ident, then it is lowered to a single
1115- // `let <pattern> = <pattern>;` statement as an optimization.
1116- //
1117- // Note that the body is embedded in `drop-temps`; an
1118- // equivalent desugaring would be `return { <body>
1119- // };`. The key point is that we wish to drop all the
1120- // let-bound variables and temporaries created in the body
1121- // (and its tail expression!) before we drop the
1122- // parameters (c.f. rust-lang/rust#64512).
1123- for ( index, parameter) in decl. inputs . iter ( ) . enumerate ( ) {
1124- let parameter = this. lower_param ( parameter) ;
1125- let span = parameter. pat . span ;
1126-
1127- // Check if this is a binding pattern, if so, we can optimize and avoid adding a
1128- // `let <pat> = __argN;` statement. In this case, we do not rename the parameter.
1129- let ( ident, is_simple_parameter) = match parameter. pat . kind {
1130- hir:: PatKind :: Binding ( hir:: BindingAnnotation ( ByRef :: No , _) , _, ident, _) => {
1131- ( ident, true )
1132- }
1133- // For `ref mut` or wildcard arguments, we can't reuse the binding, but
1134- // we can keep the same name for the parameter.
1135- // This lets rustdoc render it correctly in documentation.
1136- hir:: PatKind :: Binding ( _, _, ident, _) => ( ident, false ) ,
1137- hir:: PatKind :: Wild => {
1138- ( Ident :: with_dummy_span ( rustc_span:: symbol:: kw:: Underscore ) , false )
1139- }
1140- _ => {
1141- // Replace the ident for bindings that aren't simple.
1142- let name = format ! ( "__arg{index}" ) ;
1143- let ident = Ident :: from_str ( & name) ;
1144-
1145- ( ident, false )
1146- }
1147- } ;
1148-
1149- let desugared_span = this. mark_span_with_reason ( DesugaringKind :: Async , span, None ) ;
1150-
1151- // Construct a parameter representing `__argN: <ty>` to replace the parameter of the
1152- // async function.
1153- //
1154- // If this is the simple case, this parameter will end up being the same as the
1155- // original parameter, but with a different pattern id.
1156- let stmt_attrs = this. attrs . get ( & parameter. hir_id . local_id ) . copied ( ) ;
1157- let ( new_parameter_pat, new_parameter_id) = this. pat_ident ( desugared_span, ident) ;
1158- let new_parameter = hir:: Param {
1159- hir_id : parameter. hir_id ,
1160- pat : new_parameter_pat,
1161- ty_span : this. lower_span ( parameter. ty_span ) ,
1162- span : this. lower_span ( parameter. span ) ,
1163- } ;
1086+ let ( parameters, expr) = this. lower_coroutine_body_with_moved_arguments (
1087+ decl,
1088+ body,
1089+ coroutine_kind,
1090+ CaptureBy :: Value { move_kw : rustc_span:: DUMMY_SP } ,
1091+ ) ;
11641092
1165- if is_simple_parameter {
1166- // If this is the simple case, then we only insert one statement that is
1167- // `let <pat> = <pat>;`. We re-use the original argument's pattern so that
1168- // `HirId`s are densely assigned.
1169- let expr = this. expr_ident ( desugared_span, ident, new_parameter_id) ;
1170- let stmt = this. stmt_let_pat (
1171- stmt_attrs,
1172- desugared_span,
1173- Some ( expr) ,
1174- parameter. pat ,
1175- hir:: LocalSource :: AsyncFn ,
1176- ) ;
1177- statements. push ( stmt) ;
1178- } else {
1179- // If this is not the simple case, then we construct two statements:
1180- //
1181- // ```
1182- // let __argN = __argN;
1183- // let <pat> = __argN;
1184- // ```
1185- //
1186- // The first statement moves the parameter into the closure and thus ensures
1187- // that the drop order is correct.
1188- //
1189- // The second statement creates the bindings that the user wrote.
1190-
1191- // Construct the `let mut __argN = __argN;` statement. It must be a mut binding
1192- // because the user may have specified a `ref mut` binding in the next
1193- // statement.
1194- let ( move_pat, move_id) = this. pat_ident_binding_mode (
1195- desugared_span,
1196- ident,
1197- hir:: BindingAnnotation :: MUT ,
1198- ) ;
1199- let move_expr = this. expr_ident ( desugared_span, ident, new_parameter_id) ;
1200- let move_stmt = this. stmt_let_pat (
1201- None ,
1202- desugared_span,
1203- Some ( move_expr) ,
1204- move_pat,
1205- hir:: LocalSource :: AsyncFn ,
1206- ) ;
1093+ // FIXME(async_fn_track_caller): Can this be moved above?
1094+ let hir_id = this. lower_node_id ( coroutine_kind. closure_id ( ) ) ;
1095+ this. maybe_forward_track_caller ( body. span , fn_id, hir_id) ;
12071096
1208- // Construct the `let <pat> = __argN;` statement. We re-use the original
1209- // parameter's pattern so that `HirId`s are densely assigned.
1210- let pattern_expr = this. expr_ident ( desugared_span, ident, move_id) ;
1211- let pattern_stmt = this. stmt_let_pat (
1212- stmt_attrs,
1213- desugared_span,
1214- Some ( pattern_expr) ,
1215- parameter. pat ,
1216- hir:: LocalSource :: AsyncFn ,
1217- ) ;
1097+ ( parameters, expr)
1098+ } )
1099+ }
12181100
1219- statements. push ( move_stmt) ;
1220- statements. push ( pattern_stmt) ;
1221- } ;
1101+ /// Lowers a desugared coroutine body after moving all of the arguments
1102+ /// into the body. This is to make sure that the future actually owns the
1103+ /// arguments that are passed to the function, and to ensure things like
1104+ /// drop order are stable.
1105+ fn lower_coroutine_body_with_moved_arguments (
1106+ & mut self ,
1107+ decl : & FnDecl ,
1108+ body : & Block ,
1109+ coroutine_kind : CoroutineKind ,
1110+ capture_clause : CaptureBy ,
1111+ ) -> ( & ' hir [ hir:: Param < ' hir > ] , hir:: Expr < ' hir > ) {
1112+ let mut parameters: Vec < hir:: Param < ' _ > > = Vec :: new ( ) ;
1113+ let mut statements: Vec < hir:: Stmt < ' _ > > = Vec :: new ( ) ;
1114+
1115+ // Async function parameters are lowered into the closure body so that they are
1116+ // captured and so that the drop order matches the equivalent non-async functions.
1117+ //
1118+ // from:
1119+ //
1120+ // async fn foo(<pattern>: <ty>, <pattern>: <ty>, <pattern>: <ty>) {
1121+ // <body>
1122+ // }
1123+ //
1124+ // into:
1125+ //
1126+ // fn foo(__arg0: <ty>, __arg1: <ty>, __arg2: <ty>) {
1127+ // async move {
1128+ // let __arg2 = __arg2;
1129+ // let <pattern> = __arg2;
1130+ // let __arg1 = __arg1;
1131+ // let <pattern> = __arg1;
1132+ // let __arg0 = __arg0;
1133+ // let <pattern> = __arg0;
1134+ // drop-temps { <body> } // see comments later in fn for details
1135+ // }
1136+ // }
1137+ //
1138+ // If `<pattern>` is a simple ident, then it is lowered to a single
1139+ // `let <pattern> = <pattern>;` statement as an optimization.
1140+ //
1141+ // Note that the body is embedded in `drop-temps`; an
1142+ // equivalent desugaring would be `return { <body>
1143+ // };`. The key point is that we wish to drop all the
1144+ // let-bound variables and temporaries created in the body
1145+ // (and its tail expression!) before we drop the
1146+ // parameters (c.f. rust-lang/rust#64512).
1147+ for ( index, parameter) in decl. inputs . iter ( ) . enumerate ( ) {
1148+ let parameter = self . lower_param ( parameter) ;
1149+ let span = parameter. pat . span ;
1150+
1151+ // Check if this is a binding pattern, if so, we can optimize and avoid adding a
1152+ // `let <pat> = __argN;` statement. In this case, we do not rename the parameter.
1153+ let ( ident, is_simple_parameter) = match parameter. pat . kind {
1154+ hir:: PatKind :: Binding ( hir:: BindingAnnotation ( ByRef :: No , _) , _, ident, _) => {
1155+ ( ident, true )
1156+ }
1157+ // For `ref mut` or wildcard arguments, we can't reuse the binding, but
1158+ // we can keep the same name for the parameter.
1159+ // This lets rustdoc render it correctly in documentation.
1160+ hir:: PatKind :: Binding ( _, _, ident, _) => ( ident, false ) ,
1161+ hir:: PatKind :: Wild => {
1162+ ( Ident :: with_dummy_span ( rustc_span:: symbol:: kw:: Underscore ) , false )
1163+ }
1164+ _ => {
1165+ // Replace the ident for bindings that aren't simple.
1166+ let name = format ! ( "__arg{index}" ) ;
1167+ let ident = Ident :: from_str ( & name) ;
12221168
1223- parameters. push ( new_parameter) ;
1224- }
1169+ ( ident, false )
1170+ }
1171+ } ;
12251172
1226- let mkbody = |this : & mut LoweringContext < ' _ , ' hir > | {
1227- // Create a block from the user's function body:
1228- let user_body = this. lower_block_expr ( body) ;
1173+ let desugared_span = self . mark_span_with_reason ( DesugaringKind :: Async , span, None ) ;
12291174
1230- // Transform into `drop-temps { <user-body> }`, an expression:
1231- let desugared_span =
1232- this. mark_span_with_reason ( DesugaringKind :: Async , user_body. span , None ) ;
1233- let user_body = this. expr_drop_temps ( desugared_span, this. arena . alloc ( user_body) ) ;
1175+ // Construct a parameter representing `__argN: <ty>` to replace the parameter of the
1176+ // async function.
1177+ //
1178+ // If this is the simple case, this parameter will end up being the same as the
1179+ // original parameter, but with a different pattern id.
1180+ let stmt_attrs = self . attrs . get ( & parameter. hir_id . local_id ) . copied ( ) ;
1181+ let ( new_parameter_pat, new_parameter_id) = self . pat_ident ( desugared_span, ident) ;
1182+ let new_parameter = hir:: Param {
1183+ hir_id : parameter. hir_id ,
1184+ pat : new_parameter_pat,
1185+ ty_span : self . lower_span ( parameter. ty_span ) ,
1186+ span : self . lower_span ( parameter. span ) ,
1187+ } ;
12341188
1235- // As noted above, create the final block like
1189+ if is_simple_parameter {
1190+ // If this is the simple case, then we only insert one statement that is
1191+ // `let <pat> = <pat>;`. We re-use the original argument's pattern so that
1192+ // `HirId`s are densely assigned.
1193+ let expr = self . expr_ident ( desugared_span, ident, new_parameter_id) ;
1194+ let stmt = self . stmt_let_pat (
1195+ stmt_attrs,
1196+ desugared_span,
1197+ Some ( expr) ,
1198+ parameter. pat ,
1199+ hir:: LocalSource :: AsyncFn ,
1200+ ) ;
1201+ statements. push ( stmt) ;
1202+ } else {
1203+ // If this is not the simple case, then we construct two statements:
12361204 //
12371205 // ```
1238- // {
1239- // let $param_pattern = $raw_param;
1240- // ...
1241- // drop-temps { <user-body> }
1242- // }
1206+ // let __argN = __argN;
1207+ // let <pat> = __argN;
12431208 // ```
1244- let body = this. block_all (
1209+ //
1210+ // The first statement moves the parameter into the closure and thus ensures
1211+ // that the drop order is correct.
1212+ //
1213+ // The second statement creates the bindings that the user wrote.
1214+
1215+ // Construct the `let mut __argN = __argN;` statement. It must be a mut binding
1216+ // because the user may have specified a `ref mut` binding in the next
1217+ // statement.
1218+ let ( move_pat, move_id) =
1219+ self . pat_ident_binding_mode ( desugared_span, ident, hir:: BindingAnnotation :: MUT ) ;
1220+ let move_expr = self . expr_ident ( desugared_span, ident, new_parameter_id) ;
1221+ let move_stmt = self . stmt_let_pat (
1222+ None ,
12451223 desugared_span,
1246- this. arena . alloc_from_iter ( statements) ,
1247- Some ( user_body) ,
1224+ Some ( move_expr) ,
1225+ move_pat,
1226+ hir:: LocalSource :: AsyncFn ,
12481227 ) ;
12491228
1250- this. expr_block ( body)
1251- } ;
1252- let desugaring_kind = match coroutine_kind {
1253- CoroutineKind :: Async { .. } => hir:: CoroutineDesugaring :: Async ,
1254- CoroutineKind :: Gen { .. } => hir:: CoroutineDesugaring :: Gen ,
1255- CoroutineKind :: AsyncGen { .. } => hir:: CoroutineDesugaring :: AsyncGen ,
1229+ // Construct the `let <pat> = __argN;` statement. We re-use the original
1230+ // parameter's pattern so that `HirId`s are densely assigned.
1231+ let pattern_expr = self . expr_ident ( desugared_span, ident, move_id) ;
1232+ let pattern_stmt = self . stmt_let_pat (
1233+ stmt_attrs,
1234+ desugared_span,
1235+ Some ( pattern_expr) ,
1236+ parameter. pat ,
1237+ hir:: LocalSource :: AsyncFn ,
1238+ ) ;
1239+
1240+ statements. push ( move_stmt) ;
1241+ statements. push ( pattern_stmt) ;
12561242 } ;
1257- let coroutine_expr = this. make_desugared_coroutine_expr (
1258- CaptureBy :: Value { move_kw : rustc_span:: DUMMY_SP } ,
1259- closure_id,
1260- None ,
1261- body. span ,
1262- desugaring_kind,
1263- hir:: CoroutineSource :: Fn ,
1264- mkbody,
1243+
1244+ parameters. push ( new_parameter) ;
1245+ }
1246+
1247+ let mkbody = |this : & mut LoweringContext < ' _ , ' hir > | {
1248+ // Create a block from the user's function body:
1249+ let user_body = this. lower_block_expr ( body) ;
1250+
1251+ // Transform into `drop-temps { <user-body> }`, an expression:
1252+ let desugared_span =
1253+ this. mark_span_with_reason ( DesugaringKind :: Async , user_body. span , None ) ;
1254+ let user_body = this. expr_drop_temps ( desugared_span, this. arena . alloc ( user_body) ) ;
1255+
1256+ // As noted above, create the final block like
1257+ //
1258+ // ```
1259+ // {
1260+ // let $param_pattern = $raw_param;
1261+ // ...
1262+ // drop-temps { <user-body> }
1263+ // }
1264+ // ```
1265+ let body = this. block_all (
1266+ desugared_span,
1267+ this. arena . alloc_from_iter ( statements) ,
1268+ Some ( user_body) ,
12651269 ) ;
12661270
1267- let hir_id = this. lower_node_id ( closure_id) ;
1268- this. maybe_forward_track_caller ( body. span , fn_id, hir_id) ;
1269- let expr = hir:: Expr { hir_id, kind : coroutine_expr, span : this. lower_span ( body. span ) } ;
1271+ this. expr_block ( body)
1272+ } ;
1273+ let desugaring_kind = match coroutine_kind {
1274+ CoroutineKind :: Async { .. } => hir:: CoroutineDesugaring :: Async ,
1275+ CoroutineKind :: Gen { .. } => hir:: CoroutineDesugaring :: Gen ,
1276+ CoroutineKind :: AsyncGen { .. } => hir:: CoroutineDesugaring :: AsyncGen ,
1277+ } ;
1278+ let closure_id = coroutine_kind. closure_id ( ) ;
1279+ let coroutine_expr = self . make_desugared_coroutine_expr (
1280+ capture_clause,
1281+ closure_id,
1282+ None ,
1283+ body. span ,
1284+ desugaring_kind,
1285+ hir:: CoroutineSource :: Fn ,
1286+ mkbody,
1287+ ) ;
12701288
1271- ( this. arena . alloc_from_iter ( parameters) , expr)
1272- } )
1289+ let expr = hir:: Expr {
1290+ hir_id : self . lower_node_id ( closure_id) ,
1291+ kind : coroutine_expr,
1292+ span : self . lower_span ( body. span ) ,
1293+ } ;
1294+
1295+ ( self . arena . alloc_from_iter ( parameters) , expr)
12731296 }
12741297
12751298 fn lower_method_sig (
0 commit comments