@@ -2,6 +2,7 @@ use std::mem;
22use std:: ops:: ControlFlow ;
33use std:: sync:: Arc ;
44
5+ use rustc_ast:: node_id:: NodeMap ;
56use rustc_ast:: * ;
67use rustc_ast_pretty:: pprust:: expr_to_string;
78use rustc_data_structures:: stack:: ensure_sufficient_stack;
@@ -29,6 +30,41 @@ use super::{
2930use crate :: errors:: { InvalidLegacyConstGenericArg , UseConstGenericArg , YieldInClosure } ;
3031use crate :: { AllowReturnTypeNotation , FnDeclKind , ImplTraitPosition , TryBlockScope } ;
3132
33+ struct MoveExprOccurrence < ' a > {
34+ id : NodeId ,
35+ move_kw_span : Span ,
36+ expr : & ' a Expr ,
37+ }
38+
39+ struct MoveExprCollector < ' a > {
40+ occurrences : Vec < MoveExprOccurrence < ' a > > ,
41+ }
42+
43+ impl < ' a > MoveExprCollector < ' a > {
44+ fn collect ( expr : & ' a Expr ) -> Vec < MoveExprOccurrence < ' a > > {
45+ let mut this = Self { occurrences : Vec :: new ( ) } ;
46+ this. visit_expr ( expr) ;
47+ this. occurrences
48+ }
49+ }
50+
51+ impl < ' a > Visitor < ' a > for MoveExprCollector < ' a > {
52+ fn visit_expr ( & mut self , expr : & ' a Expr ) {
53+ match & expr. kind {
54+ ExprKind :: Move ( inner, move_kw_span) => {
55+ self . visit_expr ( inner) ;
56+ self . occurrences . push ( MoveExprOccurrence {
57+ id : expr. id ,
58+ move_kw_span : * move_kw_span,
59+ expr : inner,
60+ } ) ;
61+ }
62+ ExprKind :: Closure ( ..) | ExprKind :: Gen ( ..) | ExprKind :: ConstBlock ( ..) => { }
63+ _ => walk_expr ( self , expr) ,
64+ }
65+ }
66+ }
67+
3268struct WillCreateDefIdsVisitor { }
3369
3470impl < ' v > rustc_ast:: visit:: Visitor < ' v > for WillCreateDefIdsVisitor {
@@ -95,11 +131,12 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
95131 ExprKind :: ForLoop { pat, iter, body, label, kind } => {
96132 return self . lower_expr_for ( e, pat, iter, body, * label, * kind) ;
97133 }
134+ ExprKind :: Closure ( box closure) => return self . lower_expr_closure_expr ( e, closure) ,
98135 _ => ( ) ,
99136 }
100137
101138 let expr_hir_id = self . lower_node_id ( e. id ) ;
102- let attrs = self . lower_attrs ( expr_hir_id, & e. attrs , e. span , Target :: from_expr ( e) ) ;
139+ self . lower_attrs ( expr_hir_id, & e. attrs , e. span , Target :: from_expr ( e) ) ;
103140
104141 let kind = match & e. kind {
105142 ExprKind :: Array ( exprs) => hir:: ExprKind :: Array ( self . lower_exprs ( exprs) ) ,
@@ -219,48 +256,34 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
219256 self . dcx ( ) . span_delayed_bug ( * move_kw_span, "invalid move(expr)" ) ,
220257 ) ;
221258 }
222- self . dcx ( ) . emit_err ( MoveExprOnlyInPlainClosures { span : * move_kw_span } ) ;
223- hir:: ExprKind :: Err (
224- self . dcx ( ) . span_delayed_bug ( * move_kw_span, "invalid move(expr)" ) ,
225- )
259+ if let Some ( ( ident, binding) ) = self
260+ . move_expr_bindings
261+ . last ( )
262+ . and_then ( |bindings| bindings. get ( & e. id ) . copied ( ) )
263+ {
264+ hir:: ExprKind :: Path ( hir:: QPath :: Resolved (
265+ None ,
266+ self . arena . alloc ( hir:: Path {
267+ span : self . lower_span ( e. span ) ,
268+ res : Res :: Local ( binding) ,
269+ segments : arena_vec ! [
270+ self ;
271+ hir:: PathSegment :: new(
272+ self . lower_ident( ident) ,
273+ self . next_id( ) ,
274+ Res :: Local ( binding) ,
275+ )
276+ ] ,
277+ } ) ,
278+ ) )
279+ } else {
280+ self . dcx ( ) . emit_err ( MoveExprOnlyInPlainClosures { span : * move_kw_span } ) ;
281+ hir:: ExprKind :: Err (
282+ self . dcx ( ) . span_delayed_bug ( * move_kw_span, "invalid move(expr)" ) ,
283+ )
284+ }
226285 }
227286 ExprKind :: Use ( expr, use_kw_span) => self . lower_expr_use ( * use_kw_span, expr) ,
228- ExprKind :: Closure ( box Closure {
229- binder,
230- capture_clause,
231- constness,
232- coroutine_kind,
233- movability,
234- fn_decl,
235- body,
236- fn_decl_span,
237- fn_arg_span,
238- } ) => match coroutine_kind {
239- Some ( coroutine_kind) => self . lower_expr_coroutine_closure (
240- binder,
241- * capture_clause,
242- e. id ,
243- expr_hir_id,
244- * coroutine_kind,
245- * constness,
246- fn_decl,
247- body,
248- * fn_decl_span,
249- * fn_arg_span,
250- ) ,
251- None => self . lower_expr_closure (
252- attrs,
253- binder,
254- * capture_clause,
255- e. id ,
256- * constness,
257- * movability,
258- fn_decl,
259- body,
260- * fn_decl_span,
261- * fn_arg_span,
262- ) ,
263- } ,
264287 ExprKind :: Gen ( capture_clause, block, genblock_kind, decl_span) => {
265288 let desugaring_kind = match genblock_kind {
266289 GenBlockKind :: Async => hir:: CoroutineDesugaring :: Async ,
@@ -395,7 +418,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
395418
396419 ExprKind :: Try ( sub_expr) => self . lower_expr_try ( e. span , sub_expr) ,
397420
398- ExprKind :: Paren ( _) | ExprKind :: ForLoop { .. } => {
421+ ExprKind :: Paren ( _) | ExprKind :: ForLoop { .. } | ExprKind :: Closure ( .. ) => {
399422 unreachable ! ( "already handled" )
400423 }
401424
@@ -804,6 +827,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
804827 fn_arg_span : None ,
805828 kind : hir:: ClosureKind :: Coroutine ( coroutine_kind) ,
806829 constness : hir:: Constness :: NotConst ,
830+ explicit_captures : & [ ] ,
807831 } ) )
808832 }
809833
@@ -1067,6 +1091,134 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
10671091 hir:: ExprKind :: Use ( self . lower_expr ( expr) , self . lower_span ( use_kw_span) )
10681092 }
10691093
1094+ fn lower_expr_closure_expr ( & mut self , e : & Expr , closure : & Closure ) -> hir:: Expr < ' hir > {
1095+ let expr_hir_id = self . lower_node_id ( e. id ) ;
1096+ let attrs = self . lower_attrs ( expr_hir_id, & e. attrs , e. span , Target :: from_expr ( e) ) ;
1097+
1098+ match closure. coroutine_kind {
1099+ Some ( coroutine_kind) => hir:: Expr {
1100+ hir_id : expr_hir_id,
1101+ kind : self . lower_expr_coroutine_closure (
1102+ & closure. binder ,
1103+ closure. capture_clause ,
1104+ e. id ,
1105+ expr_hir_id,
1106+ coroutine_kind,
1107+ closure. constness ,
1108+ & closure. fn_decl ,
1109+ & closure. body ,
1110+ closure. fn_decl_span ,
1111+ closure. fn_arg_span ,
1112+ ) ,
1113+ span : self . lower_span ( e. span ) ,
1114+ } ,
1115+ None => self . lower_expr_plain_closure_with_move_exprs (
1116+ expr_hir_id,
1117+ attrs,
1118+ & closure. binder ,
1119+ closure. capture_clause ,
1120+ e. id ,
1121+ closure. constness ,
1122+ closure. movability ,
1123+ & closure. fn_decl ,
1124+ & closure. body ,
1125+ closure. fn_decl_span ,
1126+ closure. fn_arg_span ,
1127+ e. span ,
1128+ ) ,
1129+ }
1130+ }
1131+
1132+ fn lower_expr_plain_closure_with_move_exprs (
1133+ & mut self ,
1134+ expr_hir_id : HirId ,
1135+ attrs : & [ rustc_hir:: Attribute ] ,
1136+ binder : & ClosureBinder ,
1137+ capture_clause : CaptureBy ,
1138+ closure_id : NodeId ,
1139+ constness : Const ,
1140+ movability : Movability ,
1141+ decl : & FnDecl ,
1142+ body : & Expr ,
1143+ fn_decl_span : Span ,
1144+ fn_arg_span : Span ,
1145+ whole_span : Span ,
1146+ ) -> hir:: Expr < ' hir > {
1147+ let occurrences = MoveExprCollector :: collect ( body) ;
1148+ if occurrences. is_empty ( ) {
1149+ return hir:: Expr {
1150+ hir_id : expr_hir_id,
1151+ kind : self . lower_expr_closure (
1152+ attrs,
1153+ binder,
1154+ capture_clause,
1155+ closure_id,
1156+ constness,
1157+ movability,
1158+ decl,
1159+ body,
1160+ fn_decl_span,
1161+ fn_arg_span,
1162+ & [ ] ,
1163+ ) ,
1164+ span : self . lower_span ( whole_span) ,
1165+ } ;
1166+ }
1167+
1168+ let mut bindings = NodeMap :: default ( ) ;
1169+ let mut lowered_occurrences = Vec :: with_capacity ( occurrences. len ( ) ) ;
1170+ for ( index, occurrence) in occurrences. iter ( ) . enumerate ( ) {
1171+ let ident =
1172+ Ident :: from_str_and_span ( & format ! ( "__move_expr_{index}" ) , occurrence. move_kw_span ) ;
1173+ let ( pat, binding) = self . pat_ident ( occurrence. expr . span , ident) ;
1174+ bindings. insert ( occurrence. id , ( ident, binding) ) ;
1175+ lowered_occurrences. push ( ( occurrence, pat, binding) ) ;
1176+ }
1177+
1178+ self . move_expr_bindings . push ( bindings) ;
1179+ let mut stmts = Vec :: with_capacity ( lowered_occurrences. len ( ) ) ;
1180+ for ( occurrence, pat, _) in & lowered_occurrences {
1181+ let init = self . lower_expr ( occurrence. expr ) ;
1182+ stmts. push ( self . stmt_let_pat (
1183+ None ,
1184+ occurrence. expr . span ,
1185+ Some ( init) ,
1186+ * pat,
1187+ hir:: LocalSource :: Normal ,
1188+ ) ) ;
1189+ }
1190+
1191+ let explicit_captures = self . arena . alloc_from_iter ( lowered_occurrences. iter ( ) . map (
1192+ |( occurrence, _, binding) | hir:: ExplicitCapture {
1193+ var_hir_id : * binding,
1194+ origin_span : self . lower_span ( occurrence. move_kw_span ) ,
1195+ } ,
1196+ ) ) ;
1197+
1198+ let closure_expr = self . arena . alloc ( hir:: Expr {
1199+ hir_id : expr_hir_id,
1200+ kind : self . lower_expr_closure (
1201+ attrs,
1202+ binder,
1203+ capture_clause,
1204+ closure_id,
1205+ constness,
1206+ movability,
1207+ decl,
1208+ body,
1209+ fn_decl_span,
1210+ fn_arg_span,
1211+ explicit_captures,
1212+ ) ,
1213+ span : self . lower_span ( whole_span) ,
1214+ } ) ;
1215+ self . move_expr_bindings . pop ( ) ;
1216+
1217+ let stmts = self . arena . alloc_from_iter ( stmts) ;
1218+ let block = self . block_all ( whole_span, stmts, Some ( closure_expr) ) ;
1219+ self . expr ( whole_span, hir:: ExprKind :: Block ( block, None ) )
1220+ }
1221+
10701222 fn lower_expr_closure (
10711223 & mut self ,
10721224 attrs : & [ rustc_hir:: Attribute ] ,
@@ -1079,6 +1231,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
10791231 body : & Expr ,
10801232 fn_decl_span : Span ,
10811233 fn_arg_span : Span ,
1234+ explicit_captures : & ' hir [ hir:: ExplicitCapture ] ,
10821235 ) -> hir:: ExprKind < ' hir > {
10831236 let closure_def_id = self . local_def_id ( closure_id) ;
10841237 let ( binder_clause, generic_params) = self . lower_closure_binder ( binder) ;
@@ -1120,6 +1273,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
11201273 fn_arg_span : Some ( self . lower_span ( fn_arg_span) ) ,
11211274 kind : closure_kind,
11221275 constness : self . lower_constness ( constness) ,
1276+ explicit_captures,
11231277 } ) ;
11241278
11251279 hir:: ExprKind :: Closure ( c)
@@ -1241,7 +1395,8 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
12411395 // knows that a `FnDecl` output type like `-> &str` actually means
12421396 // "coroutine that returns &str", rather than directly returning a `&str`.
12431397 kind : hir:: ClosureKind :: CoroutineClosure ( coroutine_desugaring) ,
1244- constness : self . lower_constness ( constness) ,
1398+ constness : hir:: Constness :: NotConst ,
1399+ explicit_captures : & [ ] ,
12451400 } ) ;
12461401 hir:: ExprKind :: Closure ( c)
12471402 }
0 commit comments