Skip to content

as-casts for enums with tuple-only variants are not prohibited #113904

Open
@nalepamarcin

Description

@nalepamarcin

Code

#[repr(u8)]
pub enum Enum {
    V1(u8)  = 0,
    V2(u16),
    V3(u32) = 5,
}

pub fn main() -> () {
    assert_eq!(Enum::V1 as u8, 0);
    assert_eq!(Enum::V2 as u8, 1);
    assert_eq!(Enum::V3 as u8, 5);
}

Current output

-
compiles without any warnings or errors

Desired output

No response

Rationale and extra context

Hello,
According to https://doc.rust-lang.org/reference/items/enumerations.html#casting as-casting enum variants to their discriminants should be possible if they do not have explicit discriminants, or where only unit variants are explicit (there's also case for unit-only enums but it's irrelevant to the case).

Despite all that I can write code as seen in the example that clearly brakes only unit variants are explicit rule.
Moreover, it compiles without any warnings or errors and produces counter-intuitive results in the runtime, e.g.:

thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `208`,
 right: `0`', prog.rs:9:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

I've confirmed (using recommended pointer casting method) that created enum variant holds the correct value i.e. Enum::V1(0).discriminant() is indeed 0.

If I correctly understand the intentions of the authors, the expressions like Enum::V1 as u8 should not be allowed at this time.

As for the future, I think that it would be nice if there was a way to fetch the discriminant value of the variant without creating it in the first place, i.e. discussed constructions would be allowed and returned discriminant of that variant.

Few related discussions I've came about while researching this:
#60553 (comment)
#88621

Other cases

No response

Anything else?

No response

Activity

added
A-diagnosticsArea: Messages for errors, warnings, and lints
T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
on Jul 20, 2023
added
needs-triageThis issue may need triage. Remove it if it has been sufficiently triaged.
on Jul 20, 2023
clubby789

clubby789 commented on Jul 21, 2023

@clubby789
Contributor

Enum::V1 here is actually a function pointer, something like fn V1(val: u8) { Enum::V1(val) }. You're taking the address of the function and casting it to u8, i.e. truncating it to the least significant byte. This is more noticeable from the disassembly:

playground::main:
	sub	rsp, 56
	lea	rax, [rip + playground::Enum::V1] // load address of function
	mov	byte ptr [rsp + 7], al                 // take lowest byte

Enum::V1(0) as u8 (constructing then casting the enum) is indeed forbidden.

workingjubilee

workingjubilee commented on Jul 21, 2023

@workingjubilee
Member

I thought we added a lint against that...

clubby789

clubby789 commented on Jul 21, 2023

@clubby789
Contributor

It's a Clippy one I believe

 --> src/main.rs:9:16
  |
9 |     assert_eq!(Enum::V1 as u8, 0);
  |                ^^^^^^^^^^^^^^ help: try: `Enum::V1 as usize`
  |
  = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast_with_truncation
  = note: `#[warn(clippy::fn_to_numeric_cast_with_truncation)]` on by default
nalepamarcin

nalepamarcin commented on Jul 22, 2023

@nalepamarcin
Author

You're taking the address of the function and casting it to u8

Oh, thanks for explaining that. It makes more sense now :)

TBH, I'm not sure how to proceed with that being the case. Taking a function pointer seems like a legitimate use case and it just happens to be very similar to getting discriminant.

removed
needs-triageThis issue may need triage. Remove it if it has been sufficiently triaged.
on Jul 22, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-diagnosticsArea: Messages for errors, warnings, and lintsT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @saethlin@clubby789@nalepamarcin@workingjubilee@rustbot

        Issue actions

          as-casts for enums with tuple-only variants are not prohibited · Issue #113904 · rust-lang/rust