@@ -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;
@@ -21,15 +22,50 @@ use visit::{Visitor, walk_expr};
2122use super :: errors:: {
2223 AsyncCoroutinesNotSupported , AwaitOnlyInAsyncFnAndBlocks , ClosureCannotBeStatic ,
2324 CoroutineTooManyParameters , FunctionalRecordUpdateDestructuringAssignment ,
24- InclusiveRangeWithNoEnd , MatchArmWithNoBody , NeverPatternWithBody , NeverPatternWithGuard ,
25- UnderscoreExprLhsAssign ,
25+ InclusiveRangeWithNoEnd , MatchArmWithNoBody , MoveExprOnlyInPlainClosures ,
26+ NeverPatternWithBody , NeverPatternWithGuard , UnderscoreExprLhsAssign ,
2627} ;
2728use super :: {
2829 GenericArgsMode , ImplTraitContext , LoweringContext , ParamMode , ResolverAstLoweringExt ,
2930} ;
3031use crate :: errors:: { InvalidLegacyConstGenericArg , UseConstGenericArg , YieldInClosure } ;
3132use crate :: { AllowReturnTypeNotation , FnDeclKind , ImplTraitPosition , TryBlockScope } ;
3233
34+ struct MoveExprOccurrence < ' a > {
35+ id : NodeId ,
36+ move_kw_span : Span ,
37+ expr : & ' a Expr ,
38+ }
39+
40+ struct MoveExprCollector < ' a > {
41+ occurrences : Vec < MoveExprOccurrence < ' a > > ,
42+ }
43+
44+ impl < ' a > MoveExprCollector < ' a > {
45+ fn collect ( expr : & ' a Expr ) -> Vec < MoveExprOccurrence < ' a > > {
46+ let mut this = Self { occurrences : Vec :: new ( ) } ;
47+ this. visit_expr ( expr) ;
48+ this. occurrences
49+ }
50+ }
51+
52+ impl < ' a > Visitor < ' a > for MoveExprCollector < ' a > {
53+ fn visit_expr ( & mut self , expr : & ' a Expr ) {
54+ match & expr. kind {
55+ ExprKind :: Move ( inner, move_kw_span) => {
56+ self . visit_expr ( inner) ;
57+ self . occurrences . push ( MoveExprOccurrence {
58+ id : expr. id ,
59+ move_kw_span : * move_kw_span,
60+ expr : inner,
61+ } ) ;
62+ }
63+ ExprKind :: Closure ( ..) | ExprKind :: Gen ( ..) | ExprKind :: ConstBlock ( ..) => { }
64+ _ => walk_expr ( self , expr) ,
65+ }
66+ }
67+ }
68+
3369struct WillCreateDefIdsVisitor { }
3470
3571impl < ' v > rustc_ast:: visit:: Visitor < ' v > for WillCreateDefIdsVisitor {
@@ -96,11 +132,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
96132 ExprKind :: ForLoop { pat, iter, body, label, kind } => {
97133 return self . lower_expr_for ( e, pat, iter, body, * label, * kind) ;
98134 }
135+ ExprKind :: Closure ( box closure) => return self . lower_expr_closure_expr ( e, closure) ,
99136 _ => ( ) ,
100137 }
101138
102139 let expr_hir_id = self . lower_node_id ( e. id ) ;
103- let attrs = self . lower_attrs ( expr_hir_id, & e. attrs , e. span , Target :: from_expr ( e) ) ;
140+ self . lower_attrs ( expr_hir_id, & e. attrs , e. span , Target :: from_expr ( e) ) ;
104141
105142 let kind = match & e. kind {
106143 ExprKind :: Array ( exprs) => hir:: ExprKind :: Array ( self . lower_exprs ( exprs) ) ,
@@ -213,42 +250,35 @@ impl<'hir> LoweringContext<'_, 'hir> {
213250 } ,
214251 ) ,
215252 ExprKind :: Await ( expr, await_kw_span) => self . lower_expr_await ( * await_kw_span, expr) ,
253+ ExprKind :: Move ( _, move_kw_span) => {
254+ if let Some ( ( ident, binding) ) = self
255+ . move_expr_bindings
256+ . last ( )
257+ . and_then ( |bindings| bindings. get ( & e. id ) . copied ( ) )
258+ {
259+ hir:: ExprKind :: Path ( hir:: QPath :: Resolved (
260+ None ,
261+ self . arena . alloc ( hir:: Path {
262+ span : self . lower_span ( e. span ) ,
263+ res : Res :: Local ( binding) ,
264+ segments : arena_vec ! [
265+ self ;
266+ hir:: PathSegment :: new(
267+ self . lower_ident( ident) ,
268+ self . next_id( ) ,
269+ Res :: Local ( binding) ,
270+ )
271+ ] ,
272+ } ) ,
273+ ) )
274+ } else {
275+ self . dcx ( ) . emit_err ( MoveExprOnlyInPlainClosures { span : * move_kw_span } ) ;
276+ hir:: ExprKind :: Err (
277+ self . dcx ( ) . span_delayed_bug ( * move_kw_span, "invalid move(expr)" ) ,
278+ )
279+ }
280+ }
216281 ExprKind :: Use ( expr, use_kw_span) => self . lower_expr_use ( * use_kw_span, expr) ,
217- ExprKind :: Closure ( box Closure {
218- binder,
219- capture_clause,
220- constness,
221- coroutine_kind,
222- movability,
223- fn_decl,
224- body,
225- fn_decl_span,
226- fn_arg_span,
227- } ) => match coroutine_kind {
228- Some ( coroutine_kind) => self . lower_expr_coroutine_closure (
229- binder,
230- * capture_clause,
231- e. id ,
232- expr_hir_id,
233- * coroutine_kind,
234- fn_decl,
235- body,
236- * fn_decl_span,
237- * fn_arg_span,
238- ) ,
239- None => self . lower_expr_closure (
240- attrs,
241- binder,
242- * capture_clause,
243- e. id ,
244- * constness,
245- * movability,
246- fn_decl,
247- body,
248- * fn_decl_span,
249- * fn_arg_span,
250- ) ,
251- } ,
252282 ExprKind :: Gen ( capture_clause, block, genblock_kind, decl_span) => {
253283 let desugaring_kind = match genblock_kind {
254284 GenBlockKind :: Async => hir:: CoroutineDesugaring :: Async ,
@@ -383,7 +413,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
383413
384414 ExprKind :: Try ( sub_expr) => self . lower_expr_try ( e. span , sub_expr) ,
385415
386- ExprKind :: Paren ( _) | ExprKind :: ForLoop { .. } => {
416+ ExprKind :: Paren ( _) | ExprKind :: ForLoop { .. } | ExprKind :: Closure ( .. ) => {
387417 unreachable ! ( "already handled" )
388418 }
389419
@@ -792,6 +822,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
792822 fn_arg_span : None ,
793823 kind : hir:: ClosureKind :: Coroutine ( coroutine_kind) ,
794824 constness : hir:: Constness :: NotConst ,
825+ explicit_captures : & [ ] ,
795826 } ) )
796827 }
797828
@@ -1055,6 +1086,133 @@ impl<'hir> LoweringContext<'_, 'hir> {
10551086 hir:: ExprKind :: Use ( self . lower_expr ( expr) , self . lower_span ( use_kw_span) )
10561087 }
10571088
1089+ fn lower_expr_closure_expr ( & mut self , e : & Expr , closure : & Closure ) -> hir:: Expr < ' hir > {
1090+ let expr_hir_id = self . lower_node_id ( e. id ) ;
1091+ let attrs = self . lower_attrs ( expr_hir_id, & e. attrs , e. span , Target :: from_expr ( e) ) ;
1092+
1093+ match closure. coroutine_kind {
1094+ Some ( coroutine_kind) => hir:: Expr {
1095+ hir_id : expr_hir_id,
1096+ kind : self . lower_expr_coroutine_closure (
1097+ & closure. binder ,
1098+ closure. capture_clause ,
1099+ e. id ,
1100+ expr_hir_id,
1101+ coroutine_kind,
1102+ & closure. fn_decl ,
1103+ & closure. body ,
1104+ closure. fn_decl_span ,
1105+ closure. fn_arg_span ,
1106+ ) ,
1107+ span : self . lower_span ( e. span ) ,
1108+ } ,
1109+ None => self . lower_expr_plain_closure_with_move_exprs (
1110+ expr_hir_id,
1111+ attrs,
1112+ & closure. binder ,
1113+ closure. capture_clause ,
1114+ e. id ,
1115+ closure. constness ,
1116+ closure. movability ,
1117+ & closure. fn_decl ,
1118+ & closure. body ,
1119+ closure. fn_decl_span ,
1120+ closure. fn_arg_span ,
1121+ e. span ,
1122+ ) ,
1123+ }
1124+ }
1125+
1126+ fn lower_expr_plain_closure_with_move_exprs (
1127+ & mut self ,
1128+ expr_hir_id : HirId ,
1129+ attrs : & [ rustc_hir:: Attribute ] ,
1130+ binder : & ClosureBinder ,
1131+ capture_clause : CaptureBy ,
1132+ closure_id : NodeId ,
1133+ constness : Const ,
1134+ movability : Movability ,
1135+ decl : & FnDecl ,
1136+ body : & Expr ,
1137+ fn_decl_span : Span ,
1138+ fn_arg_span : Span ,
1139+ whole_span : Span ,
1140+ ) -> hir:: Expr < ' hir > {
1141+ let occurrences = MoveExprCollector :: collect ( body) ;
1142+ if occurrences. is_empty ( ) {
1143+ return hir:: Expr {
1144+ hir_id : expr_hir_id,
1145+ kind : self . lower_expr_closure (
1146+ attrs,
1147+ binder,
1148+ capture_clause,
1149+ closure_id,
1150+ constness,
1151+ movability,
1152+ decl,
1153+ body,
1154+ fn_decl_span,
1155+ fn_arg_span,
1156+ & [ ] ,
1157+ ) ,
1158+ span : self . lower_span ( whole_span) ,
1159+ } ;
1160+ }
1161+
1162+ let mut bindings = NodeMap :: default ( ) ;
1163+ let mut lowered_occurrences = Vec :: with_capacity ( occurrences. len ( ) ) ;
1164+ for ( index, occurrence) in occurrences. iter ( ) . enumerate ( ) {
1165+ let ident = Ident :: from_str_and_span ( & format ! ( "__move_expr_{index}" ) , occurrence. move_kw_span ) ;
1166+ let ( pat, binding) = self . pat_ident ( occurrence. expr . span , ident) ;
1167+ bindings. insert ( occurrence. id , ( ident, binding) ) ;
1168+ lowered_occurrences. push ( ( occurrence, pat, binding) ) ;
1169+ }
1170+
1171+ self . move_expr_bindings . push ( bindings) ;
1172+ let mut stmts = Vec :: with_capacity ( lowered_occurrences. len ( ) ) ;
1173+ for ( occurrence, pat, _) in & lowered_occurrences {
1174+ let init = self . lower_expr ( occurrence. expr ) ;
1175+ stmts. push ( self . stmt_let_pat (
1176+ None ,
1177+ occurrence. expr . span ,
1178+ Some ( init) ,
1179+ * pat,
1180+ hir:: LocalSource :: Normal ,
1181+ ) ) ;
1182+ }
1183+
1184+ let explicit_captures =
1185+ self . arena . alloc_from_iter ( lowered_occurrences. iter ( ) . map ( |( occurrence, _, binding) | {
1186+ hir:: ExplicitCapture {
1187+ var_hir_id : * binding,
1188+ origin_span : self . lower_span ( occurrence. move_kw_span ) ,
1189+ }
1190+ } ) ) ;
1191+
1192+ let closure_expr = self . arena . alloc ( hir:: Expr {
1193+ hir_id : expr_hir_id,
1194+ kind : self . lower_expr_closure (
1195+ attrs,
1196+ binder,
1197+ capture_clause,
1198+ closure_id,
1199+ constness,
1200+ movability,
1201+ decl,
1202+ body,
1203+ fn_decl_span,
1204+ fn_arg_span,
1205+ explicit_captures,
1206+ ) ,
1207+ span : self . lower_span ( whole_span) ,
1208+ } ) ;
1209+ self . move_expr_bindings . pop ( ) ;
1210+
1211+ let stmts = self . arena . alloc_from_iter ( stmts) ;
1212+ let block = self . block_all ( whole_span, stmts, Some ( closure_expr) ) ;
1213+ self . expr ( whole_span, hir:: ExprKind :: Block ( block, None ) )
1214+ }
1215+
10581216 fn lower_expr_closure (
10591217 & mut self ,
10601218 attrs : & [ rustc_hir:: Attribute ] ,
@@ -1067,6 +1225,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
10671225 body : & Expr ,
10681226 fn_decl_span : Span ,
10691227 fn_arg_span : Span ,
1228+ explicit_captures : & ' hir [ hir:: ExplicitCapture ] ,
10701229 ) -> hir:: ExprKind < ' hir > {
10711230 let closure_def_id = self . local_def_id ( closure_id) ;
10721231 let ( binder_clause, generic_params) = self . lower_closure_binder ( binder) ;
@@ -1101,6 +1260,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
11011260 fn_arg_span : Some ( self . lower_span ( fn_arg_span) ) ,
11021261 kind : closure_kind,
11031262 constness : self . lower_constness ( constness) ,
1263+ explicit_captures,
11041264 } ) ;
11051265
11061266 hir:: ExprKind :: Closure ( c)
@@ -1218,6 +1378,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
12181378 // "coroutine that returns &str", rather than directly returning a `&str`.
12191379 kind : hir:: ClosureKind :: CoroutineClosure ( coroutine_desugaring) ,
12201380 constness : hir:: Constness :: NotConst ,
1381+ explicit_captures : & [ ] ,
12211382 } ) ;
12221383 hir:: ExprKind :: Closure ( c)
12231384 }
0 commit comments