Rust: Tracking issue for RFC 2341, Allow locals and destructuring in const fn

Created on 7 Mar 2018  路  22Comments  路  Source: rust-lang/rust

This is a tracking issue for the RFC "Allow locals and destructuring in const fn" (rust-lang/rfcs#2341).

Steps:

  • [x] Implement the RFC (cc @oli-obk - just remove the few checks)
  • [x] Adjust documentation (https://github.com/rust-lang-nursery/reference/issues/506)
  • [x] Stabilize (proposal: https://github.com/rust-lang/rust/pull/57175#issuecomment-450593735)
  • [x] Fix short-circuiting operators https://github.com/rust-lang/rust/issues/53515 (no longer compiles on nightly -- https://github.com/rust-lang/rust/issues/53515#issuecomment-450589193)

Unresolved questions:

None.

A-const-eval A-const-fn B-RFC-approved C-tracking-issue E-mentor T-lang

Most helpful comment

Stabilized in https://github.com/rust-lang/rust/pull/57175; Documentation issue: https://github.com/rust-lang-nursery/reference/issues/506

Everything is done so closing therefore.

All 22 comments

just remove the few checks

It's a bit trickier, because rustc_mir::transform::qualify_consts needs to track local variables just like it does only temporaries right now, but it shouldn't

Also, was let in other const contexts in the RFC, i.e. const X: i32 = { let x = 2 + 3; x * x};?

@eddyb Feel free to edit the issue description =)

Also, was let in other const contexts in the RFC, i.e. const X: i32 = { let x = 2 + 3; x * x}; ?

Yes, because (quoting the summary):

Allow let bindings in the body of constants and const fns. Additionally enable destructuring in let bindings and const fn arguments.

A question about the "Drawbacks" section from the original RFC:

You can create mutable locals in constants and then actually modify them. This has no real impact on the constness, as the mutation happens entirely at compile time and results in an immutable value.

Can you elaborate on this? Is this just referring to something like const foo: i32 = { let mut x = 0; x += 1; x };? That's my straightforward reading of the text, but it also seems completely expected so I'm not sure whether there's a more pernicious drawback I ought to be seeing.

Not a drawback really, but a note that this is new behaviour, because before you could never modify the same memory twice, only emulate the same program behaviour via const fn.

This works now on nightly (behind a feature gate). Please play around with this feature liberally and report any findings! Any help in documenting and pushing it over the stabilization line is appreciated.

There seems to be a bug in the current implementation. This should work, right? http://play.rust-lang.org/?gist=5009873918b2b45bfa8015d4f21bb355&version=nightly&mode=debug&edition=2015

Imo it would be fine if added behind its own feature gate. So if you're looking for something easy to do:

  1. add a new feature gate (just search for const_let and copy all the defining parts)
  2. wrap https://github.com/rust-lang/rust/blob/master/src/librustc_mir/transform/qualify_consts.rs#L276 in a feature gate check (so if the feature gate is active, then that line needs to be not called)
  3. Add regression tests

Short-circuiting operators need to be fixed before stabilizing const_let. Otherwise it is possible to observe wrong results when changing a fn to const fn. #53515

I already added it to the OP ;)

The const_let feature gate does not seem to work for field assignment.

#![feature(const_let)]

struct S(i32);

const A: () = {
    let mut s = S(0);
    s.0 = 1;
};

fn main() {}
error[E0658]: statements in constants are unstable (see issue #48821)
 --> src/main.rs:7:5
  |
7 |     s.0 = 1;
  |     ^^^^^^^
  |
  = help: add #![feature(const_let)] to the crate attributes to enable

It suggests adding #![feature(const_let)] even though that feature is already enabled.

@dtolnay cc #52613 #51251 54098
This bug exists from 31 May at least.

We could stabilize let bindings in const fn (but not in const/static), because const functions do not have the issue that && and || short circuit (since these operations are illegal in const functions until control flow in general is allowed).

Due to backwards compatibility constraints we cannot make && and || illegal in constants and statics.

cc @Centril

@oli-obk Hmm... there are a bunch of bug reports cited in https://github.com/rust-lang/rust/issues/48821#issuecomment-425705272... we'd have to feel comfortable with the implementation before stabilizing.

However, my main question re. stabilizing is whether stabilizing let without control flow would bring much benefit without any control flow? What is it that we "unlock" by stabilizing in const fn only?

I have a fix ready for these bugs in https://github.com/rust-lang/rust/pull/56070

However, my main question re. stabilizing is whether stabilizing let without control flow would bring much benefit without any control flow? What is it that we "unlock" by stabilizing in const fn only?

You can do things like

fn bar() -> [u32; 500] {
    let mut foo = [0; 500];
    foo[3] = 42;
    foo
}

Or just generally make your code more readable in case the return expression is very complex.

@oli-obk

I have a fix ready for these bugs in #56070

Cool. :)

Or just generally make your code more readable in case the return expression is very complex.

I somehow doubt expressions can become complex without any sort of control flow but I suppose it doesn't hurt. Clearly enough time has passed since it was landed in nightly...

Could you? prepare:

  1. a special new issue or alternatively a stabilization PR (the latter is my preference)
  2. with a report that points out:

    1. when the initial implementation landed in nightly

    2. relevant tests

    3. what exactly is being stabilized

    4. what is not being stabilized



      1. and why



    5. any divergences from the RFC (there are such because of c) )

  3. change this tracking issue with a checkbox pointing out the remaining work after the initial stabilization

@oli-obk PS: also make sure that const fn with let bindings is well behaved when then later used in a const or static item wrt. short circuit.

also make sure that const fn with let bindings is well behaved when then later used in a const or static item wrt. short circuit.

I'm not even sure I understand. Are you asking whether calling a const fn inside a const initializer could be problematic in the presence of short circuiting operators in the initializer? I don't see how the body of the const fn can be relevant here.

@oli-obk Never mind; I was saying nonsense things. =P

Does this tracking issue include mutable references? Or is that a separate RFC/tracking issue?

Mutable references require their own full rfc imo. There are so many edge cases. I have started tracking some in https://github.com/rust-rfcs/const-eval/issues/16

Stabilized in https://github.com/rust-lang/rust/pull/57175; Documentation issue: https://github.com/rust-lang-nursery/reference/issues/506

Everything is done so closing therefore.

Was this page helpful?
0 / 5 - 0 ratings