@@ -160,6 +160,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
160
160
mut unwind : mir:: UnwindAction ,
161
161
lifetime_ends_after_call : & [ ( Bx :: Value , Size ) ] ,
162
162
instance : Option < Instance < ' tcx > > ,
163
+ tail : bool ,
163
164
mergeable_succ : bool ,
164
165
) -> MergingSucc {
165
166
let tcx = bx. tcx ( ) ;
@@ -252,8 +253,16 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
252
253
}
253
254
MergingSucc :: False
254
255
} else {
255
- let llret =
256
- bx. call ( fn_ty, fn_attrs, Some ( fn_abi) , fn_ptr, llargs, self . funclet ( fx) , instance) ;
256
+ let llret = if !tail {
257
+ bx. call ( fn_ty, fn_attrs, Some ( fn_abi) , fn_ptr, llargs, self . funclet ( fx) , instance)
258
+ } else {
259
+ bx. call ( fn_ty, fn_attrs, Some ( fn_abi) , fn_ptr, llargs, None , instance)
260
+ } ;
261
+
262
+ if tail {
263
+ bx. set_tail_call ( llret) ;
264
+ }
265
+
257
266
if fx. mir [ self . bb ] . is_cleanup {
258
267
bx. apply_attrs_to_cleanup_callsite ( llret) ;
259
268
}
@@ -264,6 +273,12 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
264
273
}
265
274
fx. store_return ( bx, ret_dest, & fn_abi. ret , llret) ;
266
275
self . funclet_br ( fx, bx, target, mergeable_succ)
276
+ } else if tail {
277
+ for & ( tmp, size) in lifetime_ends_after_call {
278
+ bx. lifetime_end ( tmp, size) ;
279
+ }
280
+ bx. ret ( llret) ;
281
+ MergingSucc :: False
267
282
} else {
268
283
bx. unreachable ( ) ;
269
284
MergingSucc :: False
@@ -659,6 +674,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
659
674
unwind,
660
675
& [ ] ,
661
676
Some ( drop_instance) ,
677
+ false ,
662
678
!maybe_null && mergeable_succ,
663
679
)
664
680
}
@@ -747,8 +763,19 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
747
763
let ( fn_abi, llfn, instance) = common:: build_langcall ( bx, span, lang_item) ;
748
764
749
765
// Codegen the actual panic invoke/call.
750
- let merging_succ =
751
- helper. do_call ( self , bx, fn_abi, llfn, & args, None , unwind, & [ ] , Some ( instance) , false ) ;
766
+ let merging_succ = helper. do_call (
767
+ self ,
768
+ bx,
769
+ fn_abi,
770
+ llfn,
771
+ & args,
772
+ None ,
773
+ unwind,
774
+ & [ ] ,
775
+ Some ( instance) ,
776
+ false ,
777
+ false ,
778
+ ) ;
752
779
assert_eq ! ( merging_succ, MergingSucc :: False ) ;
753
780
MergingSucc :: False
754
781
}
@@ -778,6 +805,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
778
805
& [ ] ,
779
806
Some ( instance) ,
780
807
false ,
808
+ false ,
781
809
) ;
782
810
assert_eq ! ( merging_succ, MergingSucc :: False ) ;
783
811
}
@@ -845,6 +873,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
845
873
unwind,
846
874
& [ ] ,
847
875
Some ( instance) ,
876
+ false ,
848
877
mergeable_succ,
849
878
) )
850
879
}
@@ -860,6 +889,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
860
889
target : Option < mir:: BasicBlock > ,
861
890
unwind : mir:: UnwindAction ,
862
891
fn_span : Span ,
892
+ tail : bool ,
863
893
mergeable_succ : bool ,
864
894
) -> MergingSucc {
865
895
let source_info = mir:: SourceInfo { span : fn_span, ..terminator. source_info } ;
@@ -1003,8 +1033,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
1003
1033
// We still need to call `make_return_dest` even if there's no `target`, since
1004
1034
// `fn_abi.ret` could be `PassMode::Indirect`, even if it is uninhabited,
1005
1035
// and `make_return_dest` adds the return-place indirect pointer to `llargs`.
1006
- let return_dest = self . make_return_dest ( bx, destination, & fn_abi. ret , & mut llargs) ;
1007
- let destination = target. map ( |target| ( return_dest, target) ) ;
1036
+ let destination = if !tail {
1037
+ let return_dest = self . make_return_dest ( bx, destination, & fn_abi. ret , & mut llargs) ;
1038
+ target. map ( |target| ( return_dest, target) )
1039
+ } else {
1040
+ None
1041
+ } ;
1008
1042
1009
1043
// Split the rust-call tupled arguments off.
1010
1044
let ( first_args, untuple) = if sig. abi ( ) == ExternAbi :: RustCall
@@ -1147,106 +1181,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
1147
1181
unwind,
1148
1182
& lifetime_ends_after_call,
1149
1183
instance,
1184
+ tail,
1150
1185
mergeable_succ,
1151
1186
)
1152
1187
}
1153
1188
1154
- fn codegen_tail_call_terminator (
1155
- & mut self ,
1156
- bx : & mut Bx ,
1157
- func : & mir:: Operand < ' tcx > ,
1158
- args : & [ Spanned < mir:: Operand < ' tcx > > ] ,
1159
- fn_span : Span ,
1160
- mergeable_succ : bool ,
1161
- ) -> MergingSucc {
1162
- // We don't need source_info as we already have fn_span for diagnostics
1163
- let func = self . codegen_operand ( bx, func) ;
1164
- let fn_ty = func. layout . ty ;
1165
-
1166
- // Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar.
1167
- let ( fn_ptr, fn_abi, instance) = match * fn_ty. kind ( ) {
1168
- ty:: FnDef ( def_id, substs) => {
1169
- let instance = ty:: Instance :: expect_resolve (
1170
- bx. tcx ( ) ,
1171
- bx. typing_env ( ) ,
1172
- def_id,
1173
- substs,
1174
- fn_span,
1175
- ) ;
1176
- let fn_ptr = bx. get_fn_addr ( instance) ;
1177
- let fn_abi = bx. fn_abi_of_instance ( instance, ty:: List :: empty ( ) ) ;
1178
- ( fn_ptr, fn_abi, Some ( instance) )
1179
- }
1180
- ty:: FnPtr ( ..) => {
1181
- let sig = fn_ty. fn_sig ( bx. tcx ( ) ) ;
1182
- let extra_args = bx. tcx ( ) . mk_type_list ( & [ ] ) ;
1183
- let fn_ptr = func. immediate ( ) ;
1184
- let fn_abi = bx. fn_abi_of_fn_ptr ( sig, extra_args) ;
1185
- ( fn_ptr, fn_abi, None )
1186
- }
1187
- _ => bug ! ( "{} is not callable" , func. layout. ty) ,
1188
- } ;
1189
-
1190
- let mut llargs = Vec :: with_capacity ( args. len ( ) ) ;
1191
- let mut lifetime_ends_after_call = Vec :: new ( ) ;
1192
-
1193
- // Process arguments
1194
- for arg in args {
1195
- let op = self . codegen_operand ( bx, & arg. node ) ;
1196
- let arg_idx = llargs. len ( ) ;
1197
-
1198
- if arg_idx < fn_abi. args . len ( ) {
1199
- self . codegen_argument (
1200
- bx,
1201
- op,
1202
- & mut llargs,
1203
- & fn_abi. args [ arg_idx] ,
1204
- & mut lifetime_ends_after_call,
1205
- ) ;
1206
- } else {
1207
- // This can happen in case of C-variadic functions
1208
- let is_immediate = match op. val {
1209
- Immediate ( _) => true ,
1210
- _ => false ,
1211
- } ;
1212
-
1213
- if is_immediate {
1214
- llargs. push ( op. immediate ( ) ) ;
1215
- } else {
1216
- let temp = PlaceRef :: alloca ( bx, op. layout ) ;
1217
- op. val . store ( bx, temp) ;
1218
- llargs. push ( bx. load (
1219
- bx. backend_type ( op. layout ) ,
1220
- temp. val . llval ,
1221
- temp. val . align ,
1222
- ) ) ;
1223
- }
1224
- }
1225
- }
1226
-
1227
- // Call the function
1228
- let fn_ty = bx. fn_decl_backend_type ( fn_abi) ;
1229
- let fn_attrs = if let Some ( instance) = instance
1230
- && bx. tcx ( ) . def_kind ( instance. def_id ( ) ) . has_codegen_attrs ( )
1231
- {
1232
- Some ( bx. tcx ( ) . codegen_fn_attrs ( instance. def_id ( ) ) )
1233
- } else {
1234
- None
1235
- } ;
1236
-
1237
- // Perform the actual function call
1238
- let llret = bx. call ( fn_ty, fn_attrs, Some ( fn_abi) , fn_ptr, & llargs, None , instance) ;
1239
-
1240
- // Mark as tail call - this is the critical part
1241
- bx. set_tail_call ( llret) ;
1242
-
1243
- // Return the result - musttail requires ret immediately after the call
1244
- bx. ret ( llret) ;
1245
-
1246
- assert_eq ! ( mergeable_succ, false ) ;
1247
- MergingSucc :: False
1248
- }
1249
-
1250
1189
fn codegen_asm_terminator (
1251
1190
& mut self ,
1252
1191
helper : TerminatorCodegenHelper < ' tcx > ,
@@ -1484,10 +1423,27 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
1484
1423
target,
1485
1424
unwind,
1486
1425
fn_span,
1426
+ false ,
1487
1427
mergeable_succ ( ) ,
1488
1428
) ,
1489
1429
mir:: TerminatorKind :: TailCall { ref func, ref args, fn_span } => {
1490
- self . codegen_tail_call_terminator ( bx, func, args, fn_span, mergeable_succ ( ) )
1430
+ let destination = mir:: Place :: from ( mir:: RETURN_PLACE ) ;
1431
+ let target = None ;
1432
+ let unwind = mir:: UnwindAction :: Unreachable ;
1433
+
1434
+ self . codegen_call_terminator (
1435
+ helper,
1436
+ bx,
1437
+ terminator,
1438
+ func,
1439
+ args,
1440
+ destination,
1441
+ target,
1442
+ unwind,
1443
+ fn_span,
1444
+ true ,
1445
+ mergeable_succ ( ) ,
1446
+ )
1491
1447
}
1492
1448
mir:: TerminatorKind :: CoroutineDrop | mir:: TerminatorKind :: Yield { .. } => {
1493
1449
bug ! ( "coroutine ops in codegen" )
0 commit comments