Skip to content

add a compile error for using @bitCast to convert an enum to an integer #3647

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

Closed
andrewrk opened this issue Nov 10, 2019 · 10 comments
Closed
Labels
accepted This proposal is planned. breaking Implementing this issue could cause existing code to no longer compile or have different behavior. proposal This issue suggests modifications. If it also has the "accepted" label then it is planned.
Milestone

Comments

@andrewrk
Copy link
Member

const std = @import("std");

const Number = enum(u32) {
    one,
    two,
};

test "passes but should be a compile error" {
    const x: Number = .one;
    const y = @bitCast(u32, x);
}

The proper cast is @enumToInt:

const std = @import("std");

const Number = enum(u32) {
    one,
    two,
};

test "enum to int" {
    const x: Number = .one;
    const y = @enumToInt(x);
}
@andrewrk andrewrk added the proposal This issue suggests modifications. If it also has the "accepted" label then it is planned. label Nov 10, 2019
@andrewrk andrewrk added this to the 0.7.0 milestone Nov 10, 2019
@SpexGuy
Copy link
Contributor

SpexGuy commented Nov 20, 2019

const Foo = enum(u32) { A, B, C };
const Wrapped = struct { val: Foo };
const a = Foo.A;
const wrappedA = Wrapped{ .val = a };
const compiles = @bitCast(u32, wrappedA);
const fails = @bitCast(u32, a);

This seems like a totally arbitrary compile failure. A rule like this can cause unnecessary complexity in generic code. I don't really see a good reason why @bitCast shouldn't be defined in this case.

@daurnimator
Copy link
Contributor

I don't really see a good reason why @bitCast shouldn't be defined in this case.

Struct layout for non extern structs is not defined: for certain debug features or other purposes in the future, the struct may have hidden members.

@SpexGuy
Copy link
Contributor

SpexGuy commented Nov 20, 2019

That's a good point, but the struct cast is the one that compiles. This issue would make the enum cast invalid. On a related note though, does that mean this is UB?

comptime assert(@sizeOf(Wrapped) == @sizeOf(u32));
const a = Wrapped { .val = .A };
const b = @bitCast(u32, a);
const c = @bitCast(Wrapped, b);
const d = c.val; // undefined?

@SpexGuy
Copy link
Contributor

SpexGuy commented Nov 20, 2019

Wait a minute... Struct layout is not guaranteed to be in any consistent order, but it must be defined. Otherwise @offsetOf would be UB.

@SpexGuy
Copy link
Contributor

SpexGuy commented Nov 20, 2019

Ah, nevermind. I misunderstood the intent of bitCast. Sorry for the fuss.

@andrewrk andrewrk added the accepted This proposal is planned. label Nov 29, 2019
@eriksik2
Copy link

This would force any generic function dealing with bit casts to add a special case for enums. If anything I think @enumToInt(...) should be removed in favor of the more general @bitCast(@tagType(...), ...), instead of forcing a special case.

@tadeokondrak
Copy link
Contributor

Does this conflict with #1467?

@WoodyAtHome
Copy link

If I access microcontroller peripheral I use packed structs with enums inside for register access. E.g. STM32:

const EPxR = packed struct {
    const Stat = enum(u2) {
        disabled = 0, stall = 1, nak = 2, valid = 3
    };
    const EpType = enum(u2) {
        bulk = 0, control = 1, iso = 2, interrupt = 3
    };

    EA: u4 = 0,
    STAT_TX: Stat = Stat.disabled,
    DTOG_TX: bool = false,
    CTR_TX: bool = false,
    EP_KIND: bool = false,
    EP_TYPE: EpType = EpType.bulk,
    SETUP: bool = false,
    STAT_RX: Stat = Stat.disabled,
    DTOG_RX: bool = false,
    CTR_RX: bool = false,

    pub fn toInt(self: @This()) u16 {
        return @bitCast(u16, self);
    }
};

How can I do this without enums if bitCast doesn't work? I agree with @eriksik2: It is better to drop enumToInt and always use bitCast.

@andrewrk andrewrk modified the milestones: 0.7.0, 0.8.0 Oct 9, 2020
@andrewrk andrewrk modified the milestones: 0.8.0, 0.9.0 May 19, 2021
@andrewrk andrewrk modified the milestones: 0.9.0, 0.10.0 Nov 20, 2021
@andrewrk andrewrk added the breaking Implementing this issue could cause existing code to no longer compile or have different behavior. label Dec 6, 2021
@andrewrk andrewrk modified the milestones: 0.10.0, 0.11.0 Apr 16, 2022
@alichraghi
Copy link
Contributor

Compile error has been implemented

test.zig:10:23: error: cannot @bitCast from 'z.Number'
    _ = @bitCast(u32, x);
                      ^
test.zig:10:23: note: use @enumToInt to cast to 'u32'

@Vexu
Copy link
Member

Vexu commented Oct 4, 2022

There's even a test.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
accepted This proposal is planned. breaking Implementing this issue could cause existing code to no longer compile or have different behavior. proposal This issue suggests modifications. If it also has the "accepted" label then it is planned.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants