@@ -160,6 +160,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
160160 mut unwind : mir:: UnwindAction ,
161161 lifetime_ends_after_call : & [ ( Bx :: Value , Size ) ] ,
162162 instance : Option < Instance < ' tcx > > ,
163+ tail : bool ,
163164 mergeable_succ : bool ,
164165 ) -> MergingSucc {
165166 let tcx = bx. tcx ( ) ;
@@ -252,8 +253,16 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
252253 }
253254 MergingSucc :: False
254255 } 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+
257266 if fx. mir [ self . bb ] . is_cleanup {
258267 bx. apply_attrs_to_cleanup_callsite ( llret) ;
259268 }
@@ -264,6 +273,12 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
264273 }
265274 fx. store_return ( bx, ret_dest, & fn_abi. ret , llret) ;
266275 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
267282 } else {
268283 bx. unreachable ( ) ;
269284 MergingSucc :: False
@@ -659,6 +674,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
659674 unwind,
660675 & [ ] ,
661676 Some ( drop_instance) ,
677+ false ,
662678 !maybe_null && mergeable_succ,
663679 )
664680 }
@@ -747,8 +763,19 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
747763 let ( fn_abi, llfn, instance) = common:: build_langcall ( bx, span, lang_item) ;
748764
749765 // 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+ ) ;
752779 assert_eq ! ( merging_succ, MergingSucc :: False ) ;
753780 MergingSucc :: False
754781 }
@@ -778,6 +805,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
778805 & [ ] ,
779806 Some ( instance) ,
780807 false ,
808+ false ,
781809 ) ;
782810 assert_eq ! ( merging_succ, MergingSucc :: False ) ;
783811 }
@@ -845,6 +873,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
845873 unwind,
846874 & [ ] ,
847875 Some ( instance) ,
876+ false ,
848877 mergeable_succ,
849878 ) )
850879 }
@@ -860,6 +889,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
860889 target : Option < mir:: BasicBlock > ,
861890 unwind : mir:: UnwindAction ,
862891 fn_span : Span ,
892+ tail : bool ,
863893 mergeable_succ : bool ,
864894 ) -> MergingSucc {
865895 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> {
10031033 // We still need to call `make_return_dest` even if there's no `target`, since
10041034 // `fn_abi.ret` could be `PassMode::Indirect`, even if it is uninhabited,
10051035 // 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+ } ;
10081042
10091043 // Split the rust-call tupled arguments off.
10101044 let ( first_args, untuple) = if sig. abi ( ) == ExternAbi :: RustCall
@@ -1147,106 +1181,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
11471181 unwind,
11481182 & lifetime_ends_after_call,
11491183 instance,
1184+ tail,
11501185 mergeable_succ,
11511186 )
11521187 }
11531188
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-
12501189 fn codegen_asm_terminator (
12511190 & mut self ,
12521191 helper : TerminatorCodegenHelper < ' tcx > ,
@@ -1484,10 +1423,27 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
14841423 target,
14851424 unwind,
14861425 fn_span,
1426+ false ,
14871427 mergeable_succ ( ) ,
14881428 ) ,
14891429 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+ )
14911447 }
14921448 mir:: TerminatorKind :: CoroutineDrop | mir:: TerminatorKind :: Yield { .. } => {
14931449 bug ! ( "coroutine ops in codegen" )
0 commit comments