@@ -904,7 +904,7 @@ fn inline_call<'tcx, I: Inliner<'tcx>>(
904904 destination,
905905 ) ;
906906 let dest_ty = dest. ty ( caller_body, tcx) ;
907- let temp = Place :: from ( new_call_temp ( caller_body, callsite, dest_ty, return_block) ) ;
907+ let temp = Place :: from ( new_call_temp ( caller_body, callsite, dest_ty, return_block, unwind ) ) ;
908908 caller_body[ callsite. block ] . statements . push ( Statement :: new (
909909 callsite. source_info ,
910910 StatementKind :: Assign ( Box :: new ( ( temp, dest) ) ) ,
@@ -921,12 +921,19 @@ fn inline_call<'tcx, I: Inliner<'tcx>>(
921921 } else {
922922 (
923923 true ,
924- new_call_temp ( caller_body, callsite, destination. ty ( caller_body, tcx) . ty , return_block) ,
924+ new_call_temp (
925+ caller_body,
926+ callsite,
927+ destination. ty ( caller_body, tcx) . ty ,
928+ return_block,
929+ unwind,
930+ ) ,
925931 )
926932 } ;
927933
928934 // Copy the arguments if needed.
929- let args = make_call_args ( inliner, args, callsite, caller_body, & callee_body, return_block) ;
935+ let args =
936+ make_call_args ( inliner, args, callsite, caller_body, & callee_body, return_block, unwind) ;
930937
931938 let mut integrator = Integrator {
932939 args : & args,
@@ -983,6 +990,25 @@ fn inline_call<'tcx, I: Inliner<'tcx>>(
983990 }
984991 caller_body[ block] . statements . rotate_right ( n) ;
985992 }
993+ if let UnwindAction :: Cleanup ( block) = unwind {
994+ // To avoid repeated O(n) insert, push any new statements to the end and rotate
995+ // the slice once.
996+ let mut n = 0 ;
997+ for local in callee_body. vars_and_temps_iter ( ) . rev ( ) {
998+ // Do this for *all* locals instead of just the always-live ones.
999+ // This is necessary because StorageDead is often not preserved on
1000+ // unwind paths.
1001+ //
1002+ // FIXME: Restrict this to only locals that are storage-live at an
1003+ // UnwindAction::Continue.
1004+ let new_local = integrator. map_local ( local) ;
1005+ caller_body[ block]
1006+ . statements
1007+ . push ( Statement :: new ( callsite. source_info , StatementKind :: StorageDead ( new_local) ) ) ;
1008+ n += 1 ;
1009+ }
1010+ caller_body[ block] . statements . rotate_right ( n) ;
1011+ }
9861012
9871013 // Insert all of the (mapped) parts of the callee body into the caller.
9881014 caller_body. local_decls . extend ( callee_body. drain_vars_and_temps ( ) ) ;
@@ -1045,6 +1071,7 @@ fn make_call_args<'tcx, I: Inliner<'tcx>>(
10451071 caller_body : & mut Body < ' tcx > ,
10461072 callee_body : & Body < ' tcx > ,
10471073 return_block : Option < BasicBlock > ,
1074+ unwind : UnwindAction ,
10481075) -> Box < [ Local ] > {
10491076 let tcx = inliner. tcx ( ) ;
10501077
@@ -1080,13 +1107,15 @@ fn make_call_args<'tcx, I: Inliner<'tcx>>(
10801107 callsite,
10811108 caller_body,
10821109 return_block,
1110+ unwind,
10831111 ) ;
10841112 let tuple = create_temp_if_necessary (
10851113 inliner,
10861114 args. next ( ) . unwrap ( ) . node ,
10871115 callsite,
10881116 caller_body,
10891117 return_block,
1118+ unwind,
10901119 ) ;
10911120 assert ! ( args. next( ) . is_none( ) ) ;
10921121
@@ -1104,13 +1133,29 @@ fn make_call_args<'tcx, I: Inliner<'tcx>>(
11041133 let tuple_field = Operand :: Move ( tcx. mk_place_field ( tuple, FieldIdx :: new ( i) , ty) ) ;
11051134
11061135 // Spill to a local to make e.g., `tmp0`.
1107- create_temp_if_necessary ( inliner, tuple_field, callsite, caller_body, return_block)
1136+ create_temp_if_necessary (
1137+ inliner,
1138+ tuple_field,
1139+ callsite,
1140+ caller_body,
1141+ return_block,
1142+ unwind,
1143+ )
11081144 } ) ;
11091145
11101146 closure_ref_arg. chain ( tuple_tmp_args) . collect ( )
11111147 } else {
11121148 args. into_iter ( )
1113- . map ( |a| create_temp_if_necessary ( inliner, a. node , callsite, caller_body, return_block) )
1149+ . map ( |a| {
1150+ create_temp_if_necessary (
1151+ inliner,
1152+ a. node ,
1153+ callsite,
1154+ caller_body,
1155+ return_block,
1156+ unwind,
1157+ )
1158+ } )
11141159 . collect ( )
11151160 }
11161161}
@@ -1123,6 +1168,7 @@ fn create_temp_if_necessary<'tcx, I: Inliner<'tcx>>(
11231168 callsite : & CallSite < ' tcx > ,
11241169 caller_body : & mut Body < ' tcx > ,
11251170 return_block : Option < BasicBlock > ,
1171+ unwind : UnwindAction ,
11261172) -> Local {
11271173 // Reuse the operand if it is a moved temporary.
11281174 if let Operand :: Move ( place) = & arg
@@ -1135,7 +1181,7 @@ fn create_temp_if_necessary<'tcx, I: Inliner<'tcx>>(
11351181 // Otherwise, create a temporary for the argument.
11361182 trace ! ( "creating temp for argument {:?}" , arg) ;
11371183 let arg_ty = arg. ty ( caller_body, inliner. tcx ( ) ) ;
1138- let local = new_call_temp ( caller_body, callsite, arg_ty, return_block) ;
1184+ let local = new_call_temp ( caller_body, callsite, arg_ty, return_block, unwind ) ;
11391185 caller_body[ callsite. block ] . statements . push ( Statement :: new (
11401186 callsite. source_info ,
11411187 StatementKind :: Assign ( Box :: new ( ( Place :: from ( local) , Rvalue :: Use ( arg, WithRetag :: Yes ) ) ) ) ,
@@ -1149,6 +1195,7 @@ fn new_call_temp<'tcx>(
11491195 callsite : & CallSite < ' tcx > ,
11501196 ty : Ty < ' tcx > ,
11511197 return_block : Option < BasicBlock > ,
1198+ unwind : UnwindAction ,
11521199) -> Local {
11531200 let local = caller_body. local_decls . push ( LocalDecl :: new ( ty, callsite. source_info . span ) ) ;
11541201
@@ -1161,6 +1208,11 @@ fn new_call_temp<'tcx>(
11611208 . statements
11621209 . insert ( 0 , Statement :: new ( callsite. source_info , StatementKind :: StorageDead ( local) ) ) ;
11631210 }
1211+ if let UnwindAction :: Cleanup ( block) = unwind {
1212+ caller_body[ block]
1213+ . statements
1214+ . insert ( 0 , Statement :: new ( callsite. source_info , StatementKind :: StorageDead ( local) ) ) ;
1215+ }
11641216
11651217 local
11661218}
0 commit comments