1
Fork 0

Auto merge of #137907 - compiler-errors:inline-fnonce, r=saethlin

Inline `FnOnce`/`FnMut`/`Fn` shims once again

This PR fixes the argument checking for `extern "rust-call"` ABI functions with a spread arg, which do no expect their arguments to be exploded from a tuple like closures do.

Secondly, it removes the hack that prevented them from being inlined. This results in more work done by the compiler, but it does end up allowing us to inline functions we didn't before.

Fixes #137901
This commit is contained in:
bors 2025-03-05 18:39:17 +00:00
commit 30f168ef81
23 changed files with 397 additions and 123 deletions

View file

@ -606,14 +606,14 @@ fn try_inlining<'tcx, I: Inliner<'tcx>>(
ty::EarlyBinder::bind(callee_body.clone()),
) else {
debug!("failed to normalize callee body");
return Err("implementation limitation");
return Err("implementation limitation -- could not normalize callee body");
};
// Normally, this shouldn't be required, but trait normalization failure can create a
// validation ICE.
if !validate_types(tcx, inliner.typing_env(), &callee_body, &caller_body).is_empty() {
debug!("failed to validate callee body");
return Err("implementation limitation");
return Err("implementation limitation -- callee body failed validation");
}
// Check call signature compatibility.
@ -622,17 +622,9 @@ fn try_inlining<'tcx, I: Inliner<'tcx>>(
let output_type = callee_body.return_ty();
if !util::sub_types(tcx, inliner.typing_env(), output_type, destination_ty) {
trace!(?output_type, ?destination_ty);
debug!("failed to normalize return type");
return Err("implementation limitation");
return Err("implementation limitation -- return type mismatch");
}
if callsite.fn_sig.abi() == ExternAbi::RustCall {
// FIXME: Don't inline user-written `extern "rust-call"` functions,
// since this is generally perf-negative on rustc, and we hope that
// LLVM will inline these functions instead.
if callee_body.spread_arg.is_some() {
return Err("user-written rust-call functions");
}
let (self_arg, arg_tuple) = match &args[..] {
[arg_tuple] => (None, arg_tuple),
[self_arg, arg_tuple] => (Some(self_arg), arg_tuple),
@ -642,12 +634,17 @@ fn try_inlining<'tcx, I: Inliner<'tcx>>(
let self_arg_ty = self_arg.map(|self_arg| self_arg.node.ty(&caller_body.local_decls, tcx));
let arg_tuple_ty = arg_tuple.node.ty(&caller_body.local_decls, tcx);
let ty::Tuple(arg_tuple_tys) = *arg_tuple_ty.kind() else {
bug!("Closure arguments are not passed as a tuple");
let arg_tys = if callee_body.spread_arg.is_some() {
std::slice::from_ref(&arg_tuple_ty)
} else {
let ty::Tuple(arg_tuple_tys) = *arg_tuple_ty.kind() else {
bug!("Closure arguments are not passed as a tuple");
};
arg_tuple_tys.as_slice()
};
for (arg_ty, input) in
self_arg_ty.into_iter().chain(arg_tuple_tys).zip(callee_body.args_iter())
self_arg_ty.into_iter().chain(arg_tys.iter().copied()).zip(callee_body.args_iter())
{
let input_type = callee_body.local_decls[input].ty;
if !util::sub_types(tcx, inliner.typing_env(), input_type, arg_ty) {
@ -663,7 +660,7 @@ fn try_inlining<'tcx, I: Inliner<'tcx>>(
if !util::sub_types(tcx, inliner.typing_env(), input_type, arg_ty) {
trace!(?arg_ty, ?input_type);
debug!("failed to normalize argument type");
return Err("implementation limitation");
return Err("implementation limitation -- arg mismatch");
}
}
}
@ -693,13 +690,13 @@ fn check_mir_is_available<'tcx, I: Inliner<'tcx>>(
// won't cause cycles on this.
if !inliner.tcx().is_mir_available(callee_def_id) {
debug!("item MIR unavailable");
return Err("implementation limitation");
return Err("implementation limitation -- MIR unavailable");
}
}
// These have no own callable MIR.
InstanceKind::Intrinsic(_) | InstanceKind::Virtual(..) => {
debug!("instance without MIR (intrinsic / virtual)");
return Err("implementation limitation");
return Err("implementation limitation -- cannot inline intrinsic");
}
// FIXME(#127030): `ConstParamHasTy` has bad interactions with
@ -709,7 +706,7 @@ fn check_mir_is_available<'tcx, I: Inliner<'tcx>>(
// substituted.
InstanceKind::DropGlue(_, Some(ty)) if ty.has_type_flags(TypeFlags::HAS_CT_PARAM) => {
debug!("still needs substitution");
return Err("implementation limitation");
return Err("implementation limitation -- HACK for dropping polymorphic type");
}
// This cannot result in an immediate cycle since the callee MIR is a shim, which does
@ -1060,8 +1057,7 @@ fn make_call_args<'tcx, I: Inliner<'tcx>>(
closure_ref_arg.chain(tuple_tmp_args).collect()
} else {
// FIXME(edition_2024): switch back to a normal method call.
<_>::into_iter(args)
args.into_iter()
.map(|a| create_temp_if_necessary(inliner, a.node, callsite, caller_body, return_block))
.collect()
}