@@ -342,6 +342,99 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
342342
343343/// Codegen implementations for some terminator variants.
344344impl < ' a , ' tcx , Bx : BuilderMethods < ' a , ' tcx > > FunctionCx < ' a , ' tcx , Bx > {
345+ #[ allow( dead_code) ]
346+ fn codegen_tail_call_terminator (
347+ & mut self ,
348+ bx : & mut Bx ,
349+ func : & mir:: Operand < ' tcx > ,
350+ args : & [ Spanned < mir:: Operand < ' tcx > > ] ,
351+ fn_span : Span ,
352+ ) {
353+ // We don't need source_info as we already have fn_span for diagnostics
354+ let func = self . codegen_operand ( bx, func) ;
355+ let fn_ty = func. layout . ty ;
356+
357+ // Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar.
358+ let ( fn_ptr, fn_abi, instance) = match * fn_ty. kind ( ) {
359+ ty:: FnDef ( def_id, substs) => {
360+ let instance = ty:: Instance :: expect_resolve (
361+ bx. tcx ( ) ,
362+ bx. typing_env ( ) ,
363+ def_id,
364+ substs,
365+ fn_span,
366+ ) ;
367+ let fn_ptr = bx. get_fn_addr ( instance) ;
368+ let fn_abi = bx. fn_abi_of_instance ( instance, ty:: List :: empty ( ) ) ;
369+ ( fn_ptr, fn_abi, Some ( instance) )
370+ }
371+ ty:: FnPtr ( ..) => {
372+ let sig = fn_ty. fn_sig ( bx. tcx ( ) ) ;
373+ let extra_args = bx. tcx ( ) . mk_type_list ( & [ ] ) ;
374+ let fn_ptr = func. immediate ( ) ;
375+ let fn_abi = bx. fn_abi_of_fn_ptr ( sig, extra_args) ;
376+ ( fn_ptr, fn_abi, None )
377+ }
378+ _ => bug ! ( "{} is not callable" , func. layout. ty) ,
379+ } ;
380+
381+ let mut llargs = Vec :: with_capacity ( args. len ( ) ) ;
382+ let mut lifetime_ends_after_call = Vec :: new ( ) ;
383+
384+ // Process arguments
385+ for arg in args {
386+ let op = self . codegen_operand ( bx, & arg. node ) ;
387+ let arg_idx = llargs. len ( ) ;
388+
389+ if arg_idx < fn_abi. args . len ( ) {
390+ self . codegen_argument (
391+ bx,
392+ op,
393+ & mut llargs,
394+ & fn_abi. args [ arg_idx] ,
395+ & mut lifetime_ends_after_call,
396+ ) ;
397+ } else {
398+ // This can happen in case of C-variadic functions
399+ let is_immediate = match op. val {
400+ Immediate ( _) => true ,
401+ _ => false ,
402+ } ;
403+
404+ if is_immediate {
405+ llargs. push ( op. immediate ( ) ) ;
406+ } else {
407+ let temp = PlaceRef :: alloca ( bx, op. layout ) ;
408+ op. val . store ( bx, temp) ;
409+ llargs. push ( bx. load (
410+ bx. backend_type ( op. layout ) ,
411+ temp. val . llval ,
412+ temp. val . align ,
413+ ) ) ;
414+ }
415+ }
416+ }
417+
418+ // Call the function
419+ let fn_ty = bx. fn_decl_backend_type ( fn_abi) ;
420+ let fn_attrs = if let Some ( instance) = instance
421+ && bx. tcx ( ) . def_kind ( instance. def_id ( ) ) . has_codegen_attrs ( )
422+ {
423+ Some ( bx. tcx ( ) . codegen_fn_attrs ( instance. def_id ( ) ) )
424+ } else {
425+ None
426+ } ;
427+
428+ // Perform the actual function call
429+ let llret = bx. call ( fn_ty, fn_attrs, Some ( fn_abi) , fn_ptr, & llargs, None , instance) ;
430+
431+ // Mark as tail call - this is the critical part
432+ bx. set_tail_call ( llret) ;
433+
434+ // Return the result - musttail requires ret immediately after the call
435+ bx. ret ( llret) ;
436+ }
437+
345438 /// Generates code for a `Resume` terminator.
346439 fn codegen_resume_terminator ( & mut self , helper : TerminatorCodegenHelper < ' tcx > , bx : & mut Bx ) {
347440 if let Some ( funclet) = helper. funclet ( self ) {
0 commit comments