Skip to content

Commit bf57e8a

Browse files
committed
Auto merge of rust-lang#108080 - oli-obk:FnPtr-trait, r=lcnr
Add a builtin `FnPtr` trait that is implemented for all function pointers r? `@ghost` Rebased version of rust-lang#99531 (plus adjustments mentioned in the PR). If perf is happy with this version, I would like to land it, even if the diagnostics fix in 9df8e1befb5031a5bf9d8dfe25170620642d3c59 only works for `FnPtr` specifically, and does not generally improve blanket impls.
2 parents 6066037 + 5ae6caa commit bf57e8a

File tree

23 files changed

+476
-180
lines changed

23 files changed

+476
-180
lines changed

compiler/rustc_const_eval/src/interpret/terminator.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
382382
| ty::InstanceDef::FnPtrShim(..)
383383
| ty::InstanceDef::DropGlue(..)
384384
| ty::InstanceDef::CloneShim(..)
385+
| ty::InstanceDef::FnPtrAddrShim(..)
385386
| ty::InstanceDef::Item(_) => {
386387
// We need MIR for this fn
387388
let Some((body, instance)) =

compiler/rustc_hir/src/lang_items.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,9 @@ language_item_table! {
166166

167167
Freeze, sym::freeze, freeze_trait, Target::Trait, GenericRequirement::Exact(0);
168168

169+
FnPtrTrait, sym::fn_ptr_trait, fn_ptr_trait, Target::Trait, GenericRequirement::Exact(0);
170+
FnPtrAddr, sym::fn_ptr_addr, fn_ptr_addr, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
171+
169172
Drop, sym::drop, drop_trait, Target::Trait, GenericRequirement::None;
170173
Destruct, sym::destruct, destruct_trait, Target::Trait, GenericRequirement::None;
171174

compiler/rustc_middle/src/mir/mono.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,8 @@ impl<'tcx> CodegenUnit<'tcx> {
381381
| InstanceDef::Virtual(..)
382382
| InstanceDef::ClosureOnceShim { .. }
383383
| InstanceDef::DropGlue(..)
384-
| InstanceDef::CloneShim(..) => None,
384+
| InstanceDef::CloneShim(..)
385+
| InstanceDef::FnPtrAddrShim(..) => None,
385386
}
386387
}
387388
MonoItem::Static(def_id) => def_id.as_local().map(Idx::index),

compiler/rustc_middle/src/mir/visit.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,8 @@ macro_rules! make_mir_visitor {
340340

341341
ty::InstanceDef::FnPtrShim(_def_id, ty) |
342342
ty::InstanceDef::DropGlue(_def_id, Some(ty)) |
343-
ty::InstanceDef::CloneShim(_def_id, ty) => {
343+
ty::InstanceDef::CloneShim(_def_id, ty) |
344+
ty::InstanceDef::FnPtrAddrShim(_def_id, ty) => {
344345
// FIXME(eddyb) use a better `TyContext` here.
345346
self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
346347
}

compiler/rustc_middle/src/ty/instance.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,13 @@ pub enum InstanceDef<'tcx> {
9696
///
9797
/// The `DefId` is for `Clone::clone`, the `Ty` is the type `T` with the builtin `Clone` impl.
9898
CloneShim(DefId, Ty<'tcx>),
99+
100+
/// Compiler-generated `<T as FnPtr>::addr` implementation.
101+
///
102+
/// Automatically generated for all potentially higher-ranked `fn(I) -> R` types.
103+
///
104+
/// The `DefId` is for `FnPtr::addr`, the `Ty` is the type `T`.
105+
FnPtrAddrShim(DefId, Ty<'tcx>),
99106
}
100107

101108
impl<'tcx> Instance<'tcx> {
@@ -151,7 +158,8 @@ impl<'tcx> InstanceDef<'tcx> {
151158
| InstanceDef::Intrinsic(def_id)
152159
| InstanceDef::ClosureOnceShim { call_once: def_id, track_caller: _ }
153160
| InstanceDef::DropGlue(def_id, _)
154-
| InstanceDef::CloneShim(def_id, _) => def_id,
161+
| InstanceDef::CloneShim(def_id, _)
162+
| InstanceDef::FnPtrAddrShim(def_id, _) => def_id,
155163
}
156164
}
157165

@@ -167,7 +175,8 @@ impl<'tcx> InstanceDef<'tcx> {
167175
| InstanceDef::Intrinsic(..)
168176
| InstanceDef::ClosureOnceShim { .. }
169177
| InstanceDef::DropGlue(..)
170-
| InstanceDef::CloneShim(..) => None,
178+
| InstanceDef::CloneShim(..)
179+
| InstanceDef::FnPtrAddrShim(..) => None,
171180
}
172181
}
173182

@@ -182,7 +191,8 @@ impl<'tcx> InstanceDef<'tcx> {
182191
| InstanceDef::Intrinsic(def_id)
183192
| InstanceDef::ClosureOnceShim { call_once: def_id, track_caller: _ }
184193
| InstanceDef::DropGlue(def_id, _)
185-
| InstanceDef::CloneShim(def_id, _) => ty::WithOptConstParam::unknown(def_id),
194+
| InstanceDef::CloneShim(def_id, _)
195+
| InstanceDef::FnPtrAddrShim(def_id, _) => ty::WithOptConstParam::unknown(def_id),
186196
}
187197
}
188198

@@ -268,6 +278,7 @@ impl<'tcx> InstanceDef<'tcx> {
268278
pub fn has_polymorphic_mir_body(&self) -> bool {
269279
match *self {
270280
InstanceDef::CloneShim(..)
281+
| InstanceDef::FnPtrAddrShim(..)
271282
| InstanceDef::FnPtrShim(..)
272283
| InstanceDef::DropGlue(_, Some(_)) => false,
273284
InstanceDef::ClosureOnceShim { .. }
@@ -306,6 +317,7 @@ fn fmt_instance(
306317
InstanceDef::DropGlue(_, None) => write!(f, " - shim(None)"),
307318
InstanceDef::DropGlue(_, Some(ty)) => write!(f, " - shim(Some({}))", ty),
308319
InstanceDef::CloneShim(_, ty) => write!(f, " - shim({})", ty),
320+
InstanceDef::FnPtrAddrShim(_, ty) => write!(f, " - shim({})", ty),
309321
}
310322
}
311323

compiler/rustc_middle/src/ty/mod.rs

Lines changed: 10 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2279,76 +2279,56 @@ impl<'tcx> TyCtxt<'tcx> {
22792279

22802280
/// Returns `true` if the impls are the same polarity and the trait either
22812281
/// has no items or is annotated `#[marker]` and prevents item overrides.
2282+
#[instrument(level = "debug", skip(self), ret)]
22822283
pub fn impls_are_allowed_to_overlap(
22832284
self,
22842285
def_id1: DefId,
22852286
def_id2: DefId,
22862287
) -> Option<ImplOverlapKind> {
2288+
let impl_trait_ref1 = self.impl_trait_ref(def_id1);
2289+
let impl_trait_ref2 = self.impl_trait_ref(def_id2);
22872290
// If either trait impl references an error, they're allowed to overlap,
22882291
// as one of them essentially doesn't exist.
2289-
if self.impl_trait_ref(def_id1).map_or(false, |tr| tr.subst_identity().references_error())
2290-
|| self
2291-
.impl_trait_ref(def_id2)
2292-
.map_or(false, |tr| tr.subst_identity().references_error())
2292+
if impl_trait_ref1.map_or(false, |tr| tr.subst_identity().references_error())
2293+
|| impl_trait_ref2.map_or(false, |tr| tr.subst_identity().references_error())
22932294
{
22942295
return Some(ImplOverlapKind::Permitted { marker: false });
22952296
}
22962297

22972298
match (self.impl_polarity(def_id1), self.impl_polarity(def_id2)) {
22982299
(ImplPolarity::Reservation, _) | (_, ImplPolarity::Reservation) => {
22992300
// `#[rustc_reservation_impl]` impls don't overlap with anything
2300-
debug!(
2301-
"impls_are_allowed_to_overlap({:?}, {:?}) = Some(Permitted) (reservations)",
2302-
def_id1, def_id2
2303-
);
23042301
return Some(ImplOverlapKind::Permitted { marker: false });
23052302
}
23062303
(ImplPolarity::Positive, ImplPolarity::Negative)
23072304
| (ImplPolarity::Negative, ImplPolarity::Positive) => {
23082305
// `impl AutoTrait for Type` + `impl !AutoTrait for Type`
2309-
debug!(
2310-
"impls_are_allowed_to_overlap({:?}, {:?}) - None (differing polarities)",
2311-
def_id1, def_id2
2312-
);
23132306
return None;
23142307
}
23152308
(ImplPolarity::Positive, ImplPolarity::Positive)
23162309
| (ImplPolarity::Negative, ImplPolarity::Negative) => {}
23172310
};
23182311

23192312
let is_marker_overlap = {
2320-
let is_marker_impl = |def_id: DefId| -> bool {
2321-
let trait_ref = self.impl_trait_ref(def_id);
2313+
let is_marker_impl = |trait_ref: Option<EarlyBinder<TraitRef<'_>>>| -> bool {
23222314
trait_ref.map_or(false, |tr| self.trait_def(tr.skip_binder().def_id).is_marker)
23232315
};
2324-
is_marker_impl(def_id1) && is_marker_impl(def_id2)
2316+
is_marker_impl(impl_trait_ref1) && is_marker_impl(impl_trait_ref2)
23252317
};
23262318

23272319
if is_marker_overlap {
2328-
debug!(
2329-
"impls_are_allowed_to_overlap({:?}, {:?}) = Some(Permitted) (marker overlap)",
2330-
def_id1, def_id2
2331-
);
23322320
Some(ImplOverlapKind::Permitted { marker: true })
23332321
} else {
23342322
if let Some(self_ty1) = self.issue33140_self_ty(def_id1) {
23352323
if let Some(self_ty2) = self.issue33140_self_ty(def_id2) {
23362324
if self_ty1 == self_ty2 {
2337-
debug!(
2338-
"impls_are_allowed_to_overlap({:?}, {:?}) - issue #33140 HACK",
2339-
def_id1, def_id2
2340-
);
23412325
return Some(ImplOverlapKind::Issue33140);
23422326
} else {
2343-
debug!(
2344-
"impls_are_allowed_to_overlap({:?}, {:?}) - found {:?} != {:?}",
2345-
def_id1, def_id2, self_ty1, self_ty2
2346-
);
2327+
debug!("found {self_ty1:?} != {self_ty2:?}");
23472328
}
23482329
}
23492330
}
23502331

2351-
debug!("impls_are_allowed_to_overlap({:?}, {:?}) = None", def_id1, def_id2);
23522332
None
23532333
}
23542334
}
@@ -2405,7 +2385,8 @@ impl<'tcx> TyCtxt<'tcx> {
24052385
| ty::InstanceDef::Virtual(..)
24062386
| ty::InstanceDef::ClosureOnceShim { .. }
24072387
| ty::InstanceDef::DropGlue(..)
2408-
| ty::InstanceDef::CloneShim(..) => self.mir_shims(instance),
2388+
| ty::InstanceDef::CloneShim(..)
2389+
| ty::InstanceDef::FnPtrAddrShim(..) => self.mir_shims(instance),
24092390
}
24102391
}
24112392

compiler/rustc_mir_transform/src/inline.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,8 @@ impl<'tcx> Inliner<'tcx> {
270270
| InstanceDef::FnPtrShim(..)
271271
| InstanceDef::ClosureOnceShim { .. }
272272
| InstanceDef::DropGlue(..)
273-
| InstanceDef::CloneShim(..) => return Ok(()),
273+
| InstanceDef::CloneShim(..)
274+
| InstanceDef::FnPtrAddrShim(..) => return Ok(()),
274275
}
275276

276277
if self.tcx.is_constructor(callee_def_id) {

compiler/rustc_mir_transform/src/inline/cycle.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ pub(crate) fn mir_callgraph_reachable<'tcx>(
8484
| InstanceDef::FnPtrShim(..)
8585
| InstanceDef::ClosureOnceShim { .. }
8686
| InstanceDef::CloneShim(..) => {}
87+
88+
// This shim does not call any other functions, thus there can be no recursion.
89+
InstanceDef::FnPtrAddrShim(..) => continue,
8790
InstanceDef::DropGlue(..) => {
8891
// FIXME: A not fully substituted drop shim can cause ICEs if one attempts to
8992
// have its MIR built. Likely oli-obk just screwed up the `ParamEnv`s, so this

compiler/rustc_mir_transform/src/shim.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
7777
build_drop_shim(tcx, def_id, ty)
7878
}
7979
ty::InstanceDef::CloneShim(def_id, ty) => build_clone_shim(tcx, def_id, ty),
80+
ty::InstanceDef::FnPtrAddrShim(def_id, ty) => build_fn_ptr_addr_shim(tcx, def_id, ty),
8081
ty::InstanceDef::Virtual(..) => {
8182
bug!("InstanceDef::Virtual ({:?}) is for direct calls only", instance)
8283
}
@@ -861,3 +862,39 @@ pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> {
861862

862863
body
863864
}
865+
866+
/// ```ignore (pseudo-impl)
867+
/// impl FnPtr for fn(u32) {
868+
/// fn addr(self) -> usize {
869+
/// self as usize
870+
/// }
871+
/// }
872+
/// ```
873+
fn build_fn_ptr_addr_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Body<'tcx> {
874+
assert!(matches!(self_ty.kind(), ty::FnPtr(..)), "expected fn ptr, found {self_ty}");
875+
let span = tcx.def_span(def_id);
876+
let Some(sig) = tcx.fn_sig(def_id).subst(tcx, &[self_ty.into()]).no_bound_vars() else {
877+
span_bug!(span, "FnPtr::addr with bound vars for `{self_ty}`");
878+
};
879+
let locals = local_decls_for_sig(&sig, span);
880+
881+
let source_info = SourceInfo::outermost(span);
882+
// FIXME: use `expose_addr` once we figure out whether function pointers have meaningful provenance.
883+
let rvalue = Rvalue::Cast(
884+
CastKind::FnPtrToPtr,
885+
Operand::Move(Place::from(Local::new(1))),
886+
tcx.mk_imm_ptr(tcx.types.unit),
887+
);
888+
let stmt = Statement {
889+
source_info,
890+
kind: StatementKind::Assign(Box::new((Place::return_place(), rvalue))),
891+
};
892+
let statements = vec![stmt];
893+
let start_block = BasicBlockData {
894+
statements,
895+
terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }),
896+
is_cleanup: false,
897+
};
898+
let source = MirSource::from_instance(ty::InstanceDef::FnPtrAddrShim(def_id, self_ty));
899+
new_body(source, IndexVec::from_elem_n(start_block, 1), locals, sig.inputs().len(), span)
900+
}

compiler/rustc_monomorphize/src/collector.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -974,7 +974,8 @@ fn visit_instance_use<'tcx>(
974974
| ty::InstanceDef::ClosureOnceShim { .. }
975975
| ty::InstanceDef::Item(..)
976976
| ty::InstanceDef::FnPtrShim(..)
977-
| ty::InstanceDef::CloneShim(..) => {
977+
| ty::InstanceDef::CloneShim(..)
978+
| ty::InstanceDef::FnPtrAddrShim(..) => {
978979
output.push(create_fn_mono_item(tcx, instance, source));
979980
}
980981
}

0 commit comments

Comments
 (0)