Rollup merge of #144936 - rcvalle:rust-cfi-fix-144641, r=lcnr

CFI: Fix types that implement Fn, FnMut, or FnOnce

When looking for instances which could either be dynamically called through a vtable or through a concrete trait method, we missed `FnPtrShim`, instead only looking at `Item` and closure-likes. Fixes rust-lang/rust#144641.

cc ```@1c3t3a``` ```@Jakob-Koschel```
This commit is contained in:
Stuart Cook
2025-10-28 20:39:32 +11:00
committed by GitHub
3 changed files with 93 additions and 5 deletions

View File

@@ -10,9 +10,8 @@ use rustc_hir as hir;
use rustc_hir::LangItem;
use rustc_middle::bug;
use rustc_middle::ty::{
self, AssocContainer, ExistentialPredicateStableCmpExt as _, Instance, InstanceKind, IntTy,
List, TraitRef, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
UintTy,
self, AssocContainer, ExistentialPredicateStableCmpExt as _, Instance, IntTy, List, TraitRef,
Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, UintTy,
};
use rustc_span::def_id::DefId;
use rustc_span::{DUMMY_SP, sym};
@@ -459,6 +458,30 @@ pub(crate) fn transform_instance<'tcx>(
instance
}
fn default_or_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Option<DefId> {
match instance.def {
ty::InstanceKind::Item(def_id) | ty::InstanceKind::FnPtrShim(def_id, _) => {
tcx.opt_associated_item(def_id).map(|item| item.def_id)
}
_ => None,
}
}
/// Determines if an instance represents a trait method implementation and returns the necessary
/// information for type erasure.
///
/// This function handles two main cases:
///
/// * **Implementation in an `impl` block**: When the instance represents a concrete implementation
/// of a trait method in an `impl` block, it extracts the trait reference, method ID, and trait
/// ID from the implementation. The method ID is obtained from the `trait_item_def_id` field of
/// the associated item, which points to the original trait method definition.
///
/// * **Provided method in a `trait` block or synthetic `shim`**: When the instance represents a
/// default implementation provided in the trait definition itself or a synthetic shim, it uses
/// the instance's own `def_id` as the method ID and determines the trait ID from the associated
/// item.
///
fn implemented_method<'tcx>(
tcx: TyCtxt<'tcx>,
instance: Instance<'tcx>,
@@ -476,10 +499,11 @@ fn implemented_method<'tcx>(
trait_id = trait_ref.skip_binder().def_id;
impl_id
} else if let AssocContainer::Trait = assoc.container
&& let InstanceKind::Item(def_id) = instance.def
&& let Some(trait_method_def_id) = default_or_shim(tcx, instance)
{
// Provided method in a `trait` block or a synthetic `shim`
trait_method = assoc;
method_id = def_id;
method_id = trait_method_def_id;
trait_id = tcx.parent(method_id);
trait_ref = ty::EarlyBinder::bind(TraitRef::from_assoc(tcx, trait_id, instance.args));
trait_id