Skip to content

CWG3046 [dcl.enum] Reading non-representable value from enumeration without fixed underlying type via common initial sequence rule. #732

Closed
cplusplus/draft
#9147

Description

@keinflue

Full name of submitter (unless configured in github; will be published with the issue): Benjamin Sch.

Reference (section label): [dcl.enum], [class.mem.general]

Link to reflector thread (if any):

Issue description:

#include<iostream>
#include<type_traits>

enum E { E0 } e;
enum F { F0, F1, F2, F3 };
static_assert(std::is_same_v<std::underlying_type_t<E>, std::underlying_type_t<F>>);

struct A { E e; };
struct B { F f; };
union U {
    A a;
    B b;
} u;

bool test() {
    return u.a.e == 2;
}

auto ptest = test;

int main() {
    u.b.f = F2;
    std::cout << ptest();
}

Assuming the static_assert passes, then because the two enumerations have the same underlying type, they are layout-compatible and therefore it is permitted to use the inactive u.a.e to read the active u.b.f corresponding to it in the common initial sequence. The read should happen as if u.b.f was nominated, meaning it should read the value 2 even if E is not able to represent that value. And therefore this program must print 1.

Is this intentional? It prevents the implementation from optimizing the body of test to return false; as it otherwise could because E can't represent a value of 2. Is the implementation required to special case this enumeration read through union access?

I originally reported this as bug against Clang in llvm/llvm-project#150833.

Activity

  1. frederick-vs-ja commented on Jul 28, 2025

    @frederick-vs-ja

    Anyway, the "the behavior is as if the corresponding member of T1 were nominated" part in [class.mem.general] p30 looks defective for this example.
    Maybe we can say "as if every possibly recursive subobject of the T2 member of a scalar type had the same object representation as the corresponding subobject of the T1 member"? Then we can infer that there's UB due to invalid object representation ([conv.lval] p3.4).

  2. t3nsor commented on Jul 28, 2025

    @t3nsor

    I don't think it's necessary to talk about object representations. We can just say that two enumerations are not layout-compatible if their ranges are not the same.

    We could be even more strict (while remaining C-compatible) by also requiring both enumerations to have the same number of enumerators, with corresponding enumerators in declaration order having the same value. However, that change would not be necessary for resolving this issue, and goes a bit into design territory.

  3. jensmaurer commented on Jul 28, 2025

    @jensmaurer
    Member
  4. changed the title [-][dcl.enum] Reading non-representable value from enumeration without fixed underlying type via common initial sequence rule.[/-] [+]CWG3046 [dcl.enum] Reading non-representable value from enumeration without fixed underlying type via common initial sequence rule.[/+] on Jul 28, 2025
  5. keinflue commented on Jul 28, 2025

    @keinflue
    Author

    I think both the conditions of same underlying type and same value range are required. I do not see anything forcing the implementation to choose the same underlying type only because the value ranges are the same.

  6. frederick-vs-ja commented on Nov 26, 2025

    @frederick-vs-ja

    Oh, I found that it was expressed in #39 (comment) that it seems plausible to make an enumeration type layout-compatible with its underlying type.
    But the current approach of CWG3046 either conflicts with such intent or potentially makes layout-compatibility not a transitive relationship (after achieving the aforementioned layout-compatibility).

  7. jensmaurer commented on Nov 29, 2025

    @jensmaurer
    Member

    Adjusted CWG3046 to continue to require "same underlying type".

    This is at least conservatively correct; if someone wants more, that's probably a feature paper.

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions