Skip to content

Commit e4faa20

Browse files
committed
Initial implementation of FnPtr trait
This commit is an initial implementation of the `FnPtr` trait as described in the `fn_static` tracking issue, which consists of moving the internally unstable `core::marker::FnPtr` to `core::ops::FnPtr`, as well as changing the API. Because `NonNull` is used in the new `as_ptr` signature, it was also turned into a proper lang item.
1 parent cb40c25 commit e4faa20

25 files changed

Lines changed: 154 additions & 69 deletions

File tree

compiler/rustc_feature/src/unstable.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,8 @@ declare_features! (
556556
(unstable, fn_align, "1.53.0", Some(82232)),
557557
/// Support delegating implementation of functions to other already implemented functions.
558558
(incomplete, fn_delegation, "1.76.0", Some(118212)),
559+
/// Traits for function pointers and items
560+
(unstable, fn_static, "CURRENT_RUSTC_VERSION", Some(148768)),
559561
/// Allows impls for the Freeze trait.
560562
(internal, freeze_impls, "1.78.0", Some(121675)),
561563
/// Frontmatter `---` blocks for use by external tools.

compiler/rustc_hir/src/lang_items.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,11 +175,13 @@ language_item_table! {
175175
Metadata, sym::metadata_type, metadata_type, Target::AssocTy, GenericRequirement::None;
176176
DynMetadata, sym::dyn_metadata, dyn_metadata, Target::Struct, GenericRequirement::None;
177177

178+
NonNull, sym::non_null, non_null_trait, Target::Struct, GenericRequirement::Exact(1);
179+
178180
Freeze, sym::freeze, freeze_trait, Target::Trait, GenericRequirement::Exact(0);
179181
UnsafeUnpin, sym::unsafe_unpin, unsafe_unpin_trait, Target::Trait, GenericRequirement::Exact(0);
180182

181183
FnPtrTrait, sym::fn_ptr_trait, fn_ptr_trait, Target::Trait, GenericRequirement::Exact(0);
182-
FnPtrAddr, sym::fn_ptr_addr, fn_ptr_addr, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
184+
FnPtrAsPtr, sym::fn_ptr_as_ptr, fn_ptr_as_ptr, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
183185

184186
Drop, sym::drop, drop_trait, Target::Trait, GenericRequirement::None;
185187
Destruct, sym::destruct, destruct_trait, Target::Trait, GenericRequirement::None;
@@ -235,6 +237,7 @@ language_item_table! {
235237
Fn, kw::Fn, fn_trait, Target::Trait, GenericRequirement::Exact(1);
236238
FnMut, sym::fn_mut, fn_mut_trait, Target::Trait, GenericRequirement::Exact(1);
237239
FnOnce, sym::fn_once, fn_once_trait, Target::Trait, GenericRequirement::Exact(1);
240+
FnStatic, sym::fn_static, fn_static_trait, Target::Trait, GenericRequirement::Exact(1);
238241

239242
AsyncFn, sym::async_fn, async_fn_trait, Target::Trait, GenericRequirement::Exact(1);
240243
AsyncFnMut, sym::async_fn_mut, async_fn_mut_trait, Target::Trait, GenericRequirement::Exact(1);

compiler/rustc_hir_analysis/src/check/wfcheck.rs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1894,14 +1894,22 @@ fn check_method_receiver<'tcx>(
18941894
{
18951895
match receiver_validity_err {
18961896
ReceiverValidityError::DoesNotDeref if arbitrary_self_types_level.is_some() => {
1897-
let hint = match receiver_ty
1898-
.builtin_deref(false)
1899-
.unwrap_or(receiver_ty)
1900-
.ty_adt_def()
1901-
.and_then(|adt_def| tcx.get_diagnostic_name(adt_def.did()))
1902-
{
1903-
Some(sym::RcWeak | sym::ArcWeak) => Some(InvalidReceiverTyHint::Weak),
1904-
Some(sym::NonNull) => Some(InvalidReceiverTyHint::NonNull),
1897+
let adt_def =
1898+
receiver_ty.builtin_deref(false).unwrap_or(receiver_ty).ty_adt_def();
1899+
1900+
let hint = match adt_def {
1901+
Some(adt) => {
1902+
if tcx.is_lang_item(adt.did(), LangItem::NonNull) {
1903+
Some(InvalidReceiverTyHint::NonNull)
1904+
} else {
1905+
match tcx.get_diagnostic_name(adt.did()) {
1906+
Some(sym::RcWeak | sym::ArcWeak) => {
1907+
Some(InvalidReceiverTyHint::Weak)
1908+
}
1909+
_ => None,
1910+
}
1911+
}
1912+
}
19051913
_ => None,
19061914
};
19071915

compiler/rustc_lint/src/types.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ fn lint_wide_pointer<'tcx>(
312312
let mut modifiers = String::new();
313313
ty = match ty.kind() {
314314
ty::RawPtr(ty, _) => *ty,
315-
ty::Adt(def, args) if cx.tcx.is_diagnostic_item(sym::NonNull, def.did()) => {
315+
ty::Adt(def, args) if cx.tcx.is_lang_item(def.did(), LangItem::NonNull) => {
316316
modifiers.push_str(".as_ptr()");
317317
args.type_at(0)
318318
}

compiler/rustc_mir_transform/src/shim.rs

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,27 +1077,42 @@ pub(super) fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> {
10771077
/// ```
10781078
fn build_fn_ptr_addr_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Body<'tcx> {
10791079
assert_matches!(self_ty.kind(), ty::FnPtr(..), "expected fn ptr, found {self_ty}");
1080+
10801081
let span = tcx.def_span(def_id);
1082+
let nonnull_did = tcx.require_lang_item(LangItem::NonNull, span);
1083+
let nonnull_ty = tcx
1084+
.type_of(nonnull_did)
1085+
.instantiate(tcx, &[ty::GenericArg::from(tcx.types.unit)])
1086+
.skip_norm_wip();
1087+
10811088
let Some(sig) =
10821089
tcx.fn_sig(def_id).instantiate(tcx, &[self_ty.into()]).skip_norm_wip().no_bound_vars()
10831090
else {
10841091
span_bug!(span, "FnPtr::addr with bound vars for `{self_ty}`");
10851092
};
1086-
let locals = local_decls_for_sig(&sig, span);
1093+
let mut locals = local_decls_for_sig(&sig, span);
10871094

10881095
let source_info = SourceInfo::outermost(span);
1096+
1097+
let mut statements = vec![];
10891098
// FIXME: use `expose_provenance` once we figure out whether function pointers have meaningful
10901099
// provenance.
1091-
let rvalue = Rvalue::Cast(
1092-
CastKind::FnPtrToPtr,
1093-
Operand::Move(Place::from(Local::arg(0))),
1094-
Ty::new_imm_ptr(tcx, tcx.types.unit),
1095-
);
1096-
let stmt = Statement::new(
1100+
let raw_unit_ptr = Ty::new_imm_ptr(tcx, tcx.types.unit);
1101+
let cast_to_raw_rvalue =
1102+
Rvalue::Cast(CastKind::FnPtrToPtr, Operand::Move(Place::from(Local::arg(0))), raw_unit_ptr);
1103+
let raw_ptr = locals.push(LocalDecl::with_source_info(raw_unit_ptr, source_info)).into();
1104+
statements.push(Statement::new(
10971105
source_info,
1098-
StatementKind::Assign(Box::new((Place::return_place(), rvalue))),
1099-
);
1100-
let statements = vec![stmt];
1106+
StatementKind::Assign(Box::new((raw_ptr, cast_to_raw_rvalue))),
1107+
));
1108+
1109+
let transmute_to_nonnull =
1110+
Rvalue::Cast(CastKind::Transmute, Operand::Move(Place::from(raw_ptr)), nonnull_ty);
1111+
statements.push(Statement::new(
1112+
source_info,
1113+
StatementKind::Assign(Box::new((Place::return_place(), transmute_to_nonnull))),
1114+
));
1115+
11011116
let start_block = BasicBlockData::new_stmts(
11021117
statements,
11031118
Some(Terminator { source_info, kind: TerminatorKind::Return }),

compiler/rustc_span/src/symbol.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,6 @@ symbols! {
252252
Mutex,
253253
MutexGuard,
254254
Named,
255-
NonNull,
256255
NonZero,
257256
None,
258257
Normal,
@@ -975,8 +974,9 @@ symbols! {
975974
fn_mut,
976975
fn_once,
977976
fn_once_output,
978-
fn_ptr_addr,
977+
fn_ptr_as_ptr,
979978
fn_ptr_trait,
979+
fn_static,
980980
forbid,
981981
force_target_feature,
982982
forget,
@@ -1398,6 +1398,7 @@ symbols! {
13981398
non_exhaustive_omitted_patterns_lint,
13991399
non_lifetime_binders,
14001400
non_modrs_mods,
1401+
non_null,
14011402
nonblocking,
14021403
none,
14031404
nontemporal_store,

compiler/rustc_ty_utils/src/errors.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,6 @@ pub(crate) enum GenericConstantTooComplexSub {
7171
OperationNotSupported(#[primary_span] Span),
7272
}
7373

74-
#[derive(Diagnostic)]
75-
#[diag("`FnPtr` trait with unexpected associated item")]
76-
pub(crate) struct UnexpectedFnPtrAssociatedItem {
77-
#[primary_span]
78-
pub span: Span,
79-
}
80-
8174
#[derive(Diagnostic)]
8275
#[diag(
8376
"monomorphising SIMD type `{$ty}` with a non-primitive-scalar (integer/float/pointer) element type `{$e_ty}`"

compiler/rustc_ty_utils/src/instance.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ use rustc_trait_selection::traits;
1414
use tracing::debug;
1515
use traits::translate_args;
1616

17-
use crate::errors::UnexpectedFnPtrAssociatedItem;
18-
1917
fn resolve_instance_raw<'tcx>(
2018
tcx: TyCtxt<'tcx>,
2119
key: ty::PseudoCanonicalInput<'tcx, (DefId, GenericArgsRef<'tcx>)>,
@@ -288,7 +286,7 @@ fn resolve_associated_item<'tcx>(
288286
Some(ty::Instance::new_raw(trait_item_id, args))
289287
}
290288
} else if tcx.is_lang_item(trait_ref.def_id, LangItem::FnPtrTrait) {
291-
if tcx.is_lang_item(trait_item_id, LangItem::FnPtrAddr) {
289+
if tcx.is_lang_item(trait_item_id, LangItem::FnPtrAsPtr) {
292290
let self_ty = trait_ref.self_ty();
293291
if !matches!(self_ty.kind(), ty::FnPtr(..)) {
294292
return Ok(None);
@@ -298,9 +296,9 @@ fn resolve_associated_item<'tcx>(
298296
args: rcvr_args,
299297
})
300298
} else {
301-
tcx.dcx().emit_fatal(UnexpectedFnPtrAssociatedItem {
302-
span: tcx.def_span(trait_item_id),
303-
})
299+
Some(Instance { def: ty::InstanceKind::Item(trait_item_id), args: rcvr_args })
300+
// debug_assert!(tcx.defaultness(trait_item_id).has_value());
301+
// Some(Instance::new(trait_item_id, rcvr_args))
304302
}
305303
} else if let Some(target_kind) = tcx.fn_trait_kind_from_def_id(trait_ref.def_id) {
306304
// FIXME: This doesn't check for malformed libcore that defines, e.g.,

library/core/src/marker.rs

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,24 +1120,6 @@ marker_impls! {
11201120
{T: ConstParamTy_ + ?Sized} &T,
11211121
}
11221122

1123-
/// A common trait implemented by all function pointers.
1124-
//
1125-
// Note that while the trait is internal and unstable it is nevertheless
1126-
// exposed as a public bound of the stable `core::ptr::fn_addr_eq` function.
1127-
#[unstable(
1128-
feature = "fn_ptr_trait",
1129-
issue = "none",
1130-
reason = "internal trait for implementing various traits for all function pointers"
1131-
)]
1132-
#[lang = "fn_ptr_trait"]
1133-
#[rustc_deny_explicit_impl]
1134-
#[rustc_dyn_incompatible_trait]
1135-
pub trait FnPtr: Copy + Clone {
1136-
/// Returns the address of the function pointer.
1137-
#[lang = "fn_ptr_addr"]
1138-
fn addr(self) -> *const ();
1139-
}
1140-
11411123
/// Derive macro that makes a smart pointer usable with trait objects.
11421124
///
11431125
/// # What this macro does

library/core/src/ops/function.rs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::marker::Tuple;
2-
2+
use crate::ptr::NonNull;
33
/// The version of the call operator that takes an immutable receiver.
44
///
55
/// Instances of `Fn` can be called repeatedly without mutating state.
@@ -311,3 +311,39 @@ mod impls {
311311
}
312312
}
313313
}
314+
315+
/// A type representing a pointer to a function pointer.
316+
// FIXME: Make this a proper extern type.
317+
#[unstable(feature = "fn_static", issue = "148768")]
318+
pub type Code = ();
319+
320+
/// A common trait implemented by all function pointers.
321+
#[unstable(feature = "fn_static", issue = "148768")]
322+
#[lang = "fn_ptr_trait"]
323+
#[rustc_deny_explicit_impl]
324+
#[rustc_dyn_incompatible_trait]
325+
pub trait FnPtr: Copy + Clone {
326+
/// Returns the address of the function pointer.
327+
#[unstable(feature = "fn_static", issue = "148768")]
328+
fn addr(self) -> usize {
329+
self.as_ptr().addr().get()
330+
}
331+
332+
/// Returns the function pointer as a [`NonNull<Code>`].
333+
#[unstable(feature = "fn_static", issue = "148768")]
334+
#[lang = "fn_ptr_as_ptr"]
335+
fn as_ptr(self) -> NonNull<Code>;
336+
337+
/// Constructs a function pointer from a `NonNull` pointer.
338+
///
339+
/// # Safety
340+
///
341+
/// The function pointer must have been obtained
342+
/// from an [`FnPtr::as_ptr`] call from a function
343+
/// pointer type that is ABI compatible.
344+
#[unstable(feature = "fn_static", issue = "148768")]
345+
unsafe fn from_ptr(ptr: NonNull<Code>) -> Self {
346+
// SAFETY: The pointer is valid and points to an ABI-compatible function.
347+
unsafe { crate::mem::transmute(ptr.as_ptr()) }
348+
}
349+
}

0 commit comments

Comments
 (0)