Uh oh!
There was an error while loading. Please reload this page.
test more variants of enum-int-casting - #61702
Conversation
rust-highfive
commented
Jun 9, 2019
(rust_highfive has picked a reviewer for you, use r? to override) |
I looked at the MIR for something like fnmain(){let _val = std::cmp::Ordering::Lessasi32;}has the following MIR: What is even going on? Why is there an addition? Of 0? Checked for overflow?!? I find it unlikely that adding 0 will make anything overflow. For comparison, the MIR with an intermediate let-binding: fnmain(){let val = std::cmp::Ordering::Less;let _val = val asi32;}That's what I expected to begin with. Cc @eddyb (This is unrelated to the PR by the way, I am just not sure what would be a better place to discuss this.) |
eddyb
commented
Jun 10, 2019
@RalfJung Heh, @oli-obk knows why because IIRC he did all of this. Let's take it one by one: Now, why is So, that weird MIR you see, doesn't depend on |
So
I was more wondering where it comes from, but now I guess this is from the "counting up" that happens where the next variant gets N+1 if it does not have an explicit discriminator expression?
I don't understand. Who can get which discriminants of which other expressions but not at run-time...? Why is it better to refer to the discriminant expression here instead of doing something like what happens with an intermediate let-binding? The code generated with the let-binding is more readable and it needs fewer basic blocks. Having a special case for "immediate cast to int" makes testing harder. This almost caused an incorrect assertion to sneak into the miri engine that neither the rustc CTFE test suite nor the Miri test suite found, because nobody writes these tests in let-expanded way and nobody expects that to hit a totally different code path. Is there any argument for this funny special case translation? I could understand if some sort of const propagation would kick in later and replace statically-known casts with constant stuff, but that is not what is happening here. |
eddyb
commented
Jun 10, 2019
enumFoo{A = 0,B = Foo::Aasisize + 2,}This will cycle error if you do the runtime thing, because the runtime thing requires knowing the layout, and knowing the layout requires knowing the discriminants. |
But we still cycle error for this: enumFoo{A = 0,B = {let v = Foo::A; v asisize + 2},}or this: constfndo_something(x:Foo) -> isize{ ...}enumFoo{A = 0,B = do_something(Foo::A),}Seems like an awful hack for a partial solution... and even supporting this very special case seems way not worth the cost in incurs. This affects all MIR generated anywhere! |
eddyb
commented
Jun 10, 2019
@RalfJung Backwards compatibility is certainly worth it, and there was no |
RalfJung
commented
Jun 10, 2019
Well I'd be in favor of deprecating cyclic enums... But in the interrim, can we do something like only apply this weird special case when translating an enum discriminant expression? |
RalfJung
commented
Jun 10, 2019
Can you point me to the code implementing this? I did a grep for "enum" and "cast" in |
eddyb
commented
Jun 10, 2019
rust/src/librustc_mir/hair/cx/expr.rs Lines 636 to 710 in 1cbd8a4 |
RalfJung
commented
Jun 10, 2019
Okay, let's see in #61723 what crater finds, and let's move the discussion there. Until then, this PR helps to at least get us some basic test coverage for "both kinds" of enum-int-casts. |
RalfJung
commented
Jun 16, 2019
r? @oli-obk |
oli-obk
commented
Jun 17, 2019
@bors r+ rollup |
bors
commented
Jun 17, 2019
📌 Commit 2e9931f has been approved by |
test more variants of enum-int-casting As I learned in rust-lang#61673 (comment), there is a code path we are not testing yet. Looks like enum-int-casting with and without an intermediate let-binding is totally different. EDIT: The reason for this is to get rid of the cycle in definitions such as: ```rust enum Foo { A = 0, B = Foo::A as isize + 2, } ``` This has historically been supported, so a hack adding special treatment to `Enum::Variant as _` was added to keep supporting it.
Rollup of 5 pull requests Successful merges: - #61702 (test more variants of enum-int-casting) - #61836 (Replace some uses of NodeId with HirId) - #61885 (Help LLVM better optimize slice::Iter(Mut)::len) - #61893 (make `Weak::ptr_eq`s into methods) - #61908 (don't ICE on large files) Failed merges: r? @ghost
As I learned in #61673 (comment), there is a code path we are not testing yet. Looks like enum-int-casting with and without an intermediate let-binding is totally different.
EDIT: The reason for this is to get rid of the cycle in definitions such as:
This has historically been supported, so a hack adding special treatment to
Enum::Variant as _was added to keep supporting it.