Repository navigation
Tracking issue for const fn pointers #63997
Description
Activity
- addedB-RFC-approvedBlocker: Approved by a merged RFC but not yet implemented.Blocker: Approved by a merged RFC but not yet implemented.C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCCategory: An issue tracking the progress of sth. like the implementation of an RFCT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.T-langRelevant to the language teamRelevant to the language team
on Aug 29, 2019 I think that, at the very least, this should work:
const fn foo() {} const FOO: const fn() = foo; const fn bar() { FOO() } const fn baz(x: const fn()) { x() } const fn bazz() { baz(FOO) }
For this to work:
constmust be part offntypes (just likeunsafe, theextern "ABI", etc.)- we should allow calling
const fntypes from const fn
Currently,
const fns already coerce tofns, soconst fntypes should too:const fn foo() {} let x: const fn() = foo; let y: fn() = x; // OK: const fn => fn coercion
I don't see any problems with supporting this. The RFC mentions some issues, but I don't see anything against just supporting this restricted subset.
This subset would be super useful. For example, you could do:
struct Foo<T>(T); trait Bar { const F: const fn(Self) -> Self; } impl<T: Bar> Foo<T> { const fn new(x: T) -> Self { Foo(<T as Bar>::F(x)) } } const fn map_i32(x: i32) -> i32 { x * 2 } impl Bar for i32 { const F: const fn(Self) -> Self = map_i32; } const fn map_u32(x: i32) -> i32 { x * 3 } impl Bar for u32 { const F: const fn(Self) -> Self = map_u32; }
which is a quite awesome work around for the lack of
consttrait methods, but much simpler since dynamic dispatch isn't an issue, as opposed to:trait Bar { const fn map(self) -> Self; } impl Bar for i32 { ... } impl Bar for u32 { ... } // or const impl Bar for i32 { ... {
This is also a way to avoid having to use
if/matchetc. inconst fns, since you can create a trait with a const, and just dispatch on it to achieve "conditional" control-flow at least at compile-time.Reacted by A.J. Ruckman, hkalbasi, sam0x17, Morten Lohne, Eric Shimizu Karbstein and Angad TendulkarAFAIK
const fntypes are not even RFC'd, isn't it too early for a tracking issue?Don't know, @Centril suggested that I open one.
I have no idea why
const fntypes aren't allowed. AFAICT, whether a function isconstor not is part of its type, and the fact thatconst fnis rejected in a type is an implementation / original RFC oversight. If this isn't the case, what is the case?EDIT: If I call a non-
const fnfrom aconst fn, that code fails to type check, so for that to happenconstmust be part of afntype.- removedB-RFC-approvedBlocker: Approved by a merged RFC but not yet implemented.Blocker: Approved by a merged RFC but not yet implemented.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.
on Aug 29, 2019 AFAIK
const fntypes are not even RFC'd, isn't it too early for a tracking issue?Lotsa things aren't RFCed with respect to
const fn. I want these issues for targeted discussion so it doesn't happen on the meta issue.If I call a non-const fn from a const fn, that code fails to type check, so for that to happen const must be part of a fn type.
it is.
you can do
const fn f() {} let x = f; x();
inside a constant. But this information is lost when casting to a function pointer. Function pointers just don't have the concept of of constness.
Figuring out constness in function pointers or dyn traits is a tricky questions, with a lot of prior discussion in the RFC and the pre-RFC.
whats about?
pub trait Reflector { fn Reflect(&mut self)-> (const fn(Cow<str>)->Option<Descriptor>); }10 remaining items
impl<T> Cell<T> { pub fn with<U>(&self, func: const fn(&mut T) -> U) -> U; }
Wouldn't const fn pointers make this sound? A const fn can't access a static or a thread-local, which would make this unsound.
Edit: a cell containing a reference to itself makes this unsound
It seems assignment is currently broken, complaining about casts, even though no such casts are actually performed. (A const function simply assigning a function ptr basically). #83033
See my response at #83033 (comment) -- short summary: there is in fact a cast going on here; see the reference on "function item types" for more details.
Reacted by Hindrik StegengaJust in case other people run into this being unstable: It's still possible to use function pointers in
const fnas long as they're wrapped in some other type (eg. a#[repr(transparent)]newtype or anOption<fn()>):I've found a case where this isn't true. (playground link)
struct Handlers([Option<fn()>; _]); impl Handlers { const fn new() -> Self { Self([None; _]) } }
Yea, just like with dyn Trait or generic trait bounds, there are workarounds to our checks and I'm convinced now we should just allow all of these like we do in const items. You can't call them, but you can pass them around.
- addedS-tracking-needs-summaryStatus: It's hard to tell what's been done and what hasn't! Someone should do some investigation.Status: It's hard to tell what's been done and what hasn't! Someone should do some investigation.
on Jun 22, 2022 For const closures a lot has happened in 2022.
This now works since
rustc 1.61.0-nightly (03918badd 2022-03-07)(commit range is 38a0b81...03918ba but I can't narrow it down to a single PR... maybe a side effect of #93827 ???):#![feature(const_trait_impl)] const fn foo<T: ~const Fn() -> i32>(f: &T) -> i32 { f() }
And since
rustc 1.68.0-nightly (9c07efe84 2022-12-16)(I suppose the PR was #105725) you can even useimpl Traitsyntax:#![feature(const_trait_impl)] const fn foo(f: &impl ~const Fn() -> i32) -> i32 { f() }
For const fn pointers, nothing much has happened though. This still errors:
const fn foo(f: ~const fn() -> i32) -> i32 { f() }
gives
Details
error: expected identifier, found keyword `fn` --> src/lib.rs:2:24 | 2 | const fn foo(f: ~const fn() -> i32) -> i32 { | ^^ | help: use `Fn` to refer to the trait | 2 | const fn foo(f: ~const Fn() -> i32) -> i32 { | ~~ error: `~const` is not allowed here --> src/lib.rs:2:17 | 2 | const fn foo(f: ~const fn() -> i32) -> i32 { | ^^^^^^^^^^^^^^^^^^ | = note: trait objects cannot have `~const` trait bounds error[E0782]: trait objects must include the `dyn` keyword --> src/lib.rs:2:17 | 2 | const fn foo(f: ~const fn() -> i32) -> i32 { | ^^^^^^^^^^^^^^^^^^ | help: add `dyn` keyword before this trait | 2 | const fn foo(f: dyn ~const fn() -> i32) -> i32 { | +++ For more information about this error, try `rustc --explain E0782`. error: could not compile `playground` (lib) due to 3 previous errorsEdit: note that while what I said is great progress, the two aren't well comparable, as the
Fntrait support is for monomorphized generics cases, as in those where we know the type at const eval time and can derive the function from the type.dyn Fntrait support is still not existent. This gives a bunch of errors:#![feature(const_trait_impl)] const fn foo(f: &dyn ~const Fn() -> i32) -> i32 { f() }
Reacted by Thomas de ZeeuwSeems to have been patched. You need
#[const_trait]attribute to use~const, which theFntrait doesn't have.
rust-stdsays that it has "effects"... #[must_use = "closures are lazy and do nothing unless called"] // FIXME(effects) #[const_trait] pub trait Fn<Args: Tuple>: FnMut<Args> { ...
- addedA-const-evalArea: Constant evaluation, covers all const contexts (static, const fn, ...)Area: Constant evaluation, covers all const contexts (static, const fn, ...)and removed
on Dec 1, 2024 - addedPG-const-traitsProject group: Const traitsProject group: Const traitsS-tracking-needs-design-proposalStatus: This needs a clear design proposal and then a meeting with the team.Status: This needs a clear design proposal and then a meeting with the team.and removedS-tracking-needs-summaryStatus: It's hard to tell what's been done and what hasn't! Someone should do some investigation.Status: It's hard to tell what's been done and what hasn't! Someone should do some investigation.
on Nov 9, 2025 - addedT-typesRelevant to the types team, which will review and decide on the PR/issue.Relevant to the types team, which will review and decide on the PR/issue.
on Feb 14, 2026
Sub-tracking issue for #57563.
This tracks
const fntypes and callingfntypes inconst fn.From the RFC (https://github.com/oli-obk/rfcs/blob/const_generic_const_fn_bounds/text/0000-const-generic-const-fn-bounds.md#const-function-pointers):
constfunction pointersis illegal before and with this RFC. While we can change the language to allow this feature, two
questions make themselves known:
fn pointers in constants
is already legal in Rust today, even though the
Fdoesn't need to be aconstfunction.Opt out bounds might seem unintuitive?
Alternatively one can prefix function pointers to
constfunctions withconst:This opens up the curious situation of
constfunction pointers in non-const functions:Which is useless except for ensuring some sense of "purity" of the function pointer ensuring that
subsequent calls will only modify global state if passed in via arguments.