rust-lang/rust

Tracking Issue for const `mem::discriminant`

lcnr opened this issue ยท 15 comments

lcnr commented

The feature gate for the issue is #![feature(const_discriminant)].

Implemented in #69825

Unresolved issues

  • #89765 ICE when used on zero variant enums

The intrinsic is already implemented in Miri, you can copy that to rustc if you want.

If you do, please also submit a PR to Miri to remove the implementation there.

Should we consider adding more symbol kinds to const eval (like the way pointers can't be read as bits) to ensure that this feature isn't used to read discriminants as integers? Or is doing so at compile time actually something that enables legit use cases?

What we do for pointers is born out of necessity, and causes pain throughout the engine.

For discriminants (a) I cannot think of a practical way to do so, and (b) I view this the same as layout details: it is not UB to use raw pointers to observe and mess with repr(Rust) layout if you get it right, but layout might change any time so you have no way to be sure that whatever is right for current Rust will remain right in the future.

lcnr commented

Would this be to prevent something like this (which may break due to compiler updates)?

#![feature(core_intrinsics, const_discriminant)]

const ARR: [u32; std::intrinsics::discriminant_value(&Some(7)) as usize] = [42];

@lcnr we already have that with things like

const ARR: [u32; mem::size_of::<Option<Option<bool>>> = [42];

It seems that mem::discriminant is now const, as the doc shows. Shouldn't this issue be closed?

@stephanemagnenat the const part of it is still unstable.

#[stable(feature = "discriminant_value", since = "1.21.0")]
#[rustc_const_unstable(feature = "const_discriminant", issue = "69821")]
pub const fn discriminant<T>(v: &T) -> Discriminant<T> {
Discriminant(intrinsics::discriminant_value(v))
}

If you view nightly docs, it is much clearer, showing (const: unstable) next to the function. It will take a couple of releases before that rustdoc feature is part of stable docs.

image

Thank you for the clarification!

Btw, I saw on the PR (#69825) that people were asking for use cases to decide whether to stabilise this feature. I believe I have such a use case: I am making a parser for a DSL that must match existing data structures, and these can have members of various types. I thus have a custom Value type, and would like these data structures to return a description of themselves that contains which variant of Value they accept. I was planning to use the Discriminant<Value> type, but as I cannot have const values of this type in stable, I'll probably use the enum-kinds crate for now.

We have a similar issue in https://github.com/mapeditor/rs-tiled, so far we've resorted to creating a Tag enum but using the discriminant would be much cleaner. One thing I'm unsure about though, is how to refer to the discriminant of a variant at compiletime without actually creating an instance of the enum.

One thing I'm unsure about though, is how to refer to the discriminant of a variant at compiletime without actually creating an instance of the enum.

I don't think that is possible. There is currently no work being done to allow this, and it's unclear to me how that could be done without making enum variants their own types that you can mention without needing a value

Maybe some kind of macro could do the job, like std::mem::discriminant_of!(Enum::Variant).

I'm not saying we can't add it, but that there are no plans for it. This issue is also the wrong place to figure out a design for it, so maybe open a thread on the internals forum?

We reviewed this in today's @rust-lang/lang meeting. It looks like there are mentions of wanting a use case to justify making this available in const. Leaving aside that there appear to have been mentions of use cases, in general we feel that if a function exists as non-const and it can be written as const then we should make it available in const.

I have another use case (currently I ended up using the strum and num_traits packages), in addition to the one I mentioned on June 25 last year. I have a block-based visual programming language (see https://cand.li for a screenshot). Each block has possibly parameters (e.g. speed vector), and all blocks together are joined in a union. Sometimes, we want configurations where only a subset of blocks can be used (e.g. simple mode). It would be convenient to have such configurations const, so that they can be used in const contexts (as a global configuration for example). Ideally that feature would use the macro evoked by @aleokdev but even without it, there could be a const prototype for each block type (e.g. the one we show on the block palette) out of which the discriminant can be extracted in a const way.