Skip to content

Commit 04accf1

Browse files
committed
add a builtin FnPtr trait
1 parent ed4dd0c commit 04accf1

File tree

17 files changed

+163
-13
lines changed

17 files changed

+163
-13
lines changed

compiler/rustc_const_eval/src/interpret/terminator.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
370370
| ty::InstanceDef::FnPtrShim(..)
371371
| ty::InstanceDef::DropGlue(..)
372372
| ty::InstanceDef::CloneShim(..)
373+
| ty::InstanceDef::FnPtrAddrShim(..)
373374
| ty::InstanceDef::Item(_) => {
374375
// We need MIR for this fn
375376
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
@@ -185,6 +185,9 @@ language_item_table! {
185185

186186
Freeze, sym::freeze, freeze_trait, Target::Trait, GenericRequirement::Exact(0);
187187

188+
FnPtrTrait, sym::fn_ptr_trait, fn_ptr_trait, Target::Trait, GenericRequirement::Exact(0);
189+
FnPtrAddr, sym::fn_ptr_addr, fn_ptr_addr, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
190+
188191
Drop, sym::drop, drop_trait, Target::Trait, GenericRequirement::None;
189192
Destruct, sym::destruct, destruct_trait, Target::Trait, GenericRequirement::None;
190193

compiler/rustc_middle/src/mir/mono.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,8 @@ impl<'tcx> CodegenUnit<'tcx> {
369369
| InstanceDef::Virtual(..)
370370
| InstanceDef::ClosureOnceShim { .. }
371371
| InstanceDef::DropGlue(..)
372-
| InstanceDef::CloneShim(..) => None,
372+
| InstanceDef::CloneShim(..)
373+
| InstanceDef::FnPtrAddrShim(..) => None,
373374
}
374375
}
375376
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
@@ -402,7 +402,8 @@ macro_rules! make_mir_visitor {
402402

403403
ty::InstanceDef::FnPtrShim(_def_id, ty) |
404404
ty::InstanceDef::DropGlue(_def_id, Some(ty)) |
405-
ty::InstanceDef::CloneShim(_def_id, ty) => {
405+
ty::InstanceDef::CloneShim(_def_id, ty) |
406+
ty::InstanceDef::FnPtrAddrShim(_def_id, ty) => {
406407
// FIXME(eddyb) use a better `TyContext` here.
407408
self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
408409
}

compiler/rustc_middle/src/ty/instance.rs

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

102109
impl<'tcx> Instance<'tcx> {
@@ -152,7 +159,8 @@ impl<'tcx> InstanceDef<'tcx> {
152159
| InstanceDef::Intrinsic(def_id)
153160
| InstanceDef::ClosureOnceShim { call_once: def_id, track_caller: _ }
154161
| InstanceDef::DropGlue(def_id, _)
155-
| InstanceDef::CloneShim(def_id, _) => def_id,
162+
| InstanceDef::CloneShim(def_id, _)
163+
| InstanceDef::FnPtrAddrShim(def_id, _) => def_id,
156164
}
157165
}
158166

@@ -168,7 +176,8 @@ impl<'tcx> InstanceDef<'tcx> {
168176
| InstanceDef::Intrinsic(..)
169177
| InstanceDef::ClosureOnceShim { .. }
170178
| InstanceDef::DropGlue(..)
171-
| InstanceDef::CloneShim(..) => None,
179+
| InstanceDef::CloneShim(..)
180+
| InstanceDef::FnPtrAddrShim(..) => None,
172181
}
173182
}
174183

@@ -183,7 +192,8 @@ impl<'tcx> InstanceDef<'tcx> {
183192
| InstanceDef::Intrinsic(def_id)
184193
| InstanceDef::ClosureOnceShim { call_once: def_id, track_caller: _ }
185194
| InstanceDef::DropGlue(def_id, _)
186-
| InstanceDef::CloneShim(def_id, _) => ty::WithOptConstParam::unknown(def_id),
195+
| InstanceDef::CloneShim(def_id, _)
196+
| InstanceDef::FnPtrAddrShim(def_id, _) => ty::WithOptConstParam::unknown(def_id),
187197
}
188198
}
189199

@@ -265,6 +275,7 @@ impl<'tcx> InstanceDef<'tcx> {
265275
pub fn has_polymorphic_mir_body(&self) -> bool {
266276
match *self {
267277
InstanceDef::CloneShim(..)
278+
| InstanceDef::FnPtrAddrShim(..)
268279
| InstanceDef::FnPtrShim(..)
269280
| InstanceDef::DropGlue(_, Some(_)) => false,
270281
InstanceDef::ClosureOnceShim { .. }
@@ -299,6 +310,7 @@ impl<'tcx> fmt::Display for Instance<'tcx> {
299310
InstanceDef::DropGlue(_, None) => write!(f, " - shim(None)"),
300311
InstanceDef::DropGlue(_, Some(ty)) => write!(f, " - shim(Some({}))", ty),
301312
InstanceDef::CloneShim(_, ty) => write!(f, " - shim({})", ty),
313+
InstanceDef::FnPtrAddrShim(_, ty) => write!(f, " - shim({})", ty),
302314
}
303315
}
304316
}

compiler/rustc_middle/src/ty/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2148,7 +2148,8 @@ impl<'tcx> TyCtxt<'tcx> {
21482148
| ty::InstanceDef::Virtual(..)
21492149
| ty::InstanceDef::ClosureOnceShim { .. }
21502150
| ty::InstanceDef::DropGlue(..)
2151-
| ty::InstanceDef::CloneShim(..) => self.mir_shims(instance),
2151+
| ty::InstanceDef::CloneShim(..)
2152+
| ty::InstanceDef::FnPtrAddrShim(..) => self.mir_shims(instance),
21522153
}
21532154
}
21542155

compiler/rustc_middle/src/ty/structural_impls.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,9 @@ impl<'a, 'tcx> Lift<'tcx> for ty::InstanceDef<'a> {
640640
ty::InstanceDef::CloneShim(def_id, ty) => {
641641
Some(ty::InstanceDef::CloneShim(def_id, tcx.lift(ty)?))
642642
}
643+
ty::InstanceDef::FnPtrAddrShim(def_id, ty) => {
644+
Some(ty::InstanceDef::FnPtrAddrShim(def_id, tcx.lift(ty)?))
645+
}
643646
}
644647
}
645648
}
@@ -943,6 +946,9 @@ impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> {
943946
CloneShim(did, ty) => {
944947
CloneShim(did.try_fold_with(folder)?, ty.try_fold_with(folder)?)
945948
}
949+
FnPtrAddrShim(did, ty) => {
950+
FnPtrAddrShim(did.try_fold_with(folder)?, ty.try_fold_with(folder)?)
951+
}
946952
},
947953
})
948954
}
@@ -957,7 +963,7 @@ impl<'tcx> TypeVisitable<'tcx> for ty::instance::Instance<'tcx> {
957963
VTableShim(did) | ReifyShim(did) | Intrinsic(did) | Virtual(did, _) => {
958964
did.visit_with(visitor)
959965
}
960-
FnPtrShim(did, ty) | CloneShim(did, ty) => {
966+
FnPtrShim(did, ty) | CloneShim(did, ty) | FnPtrAddrShim(did, ty) => {
961967
did.visit_with(visitor)?;
962968
ty.visit_with(visitor)
963969
}

compiler/rustc_mir_transform/src/inline.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,8 @@ impl<'tcx> Inliner<'tcx> {
251251
| InstanceDef::FnPtrShim(..)
252252
| InstanceDef::ClosureOnceShim { .. }
253253
| InstanceDef::DropGlue(..)
254-
| InstanceDef::CloneShim(..) => return Ok(()),
254+
| InstanceDef::CloneShim(..)
255+
| InstanceDef::FnPtrAddrShim(..) => return Ok(()),
255256
}
256257

257258
if self.tcx.is_constructor(callee_def_id) {

compiler/rustc_mir_transform/src/inline/cycle.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,14 @@ pub(crate) fn mir_callgraph_reachable<'tcx>(
7979
// These have MIR and if that MIR is inlined, substituted and then inlining is run
8080
// again, a function item can end up getting inlined. Thus we'll be able to cause
8181
// a cycle that way
82+
//
83+
// FIXME: `FnPtrAddrShim` should not be able to cause recursion.
8284
InstanceDef::VTableShim(_)
8385
| InstanceDef::ReifyShim(_)
8486
| InstanceDef::FnPtrShim(..)
8587
| InstanceDef::ClosureOnceShim { .. }
86-
| InstanceDef::CloneShim(..) => {}
88+
| InstanceDef::CloneShim(..)
89+
| InstanceDef::FnPtrAddrShim(..) => {}
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: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
7878
build_drop_shim(tcx, def_id, ty)
7979
}
8080
ty::InstanceDef::CloneShim(def_id, ty) => build_clone_shim(tcx, def_id, ty),
81+
ty::InstanceDef::FnPtrAddrShim(def_id, ty) => build_fn_ptr_addr_shim(tcx, def_id, ty),
8182
ty::InstanceDef::Virtual(..) => {
8283
bug!("InstanceDef::Virtual ({:?}) is for direct calls only", instance)
8384
}
@@ -788,3 +789,38 @@ pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> {
788789

789790
body
790791
}
792+
793+
/// ```ignore (pseudo-impl)
794+
/// impl FnPtr for fn(u32) {
795+
/// fn addr(self) -> usize {
796+
/// self as usize
797+
/// }
798+
/// }
799+
/// ```
800+
fn build_fn_ptr_addr_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Body<'tcx> {
801+
assert!(matches!(self_ty.kind(), ty::FnPtr(..)), "expected fn ptr, found {self_ty}");
802+
let span = tcx.def_span(def_id);
803+
let Some(sig) = tcx.bound_fn_sig(def_id).subst(tcx, &[self_ty.into()]).no_bound_vars() else {
804+
span_bug!(span, "FnPtr::addr with bound vars for `{self_ty}`");
805+
};
806+
let locals = local_decls_for_sig(&sig, span);
807+
808+
let source_info = SourceInfo::outermost(span);
809+
let rvalue = Rvalue::Cast(
810+
CastKind::PointerExposeAddress,
811+
Operand::Move(Place::from(Local::new(1))),
812+
tcx.types.usize,
813+
);
814+
let stmt = Statement {
815+
source_info,
816+
kind: StatementKind::Assign(Box::new((Place::return_place(), rvalue))),
817+
};
818+
let statements = vec![stmt];
819+
let start_block = BasicBlockData {
820+
statements,
821+
terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }),
822+
is_cleanup: false,
823+
};
824+
let source = MirSource::from_instance(ty::InstanceDef::FnPtrAddrShim(def_id, self_ty));
825+
new_body(source, IndexVec::from_elem_n(start_block, 1), locals, sig.inputs().len(), span)
826+
}

0 commit comments

Comments
 (0)