Repository: rust-lang/rust
File: compiler/rustc_codegen_ssa/src/mir/block.rs (Rust)

Code before:
                        span_bug!(fn_span, "can't codegen a virtual call on {:#?}", op);
                    }
                }
            }

            match kind {
                CallKind::Tail => {
                    match fn_abi.args[i].mode {
                        PassMode::Indirect { on_stack: false, .. } => {
                            let Some(tmp) = tail_call_temporaries[i].take() else {
                                span_bug!(
                                    fn_span,
                                    "missing temporary for indirect tail call argument #{i}"
                                )
                            };

                            let local = self.mir.args_iter().nth(i).unwrap();

                            match &self.locals[local] {
                                LocalRef::Place(arg) => {
                                    bx.typed_place_copy(arg.val, tmp.val, fn_abi.args[i].layout);
                                    op.val = Ref(arg.val);
                                }
                                LocalRef::Operand(arg) => {
                                    bx.typed_place_copy(
                                        arg.val.deref(fn_abi.args[i].layout.align.abi),
                                        tmp.val,
                                        fn_abi.args[i].layout,
                                    );
                                    op.val = arg.val;
                                }
                                LocalRef::UnsizedPlace(_) => {
                                    span_bug!(fn_span, "unsized types are not supported")
                                }
                                LocalRef::PendingOperand => {
                                    span_bug!(fn_span, "argument local should not be pending")
                                }
                            };

                            bx.lifetime_end(tmp.val.llval, tmp.layout.size);
                        }
                        PassMode::Indirect { on_stack: true, .. } => {
                            // FIXME: some LLVM backends (notably x86) do not correctly pass byval
                            // arguments to tail calls (as of LLVM 21). See also:
                            //
                            // - https://github.com/rust-lang/rust/pull/144232#discussion_r2218543841
                            // - https://github.com/rust-lang/rust/issues/144855
                            span_bug!(
                                fn_span,
                                "arguments using PassMode::Indirect {{ on_stack: true, .. }} are currently not supported for tail calls"
                            )

Review comment (bug):
This shouldn't be a deref. `arg.val` is not a pointer to the argument value, but an operand representing the value itself. Rather I think it is always a `OperandValue::Ref(place)` where `place` is the location that the argument is stored at. `arg.val.deref()` would incorrectly treat the argument as a pointer itself. Would you mind adding a test for tail calling with a u128 argument on Windows?

Code after:
                            op.layout.ty,
                            fn_abi,
                        ));
                        llargs.push(data_ptr);
                        continue;
                    }
                    _ => {
                        span_bug!(fn_span, "can't codegen a virtual call on {:#?}", op);
                    }
                }
            }

            match kind {
                CallKind::Normal => {
                    // The callee needs to own the argument memory if we pass it
                    // by-ref, so make a local copy of non-immediate constants.
                    if let &mir::Operand::Copy(_) | &mir::Operand::Constant(_) = &arg.node
                        && let Ref(PlaceValue { llextra: None, .. }) = op.val
                    {
                        let tmp = PlaceRef::alloca(bx, op.layout);
                        bx.lifetime_start(tmp.val.llval, tmp.layout.size);
                        op.store_with_annotation(bx, tmp);
                        op.val = Ref(tmp.val);
                        lifetime_ends_after_call.push((tmp.val.llval, tmp.layout.size));
                    }
                }
                CallKind::Tail => {
                    match fn_abi.args[i].mode {
                        PassMode::Indirect { on_stack: false, .. } => {
                            let Some(tmp) = tail_call_temporaries[i].take() else {
                                span_bug!(
                                    fn_span,
                                    "missing temporary for indirect tail call argument #{i}"
                                )
                            };

                            let local = self.mir.args_iter().nth(i).unwrap();

                            match &self.locals[local] {
                                LocalRef::Place(arg) => {
                                    bx.typed_place_copy(arg.val, tmp.val, fn_abi.args[i].layout);
                                    op.val = Ref(arg.val);
                                }
                                LocalRef::Operand(arg) => {
                                    let Ref(place_value) = arg.val else {
                                        bug!("only `Ref` should use `PassMode::Indirect`");
                                    };
                                    bx.typed_place_copy(
                                        place_value,
                                        tmp.val,
                                        fn_abi.args[i].layout,