Skip to content

Feature Request: Support C23 style enum definitions with type specifier #103

Description

@axman6

C23 adds a feature from C++11 that allows the storage type for an enum definition to be specifies with the syntax:

enum my_enum : uint8_t { 
   ...
};

This has been supported by C compilers for quite a while, and is used in places like macOS's system headers. For example, in MacOSX.sdk/usr/include/sys/mount.h, there is the following definition:

OS_ENUM(graftdmg_type, uint32_t,
    GRAFTDMG_CRYPTEX_BOOT = 1,
    GRAFTDMG_CRYPTEX_PREBOOT = 2,
    GRAFTDMG_CRYPTEX_DOWNLEVEL = 3,
    // Reserved: CRYPTEX1_AUTH_ENV_GENERIC = 4,
    // Reserved: CRYPTEX1_AUTH_ENV_GENERIC_SUPPLEMENTAL = 5,
    GRAFTDMG_CRYPTEX_PDI_NONCE = 6,
    GRAFTDMG_CRYPTEX_EFFECTIVE_AP = 7,
    GRAFTDMG_CRYPTEX_MOBILE_ASSET = 8,
    // Update this when a new type is added
    GRAFTDMG_CRYPTEX_MAX = 8);

which expands to

typedef enum : uint32_t {
    GRAFTDMG_CRYPTEX_BOOT = 1, 
    GRAFTDMG_CRYPTEX_PREBOOT = 2,
    GRAFTDMG_CRYPTEX_DOWNLEVEL = 3,
    GRAFTDMG_CRYPTEX_PDI_NONCE = 6,
    GRAFTDMG_CRYPTEX_EFFECTIVE_AP = 7,
    GRAFTDMG_CRYPTEX_MOBILE_ASSET = 8,
    GRAFTDMG_CRYPTEX_MAX = 8 
} graftdmg_type_t

For reference, definition of OS_ENUM is guarded by come __has_extension checks, and I guess at least one must be true when c2hs is parsing the file:

#if __has_feature(objc_fixed_enum) || __has_extension(cxx_fixed_enum) || \
        __has_extension(cxx_strong_enums)
#define OS_ENUM(_name, _type, ...) \
	typedef enum : _type { __VA_ARGS__ } _name##_t
#define OS_CLOSED_ENUM(_name, _type, ...) \
	typedef enum : _type { __VA_ARGS__ } __OS_ENUM_ATTR_CLOSED _name##_t
#define OS_OPTIONS(_name, _type, ...) \
	typedef enum : _type { __VA_ARGS__ } __OS_ENUM_ATTR __OS_OPTIONS_ATTR _name##_t
#define OS_CLOSED_OPTIONS(_name, _type, ...) \
	typedef enum : _type { __VA_ARGS__ } __OS_ENUM_ATTR_CLOSED __OS_OPTIONS_ATTR _name##_t
#else
/*!
 * There is unfortunately no good way in plain C to have both fixed-type enums
 * and enforcement for clang's enum_extensibility extensions. The primary goal
 * of these macros is to allow you to define an enum and specify its width in a
 * single statement, and for plain C that is accomplished by defining an
 * anonymous enum and then separately typedef'ing the requested type name to the
 * requested underlying integer type. So the type emitted actually has no
 * relationship at all to the enum, and therefore while the compiler could
 * enforce enum extensibility if you used the enum type, it cannot do so if you
 * use the "_t" type resulting from this expression.
 *
 * But we still define a named enum type and decorate it appropriately for you,
 * so if you really want the enum extensibility enforcement, you can use the
 * enum type yourself, i.e. when compiling with a C compiler:
 *
 *     OS_CLOSED_ENUM(my_type, uint64_t,
 *         FOO,
 *         BAR,
 *         BAZ,
 *     );
 *
 *     my_type_t mt = 98; // legal
 *     enum my_type emt = 98; // illegal
 *
 * But be aware that the underlying enum type's width is subject only to the C
 * language's guarantees -- namely that it will be compatible with int, char,
 * and unsigned char. It is not safe to rely on the size of this type.
 *
 * When compiling in ObjC or C++, both of the above assignments are illegal.
 */
#define __OS_ENUM_C_FALLBACK(_name, _type, ...) \
	typedef _type _name##_t; enum _name { __VA_ARGS__ }

#define OS_ENUM(_name, _type, ...) \
	typedef _type _name##_t; enum { __VA_ARGS__ }
#define OS_CLOSED_ENUM(_name, _type, ...) \
	__OS_ENUM_C_FALLBACK(_name, _type, ## __VA_ARGS__) \
	__OS_ENUM_ATTR_CLOSED
#define OS_OPTIONS(_name, _type, ...) \
	__OS_ENUM_C_FALLBACK(_name, _type, ## __VA_ARGS__) \
	__OS_ENUM_ATTR __OS_OPTIONS_ATTR
#define OS_CLOSED_OPTIONS(_name, _type, ...) \
	__OS_ENUM_C_FALLBACK(_name, _type, ## __VA_ARGS__) \
	__OS_ENUM_ATTR_CLOSED __OS_OPTIONS_ATTR
#endif // __has_feature(objc_fixed_enum) || __has_extension(cxx_strong_enums)

Clangs docs on its support:

https://clang.llvm.org/docs/LanguageExtensions.html#enumerations-with-a-fixed-underlying-type
https://clang.llvm.org/docs/LanguageExtensions.html#c-11-strongly-typed-enumerations

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions