Skip to content
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

CWG2590 [dcl.enum] Underlying type of enum should determine its size and alignment requirement #39

Closed
t3nsor opened this issue May 16, 2022 · 9 comments

Comments

@t3nsor
Copy link

t3nsor commented May 16, 2022

Full name of submitter: Brian Bi

Reference (section label): [dcl.enum]

Issue description: [dcl.enum] explains how the underlying type of an enumeration is determined, and for scoped enumerations, specifies that the enumeration has the same set of values as the underlying type. I'm quite sure that it was intended that the enumeration has the same size and alignment requirement as its underlying type, but the current wording does not explicitly state this. I'm less sure of whether (analogously to [basic.fundamental]/6) it was intended that enumerations always have the same value representation as their underlying type and that every valid value of the enumeration always has the same representation as it does in the underlying type. I think the answer to both is "yes" because otherwise it would be hard to satisfy [dcl.enum]/9 (according to which identity of underlying types is sufficient for layout-compatibility). If so, it should be made explicit. If not, perhaps it would be appropriate to add a note indicating what is not guaranteed.

Suggested resolution: Insert the following paragraph after [dcl.enum]/8:

An enumeration has the same size, value representation, and alignment requirements ([basic.align]) as its underlying type. Furthermore, each value of an enumeration has the same representation as the same value of the underlying type.

@jensmaurer
Copy link
Member

I think we want the phrasing from [basic.fundamental] p6 here.
Maybe that should be a general rule for all "underlying types".

@t3nsor
Copy link
Author

t3nsor commented May 16, 2022

The rule from [basic.fundamental]/6 about the range being the same doesn't apply, though; the range is more restricted in the case of enumerations with non-fixed underlying type: http://www.eel.is/c++draft/dcl.enum#8

@frederick-vs-ja
Copy link

It seems that an enumeration type is not layout-compatible with its underlying type. Is this intended?

@jensmaurer jensmaurer changed the title [dcl.enum] Underlying type of enum should determine its size and alignment requirement CWG2590 [dcl.enum] Underlying type of enum should determine its size and alignment requirement May 30, 2022
@jensmaurer
Copy link
Member

CWG2590

@willwray
Copy link

There's still the question of layout compatibility:

https://stackoverflow.com/questions/21956017/are-enumeration-types-layout-compatible-with-their-underlying-type

In C, this is guaranteed, and C++ requires support for mixing with C code, which cannot be implemented correctly unless C++ uses the same representation as C.

The suggested resolution guarantees same size, representation and alignment; should layout compatibility follow?
As well as the C compatibility argument, this can be useful for C++ type erasure techniques using enum tags.

@jensmaurer
Copy link
Member

"Furthermore, each value of an enumeration has the same representation as the same value of the underlying type."

should suffice, I think.

We need "layout-compatible" only for "common initial sequence", which seems a fairly narrow use-case. I do recognize that two enumerations are layout-compatible if they have the same underlying type, so it seems plausible to also declare layout-compatibility between an enumeration and its underlying type.

@willwray
Copy link

Thanks Jens; more thoughts.

The fact that C++20 introduced P0466 Layout-compatibility and Pointer-interconvertibility Traits argues that this use case was considered important enough to add traits to assert its applicability (only recently implemented in gcc and msvc).

Common initial sequence is applicable to C structs, e.g. for OS 'protocol' headers. Here, a first element of enum type can be a 'strong type' tag value encoding the trailing message fields. The existing specification guarantees that this is with a distinct CIS enum type which weakens its usage as a 'strong type' (without reflection there's no way to further check and assert enumerated values or their ids). It seems strictly better to allow pointer-interconvertibility with the underlying type.

@jensmaurer
Copy link
Member

Pointer-interconvertible is unrelated to layout-compatible. "Layout-compatible" is only used for "common initial sequence" for unions.

@willwray
Copy link

Thanks for the correction.

The main thought was that punning between distinct enum types compromises the type system more than does access to the underlying type.

The rationale for allowing enum-enum conversions may have been because 'they are integer types'
std-discussion: Why cast between two strongly typed C++11 enum classes is allowed?

C++23's value-returning to_underlying(e) is an information-losing conversion, and
a reference-returning as_underlying(e) sibling would be a fairly benign down-cast
(yet can't be implemented constexpr).

Overlaying the information of two more richly structured types is a cross-cast, or
a down-cast followed by an up-cast, with room for mismatch, dissonance, interference...

Conclusion:
Specifying enum layout-compatibility with its underlying type would be consistent with current
static_cast and other conversion rules, no worse than enum-enum compatibility, and useful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants