@@ -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 ( ) ;
@@ -221,6 +222,11 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
221
222
}
222
223
} ;
223
224
225
+ if tail {
226
+ bx. tail_call ( fn_ty, fn_attrs, fn_abi, fn_ptr, llargs, self . funclet ( fx) , instance) ;
227
+ return MergingSucc :: False ;
228
+ }
229
+
224
230
if let Some ( unwind_block) = unwind_block {
225
231
let ret_llbb = if let Some ( ( _, target) ) = destination {
226
232
fx. llbb ( target)
@@ -659,6 +665,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
659
665
unwind,
660
666
& [ ] ,
661
667
Some ( drop_instance) ,
668
+ false ,
662
669
!maybe_null && mergeable_succ,
663
670
)
664
671
}
@@ -747,8 +754,19 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
747
754
let ( fn_abi, llfn, instance) = common:: build_langcall ( bx, span, lang_item) ;
748
755
749
756
// 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 ) ;
757
+ let merging_succ = helper. do_call (
758
+ self ,
759
+ bx,
760
+ fn_abi,
761
+ llfn,
762
+ & args,
763
+ None ,
764
+ unwind,
765
+ & [ ] ,
766
+ Some ( instance) ,
767
+ false ,
768
+ false ,
769
+ ) ;
752
770
assert_eq ! ( merging_succ, MergingSucc :: False ) ;
753
771
MergingSucc :: False
754
772
}
@@ -778,6 +796,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
778
796
& [ ] ,
779
797
Some ( instance) ,
780
798
false ,
799
+ false ,
781
800
) ;
782
801
assert_eq ! ( merging_succ, MergingSucc :: False ) ;
783
802
}
@@ -845,6 +864,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
845
864
unwind,
846
865
& [ ] ,
847
866
Some ( instance) ,
867
+ false ,
848
868
mergeable_succ,
849
869
) )
850
870
}
@@ -860,6 +880,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
860
880
target : Option < mir:: BasicBlock > ,
861
881
unwind : mir:: UnwindAction ,
862
882
fn_span : Span ,
883
+ tail : bool ,
863
884
mergeable_succ : bool ,
864
885
) -> MergingSucc {
865
886
let source_info = mir:: SourceInfo { span : fn_span, ..terminator. source_info } ;
@@ -1003,8 +1024,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
1003
1024
// We still need to call `make_return_dest` even if there's no `target`, since
1004
1025
// `fn_abi.ret` could be `PassMode::Indirect`, even if it is uninhabited,
1005
1026
// 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) ) ;
1027
+ let destination = if !tail {
1028
+ let return_dest = self . make_return_dest ( bx, destination, & fn_abi. ret , & mut llargs) ;
1029
+ target. map ( |target| ( return_dest, target) )
1030
+ } else {
1031
+ None
1032
+ } ;
1008
1033
1009
1034
// Split the rust-call tupled arguments off.
1010
1035
let ( first_args, untuple) = if sig. abi ( ) == ExternAbi :: RustCall
@@ -1020,6 +1045,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
1020
1045
// to generate `lifetime_end` when the call returns.
1021
1046
let mut lifetime_ends_after_call: Vec < ( Bx :: Value , Size ) > = Vec :: new ( ) ;
1022
1047
' make_args: for ( i, arg) in first_args. iter ( ) . enumerate ( ) {
1048
+ if tail && matches ! ( fn_abi. args[ i] . mode, PassMode :: Indirect { .. } ) {
1049
+ span_bug ! (
1050
+ fn_span,
1051
+ "arguments using PassMode::Indirect are currently not supported for tail calls"
1052
+ ) ;
1053
+ }
1054
+
1023
1055
let mut op = self . codegen_operand ( bx, & arg. node ) ;
1024
1056
1025
1057
if let ( 0 , Some ( ty:: InstanceKind :: Virtual ( _, idx) ) ) = ( i, instance. map ( |i| i. def ) ) {
@@ -1147,6 +1179,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
1147
1179
unwind,
1148
1180
& lifetime_ends_after_call,
1149
1181
instance,
1182
+ tail,
1150
1183
mergeable_succ,
1151
1184
)
1152
1185
}
@@ -1388,15 +1421,23 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
1388
1421
target,
1389
1422
unwind,
1390
1423
fn_span,
1424
+ false ,
1391
1425
mergeable_succ ( ) ,
1392
1426
) ,
1393
- mir:: TerminatorKind :: TailCall { .. } => {
1394
- // FIXME(explicit_tail_calls): implement tail calls in ssa backend
1395
- span_bug ! (
1396
- terminator. source_info. span,
1397
- "`TailCall` terminator is not yet supported by `rustc_codegen_ssa`"
1398
- )
1399
- }
1427
+ mir:: TerminatorKind :: TailCall { ref func, ref args, fn_span } => self
1428
+ . codegen_call_terminator (
1429
+ helper,
1430
+ bx,
1431
+ terminator,
1432
+ func,
1433
+ args,
1434
+ mir:: Place :: from ( mir:: RETURN_PLACE ) ,
1435
+ None ,
1436
+ mir:: UnwindAction :: Unreachable ,
1437
+ fn_span,
1438
+ true ,
1439
+ mergeable_succ ( ) ,
1440
+ ) ,
1400
1441
mir:: TerminatorKind :: CoroutineDrop | mir:: TerminatorKind :: Yield { .. } => {
1401
1442
bug ! ( "coroutine ops in codegen" )
1402
1443
}
0 commit comments