-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
enums should disallow multiple enumerations with the same value #2115
Comments
I'll add something related to this, that I've hit before. enum flags {
A = 1 << 0,
B = 1 << 1,
};
enum flags all = A | B; translate_c will also fail to translate something like this if |
It's possible to do this using definitions:
However the definitions don't work as enum literals. |
I think that C enums should be converted to: pub const mylib_enumname: type = struct {
pub const A: comptime_int = 0;
pub const B: comptime_int = 1;
// ...
}; Since that matches how C sees them. At the moment there are plenty of C headers that cannot be imported without modification. |
This also shows up in clang-c/libclang https://clang.llvm.org/doxygen/Index_8h_source.html in the CXCursor enumeration. |
Encountered this when creating bindings for Godot script API: https://github.com/GodotNativeTools/godot_headers/blob/master/nativescript/godot_nativescript.h#L45 |
I've been thinking about the current definition of Zig's C translator replaces enums with integer types of the correct size. The constant values, however, are generated as
Personally I like the second option better, but either of these would improve ergonomics and make interfacing with C code safer. |
|
The behaviour is checked, but only in debug and safe builds. Mismatched dll versions are the sort of thing that happens often in production and very rarely during development. |
Ah, I hadn't seen #2524. Having |
I think the best way Pros:
Cons:
I have enums implemented in |
Implemented here Vexu@7353e17 for reference. |
Here's what's accepted:
What I'm not convinced of:
Note that extern enums do not necessarily mean "compatible with the semantics of C" - they mean "compatible with the ABI of C". Enums are not a valid way to represent flags. An enum is a scalar value; flags is a set of booleans. As far as what this means for translate-c, I think the "Beating C at its own game" -> as long as the .h file does proper C types. Using enums for flags even in C is an abuse of the type system, and so I'm happy with that being awkward to deal with. The awkwardness is correct. |
This is now implemented and in master branch. However, note the bug #3991 |
See #2115. The concept of `packed enum` and `extern enum` is getting removed from the language.
Translate enum types as the underlying integer type. Translate enum constants as top-level integer constants of the correct type (which does not necessarily match the enum integer type). If an enum constant's type cannot be translated for some reason, omit it. See discussion ziglang#2115 (comment) Fixes ziglang#9153
Translate enum types as the underlying integer type. Translate enum constants as top-level integer constants of the correct type (which does not necessarily match the enum integer type). If an enum constant's type cannot be translated for some reason, omit it. See discussion ziglang#2115 (comment) Fixes ziglang#9153
Translate enum types as the underlying integer type. Translate enum constants as top-level integer constants of the correct type (which does not necessarily match the enum integer type). If an enum constant's type cannot be translated for some reason, omit it. See discussion #2115 (comment) Fixes #9153
There are two recent changes in zig that effect awshttp. 1. cf65ab8 disallows unused variables. Fair enough and backward compatible. 2. ziglang/zig#2115 (comment) This comment resulted in a backward incompatible change to use the underlying value from a C enum rather than its symbol. This reduces edge cases in the compiler. Ultimately we may want awshttp to define zig enums that mirror the C enums, but for now I've commented the definitions of the C enums used.
People mentioned enum flags being used in C. Here's an idiom I've been using when interacting with certain OS data structures whose enums have certain values based on other enum values: /// Page protection flags
pub const Protection = EnumFromDecl(vm_prot_t, false, struct {
pub const READ: u32 = 0x01;
pub const WRITE: u32 = 0x02;
pub const READ_WRITE: u32 = READ | WRITE;
...
}); This mirrors the C definition/documentation nicely, while allowing use-sites to switch on the enum: switch (seg64.initprot) {
...
.READ_WRITE => std.debug.print("Read-write case\n", .{}),
...
}
The bool parameter determines if the resulting enum should be exhaustive or not. |
@cryptocode, enum flags should be represented using pub const Protection = packed struct(u32) {
read: bool, // this is the LSB
write: bool, // and the next bit
execute: bool, // etc
_: u29 = 0, // remaining (padding) bits
}; |
@mlugg yeah most of time either that or just constants. But sometimes you really do want an enum, it just so happens that some fields are based on others. That is, on use-sites you wanna switch on the named combinations rather than inspecting individual flags. Narrow usecase, but when it fits it's really nice as you get the benefits of using switch (exhaustiveness being one) Not proposing any changes to language or std, just sharing an idiom that's been useful, say, when all named flag combinations must be handled. |
This was indeed reversed, the language now disallows multiple enumerations with the same value. https://ziglang.org/download/0.8.0/release-notes.html#No-More-Extern-or-Packed-Enums #9938 provides an alternative to enum tag aliasing. |
This works, until it doesn't. The whole
The packed struct trick is neat, but it falls down whenever you realize that using it implies a guarantee that the flags do not, and will never overlap. I'm not sure I would easily give that promise easily on my own code, much less on code over which I have no control, such as when using Also the whole renaming of enums I support very much the decision to drop these idioms from any manual or |
@andrewrk: I re-opened this to propose reversing the decision
A C enum allows multiple values. e.g.
However, zig
extern enum
's do not (note: we cannot declare a member based on another member, another possibly improvement)Fails with compilation
We should allow extern enums to have the same tag value for multiple members. The specific use-case here would be for translate-c. Encountered this when trying to process
gmp.h
which has this enum present:Alternatively for translate-c enums could be translated as sets of constants but this feels wrong. There are possibly some questions regarding switch cases and handling of duplicate values there that I haven't considered.
The text was updated successfully, but these errors were encountered: