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

Tracking issue for RFC 2342, "Allow `if` and `match` in constants" #49146

Open
Centril opened this Issue Mar 18, 2018 · 31 comments

Comments

Projects
None yet
8 participants
@Centril
Copy link
Contributor

Centril commented Mar 18, 2018

This is a tracking issue for the RFC "Allow if and match in constants" (rust-lang/rfcs#2342).

Steps:

Unresolved questions:

None

@oli-obk

This comment has been minimized.

Copy link
Contributor

oli-obk commented Mar 19, 2018

  1. add a feature gate for it
  2. switch and switchInt terminators in https://github.com/rust-lang/rust/blob/master/src/librustc_mir/transform/qualify_consts.rs#L347 need to have custom code in case the feature gate is active
  3. instead of having a single current basic block (https://github.com/rust-lang/rust/blob/master/src/librustc_mir/transform/qualify_consts.rs#L328) this needs to be some container that has a list of basic blocks it still has to process.
@eddyb

This comment has been minimized.

Copy link
Member

eddyb commented Mar 19, 2018

@oli-obk It's a bit trickier because the complex control-flow means dataflow analysis needs to be employed. I need to get back to @alexreg and figure out how to integrate their changes.

@alexreg

This comment has been minimized.

Copy link
Contributor

alexreg commented Mar 19, 2018

@eddyb A good starting point would probably be to take my const-qualif branch (minus the top commit), rebase it over master (not going to be fun), and then add data annotation stuff, right?

@mark-i-m

This comment has been minimized.

Copy link
Contributor

mark-i-m commented Apr 25, 2018

Any news on this?

@alexreg

This comment has been minimized.

Copy link
Contributor

alexreg commented Apr 26, 2018

@mark-i-m Alas no. I think @eddyb has been very busy indeed, because I've not even been able to ping him on IRC for the last few weeks hah. Sadly my const-qualif branch doesn't even compile since I last rebased it over master. (I don't believe I've pushed yet though.)

thread 'main' panicked at 'assertion failed: position <= slice.len()', libserialize/leb128.rs:97:1
note: Run with `RUST_BACKTRACE=1` for a backtrace.
error: Could not compile `rustc_llvm`.

Caused by:
  process didn't exit successfully: `/Users/alex/Software/rust/build/bootstrap/debug/rustc --crate-name build_script_build librustc_llvm/build.rs --error-format json --crate-type bin --emit=dep-info,link -C opt-level=2 -C metadata=74f2a810ad96be1d -C extra-filename=-74f2a810ad96be1d --out-dir /Users/alex/Software/rust/build/x86_64-apple-darwin/stage1-rustc/release/build/rustc_llvm-74f2a810ad96be1d -L dependency=/Users/alex/Software/rust/build/x86_64-apple-darwin/stage1-rustc/release/deps --extern build_helper=/Users/alex/Software/rust/build/x86_64-apple-darwin/stage1-rustc/release/deps/libbuild_helper-89aaac40d3077cd7.rlib --extern cc=/Users/alex/Software/rust/build/x86_64-apple-darwin/stage1-rustc/release/deps/libcc-ead7d4af4a69e776.rlib` (exit code: 101)
warning: build failed, waiting for other jobs to finish...
error: build failed
command did not execute successfully: "/Users/alex/Software/rust/build/x86_64-apple-darwin/stage0/bin/cargo" "build" "--target" "x86_64-apple-darwin" "-j" "8" "--release" "--manifest-path" "/Users/alex/Software/rust/src/librustc_trans/Cargo.toml" "--features" " jemalloc" "--message-format" "json"
expected success, got: exit code: 101
thread 'main' panicked at 'cargo must succeed', bootstrap/compile.rs:1085:9
note: Run with `RUST_BACKTRACE=1` for a backtrace.
failed to run: /Users/alex/Software/rust/build/bootstrap/debug/bootstrap -i build
@alexreg

This comment has been minimized.

Copy link
Contributor

alexreg commented Apr 26, 2018

Okay, funnily enough, I rebased again just today and it seems to be building all fine now! Looks like there was a regression, and it just got fixed. All over to @eddyb now.

@eddyb

This comment has been minimized.

Copy link
Member

eddyb commented Apr 26, 2018

@alexreg Sorry, I've switched to a local sleep schedule and I see you've pinged me when I wake up but then you're offline all day when I'm awake (ugh timezones).
Should I just make a PR out of your branch? I forgot what we were supposed to do with it?

@alexreg

This comment has been minimized.

Copy link
Contributor

alexreg commented Apr 26, 2018

@eddyb That's alright heh. You must be off to bed early, since I'm usually on from 8:00PM GMT, but it's all good! :-)

kennytm added a commit to kennytm/rust that referenced this issue Apr 30, 2018

Rollup merge of rust-lang#50233 - mark-i-m:const_vec, r=kennytm
Make `Vec::new` a `const fn`

`RawVec::empty/_in` are a hack. They're there because `if size_of::<T> == 0 { !0 } else { 0 }` is not allowed in `const` yet. However, because `RawVec` is unstable, the `empty/empty_in` constructors can be removed when rust-lang#49146 is done...
@eddyb

This comment has been minimized.

Copy link
Member

eddyb commented May 4, 2018

I'm really sorry, took me a while to realize that the series of patches in question requires removing Qualif::STATIC{,_REF}, i.e. the errors about accessing statics at compile-time. OTOH, this is already broken in terms of const fns and access to statics:

#![feature(const_fn)]
const fn read<T: Copy>(x: &T) -> T { *x }
static FOO: u32 = read(&BAR);
static BAR: u32 = 5;
fn main() {
    println!("{}", FOO);
}

This is not detected statically, instead miri complains that "dangling pointer was dereferenced" (which should really say something about statics instead of "dangling pointer").

So I think reading statics at compile-time should be fine, but some people want const fn to be "pure" (i.e. "referentially transparent" or thereabouts) at runtime, which would mean that a const fn reading from behind a reference it got as an argument is fine, but a const fn should never be able to obtain a reference to a static out of thin air (including from consts).

I think then we can keep statically denying mentioning statics (even if only to take their reference) in consts, const fn, and other constant contexts (including promoteds).
But we still have to remove the STATIC_REF hack which allows statics to take the reference of other statics but (poorly tries and fails to) deny reading from behind those references.

Do we need an RFC for this?

@alexreg

This comment has been minimized.

Copy link
Contributor

alexreg commented May 4, 2018

Sounds fair w.r.t. reading from statics. Doubt it needs an RFC, maybe just a crater run, but then I’m probably not the best one to say.

@eddyb

This comment has been minimized.

Copy link
Member

eddyb commented May 4, 2018

Note that we wouldn't be restricting anything, we'd be relaxing a restriction that's already broken.

@alexreg

This comment has been minimized.

Copy link
Contributor

alexreg commented May 4, 2018

Oh, I misread. So const evaluation would still be sound, just not referentially transparent?

@eddyb

This comment has been minimized.

Copy link
Member

eddyb commented May 4, 2018

The last paragraph describes a referentially transparent approach (but we lose that property if we start allowing mentioning statics in consts and const fns). I don't think soundness was really under discussion.

@alexreg

This comment has been minimized.

Copy link
Contributor

alexreg commented May 4, 2018

Well, "dangling pointer" sure sounds like a soundness issue, but I'll trust you on this!

@eddyb

This comment has been minimized.

Copy link
Member

eddyb commented May 4, 2018

"dangling pointer" is a bad error message, that's just miri forbidding reading from statics. The only constant contexts that can even refer to statics are other statics, so we could "just" allow those reads, since all of that code always runs once, at compile-time.

(from IRC) To summarize, referentially transparent const fn could only ever reach frozen allocations, without going through arguments, which means const needs the same restriction, and non-frozen allocations can only come from statics.

@Centril

This comment has been minimized.

Copy link
Contributor Author

Centril commented May 4, 2018

I do like preserving referential transparency so @eddyb's idea sounds fantastic!

@alexreg

This comment has been minimized.

Copy link
Contributor

alexreg commented May 4, 2018

Yeah I’m pro making const fns pure as well.

@eddyb

This comment has been minimized.

Copy link
Member

eddyb commented May 4, 2018

Please note that certain seemingly harmless plans could ruin referential transparency, e.g.:

let x = 0;
let non_deterministic = &x as *const _ as usize;
if non_deterministic.count_ones() % 2 == 0 {
    // do one thing
} else {
    // do a completely different thing
}

This would fail with a miri error at compile-time, but would be non-deterministic at runtime (because we can't mark that memory address as "abstract" like miri can).

EDIT: @Centril had the idea of making certain raw pointer operations (such as comparisons and casts to integers) unsafe within const fn (which we can do up until we stabilize const fn), and state that they can only be used in ways that miri would allow at compile-time.
For example, subtracting two pointers into the same local should be fine (you get a relative distance that only depends on the type layout, array indices, etc.), but formatting the address of a reference (via {:p}) is an incorrect use and therefore fmt::Pointer::fmt can't be marked const fn.
Also none of the Ord / Eq trait impls for raw pointers can be marked as const (whenever we get the ability to annotate them as such), because they're safe but the operation is unsafe in const fn.

@alexreg

This comment has been minimized.

Copy link
Contributor

alexreg commented May 4, 2018

Depends what you mean by "harmless"... I can certainly see reason we'd want to ban such non-deterministic behaviour.

@eddyb eddyb referenced this issue May 4, 2018

Closed

const fn tracking issue (RFC 911) #24111

3 of 3 tasks complete

bors added a commit that referenced this issue May 8, 2018

Auto merge of #50390 - hdhoang:46205_deny_by_default, r=nikomatsakis
lint: deny incoherent_fundamental_impls by default

Warn the ecosystem of the pending intent-to-disallow in #49799.

There are 4 ICEs on my machine, look unrelated (having happened before in #49146 (comment))

```rust
thread 'main' panicked at 'assertion failed: position <= slice.len()', libserialize/leb128.rs:97:1
```

```
    [run-pass] run-pass/allocator/xcrate-use2.rs
    [run-pass] run-pass/issue-12133-3.rs
    [run-pass] run-pass/issue-32518.rs
    [run-pass] run-pass/trait-default-method-xc-2.rs
```

r? @nikomatsakis
@lachlansneff

This comment has been minimized.

Copy link

lachlansneff commented Jun 18, 2018

It would be fantastic if work were continued on this.

@alexreg

This comment has been minimized.

Copy link
Contributor

alexreg commented Jun 18, 2018

@lachlansneff It's moving... not as quickly as we'd like, but work is being done. At the moment we're waiting on #51110 as a blocker.

@lachlansneff

This comment has been minimized.

Copy link

lachlansneff commented Jun 18, 2018

@alexreg Ah, thank you. It would be very useful to be able to mark a match or if as const even when not in a const fn.

@programmerjake

This comment has been minimized.

Copy link

programmerjake commented Aug 20, 2018

any status updates now that #51110 is merged?

@alexreg

This comment has been minimized.

Copy link
Contributor

alexreg commented Aug 20, 2018

@programmerjake I'm waiting for some feedback from @eddyb on #52518 before it can get merged (hopefully very soon). He's been very busy lately (always in high demand), but he's gotten back to reviews and whatnot in the past few days, so I'm hopeful. After that, it will need some work by him personally, I suspect, since adding proper dataflow analysis is a complicated affair. We'll see though.

@RalfJung

This comment has been minimized.

Copy link
Member

RalfJung commented Aug 29, 2018

Somewhere to the TODO lists in the first post(s), it should be added to remove the current horrible hack that translates && and || to & and | inside constants.

@alexreg

This comment has been minimized.

Copy link
Contributor

alexreg commented Aug 29, 2018

@RalfJung Wasn't that part of the old const eval, that's complete gone now that MIRI CTFE is in place?

@RalfJung

This comment has been minimized.

Copy link
Member

RalfJung commented Aug 30, 2018

AFAIK we do that translation somewhere in HIR lowering, because we have code in const_qualify that rejects SwitchInt terminators which would otherwise be generated by ||/&&.

Also,another point: @oli-obk said somewhere (but I cannot find where) that conditionals are somehow more complicated than one would naively think... was that "just" about the analysis for drop/interior mutability?

@oli-obk

This comment has been minimized.

Copy link
Contributor

oli-obk commented Aug 30, 2018

was that "just" about the analysis for drop/interior mutability?

I'm currently trying to clear that up. Will get back to you when I have all the information

@mark-i-m

This comment has been minimized.

Copy link
Contributor

mark-i-m commented Feb 1, 2019

What's the status of this? Is this in need of manpower or is it blocked on solving some problem?

@alexreg

This comment has been minimized.

Copy link
Contributor

alexreg commented Feb 1, 2019

@mark-i-m It's blocked on implementing proper dataflow analysis for const qualification. @eddyb is the most knowledgeable in this area, and he had previously done some work on this. (So had I, but that sort of stagnated...) If @eddyb still doesn't have time, perhaps @oli-obk or @RalfJung could tackle this at some point soon. :-)

@eddyb

This comment has been minimized.

Copy link
Member

eddyb commented Feb 14, 2019

#58403 is a small step towards dataflow-based qualification.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.