Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

const fn tracking issue (RFC 911) #24111

Closed
3 tasks done
nikomatsakis opened this issue Apr 6, 2015 · 275 comments
Closed
3 tasks done

const fn tracking issue (RFC 911) #24111

nikomatsakis opened this issue Apr 6, 2015 · 275 comments
Labels
A-const-eval Area: Constant evaluation (MIR interpretation) A-const-fn Area: const fn foo(..) {..}. Pure functions which can be applied at compile time. B-RFC-approved Blocker: Approved by a merged RFC but not yet implemented. B-RFC-implemented Blocker: Approved by a merged RFC and implemented. B-unstable Blocker: Implemented in the nightly compiler and unstable. C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@nikomatsakis
Copy link
Contributor

nikomatsakis commented Apr 6, 2015

#57563 | new meta tracking issue

Old content

Tracking issue for rust-lang/rfcs#911.

This issue has been closed in favor of more targeted issues:

Things to be done before stabilizing:

CTFE = https://en.wikipedia.org/wiki/Compile_time_function_execution

@steveklabnik steveklabnik added B-RFC B-RFC-approved Blocker: Approved by a merged RFC but not yet implemented. and removed B-RFC labels Apr 6, 2015
@Munksgaard
Copy link
Contributor

Is this closed by #25609?

@abonander
Copy link
Contributor

@Munksgaard That just adds support to the compiler AFAIK. There's a lot of functions in the stdlib that need to be changed to const fn and tested for breakage. I don't know what the progress is on that.

@nodakai
Copy link
Contributor

nodakai commented Aug 2, 2015

I'm hoping this to be implemented on std::ptr::null() and null_mut() so that we can use them to initialize static mut *MyTypeWithDrop without resorting to 0usize as *mut _

@alexcrichton alexcrichton added the T-lang Relevant to the language team, which will review and decide on the PR/issue. label Aug 11, 2015
@rohel01

This comment has been minimized.

@glaebhoerl
Copy link
Contributor

To be clear, the question here is not primarily about the usefulness of the feature but rather regarding the best way to formulate it (or the best framework to formulate it in). See the RFC discussion.

Manishearth added a commit to Manishearth/rust that referenced this issue Sep 20, 2015
@aturon aturon added B-unstable Blocker: Implemented in the nightly compiler and unstable. and removed B-RFC-approved Blocker: Approved by a merged RFC but not yet implemented. labels Nov 5, 2015
@aturon
Copy link
Member

aturon commented Nov 5, 2015

This is now the tracking issue for eventual stabilization.

@briansmith
Copy link
Contributor

#29107 has been closed.

I disagree that "Integration with patterns", or any changes to the standard library should block this. This is very useful even without those changes, and those changes can be done later. In particular, I would like to start using const fn in my own code soon.

Accordingly, could the stabilization status of this be re-evaluated?

@glaebhoerl
Copy link
Contributor

I don't doubt that const fn even in its current limited form would be useful functionality to have, but what I would really like, ideally before going further along this path, would be for those in favor of "the const fn approach" to think about and articulate their preferred endgame. If we just keep on incrementally adding useful-seeming functionality in the most obvious way, it seems very likely to me that we'll eventually end up copying more or less the entirety of C++'s constexpr design. Is that something we are comfortable with? Even if we say yes, I would much rather that we choose that path in a clear-eyed way, instead of backing into it with small steps over time, as the path of least resistance, until it has become inevitable.

(Given that the semantics of safe Rust code should be fully definable, it seems likely that eventually at least every function which doesn't (transitively) depend on unsafe should be able to be marked as const. And given that unsafe is supposed to be an implementation detail, I bet people will push for somehow loosening that restriction as well. I would much rather we looked abroad and tried to find a more cohesive, capable, and well-integrated story for staging and type-level computation.)

@nikomatsakis
Copy link
Contributor Author

@glaebhoerl

I don't doubt that const fn even in its current limited form would be useful functionality to have, but what I would really like, ideally before going further along this path, would be for those in favor of "the const fn approach" to think about and articulate their preferred endgame...it seems very likely to me that we'll eventually end up copying more or less the entirety of C++'s constexpr design.

What I would personally like, even more than that, is that we have a fairly clear view on how we're going to implement it, and what portion of the language we are going to cover. That said, this is very closely related to support for associated constants or generics over integers in my mind.

@eddyb and I did some sketching recently on a scheme which could enable constant evaluation of a very broad swath of code. Basically lowering all constants to MIR and intrepreting it (in some cases,
abstract interpreting, if there are generics you cannot yet evaluate, which is where things get most interesting to me).

However, while it seems like it would be fairly easy to support a very large fraction of the "builtin language", real code in practice hits up against the need to do memory allocation very quickly. In other words, you want to use Vec or some other container. And that's where this whole interpreting scheme starts to get more complicated to my mind.

That said, @glaebhoerl, I'd also love to hear you articulate your preferred alternative endgame. I think you sketched out some such thoughts in the const fn RFC, but I think it'd be good to hear it again, and in this context. :)

@eddyb
Copy link
Member

eddyb commented Jan 16, 2016

The problem with allocation is having it escape into run-time.
If we can somehow disallow crossing that compile-time/run-time barrier, then I believe we could have a working liballoc with const fn.
It would be no harder to manage those kinds of allocations than would be to deal with byte-addressable values on an interpreted stack.

Alternatively, we could generate runtime code to allocate and fill in the values every time that barrier has to be passed, although I'm not sure what kind of usecases that has.

Keep in mind that even with full-fledged constexpr-like evaluation, const fn would still be pure: running it twice on 'static data would result in the exact same result and no side-effects.

@glaebhoerl
Copy link
Contributor

@nikomatsakis If I had one I would have mentioned it. :) I mainly just see known unknowns. The whole thing with consts as part of the generics system was of course part of what I understood as being the C++ design. As far as having associated consts and const generic parameters, considering that we already have fixed-size arrays with consts as part of their type and would like to abstract over them, I would be surprised if there were a much better -- as opposed to merely more general -- way of doing it. The const fn part of things feels more separable and variable. It's easy to imagine taking things further and having things like const impls and const Trait bounds in generics, but I'm sure there is prior art for this sort of general thing which has already figured things out and we should try to find it.

Of the main use cases for the Rust language, the ones that primarily need low-level control, like kernels, seem reasonably well-served already, but another area where Rust could have lots of potential is things that primarily need high performance, and in that space powerful support (in some form) for staged computation (which const fn is already a very limited instance of) seems like it could be a game-changer. (Just in the last few weeks I came across two separate tweets by people who decided to switch from Rust to a language with better staging capabilities.) I'm not sure if any of the existing solutions in languages "close to us" -- C++'s constexpr, D's ad-hoc CTFE, our procedural macros -- really feel inspiring and powerful/complete enough for this sort of thing. (Procedural macros seem like a good thing to have, but more for abstraction and DSLs, not as much for performance-oriented code generation.)

As for what would be inspiring and good enough... I haven't seen it yet, and I'm not familiar enough with the whole space to know, precisely, where to look. Of course, per the above, we might want to at least glance at Julia and Terra, even if they seem like quite different languages from Rust in many ways. I know Oleg Kiselyov has done a lot of interesting work in this area. Tiark Rompf's work on Lancet and Lightweight Modular Staging for Scala seems definitely worth looking at. I recall seeing a presentation by @kmcallister at some point about what a dependently typed Rust might look like (which might at least be more general than sticking const everywhere), and I also recall seeing something from Oleg to the effect that types themselves are a form of staging (which feels natural considering the phase separation between compile- and runtime is a lot like stages)... lots of exciting potential connections in many different directions, which is why it'd feel like a missed opportunity if we were to just commit to the first solution which occurs to us. :)

(This was just a braindump and I've almost surely imperfectly characterized many things.)

@briansmith
Copy link
Contributor

However, while it seems like it would be fairly easy to support a very large fraction of the "builtin language", real code in practice hits up against the need to do memory allocation very quickly. In other words, you want to use Vec or some other container. And that's where this whole interpreting scheme starts to get more complicated to my mind.

I disagree with that characterization of "real code in practice". I think there is big interest in Rust because it helps reduce the need for heap memory allocation. My code, in particular, makes a concrete effort to avoid heap allocation whenever possible.

Being able to do more than that would be nice but being able to construct static instances of non-trivial types with compiler-enforced invariants is essential. The C++ constexpr approach is extremely limiting, but it is more than what I need for my use cases: I need to provide a function that can construct an instance of type T with parameters x, y, and z such that the function guarantees that x, y, and z are valid (e.g., x < y && z > 0), such that the result can be a static variable, without the use of initialization code that runs at startup.

@glaebhoerl
Copy link
Contributor

@briansmith FWIW another approach which has a chance of solving the same use cases would be if macros had privacy hygiene, which I believe (hope) we're planning to make them have.

@briansmith
Copy link
Contributor

@briansmith FWIW another approach which has a chance of solving the same use cases would be if macros had privacy hygiene, which I believe (hope) we're planning to make them have.

I guess if you use the procedural macros then you can evaluate x < y && z > 0 at compile-time. But, it seems like it would be many, many months before procedural macros could be used in stable Rust, if they ever are. const fn is interesting because it can be enabled for stable Rust now, as far as I understand the state of things.

@eddyb
Copy link
Member

eddyb commented Jan 16, 2016

@glaebhoerl I wouldn't hold my breath for strict hygiene, it's quite possible we're going to have an escape mechanism (just like real LISPs), so you may not want it for any kind of safety purposes.

@nikomatsakis
Copy link
Contributor Author

@glaebhoerl there is also https://anydsl.github.io/, which even uses
Rust-like syntax ;) they are basically targeting staged computation and in
particular partial evaluation.

On Sat, Jan 16, 2016 at 6:29 PM, Eduard-Mihai Burtescu <
[email protected]> wrote:

@glaebhoerl https://github.com/glaebhoerl I wouldn't hold my breath for
strict hygiene, it's quite possible we're going to have an escape mechanism
(just like real LISPs), so you may not want it for any kind of safety
purposes.


Reply to this email directly or view it on GitHub
#24111 (comment).

@jethrogb
Copy link
Contributor

jethrogb commented Apr 2, 2016

#29525 should be fixed before stabilization

@glaebhoerl
Copy link
Contributor

Given that the semantics of safe Rust code should be fully definable, it seems likely that eventually at least every function which doesn't (transitively) depend on unsafe should be able to be marked as const. And given that unsafe is supposed to be an implementation detail, I bet people will push for somehow loosening that restriction as well.

Just a thought: if we ever formally define Rust's memory model, then even unsafe code could potentially be safely and sensibly evaluated at compile-time by interpreting it abstractly/symbolically -- that is, use of raw pointers wouldn't turn into direct memory accesses like at runtime, but rather something (just as an example for illustration) like a lookup into a hashmap of allocated addresses, together with their types and values, or similar, with every step checked for validity -- so that any execution whose behavior is undefined would be strictly a compiler-reported error, instead of a security vulnerability in rustc. (This might also be connected to the situation w.r.t. handling isize and usize at compile-time symbolically or in a platform-dependent way.)

I'm not sure where that leaves us with respect to const fn. On the one hand, that would likely open up much more useful code to be available at compile time -- Box, Vec, Rc, anything using unsafe for performance optimization -- which is good. One arbitrary restriction fewer. On the other hand, the boundary for "what can possibly be a const fn" would now essentially be moved outwards to anything that doesn't involve the FFI. So what we'd actually be tracking in the type system, under the guise of constness, is what things (transitively) rely on the FFI and what things don't. And whether or not something uses the FFI is still something that people rightfully consider to be an internal implementation detail, and this restriction (unlike unsafe) really doesn't seem feasible to lift. And under this scenario you'd probably have far more fns being eligible for constness than ones which wouldn't.

So you'd still have constness revolving around an arbitrary, implementation-exposing restriction, and you'd also end up having to write const almost everywhere. That doesn't sound too appealing either...

@eddyb
Copy link
Member

eddyb commented Apr 3, 2016

that is, use of raw pointers wouldn't turn into direct memory accesses like at runtime, but rather something ... like a lookup into a hashmap of allocated addresses,

@glaebhoerl Well, that is pretty much the model I described and which @tsion's miri is implementing.

I think the FFI distinction is very important because of purity, which is required for coherence.
You couldn't even use GHC for Rust const fns because it has unsafePerformIO.

I don't like the const keyword too much myself which is why I am okay with const fn foo<T: Trait> instead of const fn foo<T: const Trait> (for requiring a const impl Trait for T).

Just like Sized, we probably have the wrong defaults, but I haven't seen any other proposals that can realistically work.

@Centril
Copy link
Contributor

Centril commented Dec 31, 2018

I've filed targeted issues for:

The following targeted issues already exist:

If there are other areas, not already tracked by other issues, that need to be discussed wrt. const eval and const fn, I suggest that people make new issues (and cc me + @oli-obk in them).

This concludes the usefulness of this issue, which is hereby closed.

@Centril Centril closed this as completed Dec 31, 2018
@Centril Centril added A-const-fn Area: const fn foo(..) {..}. Pure functions which can be applied at compile time. A-const-eval Area: Constant evaluation (MIR interpretation) labels Dec 31, 2018
@SimonSapin
Copy link
Contributor

I don’t have all the specifics in mind, but isn’t there a lot more that’s suppported by miri but not enabled yet in min_const_fn? For example raw pointers.

@Centril
Copy link
Contributor

Centril commented Jan 1, 2019

@SimonSapin Yeah, good catch. There are some more existing issues for that. I've updated the comment + issue description. If there's something not covered that you happen upon, make new issues please.

@SimonSapin
Copy link
Contributor

SimonSapin commented Jan 1, 2019

I think it’s not appropriate to close a meta tracking issue when it’s not at all clear that what it covers is exhaustively covered by more specific issues.

When I remove #![feature(const_fn)] in Servo, the error messages are:

  • trait bounds other than `Sized` on const fn parameters are unstable
  • function pointers in const fn are unstable

(These const fns are all trivial constructors for types with private fields. The former message is on the constructor of struct Guard<T: Clone + Copy>, even though Clone is not used in the constructor. The latter is for initializing Option<fn()> (simplified) to either None or Some(name_of_a_function_item).)

However, neither traits nor function pointer types are mentioned in this issue’s description.

I don’t mean we should have just two more specific issues for the above. I mean we should reopen this one until we somehow ensure that everything behind the const_fn feature gate (which still points here in error messages) has a tracking issue. Or until const_fn is fully stabilized.

@Centril
Copy link
Contributor

Centril commented Jan 2, 2019

@SimonSapin

I think it’s not appropriate to close a meta tracking issue when it’s not at all clear that what it covers is exhaustively covered by more specific issues.

This issue has the flavor of #34511 which is one of the biggest messes there are as far as tracking issues go. This issue has also been a free-for-all for some time so it doesn't act as a meta-issue right now. For such free-for-alls, please use http://internals.rust-lang.org/ instead.

However, neither traits nor function pointer types are mentioned in this issue’s description.

I don’t mean we should have just two more specific issues for the above.

That's exactly what I think should be done. From a T-Lang triage perspective, it is favorable to have targeted and actionable issues.

I mean we should reopen this one until we somehow ensure that everything behind the const_fn feature gate (which still points here in error messages) has a tracking issue. Or until const_fn is fully stabilized.

It's not even clear to me what const_fn the feature gate even constitutes or that it will all be stabilized at some point. Everything besides bounds and function pointers from the original RFC has open issues and then some.

@SimonSapin
Copy link
Contributor

It's not even clear to me what const_fn the feature gate even constitutes

That’s exactly why we shouldn’t close it until we figure that out, IMO.

Everything

Is it really everything, though?

@SimonSapin
Copy link
Contributor

Related: #57261

@phansch
Copy link
Member

phansch commented Jan 9, 2019

Does someone know what happened to the const_string_new feature? Is there a tracking issue for it? The unstable book just links here.

@Centril
Copy link
Contributor

Centril commented Jan 9, 2019

@phansch That's because all rustc_const_unstable point here. (cc @oli-obk can we fix that?)

@durka
Copy link
Contributor

durka commented Jan 9, 2019 via email

@ErichDonGubler
Copy link
Contributor

@durka: There's always going to be a possible window where something is closed in nightly and the resolution still hasn't landed in stable. How is that insulting?

@nixpulvis
Copy link

nixpulvis commented Jan 9, 2019

I've been resisting commenting here, and maybe we should move this conversation to a thread on internals (is there one already?) but...

The decision to close this makes no sense to me. It's a tracking issue, because it shows up in error messages from the compiler, and it's not alone, see this post for some more examples: https://internals.rust-lang.org/t/psa-tracking-for-gated-language-features/2887. Closing this issue to me implies stability, which is obviously not yet the case.

I frankly can't see an argument for closing this... I'm glad more targeted issue now exist, so implementation can move forward, with hopefully new discussion and focus, but I don't see a clear way to associate the compiler messages with those.

Again, if this needs (or already has) a thread on internals maybe let's move this conversation there?

EDIT: Or is the issue just that the book is outdated? Trying the example from the RFC (it's missing a couple #[derive(...)]s) seems to work without errors on Rust rustc 1.31.1. Are there still compiler error message pointing here? It would be nice to have a place to link errors like:

error: only int, `bool` and `char` operations are stable in const fn

If we want to have them linked to the specific issues that would be an improvement possibly.

@nixpulvis
Copy link

Ok, so here should be some strong evidence for this issue remaining open. As far as I can tell this:

(active, const_fn, "1.2.0", Some(24111), None),

is the only active feature that points to a closed issue.

In an ideal world I believe these kinda of discussions should really be automated, since as we've discovered, people have varying opinions and ideas about how things should work. But that's really not a conversation for this thread...

@shepmaster
Copy link
Member

If we want to have them linked to the specific issues that would be an improvement possibly.

Yes, this is the correct solution, and what @Centril already suggested.

The initial comment has also been edited to redirect people to the specific issues who arrive here in the "window" that @ErichDonGubler mentions.

@varkor
Copy link
Member

varkor commented Jan 13, 2019

#57563 has now been opened to track the remaining unstable const features.

Centril added a commit to Centril/rust that referenced this issue Jan 13, 2019
…ue, r=Centril

Update the const fn tracking issue to the new metabug

The new `const fn` tracking issue is rust-lang#57563. We don't want to point to a closed issue in the diagnostics (or FIXMEs), so these have been updated (from the old issue, rust-lang#24111).

r? @Centril
@glaebhoerl
Copy link
Contributor

Someone could edit the issue body here to prominently link to #57563 then?

@Centril
Copy link
Contributor

Centril commented Jan 13, 2019

@glaebhoerl done :)

@jtakalai
Copy link

jtakalai commented Mar 22, 2019

Hi, I got here because I got error[E0658]: const fn is unstable (see issue #24111) when compiling ncurses-rs. What should I do? Upgrade rust? I've got

$ cargo version
cargo 1.27.0
$ rustc --version
rustc 1.27.2

EDIT: did brew uninstall rust and followed rustup install instructions, now rustc --version is rustc 1.33.0 (2aa4c46cf 2019-02-28) and that error went away.

@oli-obk
Copy link
Contributor

oli-obk commented Mar 22, 2019

Yes, in order to be able to use const fn on stable, you'll need to update your compiler.

@theoparis
Copy link

I am coming from Zig where you can use iterators and functions like sin at compile time. However, attempting to do this in rust gives the following errors. Are these planned to be added to the language at some point? I haven't found an issue mentioning these so I figured I'd post here.

 cannot call non-const fn `<std::ops::Range<usize> as Iterator>::next` in constant functions
 --> src/main.rs:9:14
 cannot call non-const fn `f64::<impl f64>::sin` in constant functions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-const-eval Area: Constant evaluation (MIR interpretation) A-const-fn Area: const fn foo(..) {..}. Pure functions which can be applied at compile time. B-RFC-approved Blocker: Approved by a merged RFC but not yet implemented. B-RFC-implemented Blocker: Approved by a merged RFC and implemented. B-unstable Blocker: Implemented in the nightly compiler and unstable. C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests